@deepseek-ai/dsh-settings 0.1.6-alpha.2 → 0.1.7-alpha.2
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/README.i18n.yaml +2 -2
- package/README.md +19 -96
- package/README.zh.md +25 -102
- package/lib/index.js +360 -426
- package/lib/types/index.d.ts +66 -283
- package/lib/types/index.js +271 -512
- package/lib/types/redact.d.ts +2 -4
- package/lib/types/redact.js +14 -8
- package/lib/types/schema.d.ts +24 -0
- package/lib/types/schema.js +85 -0
- package/lib/types/types.d.ts +16 -44
- package/lib/types/types.js +1 -9
- package/package.json +21 -17
- package/lib/invariant.js +0 -35
- package/lib/types/invariant.d.ts +0 -16
- package/lib/types/invariant.js +0 -41
package/lib/types/redact.d.ts
CHANGED
|
@@ -27,10 +27,8 @@ export interface RedactedValue {
|
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Remove every `role('secret')` field a schema declares from a value. The
|
|
30
|
-
* walker
|
|
31
|
-
*
|
|
32
|
-
* buried inside a union branch or transform is not reachable and must not be
|
|
33
|
-
* modeled that way). The input is never mutated.
|
|
30
|
+
* walker visits every union branch, conservatively removing any field declared
|
|
31
|
+
* secret by a branch. The input is never mutated.
|
|
34
32
|
* @param schema - live schemastery schema describing the value.
|
|
35
33
|
* @param value - the value to strip; `undefined` yields an empty record with
|
|
36
34
|
* object-property secret slots still enumerated.
|
package/lib/types/redact.js
CHANGED
|
@@ -52,19 +52,19 @@ function walk(node, value, path, secrets) {
|
|
|
52
52
|
return value;
|
|
53
53
|
return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets));
|
|
54
54
|
}
|
|
55
|
+
case 'union':
|
|
56
|
+
case 'intersect':
|
|
57
|
+
return (node.list ?? []).reduce((current, child) => walk(child, current, path, secrets), value);
|
|
58
|
+
case 'transform':
|
|
59
|
+
return walk(node.inner, value, path, secrets);
|
|
55
60
|
default:
|
|
56
|
-
// TODO(settings-wire-redaction): Fail closed instead — a secret reachable
|
|
57
|
-
// only through a union, intersection, or transform is returned verbatim
|
|
58
|
-
// here, with nothing recording that it was missed.
|
|
59
61
|
return value;
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
/**
|
|
63
65
|
* Remove every `role('secret')` field a schema declares from a value. The
|
|
64
|
-
* walker
|
|
65
|
-
*
|
|
66
|
-
* buried inside a union branch or transform is not reachable and must not be
|
|
67
|
-
* modeled that way). The input is never mutated.
|
|
66
|
+
* walker visits every union branch, conservatively removing any field declared
|
|
67
|
+
* secret by a branch. The input is never mutated.
|
|
68
68
|
* @param schema - live schemastery schema describing the value.
|
|
69
69
|
* @param value - the value to strip; `undefined` yields an empty record with
|
|
70
70
|
* object-property secret slots still enumerated.
|
|
@@ -73,6 +73,12 @@ function walk(node, value, path, secrets) {
|
|
|
73
73
|
export function redactSecrets(schema, value) {
|
|
74
74
|
const secrets = [];
|
|
75
75
|
const stripped = walk(schema, value, [], secrets);
|
|
76
|
-
|
|
76
|
+
const positions = new Map();
|
|
77
|
+
for (const secret of secrets) {
|
|
78
|
+
const key = JSON.stringify(secret.path);
|
|
79
|
+
const previous = positions.get(key);
|
|
80
|
+
positions.set(key, { ...secret, set: secret.set || previous?.set === true });
|
|
81
|
+
}
|
|
82
|
+
return { value: stripped, secrets: [...positions.values()] };
|
|
77
83
|
}
|
|
78
84
|
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import z from '@deepseek-ai/schemastery';
|
|
2
|
+
/** Remove runtime references from a configuration snapshot.
|
|
3
|
+
* @param value Parsed Config output.
|
|
4
|
+
* @returns Detached ordinary values suitable for redaction and forms.
|
|
5
|
+
*/
|
|
6
|
+
export declare function plainConfig(value: unknown): unknown;
|
|
7
|
+
/** Select fields whose nearest volatile ancestor makes them editable without remounting.
|
|
8
|
+
* @param schema The plugin's Config schema.
|
|
9
|
+
* @returns A plain form schema, or undefined when no field is live.
|
|
10
|
+
*/
|
|
11
|
+
export declare function volatileForm(schema: z): z | undefined;
|
|
12
|
+
/** Project only schema-declared fields, excluding ordinary configuration.
|
|
13
|
+
* @param schema The filtered form schema.
|
|
14
|
+
* @param value Plain raw or resolved config.
|
|
15
|
+
* @returns The fields visible to this form.
|
|
16
|
+
*/
|
|
17
|
+
export declare function projectForm(schema: z, value: unknown): unknown;
|
|
18
|
+
/** Check that a field path lies beneath a declared volatile node.
|
|
19
|
+
* @param schema Complete plugin Config schema.
|
|
20
|
+
* @param path Field path addressed by a form edit.
|
|
21
|
+
* @returns Whether the path can be edited live.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isVolatilePath(schema: z, path: readonly string[]): boolean;
|
|
24
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Derive editable forms and plain values from plugin Config schemas. */
|
|
2
|
+
import { redactSecrets } from "./redact.js";
|
|
3
|
+
import z from '@deepseek-ai/schemastery';
|
|
4
|
+
import { isVolatile } from '@deepseek-ai/cosmokit';
|
|
5
|
+
/** Remove runtime references from a configuration snapshot.
|
|
6
|
+
* @param value Parsed Config output.
|
|
7
|
+
* @returns Detached ordinary values suitable for redaction and forms.
|
|
8
|
+
*/
|
|
9
|
+
export function plainConfig(value) {
|
|
10
|
+
if (isVolatile(value))
|
|
11
|
+
return plainConfig(value.get());
|
|
12
|
+
if (Array.isArray(value))
|
|
13
|
+
return value.map(plainConfig);
|
|
14
|
+
if (value !== null && typeof value === 'object') {
|
|
15
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, plainConfig(child)]));
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function plainSchema(schema) {
|
|
20
|
+
const result = new z(schema.toJSON());
|
|
21
|
+
const walk = (node) => {
|
|
22
|
+
delete node.meta.volatile;
|
|
23
|
+
if (node.meta.role === 'secret') {
|
|
24
|
+
delete node.meta.default;
|
|
25
|
+
delete node.meta.required;
|
|
26
|
+
}
|
|
27
|
+
else if (node.meta.default !== undefined)
|
|
28
|
+
node.meta.default = redactSecrets(node, node.meta.default).value;
|
|
29
|
+
for (const child of Object.values(node.dict ?? {}))
|
|
30
|
+
walk(child);
|
|
31
|
+
if (node.inner)
|
|
32
|
+
walk(node.inner);
|
|
33
|
+
for (const child of node.list ?? [])
|
|
34
|
+
walk(child);
|
|
35
|
+
};
|
|
36
|
+
walk(result);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/** Select fields whose nearest volatile ancestor makes them editable without remounting.
|
|
40
|
+
* @param schema The plugin's Config schema.
|
|
41
|
+
* @returns A plain form schema, or undefined when no field is live.
|
|
42
|
+
*/
|
|
43
|
+
export function volatileForm(schema) {
|
|
44
|
+
if (schema.meta.volatile)
|
|
45
|
+
return plainSchema(schema);
|
|
46
|
+
if (schema.type === 'object') {
|
|
47
|
+
const dict = Object.fromEntries(Object.entries(schema.dict ?? {}).flatMap(([key, child]) => {
|
|
48
|
+
const field = volatileForm(child);
|
|
49
|
+
return field === undefined ? [] : [[key, field]];
|
|
50
|
+
}));
|
|
51
|
+
return Object.keys(dict).length === 0 ? undefined : z.object(dict);
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
/** Whether a raw config node is an unevaluated `!!js` expression, kept whole rather than projected field by field. */
|
|
56
|
+
function isExpression(value) {
|
|
57
|
+
return Object.keys(value).length === 1 && typeof Reflect.get(value, '__jsExpr') === 'string';
|
|
58
|
+
}
|
|
59
|
+
/** Project only schema-declared fields, excluding ordinary configuration.
|
|
60
|
+
* @param schema The filtered form schema.
|
|
61
|
+
* @param value Plain raw or resolved config.
|
|
62
|
+
* @returns The fields visible to this form.
|
|
63
|
+
*/
|
|
64
|
+
export function projectForm(schema, value) {
|
|
65
|
+
if (schema.type === 'object' && value !== null && typeof value === 'object' && !isExpression(value)) {
|
|
66
|
+
return Object.fromEntries(Object.entries(schema.dict ?? {}).flatMap(([key, child]) => {
|
|
67
|
+
const field = Reflect.get(value, key);
|
|
68
|
+
return field === undefined ? [] : [[key, projectForm(child, field)]];
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
/** Check that a field path lies beneath a declared volatile node.
|
|
74
|
+
* @param schema Complete plugin Config schema.
|
|
75
|
+
* @param path Field path addressed by a form edit.
|
|
76
|
+
* @returns Whether the path can be edited live.
|
|
77
|
+
*/
|
|
78
|
+
export function isVolatilePath(schema, path) {
|
|
79
|
+
if (schema.meta.volatile)
|
|
80
|
+
return true;
|
|
81
|
+
const [key, ...rest] = path;
|
|
82
|
+
const child = key === undefined ? undefined : schema.dict?.[key];
|
|
83
|
+
return child !== undefined && isVolatilePath(child, rest);
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=schema.js.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-safe type surface of the user-settings seam: the namespace brand, the
|
|
3
|
-
* commit-origin union, the redacted views a configuration surface reads over
|
|
4
|
-
* the Remote wire, and the seam's Cordis event declarations. Types only — no
|
|
5
|
-
* runtime code, and nothing here reaches a Host-only symbol, so a Client
|
|
6
|
-
* compilation face reads exactly the signatures the Host emits.
|
|
7
|
-
*
|
|
8
|
-
* @module @deepseek-ai/dsh-settings/types
|
|
9
|
-
*/
|
|
1
|
+
/** Client-safe configuration form views and change notifications. */
|
|
10
2
|
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
11
3
|
import type { JsonValue } from '@deepseek-ai/dsh-util-values';
|
|
12
|
-
/** Nominal id of one
|
|
4
|
+
/** Nominal id of one profile plugin entry. */
|
|
13
5
|
export type SettingsNamespace = Branded<'SettingsNamespace'>;
|
|
14
|
-
/** Origin of one committed settings change. */
|
|
15
|
-
export type SettingsUpdateSource = 'update' | 'provider';
|
|
16
6
|
/** One schema-declared secret slot inside a redacted namespace value. */
|
|
17
7
|
export interface SettingsSecretView {
|
|
18
8
|
/** Path from the section root to the removed field. */
|
|
@@ -21,27 +11,29 @@ export interface SettingsSecretView {
|
|
|
21
11
|
set: boolean;
|
|
22
12
|
}
|
|
23
13
|
/**
|
|
24
|
-
* Wire view of one
|
|
14
|
+
* Wire view of one profile plugin entry, always read under `redactSecrets`. The
|
|
25
15
|
* JSON-valued fields are `JsonValue` rather than the descriptor's `unknown`
|
|
26
16
|
* because the Remote boundary admits no unconstrained data.
|
|
27
17
|
*/
|
|
28
18
|
export interface SettingsNamespaceView {
|
|
19
|
+
/** Generate a page if no custom page is registered for this instance. */
|
|
20
|
+
autoGenerate: boolean;
|
|
29
21
|
/** Namespace key (`llm-deepseek`, `llm-pi-ai`, …). */
|
|
30
22
|
ns: string;
|
|
31
23
|
/** Serialized schemastery schema envelope (`schema.toJSON()`); rehydrate with `new Schema(json)`. */
|
|
32
24
|
schema: JsonValue;
|
|
33
25
|
/** Redacted resolved value (schema defaults → composition base → user layer). */
|
|
34
26
|
value: JsonValue;
|
|
35
|
-
/** Redacted composition base layer,
|
|
27
|
+
/** Redacted composition base layer, with defaults resolved. */
|
|
36
28
|
base?: JsonValue;
|
|
37
29
|
/** Redacted raw user section, when one exists; a field's presence here marks it user-overridden. */
|
|
38
30
|
user?: JsonValue;
|
|
39
31
|
/** When the owner applies changes. */
|
|
40
|
-
applies: 'live'
|
|
32
|
+
applies: 'live';
|
|
41
33
|
/** Every schema-declared secret slot with its configured state. */
|
|
42
34
|
secrets: SettingsSecretView[];
|
|
43
35
|
/**
|
|
44
|
-
* Monotonic revision of the raw
|
|
36
|
+
* Monotonic revision of the raw entry configuration this view was read at. Send it
|
|
45
37
|
* back as `expectedRevision` on a write so a stale editor is refused rather
|
|
46
38
|
* than silently overwriting a concurrent change.
|
|
47
39
|
*/
|
|
@@ -60,42 +52,22 @@ export type SettingsPathOpView = {
|
|
|
60
52
|
op: 'unset';
|
|
61
53
|
path: string[];
|
|
62
54
|
};
|
|
63
|
-
/** Every
|
|
55
|
+
/** Every profile plugin entry with the deployment facts a configuration page renders around them. */
|
|
64
56
|
export interface SettingsDescribeValue {
|
|
65
|
-
/** Whether the
|
|
57
|
+
/** Whether the profile accepts writes; `false` disables every write control. */
|
|
66
58
|
writable: boolean;
|
|
67
|
-
/** Whether
|
|
59
|
+
/** Whether the configuration editor owns a local document, without exposing its Host path. */
|
|
68
60
|
hasDocument: boolean;
|
|
69
|
-
/** One view per
|
|
61
|
+
/** One view per profile plugin entry. */
|
|
70
62
|
namespaces: SettingsNamespaceView[];
|
|
71
63
|
}
|
|
72
64
|
declare module '@deepseek-ai/cordis' {
|
|
73
65
|
interface Events {
|
|
74
66
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* rejection alike — except `INVARIANT`-coded failures, which rethrow
|
|
80
|
-
* after every listener ran; that rethrow reaches the emitter only from
|
|
81
|
-
* synchronous listeners, so invariant checks on this event must not be
|
|
82
|
-
* async functions.
|
|
83
|
-
* @param ns - the namespace whose resolved value changed.
|
|
84
|
-
* @param next - the new resolved value.
|
|
85
|
-
* @param prev - the previous resolved value.
|
|
86
|
-
* @param source - whether the change entered through `update()` or the provider.
|
|
87
|
-
* @mode emit
|
|
88
|
-
*/
|
|
89
|
-
'settings/updated'(ns: SettingsNamespace, next: unknown, prev: unknown, source: SettingsUpdateSource): void;
|
|
90
|
-
/**
|
|
91
|
-
* One registered namespace's RAW user section changed, whether or not the
|
|
92
|
-
* resolved value did. `settings/updated` is the consumer-facing event and
|
|
93
|
-
* stays deep-equal-gated; this one exists for configuration surfaces,
|
|
94
|
-
* which must learn that a field went from inherited to overridden (same
|
|
95
|
-
* resolved value, different meaning) and that their held revision is
|
|
96
|
-
* stale. Listener containment matches `settings/updated`.
|
|
97
|
-
* @param ns - the namespace whose stored section changed.
|
|
98
|
-
* @param revision - the namespace's new revision.
|
|
67
|
+
* One profile entry's form values, availability, or page policy changed.
|
|
68
|
+
* Form clients re-read its schema, resolved values, and revision.
|
|
69
|
+
* @param ns Profile entry id.
|
|
70
|
+
* @param revision The entry's new revision.
|
|
99
71
|
* @mode emit
|
|
100
72
|
*/
|
|
101
73
|
'settings/document-updated'(ns: SettingsNamespace, revision: number): void;
|
package/lib/types/types.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-safe type surface of the user-settings seam: the namespace brand, the
|
|
3
|
-
* commit-origin union, the redacted views a configuration surface reads over
|
|
4
|
-
* the Remote wire, and the seam's Cordis event declarations. Types only — no
|
|
5
|
-
* runtime code, and nothing here reaches a Host-only symbol, so a Client
|
|
6
|
-
* compilation face reads exactly the signatures the Host emits.
|
|
7
|
-
*
|
|
8
|
-
* @module @deepseek-ai/dsh-settings/types
|
|
9
|
-
*/
|
|
1
|
+
/** Client-safe configuration form views and change notifications. */
|
|
10
2
|
export {};
|
|
11
3
|
//# sourceMappingURL=types.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-settings",
|
|
3
3
|
"description": "Abstract user-settings seam (ctx.settings) for the DeepSeek Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"types": "./lib/types/index.d.ts",
|
|
19
19
|
"default": "./lib/index.js"
|
|
20
20
|
},
|
|
21
|
-
"./invariant": {
|
|
22
|
-
"types": "./lib/types/invariant.d.ts",
|
|
23
|
-
"default": "./lib/invariant.js"
|
|
24
|
-
},
|
|
25
21
|
"./types": {
|
|
26
22
|
"types": "./lib/types/types.d.ts",
|
|
27
23
|
"default": "./lib/types/types.js"
|
|
@@ -31,26 +27,34 @@
|
|
|
31
27
|
},
|
|
32
28
|
"files": [
|
|
33
29
|
"lib/index.js",
|
|
34
|
-
"lib/invariant.js",
|
|
35
30
|
"lib/types/**/*.js",
|
|
36
31
|
"lib/types/**/*.d.ts"
|
|
37
32
|
],
|
|
38
33
|
"license": "MIT",
|
|
39
34
|
"peerDependencies": {
|
|
40
|
-
"@deepseek-ai/cordis": "
|
|
41
|
-
"@deepseek-ai/dsh-session": "
|
|
42
|
-
"@deepseek-ai/dsh-
|
|
43
|
-
"@deepseek-ai/schemastery": "
|
|
44
|
-
"@deepseek-ai/dsh-
|
|
35
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
36
|
+
"@deepseek-ai/dsh-session": "0.1.7-alpha.2",
|
|
37
|
+
"@deepseek-ai/dsh-brand": "0.1.7-alpha.2",
|
|
38
|
+
"@deepseek-ai/schemastery": "~3.18.4",
|
|
39
|
+
"@deepseek-ai/dsh-invariants": "0.1.7-alpha.2"
|
|
45
40
|
},
|
|
46
41
|
"devDependencies": {
|
|
47
|
-
"
|
|
48
|
-
"@deepseek-ai/
|
|
49
|
-
"@deepseek-ai/dsh-
|
|
50
|
-
"@deepseek-ai/dsh-
|
|
51
|
-
"@deepseek-ai/
|
|
42
|
+
"yaml": "^2.8.1",
|
|
43
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
44
|
+
"@deepseek-ai/dsh-brand": "0.1.7-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-invariants": "0.1.7-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-session": "0.1.7-alpha.2",
|
|
47
|
+
"@deepseek-ai/schemastery": "~3.18.4",
|
|
48
|
+
"@deepseek-ai/cordis-plugin-timer": "~1.1.6",
|
|
49
|
+
"@deepseek-ai/dsh-app-boot": "0.1.7-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-hmr": "0.1.7-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-agent-default-model": "0.1.7-alpha.2"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"
|
|
54
|
+
"yaml": "^2.8.1",
|
|
55
|
+
"@deepseek-ai/dsh-util-values": "0.1.7-alpha.2",
|
|
56
|
+
"@deepseek-ai/dsh-config-editor": "0.1.7-alpha.2",
|
|
57
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.5",
|
|
58
|
+
"@deepseek-ai/cosmokit": "~1.8.5"
|
|
55
59
|
}
|
|
56
60
|
}
|
package/lib/invariant.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { deepEqualJson } from "@deepseek-ai/dsh-util-values";
|
|
2
|
-
//#region lib/types/invariant.js
|
|
3
|
-
/**
|
|
4
|
-
* Package-owned invariant companion for `@deepseek-ai/dsh-settings`.
|
|
5
|
-
* @module @deepseek-ai/dsh-settings/invariant
|
|
6
|
-
*/
|
|
7
|
-
const PACKAGE_NAME = "@deepseek-ai/dsh-settings";
|
|
8
|
-
/** Cordis companion plugin name. */
|
|
9
|
-
const name = "settings-invariant";
|
|
10
|
-
/** Service required before the companion can reserve package ownership. */
|
|
11
|
-
const inject = ["invariants"];
|
|
12
|
-
/**
|
|
13
|
-
* Install the commit-event contract: `settings/updated` fires only for a
|
|
14
|
-
* currently registered namespace, only when the resolved value changed, and
|
|
15
|
-
* only with the service's authoritative resolved value — all judged with the
|
|
16
|
-
* seam's own equality predicate.
|
|
17
|
-
*/
|
|
18
|
-
const install = (ctx, fail) => {
|
|
19
|
-
ctx.on("settings/updated", (ns, next, prev) => {
|
|
20
|
-
const settings = ctx.get("settings");
|
|
21
|
-
if (settings === void 0) fail(`settings/updated for "${ns}" emitted without a live settings service`);
|
|
22
|
-
const current = settings.get(ns);
|
|
23
|
-
if (current === void 0) fail(`settings/updated for "${ns}" emitted while the namespace is unregistered`);
|
|
24
|
-
if (!deepEqualJson(current, next)) fail(`settings/updated for "${ns}" does not match the authoritative resolved value`);
|
|
25
|
-
if (deepEqualJson(next, prev)) fail(`settings/updated for "${ns}" emitted without a resolved-value change`);
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Register this package's invariant companion.
|
|
30
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
31
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
32
|
-
*/
|
|
33
|
-
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
34
|
-
//#endregion
|
|
35
|
-
export { apply, inject, name };
|
package/lib/types/invariant.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package-owned invariant companion for `@deepseek-ai/dsh-settings`.
|
|
3
|
-
* @module @deepseek-ai/dsh-settings/invariant
|
|
4
|
-
*/
|
|
5
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
-
/** Cordis companion plugin name. */
|
|
7
|
-
export declare const name = "settings-invariant";
|
|
8
|
-
/** Service required before the companion can reserve package ownership. */
|
|
9
|
-
export declare const inject: string[];
|
|
10
|
-
/**
|
|
11
|
-
* Register this package's invariant companion.
|
|
12
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
-
*/
|
|
15
|
-
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
-
//# sourceMappingURL=invariant.d.ts.map
|
package/lib/types/invariant.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package-owned invariant companion for `@deepseek-ai/dsh-settings`.
|
|
3
|
-
* @module @deepseek-ai/dsh-settings/invariant
|
|
4
|
-
*/
|
|
5
|
-
import { deepEqualJson } from '@deepseek-ai/dsh-util-values';
|
|
6
|
-
const PACKAGE_NAME = '@deepseek-ai/dsh-settings';
|
|
7
|
-
/** Cordis companion plugin name. */
|
|
8
|
-
export const name = 'settings-invariant';
|
|
9
|
-
/** Service required before the companion can reserve package ownership. */
|
|
10
|
-
export const inject = ['invariants'];
|
|
11
|
-
/**
|
|
12
|
-
* Install the commit-event contract: `settings/updated` fires only for a
|
|
13
|
-
* currently registered namespace, only when the resolved value changed, and
|
|
14
|
-
* only with the service's authoritative resolved value — all judged with the
|
|
15
|
-
* seam's own equality predicate.
|
|
16
|
-
*/
|
|
17
|
-
const install = (ctx, fail) => {
|
|
18
|
-
ctx.on('settings/updated', (ns, next, prev) => {
|
|
19
|
-
const settings = ctx.get('settings');
|
|
20
|
-
if (settings === undefined) {
|
|
21
|
-
fail(`settings/updated for "${ns}" emitted without a live settings service`);
|
|
22
|
-
}
|
|
23
|
-
const current = settings.get(ns);
|
|
24
|
-
if (current === undefined) {
|
|
25
|
-
fail(`settings/updated for "${ns}" emitted while the namespace is unregistered`);
|
|
26
|
-
}
|
|
27
|
-
if (!deepEqualJson(current, next)) {
|
|
28
|
-
fail(`settings/updated for "${ns}" does not match the authoritative resolved value`);
|
|
29
|
-
}
|
|
30
|
-
if (deepEqualJson(next, prev)) {
|
|
31
|
-
fail(`settings/updated for "${ns}" emitted without a resolved-value change`);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Register this package's invariant companion.
|
|
37
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
38
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
39
|
-
*/
|
|
40
|
-
export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
41
|
-
//# sourceMappingURL=invariant.js.map
|