@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/index.d.ts
CHANGED
|
@@ -1,123 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* resolved value, which layers schema defaults, the registrant's composition
|
|
5
|
-
* `base`, and the user document section, in that order.
|
|
6
|
-
* @module @deepseek-ai/dsh-settings
|
|
7
|
-
*/
|
|
8
|
-
import { Context, Service } from '@deepseek-ai/cordis';
|
|
9
|
-
import type z from '@deepseek-ai/schemastery';
|
|
10
|
-
import type { RedactedSecret } from './redact.ts';
|
|
11
|
-
import type { SettingsNamespace, SettingsUpdateSource } from './types.ts';
|
|
1
|
+
import { Context, Service, type Fiber } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type RedactedSecret } from './redact.ts';
|
|
3
|
+
import type { SettingsNamespace } from './types.ts';
|
|
12
4
|
export { redactSecrets } from './redact.ts';
|
|
13
5
|
export type { RedactedSecret, RedactedValue } from './redact.ts';
|
|
14
|
-
export type { SettingsNamespace
|
|
15
|
-
|
|
16
|
-
type DecimalDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
|
17
|
-
type NamespaceCharacter = LowercaseLetter | DecimalDigit | '-';
|
|
18
|
-
type ValidNamespaceTail<Value extends string> = Value extends '' ? true : Value extends `${NamespaceCharacter}${infer Rest}` ? ValidNamespaceTail<Rest> : false;
|
|
19
|
-
type SettingsNamespaceInput<Value extends string> = Value extends SettingsNamespace ? Value : string extends Value ? string : Value extends `${LowercaseLetter}${infer Rest}` ? ValidNamespaceTail<Rest> extends true ? Value : never : never;
|
|
20
|
-
/** When a namespace's changes take effect for its owner. */
|
|
21
|
-
export type SettingsApplies = 'live' | 'restart';
|
|
22
|
-
/** Registration options beyond the namespace schema. */
|
|
23
|
-
export interface SettingsRegisterOptions<T> {
|
|
24
|
-
/** Composition-layer values resolved below the user layer (entry-config subset). */
|
|
25
|
-
base?: Partial<T>;
|
|
26
|
-
/** Owner's effect timing, surfaced to configuration UIs; defaults to `live`. */
|
|
27
|
-
applies?: SettingsApplies;
|
|
28
|
-
/**
|
|
29
|
-
* Reject a resolved section the owner could not act on, for constraints its
|
|
30
|
-
* schema cannot express — a cross-field requirement, or one field's validity
|
|
31
|
-
* depending on another's. Throwing here refuses the *write* that produced the
|
|
32
|
-
* value, so a caller learns at `update`/`replace`/`mutate` instead of storing
|
|
33
|
-
* something that would silently disable the owner.
|
|
34
|
-
*
|
|
35
|
-
* Kept separate from the schema because the schema is also what a
|
|
36
|
-
* configuration surface renders and what an absent section resolves through;
|
|
37
|
-
* folding a cross-field check into it would change both.
|
|
38
|
-
*
|
|
39
|
-
* Once the owner is registered, a stored section that fails this keeps the
|
|
40
|
-
* namespace's last good value and warns, exactly as a schema failure does,
|
|
41
|
-
* so an externally edited document cannot strand a running owner. At
|
|
42
|
-
* registration there is no last good value yet, so a stored section that
|
|
43
|
-
* already fails rejects the registration itself — again exactly as a schema
|
|
44
|
-
* failure does.
|
|
45
|
-
* @param value - the resolved section, schema-valid by construction.
|
|
46
|
-
*/
|
|
47
|
-
validate?: (value: T) => void;
|
|
48
|
-
}
|
|
49
|
-
/** One registered namespace as surfaced to configuration UIs. */
|
|
6
|
+
export type { SettingsNamespace } from './types.ts';
|
|
7
|
+
/** One Loader entry's live Config fields. */
|
|
50
8
|
export interface SettingsDescriptor {
|
|
51
|
-
/** The registered namespace. */
|
|
52
9
|
ns: SettingsNamespace;
|
|
53
|
-
/**
|
|
10
|
+
/** Whether the UI may generate a page when no custom page exists. */
|
|
11
|
+
autoGenerate: boolean;
|
|
54
12
|
schema: unknown;
|
|
55
|
-
/** Current resolved value. */
|
|
56
13
|
value: unknown;
|
|
57
|
-
/**
|
|
58
|
-
* Monotonic revision of the raw user section this descriptor was read at.
|
|
59
|
-
* Send it back as `expectedRevision` on a write to refuse a stale one.
|
|
60
|
-
*/
|
|
61
14
|
revision: number;
|
|
62
|
-
/** Registrant's composition `base` layer (detached), when one was declared. */
|
|
63
15
|
base?: unknown;
|
|
64
|
-
/**
|
|
65
|
-
* Raw user section from the stored document (detached), when one exists and
|
|
66
|
-
* is well-formed; a field's presence here is what marks it user-overridden.
|
|
67
|
-
*/
|
|
68
16
|
user?: unknown;
|
|
69
|
-
|
|
70
|
-
applies: SettingsApplies;
|
|
71
|
-
/** Schema-declared secret positions; present only under `redactSecrets`. */
|
|
17
|
+
applies: 'live';
|
|
72
18
|
secrets?: RedactedSecret[];
|
|
73
19
|
}
|
|
74
|
-
/**
|
|
20
|
+
/** Wire readers always request secret redaction. */
|
|
75
21
|
export interface SettingsDescribeOptions {
|
|
76
|
-
/**
|
|
77
|
-
* Strip `role('secret')` fields from `value`/`base`/`user` and enumerate
|
|
78
|
-
* them in each descriptor's `secrets`. Every wire surface MUST pass this;
|
|
79
|
-
* the verbatim default exists for same-process configuration UIs only.
|
|
80
|
-
*/
|
|
81
22
|
redactSecrets?: boolean;
|
|
82
23
|
}
|
|
83
|
-
/** Owner-facing handle for one registered namespace. */
|
|
84
|
-
export interface SettingsScope<T> {
|
|
85
|
-
/** Current resolved value: schema defaults, then `base`, then the user layer. */
|
|
86
|
-
get(): T;
|
|
87
|
-
/**
|
|
88
|
-
* Observe committed changes to this namespace's resolved value. Invocations
|
|
89
|
-
* of one callback run asynchronously, one at a time, in commit order; a
|
|
90
|
-
* rejection is contained and logged like a sync throw. After the disposer
|
|
91
|
-
* returns, no further invocation starts — one already queued is skipped;
|
|
92
|
-
* one already started still settles, and service disposal waits for it.
|
|
93
|
-
* @param callback - invoked after each commit with the next and previous values.
|
|
94
|
-
* @returns the disposer removing this observer.
|
|
95
|
-
*/
|
|
96
|
-
watch(callback: (next: T, prev: T) => void | Promise<void>): () => void;
|
|
97
|
-
/**
|
|
98
|
-
* Merge a partial patch into this namespace's user layer and persist it.
|
|
99
|
-
* @param patch - plain-object patch over the user section; JSON-compatible data
|
|
100
|
-
* only (non-JSON values reject with their path before anything persists).
|
|
101
|
-
*/
|
|
102
|
-
update(patch: object): Promise<void>;
|
|
103
|
-
/**
|
|
104
|
-
* Replace this namespace's user section wholesale; absent keys re-inherit
|
|
105
|
-
* the composition `base` and schema defaults (`replace({})` resets all).
|
|
106
|
-
* @param section - the complete next user section; JSON-compatible data only,
|
|
107
|
-
* as for {@link update}.
|
|
108
|
-
*/
|
|
109
|
-
replace(section: object): Promise<void>;
|
|
110
|
-
}
|
|
111
24
|
declare module '@deepseek-ai/cordis' {
|
|
112
25
|
interface Context {
|
|
113
|
-
|
|
26
|
+
/** Schema-derived plugin configuration forms. */
|
|
27
|
+
settings: SettingsForms;
|
|
114
28
|
}
|
|
115
29
|
}
|
|
116
|
-
/**
|
|
117
|
-
* A write refused because the namespace moved since the caller read it. The
|
|
118
|
-
* Service Definition's serialized write queue orders writes; it cannot tell a fresh writer
|
|
119
|
-
* from one holding a stale snapshot, which is what this reports.
|
|
120
|
-
*/
|
|
30
|
+
/** Refusal to overwrite configuration changed since the form was read. */
|
|
121
31
|
export declare class SettingsConflictError extends Error {
|
|
122
32
|
/** Stable machine code for wire layers mapping this to their own taxonomy. */
|
|
123
33
|
readonly code = "SETTINGS_CONFLICT";
|
|
@@ -148,189 +58,62 @@ export type SettingsPathOp = {
|
|
|
148
58
|
op: 'unset';
|
|
149
59
|
path: readonly string[];
|
|
150
60
|
};
|
|
151
|
-
/**
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
private readonly
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
*
|
|
184
|
-
* @returns
|
|
185
|
-
*/
|
|
186
|
-
get documentPath(): string | undefined;
|
|
187
|
-
/**
|
|
188
|
-
* Prepare the provider's user-editable document for a native editor. File
|
|
189
|
-
* providers may materialize an absent document before returning its path;
|
|
190
|
-
* non-file providers return undefined.
|
|
191
|
-
* @returns the absolute local document path, or undefined for non-file storage.
|
|
192
|
-
*/
|
|
193
|
-
prepareDocument(): Promise<string | undefined>;
|
|
194
|
-
/**
|
|
195
|
-
* Read the provider's current raw document (namespace to raw section).
|
|
196
|
-
* @returns the detached raw document.
|
|
197
|
-
*/
|
|
198
|
-
protected abstract load(): Promise<Record<string, unknown>>;
|
|
199
|
-
/**
|
|
200
|
-
* Durably store one namespace's merged user section.
|
|
201
|
-
* @param ns - the namespace being written.
|
|
202
|
-
* @param section - the complete merged user section to store.
|
|
203
|
-
*/
|
|
204
|
-
protected abstract persist(ns: SettingsNamespace, section: Record<string, unknown>): Promise<void>;
|
|
205
|
-
/**
|
|
206
|
-
* Register a namespace schema and receive its owner scope. The registration
|
|
207
|
-
* is an effect on the calling plugin's fiber: disposing that fiber removes
|
|
208
|
-
* the namespace and its observers. An invalid stored section fails the
|
|
209
|
-
* registration itself — the earliest point where the schema can judge it.
|
|
210
|
-
* @param ns - unique namespace; duplicate registration fails loud.
|
|
211
|
-
* @param schema - schemastery schema resolving this namespace's value.
|
|
212
|
-
* @param options - composition `base` layer and effect timing.
|
|
213
|
-
* @returns the owner scope for reads, observation, and updates.
|
|
214
|
-
* @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
|
|
215
|
-
*/
|
|
216
|
-
register<const Namespace extends string, T>(ns: Namespace & SettingsNamespaceInput<Namespace>, schema: z<T>, options?: SettingsRegisterOptions<T>): SettingsScope<T>;
|
|
217
|
-
/**
|
|
218
|
-
* Attach one optional-settings consumer to this provider. The consumer
|
|
219
|
-
* registers its composition entry as the base layer while this provider is
|
|
220
|
-
* present, then falls back to that entry if the provider detaches.
|
|
221
|
-
* @param owner - consumer context whose unload suppresses fallback work.
|
|
222
|
-
* @param ns - consumer-owned settings namespace.
|
|
223
|
-
* @param schema - schema resolving the namespace.
|
|
224
|
-
* @param entry - composition entry used as the base and fallback value.
|
|
225
|
-
* @param hooks - source sink, change notification, and optional validation.
|
|
226
|
-
* @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
|
|
227
|
-
*/
|
|
228
|
-
installSection<const Namespace extends string, T>(owner: Context, ns: Namespace & SettingsNamespaceInput<Namespace>, schema: z<T>, entry: T, hooks: SettingsSectionHooks<T>): void;
|
|
229
|
-
/**
|
|
230
|
-
* Describe every registered namespace for configuration surfaces, including
|
|
231
|
-
* the composition `base` and raw user layers so a form can mark which fields
|
|
232
|
-
* the user overrode (presence in `user`) and what a reset returns to.
|
|
233
|
-
* @param options - redaction switch; wire surfaces must redact.
|
|
234
|
-
* @returns one descriptor per registered namespace, in registration order.
|
|
61
|
+
/** Project Config schemas into forms and own optional instance-level UI policy. */
|
|
62
|
+
export declare class SettingsForms extends Service {
|
|
63
|
+
private readonly ownerContext;
|
|
64
|
+
static inject: string[];
|
|
65
|
+
private revisions;
|
|
66
|
+
private closed;
|
|
67
|
+
private scheduled;
|
|
68
|
+
private readonly presentations;
|
|
69
|
+
constructor(ownerContext: Context);
|
|
70
|
+
/** Move the sections of the removed `settings.yaml` into the active profile once the Loader has settled every entry.
|
|
71
|
+
* The document is renamed before the first write, so a partial import never repeats; a section the running
|
|
72
|
+
* composition rejects is logged and remains only in the renamed file. */
|
|
73
|
+
private importLegacyDocument;
|
|
74
|
+
/** Register the calling plugin instance's page policy without changing its Config.
|
|
75
|
+
* @param presentation Automatic-page policy for this instance; `auto` defaults to true.
|
|
76
|
+
* @param owner Plugin instance the policy belongs to; defaults to the calling fiber.
|
|
77
|
+
* @returns Disposer; register it with the calling plugin's effects.
|
|
78
|
+
* @throws If this instance already has a registered policy.
|
|
79
|
+
*/
|
|
80
|
+
configure(presentation: {
|
|
81
|
+
auto?: boolean;
|
|
82
|
+
}, owner?: Fiber): () => void;
|
|
83
|
+
private invalidate;
|
|
84
|
+
/** Whether the active profile accepts form edits. */
|
|
85
|
+
get writable(): boolean;
|
|
86
|
+
/** Current profile patch shown by the native configuration editor. */
|
|
87
|
+
get documentPath(): string;
|
|
88
|
+
/** Locate the profile patch for native editing.
|
|
89
|
+
* @returns The existing profile patch path.
|
|
90
|
+
*/
|
|
91
|
+
prepareDocument(): Promise<string>;
|
|
92
|
+
/** Read active plugin schemas and their live values.
|
|
93
|
+
* @param options Redaction required for remote callers.
|
|
94
|
+
* @returns Forms keyed by unique profile entry ids.
|
|
235
95
|
*/
|
|
236
96
|
describe(options?: SettingsDescribeOptions): SettingsDescriptor[];
|
|
237
|
-
/**
|
|
238
|
-
*
|
|
239
|
-
* @param
|
|
240
|
-
* @
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
* @param ns
|
|
251
|
-
* @param
|
|
252
|
-
* @param expectedRevision
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
*/
|
|
256
|
-
update<const Namespace extends string>(ns: Namespace & SettingsNamespaceInput<Namespace>, patch: object, expectedRevision?: number): Promise<void>;
|
|
257
|
-
/**
|
|
258
|
-
* Replace one registered namespace's user section wholesale, validate,
|
|
259
|
-
* persist, then commit and emit. Keys absent from `section` fall back to the
|
|
260
|
-
* composition `base` and schema defaults — this is the removal/reset path a
|
|
261
|
-
* merge-only patch cannot express (`replace({})` re-inherits everything).
|
|
262
|
-
* @param ns - the registered namespace to replace.
|
|
263
|
-
* @param section - the complete next user section.
|
|
264
|
-
* @param expectedRevision - the descriptor `revision` the caller read; a
|
|
265
|
-
* namespace that moved past it rejects with {@link SettingsConflictError}.
|
|
266
|
-
* @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
|
|
267
|
-
*/
|
|
268
|
-
replace<const Namespace extends string>(ns: Namespace & SettingsNamespaceInput<Namespace>, section: object, expectedRevision?: number): Promise<void>;
|
|
269
|
-
/**
|
|
270
|
-
* Apply path-addressed edits to one registered namespace's user section,
|
|
271
|
-
* validate, persist, then commit and emit. The ops are applied to the
|
|
272
|
-
* section as it stands when the write reaches the front of the queue, so a
|
|
273
|
-
* caller never has to restate fields it did not touch — and, crucially,
|
|
274
|
-
* cannot delete fields it never saw. This is the write path for any caller
|
|
275
|
-
* holding a redacted view; `replace` remains the wholesale reset.
|
|
276
|
-
* @param ns - the registered namespace to edit.
|
|
277
|
-
* @param ops - ordered path edits; later ops observe earlier ones.
|
|
278
|
-
* @param expectedRevision - the descriptor `revision` the caller read; a
|
|
279
|
-
* namespace that moved past it rejects with {@link SettingsConflictError}.
|
|
280
|
-
* @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
|
|
281
|
-
*/
|
|
282
|
-
mutate<const Namespace extends string>(ns: Namespace & SettingsNamespaceInput<Namespace>, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise<void>;
|
|
283
|
-
/** Validate a write, then queue it on the namespace's serialized write chain. */
|
|
97
|
+
/** Merge editable fields into an entry's config.
|
|
98
|
+
* @param ns Profile entry id.
|
|
99
|
+
* @param patch Fields to merge.
|
|
100
|
+
* @param expectedRevision Revision returned by describe.
|
|
101
|
+
*/
|
|
102
|
+
update(ns: string, patch: object, expectedRevision?: number): Promise<void>;
|
|
103
|
+
/** Reset all live fields, then set the supplied fields; ordinary config is preserved.
|
|
104
|
+
* @param ns Profile entry id.
|
|
105
|
+
* @param section Complete form values.
|
|
106
|
+
* @param expectedRevision Revision returned by describe.
|
|
107
|
+
*/
|
|
108
|
+
replace(ns: string, section: object, expectedRevision?: number): Promise<void>;
|
|
109
|
+
/** Apply field edits without restating redacted secrets; unsetting an array index removes its element.
|
|
110
|
+
* @param ns Profile entry id.
|
|
111
|
+
* @param ops Ordered form edits.
|
|
112
|
+
* @param expectedRevision Revision returned by describe.
|
|
113
|
+
*/
|
|
114
|
+
mutate(ns: string, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise<void>;
|
|
284
115
|
private write;
|
|
285
|
-
|
|
286
|
-
* Provider hook: commit a complete raw document observed in storage. Each
|
|
287
|
-
* registered namespace re-resolves; an invalid section keeps that
|
|
288
|
-
* namespace's last good value and warns, other namespaces still commit.
|
|
289
|
-
* @param doc - the detached raw document (unregistered sections preserved).
|
|
290
|
-
* @param source - change origin; defaults to `provider`.
|
|
291
|
-
*/
|
|
292
|
-
protected publish(doc: Record<string, unknown>, source?: SettingsUpdateSource): void;
|
|
293
|
-
/** Read one namespace's raw user section, rejecting non-object sections. */
|
|
294
|
-
private section;
|
|
295
|
-
/** Resolve one namespace value: schema defaults, then `base`, then the user layer. */
|
|
296
|
-
private resolve;
|
|
297
|
-
/**
|
|
298
|
-
* Advance a namespace's revision when its RAW section changed, and announce
|
|
299
|
-
* it. Deliberately independent of {@link commit}'s resolved-value equality:
|
|
300
|
-
* storing an override equal to the composition base leaves the resolved
|
|
301
|
-
* value alone but changes what the document says, which is exactly what a
|
|
302
|
-
* configuration surface must re-read.
|
|
303
|
-
*/
|
|
304
|
-
private bumpRevision;
|
|
305
|
-
/** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */
|
|
306
|
-
private emitDocumentUpdated;
|
|
307
|
-
/** Commit a resolved value when changed: swap, notify watchers, emit the event. */
|
|
308
|
-
private commit;
|
|
309
|
-
/** Contained-watcher diagnostic shared by the sync and async failure paths. */
|
|
310
|
-
private warnWatcherFailure;
|
|
311
|
-
/** Contained-listener diagnostic shared by the sync and async failure paths. */
|
|
312
|
-
private warnListenerFailure;
|
|
313
|
-
}
|
|
314
|
-
/** Hooks a consumer hands to {@link SettingsProvider.installSection}. */
|
|
315
|
-
export interface SettingsSectionHooks<T> {
|
|
316
|
-
/**
|
|
317
|
-
* Receive the active configuration source: the resolved settings scope
|
|
318
|
-
* while one is attached, the composition entry otherwise. Called before
|
|
319
|
-
* the matching `onChange` at attach and at detach.
|
|
320
|
-
* @param current - thunk returning the currently authoritative value.
|
|
321
|
-
*/
|
|
322
|
-
setSource(current: () => T): void;
|
|
323
|
-
/**
|
|
324
|
-
* Re-judge anything derived from the source — registration-level facts,
|
|
325
|
-
* memoized resolutions — after an attach, a detach, or a committed change.
|
|
326
|
-
*/
|
|
327
|
-
onChange(): void;
|
|
328
|
-
/**
|
|
329
|
-
* Reject a resolved section this consumer could not act on, for constraints
|
|
330
|
-
* its schema cannot express. See {@link SettingsRegisterOptions.validate}.
|
|
331
|
-
* @param value - the resolved section, schema-valid by construction.
|
|
332
|
-
*/
|
|
333
|
-
validate?: (value: T) => void;
|
|
116
|
+
private schema;
|
|
334
117
|
}
|
|
335
|
-
export default
|
|
118
|
+
export default SettingsForms;
|
|
336
119
|
//# sourceMappingURL=index.d.ts.map
|