@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.
- package/dist/navigation/agent-tools.js +20 -3
- package/dist/navigation/index.d.ts +3 -1
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/menu-html.d.ts +31 -0
- package/dist/navigation/menu-html.js +53 -0
- package/dist/navigation/menu-service.d.ts +9 -3
- package/dist/navigation/menu-service.js +15 -3
- package/dist/navigation/tool-registrations.d.ts +5 -0
- package/dist/navigation/tool-registrations.js +32 -2
- package/dist/navigation/types.d.ts +6 -0
- package/dist/widgets/resolvers/menu.d.ts +8 -0
- package/dist/widgets/resolvers/menu.js +21 -6
- package/package.json +3 -3
- package/dist/http/settings/cms-adapter.d.ts +0 -20
- package/dist/http/settings/cms-adapter.js +0 -124
- package/dist/http/settings/contracts.d.ts +0 -135
- package/dist/http/settings/contracts.js +0 -2
- package/dist/http/settings/http.d.ts +0 -10
- package/dist/http/settings/http.js +0 -211
- package/dist/http/settings/index.d.ts +0 -5
- package/dist/http/settings/index.js +0 -4
- package/dist/http/settings/shared.d.ts +0 -68
- package/dist/http/settings/shared.js +0 -54
- package/dist/http/settings/stream.d.ts +0 -24
- package/dist/http/settings/stream.js +0 -147
- package/dist/settings/agent-tools.d.ts +0 -10
- package/dist/settings/agent-tools.js +0 -204
- package/dist/settings/agent-value-write-tools.d.ts +0 -22
- package/dist/settings/agent-value-write-tools.js +0 -154
- package/dist/settings/agent-writable-preferences.d.ts +0 -67
- package/dist/settings/agent-writable-preferences.js +0 -132
- package/dist/settings/agent-write-denylist.d.ts +0 -19
- package/dist/settings/agent-write-denylist.js +0 -15
- package/dist/settings/change-feed.d.ts +0 -83
- package/dist/settings/change-feed.js +0 -61
- package/dist/settings/definitions-dispatch.d.ts +0 -56
- package/dist/settings/definitions-dispatch.js +0 -86
- package/dist/settings/dictionaries/index.d.ts +0 -48
- package/dist/settings/dictionaries/index.js +0 -69
- package/dist/settings/dictionaries/settings-dialog.ar.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ar.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.bn.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.bn.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.de.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.de.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.es.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.es.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.fa.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.fa.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.fr.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.fr.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.hi.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.hi.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.hu.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.hu.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.id.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.id.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.it.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.it.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ja.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ja.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ko.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ko.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.pl.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.pl.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.pt-BR.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ru.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ru.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.th.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.th.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.tr.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.tr.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.uk.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.uk.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ur.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ur.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.zh-CN.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.zh-TW.js +0 -27
- package/dist/settings/ensure-definitions.d.ts +0 -88
- package/dist/settings/ensure-definitions.js +0 -91
- package/dist/settings/errors.d.ts +0 -42
- package/dist/settings/errors.js +0 -46
- package/dist/settings/express/cms-adapter.d.ts +0 -20
- package/dist/settings/express/cms-adapter.js +0 -124
- package/dist/settings/express/contracts.d.ts +0 -135
- package/dist/settings/express/contracts.js +0 -2
- package/dist/settings/express/http.d.ts +0 -10
- package/dist/settings/express/http.js +0 -211
- package/dist/settings/express/shared.d.ts +0 -68
- package/dist/settings/express/shared.js +0 -54
- package/dist/settings/express/stream.d.ts +0 -24
- package/dist/settings/express/stream.js +0 -147
- package/dist/settings/ports.d.ts +0 -118
- package/dist/settings/ports.js +0 -2
- package/dist/settings/principal-lookup.d.ts +0 -9
- package/dist/settings/principal-lookup.js +0 -2
- package/dist/settings/purge-service.d.ts +0 -54
- package/dist/settings/purge-service.js +0 -106
- package/dist/settings/repo.memory.d.ts +0 -119
- package/dist/settings/repo.memory.js +0 -199
- package/dist/settings/settings.d.ts +0 -139
- package/dist/settings/settings.js +0 -259
- package/dist/settings/tool-registrations.d.ts +0 -51
- package/dist/settings/tool-registrations.js +0 -250
- package/dist/settings/types.d.ts +0 -125
- package/dist/settings/types.js +0 -3
- package/dist/settings/ui-tab-definitions.d.ts +0 -41
- package/dist/settings/ui-tab-definitions.js +0 -148
- package/dist/settings/write-service.d.ts +0 -320
- package/dist/settings/write-service.js +0 -683
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { resolveDefinitionRaw } from "./settings.js";
|
|
2
|
-
import { SCOPE_BIT } from "./types.js";
|
|
3
|
-
import { reconcileDefinitionDefault, registerDefinitions } from "./write-service.js";
|
|
4
|
-
/** Boot-time infra work is trusted by construction — mirrors every other
|
|
5
|
-
* `ensure*SettingDefinitions`'s identical shim. */
|
|
6
|
-
const alwaysAllowBoot = async () => ({ allowed: true, reason: "system_boot" });
|
|
7
|
-
/**
|
|
8
|
-
* Idempotently registers every definition in `input.definitions` under
|
|
9
|
-
* `input.namespace`, and reconciles the stored default of any that already
|
|
10
|
-
* exist to the default source declares. Safe to call on every boot.
|
|
11
|
-
*
|
|
12
|
-
* The reconcile half matters as much as the register half: registration is
|
|
13
|
-
* once-only, so without it a `defaultValue` edited in source never reaches an
|
|
14
|
-
* install that has booted before. Code owns `core` defaults; the stored row
|
|
15
|
-
* does not get to outvote it.
|
|
16
|
-
*
|
|
17
|
-
* All definitions registered here are `ownerKind: "core"` — a settings-dialog
|
|
18
|
-
* tab configures a platform-level capability, not per-site content. Per the
|
|
19
|
-
* namespace-fence CHECK, `owner_kind='core'` requires `workspaceId: null` at
|
|
20
|
-
* the DEFINITION level regardless of which workspace is booting, while the
|
|
21
|
-
* `scopes` bitmask still lets each workspace (or user) hold its own VALUE row.
|
|
22
|
-
*
|
|
23
|
-
* @complexity O(n) in the number of definitions — each is one
|
|
24
|
-
* skip-if-registered lookup plus at most one `registerDefinitions` call.
|
|
25
|
-
*/
|
|
26
|
-
export async function ensureSettingDefinitions(deps, input) {
|
|
27
|
-
const writeDeps = {
|
|
28
|
-
repo: deps.settingsRepo,
|
|
29
|
-
clock: deps.clock,
|
|
30
|
-
ids: deps.ids,
|
|
31
|
-
authorize: alwaysAllowBoot,
|
|
32
|
-
principals: deps.principals,
|
|
33
|
-
};
|
|
34
|
-
for (const def of input.definitions) {
|
|
35
|
-
const existing = await resolveDefinitionRaw({ repo: deps.settingsRepo }, { namespace: input.namespace, key: def.key, workspaceId: null });
|
|
36
|
-
if (existing) {
|
|
37
|
-
// Registration is once-only, but the DEFAULT is not. Without this, a
|
|
38
|
-
// `defaultValue` changed in source is unreachable in any install that
|
|
39
|
-
// has already booted — the stored `default_json` from first boot keeps
|
|
40
|
-
// winning, for every settings-dialog tab. See `reconcileDefinitionDefault`
|
|
41
|
-
// for the bug this closes.
|
|
42
|
-
//
|
|
43
|
-
// Three slots are deliberately left alone rather than reconciled:
|
|
44
|
-
// a non-`active` row (deprecated/tombstoned) is not ours to rewrite; a
|
|
45
|
-
// non-`core` row is operator-owned; and a row whose identity differs
|
|
46
|
-
// from the slot we asked for means `resolveDefinitionRaw` followed an
|
|
47
|
-
// alias, so rewriting it would silently change a DIFFERENT definition's
|
|
48
|
-
// default. `reconcileDefinitionDefault` would throw on the first two —
|
|
49
|
-
// this skips them quietly because boot must not fail on them.
|
|
50
|
-
const isSameSlot = existing.namespace === input.namespace && existing.key === def.key;
|
|
51
|
-
if (existing.status === "active" && existing.ownerKind === "core" && isSameSlot) {
|
|
52
|
-
await reconcileDefinitionDefault({
|
|
53
|
-
deps: writeDeps,
|
|
54
|
-
input: {
|
|
55
|
-
namespace: input.namespace,
|
|
56
|
-
key: def.key,
|
|
57
|
-
workspaceId: null,
|
|
58
|
-
defaultValue: def.defaultValue,
|
|
59
|
-
callerPrincipalId: input.systemPrincipalId,
|
|
60
|
-
authWorkspaceId: input.systemPrincipalId,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
await registerDefinitions({
|
|
67
|
-
deps: writeDeps,
|
|
68
|
-
input: {
|
|
69
|
-
callerPrincipalId: input.systemPrincipalId,
|
|
70
|
-
// Platform (core) definitions aren't scoped to any one workspace, but
|
|
71
|
-
// `registerDefinitions`'s authorization check still needs a workspace
|
|
72
|
-
// context to authorize against — the seeded workspace mirrors every
|
|
73
|
-
// other boot-time registrar's identical `authWorkspaceId` shape.
|
|
74
|
-
authWorkspaceId: input.systemPrincipalId,
|
|
75
|
-
definitions: [
|
|
76
|
-
{
|
|
77
|
-
namespace: input.namespace,
|
|
78
|
-
key: def.key,
|
|
79
|
-
ownerKind: "core",
|
|
80
|
-
workspaceId: null,
|
|
81
|
-
schema: def.schema,
|
|
82
|
-
defaultValue: def.defaultValue,
|
|
83
|
-
scopes: def.scopes ?? SCOPE_BIT.workspace,
|
|
84
|
-
secret: false,
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=ensure-definitions.js.map
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Typed domain errors for `settings`.
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* One class per error this module originates, mirroring the
|
|
6
|
-
* `PresentationSettingsNotFoundError`/`PresentationSettingsValidationError`
|
|
7
|
-
* convention a host's own presentation-settings module may use. Route
|
|
8
|
-
* handlers map these 1:1 to HTTP codes.
|
|
9
|
-
*/
|
|
10
|
-
export declare class DefinitionInvalidError extends Error {
|
|
11
|
-
}
|
|
12
|
-
export declare class ScopeNotAllowedError extends Error {
|
|
13
|
-
}
|
|
14
|
-
export declare class SecretNotSupportedError extends Error {
|
|
15
|
-
constructor({ message }: {
|
|
16
|
-
message: string;
|
|
17
|
-
}, optional?: ErrorOptions);
|
|
18
|
-
}
|
|
19
|
-
export declare class ValueValidationFailedError extends Error {
|
|
20
|
-
}
|
|
21
|
-
export declare class RenameRetypeConflictError extends Error {
|
|
22
|
-
}
|
|
23
|
-
export declare class AliasDepthExceededError extends Error {
|
|
24
|
-
}
|
|
25
|
-
export declare class DefinitionTombstonedError extends Error {
|
|
26
|
-
}
|
|
27
|
-
export declare class DefinitionNotFoundError extends Error {
|
|
28
|
-
}
|
|
29
|
-
export declare class PurgeRequiredError extends Error {
|
|
30
|
-
constructor({ message }: {
|
|
31
|
-
message: string;
|
|
32
|
-
}, optional?: ErrorOptions);
|
|
33
|
-
}
|
|
34
|
-
export declare class ForbiddenError extends Error {
|
|
35
|
-
}
|
|
36
|
-
/** : the target `principalId` does not resolve to an active principal in the request's workspace. See docs/decisions/DR-003-settings-ledger-invariants.md. */
|
|
37
|
-
export declare class PrincipalNotFoundError extends Error {
|
|
38
|
-
readonly principalId: string;
|
|
39
|
-
readonly workspaceId: string;
|
|
40
|
-
constructor(message: string, principalId: string, workspaceId: string);
|
|
41
|
-
}
|
|
42
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/dist/settings/errors.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Typed domain errors for `settings`.
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* One class per error this module originates, mirroring the
|
|
6
|
-
* `PresentationSettingsNotFoundError`/`PresentationSettingsValidationError`
|
|
7
|
-
* convention a host's own presentation-settings module may use. Route
|
|
8
|
-
* handlers map these 1:1 to HTTP codes.
|
|
9
|
-
*/
|
|
10
|
-
export class DefinitionInvalidError extends Error {
|
|
11
|
-
}
|
|
12
|
-
export class ScopeNotAllowedError extends Error {
|
|
13
|
-
}
|
|
14
|
-
export class SecretNotSupportedError extends Error {
|
|
15
|
-
constructor({ message }, optional = {}) {
|
|
16
|
-
super(message, optional);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export class ValueValidationFailedError extends Error {
|
|
20
|
-
}
|
|
21
|
-
export class RenameRetypeConflictError extends Error {
|
|
22
|
-
}
|
|
23
|
-
export class AliasDepthExceededError extends Error {
|
|
24
|
-
}
|
|
25
|
-
export class DefinitionTombstonedError extends Error {
|
|
26
|
-
}
|
|
27
|
-
export class DefinitionNotFoundError extends Error {
|
|
28
|
-
}
|
|
29
|
-
export class PurgeRequiredError extends Error {
|
|
30
|
-
constructor({ message }, optional = {}) {
|
|
31
|
-
super(message, optional);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
export class ForbiddenError extends Error {
|
|
35
|
-
}
|
|
36
|
-
/** : the target `principalId` does not resolve to an active principal in the request's workspace. See docs/decisions/DR-003-settings-ledger-invariants.md. */
|
|
37
|
-
export class PrincipalNotFoundError extends Error {
|
|
38
|
-
principalId;
|
|
39
|
-
workspaceId;
|
|
40
|
-
constructor(message, principalId, workspaceId) {
|
|
41
|
-
super(message);
|
|
42
|
-
this.principalId = principalId;
|
|
43
|
-
this.workspaceId = workspaceId;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=errors.js.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type SettingsWriteServiceDeps, type SettingsRepoPort } from "../index.js";
|
|
2
|
-
import type { SettingsService, SettingsPermissions, SettingsChangeFeed } from "./contracts.js";
|
|
3
|
-
/** Keep the CMS write chokepoint while translating its permission vocabulary to host policy. */
|
|
4
|
-
/** Bind the CMS ledger and write chokepoint without copying their domain logic.
|
|
5
|
-
* Effective reads scan definitions and resolve each namespace key; mutations inherit CMS transactions/errors.
|
|
6
|
-
* @complexity O(1) setup. Per operation: O(definitions + keys) reads, or O(batch size) writes.
|
|
7
|
-
* @example createCmsSettingsService({ deps: cmsPorts, permissions });
|
|
8
|
-
*/
|
|
9
|
-
export declare function createCmsSettingsService(required: {
|
|
10
|
-
deps: SettingsWriteServiceDeps;
|
|
11
|
-
permissions: SettingsPermissions;
|
|
12
|
-
}): SettingsService;
|
|
13
|
-
/** Adapt the ledger through CMS tenant/principal disclosure rules, returning names and cursors only.
|
|
14
|
-
* @complexity O(1) setup; collect is O(page size), with namespace lookup per visible revision.
|
|
15
|
-
* @example createCmsSettingsChangeFeed({ repo });
|
|
16
|
-
*/
|
|
17
|
-
export declare function createCmsSettingsChangeFeed(required: {
|
|
18
|
-
repo: SettingsRepoPort;
|
|
19
|
-
}): SettingsChangeFeed;
|
|
20
|
-
//# sourceMappingURL=cms-adapter.d.ts.map
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { getEffective, resolveDefinition, set, clear, resetNamespace, registerDefinitions, NON_REGISTER_DEFINITION_OPS, parseNonRegisterDefinitionOp, collectChangedNamespaces, } from "../index.js";
|
|
2
|
-
/** Keep the CMS write chokepoint while translating its permission vocabulary to host policy. */
|
|
3
|
-
/** Bind the CMS ledger and write chokepoint without copying their domain logic.
|
|
4
|
-
* Effective reads scan definitions and resolve each namespace key; mutations inherit CMS transactions/errors.
|
|
5
|
-
* @complexity O(1) setup. Per operation: O(definitions + keys) reads, or O(batch size) writes.
|
|
6
|
-
* @example createCmsSettingsService({ deps: cmsPorts, permissions });
|
|
7
|
-
*/
|
|
8
|
-
export function createCmsSettingsService(required) {
|
|
9
|
-
const { deps: original, permissions } = required;
|
|
10
|
-
const permissionMap = new Map([
|
|
11
|
-
["settings.definitions.manage", permissions.manageDefinitions],
|
|
12
|
-
["settings.global.write", permissions.writeGlobal],
|
|
13
|
-
["settings.workspace.write", permissions.writeWorkspace],
|
|
14
|
-
["settings.user.self.write", permissions.writeUserSelf],
|
|
15
|
-
["settings.user.write", permissions.writeUserOther],
|
|
16
|
-
["settings.reset.global", permissions.reset.global],
|
|
17
|
-
["settings.reset.workspace", permissions.reset.workspace],
|
|
18
|
-
["settings.reset.user", permissions.reset.user],
|
|
19
|
-
]);
|
|
20
|
-
const deps = { ...original,
|
|
21
|
-
authorize: (input) => {
|
|
22
|
-
const permission = permissionMap.get(input.permission);
|
|
23
|
-
if (permission === undefined)
|
|
24
|
-
return Promise.resolve({ allowed: false, reason: "unknown_settings_permission" });
|
|
25
|
-
return original.authorize({ ...input, permission });
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
const repo = deps.repo;
|
|
29
|
-
const listDefinitions = async ({ workspaceId }) => {
|
|
30
|
-
const [platform, workspace] = await Promise.all([
|
|
31
|
-
repo.listActiveDefinitions({ workspaceId: null }), repo.listActiveDefinitions({ workspaceId }),
|
|
32
|
-
]);
|
|
33
|
-
return [...platform, ...workspace];
|
|
34
|
-
};
|
|
35
|
-
return {
|
|
36
|
-
listDefinitions,
|
|
37
|
-
effective: async ({ namespace, workspaceId, principalId }) => {
|
|
38
|
-
const defs = await listDefinitions({ workspaceId });
|
|
39
|
-
const keys = new Set(defs.filter((d) => d.namespace === namespace).map((d) => d.key));
|
|
40
|
-
const data = [];
|
|
41
|
-
for (const key of keys) {
|
|
42
|
-
const result = await getEffective({ repo }, { namespace, key, scopeContext: { workspaceId, principalId } });
|
|
43
|
-
if (result)
|
|
44
|
-
data.push({ key, value: result.value, sourceLayer: result.sourceLayer, defVersion: result.defVersion });
|
|
45
|
-
}
|
|
46
|
-
return data;
|
|
47
|
-
},
|
|
48
|
-
raw: async ({ namespace, key, workspaceId, principalId }) => {
|
|
49
|
-
const definition = await resolveDefinition({ repo }, { namespace, key, workspaceId });
|
|
50
|
-
if (!definition)
|
|
51
|
-
return null;
|
|
52
|
-
const settingId = definition.settingId;
|
|
53
|
-
const records = await Promise.all([
|
|
54
|
-
repo.getGlobalValue(settingId), repo.getWorkspaceValue({ workspaceId, settingId }),
|
|
55
|
-
principalId ? repo.getUserValue({ workspaceId, principalId, settingId }) : Promise.resolve(null),
|
|
56
|
-
]);
|
|
57
|
-
const values = records.map((r) => r?.state === "set" ? r.valueJson : null);
|
|
58
|
-
return { key: `${namespace}.${key}`, global: values[0], workspace: values[1], user: values[2], default: definition.defaultValue };
|
|
59
|
-
},
|
|
60
|
-
set: (input) => set({ deps, input }),
|
|
61
|
-
clear: (input) => clear({ deps, input }),
|
|
62
|
-
reset: async (input) => {
|
|
63
|
-
const definitions = await repo.listActiveDefinitions({ workspaceId: input.scope === "global" ? null : (input.workspaceId ?? input.authWorkspaceId ?? null) });
|
|
64
|
-
const keys = definitions.filter((d) => d.namespace === input.namespace).map((d) => d.key);
|
|
65
|
-
return resetNamespace({ deps, input }, keys);
|
|
66
|
-
},
|
|
67
|
-
definitions: ({ items, callerPrincipalId, authWorkspaceId }) => applyDefinitions({ deps, items, callerPrincipalId, authWorkspaceId }),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/** Preserve register batching and ordered non-register writes over existing CMS operation contracts.
|
|
71
|
-
* Unknown operations return their name. Earlier non-register writes are not rolled back by later failures.
|
|
72
|
-
* @complexity O(item count) time/space plus CMS effects; this batch is not atomic.
|
|
73
|
-
*/
|
|
74
|
-
async function applyDefinitions(required) {
|
|
75
|
-
const { deps, items, callerPrincipalId, authWorkspaceId } = required;
|
|
76
|
-
const toRegister = [];
|
|
77
|
-
const applied = [];
|
|
78
|
-
for (const raw of items) {
|
|
79
|
-
const item = raw;
|
|
80
|
-
const op = String(item.op ?? "register");
|
|
81
|
-
const namespace = String(item.namespace ?? "");
|
|
82
|
-
const key = String(item.key ?? "");
|
|
83
|
-
const ownerKind = item.ownerKind;
|
|
84
|
-
const workspaceId = ownerKind === "site" ? authWorkspaceId : null;
|
|
85
|
-
const defaultValue = (item.defaultJson ?? null);
|
|
86
|
-
if (op === "register") {
|
|
87
|
-
toRegister.push({ namespace, key, ownerKind, workspaceId, schema: item.schemaJson,
|
|
88
|
-
defaultValue, scopes: Number(item.scopes), secret: Boolean(item.secret ?? false) });
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
const parsedOp = parseNonRegisterDefinitionOp({ op });
|
|
92
|
-
if (!parsedOp)
|
|
93
|
-
return { unknownOp: op };
|
|
94
|
-
const opItem = { namespace, key, ownerKind, workspaceId, defaultJson: defaultValue,
|
|
95
|
-
...(item.newNamespace === undefined ? {} : { newNamespace: item.newNamespace }),
|
|
96
|
-
...(item.newKey === undefined ? {} : { newKey: item.newKey }),
|
|
97
|
-
...(item.schemaJson === undefined ? {} : { schemaJson: item.schemaJson }),
|
|
98
|
-
...(item.coercionJson === undefined ? {} : { coercionJson: item.coercionJson }),
|
|
99
|
-
};
|
|
100
|
-
await NON_REGISTER_DEFINITION_OPS[parsedOp]({ ctx: { deps, callerPrincipalId, authWorkspaceId }, item: opItem });
|
|
101
|
-
}
|
|
102
|
-
applied.push({ key: `${namespace}.${key}`, op, status: "applied" });
|
|
103
|
-
}
|
|
104
|
-
if (toRegister.length)
|
|
105
|
-
await registerDefinitions({ deps, input: { definitions: toRegister, callerPrincipalId, authWorkspaceId } });
|
|
106
|
-
return { applied };
|
|
107
|
-
}
|
|
108
|
-
/** Adapt the ledger through CMS tenant/principal disclosure rules, returning names and cursors only.
|
|
109
|
-
* @complexity O(1) setup; collect is O(page size), with namespace lookup per visible revision.
|
|
110
|
-
* @example createCmsSettingsChangeFeed({ repo });
|
|
111
|
-
*/
|
|
112
|
-
export function createCmsSettingsChangeFeed(required) {
|
|
113
|
-
const { repo } = required;
|
|
114
|
-
return {
|
|
115
|
-
head: () => repo.maxRevisionSeq(),
|
|
116
|
-
collect: async ({ sinceSeq, limit, viewer }) => {
|
|
117
|
-
const revisions = await repo.listRevisionsSince({ sinceSeq, limit, workspaceId: viewer.workspaceId });
|
|
118
|
-
// Resolve afresh each batch: a rename must never leave a stale namespace cached forever.
|
|
119
|
-
const batch = await collectChangedNamespaces({ revisions, viewer, resolveNamespace: async ({ settingId }) => (await repo.findDefinitionBySettingId({ settingId }))?.namespace ?? null });
|
|
120
|
-
return { ...batch, examinedCount: revisions.length };
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
//# sourceMappingURL=cms-adapter.js.map
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import type { Request, Response, Express } from "express";
|
|
2
|
-
import type { SettingScope, SettingDefinitionRecord, SetValueRequired, ClearValueRequired, ResetNamespaceRequired, ChangeFeedViewer, ChangeFeedBatch } from "../index.js";
|
|
3
|
-
export type Authorize = (required: {
|
|
4
|
-
principalId: string;
|
|
5
|
-
workspaceId: string;
|
|
6
|
-
permission: string;
|
|
7
|
-
entityType: string;
|
|
8
|
-
}) => Promise<{
|
|
9
|
-
allowed: boolean;
|
|
10
|
-
reason: string;
|
|
11
|
-
}>;
|
|
12
|
-
export type PrincipalResolver = (required: {
|
|
13
|
-
request: Request;
|
|
14
|
-
response: Response;
|
|
15
|
-
}) => Promise<{
|
|
16
|
-
id: string;
|
|
17
|
-
} | null> | {
|
|
18
|
-
id: string;
|
|
19
|
-
} | null;
|
|
20
|
-
export interface Scheduler {
|
|
21
|
-
/** Return an idempotent cancellation callback. */
|
|
22
|
-
every(required: {
|
|
23
|
-
intervalMs: number;
|
|
24
|
-
callback: () => void;
|
|
25
|
-
}): () => void;
|
|
26
|
-
}
|
|
27
|
-
export interface SettingsPermissions {
|
|
28
|
-
read: string;
|
|
29
|
-
readRaw: string;
|
|
30
|
-
readDefinitions: string;
|
|
31
|
-
readOtherUser: string;
|
|
32
|
-
manageDefinitions: string;
|
|
33
|
-
writeGlobal: string;
|
|
34
|
-
writeWorkspace: string;
|
|
35
|
-
writeUserSelf: string;
|
|
36
|
-
writeUserOther: string;
|
|
37
|
-
reset: Record<SettingScope, string>;
|
|
38
|
-
}
|
|
39
|
-
export interface SettingsRoutes {
|
|
40
|
-
definitions: string;
|
|
41
|
-
effective: string;
|
|
42
|
-
raw: string;
|
|
43
|
-
value: string;
|
|
44
|
-
reset: string;
|
|
45
|
-
events: string;
|
|
46
|
-
workspaceParam: string;
|
|
47
|
-
}
|
|
48
|
-
export type EffectiveSettingRow = {
|
|
49
|
-
key: string;
|
|
50
|
-
value: unknown;
|
|
51
|
-
sourceLayer: string;
|
|
52
|
-
defVersion: number;
|
|
53
|
-
};
|
|
54
|
-
export type RawSetting = {
|
|
55
|
-
key: string;
|
|
56
|
-
global: unknown;
|
|
57
|
-
workspace: unknown;
|
|
58
|
-
user: unknown;
|
|
59
|
-
default: unknown;
|
|
60
|
-
};
|
|
61
|
-
export type DefinitionResult = {
|
|
62
|
-
applied: Array<{
|
|
63
|
-
key: string;
|
|
64
|
-
op: string;
|
|
65
|
-
status: string;
|
|
66
|
-
}>;
|
|
67
|
-
} | {
|
|
68
|
-
unknownOp: string;
|
|
69
|
-
};
|
|
70
|
-
export interface SettingsService {
|
|
71
|
-
listDefinitions(required: {
|
|
72
|
-
workspaceId: string;
|
|
73
|
-
}): Promise<SettingDefinitionRecord[]>;
|
|
74
|
-
effective(required: {
|
|
75
|
-
namespace: string;
|
|
76
|
-
workspaceId: string;
|
|
77
|
-
principalId: string | undefined;
|
|
78
|
-
}): Promise<EffectiveSettingRow[]>;
|
|
79
|
-
raw(required: {
|
|
80
|
-
namespace: string;
|
|
81
|
-
key: string;
|
|
82
|
-
workspaceId: string;
|
|
83
|
-
principalId: string | undefined;
|
|
84
|
-
}): Promise<RawSetting | null>;
|
|
85
|
-
set(required: SetValueRequired["input"]): Promise<{
|
|
86
|
-
value: unknown;
|
|
87
|
-
revisionSeq: number;
|
|
88
|
-
}>;
|
|
89
|
-
clear(required: ClearValueRequired["input"]): Promise<{
|
|
90
|
-
revisionSeq: number;
|
|
91
|
-
}>;
|
|
92
|
-
reset(required: ResetNamespaceRequired["input"]): Promise<{
|
|
93
|
-
clearedCount: number;
|
|
94
|
-
revisionSeqs: number[];
|
|
95
|
-
}>;
|
|
96
|
-
definitions(required: {
|
|
97
|
-
items: readonly unknown[];
|
|
98
|
-
callerPrincipalId: string;
|
|
99
|
-
authWorkspaceId: string;
|
|
100
|
-
}): Promise<DefinitionResult>;
|
|
101
|
-
}
|
|
102
|
-
export interface SettingsChangeFeed {
|
|
103
|
-
head(required: Record<string, never>): Promise<number>;
|
|
104
|
-
/** Cursor advances across invisible rows. The emitted id MUST use batch.cursor, never head. */
|
|
105
|
-
collect(required: {
|
|
106
|
-
sinceSeq: number;
|
|
107
|
-
limit: number;
|
|
108
|
-
viewer: ChangeFeedViewer;
|
|
109
|
-
}): Promise<ChangeFeedBatch & {
|
|
110
|
-
examinedCount: number;
|
|
111
|
-
}>;
|
|
112
|
-
}
|
|
113
|
-
export interface SettingsHttpRequired {
|
|
114
|
-
app: Pick<Express, "get" | "post" | "put" | "delete">;
|
|
115
|
-
workspaceId: string;
|
|
116
|
-
ready: Promise<void>;
|
|
117
|
-
service: SettingsService;
|
|
118
|
-
changeFeed: SettingsChangeFeed;
|
|
119
|
-
principalResolver: PrincipalResolver;
|
|
120
|
-
authorize: Authorize;
|
|
121
|
-
scheduler: Scheduler;
|
|
122
|
-
routes: SettingsRoutes;
|
|
123
|
-
permissions: SettingsPermissions;
|
|
124
|
-
}
|
|
125
|
-
export interface SettingsHttpOptions {
|
|
126
|
-
pollIntervalMs?: number;
|
|
127
|
-
keepaliveIntervalMs?: number;
|
|
128
|
-
reauthorizeIntervalMs?: number;
|
|
129
|
-
revisionPageSize?: number;
|
|
130
|
-
onError?: (required: {
|
|
131
|
-
operation: string;
|
|
132
|
-
error: unknown;
|
|
133
|
-
}) => void;
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { SettingsHttpRequired, SettingsHttpOptions } from "./contracts.js";
|
|
2
|
-
/** Mount all eight endpoints. The returned disposer closes active feeds and cancels their schedules. */
|
|
3
|
-
/** Injected policy and services preserve the settings HTTP response envelopes.
|
|
4
|
-
* O(1) mounting; read/mutation work is delegated. Feed resources are bounded per connection.
|
|
5
|
-
* @example registerSettingsRoutes({ app, workspaceId, ready, service, changeFeed, principalResolver, authorize, scheduler, routes, permissions });
|
|
6
|
-
*/
|
|
7
|
-
export declare function registerSettingsRoutes(required: SettingsHttpRequired, optional?: SettingsHttpOptions): {
|
|
8
|
-
dispose(): void;
|
|
9
|
-
};
|
|
10
|
-
//# sourceMappingURL=http.d.ts.map
|