@jini-ai/cms 0.5.4 → 0.5.5

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 (113) hide show
  1. package/dist/navigation/agent-tools.js +20 -3
  2. package/dist/navigation/index.d.ts +3 -1
  3. package/dist/navigation/index.js +2 -0
  4. package/dist/navigation/menu-html.d.ts +31 -0
  5. package/dist/navigation/menu-html.js +53 -0
  6. package/dist/navigation/menu-service.d.ts +9 -3
  7. package/dist/navigation/menu-service.js +15 -3
  8. package/dist/navigation/tool-registrations.d.ts +5 -0
  9. package/dist/navigation/tool-registrations.js +32 -2
  10. package/dist/navigation/types.d.ts +6 -0
  11. package/dist/widgets/resolvers/menu.d.ts +8 -0
  12. package/dist/widgets/resolvers/menu.js +21 -6
  13. package/package.json +3 -3
  14. package/dist/http/settings/cms-adapter.d.ts +0 -20
  15. package/dist/http/settings/cms-adapter.js +0 -124
  16. package/dist/http/settings/contracts.d.ts +0 -135
  17. package/dist/http/settings/contracts.js +0 -2
  18. package/dist/http/settings/http.d.ts +0 -10
  19. package/dist/http/settings/http.js +0 -211
  20. package/dist/http/settings/index.d.ts +0 -5
  21. package/dist/http/settings/index.js +0 -4
  22. package/dist/http/settings/shared.d.ts +0 -68
  23. package/dist/http/settings/shared.js +0 -54
  24. package/dist/http/settings/stream.d.ts +0 -24
  25. package/dist/http/settings/stream.js +0 -147
  26. package/dist/settings/agent-tools.d.ts +0 -10
  27. package/dist/settings/agent-tools.js +0 -204
  28. package/dist/settings/agent-value-write-tools.d.ts +0 -22
  29. package/dist/settings/agent-value-write-tools.js +0 -154
  30. package/dist/settings/agent-writable-preferences.d.ts +0 -67
  31. package/dist/settings/agent-writable-preferences.js +0 -132
  32. package/dist/settings/agent-write-denylist.d.ts +0 -19
  33. package/dist/settings/agent-write-denylist.js +0 -15
  34. package/dist/settings/change-feed.d.ts +0 -83
  35. package/dist/settings/change-feed.js +0 -61
  36. package/dist/settings/definitions-dispatch.d.ts +0 -56
  37. package/dist/settings/definitions-dispatch.js +0 -86
  38. package/dist/settings/dictionaries/index.d.ts +0 -48
  39. package/dist/settings/dictionaries/index.js +0 -69
  40. package/dist/settings/dictionaries/settings-dialog.ar.d.ts +0 -3
  41. package/dist/settings/dictionaries/settings-dialog.ar.js +0 -27
  42. package/dist/settings/dictionaries/settings-dialog.bn.d.ts +0 -3
  43. package/dist/settings/dictionaries/settings-dialog.bn.js +0 -27
  44. package/dist/settings/dictionaries/settings-dialog.de.d.ts +0 -3
  45. package/dist/settings/dictionaries/settings-dialog.de.js +0 -27
  46. package/dist/settings/dictionaries/settings-dialog.es.d.ts +0 -3
  47. package/dist/settings/dictionaries/settings-dialog.es.js +0 -27
  48. package/dist/settings/dictionaries/settings-dialog.fa.d.ts +0 -3
  49. package/dist/settings/dictionaries/settings-dialog.fa.js +0 -27
  50. package/dist/settings/dictionaries/settings-dialog.fr.d.ts +0 -3
  51. package/dist/settings/dictionaries/settings-dialog.fr.js +0 -27
  52. package/dist/settings/dictionaries/settings-dialog.hi.d.ts +0 -3
  53. package/dist/settings/dictionaries/settings-dialog.hi.js +0 -27
  54. package/dist/settings/dictionaries/settings-dialog.hu.d.ts +0 -3
  55. package/dist/settings/dictionaries/settings-dialog.hu.js +0 -27
  56. package/dist/settings/dictionaries/settings-dialog.id.d.ts +0 -3
  57. package/dist/settings/dictionaries/settings-dialog.id.js +0 -27
  58. package/dist/settings/dictionaries/settings-dialog.it.d.ts +0 -3
  59. package/dist/settings/dictionaries/settings-dialog.it.js +0 -27
  60. package/dist/settings/dictionaries/settings-dialog.ja.d.ts +0 -3
  61. package/dist/settings/dictionaries/settings-dialog.ja.js +0 -27
  62. package/dist/settings/dictionaries/settings-dialog.ko.d.ts +0 -3
  63. package/dist/settings/dictionaries/settings-dialog.ko.js +0 -27
  64. package/dist/settings/dictionaries/settings-dialog.pl.d.ts +0 -3
  65. package/dist/settings/dictionaries/settings-dialog.pl.js +0 -27
  66. package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts +0 -3
  67. package/dist/settings/dictionaries/settings-dialog.pt-BR.js +0 -27
  68. package/dist/settings/dictionaries/settings-dialog.ru.d.ts +0 -3
  69. package/dist/settings/dictionaries/settings-dialog.ru.js +0 -27
  70. package/dist/settings/dictionaries/settings-dialog.th.d.ts +0 -3
  71. package/dist/settings/dictionaries/settings-dialog.th.js +0 -27
  72. package/dist/settings/dictionaries/settings-dialog.tr.d.ts +0 -3
  73. package/dist/settings/dictionaries/settings-dialog.tr.js +0 -27
  74. package/dist/settings/dictionaries/settings-dialog.uk.d.ts +0 -3
  75. package/dist/settings/dictionaries/settings-dialog.uk.js +0 -27
  76. package/dist/settings/dictionaries/settings-dialog.ur.d.ts +0 -3
  77. package/dist/settings/dictionaries/settings-dialog.ur.js +0 -27
  78. package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts +0 -3
  79. package/dist/settings/dictionaries/settings-dialog.zh-CN.js +0 -27
  80. package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts +0 -3
  81. package/dist/settings/dictionaries/settings-dialog.zh-TW.js +0 -27
  82. package/dist/settings/ensure-definitions.d.ts +0 -88
  83. package/dist/settings/ensure-definitions.js +0 -91
  84. package/dist/settings/errors.d.ts +0 -42
  85. package/dist/settings/errors.js +0 -46
  86. package/dist/settings/express/cms-adapter.d.ts +0 -20
  87. package/dist/settings/express/cms-adapter.js +0 -124
  88. package/dist/settings/express/contracts.d.ts +0 -135
  89. package/dist/settings/express/contracts.js +0 -2
  90. package/dist/settings/express/http.d.ts +0 -10
  91. package/dist/settings/express/http.js +0 -211
  92. package/dist/settings/express/shared.d.ts +0 -68
  93. package/dist/settings/express/shared.js +0 -54
  94. package/dist/settings/express/stream.d.ts +0 -24
  95. package/dist/settings/express/stream.js +0 -147
  96. package/dist/settings/ports.d.ts +0 -118
  97. package/dist/settings/ports.js +0 -2
  98. package/dist/settings/principal-lookup.d.ts +0 -9
  99. package/dist/settings/principal-lookup.js +0 -2
  100. package/dist/settings/purge-service.d.ts +0 -54
  101. package/dist/settings/purge-service.js +0 -106
  102. package/dist/settings/repo.memory.d.ts +0 -119
  103. package/dist/settings/repo.memory.js +0 -199
  104. package/dist/settings/settings.d.ts +0 -139
  105. package/dist/settings/settings.js +0 -259
  106. package/dist/settings/tool-registrations.d.ts +0 -51
  107. package/dist/settings/tool-registrations.js +0 -250
  108. package/dist/settings/types.d.ts +0 -125
  109. package/dist/settings/types.js +0 -3
  110. package/dist/settings/ui-tab-definitions.d.ts +0 -41
  111. package/dist/settings/ui-tab-definitions.js +0 -148
  112. package/dist/settings/write-service.d.ts +0 -320
  113. package/dist/settings/write-service.js +0 -683
@@ -1,125 +0,0 @@
1
- import type { ISODateTime, JsonValue, UUID } from "@jini-ai/core/primitives";
2
- /**
3
- * @file Settings domain types.
4
- *
5
- * Purpose:
6
- * Record shapes + the schema-validation vocabulary shared by `settings.ts`,
7
- * `write-service.ts`, `purge-service.ts`, and both repo adapters. Interfaces
8
- * and types only — no feature logic (mirrors `identity/types.ts`).
9
- */
10
- export type SettingScope = "global" | "workspace" | "user";
11
- export type SettingOwnerKind = "core" | "site" | "theme";
12
- export type DefinitionStatus = "active" | "alias" | "deprecated" | "tombstone";
13
- export type ValueState = "set" | "cleared";
14
- export type RevisionEntityKind = "definition" | "value";
15
- export type RevisionOp = "register" | "alias" | "retype"
16
- /**
17
- * A `core` definition's stored `default_json` was reconciled to the default
18
- * its source declares (`write-service.ts`'s `reconcileDefinitionDefault`).
19
- * Distinct from `retype`: the schema is unchanged, so no stored value needs
20
- * coercion and the definition version does NOT advance. Only unset-value
21
- * resolution changes.
22
- */
23
- | "redefault" | "deprecate" | "tombstone" | "set" | "clear" | "purge" | "coerce";
24
- /** Scope bitmask values: global=1, workspace=2, user=4. Legal range 1..7. */
25
- export declare const SCOPE_BIT: {
26
- readonly global: 1;
27
- readonly workspace: 2;
28
- readonly user: 4;
29
- };
30
- /**
31
- * A deliberately small, total value-schema vocabulary (Article III — this
32
- * feature registers string/number/boolean/enum settings; a generic JSON
33
- * Schema engine is not needed and would be speculative generality). Every
34
- * variant is exhaustively validatable by `validateValue`.
35
- */
36
- /**
37
- * `{type:"json"}` is a deliberately narrow, scalar-ADJACENT exception to the
38
- * "deliberately small" vocabulary above: it accepts any JSON value
39
- * (object/array/scalar) and validates nothing about its internal shape —
40
- * that is the registering feature's own write-path responsibility, never
41
- * this ledger's job.
42
- *
43
- * Enforcement rule that must survive any refactor: Code Review must confirm
44
- * that EVERY use is genuinely unbounded, list-shaped data with no scalar
45
- * decomposition available — it is not a general escape hatch for fields that
46
- * could be scalar-decomposed instead. The check is per-use, deliberately not
47
- * a headcount. See `docs/decisions/settings-json-schema-variant.md` for the
48
- * originating rationale and a related non-null-default invariant.
49
- */
50
- export type SettingValueSchema = {
51
- type: "string";
52
- nullable?: boolean;
53
- } | {
54
- type: "number";
55
- nullable?: boolean;
56
- } | {
57
- type: "boolean";
58
- nullable?: boolean;
59
- } | {
60
- type: "enum";
61
- values: readonly string[];
62
- nullable?: boolean;
63
- } | {
64
- type: "json";
65
- nullable?: boolean;
66
- };
67
- export interface SettingDefinitionRecord {
68
- settingId: UUID;
69
- version: number;
70
- /** NULL = platform def (core/theme); non-null = site-owned. */
71
- workspaceId: UUID | null;
72
- namespace: string;
73
- key: string;
74
- ownerKind: SettingOwnerKind;
75
- ownerId: string | null;
76
- schema: SettingValueSchema;
77
- defaultValue: JsonValue | null;
78
- /** Bitmask over `SCOPE_BIT`, legal range 1..7. */
79
- scopes: number;
80
- secret: boolean;
81
- status: DefinitionStatus;
82
- aliasOfNamespace: string | null;
83
- aliasOfKey: string | null;
84
- /** Present only when `version > 1`; a total coercer id/tag for the prior version. */
85
- coercionTag: string | null;
86
- createdAt: ISODateTime;
87
- updatedAt: ISODateTime;
88
- }
89
- export interface SettingValueRecord {
90
- settingId: UUID;
91
- scope: SettingScope;
92
- /** Present for workspace/user scope; null for global. */
93
- workspaceId: UUID | null;
94
- /** Present for user scope only. */
95
- principalId: UUID | null;
96
- valueJson: JsonValue | null;
97
- state: ValueState;
98
- defVersion: number;
99
- seq: number;
100
- updatedBy: UUID;
101
- updatedAt: ISODateTime;
102
- originPluginId: string | null;
103
- }
104
- export interface SettingRevisionRecord {
105
- seq: number;
106
- entityKind: RevisionEntityKind;
107
- settingId: UUID;
108
- scope: SettingScope | null;
109
- workspaceId: UUID | null;
110
- principalId: UUID | null;
111
- op: RevisionOp;
112
- beforeJson: JsonValue | null;
113
- afterJson: JsonValue | null;
114
- defVersion: number;
115
- actor: UUID;
116
- originPluginId: string | null;
117
- changeSetId: string | null;
118
- createdAt: ISODateTime;
119
- }
120
- /** The context a resolver/write call is evaluated against. */
121
- export interface SettingScopeContext {
122
- workspaceId?: UUID | undefined;
123
- principalId?: UUID | undefined;
124
- }
125
- //# sourceMappingURL=types.d.ts.map
@@ -1,3 +0,0 @@
1
- /** Scope bitmask values: global=1, workspace=2, user=4. Legal range 1..7. */
2
- export const SCOPE_BIT = { global: 1, workspace: 2, user: 4 };
3
- //# sourceMappingURL=types.js.map
@@ -1,41 +0,0 @@
1
- import type { UUID } from "@jini-ai/core/primitives";
2
- import { type EnsureSettingDefinitionsDeps } from "./ensure-definitions.js";
3
- /**
4
- * @file Boot-time definition registration for the settings-dialog tabs that
5
- * need nothing but ledger storage — Instructions, Notifications, and Privacy.
6
- *
7
- * These three sit together because they are the same shape of problem, not
8
- * because they are the same domain: each is a `value` + `onChange` component
9
- * from a shared UI library with no async port, so the entire host-side cost
10
- * is "register some keys and map them". A tab that needs real backend work
11
- * (routes, a port) should keep its own module rather than accreting into
12
- * this one.
13
- *
14
- * All three read and write through the generic settings ledger routes a host
15
- * exposes, gated by the ledger's own scope-derived `settings.workspace.write`
16
- * check. There is no bespoke get/set service and no per-tab permission — the
17
- * reason the shared `ensureSettingDefinitions` helper exists.
18
- */
19
- /** Custom instructions applied to every admin-assistant conversation. */
20
- export declare const INSTRUCTIONS_NAMESPACE = "core.instructions";
21
- /** Completion-sound and desktop-notification preferences. */
22
- export declare const NOTIFICATIONS_NAMESPACE = "core.notifications";
23
- /** Telemetry consent state. */
24
- export declare const PRIVACY_NAMESPACE = "core.privacy";
25
- /** Theme choice and accent color for the settings-dialog surface. */
26
- export declare const APPEARANCE_NAMESPACE = "core.appearance";
27
- /** Admin UI locale. */
28
- export declare const LANGUAGE_NAMESPACE = "core.language";
29
- export interface EnsureSettingsUiTabDefinitionsInput {
30
- /** The trusted boot-time actor these writes are attributed to. */
31
- systemPrincipalId: UUID;
32
- }
33
- /**
34
- * Idempotently registers the Instructions, Notifications, and Privacy
35
- * definitions. Safe to call on every boot.
36
- *
37
- * @complexity O(n) in the total number of definitions (9), each a
38
- * skip-if-registered check plus at most one `registerDefinitions` call.
39
- */
40
- export declare function ensureSettingsUiTabDefinitions(deps: EnsureSettingDefinitionsDeps, input: EnsureSettingsUiTabDefinitionsInput): Promise<void>;
41
- //# sourceMappingURL=ui-tab-definitions.d.ts.map
@@ -1,148 +0,0 @@
1
- import { ensureSettingDefinitions, } from "./ensure-definitions.js";
2
- import { SCOPE_BIT } from "./types.js";
3
- /**
4
- * @file Boot-time definition registration for the settings-dialog tabs that
5
- * need nothing but ledger storage — Instructions, Notifications, and Privacy.
6
- *
7
- * These three sit together because they are the same shape of problem, not
8
- * because they are the same domain: each is a `value` + `onChange` component
9
- * from a shared UI library with no async port, so the entire host-side cost
10
- * is "register some keys and map them". A tab that needs real backend work
11
- * (routes, a port) should keep its own module rather than accreting into
12
- * this one.
13
- *
14
- * All three read and write through the generic settings ledger routes a host
15
- * exposes, gated by the ledger's own scope-derived `settings.workspace.write`
16
- * check. There is no bespoke get/set service and no per-tab permission — the
17
- * reason the shared `ensureSettingDefinitions` helper exists.
18
- */
19
- /** Custom instructions applied to every admin-assistant conversation. */
20
- export const INSTRUCTIONS_NAMESPACE = "core.instructions";
21
- /** Completion-sound and desktop-notification preferences. */
22
- export const NOTIFICATIONS_NAMESPACE = "core.notifications";
23
- /** Telemetry consent state. */
24
- export const PRIVACY_NAMESPACE = "core.privacy";
25
- /** Theme choice and accent color for the settings-dialog surface. */
26
- export const APPEARANCE_NAMESPACE = "core.appearance";
27
- /** Admin UI locale. */
28
- export const LANGUAGE_NAMESPACE = "core.language";
29
- /**
30
- * "No consent decision recorded yet", which a host's UI layer may spell as
31
- * `privacyDecisionAt: null`.
32
- *
33
- * A literal `null` default is not registrable (see `SettingDefinitionSpec.
34
- * defaultValue` — non-secret definitions reject a null default outright), so
35
- * this needs a sentinel. `0` is safe rather than merely convenient: the field
36
- * is epoch milliseconds, and 0 is 1970-01-01, which cannot be a real decision
37
- * timestamp for software that did not exist then. The tab uses this exact
38
- * distinction — an unset value renders the first-run consent prompt, a set one
39
- * renders the "decided" state — so collapsing the two would silently re-prompt
40
- * an operator who has already chosen.
41
- */
42
- const NO_DECISION_SENTINEL = 0;
43
- /**
44
- * "No installation id", which a host's UI layer may spell as
45
- * `installationId: null` (its meaning: telemetry sharing is fully declined).
46
- * `""` is not a legal id — the tab generates opaque non-empty strings — so it
47
- * cannot collide with a real one.
48
- */
49
- const NO_INSTALLATION_ID_SENTINEL = "";
50
- const INSTRUCTIONS_DEFINITIONS = [
51
- // A host's `InstructionsTab` may collapse an all-empty textarea to `undefined` rather than `''`
52
- // (its `onChange` contract), so the adapter maps that back to this empty-string default instead
53
- // of storing a distinguishable "explicitly emptied" state the tab cannot itself produce.
54
- { key: "custom", schema: { type: "string" }, defaultValue: "" },
55
- ];
56
- /**
57
- * Notification preferences are the one genuinely PER-OPERATOR surface in this
58
- * set, so they register `SCOPE_BIT.user` alongside `workspace` and the adapter
59
- * writes at user scope. Two admins sharing a workspace should not fight over
60
- * whether a completion sound plays on the other's machine — unlike a tab
61
- * whose backing resource is genuinely shared workspace state.
62
- *
63
- * The `workspace` bit stays in the mask so an operator with no user-scoped row
64
- * still inherits a workspace-level default rather than falling all the way
65
- * back to the registered one.
66
- */
67
- const NOTIFICATIONS_SCOPES = SCOPE_BIT.user | SCOPE_BIT.workspace;
68
- const NOTIFICATIONS_DEFINITIONS = [
69
- { key: "soundEnabled", schema: { type: "boolean" }, defaultValue: false, scopes: NOTIFICATIONS_SCOPES },
70
- // Free-form strings rather than an enum: sound ids are plain strings upstream and the catalog is
71
- // owned by a host's UI library. Pinning an enum here would make a package-side catalog addition
72
- // fail validation on an already-registered definition, which is a worse failure than accepting an
73
- // id the catalog no longer lists (the tab falls back to its own default for an unknown id).
74
- { key: "successSoundId", schema: { type: "string" }, defaultValue: "ding", scopes: NOTIFICATIONS_SCOPES },
75
- { key: "failureSoundId", schema: { type: "string" }, defaultValue: "buzz", scopes: NOTIFICATIONS_SCOPES },
76
- // Desktop notifications also need the BROWSER's Notification permission,
77
- // which is per-browser and not ours to store. This flag is only the
78
- // operator's intent; the tab reconciles it against the live permission.
79
- { key: "desktopEnabled", schema: { type: "boolean" }, defaultValue: false, scopes: NOTIFICATIONS_SCOPES },
80
- ];
81
- const PRIVACY_DEFINITIONS = [
82
- // Both telemetry categories default OFF. A "consent state" type may type them optional, but
83
- // "unset" is carried by `decisionAt` instead — an operator who has decided has a timestamp, and
84
- // these two then mean exactly what they say.
85
- { key: "telemetry.metrics", schema: { type: "boolean" }, defaultValue: false },
86
- { key: "telemetry.content", schema: { type: "boolean" }, defaultValue: false },
87
- { key: "installationId", schema: { type: "string" }, defaultValue: NO_INSTALLATION_ID_SENTINEL },
88
- { key: "decisionAt", schema: { type: "number" }, defaultValue: NO_DECISION_SENTINEL },
89
- ];
90
- /**
91
- * Appearance and Language are per-OPERATOR, same reasoning as Notifications:
92
- * which theme one admin looks at, and which language they read, are not
93
- * properties of the workspace. The `workspace` bit stays in the mask so an
94
- * operator with no user-scoped row still inherits a workspace default.
95
- */
96
- const PER_OPERATOR_SCOPES = SCOPE_BIT.user | SCOPE_BIT.workspace;
97
- const APPEARANCE_DEFINITIONS = [
98
- // Defaults to LIGHT rather than "system" here — a host whose surrounding admin UI is
99
- // light-only would put a dark panel inside a light app for every operator on a dark-mode
100
- // machine if this defaulted to following the OS. "system" stays selectable; a host can
101
- // override this default at its own registration call site if its UI has a real dark variant.
102
- {
103
- key: "theme",
104
- schema: { type: "enum", values: ["system", "light", "dark"] },
105
- defaultValue: "light",
106
- scopes: PER_OPERATOR_SCOPES,
107
- },
108
- // Free-form string rather than an enum over a swatch palette: a host's UI may ship a color
109
- // picker, so any `#rrggbb` is reachable, and its own accent-color normalizer already rejects
110
- // malformed values at render time. Pinning an enum here would reject a legitimate custom color
111
- // at the ledger.
112
- {
113
- key: "accentColor",
114
- schema: { type: "string" },
115
- defaultValue: "#2563eb",
116
- scopes: PER_OPERATOR_SCOPES,
117
- },
118
- ];
119
- const LANGUAGE_DEFINITIONS = [
120
- // A BCP-47-ish code, not an enum. The catalog of real locales is a host's own i18n concern, not
121
- // this library's; the tab takes a host-supplied `LocaleOption[]` and an unknown stored code
122
- // simply selects nothing rather than failing a ledger write.
123
- { key: "locale", schema: { type: "string" }, defaultValue: "en", scopes: PER_OPERATOR_SCOPES },
124
- ];
125
- /**
126
- * Idempotently registers the Instructions, Notifications, and Privacy
127
- * definitions. Safe to call on every boot.
128
- *
129
- * @complexity O(n) in the total number of definitions (9), each a
130
- * skip-if-registered check plus at most one `registerDefinitions` call.
131
- */
132
- export async function ensureSettingsUiTabDefinitions(deps, input) {
133
- const namespaces = [
134
- { namespace: INSTRUCTIONS_NAMESPACE, definitions: INSTRUCTIONS_DEFINITIONS },
135
- { namespace: NOTIFICATIONS_NAMESPACE, definitions: NOTIFICATIONS_DEFINITIONS },
136
- { namespace: PRIVACY_NAMESPACE, definitions: PRIVACY_DEFINITIONS },
137
- { namespace: APPEARANCE_NAMESPACE, definitions: APPEARANCE_DEFINITIONS },
138
- { namespace: LANGUAGE_NAMESPACE, definitions: LANGUAGE_DEFINITIONS },
139
- ];
140
- for (const { namespace, definitions } of namespaces) {
141
- await ensureSettingDefinitions(deps, {
142
- namespace,
143
- definitions,
144
- systemPrincipalId: input.systemPrincipalId,
145
- });
146
- }
147
- }
148
- //# sourceMappingURL=ui-tab-definitions.js.map
@@ -1,320 +0,0 @@
1
- import type { Clock, IdGenerator, JsonValue, UUID } from "@jini-ai/core/primitives";
2
- import type { SettingsPrincipalLookupPort } from "./principal-lookup.js";
3
- import type { SettingsRepoPort } from "./ports.js";
4
- import { type DefinitionInput } from "./settings.js";
5
- import { type SettingScope, type SettingValueSchema } from "./types.js";
6
- /**
7
- * @file `SettingsWriteService` — the single write chokepoint.
8
- *
9
- * Purpose:
10
- * The ONLY value/definition-mutation path. Repo write methods
11
- * (`saveDefinition`/`save*Value`/`appendRevision`/`delete*Value`) must never
12
- * be called from outside this file (Code Review enforces this as a file-
13
- * boundary check).
14
- *
15
- * Every export here: `authorize` first (fail-closed) -> validate ->
16
- * write value/definition row + revision in one transaction.
17
- *
18
- * `deriveRequiredPermission` is the sole source of truth for the self-vs-
19
- * other permission rule (behavior.spec.md §1.3) — closes Red-Team.
20
- * target-principal checks use a host-supplied active-principal lookup over core Principal;
21
- * identity and membership policy remain at the host boundary.
22
- * See docs/decisions/DR-003-settings-ledger-invariants.md.
23
- */
24
- /** Matches `core/commands/command.ts`'s `AuthorizeFn` shape structurally — no import, kept decoupled. */
25
- export type AuthorizeFn = (params: {
26
- principalId: UUID;
27
- permission: string;
28
- workspaceId: UUID;
29
- entityType?: string;
30
- entityId?: UUID;
31
- }) => Promise<{
32
- allowed: boolean;
33
- reason: string;
34
- }>;
35
- export interface SettingsWriteServiceDeps {
36
- repo: SettingsRepoPort;
37
- clock: Clock;
38
- ids: IdGenerator;
39
- authorize: AuthorizeFn;
40
- /** Host lookup must hide disabled and out-of-workspace principals. See docs/decisions/DR-003-settings-ledger-invariants.md. */
41
- principals: SettingsPrincipalLookupPort;
42
- }
43
- /**
44
- * behavior.spec.md §1.3 / `[internal-invariant]` — the self-vs-other
45
- * permission derivation. `targetPrincipalId` omitted or equal to the caller
46
- * -> `settings.user.self.write`; any other principal -> `settings.user.write`.
47
- * A divergence between this function and any other implementation of the
48
- * rule is a fail-open authorization bug (Red-Team ) — this is the only
49
- * place the rule may be encoded.
50
- *
51
- * @complexity O(1), pure.
52
- * @overallScore 100
53
- * See docs/decisions/DR-003-settings-ledger-invariants.md.
54
- */
55
- export declare function deriveRequiredPermission(input: {
56
- scope: SettingScope;
57
- targetPrincipalId?: UUID | undefined;
58
- callerPrincipalId: UUID;
59
- }): string;
60
- export interface RegisterDefinitionsRequired {
61
- deps: SettingsWriteServiceDeps;
62
- input: {
63
- definitions: DefinitionInput[];
64
- callerPrincipalId: UUID;
65
- /** The workspace the caller is authorizing in (always required — even platform-def registration is authorized within a workspace context). */
66
- authWorkspaceId: UUID;
67
- };
68
- }
69
- /** chokepoint write: authorize `settings.definitions.manage` -> validate -> write + revision, one per definition, each its own tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
70
- export declare function registerDefinitions(required: RegisterDefinitionsRequired): Promise<{
71
- registered: string[];
72
- }>;
73
- export interface SetValueRequired {
74
- deps: SettingsWriteServiceDeps;
75
- input: {
76
- namespace: string;
77
- key: string;
78
- scope: SettingScope;
79
- value: JsonValue;
80
- workspaceId?: UUID | undefined;
81
- principalId?: UUID | undefined;
82
- callerPrincipalId: UUID;
83
- /**
84
- * The ambient workspace to authorize the caller's grant in. Optional and
85
- * additive: when omitted, falls back to `input.workspaceId ??
86
- * input.callerPrincipalId`. Callers that DO have a real ambient workspace
87
- * (every HTTP route in a single-workspace host) should pass it
88
- * explicitly: for `scope=global` (no `workspaceId`), falling back to
89
- * `callerPrincipalId` as a stand-in "workspace" id is nonsensical against
90
- * the real `authorize()` (identity's own authorize looks the principal up
91
- * by `{workspaceId, id}` — a bogus workspaceId means `findById` returns
92
- * null and every request is denied `principal_disabled`, including the
93
- * wildcard-owner).
94
- */
95
- authWorkspaceId?: UUID | undefined;
96
- /**
97
- * `deriveRequiredPermission` unconditionally derives `settings.workspace.write` for
98
- * `scope: "workspace"` — a caller that already authorized a narrower, domain-specific
99
- * permission at its own route layer (e.g. a comments module's `comments.configure`, an SEO
100
- * module's `admin.seo.manage`) still hits this chokepoint's generic `settings.workspace.write`
101
- * check and gets a masked 500 if it lacks that broader grant, even though its own domain
102
- * permission is exactly what the feature's admin UI advertises as sufficient. Optional and
103
- * additive: omitted, behavior is unchanged (every pre-existing caller still gets the
104
- * scope-derived permission). When a domain-settings module supplies this, the chokepoint
105
- * authorizes THIS permission instead of the scope-derived one — still a mandatory
106
- * `authorize` call before any write ( fail-closed discipline is not relaxed, only
107
- * which permission string is checked).
108
- * See docs/decisions/DR-003-settings-ledger-invariants.md.
109
- */
110
- requiredPermissionOverride?: string | undefined;
111
- };
112
- }
113
- /** chokepoint write: authorize -> validate -> value + revision, same tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
114
- export declare function set(required: SetValueRequired): Promise<{
115
- value: JsonValue;
116
- revisionSeq: number;
117
- }>;
118
- export interface ClearValueRequired {
119
- deps: SettingsWriteServiceDeps;
120
- input: {
121
- namespace: string;
122
- key: string;
123
- scope: SettingScope;
124
- workspaceId?: UUID | undefined;
125
- principalId?: UUID | undefined;
126
- callerPrincipalId: UUID;
127
- /** Set by `resetNamespace` when looping `clear` in its own reset-authorized context — bypasses the inner authorize re-check, still writes a normal revision. See docs/decisions/DR-003-settings-ledger-invariants.md. */
128
- skipAuthorize?: boolean | undefined;
129
- /** Set by a caller that has ALREADY opened a transaction around this write —
130
- * see `resetNamespace`. Explicit rather than an ambient depth counter,
131
- * because an ambient one cannot tell a genuine nesting from a concurrent
132
- * unrelated transaction and silently merges the two. */
133
- skipTransaction?: boolean | undefined;
134
- /** See `SetValueRequired.input.authWorkspaceId`'s doc. Optional/additive. */
135
- authWorkspaceId?: UUID | undefined;
136
- };
137
- }
138
- /** chokepoint write: authorize -> value + revision (state='cleared'), same tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
139
- export declare function clear(required: ClearValueRequired): Promise<{
140
- revisionSeq: number;
141
- }>;
142
- export interface ResetNamespaceRequired {
143
- deps: SettingsWriteServiceDeps;
144
- input: {
145
- namespace: string;
146
- scope: Exclude<SettingScope, never>;
147
- workspaceId?: UUID | undefined;
148
- principalId?: UUID | undefined;
149
- callerPrincipalId: UUID;
150
- /** See `SetValueRequired.input.authWorkspaceId`'s doc. Optional/additive. */
151
- authWorkspaceId?: UUID | undefined;
152
- };
153
- }
154
- /**
155
- * — an explicit, human-invoked orchestrator: authorize
156
- * the matching `settings.reset.*` permission once, then loop `clear` for
157
- * every setting in the namespace in the reset-authorized internal context
158
- * (`skipAuthorize: true`) — the outer reset permission is sufficient on its
159
- * own; each inner clear still emits its own `op='clear'` revision.
160
- *
161
- * `revisionSeqs` collects each inner `clear` call's own `revisionSeq` so a
162
- * host's admin HTTP route can surface the full contract without a second
163
- * read. Existing callers that only read `.clearedCount` are unaffected.
164
- * See docs/decisions/DR-003-settings-ledger-invariants.md.
165
- */
166
- export declare function resetNamespace(required: ResetNamespaceRequired, keysInNamespace: string[]): Promise<{
167
- clearedCount: number;
168
- revisionSeqs: number[];
169
- }>;
170
- export interface RenameDefinitionRequired {
171
- deps: SettingsWriteServiceDeps;
172
- input: {
173
- namespace: string;
174
- key: string;
175
- workspaceId: UUID | null;
176
- newNamespace: string;
177
- newKey: string;
178
- callerPrincipalId: UUID;
179
- /** The workspace the caller is authorizing in (see `registerDefinitions`' identical field). */
180
- authWorkspaceId: UUID;
181
- };
182
- }
183
- /**
184
- * The rename mechanism : a same-tx pair —
185
- * (1) UPDATE the active definition row's `(namespace,key)` to the new name,
186
- * same `setting_id`/`version` (ledgered `op='alias'`); (2) INSERT a fresh v1
187
- * alias marker at the OLD name pointing at the new name. Because identity
188
- * never moves, value rows (keyed on `setting_id` only) stay attached.
189
- *
190
- * Sequential rename (A->B then B->C) retargets every prior marker pointing
191
- * at the OLD name to the NEW name in the same tx. A rename target that
192
- * itself resolves to an existing alias is rejected `ALIAS_DEPTH_EXCEEDED`
193
- * (behavior.spec.md §7: "the rename target resolves to an alias").
194
- *
195
- * Never touches `schema`/`defaultValue`/`scopes` -- a pure rename can never
196
- * trigger `RENAME_RETYPE_CONFLICT` by construction; that guard lives in
197
- * `retypeDefinition` ("no rename+retype in one op").
198
- * See docs/decisions/DR-003-settings-ledger-invariants.md.
199
- */
200
- export declare function renameDefinition(required: RenameDefinitionRequired): Promise<{
201
- settingId: string;
202
- markerSettingId: string;
203
- }>;
204
- export interface RetypeDefinitionRequired {
205
- deps: SettingsWriteServiceDeps;
206
- input: {
207
- namespace: string;
208
- key: string;
209
- workspaceId: UUID | null;
210
- schema: SettingValueSchema;
211
- defaultValue: JsonValue | null;
212
- /** A total coercer id/tag ( registry in `settings.ts`) for reading values recorded under any prior version. See docs/decisions/DR-003-settings-ledger-invariants.md. */
213
- coercionTag: string;
214
- /**
215
- * Present only to detect a combined rename+retype request;
216
- * retype never actually moves `(namespace,key)` -- if provided and it
217
- * differs from the current name while `schema` also differs, the whole
218
- * op is rejected `RENAME_RETYPE_CONFLICT` rather than silently doing
219
- * only the schema half.
220
- */
221
- newNamespace?: string | undefined;
222
- newKey?: string | undefined;
223
- callerPrincipalId: UUID;
224
- authWorkspaceId: UUID;
225
- };
226
- }
227
- /**
228
- * The retype mechanism : a same-tx pair --
229
- * (1) UPDATE the prior active version's `status` to `deprecated` FIRST (else
230
- * the insert in step 2 collides with the one-active-row-per-slot
231
- * invariant); (2) INSERT the new `version+1` row as `active`, same
232
- * `setting_id`/`namespace`/`key`. Rejected unless every prior version
233
- * (2..N) already carries a total coercer -- `coercionTag` is `null` only for
234
- * version 1 by construction (`types.ts`), so this walks 2..N and requires
235
- * each to be non-null.
236
- * See docs/decisions/DR-003-settings-ledger-invariants.md.
237
- */
238
- export declare function retypeDefinition(required: RetypeDefinitionRequired): Promise<{
239
- settingId: string;
240
- version: number;
241
- }>;
242
- export interface ReconcileDefinitionDefaultRequired {
243
- deps: SettingsWriteServiceDeps;
244
- input: {
245
- namespace: string;
246
- key: string;
247
- workspaceId: UUID | null;
248
- /** The default the SOURCE declares. Wins over a differing stored default. */
249
- defaultValue: JsonValue;
250
- callerPrincipalId: UUID;
251
- authWorkspaceId: UUID;
252
- };
253
- }
254
- /**
255
- * Reconciles a stored `default_json` that has drifted from the default its
256
- * source declares. Idempotent and a no-op when they already agree.
257
- *
258
- * Why this exists — the bug it closes:
259
- * `ensure-definitions.ts` registers each definition once and then skips it
260
- * forever (`if (existing) continue;`). That makes a changed `defaultValue` in
261
- * SOURCE unreachable in any install that has already booted, for every
262
- * settings-dialog tab a host registers this way. It can surface as a stored
263
- * default staying "system" in the database while source says "light",
264
- * rendering a settings panel with the wrong initial state — a visibly wrong
265
- * value produced by entirely correct-looking source. The next occurrence
266
- * could be a silently wrong default with no visual tell at all.
267
- *
268
- * Why `core`-only:
269
- * `ownerKind` already encodes who owns a definition. `core` definitions
270
- * configure a platform capability and are code-owned, so code is the authority
271
- * on their default and may overwrite a drifted stored one. `site` and `theme`
272
- * definitions are operator-owned — silently overwriting those would destroy a
273
- * deliberate choice, so they are rejected rather than reconciled.
274
- *
275
- * Why this is NOT a `retype`:
276
- * `retype` deprecates the active row and inserts `version+1` because a changed
277
- * SCHEMA means every stored value needs a total coercer. A changed DEFAULT
278
- * needs none — the schema is untouched, so every stored value stays valid and
279
- * only the resolution of UNSET values moves. The row is therefore updated in
280
- * place at the same version, and the paired revision carries the old and new
281
- * default in `beforeJson`/`afterJson` so the change is auditable.
282
- *
283
- * @complexity O(1) — one definition lookup plus at most one row update and one
284
- * revision append, in a single transaction.
285
- */
286
- export declare function reconcileDefinitionDefault(required: ReconcileDefinitionDefaultRequired): Promise<{
287
- settingId: string;
288
- changed: boolean;
289
- }>;
290
- export interface DeprecateDefinitionRequired {
291
- deps: SettingsWriteServiceDeps;
292
- input: {
293
- namespace: string;
294
- key: string;
295
- workspaceId: UUID | null;
296
- callerPrincipalId: UUID;
297
- authWorkspaceId: UUID;
298
- };
299
- }
300
- export interface TombstoneDefinitionRequired {
301
- deps: SettingsWriteServiceDeps;
302
- input: {
303
- namespace: string;
304
- key: string;
305
- workspaceId: UUID | null;
306
- callerPrincipalId: UUID;
307
- authWorkspaceId: UUID;
308
- };
309
- }
310
- /** Flips the active definition's status to `deprecated`, ledgered `op='deprecate'` -- same-tx, chokepoint-gated. */
311
- export declare function deprecateDefinition(required: DeprecateDefinitionRequired): Promise<{
312
- settingId: string;
313
- version: number;
314
- }>;
315
- /** Flips the active definition's status to `tombstone` (kills a core key), ledgered `op='tombstone'` -- same-tx, chokepoint-gated. */
316
- export declare function tombstoneDefinition(required: TombstoneDefinitionRequired): Promise<{
317
- settingId: string;
318
- version: number;
319
- }>;
320
- //# sourceMappingURL=write-service.d.ts.map