@gandalan/weblibs 2.0.8 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/JSDOC.md CHANGED
@@ -273,6 +273,35 @@ export {};
273
273
  If that type must be visible to consumers, make sure the file is part of the generator input and regenerate declarations.
274
274
 
275
275
 
276
+ ### Add an overloaded function type
277
+
278
+ Some public entry points behave differently depending on the argument type —
279
+ `NeherApp3I18n.localize` translates a string but acts as a Svelte action when
280
+ it gets a DOM node. `@callback` cannot express that (one signature only), so
281
+ write the type as a typedef with **call signatures**:
282
+
283
+ ```js
284
+ /**
285
+ * @typedef {{
286
+ * (key: string, params?: LocalizeParams, namespace?: string): string;
287
+ * (node: Element, options?: LocalizeActionOptions): LocalizeActionHandle;
288
+ * }} Localize
289
+ */
290
+ ```
291
+
292
+ The generator copies the type expression verbatim, so `index.d.ts` gets a real
293
+ overload set and consumers see the precise return type per call form.
294
+
295
+ Two things to know when a consumer *implements* such a type:
296
+
297
+ - Annotate the implementation with the type instead of repeating `@overload`
298
+ blocks — `/** @type {Localize} */ const localize = (…) => …`. Two separately
299
+ declared overload sets are not assignable to each other in TypeScript, even
300
+ when they look identical.
301
+ - The implementation itself has one signature, so widen its return
302
+ (`/** @type {*} */ (…)`) and give trailing parameters defaults so it also
303
+ accepts the shorter call form.
304
+
276
305
  ## Root Consumption Model
277
306
 
278
307
  There are two public surfaces:
package/README.md CHANGED
@@ -14,6 +14,15 @@
14
14
  - IDAS API (Swagger): https://api.dev.idas-cloudservices.net/swagger/
15
15
  - JSDoc-Regeln und Typing-Konventionen: [JSDOC.md](./JSDOC.md)
16
16
 
17
+ ### NeherApp3-Hosttypen
18
+ `api/neherApp3Types.js` ist die Master-Referenz fuer die Vertraege der
19
+ NeherApp3-Rahmen-App: `NeherApp3` (Host-API), `NeherApp3Module` (Modul-Einstieg),
20
+ `NeherApp3Messages` (In-Realm-Nachrichtenbus) und `NeherApp3I18n`
21
+ (Lokalisierung: `localize` als Funktion *und* Svelte-Action, Modul-Kataloge,
22
+ sprachrichtige Sortierung). Die Datei enthaelt nur Typen und wird von Hand
23
+ gepflegt; die Leitfaeden liegen im NeherApp3-Repository
24
+ (`docs/MODULE.md`, `docs/MESSAGING.md`, `docs/I18N.md`).
25
+
17
26
  ### Voraussetzungen
18
27
  - Browser-Umgebung
19
28
  - Gueltiger App-Token im UUID-Format
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Auto-generated NeherApp3 root type definitions.
3
- * Do not modify manually - changes will be overwritten by scripts/generate-root-dto-typedefs.mjs
2
+ * NeherApp3 root type definitions — the master reference for the shell's host
3
+ * API. Maintained by hand; `scripts/generate-dts.mjs` reads these typedefs and
4
+ * emits them into `index.d.ts`.
4
5
  */
5
6
 
6
7
  /** @typedef {import("./fluentApi.js").FluentApi} FluentApi */
@@ -69,6 +70,7 @@
69
70
  * @property {string | null} [parent] - Parent menu item (optional). If not set, the item will be added to the top level menu.
70
71
  * @property {boolean} [hidden] - If true, the menu item will not be displayed
71
72
  * @property {boolean} [separator] - If true, renders as a non-interactive divider between items (text/icon/url are ignored). Use `parent` to place the separator inside a sub-menu.
73
+ * @property {string} [i18nNamespace] - Catalog in which `text` is translated. Set automatically to the registering module's name; only pass it explicitly for items added outside `setup`. See `NeherApp3I18n`.
72
74
  */
73
75
 
74
76
  /**
@@ -156,6 +158,10 @@
156
158
  * In-realm message bus for module-to-module communication, exposed at
157
159
  * `neherapp3.messages`. Messaging, not RPC: `send`/`broadcast` return delivery
158
160
  * information, never a handler's result.
161
+ *
162
+ * Topics the shell itself broadcasts: `i18n.localeChanged` with payload
163
+ * `{ locale: string }` (sent with `retain: true`, so late subscribers receive
164
+ * the current language as well).
159
165
  * @typedef {Object} NeherApp3Messages
160
166
  * @property {(moduleName: string) => Endpoint} register - Register a module as a reachable endpoint.
161
167
  * @property {(to: string, type: string, payload?: any, options?: SendOptions) => Delivery} send - Directed message (`from` via `options.from`).
@@ -165,6 +171,189 @@
165
171
  * @property {string[]} reachable - Reactive list of all currently reachable module names.
166
172
  */
167
173
 
174
+ /**
175
+ * A translation table: key (the German source text) -> translation.
176
+ * @typedef {Record<string, string>} TranslationTable
177
+ */
178
+
179
+ /**
180
+ * Translation tables by BCP-47 language code, e.g. `{ en: { "Bestand": "Stock" } }`.
181
+ * @typedef {Record<string, TranslationTable>} TranslationCatalogs
182
+ */
183
+
184
+ /**
185
+ * Values for `{placeholder}` markers inside a translated text.
186
+ * @typedef {Record<string, string | number>} LocalizeParams
187
+ */
188
+
189
+ /**
190
+ * A language offered by the shell.
191
+ * @typedef {Object} NeherApp3LocaleInfo
192
+ * @property {string} code - BCP-47 code, e.g. `de`, `de-x-du`, `en`.
193
+ * @property {string} label - Display name in its own language.
194
+ */
195
+
196
+ /**
197
+ * Options for the `use:localize` action.
198
+ *
199
+ * Without options the action translates the element's own text nodes (child
200
+ * elements are left untouched) and every attribute listed in the element's
201
+ * `data-i18n` attribute, using each attribute's current value as the key.
202
+ * These fields cover everything that cannot be written statically in markup.
203
+ * @typedef {Object} LocalizeActionOptions
204
+ * @property {string} [text] - Key for the whole text content (replaces it).
205
+ * @property {string} [html] - Like `text`, but the translation contains markup.
206
+ * @property {LocalizeParams} [params] - Values for `{placeholder}` markers in text, html and attributes.
207
+ * @property {Record<string, string>} [attrs] - Attribute name -> key, for dynamic attribute values.
208
+ * @property {string} [ns] - Namespace to look in first (defaults to the endpoint's namespace, otherwise `shell`).
209
+ */
210
+
211
+ /**
212
+ * Return value of the `use:localize` action (a Svelte action handle).
213
+ * @typedef {Object} LocalizeActionHandle
214
+ * @property {(options?: LocalizeActionOptions) => void} update - Re-translate with new options (called by Svelte when the parameter changes).
215
+ * @property {() => void} destroy - Detach from language/catalog changes.
216
+ */
217
+
218
+ /**
219
+ * Dual-purpose translation entry point: pass a **key** to translate a string,
220
+ * pass a **DOM node** to use it as a Svelte action (`use:localize`).
221
+ *
222
+ * ```js
223
+ * localize("Speichern"); // -> "Save"
224
+ * localize("{n} Treffer", { n: 3 }); // placeholders
225
+ * ```
226
+ * ```svelte
227
+ * <h2 use:localize>Persönliche Daten</h2>
228
+ * <button title="Kopieren" use:localize data-i18n="title">…</button>
229
+ * ```
230
+ *
231
+ * @typedef {{
232
+ * (key: string, params?: LocalizeParams, namespace?: string): string;
233
+ * (node: Element, options?: LocalizeActionOptions): LocalizeActionHandle;
234
+ * }} Localize
235
+ */
236
+
237
+ /**
238
+ * A registered translation namespace, returned by `i18n.register`. `register`
239
+ * is idempotent; each handle's `dispose` only removes the tables added through
240
+ * it. Lookups fall back to the shell catalog, so shared terms such as
241
+ * "Speichern" need not be translated again per module.
242
+ * @typedef {Object} NeherApp3I18nEndpoint
243
+ * @property {string} namespace - The namespace of this handle (usually the module name).
244
+ * @property {Localize} localize - Translate in this namespace: as a function for script code, as a `use:` action for markup.
245
+ * @property {(translations: TranslationCatalogs) => void} add - Add further tables later (e.g. lazily loaded language files).
246
+ * @property {(key: string) => boolean} has - Is there a real translation (not just the key)?
247
+ * @property {() => void} dispose - Remove exactly the tables registered through this handle.
248
+ */
249
+
250
+ /**
251
+ * Localization, exposed at `neherapp3.i18n`.
252
+ *
253
+ * German is the source language and **the key is the German text**
254
+ * (`localize("Speichern")`); a missing translation falls back to the key, so an
255
+ * untranslated UI is never broken, just German. There is therefore no `de`
256
+ * catalog. The shell carries only its own texts (namespace `shell`); every
257
+ * module registers its own catalog under its module name.
258
+ * @typedef {Object} NeherApp3I18n
259
+ * @property {(namespace: string, translations?: TranslationCatalogs) => NeherApp3I18nEndpoint} register - Register a namespace's translation tables.
260
+ * @property {Localize} localize - Translate a key, or translate an element via `use:localize`.
261
+ * @property {(key: string, namespace?: string) => boolean} has - Is there a real translation for the key?
262
+ * @property {(a: string, b: string) => number} compare - Compare two **display texts** with the collator of the active language.
263
+ * @property {<T>(items: readonly T[], selector?: (item: T) => string) => T[]} sort - Sorted copy, ordered by the **translated** text (translate first, then sort).
264
+ * @property {(code: string) => void} setLocale - Switch the language and persist the choice.
265
+ * @property {(listener: (locale: string) => void) => (() => void)} onLocaleChange - Listen for language changes (for consumers without Svelte reactivity); returns an unsubscribe function.
266
+ * @property {string} sourceLocale - The source language — the keys themselves are texts in this language (`"de"`).
267
+ * @property {string} locale - Active language (reactive).
268
+ * @property {NeherApp3LocaleInfo[]} locales - Languages offered by the shell.
269
+ */
270
+
271
+ /**
272
+ * Settings handle of a single namespace — what
273
+ * `neherapp3.settings.register("my-module")` returns.
274
+ * @typedef {Object} NeherApp3SettingsHandle
275
+ * @property {string} namespace - The bound namespace (lower case).
276
+ * @property {(key: string, fallback?: any) => any} get - Value of a setting, or `fallback`. Reactive.
277
+ * @property {(key: string, value: unknown) => void} set - Store a value: applied locally at once, sent to the server coalesced.
278
+ * @property {(key: string) => void} remove - Drop a setting; the user is back to its default.
279
+ * @property {() => Record<string, unknown>} all - All settings of this namespace.
280
+ * @property {() => Promise<void>} flush - Write pending changes now. Call before a reload.
281
+ */
282
+
283
+ /**
284
+ * User settings, exposed at `neherapp3.settings`.
285
+ *
286
+ * The store is the **database**, not `localStorage`: inside the i3 WebView
287
+ * `localStorage` is ephemeral and would lose every setting on each start. A
288
+ * setting is addressed by namespace and key, both lower case; `shell` belongs
289
+ * to the framework, every module uses its own namespace — the same one it uses
290
+ * for `i18n.register`. Values are arbitrary JSON.
291
+ *
292
+ * Reads are reactive. Writes are applied locally at once and sent to the
293
+ * server after a short coalescing delay, so call `flush()` before a reload.
294
+ * @typedef {Object} NeherApp3Settings
295
+ * @property {string} scope - Namespace of the framework (`"shell"`).
296
+ * @property {boolean} loaded - `true` once the values from the database have arrived.
297
+ * @property {(namespace: string) => NeherApp3SettingsHandle} register - Settings handle bound to a module's namespace.
298
+ * @property {(scope: string, key: string, fallback?: any) => any} get - Value of a setting, or `fallback`. Reactive.
299
+ * @property {(scope: string, key: string, value: unknown) => void} set - Store a value.
300
+ * @property {(scope: string, key: string) => void} remove - Drop a setting.
301
+ * @property {(scope: string) => Record<string, unknown>} all - All settings of one namespace.
302
+ * @property {() => Promise<void>} flush - Write pending changes now. Call before a reload.
303
+ */
304
+
305
+ /**
306
+ * The profile of *another* user, as returned by `profile.byEmail` and friends.
307
+ *
308
+ * Identity comes from the platform's user table — whoever has signed in here at
309
+ * least once; the remaining fields are filled in only where that user curated
310
+ * them.
311
+ * @typedef {Object} NeherApp3PublicProfile
312
+ * @property {string} userId - The user's `benutzerGuid`.
313
+ * @property {string} userName - Login name.
314
+ * @property {string} email - E-mail address.
315
+ * @property {string | null} displayName - Self-chosen name shown in the interface.
316
+ * @property {string | null} initials - Self-chosen initials, up to 3 characters.
317
+ * @property {string | null} jobTitle - Job title / function.
318
+ * @property {string | null} department - Department.
319
+ * @property {string | null} location - Site / plant.
320
+ * @property {string | null} mobile - Mobile number.
321
+ * @property {string | null} avatar - The avatar as a data URL, or `null` when none is stored.
322
+ * @property {string | null} avatarUpdatedAt - When the avatar was last uploaded.
323
+ */
324
+
325
+ /**
326
+ * The signed-in user, exposed at `neherapp3.profile`.
327
+ *
328
+ * Two sources in one place: identity comes from the IDAS token (user id, login
329
+ * name, e-mail, roles, rights), the remaining fields from the platform's own
330
+ * profile table — above all the avatar, which IDAS does not carry.
331
+ *
332
+ * Read-only and reactive: the local fields arrive shortly after start and are
333
+ * edited in the framework's settings, not by a module. The same object carries
334
+ * the lookup of *other* users' profiles (`byEmail`, `byEmails`, `byUserId`) —
335
+ * the way to put a name and a face next to a user id in a list.
336
+ * @typedef {Object} NeherApp3Profile
337
+ * @property {string} userId - `benutzerGuid` from the token.
338
+ * @property {string} userName - Login name (`id` claim).
339
+ * @property {string} email - E-mail address from the token.
340
+ * @property {string[]} roles - Roles from the token.
341
+ * @property {string[]} rights - Rights from the token.
342
+ * @property {string} displayName - Best available name: the self-chosen one, otherwise the token's.
343
+ * @property {string} initials - Up to 3 characters: self-chosen, otherwise derived from the name.
344
+ * @property {string | null} avatar - The avatar as a data URL, or `null` when none is stored.
345
+ * @property {string | null} jobTitle - Job title / function.
346
+ * @property {string | null} department - Department.
347
+ * @property {string | null} location - Site / plant.
348
+ * @property {string | null} mobile - Mobile number (IDAS carries only one phone number).
349
+ * @property {boolean} loaded - `true` once the local profile has been fetched.
350
+ * @property {() => Promise<void>} reload - Fetch the local profile again.
351
+ * @property {(email: string) => Promise<NeherApp3PublicProfile | null>} byEmail - The profile of another user by e-mail address; `null` when this platform does not know them. Calls made close together are coalesced into one request and cached for the session.
352
+ * @property {(emails: string[]) => Promise<NeherApp3PublicProfile[]>} byEmails - The profiles of several users; unknown addresses are absent from the result.
353
+ * @property {(userId: string) => Promise<NeherApp3PublicProfile | null>} byUserId - The profile of another user by their `benutzerGuid`.
354
+ * @property {() => void} clearCache - Discard the cached profiles, so the next lookup asks again.
355
+ */
356
+
168
357
  /**
169
358
  * @typedef {Object} NeherApp3
170
359
  * @property {(menuItem: NeherApp3MenuItem) => void} addMenuItem - Adds a menu item. If an item with the same `id` already exists it is replaced.
@@ -175,6 +364,10 @@
175
364
  * @property {NeherApp3ApiCollection} api
176
365
  * @property {NeherApp3CacheCollection} cache
177
366
  * @property {NeherApp3Messages} messages - In-realm message bus for module-to-module communication.
367
+ * @property {NeherApp3I18n} i18n - Localization: register a module's translation catalog, translate, switch language, sort language-aware.
368
+ * @property {Localize} localize - Shorthand for `i18n.localize` (namespace `shell`): a function for strings, a `use:` action for elements.
369
+ * @property {NeherApp3Settings} settings - Per-user settings, stored in the database (not `localStorage`).
370
+ * @property {NeherApp3Profile} profile - The signed-in user: identity from the IDAS token plus the platform's own profile fields (avatar, job title, …).
178
371
  * @property {boolean} isEmbedded - Indicates if the app is embedded inside i3
179
372
  */
180
373
 
package/index.d.ts CHANGED
@@ -1847,6 +1847,26 @@ export type LieferzusageDTO = {
1847
1847
  ChangedDate: Date;
1848
1848
  };
1849
1849
 
1850
+ export type Localize = {
1851
+ (key: string, params?: LocalizeParams, namespace?: string): string;
1852
+ (node: Element, options?: LocalizeActionOptions): LocalizeActionHandle;
1853
+ };
1854
+
1855
+ export type LocalizeActionHandle = {
1856
+ update: (options?: LocalizeActionOptions) => void;
1857
+ destroy: () => void;
1858
+ };
1859
+
1860
+ export type LocalizeActionOptions = {
1861
+ text?: string;
1862
+ html?: string;
1863
+ params?: LocalizeParams;
1864
+ attrs?: Record<string, string>;
1865
+ ns?: string;
1866
+ };
1867
+
1868
+ export type LocalizeParams = Record<string, string | number>;
1869
+
1850
1870
  export type LoginAttemptDTO = {
1851
1871
  UserGuid: string;
1852
1872
  FailCount: number;
@@ -2055,6 +2075,10 @@ export type NeherApp3 = {
2055
2075
  api: NeherApp3ApiCollection;
2056
2076
  cache: NeherApp3CacheCollection;
2057
2077
  messages: NeherApp3Messages;
2078
+ i18n: NeherApp3I18n;
2079
+ localize: Localize;
2080
+ settings: NeherApp3Settings;
2081
+ profile: NeherApp3Profile;
2058
2082
  isEmbedded: boolean;
2059
2083
  };
2060
2084
 
@@ -2084,6 +2108,32 @@ export type NeherApp3ErfassungCache = {
2084
2108
  createUIMachine: (v: Variante) => void;
2085
2109
  };
2086
2110
 
2111
+ export type NeherApp3I18n = {
2112
+ register: (namespace: string, translations?: TranslationCatalogs) => NeherApp3I18nEndpoint;
2113
+ localize: Localize;
2114
+ has: (key: string, namespace?: string) => boolean;
2115
+ compare: (a: string, b: string) => number;
2116
+ sort: <T>(items: readonly T[], selector?: (item: T) => string) => T[];
2117
+ setLocale: (code: string) => void;
2118
+ onLocaleChange: (listener: (locale: string) => void) => (() => void);
2119
+ sourceLocale: string;
2120
+ locale: string;
2121
+ locales: NeherApp3LocaleInfo[];
2122
+ };
2123
+
2124
+ export type NeherApp3I18nEndpoint = {
2125
+ namespace: string;
2126
+ localize: Localize;
2127
+ add: (translations: TranslationCatalogs) => void;
2128
+ has: (key: string) => boolean;
2129
+ dispose: () => void;
2130
+ };
2131
+
2132
+ export type NeherApp3LocaleInfo = {
2133
+ code: string;
2134
+ label: string;
2135
+ };
2136
+
2087
2137
  export type NeherApp3MenuItem = {
2088
2138
  id?: string;
2089
2139
  selected?: boolean;
@@ -2094,6 +2144,7 @@ export type NeherApp3MenuItem = {
2094
2144
  parent?: string | null;
2095
2145
  hidden?: boolean;
2096
2146
  separator?: boolean;
2147
+ i18nNamespace?: string;
2097
2148
  };
2098
2149
 
2099
2150
  export type NeherApp3Messages = {
@@ -2116,6 +2167,27 @@ export type NeherApp3Module = {
2116
2167
 
2117
2168
  export type NeherApp3NotifyType = 0 | 1 | 2;
2118
2169
 
2170
+ export type NeherApp3Profile = {
2171
+ userId: string;
2172
+ userName: string;
2173
+ email: string;
2174
+ roles: string[];
2175
+ rights: string[];
2176
+ displayName: string;
2177
+ initials: string;
2178
+ avatar: string | null;
2179
+ jobTitle: string | null;
2180
+ department: string | null;
2181
+ location: string | null;
2182
+ mobile: string | null;
2183
+ loaded: boolean;
2184
+ reload: () => Promise<void>;
2185
+ byEmail: (email: string) => Promise<NeherApp3PublicProfile | null>;
2186
+ byEmails: (emails: string[]) => Promise<NeherApp3PublicProfile[]>;
2187
+ byUserId: (userId: string) => Promise<NeherApp3PublicProfile | null>;
2188
+ clearCache: () => void;
2189
+ };
2190
+
2119
2191
  export type NeherApp3Props = {
2120
2192
  api: FluentApi;
2121
2193
  authManager?: FluentAuthManager;
@@ -2123,6 +2195,40 @@ export type NeherApp3Props = {
2123
2195
  mainCssPath?: string;
2124
2196
  };
2125
2197
 
2198
+ export type NeherApp3PublicProfile = {
2199
+ userId: string;
2200
+ userName: string;
2201
+ email: string;
2202
+ displayName: string | null;
2203
+ initials: string | null;
2204
+ jobTitle: string | null;
2205
+ department: string | null;
2206
+ location: string | null;
2207
+ mobile: string | null;
2208
+ avatar: string | null;
2209
+ avatarUpdatedAt: string | null;
2210
+ };
2211
+
2212
+ export type NeherApp3Settings = {
2213
+ scope: string;
2214
+ loaded: boolean;
2215
+ register: (namespace: string) => NeherApp3SettingsHandle;
2216
+ get: (scope: string, key: string, fallback?: any) => any;
2217
+ set: (scope: string, key: string, value: unknown) => void;
2218
+ remove: (scope: string, key: string) => void;
2219
+ all: (scope: string) => Record<string, unknown>;
2220
+ flush: () => Promise<void>;
2221
+ };
2222
+
2223
+ export type NeherApp3SettingsHandle = {
2224
+ namespace: string;
2225
+ get: (key: string, fallback?: any) => any;
2226
+ set: (key: string, value: unknown) => void;
2227
+ remove: (key: string) => void;
2228
+ all: () => Record<string, unknown>;
2229
+ flush: () => Promise<void>;
2230
+ };
2231
+
2126
2232
  export type NeherApp3SetupContext = NeherApp3Props & { neherapp3: NeherApp3 };
2127
2233
 
2128
2234
  export type NeherMessage = {
@@ -2832,6 +2938,10 @@ export type TemplateDTO = {
2832
2938
  Benutzer: string;
2833
2939
  };
2834
2940
 
2941
+ export type TranslationCatalogs = Record<string, TranslationTable>;
2942
+
2943
+ export type TranslationTable = Record<string, string>;
2944
+
2835
2945
  export type TypePattern = string | string[];
2836
2946
 
2837
2947
  export type UiApi = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gandalan/weblibs",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "WebLibs for Gandalan JS/TS projects",
5
5
  "keywords": [
6
6
  "gandalan"