@burdenoff/fe-libs 2026.918.2 → 2026.920.1

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.
Files changed (29) hide show
  1. package/dist/shared/assistant/adminModeSendGate.d.ts +43 -0
  2. package/dist/shared/assistant/adminModeSendGate.d.ts.map +1 -1
  3. package/dist/shared/assistant/adminModeSendGate.js +33 -18
  4. package/dist/shared/assistant/i18nManifest.d.ts +5 -0
  5. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  6. package/dist/shared/assistant/i18nManifest.js +6 -1
  7. package/dist/shared/assistant/index.d.ts +1 -0
  8. package/dist/shared/assistant/index.d.ts.map +1 -1
  9. package/dist/shared/assistant/modeCapabilities.d.ts +25 -0
  10. package/dist/shared/assistant/modeCapabilities.d.ts.map +1 -1
  11. package/dist/shared/assistant/modeCapabilities.js +6 -2
  12. package/dist/shared/assistant/store.d.ts +26 -5
  13. package/dist/shared/assistant/store.d.ts.map +1 -1
  14. package/dist/shared/assistant/store.js +28 -18
  15. package/dist/shared/assistant/ui/AssistantApiCallsConsentDialog.d.ts +27 -10
  16. package/dist/shared/assistant/ui/AssistantApiCallsConsentDialog.d.ts.map +1 -1
  17. package/dist/shared/assistant/ui/AssistantApiCallsConsentDialog.js +22 -16
  18. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  19. package/dist/shared/assistant/ui/AssistantChatArea.js +363 -347
  20. package/dist/shared/assistant/writeModeConsent.d.ts +99 -0
  21. package/dist/shared/assistant/writeModeConsent.d.ts.map +1 -0
  22. package/dist/shared/assistant/writeModeConsent.js +48 -0
  23. package/dist/shared/providers/shell/I18nProvider.d.ts.map +1 -1
  24. package/dist/shared/providers/shell/I18nProvider.js +33 -39
  25. package/dist/shared/providers/shell/resolveTranslation.d.ts +23 -0
  26. package/dist/shared/providers/shell/resolveTranslation.d.ts.map +1 -0
  27. package/dist/shared/providers/shell/resolveTranslation.js +11 -0
  28. package/dist/shared-assistant.js +110 -109
  29. package/package.json +2 -2
@@ -0,0 +1,99 @@
1
+ import { AssistantModeConfig } from './conversation';
2
+ import { AssistantTr } from './i18n';
3
+ import { AssistantMode } from './types';
4
+ /**
5
+ * The single flag this module replaces, as it sits in storage written by
6
+ * fe-libs 2026.919.1 and earlier.
7
+ */
8
+ export declare const LEGACY_WRITE_CONSENT_KEY = "apiCallsAcknowledged";
9
+ /**
10
+ * The write-capable modes this profile has accepted, read back from storage.
11
+ *
12
+ * - A stored list is kept, minus anything that is not a mode id and any repeat.
13
+ * Storage is data from another build, so it is checked, not trusted.
14
+ * - Otherwise a stored legacy flag of exactly `true` becomes `["api-calls"]`.
15
+ * - Otherwise nothing is acknowledged.
16
+ *
17
+ * ★ A stored list WINS over the legacy flag, and is never merged with it. This
18
+ * build never writes the flag, and an older build drops the list the next time
19
+ * it persists (its `partialize` does not know the key), so the two are not
20
+ * stored side by side by either. Should they ever be, the list is the newer
21
+ * decision. After a rollback and a roll-forward, the flag the older build wrote
22
+ * is migrated again, exactly as on first upgrade.
23
+ */
24
+ export declare function restoreAcknowledgedWriteModes(persisted: unknown): AssistantMode[];
25
+ /** Has this profile accepted the write consent for `mode`? */
26
+ export declare function isWriteModeAcknowledged(acknowledged: readonly AssistantMode[], mode: AssistantMode): boolean;
27
+ /** Send-time consent and voice checks against the validated post-wait mode. */
28
+ export declare function writeModeSendRefusal(mode: AssistantMode, config: Pick<AssistantModeConfig, "writeCapable"> | undefined, acknowledged: readonly AssistantMode[], { dictated, confirmsWrites }: {
29
+ dictated: boolean;
30
+ confirmsWrites: boolean;
31
+ }): string | null;
32
+ /** `acknowledged` plus `mode`, unchanged (same array) if it is already there. */
33
+ export declare function withWriteModeAcknowledged(acknowledged: readonly AssistantMode[], mode: AssistantMode): readonly AssistantMode[];
34
+ /** A mode as the dialog needs it: the product's config, or just an id. */
35
+ export type WriteConsentMode = Pick<AssistantModeConfig, "id"> & Partial<Pick<AssistantModeConfig, "label" | "producesArtifacts">>;
36
+ /** Every line of the dialog, already translated. */
37
+ export interface WriteModeConsentCopy {
38
+ title: string;
39
+ body: string;
40
+ /** Whether the assistant stops for approval before a change — true or false, said plainly. */
41
+ safeguard: string;
42
+ confirm: string;
43
+ cancel: string;
44
+ }
45
+ /**
46
+ * fe-libs' own English for the `apiCalls.consent*` keys — the exact strings the
47
+ * `tr()` calls in `writeModeConsentCopy` pass as their fallbacks.
48
+ *
49
+ * ★ Written out twice ON PURPOSE. `i18nManifest.test.ts` reads the fallback
50
+ * ARGUMENT of every `tr()` call with the TypeScript parser, so a call site that
51
+ * passed this table's value instead of a literal would drop out of the manifest
52
+ * — and a key missing from the manifest is a key no product seeds, which is how
53
+ * a string silently goes English in every locale. That test pins each call site
54
+ * to the manifest, and `writeModeConsent.test.ts` pins this table to the
55
+ * manifest too, so the three cannot drift apart without CI failing.
56
+ */
57
+ export declare const TAKE_ACTION_ENGLISH: {
58
+ readonly "apiCalls.consentTitle": "Switch to Take action mode?";
59
+ readonly "apiCalls.consentBody": "In Take action mode the assistant can read AND change your data — creating records, logging activity, updating details, and more, on your behalf.";
60
+ readonly "apiCalls.consentConfirm": "Enable Take action";
61
+ readonly "apiCalls.consentCancel": "Stay in Ask";
62
+ };
63
+ /** A consent key whose English fe-libs writes itself. */
64
+ export type TakeActionConsentKey = keyof typeof TAKE_ACTION_ENGLISH;
65
+ /**
66
+ * What the consent dialog says when switching from `current` into `target`.
67
+ *
68
+ * ★★ A PRODUCT'S OWN WORDS ALWAYS WIN. `apiCalls.consent*` predate per-mode
69
+ * wording, and products have seeded them: FluidGrids authored all five in six
70
+ * languages FOR ITS OWN NAME for `api-calls` ("In Workflow mode … your
71
+ * FluidGrids data"), HealthyBowl's body names "your HealthyBowl data". So for
72
+ * `api-calls` those keys are asked FIRST, and whatever comes back that is not
73
+ * fe-libs' own English is what renders — in the reader's language, byte for
74
+ * byte as before this change.
75
+ *
76
+ * ★★ `writeConsent.*` renders only where there is no product copy to lose: a
77
+ * mode that is not `api-calls` (a build mode has no seeded consent copy at all),
78
+ * or an `api-calls` whose dictionary gave our own sentence back. It says the
79
+ * same thing through `{{mode}}`, which names the mode as its pill does — so a
80
+ * product that calls `api-calls` "Build" stops being told "Take action" without
81
+ * any product's translation turning English.
82
+ *
83
+ * ★ The cancel button keeps `apiCalls.consentCancel` ("Stay in Ask") only when
84
+ * the mode being LEFT is the one called Ask — that sentence is about `current`,
85
+ * not `target`. Leaving Build names Build.
86
+ *
87
+ * ★★ `confirmsWrites` decides the safeguard line, and the caller must derive it
88
+ * from what the SANDBOX does (`modeRequiresConfirmWrites`), never from a product
89
+ * flag. The old dialog promised a confirmation step for every write-capable
90
+ * mode; only `api-calls` boots with AI_ASSISTANT_CONFIRM_WRITES, so for any
91
+ * other mode that promise was false. It now says the opposite, plainly.
92
+ */
93
+ export declare function writeModeConsentCopy(tr: AssistantTr, { target, current, confirmsWrites, }: {
94
+ target: WriteConsentMode;
95
+ /** The mode being left; absent is read as Ask, the mode everyone starts in. */
96
+ current?: WriteConsentMode | null;
97
+ confirmsWrites: boolean;
98
+ }): WriteModeConsentCopy;
99
+ //# sourceMappingURL=writeModeConsent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeModeConsent.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/writeModeConsent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAM1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAc/D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,OAAO,GAAG,aAAa,EAAE,CAiBjF;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,SAAS,aAAa,EAAE,EACtC,IAAI,EAAE,aAAa,GAClB,OAAO,CAET;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,cAAc,CAAC,GAAG,SAAS,EAC7D,YAAY,EAAE,SAAS,aAAa,EAAE,EACtC,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,GAC3E,MAAM,GAAG,IAAI,CAQf;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,SAAS,aAAa,EAAE,EACtC,IAAI,EAAE,aAAa,GAClB,SAAS,aAAa,EAAE,CAE1B;AAED,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,GAC5D,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,mBAAmB,CAAC,CAAC,CAAC;AAEpE,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAmBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB;;;;;CAMtB,CAAC;AAEX,yDAAyD;AACzD,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAuBpE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,EACE,MAAM,EACN,OAAO,EACP,cAAc,GACf,EAAE;IACD,MAAM,EAAE,gBAAgB,CAAC;IACzB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,cAAc,EAAE,OAAO,CAAC;CACzB,GACA,oBAAoB,CA+DtB"}
@@ -0,0 +1,48 @@
1
+ import { ASSISTANT_MODE_FALLBACK_LABELS as e, assistantModeFallbackLabel as t } from "./modeCopy.js";
2
+ import { isAssistantModeId as n } from "./modeIds.js";
3
+ //#region src/shared/assistant/writeModeConsent.ts
4
+ var r = "apiCallsAcknowledged", i = "api-calls";
5
+ function a(e) {
6
+ if (typeof e != "object" || !e) return [];
7
+ let t = Object.fromEntries(Object.entries(e)), r = t.acknowledgedWriteModes;
8
+ if (Array.isArray(r)) {
9
+ let e = /* @__PURE__ */ new Set();
10
+ for (let t of r) n(t) && e.add(t);
11
+ return [...e];
12
+ }
13
+ return t.apiCallsAcknowledged === !0 ? [i] : [];
14
+ }
15
+ function o(e, t) {
16
+ return e.includes(t);
17
+ }
18
+ function s(e, t, n, { dictated: r, confirmsWrites: i }) {
19
+ return t?.writeCapable && !o(n, e) ? "Confirm this assistant mode before sending: choose it again in the mode selector." : r && (t?.writeCapable || i) ? "Voice can't be used in a mode that can change your data. Type your request instead." : null;
20
+ }
21
+ function c(e, t) {
22
+ return e.includes(t) ? e : [...e, t];
23
+ }
24
+ function l(e, n) {
25
+ return e(`mode.${n.id}`, n.label || t(n));
26
+ }
27
+ var u = (e, n) => (e.label || t(e)) === n, d = {
28
+ "apiCalls.consentTitle": "Switch to Take action mode?",
29
+ "apiCalls.consentBody": "In Take action mode the assistant can read AND change your data — creating records, logging activity, updating details, and more, on your behalf.",
30
+ "apiCalls.consentConfirm": "Enable Take action",
31
+ "apiCalls.consentCancel": "Stay in Ask"
32
+ };
33
+ function f(e, t) {
34
+ return t === d[e] ? null : t;
35
+ }
36
+ var p = { id: "assistant" };
37
+ function m(t, { target: n, current: r, confirmsWrites: i }) {
38
+ let a = l(t, n), o = n.id === "api-calls", s = !r || u(r, e.assistant);
39
+ return {
40
+ title: (o ? f("apiCalls.consentTitle", t("apiCalls.consentTitle", "Switch to Take action mode?")) : null) ?? t("writeConsent.title", "Switch to {{mode}} mode?", { mode: a }),
41
+ body: (o ? f("apiCalls.consentBody", t("apiCalls.consentBody", "In Take action mode the assistant can read AND change your data — creating records, logging activity, updating details, and more, on your behalf.")) : null) ?? t("writeConsent.body", "In {{mode}} mode the assistant can read AND change your data — creating records, logging activity, updating details, and more, on your behalf.", { mode: a }),
42
+ safeguard: i ? t("apiCalls.consentBody2", "It will describe what it is about to do and ask you to confirm before making a change. Only continue if you want the assistant to take actions for you.") : t("writeConsent.unconfirmed", "It does not stop to ask before each change — it makes changes as soon as it decides to. Only continue if you want the assistant to change your data without asking first."),
43
+ confirm: (o ? f("apiCalls.consentConfirm", t("apiCalls.consentConfirm", "Enable Take action")) : null) ?? t("writeConsent.confirm", "Enable {{mode}}", { mode: a }),
44
+ cancel: (s ? f("apiCalls.consentCancel", t("apiCalls.consentCancel", "Stay in Ask")) : null) ?? t("writeConsent.cancel", "Stay in {{mode}}", { mode: l(t, r ?? p) })
45
+ };
46
+ }
47
+ //#endregion
48
+ export { r as LEGACY_WRITE_CONSENT_KEY, d as TAKE_ACTION_ENGLISH, o as isWriteModeAcknowledged, a as restoreAcknowledgedWriteModes, c as withWriteModeAcknowledged, m as writeModeConsentCopy, s as writeModeSendRefusal };
@@ -1 +1 @@
1
- {"version":3,"file":"I18nProvider.d.ts","sourceRoot":"","sources":["../../../../src/shared/providers/shell/I18nProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAWlF,MAAM,WAAW,qBAAqB;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,qBAAqB,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,CAAC,EAAE,CACD,GAAG,EAAE,MAAM,EACX,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACrC,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAID;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;CAC9B;AA2FD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,qBAAqB,GAAG,SAAS,EACvC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,GAC1C,qBAAqB,CAsBvB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,aAAoB,EACpB,YAAY,EAAE,kBAAyC,EACvD,UAA+B,EAC/B,SAAS,EACT,iBAAiB,EACjB,wBAA+B,EAC/B,gBAAgB,GACjB,EAAE,iBAAiB,2CAwMnB;AAED,wBAAgB,OAAO,qBAMtB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D"}
1
+ {"version":3,"file":"I18nProvider.d.ts","sourceRoot":"","sources":["../../../../src/shared/providers/shell/I18nProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAWlF,MAAM,WAAW,qBAAqB;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,qBAAqB,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,CAAC,EAAE,CACD,GAAG,EAAE,MAAM,EACX,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACrC,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAID;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;CAC9B;AAoED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,qBAAqB,GAAG,SAAS,EACvC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,GAC1C,qBAAqB,CAsBvB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,aAAoB,EACpB,YAAY,EAAE,kBAAyC,EACvD,UAA+B,EAC/B,SAAS,EACT,iBAAiB,EACjB,wBAA+B,EAC/B,gBAAgB,GACjB,EAAE,iBAAiB,2CAwMnB;AAED,wBAAgB,OAAO,qBAMtB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D"}
@@ -1,8 +1,9 @@
1
1
  import { interpolate as e } from "./interpolate.js";
2
- import { createContext as t, use as n, useCallback as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
3
- import { Fragment as c, jsx as l } from "react/jsx-runtime";
2
+ import { resolveTranslationValue as t } from "./resolveTranslation.js";
3
+ import { createContext as n, use as r, useCallback as i, useEffect as a, useMemo as o, useRef as s, useState as c } from "react";
4
+ import { Fragment as l, jsx as u } from "react/jsx-runtime";
4
5
  //#region src/shared/providers/shell/I18nProvider.tsx
5
- var u = t(null), d = {
6
+ var d = n(null), f = {
6
7
  en: {},
7
8
  es: {},
8
9
  fr: {},
@@ -12,7 +13,7 @@ var u = t(null), d = {
12
13
  ta: {},
13
14
  hi: {},
14
15
  ar: {}
15
- }, f = {
16
+ }, p = {
16
17
  attempted: /* @__PURE__ */ new Set(),
17
18
  translations: {},
18
19
  version: 0,
@@ -20,7 +21,7 @@ var u = t(null), d = {
20
21
  this.attempted.clear(), this.translations = {}, this.version++;
21
22
  }
22
23
  };
23
- function p(e, t, n) {
24
+ function m(e, t, n) {
24
25
  if (typeof window > "u") return n;
25
26
  if (e) {
26
27
  let t = localStorage.getItem(`bf-p-${e}-locale`);
@@ -28,13 +29,6 @@ function p(e, t, n) {
28
29
  }
29
30
  return localStorage.getItem(t) || n;
30
31
  }
31
- function m(e, t) {
32
- if (!e) return;
33
- let n = t.split("."), r = e;
34
- for (let e of n) if (typeof r == "object" && r && e in r) r = r[e];
35
- else return;
36
- return typeof r == "string" ? r : void 0;
37
- }
38
32
  function h(e) {
39
33
  return typeof e == "object" && !!e;
40
34
  }
@@ -53,18 +47,18 @@ function g(e, t) {
53
47
  }
54
48
  return n;
55
49
  }
56
- function _({ children: t, defaultLocale: n = "en", translations: h = d, storageKey: _ = "burdenoff-locale", profileId: v, fetchTranslations: y, showChildrenWhileLoading: b = !0, loadingComponent: x }) {
57
- let [S, C] = s(() => p(v, _, n)), [w, T] = s({}), [E, D] = s(!!y), [O, k] = s(null), A = o(/* @__PURE__ */ new Set()), j = o(f.version), M = a(() => {
50
+ function _({ children: n, defaultLocale: r = "en", translations: h = f, storageKey: _ = "burdenoff-locale", profileId: v, fetchTranslations: y, showChildrenWhileLoading: b = !0, loadingComponent: x }) {
51
+ let [S, C] = c(() => m(v, _, r)), [w, T] = c({}), [E, D] = c(!!y), [O, k] = c(null), A = s(/* @__PURE__ */ new Set()), j = s(p.version), M = o(() => {
58
52
  let e = { ...h };
59
53
  for (let [t, n] of Object.entries(w)) if (n && Object.keys(n).length > 0) {
60
54
  let r = t;
61
55
  e[r] = g(h[r], n);
62
56
  }
63
57
  return e;
64
- }, [h, w]), N = r(async (e) => {
58
+ }, [h, w]), N = i(async (e) => {
65
59
  if (y) {
66
- if (j.current !== f.version && (A.current.clear(), j.current = f.version), f.attempted.has(e)) {
67
- let t = f.translations[e];
60
+ if (j.current !== p.version && (A.current.clear(), j.current = p.version), p.attempted.has(e)) {
61
+ let t = p.translations[e];
68
62
  t && Object.keys(t).length > 0 && T((n) => !n[e] || Object.keys(n[e]).length === 0 ? {
69
63
  ...n,
70
64
  [e]: t
@@ -75,7 +69,7 @@ function _({ children: t, defaultLocale: n = "en", translations: h = d, storageK
75
69
  A.current.add(e), D(!0), k(null);
76
70
  try {
77
71
  let t = await y(e);
78
- t && Object.keys(t).length > 0 && (f.attempted.add(e), f.translations[e] = t), T((n) => ({
72
+ t && Object.keys(t).length > 0 && (p.attempted.add(e), p.translations[e] = t), T((n) => ({
79
73
  ...n,
80
74
  [e]: t
81
75
  }));
@@ -87,36 +81,36 @@ function _({ children: t, defaultLocale: n = "en", translations: h = d, storageK
87
81
  }
88
82
  }
89
83
  }, [y]);
90
- i(() => {
91
- y && (f.attempted.has(S) && f.translations[S] && Object.keys(f.translations[S]).length > 0 || N(S));
84
+ a(() => {
85
+ y && (p.attempted.has(S) && p.translations[S] && Object.keys(p.translations[S]).length > 0 || N(S));
92
86
  }, [
93
87
  y,
94
88
  S,
95
89
  N
96
- ]), i(() => {
97
- let e = p(v, _, n);
90
+ ]), a(() => {
91
+ let e = m(v, _, r);
98
92
  C(e), document.documentElement.setAttribute("lang", e);
99
93
  }, [
100
94
  v,
101
95
  _,
102
- n
96
+ r
103
97
  ]);
104
- let P = r((e) => {
98
+ let P = i((e) => {
105
99
  C(e), localStorage.setItem(_, e), v && localStorage.setItem(`bf-p-${v}-locale`, e), document.documentElement.setAttribute("lang", e);
106
- }, [_, v]), F = r((t, r, i) => {
107
- let a, o;
108
- if (typeof r == "string") a = r, o = i;
109
- else if (r && typeof r == "object") {
110
- let { defaultValue: e, ...t } = r;
111
- typeof e == "string" ? a = e : typeof e == "number" && (a = String(e)), o = t;
100
+ }, [_, v]), F = i((n, i, a) => {
101
+ let o, s;
102
+ if (typeof i == "string") o = i, s = a;
103
+ else if (i && typeof i == "object") {
104
+ let { defaultValue: e, ...t } = i;
105
+ typeof e == "string" ? o = e : typeof e == "number" && (o = String(e)), s = t;
112
106
  }
113
- let s = m(M[S], t) ?? (S === n ? void 0 : m(M[n], t)) ?? (n === "en" ? void 0 : m(M.en, t)) ?? a ?? t;
114
- return o ? e(s, o) : s;
107
+ let c = t(M[S], n) ?? (S === r ? void 0 : t(M[r], n)) ?? (r === "en" ? void 0 : t(M.en, n)) ?? o ?? n;
108
+ return s ? e(c, s) : c;
115
109
  }, [
116
110
  S,
117
111
  M,
118
- n
119
- ]), I = a(() => ({
112
+ r
113
+ ]), I = o(() => ({
120
114
  locale: S,
121
115
  translations: M[S] || {},
122
116
  setLocale: P,
@@ -131,21 +125,21 @@ function _({ children: t, defaultLocale: n = "en", translations: h = d, storageK
131
125
  E,
132
126
  O
133
127
  ]);
134
- return E && !b && x ? /* @__PURE__ */ l(c, { children: x }) : /* @__PURE__ */ l(u.Provider, {
128
+ return E && !b && x ? /* @__PURE__ */ u(l, { children: x }) : /* @__PURE__ */ u(d.Provider, {
135
129
  value: I,
136
- children: t
130
+ children: n
137
131
  });
138
132
  }
139
133
  function v() {
140
- let e = n(u);
134
+ let e = r(d);
141
135
  if (!e) throw Error("useI18n must be used within an I18nProvider");
142
136
  return e;
143
137
  }
144
138
  function y() {
145
- f.clear();
139
+ p.clear();
146
140
  }
147
141
  function b(e) {
148
- return f.attempted.has(e);
142
+ return p.attempted.has(e);
149
143
  }
150
144
  //#endregion
151
145
  export { _ as I18nProvider, y as clearTranslationCache, b as isTranslationAttempted, g as mergeTranslationDictionaries, v as useI18n };
@@ -0,0 +1,23 @@
1
+ import { TranslationDictionary } from './I18nProvider';
2
+ /**
3
+ * Where a nested dictionary keeps the value of a key that is ALSO a branch.
4
+ *
5
+ * `healthybowl.common.confirm` ("Confirm") and `healthybowl.common.confirm.title`
6
+ * ("Are you sure?") cannot both live at one path of a nested object, so the
7
+ * leaf is stored beside its children as `confirm._`. The product extractors
8
+ * write that slot, the seed stores such a key literally as `….confirm._`, and
9
+ * the i18n export serves it nested — so the translation already reaches the
10
+ * client. Nothing read it: `t('healthybowl.common.confirm')` walked to the
11
+ * object and returned undefined, and the call site's inline English rendered
12
+ * in every locale (13 HealthyBowl keys, BOFF-7438; BOFF-7459).
13
+ */
14
+ export declare const LEAF_SLOT = "_";
15
+ /**
16
+ * Resolve a dot-notated translation key from a dictionary: the string at that
17
+ * path, or — when the path names a branch — the string in its `_` slot.
18
+ *
19
+ * A branch with no `_` string still resolves to undefined, so the caller's
20
+ * fallback renders rather than "[object Object]".
21
+ */
22
+ export declare function resolveTranslationValue(dictionary: TranslationDictionary | undefined, key: string): string | undefined;
23
+ //# sourceMappingURL=resolveTranslation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveTranslation.d.ts","sourceRoot":"","sources":["../../../../src/shared/providers/shell/resolveTranslation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,MAAM,CAAC;AAE7B;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,qBAAqB,GAAG,SAAS,EAC7C,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAgBpB"}
@@ -0,0 +1,11 @@
1
+ function e(e, t) {
2
+ if (!e) return;
3
+ let n = e;
4
+ for (let e of t.split(".")) if (typeof n == "object" && n && e in n) n = n[e];
5
+ else return;
6
+ if (typeof n == "string") return n;
7
+ let r = typeof n == "object" && n ? n._ : void 0;
8
+ return typeof r == "string" ? r : void 0;
9
+ }
10
+ //#endregion
11
+ export { e as resolveTranslationValue };