Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@focus4/core

Package Overview
Dependencies
Maintainers
1
Versions
174
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@focus4/core - npm Package Compare versions

Comparing version
12.11.0
to
12.11.1
+457
lib/focus4.core.d.ts
import { InitOptions, i18n } from "i18next";
import * as _$ky from "ky";
import { HTTPError } from "ky";
import { HashHistory } from "history";
//#region src/color-scheme.d.ts
declare const colorScheme: {
dark: boolean;
};
/**
* Permet d'initialiser l'utilisation du mode sombre dans une application Focus. Par défaut, il est initialisé avec le thème du navigateur de
* l'utilisateur.
* @param disableAutoDarkMode Désactive la prise en compte du thème de l'utilisateur et initialise toujours en thème clair.
*/
declare function initColorScheme(disableAutoDarkMode?: boolean): void;
//#endregion
//#region src/config.d.ts
/** Config Focus de l'application */
declare const coreConfig: {
/** Durée de cache par défaut pour les listes de référence. */referenceCacheDuration: number;
/**
* Renseigne le header `Accept-Language` par défaut de `coreFetch` pour utiliser la langue choisie dans `i18next`.
*
* (Sans ce header, le navigateur en posera un automatiquement, selon la langue de l'utilisateur).
*/
useI18nextAcceptHeader: boolean;
};
//#endregion
//#region src/i18n.d.ts
/**
* Utilitaire pour initialiser les resources i18next avec les traductions Focus.
* @param focusI18n Liste des traductions exportées par les modules Focus.
* @param customI18n Objet de traduction i18n, avec une clé par langue, qui sera mergé avec les traductions Focus.
* @returns Config de base à passer à `i18next.init()`.
*/
declare function baseI18nextConfig(focusI18n: Record<string, object>[], customI18n: Record<string, object>): InitOptions;
/** Enregistre les formatters i18next pour `boolean`, `date` et `datetime`, utilisés par défaut pour les domaines de ces schémas-là. */
declare function addValueFormatters(i18next: i18n): void;
//#endregion
//#region src/network/error-parsing.d.ts
/**
* Retour d'un appel serveur en erreur ([RFC9457]).
*
* Si le serveur n'est pas configuré pour renvoyer un `ProblemDetails` en cas d'erreur, la réponse sera wrappée dans `ProblemDetails` lorsqu'elle sera rejetée.
*/
interface ProblemDetails {
/**
* A URI reference [RFC3986] that identifies the problem type.
*
* This specification encourages that, when dereferenced, it provide human-readable documentation for the problem type (e.g., using HTML [W3C.REC-html5-20141028]).
*
* When this member is not present, its value is assumed to be "type" (string) - "about:blank".
*/
type?: string | "about:blank";
/**
* The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.
*/
status: number;
/**
* A short, human-readable summary of the problem type.
*
* It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).
*
* Si aucun message n'a été enregistré dans le `messageStore` à partir de cette instance, alors ce `title` sera enregistré comme `error` dans le `messageStore`.
*/
title?: string;
/**
* A human-readable explanation specific to this occurrence of the problem.
*
* Si renseigné, sera enregistré en premier comme `error` dans le `messageStore`.
*/
detail?: string;
/**
* A URI reference that identifies the specific occurrence of the problem.
*
* It may or may not yield further information if dereferenced.
*/
instance?: string;
/**
* Détails supplémentaires sur le problème (erreurs de validation par exemple).
*
* Chaque message d'erreur supplémentaire sera enregistré comme `error` dans le `messageStore`, préfixé par sa clé (sauf si c'est `global` ou `globals`).
*/
errors?: string | string[] | Record<string, string> | Record<string, string[]>;
/**
* Problem type definitions MAY extend the problem details object with additional members.
*
* Si la clé correspond à un type de message enregistré dans le `messageStore` et que la valeur est un `string`, `string[]`, `Record<string, string>` ou `Record<string, string[]>`,
* alors les messages seront enregistrés comme du type de leur clé dans le `messageStore` (selon les mêmes règles que `errors`).
*/
[key: string]: any;
}
/**
* HTTPError de `ky`, avec les ProblemDetails traités par Focus et les messages qui ont été ajoutés dans le MessageStore.
*/
declare class HTTPDetailedError extends HTTPError {
/** Détails de l'erreur. */
details: ProblemDetails;
/** Messages enregistrés dans le MessageStore, dans l'ordre. */
$messages: {
type: string;
message: string;
}[];
constructor(error: HTTPError, details: ProblemDetails, $messages: {
type: string;
message: string;
}[]);
}
/**
* Vérifie si l'erreur retournée par un appel est une annulation de requête.
* @param error L'erreur.
*/
declare function isAbortError(error: unknown): boolean;
//#endregion
//#region src/network/fetch.d.ts
declare const coreFetch: _$ky.KyInstance;
/** Télécharge un fichier depuis une réponse d'appel d'API. */
declare function downloadFile(response: Response): Promise<void>;
//#endregion
//#region src/network/store.d.ts
type HttpMethod = "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE";
/** Définition d'une requête. */
interface Request {
/** Id autogénéré pour la requête. */
id: string;
/** Méthode HTTP de la requête. */
method: HttpMethod;
/** URL complète (avec query string) de la requête. */
url: string;
}
/** Store de requête contenant les requêtes en cours dans l'application. */
declare class RequestStore {
/** Indique s'il y a au moins une requête en cours. */
get loading(): boolean;
/** Récupère les requêtes en cours. */
get pending(): Request[];
/**
* Vérifie s'il existe une requête suivie en cours pour un id donné.
* @param trackingId Id de suivi.
* @returns true/false
*/
readonly isLoading: (trackingId: string) => boolean;
/**
* Récupère le nombre de requêtes suivies en cours pour un id donné.
* @param trackingId Id de suivi.
* @returns Nombre de requêtes en cours.
*/
readonly getPendingCount: (trackingId: string) => number;
/**
* Enregistre une requête pour suivi par un ou plusieurs id(s).
*
* La méthode `requestStore.isLoading(trackingId)` permettra de savoir s'il y a au moins une requête suivie avec cet id qui est en cours.
* @param trackingId Id(s) de suivi.
* @param fetch Service à suivre.
* @param callback Un callback à appeler en cas de succès, pour l'inclure dans la même action que la mise à jour de l'état de chargement.
* @returns La Promise de `fetch`.
*/
track<T>(trackingId: string[] | string, fetch: () => Promise<T>, callback?: (value: T) => void): Promise<T>;
}
/** Instance principale du RequestStore. */
declare const requestStore: RequestStore;
//#endregion
//#region src/router/match.d.ts
/**
* If you have a `:paramName` you get an object {paramName:value}
*
* The last * or ** match is stored into `splat`
*
*/
interface MatchResultParams {
splat: string;
[paramName: string]: string;
}
//#endregion
//#region src/router/history.d.ts
interface RouteEnterEvent {
oldPath: string;
newPath: string;
params: MatchResultParams;
search: {
[key: string]: string;
};
}
interface RouteConfig {
/**
* The pattern to match against
*/
$: string;
/**
* Called before entering a route. This is your chance to redirect if you want.
*
*/
enter: (evt: RouteEnterEvent) => string | undefined;
}
declare function startHistory(history: HashHistory, routes: RouteConfig[]): Promise<void>;
//#endregion
//#region src/router/query.d.ts
/** Configuration des query params dans un routeur. */
interface QueryParamConfig {
[key: string]: "boolean" | "number" | "string";
}
type QueryParams<T extends QueryParamConfig> = { [P in keyof T]?: T[P] extends "string" ? string : T[P] extends "number" ? number : T[P] extends "boolean" ? boolean : never };
//#endregion
//#region src/router/param.d.ts
/** Paramètre de type number. */
interface NumberParam<N extends number = number> {
type: "number";
required: boolean;
spec: N;
}
/** Paramètre de type string. */
interface StringParam<S extends string = string> {
type: "string";
required: boolean;
spec: S;
}
/** Paramètre de routeur (number ou string). */
type Param<T extends number | string> = T extends number ? NumberParam<T> : T extends string ? StringParam<T> : never;
/** Définition d'un paramètre de routeur : nom, type et routes suivantes. */
type ParamDef<K extends string, P extends NumberParam | StringParam, V = unknown> = [K, P, V?];
/** Builder pour un type de paramètre. */
interface ParamTypeBuilder {
/**
* Spécifie un type number pour un paramètre.
* @param required Paramètre obligatoire.
*/
number<N extends number>(required?: boolean): NumberParam<N>;
/**
* Spécifie un type string pour un paramètre.
* @param required Paramètre obligatoire.
*/
string<S extends string>(required?: boolean): StringParam<S>;
}
/**
* Crée une définition de paramètre dans le routeur. A utiliser dans `makeRouter`.
*
* Un paramètre à un nom, un type (`number` ou `string`) et peut être obligatoire ou non. Si le paramètre est obligatoire, alors la section de route
* le précédant ne pourra pas être atteinte si le paramètre n'est pas renseigné.
*
* Les sections de route suivant le paramètres se précisent en troisième paramètre de cette fonction.
* @param name Nom du paramètre.
* @param type Type du paramètre.
* @param next Suite de la route.
*/
declare function param<K extends string, P extends NumberParam | StringParam, V>(name: K, type: (b: ParamTypeBuilder) => P, next?: V): ParamDef<K, P, V>;
//#endregion
//#region src/router/builders.d.ts
/** Type décrivant l'objet de valeurs de paramètre d'un routeur de configuration quelconque. */
type ParamObject<C = any> = C extends ParamDef<infer K1, Param<infer T1>, ParamDef<infer K2, Param<infer T2>>> ? Record<K1, T1> & Record<K2, T2> : C extends ParamDef<infer A3, Param<infer N3>, infer U> ? Record<A3, N3> & { readonly [P in keyof U]: ParamObject<U[P]> } : { readonly [P in keyof C]: ParamObject<C[P]> };
//#endregion
//#region src/router/types.d.ts
/** Callback permettant de décrire une définition de route. */
type UrlRouteDescriptor<C, _K = unknown, _T = unknown> = (C extends ParamDef<infer K0, Param<infer T>, infer V> ? (param: K0) => UrlRouteDescriptor<V, K0, T> : <K extends keyof C>(x: K) => C[K] extends ParamDef<infer _1, infer _2, infer _3> ? UrlRouteDescriptor<C[K]> : C[K] extends ParamDef<infer _4, infer _5> ? void : UrlRouteDescriptor<C[K]>) & {
spec: C;
};
/** Callback permettant de décrire une URL. */
type UrlPathDescriptor<C> = C extends ParamDef<infer _0, Param<infer T>, infer V> ? (param: T) => UrlPathDescriptor<V> : <K extends keyof C>(x: K) => C[K] extends ParamDef<infer _1, infer _2, infer _3> ? UrlPathDescriptor<C[K]> : C[K] extends ParamDef<infer _4, infer _5> ? void : UrlPathDescriptor<C[K]>;
/** Router correspondant à la config donnée. */
interface Router<C = any, Q extends QueryParamConfig = {}> {
/** Valeurs des paramètres de query. */
readonly query: QueryParams<Q>;
/** Etat du routeur. */
readonly state: ParamObject<C>;
/**
* Permet d'activer un mode de "confirmation" du routeur,
* qui bloque la prochaine navigation et demandera une confirmation (ou une annulation) à l'utilisateur pour continuer.
*/
confirmation: RouterConfirmation;
/**
* Si la route demandée est active, retourne le morceau de route suivant.
* @param predicate Callback décrivant la route.
*/
get<C2 = C>(predicate?: (x: UrlRouteDescriptor<C>) => UrlRouteDescriptor<C2>): (C2 extends ParamDef<infer P, infer _1, infer _2> ? P : keyof C2 & string) | undefined;
/**
* Récupère l'URL correspondante à la route demandée.
* @param predicate Callback décrivant la route.
* @param query Query params à ajouter.
*/
href(predicate?: (x: UrlPathDescriptor<C>) => void, query?: QueryParams<Q>): string;
/**
* Vérifie si la section de route demandée est active dans le routeur.
* @param predicate Callback décrivant la route.
*/
is(predicate?: (x: UrlRouteDescriptor<C>) => void): boolean;
/**
* Navigue vers l'URL demandée.
* @param predicate Callback décrivant l'URL.
* @param replace Remplace la route précédente dans l'historique.
* @param query Remplace les query params courants avec ceux donnés.
*/
to(predicate?: (x: UrlPathDescriptor<C>) => void, replace?: boolean, query?: QueryParams<Q>): void;
/**
* Construit une vue du routeur à partir d'une route donnée, permettant de manipuler une
* sous section du routeur.
* @param predicate Callback décrivant la route de base de la vue.
*/
sub<C2, K, T>(predicate: (x: UrlRouteDescriptor<C>) => UrlRouteDescriptor<C2, K, T>): Router<C2, Q> & {
state: { [P in K & string]: T };
};
/** Lance le routeur. */
start(): Promise<void>;
}
/**
* Permet d'activer un mode de "confirmation" du routeur,
* qui bloque la prochaine navigation et demandera une confirmation (ou une annulation) à l'utilisateur pour continuer.
*/
interface RouterConfirmation {
/** Si la mode "confirmation" est activé. */
readonly active: boolean;
/** S'il y a une navigation en attente. */
readonly pending: boolean;
/**
* Confirme la navigation demandée.
* @param save Si oui, appelle tous les callbacks enregistrés pour la sauvegarde au commit.
*/
commit(save?: boolean): Promise<void>;
/** Annule la navigation demandée. */
cancel(): void;
/**
* Active ou désactive le mode "confirmation", pour un identifiant donné. La mode sera activé sur le routeur s'il l'est au moins pour un identifiant.
* @param id Identifiant unique, à générer au préable.
* @param active Activation/Désactivation.
* @param onCommitSave Callback à appeler si la confirmation est appelée avec sauvegarde.
*/
toggle(id: string, active: boolean, onCommitSave?: () => Promise<void>): void;
}
/** Builder pour construire des contraintes sur les routes d'un routeur. */
interface RouterConstraintBuilder<C> {
/**
* Bloque l'accès à une route si une condition est remplie.
* @param predicate Callback décrivant la route.
* @param condition Condition.
*/
block(predicate: (x: UrlRouteDescriptor<C>) => void, condition: () => boolean): RouterConstraintBuilder<C>;
/**
* Redirige une route vers une autre si une condition est remplie.
* @param predicate Callback décrivant la route.
* @param condition Condition.
* @param to Callback décrivant l'URL cible.
*/
redirect(predicate: (x: UrlRouteDescriptor<C>) => void, condition: () => boolean, to: (x: UrlPathDescriptor<C>) => void): RouterConstraintBuilder<C>;
/**
* Construit une vue du ConstraintBuilder à partir d'une route donnée, permettant de manipuler une
* sous section du ConstraintBuilder.
* @param predicate Callback décrivant la route de base de la vue.
*/
sub<C2>(predicate: (x: UrlRouteDescriptor<C>) => UrlRouteDescriptor<C2>): RouterConstraintBuilder<C2>;
}
//#endregion
//#region src/router/index.d.ts
/**
* `makeRouter` permet de construire le routeur de l'application.
*
* Il prend en paramètre la définition de toutes les routes possibles dans l'application, définies avec des objets JS et la fonction `param`.
*
* Le routeur maintiendra ensuite un état interne qui sera le miroir de l'URL courante (la section après le #), et il pourra être requêté pour
* connaître la route courante ou les valeurs des paramètres, afin de contrôler les données à charger et afficher dans vos composants.
*
* Il pourra aussi être utilisé pour générer des URLs et naviguer entre différents états d'URL.
*
* @param config Configuration du routeur.
* @param constraintConfigurator Constraintes du routeur.
*/
declare function makeRouter<C, Q extends QueryParamConfig>(config: C, constraintConfigurator?: (b: RouterConstraintBuilder<C>) => void, queryConfig?: Q): Router<C, Q>;
//#endregion
//#region src/stores/message.d.ts
interface Message {
label: string;
action?: {
label: string;
onClick: () => void;
};
}
type MessageListener = (type: string, message: Message) => void;
/** Store de messages */
declare class MessageStore {
private readonly messages;
private readonly listeners;
/** Types de messages à traiter dans un appel à `addMessages`. */
messageTypes: string[];
/**
* Ajoute un message.
* @param type Le type
* @param message Le message.
*/
addMessage(type: string, message: string): void;
addMessage(type: string, message: Message): void;
/**
* Ajoute un message d'avertissement.
* @param message Le message.
*/
addWarningMessage(message: string): void;
addWarningMessage(message: Message): void;
/**
* Ajoute un message d'information.
* @param message Le message.
*/
addInformationMessage(message: string): void;
addInformationMessage(message: Message): void;
/**
* Ajoute un message d'erreur.
* @param message Le message.
*/
addErrorMessage(message: string): void;
addErrorMessage(message: Message): void;
/**
* Ajoute un message de succès.
* @param message Le message.
*/
addSuccessMessage(message: string): void;
addSuccessMessage(message: Message): void;
/**
* Ajoute en masse des messages dans le store. Seuls les types listés dans `messageTypes` seront pris en compte.
* Les noms de types peuvent égalements être au pluriel et/ou être préfixés par "global".
*
* Exemple : `error`/`errors`/`globalError`/`globalErrors` seront tous les 4 pris en compte pour ajouter des messages de type `error`.
*
* `addMessages` est automatiquement appelé par `coreFetch` en cas d'erreur.
* @param messages Objet faisant correspondre à chaque type le ou les messages à ajouter.
*/
addMessages(messages: Record<string, string[] | string>): {
type: string;
message: string;
}[];
/**
* Enregistre un listener pour être notifié de l'ajout de messages dans le store
* @param types Les types de message
* @param listener Le callback.
*/
addMessageListener(types: string[], listener: MessageListener): () => void;
/** Récupère le dernier message du type demandé. */
getLatestMessage(type: string): Message | undefined;
}
/** Instance principale du MessageStore. */
declare const messageStore: MessageStore;
//#endregion
//#region src/stores/user.d.ts
/** Store utilisateur de base, standardisant la gestion des rôles. A étendre pour y ajouter du métier. */
declare class UserStore<Role extends string = string> {
/** Liste des roles de l'utilisateur connecté. */
accessor roles: Role[];
/**
* Vérifie si un utilisateur possède l'un des rôles proposés.
* @param roles Les rôles proposés.
*/
hasRole(...roles: Role[]): boolean;
}
//#endregion
//#region src/focus4.core.d.ts
declare module "i18next" {
interface CustomTypeOptions {
returnNull: false;
}
}
//#endregion
export { HTTPDetailedError, type HttpMethod, type Message, type MessageListener, MessageStore, type Param, type ParamDef, type ProblemDetails, type QueryParamConfig, type Request, type Router, type RouterConfirmation, type RouterConstraintBuilder, type UrlPathDescriptor, type UrlRouteDescriptor, UserStore, addValueFormatters, baseI18nextConfig, colorScheme, coreConfig, coreFetch, downloadFile, initColorScheme, isAbortError, makeRouter, messageStore, param, requestStore, startHistory };
//# sourceMappingURL=focus4.core.d.ts.map
{"version":3,"file":"focus4.core.d.ts","names":[],"sources":["../src/color-scheme.ts","../src/config.ts","../src/i18n.ts","../src/network/error-parsing.ts","../src/network/fetch.ts","../src/network/store.ts","../src/router/match.ts","../src/router/history.ts","../src/router/query.ts","../src/router/param.ts","../src/router/builders.ts","../src/router/types.ts","../src/router/index.ts","../src/stores/message.ts","../src/stores/user.ts","../src/focus4.core.ts"],"mappings":"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"}
import i18next from "i18next";
import { action, autorun, computed, configure, extendObservable, intercept, observable, runInAction } from "mobx";
import { intersection, isEqual, lowerFirst, merge, uniq } from "es-toolkit";
import { DateTime } from "luxon";
import ky, { HTTPError, isHTTPError, isNetworkError } from "ky";
import { computedFn } from "mobx-utils";
import { createHashHistory } from "history";
//#region src/color-scheme.ts
const colorScheme = observable({ dark: false });
/**
* Permet d'initialiser l'utilisation du mode sombre dans une application Focus. Par défaut, il est initialisé avec le thème du navigateur de
* l'utilisateur.
* @param disableAutoDarkMode Désactive la prise en compte du thème de l'utilisateur et initialise toujours en thème clair.
*/
function initColorScheme(disableAutoDarkMode = false) {
const ls = localStorage.getItem("color-scheme");
if (ls === "dark" || !ls && !disableAutoDarkMode && window.matchMedia?.("(prefers-color-scheme: dark)").matches) colorScheme.dark = true;
localStorage.setItem("color-scheme", colorScheme.dark ? "dark" : "light");
autorun(() => {
const darkModeAttribute = document.documentElement.hasAttribute("dark");
if (colorScheme.dark && !darkModeAttribute) {
document.documentElement.setAttribute("dark", "true");
localStorage.setItem("color-scheme", "dark");
} else if (!colorScheme.dark && darkModeAttribute) {
document.documentElement.removeAttribute("dark");
localStorage.setItem("color-scheme", "light");
}
});
}
//#endregion
//#region src/config.ts
/** Config Focus de l'application */
const coreConfig = {
referenceCacheDuration: 36e5,
useI18nextAcceptHeader: false
};
//#endregion
//#region src/i18n.ts
/**
* Utilitaire pour initialiser les resources i18next avec les traductions Focus.
* @param focusI18n Liste des traductions exportées par les modules Focus.
* @param customI18n Objet de traduction i18n, avec une clé par langue, qui sera mergé avec les traductions Focus.
* @returns Config de base à passer à `i18next.init()`.
*/
function baseI18nextConfig(focusI18n, customI18n) {
let icons = {};
const resources = {};
for (const modulei18n of focusI18n) for (const key in modulei18n) if (key === "icons") icons = {
...icons,
...modulei18n[key]
};
else {
if (!(key in resources)) resources[key] = { translation: { focus: {} } };
resources[key].translation.focus = {
...resources[key].translation.focus,
...modulei18n[key]
};
}
for (const key in resources) if (resources[key].translation.focus) {
resources[key].translation.focus.boolean = "{{value, boolean}}";
resources[key].translation.focus.date = "{{-value, date}}";
resources[key].translation.focus.datetime = "{{-value, datetime}}";
resources[key].translation.focus.icons = icons;
}
for (const key in customI18n) {
if (!(key in resources)) resources[key] = { translation: {} };
merge(resources[key].translation, customI18n[key]);
}
return {
nsSeparator: "🤷‍♂️",
react: { useSuspense: false },
resources,
supportedLngs: Object.keys(resources)
};
}
/** Enregistre les formatters i18next pour `boolean`, `date` et `datetime`, utilisés par défaut pour les domaines de ces schémas-là. */
function addValueFormatters(i18next) {
i18next.services.formatter?.add("boolean", (value) => value !== void 0 ? i18next.t(`focus.bool.${value}`) : "");
i18next.services.formatter?.add("date", (value, lng) => value ? DateTime.fromISO(value).setLocale(lng).toLocaleString(DateTime.DATE_SHORT) : "");
i18next.services.formatter?.add("datetime", (value, lng) => value ? DateTime.fromISO(value).setLocale(lng).toLocaleString(DateTime.DATETIME_SHORT_WITH_SECONDS) : "");
}
//#endregion
//#region src/stores/message.ts
let _initProto$1;
function _applyDecs$2(e, t, n, r, o, i) {
var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length;
function g(t, n, r) {
return function(o, i) {
n && (i = o, o = e);
for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []);
return r ? i : o;
};
}
function b(e, t, n, r) {
if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined"));
return e;
}
function applyDec(e, t, n, r, o, i, u, s, f, l, p) {
function d(e) {
if (!p(e)) throw new TypeError("Attempted to access private element on non-instance");
}
var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o;
function I(t, n, r) {
return function(o, i) {
return n && (i = o, o = e), r && r(o), P[t].call(o, i);
};
}
if (!w) {
var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value";
if (f ? (l || D ? P = {
get: _setFunctionName$2(function() {
return v(this);
}, r, "get"),
set: function(e) {
t[4](this, e);
}
} : P[F] = v, l || _setFunctionName$2(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) {
if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet");
y[+s][r] = o < 3 ? 1 : o;
}
}
for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) {
var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = {
kind: [
"field",
"accessor",
"method",
"getter",
"setter",
"class"
][o],
name: r,
metadata: a,
addInitializer: function(e, t) {
if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished");
b(t, "An initializer", "be", !0), i.push(t);
}.bind(null, A)
};
if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);
else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function(e) {
return r in e;
} }, j || (c.get = f ? E ? function(e) {
return d(e), P.value;
} : I("get", 0, d) : function(e) {
return e[r];
}), E || S || (c.set = f ? I("set", 0, d) : function(e, t) {
e[r] = t;
}), N = T.call(z, D ? {
get: P.get,
set: P.set
} : P[F], H), A.v = 1, D) {
if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);
else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined");
} else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N);
}
return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N;
}
function w(e) {
return m(e, d, {
configurable: !0,
enumerable: !0,
value: a
});
}
return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function(e) {
e && f.push(g(e));
}, p = function(t, r) {
for (var i = 0; i < n.length; i++) {
var a = n[i], c = a[1], l = 7 & c;
if ((8 & c) == t && !l == r) {
var p = a[2], d = !!a[3], m = 16 & c;
applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey$2(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function(t) {
return _checkInRHS$2(t) === e;
} : o);
}
}
}, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), {
e: c,
get c() {
var n = [];
return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)];
}
};
}
function _toPropertyKey$2(t) {
var i = _toPrimitive$2(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _toPrimitive$2(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _setFunctionName$2(e, t, n) {
"symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : "");
try {
Object.defineProperty(e, "name", {
configurable: !0,
value: n ? n + " " + t : t
});
} catch (e) {}
return e;
}
function _checkInRHS$2(e) {
if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null"));
return e;
}
/** Store de messages */
var MessageStore = class {
static {
[_initProto$1] = _applyDecs$2(this, [], [
[
[action, action.bound],
18,
"addMessage"
],
[
[action, action.bound],
18,
"addWarningMessage"
],
[
[action, action.bound],
18,
"addInformationMessage"
],
[
[action, action.bound],
18,
"addErrorMessage"
],
[
[action, action.bound],
18,
"addSuccessMessage"
],
[
[action, action.bound],
18,
"addMessages"
]
]).e;
}
messages = (_initProto$1(this), observable.map());
listeners = /* @__PURE__ */ new Map();
/** Types de messages à traiter dans un appel à `addMessages`. */
messageTypes = [
"success",
"error",
"info",
"warning"
];
addMessage(type, message) {
if (!this.messages.get(type)) this.messages.set(type, []);
if (typeof message === "string") message = { label: message };
this.messages.get(type).push(message);
for (const listener of this.listeners.get(type) ?? []) listener(type, message);
}
addWarningMessage(message) {
this.addMessage("warning", message);
}
addInformationMessage(message) {
this.addMessage("info", message);
}
addErrorMessage(message) {
this.addMessage("error", message);
}
addSuccessMessage(message) {
this.addMessage("success", message);
}
/**
* Ajoute en masse des messages dans le store. Seuls les types listés dans `messageTypes` seront pris en compte.
* Les noms de types peuvent égalements être au pluriel et/ou être préfixés par "global".
*
* Exemple : `error`/`errors`/`globalError`/`globalErrors` seront tous les 4 pris en compte pour ajouter des messages de type `error`.
*
* `addMessages` est automatiquement appelé par `coreFetch` en cas d'erreur.
* @param messages Objet faisant correspondre à chaque type le ou les messages à ajouter.
*/
addMessages(messages) {
const allMessages = [];
for (const type in messages) {
const possibleTypes = [
type,
type.endsWith("s") ? type.slice(0, -1) : "",
type.startsWith("global") ? lowerFirst(type.slice(6)) : "",
type.startsWith("global") && type.endsWith("s") ? lowerFirst(type.slice(6, -1)) : ""
].filter(Boolean);
for (const possibleType of possibleTypes) if (this.messageTypes.includes(possibleType)) for (const message of Array.isArray(messages[type]) ? messages[type] : [messages[type]]) {
this.addMessage(possibleType, message);
allMessages.push({
type: possibleType,
message
});
}
}
return allMessages;
}
/**
* Enregistre un listener pour être notifié de l'ajout de messages dans le store
* @param types Les types de message
* @param listener Le callback.
*/
addMessageListener(types, listener) {
for (const type of types) {
if (!this.listeners.get(type)) this.listeners.set(type, []);
this.listeners.get(type).push(listener);
}
return () => {
for (const type of types) this.listeners.set(type, this.listeners.get(type)?.filter((l) => l !== listener) ?? []);
};
}
/** Récupère le dernier message du type demandé. */
getLatestMessage(type) {
return (this.messages.get(type) ?? []).at(-1);
}
};
/** Instance principale du MessageStore. */
const messageStore = new MessageStore();
//#endregion
//#region src/network/error-parsing.ts
/**
* HTTPError de `ky`, avec les ProblemDetails traités par Focus et les messages qui ont été ajoutés dans le MessageStore.
*/
var HTTPDetailedError = class extends HTTPError {
/** Détails de l'erreur. */
details;
/** Messages enregistrés dans le MessageStore, dans l'ordre. */
$messages;
constructor(error, details, $messages) {
super(error.response, error.request, error.options);
this.message = error.message;
this.details = details;
this.$messages = $messages;
}
};
function createProblemDetails(status, jsonResponse) {
return {
...jsonResponse,
type: jsonResponse.type ?? "about:blank",
status
};
}
function handleProblemDetails(error, problemDetails) {
const messages = {};
function add(type, ...newMessages) {
messages[type] ??= [];
messages[type].push(...newMessages);
}
if (problemDetails.detail) add("errors", problemDetails.detail);
for (const key in problemDetails) {
if ([
"type",
"status",
"title",
"detail",
"instance"
].includes(key)) continue;
if (typeof problemDetails[key] === "string") add(key, problemDetails[key]);
else if (Array.isArray(problemDetails[key]) && problemDetails[key].length > 0 && typeof problemDetails[key][0] === "string") add(key, ...problemDetails[key]);
else if (typeof problemDetails[key] === "object") {
for (const subkey in problemDetails[key]) if (typeof problemDetails[key][subkey] === "string") add(key, subkey === "global" || subkey === "globals" ? problemDetails[key][subkey] : `${subkey}: ${problemDetails[key][subkey]}`);
else if (Array.isArray(problemDetails[key][subkey]) && problemDetails[key][subkey].length > 0 && typeof problemDetails[key][subkey][0] === "string") add(key, ...problemDetails[key][subkey].map((m) => subkey === "global" || subkey === "globals" ? m : `${subkey}: ${m}`));
}
}
const $messages = messageStore.addMessages(messages);
if ($messages.length === 0 && problemDetails.title) {
messageStore.addErrorMessage(problemDetails.title);
$messages.push({
type: "error",
message: problemDetails.title
});
}
return new HTTPDetailedError(error, problemDetails, $messages);
}
/**
* Vérifie si l'erreur retournée par un appel est une annulation de requête.
* @param error L'erreur.
*/
function isAbortError(error) {
return error instanceof DOMException && error.name === "AbortError";
}
//#endregion
//#region src/network/store.ts
let _initProto;
function _applyDecs$1(e, t, n, r, o, i) {
var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length;
function g(t, n, r) {
return function(o, i) {
n && (i = o, o = e);
for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []);
return r ? i : o;
};
}
function b(e, t, n, r) {
if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined"));
return e;
}
function applyDec(e, t, n, r, o, i, u, s, f, l, p) {
function d(e) {
if (!p(e)) throw new TypeError("Attempted to access private element on non-instance");
}
var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o;
function I(t, n, r) {
return function(o, i) {
return n && (i = o, o = e), r && r(o), P[t].call(o, i);
};
}
if (!w) {
var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value";
if (f ? (l || D ? P = {
get: _setFunctionName$1(function() {
return v(this);
}, r, "get"),
set: function(e) {
t[4](this, e);
}
} : P[F] = v, l || _setFunctionName$1(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) {
if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet");
y[+s][r] = o < 3 ? 1 : o;
}
}
for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) {
var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = {
kind: [
"field",
"accessor",
"method",
"getter",
"setter",
"class"
][o],
name: r,
metadata: a,
addInitializer: function(e, t) {
if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished");
b(t, "An initializer", "be", !0), i.push(t);
}.bind(null, A)
};
if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);
else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function(e) {
return r in e;
} }, j || (c.get = f ? E ? function(e) {
return d(e), P.value;
} : I("get", 0, d) : function(e) {
return e[r];
}), E || S || (c.set = f ? I("set", 0, d) : function(e, t) {
e[r] = t;
}), N = T.call(z, D ? {
get: P.get,
set: P.set
} : P[F], H), A.v = 1, D) {
if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);
else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined");
} else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N);
}
return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N;
}
function w(e) {
return m(e, d, {
configurable: !0,
enumerable: !0,
value: a
});
}
return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function(e) {
e && f.push(g(e));
}, p = function(t, r) {
for (var i = 0; i < n.length; i++) {
var a = n[i], c = a[1], l = 7 & c;
if ((8 & c) == t && !l == r) {
var p = a[2], d = !!a[3], m = 16 & c;
applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey$1(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function(t) {
return _checkInRHS$1(t) === e;
} : o);
}
}
}, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), {
e: c,
get c() {
var n = [];
return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)];
}
};
}
function _toPropertyKey$1(t) {
var i = _toPrimitive$1(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _toPrimitive$1(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _setFunctionName$1(e, t, n) {
"symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : "");
try {
Object.defineProperty(e, "name", {
configurable: !0,
value: n ? n + " " + t : t
});
} catch (e) {}
return e;
}
function _checkInRHS$1(e) {
if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null"));
return e;
}
/** Store de requête contenant les requêtes en cours dans l'application. */
var RequestStore = class {
static {
[_initProto] = _applyDecs$1(this, [], [
[
computed,
3,
"loading"
],
[
[computed, computed.struct],
19,
"pending"
],
[
action,
2,
"endRequest"
]
]).e;
}
/** @internal */
/** Requêtes en cours. */
pendingRequests = (_initProto(this), observable.map({}, { deep: false }));
/** @internal */
/** Requêtes suivies en cours. */
trackedRequests = observable.map({}, { deep: false });
/** Indique s'il y a au moins une requête en cours. */
get loading() {
return this.pendingRequests.size > 0;
}
/** Récupère les requêtes en cours. */
get pending() {
return [...this.pendingRequests].map(([id, { method, url }]) => ({
id,
method,
url
}));
}
/**
* Vérifie s'il existe une requête suivie en cours pour un id donné.
* @param trackingId Id de suivi.
* @returns true/false
*/
isLoading = computedFn((trackingId) => [...this.trackedRequests.values()].some((trackingIds) => trackingIds.includes(trackingId)));
/**
* Récupère le nombre de requêtes suivies en cours pour un id donné.
* @param trackingId Id de suivi.
* @returns Nombre de requêtes en cours.
*/
getPendingCount = computedFn((trackingId) => [...this.trackedRequests.values()].filter((trackingIds) => trackingIds.includes(trackingId)).length);
/**
* Enregistre une requête pour suivi par un ou plusieurs id(s).
*
* La méthode `requestStore.isLoading(trackingId)` permettra de savoir s'il y a au moins une requête suivie avec cet id qui est en cours.
* @param trackingId Id(s) de suivi.
* @param fetch Service à suivre.
* @param callback Un callback à appeler en cas de succès, pour l'inclure dans la même action que la mise à jour de l'état de chargement.
* @returns La Promise de `fetch`.
*/
async track(trackingId, fetch, callback) {
const id = Math.random().toString();
await setTimeout0(() => this.trackedRequests.set(id, uniq(Array.isArray(trackingId) ? trackingId : [trackingId])));
try {
const value = await fetch();
if (callback) runInAction(() => {
this.trackedRequests.delete(id);
callback(value);
});
return value;
} finally {
this.trackedRequests.delete(id);
}
}
/**
* @internal
* Ajoute une nouvelle requête en cours dans le store.
* @returns Id de la requête.
*/
async startRequest(method, url) {
const id = Math.random().toString();
await setTimeout0(() => this.pendingRequests.set(id, {
method,
url
}));
return id;
}
/**
* @internal
* Termine une requête.
* @param id Id de la requête.
*/
endRequest(id) {
this.pendingRequests.delete(id);
}
};
/**
* @internal
* Permet de lancer une mise à jour de state MobX en dehors du contexte d'exécution courant.
*/
function setTimeout0(callback) {
return new Promise((resolve) => {
setTimeout(action(() => {
callback();
resolve();
}), 0);
});
}
/** Instance principale du RequestStore. */
const requestStore = new RequestStore();
//#endregion
//#region src/network/fetch.ts
const coreFetch = ky.create({
timeout: false,
retry: { shouldRetry(state) {
return isNetworkError(state.error);
} },
hooks: {
beforeRequest: [async ({ options, request }) => {
if (coreConfig.useI18nextAcceptHeader) request.headers.set("Accept-Language", i18next.language);
if (!options.context.requestId && !options.signal?.aborted) {
options.signal?.addEventListener("abort", () => {
requestStore.endRequest(options.context.requestId);
});
options.context.requestId = await requestStore.startRequest(request.method, request.url);
}
}],
afterResponse: [({ options }) => {
requestStore.endRequest(options.context.requestId);
}],
beforeError: [async ({ error, options, request, retryCount }) => {
if (isHTTPError(error)) {
error.message = `Une erreur ${error.response.status} est survenue lors de l'appel à "${error.request.url}".`;
const contentType = error.response.headers.get("Content-Type");
if (contentType?.includes("application/problem+json")) error = handleProblemDetails(error, error.data);
else if (contentType?.includes("application/json")) error = handleProblemDetails(error, createProblemDetails(error.response.status, error.data));
if (error instanceof HTTPDetailedError) console.error("Détails :", error.details);
} else if (!isAbortError(error)) {
requestStore.endRequest(options.context.requestId);
error.message = `Une erreur technique non gérée est survenue lors de l'appel à "${request.url}" après ${retryCount + 1} tentatives.`;
}
return error;
}]
}
});
/** Télécharge un fichier depuis une réponse d'appel d'API. */
async function downloadFile(response) {
const disposition = response.headers.get("content-disposition") ?? "";
let filename = "file";
if (disposition.includes("attachment")) {
const matches = /filename\*=UTF-8''(.+)/i.exec(disposition);
if (matches?.[1]) filename = decodeURIComponent(matches[1]);
}
const objectUrl = URL.createObjectURL(await response.blob());
const a = document.createElement("a");
a.href = objectUrl;
a.download = filename;
document.body.append(a);
a.click();
setTimeout(() => {
a.remove();
URL.revokeObjectURL(objectUrl);
}, 100);
}
//#endregion
//#region src/router/builders.ts
/**
* Construit la liste des endpoints du routeur.
* @param config Config du routeur.
*/
function buildEndpoints(config) {
const endpoints = [];
function addEndpoints(c, root) {
if (Array.isArray(c)) {
if (!c[1].required) endpoints.push(root);
root = `${root}/:${c[0]}`;
if (!Array.isArray(c[2])) endpoints.push(root);
if (c[2]) addEndpoints(c[2], root);
} else {
endpoints.push(root);
for (const key in c) addEndpoints(c[key], `${root}/${key}`);
}
}
endpoints.push("/");
addEndpoints(config, "");
return endpoints;
}
/**
* Construit la map de setters des paramètres du routeur.
* @param config Config du routeur.
* @param object Object de paramètres pré-construit.
* @param params Pour récursion.
*/
function buildParamsMap(config, object, params = {}) {
if (Array.isArray(config)) {
const setter = (value) => {
const newValue = config[1].type === "number" && value !== void 0 ? Number.parseFloat(value) : value;
object[config[0]] = newValue;
return newValue;
};
if (params[config[0]]) {
const existing = params[config[0]];
params[config[0]] = (value) => {
existing(value);
setter(value);
return value;
};
} else params[config[0]] = setter;
if (config[2]) buildParamsMap(config[2], object, params);
} else for (const key in config) buildParamsMap(config[key], object[key], params);
return params;
}
//#endregion
//#region src/router/match.ts
function escapeRegExp(string) {
return string.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
}
function _compilePattern(pattern) {
let regexpSource = "";
const paramNames = [];
const tokens = [];
let lastIndex = 0;
let m;
const matcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|\*\*|\*|\(|\)/g;
while (m = matcher.exec(pattern)) {
if (m.index !== lastIndex) {
tokens.push(pattern.slice(lastIndex, m.index));
regexpSource += escapeRegExp(pattern.slice(lastIndex, m.index));
}
if (m[1]) {
regexpSource += "([^/]+)";
paramNames.push(m[1]);
} else if (m[0] === "**") {
regexpSource += "(.*)";
paramNames.push("splat");
} else if (m[0] === "*") {
regexpSource += "(.*?)";
paramNames.push("splat");
} else if (m[0] === "(") regexpSource += "(?:";
else if (m[0] === ")") regexpSource += ")?";
tokens.push(m[0]);
lastIndex = matcher.lastIndex;
}
if (lastIndex !== pattern.length) {
tokens.push(pattern.slice(lastIndex));
regexpSource += escapeRegExp(pattern.slice(lastIndex));
}
return {
pattern,
regexpSource,
paramNames,
tokens
};
}
const CompiledPatternsCache = Object.create(null);
function compilePattern(pattern) {
CompiledPatternsCache[pattern] ??= _compilePattern(pattern);
return CompiledPatternsCache[pattern];
}
/**
* Attempts to match a pattern on the given pathname. Patterns may use
* the following special characters:
*
* - :paramName Matches a URL segment up to the next /, ?, or #. The
* captured string is considered a "param"
* - () Wraps a segment of the URL that is optional
* - * Consumes (non-greedy) all characters up to the next
* character in the pattern, or to the end of the URL if
* there is none
* - ** Consumes (greedy) all characters up to the next character
* in the pattern, or to the end of the URL if there is none
*/
function match({ pattern, path }) {
if (!pattern.startsWith("/")) pattern = `/${pattern}`;
let { regexpSource } = compilePattern(pattern);
const { paramNames, tokens } = compilePattern(pattern);
if (!pattern.endsWith("/")) regexpSource += "/?";
if (tokens.at(-1) === "*") regexpSource += "$";
const m = new RegExp(`^${regexpSource}`, "i").exec(path);
if (!m) return null;
const matchedPath = m[0];
let remainingPath = path.slice(matchedPath.length);
if (remainingPath) {
if (!matchedPath.endsWith("/")) return null;
remainingPath = `/${remainingPath}`;
}
/**
* Compose the param names and values into an object
*/
const paramValues = m.slice(1).map((v) => v && decodeURIComponent(v));
const params = {};
paramNames.forEach((paramName, index) => {
params[paramName] = paramValues[index];
});
return {
remainingPath,
params
};
}
//#endregion
//#region src/router/query.ts
function buildQueryMap(query, object) {
const map = {};
for (const key in query) {
const setter = (value) => {
const newValue = value === void 0 ? void 0 : query[key] === "number" ? Number.parseFloat(value) : query[key] === "boolean" ? value === "true" ? true : value === "false" ? false : NaN : value;
object[key] = newValue;
return newValue;
};
map[key] = setter;
}
return map;
}
function buildQueryString(query) {
return Object.keys(query).reduce((acc, qp) => query[qp] === void 0 ? acc : `${acc + (acc === "" ? "?" : "&")}${qp}=${encodeURIComponent(query[qp])}`, "");
}
function parseSearchString(query) {
return query.replace(/(^\?)/, "").split("&").reduce((obj, currentPair) => {
const pair = currentPair.split("=");
obj[pair[0]] = pair[1];
return obj;
}, {});
}
//#endregion
//#region src/router/history.ts
async function startHistory(history, routes) {
let oldPath = "/";
async function trigger({ newPath, search }) {
const parsedSearch = parseSearchString(search);
let beforeMatch;
let enterMatch;
let params;
for (const route of routes) {
const pattern = route.$;
const beforePreMatch = match({
pattern,
path: oldPath
});
const enterPreMatch = match({
pattern,
path: newPath
});
if (!beforeMatch) {
if (beforePreMatch && !beforePreMatch.remainingPath) beforeMatch = route;
}
if (!enterMatch) {
if (!enterPreMatch || enterPreMatch.remainingPath) continue;
enterMatch = route;
params = enterPreMatch.params;
}
}
if (!enterMatch || !params) {
history.replace(oldPath);
return;
}
/** Entering */
const redirect = enterMatch.enter({
oldPath,
newPath,
params,
search: parsedSearch
});
if (!redirect) oldPath = newPath;
else {
history.replace(redirect);
oldPath = redirect;
}
}
history.listen(({ location }) => {
trigger({
newPath: location.pathname,
search: location.search
});
});
await trigger({
newPath: history.location.pathname,
search: history.location.search
});
}
//#endregion
//#region src/router/param.ts
const paramTypeBuilder = {
number(required = false) {
return {
type: "number",
required,
spec: {}
};
},
string(required = false) {
return {
type: "string",
required,
spec: {}
};
}
};
/**
* Crée une définition de paramètre dans le routeur. A utiliser dans `makeRouter`.
*
* Un paramètre à un nom, un type (`number` ou `string`) et peut être obligatoire ou non. Si le paramètre est obligatoire, alors la section de route
* le précédant ne pourra pas être atteinte si le paramètre n'est pas renseigné.
*
* Les sections de route suivant le paramètres se précisent en troisième paramètre de cette fonction.
* @param name Nom du paramètre.
* @param type Type du paramètre.
* @param next Suite de la route.
*/
function param(name, type, next) {
return [
name,
type(paramTypeBuilder),
next
];
}
//#endregion
//#region src/router/index.ts
/**
* `makeRouter` permet de construire le routeur de l'application.
*
* Il prend en paramètre la définition de toutes les routes possibles dans l'application, définies avec des objets JS et la fonction `param`.
*
* Le routeur maintiendra ensuite un état interne qui sera le miroir de l'URL courante (la section après le #), et il pourra être requêté pour
* connaître la route courante ou les valeurs des paramètres, afin de contrôler les données à charger et afficher dans vos composants.
*
* Il pourra aussi être utilisé pour générer des URLs et naviguer entre différents états d'URL.
*
* @param config Configuration du routeur.
* @param constraintConfigurator Constraintes du routeur.
*/
function makeRouter(config, constraintConfigurator, queryConfig = {}) {
/**
* Construit l'objet de valeurs.
* @param cIn La config du routeur.
* @param object L'objet en cours de construction (pour appel récursif).
*/
function buildParamsObject(cIn, object = {}) {
if (Array.isArray(cIn)) {
extendObservable(object, { [cIn[0]]: void 0 });
intercept(object, cIn[0], (change) => {
if (Number.isNaN(change.newValue)) return null;
const isActive = Object.keys(store._activeParams).includes(cIn[0]);
const isUndefined = change.newValue === void 0;
if (isActive && !isUndefined) {
store._activeParams[cIn[0]] = `${change.newValue}`;
if (store._activeUrl !== window.location.hash?.replace("#", "")) history.replace(store._activeUrl);
}
if (isActive && !isUndefined || !isActive && isUndefined) return change;
return null;
});
if (cIn[2]) buildParamsObject(cIn[2], object);
} else for (const key in cIn) object[key] = buildParamsObject(cIn[key]);
return object;
}
const queryObject = observable(Object.keys(queryConfig).reduce((s, q) => ({
...s,
[q]: void 0
}), {}));
for (const key in queryObject) intercept(queryObject, key, (change) => {
if (Number.isNaN(change.newValue)) return null;
if (change.newValue === void 0 || change.newValue === "") delete store._activeQuery[key];
else store._activeQuery[key] = `${change.newValue}`;
let route = store._activeRoute + buildQueryString(store._activeQuery);
for (const param in store._activeParams) route = route.replace(`:${param}`, store._activeParams[param]);
if (route !== window.location.hash?.replace("#", "")) history.replace(route);
return change;
});
const store = extendObservable({
state: buildParamsObject(config),
query: queryObject
}, {
_activeRoute: "/",
_activeParams: {},
_activeQuery: {},
_hasConfirm: false,
_pending: void 0,
get _activeUrl() {
let url = store._activeRoute + buildQueryString(store._activeQuery);
for (const param in store._activeParams) url = url.replace(`:${param}`, store._activeParams[param]);
return url;
}
}, { _pending: observable.ref });
const paramsMap = buildParamsMap(config, store.state);
const queryMap = buildQueryMap(queryConfig, store.query);
const constraints = [];
let history;
/** Crée le routeur, appelé par "start". */
async function start() {
history = createHashHistory();
const routes = uniq(buildEndpoints(config)).map(($) => ({
$,
enter: action(({ params, oldPath, search }) => {
if (store._pending) return;
const oldPathWithQuery = oldPath + buildQueryString(store._activeQuery);
if (Object.keys(search).filter((x) => x).some((qp) => !Object.keys(queryConfig).includes(qp))) return oldPathWithQuery;
const prevRoute = store._activeRoute;
const prevParams = store._activeParams;
const prevQuery = store._activeQuery;
const prevUrl = store._activeUrl;
const activeRoute = $;
const activeParams = params;
const activeQuery = Object.keys(search).filter((x) => x).reduce((acc, k) => ({
...acc,
[k]: decodeURIComponent(search[k])
}), {});
if (isEqual({
activeRoute,
activeParams,
activeQuery
}, {
activeRoute: prevRoute,
activeParams: prevParams,
activeQuery: prevQuery
})) return;
for (const constraint of constraints.filter((c) => activeRoute.startsWith(c.route))) if (constraint.condition()) {
const redirect = (constraint.redirect?.() ?? (oldPath || "/")) + buildQueryString(activeQuery);
if (redirect !== window.location.hash?.replace("#", "")) {
store._activeRoute = prevRoute;
store._activeParams = prevParams;
return redirect;
}
}
if (store._hasConfirm) {
store._pending = {
activeRoute,
activeParams,
activeQuery,
prevUrl
};
return;
} else {
store._activeRoute = activeRoute;
store._activeParams = activeParams;
store._activeQuery = activeQuery;
}
const newValues = [];
for (const key in paramsMap) if (key in store._activeParams) newValues.push(paramsMap[key](store._activeParams[key]));
else paramsMap[key](void 0);
for (const key in queryMap) if (key in store._activeQuery) newValues.push(queryMap[key](store._activeQuery[key]));
else queryMap[key](void 0);
if (newValues.some(Number.isNaN)) {
store._activeRoute = prevRoute;
store._activeParams = prevParams;
store._activeQuery = prevQuery;
return oldPathWithQuery;
}
})
}));
await startHistory(history, routes);
}
/** Récupère le chemin correspondant à un préfixe + un prédicat. */
function getPath(route, predicate) {
const builder = (path) => {
route += `/${path}`;
return builder;
};
predicate(builder);
if (!route) route = "/";
return route;
}
/** Récupère la route correspondant à un préfixe + un prédicat. */
function getRoute(route, predicate) {
const builder = (path) => {
route += `/${Object.keys(paramsMap).includes(path) ? `:${path}` : path}`;
return builder;
};
predicate(builder);
return route;
}
/** Permet de garder le résultat de "get" en "computed" pour éviter de trigger "get" à chaque changement de route. */
const innerGet = computedFn((route) => {
if (!store._activeRoute.startsWith(route)) return;
else return store._activeRoute.replace(route, "").split("/")[1]?.replace(":", "");
}, { keepAlive: true });
/** Fonction "get" de base */
function get(route, predicate) {
return innerGet(getRoute(route, predicate));
}
/** Fonction "href" de base */
function href(route, predicate, query = {}) {
return `#${getPath(route, predicate) + buildQueryString(query)}`;
}
/** Permet de garder le résultat de "is" en "computed" pour éviter de trigger "is" à chaque changement de route. */
const innerIs = computedFn((route) => store._activeRoute.startsWith(route), { keepAlive: true });
/** Fonction "is" de base */
function is(route, predicate) {
return innerIs(getRoute(route, predicate));
}
/** Fonction "to" de base */
function to(route, predicate, replace, query) {
route = getPath(route, predicate) + buildQueryString(query ?? store._activeQuery);
if (route !== window.location.hash?.replace("#", "")) if (replace) history.replace(route);
else history.push(route);
}
function blockOutside(e) {
e.preventDefault();
}
const confirmation = observable({
_activeIds: /* @__PURE__ */ new Map(),
get active() {
return store._hasConfirm;
},
toggle(id, active, onCommitSave) {
if (this._activeIds.has(id) && !active) this._activeIds.delete(id);
else if (active) this._activeIds.set(id, onCommitSave);
const hasConfirm = this._activeIds.size > 0;
if (hasConfirm && !store._hasConfirm) window.addEventListener("beforeunload", blockOutside);
else if (!hasConfirm && store._hasConfirm) {
window.removeEventListener("beforeunload", blockOutside);
this.commit();
}
store._hasConfirm = hasConfirm;
store._pending = void 0;
},
get pending() {
return store._pending !== void 0;
},
async commit(save = false) {
if (store._hasConfirm && store._pending) {
const { activeRoute, activeParams, activeQuery } = store._pending;
if (save) await Promise.all([...this._activeIds.values()].filter((x) => !!x).map((x) => x()));
runInAction(() => {
store._activeRoute = activeRoute;
store._activeParams = activeParams;
store._activeQuery = activeQuery;
store._pending = void 0;
for (const key in paramsMap) if (key in store._activeParams) paramsMap[key](store._activeParams[key]);
else paramsMap[key](void 0);
for (const key in queryMap) if (key in store._activeQuery) queryMap[key](store._activeQuery[key]);
else queryMap[key](void 0);
});
}
},
cancel() {
if (store._hasConfirm && store._pending) {
history.push(store._pending.prevUrl);
store._pending = void 0;
}
}
});
/** Fonction "sub" de base */
function sub(route, state, predicate) {
const builder = (path) => {
const isParam = Object.keys(paramsMap).includes(path);
route += `/${isParam ? `:${path}` : path}`;
if (!isParam) state = state[path];
return builder;
};
predicate(builder);
return {
state,
query: store.query,
get: (p) => get(route, p ?? ((x) => x)),
href: (p, q) => {
let baseRoute = route;
for (const param in store._activeParams) baseRoute = baseRoute.replace(`:${param}`, store._activeParams[param]);
return href(baseRoute, p ?? ((x) => x), q);
},
is: (p) => is(route, p ?? ((x) => x)),
to: (p, r = false, q = void 0) => {
let baseRoute = route;
for (const param in store._activeParams) baseRoute = baseRoute.replace(`:${param}`, store._activeParams[param]);
to(baseRoute, p ?? ((x) => x), r, q);
},
sub: (p) => sub(route, state, p),
start: () => {
/** */
},
navigation: confirmation
};
}
store.get = (p) => get("", p ?? ((x) => x));
store.href = (p, q) => href("", p ?? ((x) => x), q);
store.is = (p) => is("", p ?? ((x) => x));
store.to = (p, r = false, q = void 0) => to("", p ?? ((x) => x), r, q);
store.sub = (p) => sub("", store.state, p);
store.start = start;
store.confirmation = confirmation;
function getConstraintBuilder(route) {
return {
block(predicate, condition) {
constraints.push({
route: getRoute(route, predicate),
condition
});
return this;
},
redirect(predicate, condition, redirect) {
constraints.push({
route: getRoute(route, predicate),
condition,
redirect: () => {
let baseRoute = route;
if (baseRoute.includes(":")) for (const param in store._activeParams) baseRoute = baseRoute.replace(`:${param}`, store._activeParams[param]);
return getPath(baseRoute, redirect);
}
});
return this;
},
sub(predicate) {
return getConstraintBuilder(getRoute(route, predicate));
}
};
}
constraintConfigurator?.(getConstraintBuilder(""));
return store;
}
//#endregion
//#region src/stores/user.ts
let _init_roles, _init_extra_roles;
function _applyDecs(e, t, n, r, o, i) {
var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length;
function g(t, n, r) {
return function(o, i) {
n && (i = o, o = e);
for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []);
return r ? i : o;
};
}
function b(e, t, n, r) {
if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined"));
return e;
}
function applyDec(e, t, n, r, o, i, u, s, f, l, p) {
function d(e) {
if (!p(e)) throw new TypeError("Attempted to access private element on non-instance");
}
var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o;
function I(t, n, r) {
return function(o, i) {
return n && (i = o, o = e), r && r(o), P[t].call(o, i);
};
}
if (!w) {
var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value";
if (f ? (l || D ? P = {
get: _setFunctionName(function() {
return v(this);
}, r, "get"),
set: function(e) {
t[4](this, e);
}
} : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) {
if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet");
y[+s][r] = o < 3 ? 1 : o;
}
}
for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) {
var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = {
kind: [
"field",
"accessor",
"method",
"getter",
"setter",
"class"
][o],
name: r,
metadata: a,
addInitializer: function(e, t) {
if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished");
b(t, "An initializer", "be", !0), i.push(t);
}.bind(null, A)
};
if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);
else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function(e) {
return r in e;
} }, j || (c.get = f ? E ? function(e) {
return d(e), P.value;
} : I("get", 0, d) : function(e) {
return e[r];
}), E || S || (c.set = f ? I("set", 0, d) : function(e, t) {
e[r] = t;
}), N = T.call(z, D ? {
get: P.get,
set: P.set
} : P[F], H), A.v = 1, D) {
if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);
else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined");
} else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N);
}
return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N;
}
function w(e) {
return m(e, d, {
configurable: !0,
enumerable: !0,
value: a
});
}
return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function(e) {
e && f.push(g(e));
}, p = function(t, r) {
for (var i = 0; i < n.length; i++) {
var a = n[i], c = a[1], l = 7 & c;
if ((8 & c) == t && !l == r) {
var p = a[2], d = !!a[3], m = 16 & c;
applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function(t) {
return _checkInRHS(t) === e;
} : o);
}
}
}, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), {
e: c,
get c() {
var n = [];
return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)];
}
};
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _setFunctionName(e, t, n) {
"symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : "");
try {
Object.defineProperty(e, "name", {
configurable: !0,
value: n ? n + " " + t : t
});
} catch (e) {}
return e;
}
function _checkInRHS(e) {
if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null"));
return e;
}
/** Store utilisateur de base, standardisant la gestion des rôles. A étendre pour y ajouter du métier. */
var UserStore = class {
static {
[_init_roles, _init_extra_roles] = _applyDecs(this, [], [[
observable,
1,
"roles"
]]).e;
}
constructor() {
_init_extra_roles(this);
}
/** Liste des roles de l'utilisateur connecté. */
#A = _init_roles(this, []);
/**
* Vérifie si un utilisateur possède l'un des rôles proposés.
* @param roles Les rôles proposés.
*/
get roles() {
return this.#A;
}
set roles(v) {
this.#A = v;
}
hasRole(...roles) {
return intersection(roles, this.roles || []).length > 0;
}
};
//#endregion
//#region src/focus4.core.ts
configure({ enforceActions: "never" });
//#endregion
export { HTTPDetailedError, MessageStore, UserStore, addValueFormatters, baseI18nextConfig, colorScheme, coreConfig, coreFetch, downloadFile, initColorScheme, isAbortError, makeRouter, messageStore, param, requestStore, startHistory };
//# sourceMappingURL=focus4.core.js.map

Sorry, the diff of this file is too big to display

+3
-3
{
"name": "@focus4/core",
"version": "12.11.0",
"version": "12.11.1",
"description": "Focus v4, core module",

@@ -30,5 +30,5 @@ "main": "lib/focus4.core.js",

"devDependencies": {
"@focus4/tooling": "12.11.0",
"@focus4/tooling": "12.11.1",
"jsdom": "29.0.2"
}
}
}