hiwork-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js ADDED
@@ -0,0 +1,3643 @@
1
+ // node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.3/node_modules/@deepseek-ai/cosmokit/lib/index.js
2
+ function isNullable(value) {
3
+ return value === null || value === void 0;
4
+ }
5
+ function isPlainObject(data) {
6
+ return data && typeof data === "object" && !Array.isArray(data);
7
+ }
8
+ function filterKeys(object, filter) {
9
+ return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)));
10
+ }
11
+ function mapValues(object, transform) {
12
+ return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)]));
13
+ }
14
+ function pick(source, keys, forced) {
15
+ if (!keys) return { ...source };
16
+ const result = {};
17
+ for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
18
+ return result;
19
+ }
20
+ function defineProperty(object, key, value) {
21
+ return Object.defineProperty(object, key, {
22
+ writable: true,
23
+ value,
24
+ enumerable: false
25
+ });
26
+ }
27
+ function is(type, value) {
28
+ if (arguments.length === 1) return (value2) => is(type, value2);
29
+ return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type;
30
+ }
31
+ function isArrayBufferLike(value) {
32
+ return is("ArrayBuffer", value) || is("SharedArrayBuffer", value);
33
+ }
34
+ function isArrayBufferSource(value) {
35
+ return isArrayBufferLike(value) || ArrayBuffer.isView(value);
36
+ }
37
+ var Binary;
38
+ (function(Binary2) {
39
+ Binary2.is = isArrayBufferLike;
40
+ Binary2.isSource = isArrayBufferSource;
41
+ function fromSource(source) {
42
+ if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
43
+ else return source;
44
+ }
45
+ Binary2.fromSource = fromSource;
46
+ function toBase64(source) {
47
+ source = fromSource(source);
48
+ if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64");
49
+ let binary = "";
50
+ const bytes = new Uint8Array(source);
51
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
52
+ return btoa(binary);
53
+ }
54
+ Binary2.toBase64 = toBase64;
55
+ function fromBase64(source) {
56
+ if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64"));
57
+ return Uint8Array.from(atob(source), (c) => c.charCodeAt(0));
58
+ }
59
+ Binary2.fromBase64 = fromBase64;
60
+ function toHex(source) {
61
+ source = fromSource(source);
62
+ if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex");
63
+ return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join("");
64
+ }
65
+ Binary2.toHex = toHex;
66
+ function fromHex(source) {
67
+ if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex"));
68
+ const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1);
69
+ const buffer = [];
70
+ for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16));
71
+ return Uint8Array.from(buffer).buffer;
72
+ }
73
+ Binary2.fromHex = fromHex;
74
+ })(Binary || (Binary = {}));
75
+ var base64ToArrayBuffer = Binary.fromBase64;
76
+ var arrayBufferToBase64 = Binary.toBase64;
77
+ var hexToArrayBuffer = Binary.fromHex;
78
+ var arrayBufferToHex = Binary.toHex;
79
+ function clone(source, refs = /* @__PURE__ */ new Map()) {
80
+ if (!source || typeof source !== "object") return source;
81
+ if (is("Date", source)) return new Date(source.valueOf());
82
+ if (is("RegExp", source)) return new RegExp(source.source, source.flags);
83
+ if (isArrayBufferLike(source)) return source.slice(0);
84
+ if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
85
+ const cached = refs.get(source);
86
+ if (cached) return cached;
87
+ if (Array.isArray(source)) {
88
+ const result2 = [];
89
+ refs.set(source, result2);
90
+ source.forEach((value, index) => {
91
+ result2[index] = Reflect.apply(clone, null, [value, refs]);
92
+ });
93
+ return result2;
94
+ }
95
+ const result = Object.create(Object.getPrototypeOf(source));
96
+ refs.set(source, result);
97
+ for (const key of Reflect.ownKeys(source)) {
98
+ const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) };
99
+ if ("value" in descriptor) descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]);
100
+ Reflect.defineProperty(result, key, descriptor);
101
+ }
102
+ return result;
103
+ }
104
+ function deepEqual(a, b, strict) {
105
+ if (a === b) return true;
106
+ if (!strict && isNullable(a) && isNullable(b)) return true;
107
+ if (typeof a !== typeof b) return false;
108
+ if (typeof a !== "object") return false;
109
+ if (!a || !b) return false;
110
+ function check(test, then) {
111
+ return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
112
+ }
113
+ return check(Array.isArray, (a2, b2) => a2.length === b2.length && a2.every((item, index) => deepEqual(item, b2[index]))) ?? check(is("Date"), (a2, b2) => a2.valueOf() === b2.valueOf()) ?? check(is("RegExp"), (a2, b2) => a2.source === b2.source && a2.flags === b2.flags) ?? check(isArrayBufferLike, (a2, b2) => {
114
+ if (a2.byteLength !== b2.byteLength) return false;
115
+ const viewA = new Uint8Array(a2);
116
+ const viewB = new Uint8Array(b2);
117
+ for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
118
+ return true;
119
+ }) ?? Object.keys({
120
+ ...a,
121
+ ...b
122
+ }).every((key) => deepEqual(a[key], b[key], strict));
123
+ }
124
+ function tokenize(source, delimiters, delimiter) {
125
+ const output = [];
126
+ let state = 0;
127
+ for (let i = 0; i < source.length; i++) {
128
+ const code = source.charCodeAt(i);
129
+ if (code >= 65 && code <= 90) {
130
+ if (state === 1) {
131
+ const next = source.charCodeAt(i + 1);
132
+ if (next >= 97 && next <= 122) output.push(delimiter);
133
+ output.push(code + 32);
134
+ } else {
135
+ if (state !== 0) output.push(delimiter);
136
+ output.push(code + 32);
137
+ }
138
+ state = 1;
139
+ } else if (code >= 97 && code <= 122) {
140
+ output.push(code);
141
+ state = 2;
142
+ } else if (delimiters.includes(code)) {
143
+ if (state !== 0) output.push(delimiter);
144
+ state = 0;
145
+ } else output.push(code);
146
+ }
147
+ return String.fromCharCode(...output);
148
+ }
149
+ function paramCase(source) {
150
+ return tokenize(source, [45, 95], 45);
151
+ }
152
+ var hyphenate = paramCase;
153
+ var Time;
154
+ (function(Time2) {
155
+ Time2.millisecond = 1;
156
+ Time2.second = 1e3;
157
+ Time2.minute = Time2.second * 60;
158
+ Time2.hour = Time2.minute * 60;
159
+ Time2.day = Time2.hour * 24;
160
+ Time2.week = Time2.day * 7;
161
+ let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
162
+ function setTimezoneOffset(offset) {
163
+ timezoneOffset = offset;
164
+ }
165
+ Time2.setTimezoneOffset = setTimezoneOffset;
166
+ function getTimezoneOffset() {
167
+ return timezoneOffset;
168
+ }
169
+ Time2.getTimezoneOffset = getTimezoneOffset;
170
+ function getDateNumber(date2 = /* @__PURE__ */ new Date(), offset) {
171
+ if (typeof date2 === "number") date2 = new Date(date2);
172
+ if (offset === void 0) offset = timezoneOffset;
173
+ return Math.floor((date2.valueOf() / Time2.minute - offset) / 1440);
174
+ }
175
+ Time2.getDateNumber = getDateNumber;
176
+ function fromDateNumber(value, offset) {
177
+ const date2 = new Date(value * Time2.day);
178
+ if (offset === void 0) offset = timezoneOffset;
179
+ return new Date(+date2 + offset * Time2.minute);
180
+ }
181
+ Time2.fromDateNumber = fromDateNumber;
182
+ const numeric = /\d+(?:\.\d+)?/.source;
183
+ const timeRegExp = new RegExp(`^${[
184
+ "w(?:eek(?:s)?)?",
185
+ "d(?:ay(?:s)?)?",
186
+ "h(?:our(?:s)?)?",
187
+ "m(?:in(?:ute)?(?:s)?)?",
188
+ "s(?:ec(?:ond)?(?:s)?)?"
189
+ ].map((unit) => `(${numeric}${unit})?`).join("")}$`);
190
+ function parseTime(source) {
191
+ const capture = timeRegExp.exec(source);
192
+ if (!capture) return 0;
193
+ return (parseFloat(capture[1]) * Time2.week || 0) + (parseFloat(capture[2]) * Time2.day || 0) + (parseFloat(capture[3]) * Time2.hour || 0) + (parseFloat(capture[4]) * Time2.minute || 0) + (parseFloat(capture[5]) * Time2.second || 0);
194
+ }
195
+ Time2.parseTime = parseTime;
196
+ function parseDate(date2) {
197
+ const parsed = parseTime(date2);
198
+ if (parsed) date2 = Date.now() + parsed;
199
+ else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date2)) date2 = `${(/* @__PURE__ */ new Date()).toLocaleDateString()}-${date2}`;
200
+ else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date2)) date2 = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date2}`;
201
+ return date2 ? new Date(date2) : /* @__PURE__ */ new Date();
202
+ }
203
+ Time2.parseDate = parseDate;
204
+ function format(ms) {
205
+ const abs = Math.abs(ms);
206
+ if (abs >= Time2.day - Time2.hour / 2) return Math.round(ms / Time2.day) + "d";
207
+ else if (abs >= Time2.hour - Time2.minute / 2) return Math.round(ms / Time2.hour) + "h";
208
+ else if (abs >= Time2.minute - Time2.second / 2) return Math.round(ms / Time2.minute) + "m";
209
+ else if (abs >= Time2.second) return Math.round(ms / Time2.second) + "s";
210
+ return ms + "ms";
211
+ }
212
+ Time2.format = format;
213
+ function toDigits(source, length = 2) {
214
+ return source.toString().padStart(length, "0");
215
+ }
216
+ Time2.toDigits = toDigits;
217
+ function template(template2, time = /* @__PURE__ */ new Date()) {
218
+ return template2.replace("yyyy", time.getFullYear().toString()).replace("yy", time.getFullYear().toString().slice(2)).replace("MM", toDigits(time.getMonth() + 1)).replace("dd", toDigits(time.getDate())).replace("hh", toDigits(time.getHours())).replace("mm", toDigits(time.getMinutes())).replace("ss", toDigits(time.getSeconds())).replace("SSS", toDigits(time.getMilliseconds(), 3));
219
+ }
220
+ Time2.template = template;
221
+ })(Time || (Time = {}));
222
+
223
+ // node_modules/.pnpm/@deepseek-ai+schemastery@3.18.2/node_modules/@deepseek-ai/schemastery/lib/index.mjs
224
+ var kSchema = Symbol.for("schemastery");
225
+ var kValidationError = Symbol.for("ValidationError");
226
+ globalThis.__schemastery_index__ ??= 0;
227
+ globalThis.__schemastery_refs__ = void 0;
228
+ var ValidationError = class extends TypeError {
229
+ options;
230
+ name = "ValidationError";
231
+ constructor(message, options) {
232
+ let prefix = "$";
233
+ for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment;
234
+ else if (typeof segment === "number") prefix += "[" + segment + "]";
235
+ else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`;
236
+ if (prefix.startsWith(".")) prefix = prefix.slice(1);
237
+ super((prefix === "$" ? "" : `${prefix} `) + message);
238
+ this.options = options;
239
+ }
240
+ static is(error) {
241
+ return !!error?.[kValidationError];
242
+ }
243
+ };
244
+ Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
245
+ var Schema = function(options) {
246
+ const schema = function(data, options2 = {}) {
247
+ return Schema.resolve(data, schema, options2)[0];
248
+ };
249
+ if (options.refs) {
250
+ const refs = mapValues(options.refs, (options2) => new Schema(options2));
251
+ const getRef = (uid) => refs[uid];
252
+ for (const key in refs) {
253
+ const options2 = refs[key];
254
+ options2.sKey = getRef(options2.sKey);
255
+ options2.inner = getRef(options2.inner);
256
+ options2.list = options2.list && options2.list.map(getRef);
257
+ options2.dict = options2.dict && mapValues(options2.dict, getRef);
258
+ }
259
+ return refs[options.uid];
260
+ }
261
+ Object.assign(schema, options);
262
+ if (typeof schema.callback === "string") try {
263
+ schema.callback = new Function("return " + schema.callback)();
264
+ } catch {
265
+ }
266
+ Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ });
267
+ Object.setPrototypeOf(schema, Schema.prototype);
268
+ schema.meta ||= {};
269
+ schema.toString = schema.toString.bind(schema);
270
+ return schema;
271
+ };
272
+ Schema.prototype = Object.create(Function.prototype);
273
+ Schema.prototype[kSchema] = true;
274
+ Object.defineProperty(Schema.prototype, "~standard", { get() {
275
+ return {
276
+ version: 1,
277
+ vendor: "schemastery",
278
+ validate: (value) => {
279
+ try {
280
+ return { value: Schema.resolve(value, this, {})[0] };
281
+ } catch (error) {
282
+ if (ValidationError.is(error)) return { issues: [{
283
+ message: error.message,
284
+ path: error.options.path
285
+ }] };
286
+ throw error;
287
+ }
288
+ }
289
+ };
290
+ } });
291
+ Schema.ValidationError = ValidationError;
292
+ Schema.prototype.toJSON = function toJSON() {
293
+ if (globalThis.__schemastery_refs__) {
294
+ globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }));
295
+ return this.uid;
296
+ }
297
+ globalThis.__schemastery_refs__ = { [this.uid]: { ...this } };
298
+ globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }));
299
+ const result = {
300
+ uid: this.uid,
301
+ refs: globalThis.__schemastery_refs__
302
+ };
303
+ globalThis.__schemastery_refs__ = void 0;
304
+ return result;
305
+ };
306
+ Schema.prototype.set = function set(key, value) {
307
+ this.dict[key] = value;
308
+ return this;
309
+ };
310
+ Schema.prototype.push = function push(value) {
311
+ this.list.push(value);
312
+ return this;
313
+ };
314
+ function mergeDesc(original, messages) {
315
+ const result = typeof original === "string" ? { "": original } : { ...original };
316
+ for (const locale in messages) {
317
+ const value = messages[locale];
318
+ if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc;
319
+ else if (typeof value === "string") result[locale] = value;
320
+ }
321
+ return result;
322
+ }
323
+ function getInner(value) {
324
+ return value?.$value ?? value?.$inner;
325
+ }
326
+ function extractKeys(data) {
327
+ return filterKeys(data ?? {}, (key) => !key.startsWith("$"));
328
+ }
329
+ Schema.prototype.i18n = function i18n(messages) {
330
+ const schema = Schema(this);
331
+ const desc = mergeDesc(schema.meta.description, messages);
332
+ if (Object.keys(desc).length) schema.meta.description = desc;
333
+ if (schema.dict) schema.dict = mapValues(schema.dict, (inner, key) => {
334
+ return inner.i18n(mapValues(messages, (data) => getInner(data)?.[key] ?? data?.[key]));
335
+ });
336
+ if (schema.list) schema.list = schema.list.map((inner, index) => {
337
+ return inner.i18n(mapValues(messages, (data = {}) => {
338
+ if (Array.isArray(getInner(data))) return getInner(data)[index];
339
+ if (Array.isArray(data)) return data[index];
340
+ return extractKeys(data);
341
+ }));
342
+ });
343
+ if (schema.inner) schema.inner = schema.inner.i18n(mapValues(messages, (data) => {
344
+ if (getInner(data)) return getInner(data);
345
+ return extractKeys(data);
346
+ }));
347
+ if (schema.sKey) schema.sKey = schema.sKey.i18n(mapValues(messages, (data) => data?.$key));
348
+ return schema;
349
+ };
350
+ Schema.prototype.extra = function extra(key, value) {
351
+ const schema = Schema(this);
352
+ schema.meta = {
353
+ ...schema.meta,
354
+ [key]: value
355
+ };
356
+ return schema;
357
+ };
358
+ for (const key of [
359
+ "required",
360
+ "disabled",
361
+ "collapse",
362
+ "hidden",
363
+ "loose"
364
+ ]) Object.assign(Schema.prototype, { [key](value = true) {
365
+ const schema = Schema(this);
366
+ schema.meta = {
367
+ ...schema.meta,
368
+ [key]: value
369
+ };
370
+ return schema;
371
+ } });
372
+ Schema.prototype.deprecated = function deprecated() {
373
+ const schema = Schema(this);
374
+ schema.meta.badges ||= [];
375
+ schema.meta.badges.push({
376
+ text: "deprecated",
377
+ type: "danger"
378
+ });
379
+ return schema;
380
+ };
381
+ Schema.prototype.experimental = function experimental() {
382
+ const schema = Schema(this);
383
+ schema.meta.badges ||= [];
384
+ schema.meta.badges.push({
385
+ text: "experimental",
386
+ type: "warning"
387
+ });
388
+ return schema;
389
+ };
390
+ Schema.prototype.pattern = function pattern(regexp) {
391
+ const schema = Schema(this);
392
+ const pattern2 = pick(regexp, ["source", "flags"]);
393
+ schema.meta = {
394
+ ...schema.meta,
395
+ pattern: pattern2
396
+ };
397
+ return schema;
398
+ };
399
+ Schema.prototype.simplify = function simplify(value) {
400
+ if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
401
+ if (isNullable(value)) return value;
402
+ if (this.type === "object" || this.type === "dict") {
403
+ const result = {};
404
+ for (const key in value) {
405
+ const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]);
406
+ if (this.type === "dict" || !isNullable(item)) result[key] = item;
407
+ }
408
+ if (deepEqual(result, this.meta.default, this.type === "dict")) return null;
409
+ return result;
410
+ } else if (this.type === "array" || this.type === "tuple") {
411
+ const result = [];
412
+ value.forEach((value2, index) => {
413
+ const schema = this.type === "array" ? this.inner : this.list[index];
414
+ const item = schema ? schema.simplify(value2) : value2;
415
+ result.push(item);
416
+ });
417
+ return result;
418
+ } else if (this.type === "intersect") {
419
+ const result = {};
420
+ for (const item of this.list) Object.assign(result, item.simplify(value));
421
+ return result;
422
+ } else if (this.type === "union") for (const schema of this.list) try {
423
+ Schema.resolve(value, schema, {});
424
+ return schema.simplify(value);
425
+ } catch {
426
+ }
427
+ return value;
428
+ };
429
+ Schema.prototype.toString = function toString(inline) {
430
+ return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`;
431
+ };
432
+ Schema.prototype.role = function role(role, extra2) {
433
+ const schema = Schema(this);
434
+ schema.meta = {
435
+ ...schema.meta,
436
+ role,
437
+ extra: extra2
438
+ };
439
+ return schema;
440
+ };
441
+ for (const key of [
442
+ "default",
443
+ "link",
444
+ "comment",
445
+ "description",
446
+ "max",
447
+ "min",
448
+ "step"
449
+ ]) Object.assign(Schema.prototype, { [key](value) {
450
+ const schema = Schema(this);
451
+ schema.meta = {
452
+ ...schema.meta,
453
+ [key]: value
454
+ };
455
+ return schema;
456
+ } });
457
+ var resolvers = {};
458
+ Schema.extend = function extend(type, resolve2) {
459
+ resolvers[type] = resolve2;
460
+ };
461
+ Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
462
+ if (!schema) return [data];
463
+ if (options.ignore?.(data, schema)) return [data];
464
+ if (isNullable(data) && schema.type !== "lazy") {
465
+ if (schema.meta.required) throw new ValidationError(`missing required value`, options);
466
+ let current = schema;
467
+ let fallback = schema.meta.default;
468
+ while (current?.type === "intersect" && isNullable(fallback)) {
469
+ current = current.list[0];
470
+ fallback = current?.meta.default;
471
+ }
472
+ if (isNullable(fallback)) return [data];
473
+ data = clone(fallback);
474
+ }
475
+ const callback = resolvers[schema.type];
476
+ if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options);
477
+ try {
478
+ return callback(data, schema, options, strict);
479
+ } catch (error) {
480
+ if (!schema.meta.loose) throw error;
481
+ return [schema.meta.default];
482
+ }
483
+ };
484
+ Schema.from = function from(source) {
485
+ if (isNullable(source)) return Schema.any();
486
+ else if ([
487
+ "string",
488
+ "number",
489
+ "boolean"
490
+ ].includes(typeof source)) return Schema.const(source).required();
491
+ else if (source[kSchema]) return source;
492
+ else if (typeof source === "function") switch (source) {
493
+ case String:
494
+ return Schema.string().required();
495
+ case Number:
496
+ return Schema.number().required();
497
+ case Boolean:
498
+ return Schema.boolean().required();
499
+ case Function:
500
+ return Schema.function().required();
501
+ default:
502
+ return Schema.is(source).required();
503
+ }
504
+ else throw new TypeError(`cannot infer schema from ${source}`);
505
+ };
506
+ Schema.lazy = function lazy(builder) {
507
+ const toJSON2 = () => {
508
+ if (!schema.inner[kSchema]) {
509
+ schema.inner = schema.builder();
510
+ schema.inner.meta = {
511
+ ...schema.meta,
512
+ ...schema.inner.meta
513
+ };
514
+ }
515
+ return schema.inner.toJSON();
516
+ };
517
+ const schema = new Schema({
518
+ type: "lazy",
519
+ builder,
520
+ inner: { toJSON: toJSON2 }
521
+ });
522
+ return schema;
523
+ };
524
+ Schema.natural = function natural() {
525
+ return Schema.number().step(1).min(0);
526
+ };
527
+ Schema.percent = function percent() {
528
+ return Schema.number().step(0.01).min(0).max(1).role("slider");
529
+ };
530
+ Schema.date = function date() {
531
+ return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => {
532
+ const date2 = new Date(value);
533
+ if (isNaN(+date2)) throw new ValidationError(`invalid date "${value}"`, options);
534
+ return date2;
535
+ }, true)]);
536
+ };
537
+ Schema.regExp = function regExp(flag = "") {
538
+ return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => {
539
+ try {
540
+ return new RegExp(value, flag);
541
+ } catch (e) {
542
+ throw new ValidationError(e.message, options);
543
+ }
544
+ }, true)]);
545
+ };
546
+ Schema.arrayBuffer = function arrayBuffer(encoding) {
547
+ return Schema.union([
548
+ Schema.is(ArrayBuffer),
549
+ Schema.is(SharedArrayBuffer),
550
+ Schema.transform(Schema.any(), (value, options) => {
551
+ if (Binary.isSource(value)) return Binary.fromSource(value);
552
+ throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options);
553
+ }, true),
554
+ ...encoding ? [Schema.transform(Schema.string(), (value, options) => {
555
+ try {
556
+ return encoding === "base64" ? Binary.fromBase64(value) : Binary.fromHex(value);
557
+ } catch (e) {
558
+ throw new ValidationError(e.message, options);
559
+ }
560
+ }, true)] : []
561
+ ]);
562
+ };
563
+ Schema.extend("lazy", (data, schema, options, strict) => {
564
+ if (!schema.inner[kSchema]) {
565
+ schema.inner = schema.builder();
566
+ schema.inner.meta = {
567
+ ...schema.meta,
568
+ ...schema.inner.meta
569
+ };
570
+ }
571
+ return Schema.resolve(data, schema.inner, options, strict);
572
+ });
573
+ Schema.extend("any", (data) => {
574
+ return [data];
575
+ });
576
+ Schema.extend("never", (data, _, options) => {
577
+ throw new ValidationError(`expected nullable but got ${data}`, options);
578
+ });
579
+ Schema.extend("const", (data, { value }, options) => {
580
+ if (deepEqual(data, value)) return [value];
581
+ throw new ValidationError(`expected ${value} but got ${data}`, options);
582
+ });
583
+ function checkWithinRange(data, meta, description, options, skipMin = false) {
584
+ const { max = Infinity, min = -Infinity } = meta;
585
+ if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options);
586
+ if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options);
587
+ }
588
+ Schema.extend("string", (data, { meta }, options) => {
589
+ if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options);
590
+ if (meta.pattern) {
591
+ const regexp = new RegExp(meta.pattern.source, meta.pattern.flags);
592
+ if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options);
593
+ }
594
+ checkWithinRange(data.length, meta, "string length", options);
595
+ return [data];
596
+ });
597
+ function decimalShift(data, digits) {
598
+ const str = data.toString();
599
+ if (str.includes("e")) return data * Math.pow(10, digits);
600
+ const index = str.indexOf(".");
601
+ if (index === -1) return data * Math.pow(10, digits);
602
+ const frac = str.slice(index + 1);
603
+ const integer = str.slice(0, index);
604
+ if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0"));
605
+ return +(integer + frac.slice(0, digits) + "." + frac.slice(digits));
606
+ }
607
+ function isMultipleOf(data, min, step) {
608
+ step = Math.abs(step);
609
+ if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0;
610
+ const index = step.toString().indexOf(".");
611
+ const digits = step.toString().slice(index + 1).length;
612
+ return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0;
613
+ }
614
+ Schema.extend("number", (data, { meta }, options) => {
615
+ if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options);
616
+ checkWithinRange(data, meta, "number", options);
617
+ const { step } = meta;
618
+ if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options);
619
+ return [data];
620
+ });
621
+ Schema.extend("boolean", (data, _, options) => {
622
+ if (typeof data === "boolean") return [data];
623
+ throw new ValidationError(`expected boolean but got ${data}`, options);
624
+ });
625
+ Schema.extend("bitset", (data, { bits, meta }, options) => {
626
+ let value = 0, keys = [];
627
+ if (typeof data === "number") {
628
+ value = data;
629
+ for (const key in bits) if (data & bits[key]) keys.push(key);
630
+ } else if (Array.isArray(data)) {
631
+ keys = data;
632
+ for (const key of keys) {
633
+ if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options);
634
+ if (key in bits) value |= bits[key];
635
+ }
636
+ } else throw new ValidationError(`expected number or array but got ${data}`, options);
637
+ if (value === meta.default) return [value];
638
+ return [value, keys];
639
+ });
640
+ Schema.extend("function", (data, _, options) => {
641
+ if (typeof data === "function") return [data];
642
+ throw new ValidationError(`expected function but got ${data}`, options);
643
+ });
644
+ Schema.extend("is", (data, { constructor }, options) => {
645
+ if (typeof constructor === "function") {
646
+ if (data instanceof constructor) return [data];
647
+ throw new ValidationError(`expected ${constructor.name} but got ${data}`, options);
648
+ } else {
649
+ if (isNullable(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options);
650
+ let prototype = Object.getPrototypeOf(data);
651
+ while (prototype) {
652
+ if (prototype.constructor?.name === constructor) return [data];
653
+ prototype = Object.getPrototypeOf(prototype);
654
+ }
655
+ throw new ValidationError(`expected ${constructor} but got ${data}`, options);
656
+ }
657
+ });
658
+ function property(data, key, schema, options) {
659
+ try {
660
+ const [value, adapted] = Schema.resolve(data[key], schema, {
661
+ ...options,
662
+ path: [...options.path || [], key]
663
+ });
664
+ if (adapted !== void 0) data[key] = adapted;
665
+ return value;
666
+ } catch (e) {
667
+ if (!options?.autofix) throw e;
668
+ delete data[key];
669
+ return schema.meta.default;
670
+ }
671
+ }
672
+ Schema.extend("array", (data, { inner, meta }, options) => {
673
+ if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
674
+ checkWithinRange(data.length, meta, "array length", options, !isNullable(inner.meta.default));
675
+ return [data.map((_, index) => property(data, index, inner, options))];
676
+ });
677
+ Schema.extend("dict", (data, { inner, sKey }, options, strict) => {
678
+ if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
679
+ const result = {};
680
+ for (const key in data) {
681
+ let rKey;
682
+ try {
683
+ rKey = Schema.resolve(key, sKey, options)[0];
684
+ } catch (error) {
685
+ if (strict) continue;
686
+ throw error;
687
+ }
688
+ result[rKey] = property(data, key, inner, options);
689
+ data[rKey] = data[key];
690
+ if (key !== rKey) delete data[key];
691
+ }
692
+ return [result];
693
+ });
694
+ Schema.extend("tuple", (data, { list }, options, strict) => {
695
+ if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
696
+ const result = list.map((inner, index) => property(data, index, inner, options));
697
+ if (strict) return [result];
698
+ result.push(...data.slice(list.length));
699
+ return [result];
700
+ });
701
+ function merge(result, data) {
702
+ for (const key in data) {
703
+ if (key in result) continue;
704
+ result[key] = data[key];
705
+ }
706
+ }
707
+ Schema.extend("object", (data, { dict }, options, strict) => {
708
+ if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
709
+ const result = {};
710
+ for (const key in dict) {
711
+ const value = property(data, key, dict[key], options);
712
+ if (!isNullable(value) || key in data) result[key] = value;
713
+ }
714
+ if (!strict) merge(result, data);
715
+ return [result];
716
+ });
717
+ Schema.extend("union", (data, { list, toString: toString2 }, options, strict) => {
718
+ const messages = [];
719
+ for (const inner of list) try {
720
+ return Schema.resolve(data, inner, options, strict);
721
+ } catch (error) {
722
+ messages.push(error);
723
+ }
724
+ throw new ValidationError(`expected ${toString2()} but got ${JSON.stringify(data)}`, options);
725
+ });
726
+ Schema.extend("intersect", (data, { list, toString: toString2 }, options, strict) => {
727
+ if (!list.length) return [data];
728
+ let result;
729
+ for (const inner of list) {
730
+ const value = Schema.resolve(data, inner, options, true)[0];
731
+ if (isNullable(value)) continue;
732
+ if (isNullable(result)) result = value;
733
+ else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString2()} but got ${JSON.stringify(data)}`, options);
734
+ else if (typeof value === "object") merge(result ??= {}, value);
735
+ else if (result !== value) throw new ValidationError(`expected ${toString2()} but got ${JSON.stringify(data)}`, options);
736
+ }
737
+ if (!strict && isPlainObject(data)) merge(result, data);
738
+ return [result];
739
+ });
740
+ Schema.extend("transform", (data, { inner, callback, preserve }, options) => {
741
+ const [result, adapted = data] = Schema.resolve(data, inner, options, true);
742
+ if (preserve) return [callback(result)];
743
+ else return [callback(result), callback(adapted)];
744
+ });
745
+ var formatters = {};
746
+ function defineMethod(name2, keys, format) {
747
+ formatters[name2] = format;
748
+ Object.assign(Schema, { [name2](...args) {
749
+ const schema = new Schema({ type: name2 });
750
+ keys.forEach((key, index) => {
751
+ switch (key) {
752
+ case "sKey":
753
+ schema.sKey = args[index] ?? Schema.string();
754
+ break;
755
+ case "inner":
756
+ schema.inner = Schema.from(args[index]);
757
+ break;
758
+ case "list":
759
+ schema.list = args[index].map(Schema.from);
760
+ break;
761
+ case "dict":
762
+ schema.dict = mapValues(args[index], Schema.from);
763
+ break;
764
+ case "bits":
765
+ schema.bits = {};
766
+ for (const key2 in args[index]) {
767
+ if (typeof args[index][key2] !== "number") continue;
768
+ schema.bits[key2] = args[index][key2];
769
+ }
770
+ break;
771
+ case "callback": {
772
+ const callback = schema.callback = args[index];
773
+ callback["toJSON"] ||= () => callback.toString();
774
+ break;
775
+ }
776
+ case "constructor": {
777
+ const constructor = schema.constructor = args[index];
778
+ if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"];
779
+ break;
780
+ }
781
+ default:
782
+ schema[key] = args[index];
783
+ }
784
+ });
785
+ if (name2 === "object" || name2 === "dict") schema.meta.default = {};
786
+ else if (name2 === "array" || name2 === "tuple") schema.meta.default = [];
787
+ else if (name2 === "bitset") schema.meta.default = 0;
788
+ return schema;
789
+ } });
790
+ }
791
+ defineMethod("is", ["constructor"], ({ constructor }) => {
792
+ if (typeof constructor === "function") return constructor.name;
793
+ else return constructor;
794
+ });
795
+ defineMethod("any", [], () => "any");
796
+ defineMethod("never", [], () => "never");
797
+ defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value);
798
+ defineMethod("string", [], () => "string");
799
+ defineMethod("number", [], () => "number");
800
+ defineMethod("boolean", [], () => "boolean");
801
+ defineMethod("bitset", ["bits"], () => "bitset");
802
+ defineMethod("function", [], () => "function");
803
+ defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`);
804
+ defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`);
805
+ defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`);
806
+ defineMethod("object", ["dict"], ({ dict }) => {
807
+ if (Object.keys(dict).length === 0) return "{}";
808
+ return `{ ${Object.entries(dict).map(([key, inner]) => {
809
+ return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`;
810
+ }).join(", ")} }`;
811
+ });
812
+ defineMethod("union", ["list"], ({ list }, inline) => {
813
+ const result = list.map(({ toString: format }) => format()).join(" | ");
814
+ return inline ? `(${result})` : result;
815
+ });
816
+ defineMethod("intersect", ["list"], ({ list }) => {
817
+ return `${list.map((inner) => inner.toString(true)).join(" & ")}`;
818
+ });
819
+ defineMethod("transform", [
820
+ "inner",
821
+ "callback",
822
+ "preserve"
823
+ ], ({ inner }, isInner) => inner.toString(isInner));
824
+
825
+ // node_modules/.pnpm/@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/cordis/lib/index.js
826
+ var DisposableList = class {
827
+ sn = 0;
828
+ map = /* @__PURE__ */ new Map();
829
+ weak = /* @__PURE__ */ new WeakMap();
830
+ get length() {
831
+ return this.map.size;
832
+ }
833
+ push(value) {
834
+ const sn = ++this.sn;
835
+ this.map.set(sn, value);
836
+ this.weak.set(value, sn);
837
+ return () => this.map.delete(sn);
838
+ }
839
+ delete(value) {
840
+ const sn = this.weak.get(value);
841
+ if (!sn) return false;
842
+ return this.map.delete(sn);
843
+ }
844
+ clear() {
845
+ const values = [...this.map.values()];
846
+ this.map.clear();
847
+ return values.reverse();
848
+ }
849
+ [Symbol.iterator]() {
850
+ return this.map.values();
851
+ }
852
+ [Symbol.for("nodejs.util.inspect.custom")]() {
853
+ return [...this];
854
+ }
855
+ };
856
+ var symbols = {
857
+ shadow: Symbol.for("cordis.shadow"),
858
+ receiver: Symbol.for("cordis.receiver"),
859
+ original: Symbol.for("cordis.original"),
860
+ metadata: Symbol.for("cordis.metadata"),
861
+ initHooks: Symbol.for("cordis.initHooks"),
862
+ checkProto: Symbol.for("cordis.checkProto"),
863
+ effect: Symbol.for("cordis.effect"),
864
+ filter: Symbol.for("cordis.filter"),
865
+ isolate: Symbol.for("cordis.isolate"),
866
+ intercept: Symbol.for("cordis.intercept"),
867
+ init: Symbol.for("cordis.init"),
868
+ check: Symbol.for("cordis.check"),
869
+ config: Symbol.for("cordis.config"),
870
+ invoke: Symbol.for("cordis.invoke"),
871
+ extend: Symbol.for("cordis.extend"),
872
+ tracker: Symbol.for("cordis.tracker"),
873
+ resolveConfig: Symbol.for("cordis.resolveConfig")
874
+ };
875
+ var GeneratorFunction = function* () {
876
+ }.constructor;
877
+ var AsyncGeneratorFunction = async function* () {
878
+ }.constructor;
879
+ function isConstructor(func) {
880
+ if (!func.prototype) return false;
881
+ if (func instanceof GeneratorFunction) return false;
882
+ if (AsyncGeneratorFunction !== Function && func instanceof AsyncGeneratorFunction) return false;
883
+ return true;
884
+ }
885
+ function joinPrototype(proto1, proto2) {
886
+ if (proto1 === Object.prototype) return proto2;
887
+ const result = Object.create(joinPrototype(Object.getPrototypeOf(proto1), proto2));
888
+ for (const key of Reflect.ownKeys(proto1)) Object.defineProperty(result, key, Object.getOwnPropertyDescriptor(proto1, key));
889
+ return result;
890
+ }
891
+ function isObject(value) {
892
+ return value && (typeof value === "object" || typeof value === "function");
893
+ }
894
+ function getPropertyDescriptor(target, prop) {
895
+ let proto = target;
896
+ while (proto) {
897
+ const desc = Reflect.getOwnPropertyDescriptor(proto, prop);
898
+ if (desc) return desc;
899
+ proto = Object.getPrototypeOf(proto);
900
+ }
901
+ }
902
+ function getTraceable(ctx, value) {
903
+ if (!isObject(value)) return value;
904
+ if (Object.hasOwn(value, symbols.shadow)) return Object.getPrototypeOf(value);
905
+ const tracker = value[symbols.tracker];
906
+ if (!tracker) return value;
907
+ return createTraceable(ctx, value, tracker);
908
+ }
909
+ function withProps(target, props) {
910
+ if (!props) return target;
911
+ return new Proxy(target, {
912
+ get: (target2, prop, receiver) => {
913
+ if (prop in props && prop !== "constructor") return Reflect.get(props, prop, receiver);
914
+ return Reflect.get(target2, prop, receiver);
915
+ },
916
+ set: (target2, prop, value, receiver) => {
917
+ if (prop in props && prop !== "constructor") return Reflect.set(props, prop, value, receiver);
918
+ return Reflect.set(target2, prop, value, receiver);
919
+ }
920
+ });
921
+ }
922
+ function withProp(target, prop, value) {
923
+ return withProps(target, Object.defineProperty(/* @__PURE__ */ Object.create(null), prop, {
924
+ value,
925
+ writable: false
926
+ }));
927
+ }
928
+ function createShadow(ctx, target, property2, receiver) {
929
+ if (!property2) return receiver;
930
+ const origin = Reflect.getOwnPropertyDescriptor(target, property2)?.value;
931
+ if (!origin) return receiver;
932
+ return withProp(receiver, property2, ctx.extend({ [symbols.shadow]: origin }));
933
+ }
934
+ function createShadowMethod(ctx, value, outer, shadow) {
935
+ return new Proxy(value, { apply: (target, thisArg, args) => {
936
+ if (thisArg === outer) thisArg = shadow;
937
+ return getTraceable(ctx, Reflect.apply(target, thisArg, args));
938
+ } });
939
+ }
940
+ function createTraceable(ctx, value, tracker) {
941
+ if (ctx[symbols.shadow] && !tracker.noShadow) ctx = Object.getPrototypeOf(ctx);
942
+ const proxy = new Proxy(value, {
943
+ get: (target, prop, receiver) => {
944
+ if (prop === symbols.original) return target;
945
+ if (prop === tracker.property) return ctx;
946
+ if (typeof prop === "symbol") return Reflect.get(target, prop, receiver);
947
+ if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) return Reflect.get(ctx, `${tracker.associate}.${prop}`, withProp(ctx, symbols.receiver, receiver));
948
+ let shadow, innerValue;
949
+ const desc = getPropertyDescriptor(target, prop);
950
+ if (desc && "value" in desc) innerValue = desc.value;
951
+ else {
952
+ shadow = createShadow(ctx, target, tracker.property, receiver);
953
+ innerValue = Reflect.get(target, prop, shadow);
954
+ }
955
+ const innerTracker = innerValue?.[symbols.tracker];
956
+ if (innerTracker) return createTraceable(ctx, innerValue, innerTracker);
957
+ else if (!tracker.noShadow && typeof innerValue === "function") {
958
+ shadow ??= createShadow(ctx, target, tracker.property, receiver);
959
+ return createShadowMethod(ctx, innerValue, receiver, shadow);
960
+ } else return innerValue;
961
+ },
962
+ set: (target, prop, value2, receiver) => {
963
+ if (prop === symbols.original) return false;
964
+ if (prop === tracker.property) return false;
965
+ if (typeof prop === "symbol") return Reflect.set(target, prop, value2, receiver);
966
+ if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) return Reflect.set(ctx, `${tracker.associate}.${prop}`, value2, withProp(ctx, symbols.receiver, receiver));
967
+ const shadow = createShadow(ctx, target, tracker.property, receiver);
968
+ return Reflect.set(target, prop, value2, shadow);
969
+ },
970
+ apply: (target, thisArg, args) => {
971
+ return applyTraceable(proxy, target, thisArg, args);
972
+ }
973
+ });
974
+ return proxy;
975
+ }
976
+ function applyTraceable(proxy, value, thisArg, args) {
977
+ if (!value[symbols.invoke]) return Reflect.apply(value, thisArg, args);
978
+ return value[symbols.invoke].apply(proxy, args);
979
+ }
980
+ function createCallable(name2, proto, tracker) {
981
+ const self = function(...args) {
982
+ return applyTraceable(createTraceable(self["ctx"], self, tracker), self, this, args);
983
+ };
984
+ defineProperty(self, "name", name2);
985
+ return Object.setPrototypeOf(self, proto);
986
+ }
987
+ function handleError(info, reason, getOuterStack) {
988
+ const innerLines = info.error.stack.split("\n");
989
+ if (typeof reason?.stack !== "string") {
990
+ const outerError = new Error(reason);
991
+ const lines2 = outerError.stack.split("\n");
992
+ lines2.splice(1, Infinity, ...getOuterStack());
993
+ outerError.stack = lines2.join("\n");
994
+ throw outerError;
995
+ }
996
+ const lines = reason.stack.split("\n");
997
+ let index = lines.indexOf(innerLines[2]);
998
+ if (index === -1) throw reason;
999
+ index -= info.offset;
1000
+ while (index > 0) {
1001
+ if (!lines[index - 1].endsWith(" (<anonymous>)")) break;
1002
+ index -= 1;
1003
+ }
1004
+ lines.splice(index, Infinity, ...getOuterStack());
1005
+ reason.stack = lines.join("\n");
1006
+ throw reason;
1007
+ }
1008
+ function composeError(callback, getOuterStack = buildOuterStack()) {
1009
+ const info = {
1010
+ offset: 1,
1011
+ error: /* @__PURE__ */ new Error()
1012
+ };
1013
+ try {
1014
+ const result = callback(info);
1015
+ if (isObject(result) && "then" in result) return result.then(void 0, (reason) => handleError(info, reason, getOuterStack));
1016
+ else return result;
1017
+ } catch (reason) {
1018
+ handleError(info, reason, getOuterStack);
1019
+ }
1020
+ }
1021
+ function buildOuterStack(offset = 0) {
1022
+ const outerError = /* @__PURE__ */ new Error();
1023
+ return () => outerError.stack.split("\n").slice(3 + offset);
1024
+ }
1025
+ function isBailed(value) {
1026
+ return value !== null && value !== false && value !== void 0;
1027
+ }
1028
+ var EventsService = class {
1029
+ ctx;
1030
+ _hooks = {};
1031
+ constructor(ctx) {
1032
+ this.ctx = ctx;
1033
+ defineProperty(this, symbols.tracker, {
1034
+ property: "ctx",
1035
+ noShadow: true
1036
+ });
1037
+ this.on("internal/listener", function(name2, listener, options) {
1038
+ if (name2 === "internal/update" && !options.global) return (this.fiber._hooks["internal/update"] ??= new DisposableList())[options.prepend ? "unshift" : "push"](listener);
1039
+ });
1040
+ this.on("internal/update", function(config, noSave, next) {
1041
+ const cbs = [...this._hooks["internal/update"] || []];
1042
+ const _next = () => {
1043
+ return (cbs.shift() ?? next).call(this, config, noSave, _next);
1044
+ };
1045
+ return _next();
1046
+ }, {
1047
+ global: true,
1048
+ prepend: true
1049
+ });
1050
+ }
1051
+ /**
1052
+ * Resolve listeners for one dispatch and apply context filtering.
1053
+ *
1054
+ * @param type — the dispatch mode, reported on `internal/dispatch`.
1055
+ * @param args — the raw dispatch arguments; consumed up to the event name.
1056
+ * @returns the matching listener callbacks, bound to the dispatch `this`.
1057
+ */
1058
+ dispatch(type, args) {
1059
+ const thisArg = typeof args[0] === "object" || typeof args[0] === "function" ? args.shift() : null;
1060
+ const name2 = args.shift();
1061
+ if (!name2.startsWith("internal/")) this.emit("internal/dispatch", type, name2, args, thisArg);
1062
+ const filter = thisArg?.[Context.filter];
1063
+ return (this._hooks[name2] || []).filter((hook) => hook.global || !filter || filter.call(thisArg, hook.ctx)).map((hook) => hook.callback.bind(thisArg));
1064
+ }
1065
+ /**
1066
+ * Run listeners concurrently and wait for all of them.
1067
+ *
1068
+ * @param args — optional `this`, the event name, then listener arguments.
1069
+ * @returns a promise resolving once every listener has settled.
1070
+ */
1071
+ async parallel(...args) {
1072
+ const errors = (await Promise.allSettled(this.dispatch("emit", args).map(async (cb) => cb(...args)))).filter((result) => result.status === "rejected");
1073
+ if (errors.length) throw new AggregateError(errors.map((error) => error.reason));
1074
+ }
1075
+ /**
1076
+ * Run listeners synchronously without waiting for returned promises.
1077
+ *
1078
+ * @param args — optional `this`, the event name, then listener arguments.
1079
+ */
1080
+ emit(...args) {
1081
+ this.dispatch("emit", args).map((cb) => cb(...args));
1082
+ }
1083
+ /**
1084
+ * Run listeners in order, awaiting each, until one returns a bail value.
1085
+ *
1086
+ * @param args — optional `this`, the event name, then listener arguments.
1087
+ * @returns the first bail value (see {@link isBailed}), if any.
1088
+ */
1089
+ async serial(...args) {
1090
+ for (const cb of this.dispatch("serial", args)) {
1091
+ const result = await cb(...args);
1092
+ if (isBailed(result)) return result;
1093
+ }
1094
+ }
1095
+ /**
1096
+ * Run listeners synchronously until one returns a bail value.
1097
+ *
1098
+ * @param args — optional `this`, the event name, then listener arguments.
1099
+ * @returns the first bail value (see {@link isBailed}), if any.
1100
+ */
1101
+ bail(...args) {
1102
+ for (const cb of this.dispatch("bail", args)) {
1103
+ const result = cb(...args);
1104
+ if (isBailed(result)) return result;
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Compose listeners around the final `next` callback.
1109
+ *
1110
+ * The last dispatch argument is treated as the innermost `next`. Listeners
1111
+ * run outermost-first; a listener that does not call `next()` vetoes the
1112
+ * rest of the chain, including the built-in behavior.
1113
+ *
1114
+ * @param args — optional `this`, the event name, listener arguments, then `next`.
1115
+ * @returns the outermost listener's return value.
1116
+ */
1117
+ waterfall(...args) {
1118
+ const cbs = this.dispatch("waterfall", args);
1119
+ const inner = args.pop();
1120
+ const next = () => {
1121
+ return (cbs.shift() ?? inner)(...args);
1122
+ };
1123
+ args.push(next);
1124
+ return next();
1125
+ }
1126
+ /**
1127
+ * Store a listener record as an effect on the current fiber.
1128
+ *
1129
+ * @param label — effect label shown in fiber diagnostics.
1130
+ * @param hooks — the listener list for one event.
1131
+ * @param callback — the listener to store.
1132
+ * @param options — placement and filtering options.
1133
+ * @returns a disposer that unregisters the listener.
1134
+ */
1135
+ register(label, hooks, callback, options) {
1136
+ const method = options.prepend ? "unshift" : "push";
1137
+ return this.ctx.fiber.effect(() => {
1138
+ hooks[method]({
1139
+ ctx: this.ctx,
1140
+ callback,
1141
+ ...options
1142
+ });
1143
+ return () => this.unregister(hooks, callback);
1144
+ }, label);
1145
+ }
1146
+ /**
1147
+ * Remove a stored listener record.
1148
+ *
1149
+ * @param hooks — the listener list for one event.
1150
+ * @param callback — the listener to remove.
1151
+ * @returns `true` if the listener was found and removed.
1152
+ */
1153
+ unregister(hooks, callback) {
1154
+ const index = hooks.findIndex((hook) => hook.callback === callback);
1155
+ if (index >= 0) {
1156
+ hooks.splice(index, 1);
1157
+ return true;
1158
+ }
1159
+ }
1160
+ /**
1161
+ * Register an event listener owned by the current fiber.
1162
+ *
1163
+ * The listener is removed automatically when the fiber unloads. Throws
1164
+ * `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed.
1165
+ *
1166
+ * @param name — the event name to listen for.
1167
+ * @param listener — called with the dispatch arguments.
1168
+ * @param options — listener options; a boolean is shorthand for `prepend`.
1169
+ * @returns a disposer removing the listener; `true` if it was still registered.
1170
+ */
1171
+ on(name2, listener, options) {
1172
+ if (typeof options !== "object") options = { prepend: options };
1173
+ this.ctx.fiber.assertActive();
1174
+ listener = this.ctx.reflect.bind(listener);
1175
+ const result = this.bail(this.ctx, "internal/listener", name2, listener, options);
1176
+ if (result) return result;
1177
+ const hooks = this._hooks[name2] ||= [];
1178
+ const label = `ctx.on(${typeof name2 === "string" ? JSON.stringify(name2) : name2.toString()})`;
1179
+ return this.register(label, hooks, listener, options);
1180
+ }
1181
+ /**
1182
+ * Register an event listener that disposes itself after the first call.
1183
+ *
1184
+ * @param name — the event name to listen for.
1185
+ * @param listener — called at most once with the dispatch arguments.
1186
+ * @param options — listener options; a boolean is shorthand for `prepend`.
1187
+ * @returns a disposer removing the listener; `true` if it was still registered.
1188
+ */
1189
+ once(name2, listener, options) {
1190
+ const dispose = this.on(name2, function(...args) {
1191
+ dispose();
1192
+ return listener.apply(this, args);
1193
+ }, options);
1194
+ return dispose;
1195
+ }
1196
+ };
1197
+ var defaultFormatters = {
1198
+ s: (value) => String(value),
1199
+ d: (value) => Math.trunc(Number(value)),
1200
+ i: (value) => Math.trunc(Number(value)),
1201
+ f: (value) => Number(value),
1202
+ o: (value) => JSON.stringify(value),
1203
+ O: (value) => JSON.stringify(value),
1204
+ c: () => "",
1205
+ C: (value, exporter, message) => {
1206
+ return Logger.color(exporter, Logger.code(message.name, exporter.colors), value);
1207
+ }
1208
+ };
1209
+ function isAggregateError(error) {
1210
+ return error instanceof Error && Array.isArray(error["errors"]);
1211
+ }
1212
+ var Logger = class {
1213
+ service;
1214
+ static color(exporter, code, value, decoration = "") {
1215
+ if (!exporter.colors) return "" + value;
1216
+ return `\x1B[3${code < 8 ? code : "8;5;" + code}${exporter.colors >= 2 ? decoration : ""}m${value}\x1B[0m`;
1217
+ }
1218
+ static code(name2, level) {
1219
+ let hash = 0;
1220
+ for (let i = 0; i < name2.length; i++) {
1221
+ hash = (hash << 3) - hash + name2.charCodeAt(i) + 13;
1222
+ hash |= 0;
1223
+ }
1224
+ const colors = !level ? [] : level >= 2 ? c256 : c16;
1225
+ return colors[Math.abs(hash) % colors.length];
1226
+ }
1227
+ static format(exporter, message) {
1228
+ const args = message.args.slice();
1229
+ if (args[0] instanceof Error) {
1230
+ args[0] = args[0].stack || args[0].message;
1231
+ args.unshift("%s");
1232
+ } else if (typeof args[0] !== "string") args.unshift("%o");
1233
+ let format = args.shift();
1234
+ format = format.replace(/%([a-zA-Z%])/g, (match, char) => {
1235
+ if (match === "%%") return "%";
1236
+ const formatter = exporter.formatters?.[char] ?? defaultFormatters[char];
1237
+ if (typeof formatter === "function") return formatter(args.shift(), exporter, message);
1238
+ return match;
1239
+ });
1240
+ const oFormatter = exporter.formatters?.o ?? defaultFormatters.o;
1241
+ for (let arg of args) {
1242
+ if (typeof arg === "object" && arg) arg = oFormatter(arg, exporter, message);
1243
+ format += " " + arg;
1244
+ }
1245
+ const { maxLength = 10240 } = exporter;
1246
+ return format.split(/\r?\n/g).map((line) => {
1247
+ return line.slice(0, maxLength) + (line.length > maxLength ? "..." : "");
1248
+ }).join("\n");
1249
+ }
1250
+ constructor(options, service) {
1251
+ this.service = service;
1252
+ Object.assign(this, options);
1253
+ this.error = this._method("error", 0);
1254
+ this.info = this._method("info", 1);
1255
+ this.warn = this._method("warn", 2);
1256
+ this.debug = this._method("debug", 3);
1257
+ }
1258
+ _method(type, level) {
1259
+ return (...args) => {
1260
+ if (args.length === 1 && args[0] instanceof Error) {
1261
+ if (args[0].cause) this[type](args[0].cause);
1262
+ else if (isAggregateError(args[0])) {
1263
+ args[0].errors.forEach((error) => this[type](error));
1264
+ return;
1265
+ }
1266
+ }
1267
+ const sn = ++this.service._snMessage;
1268
+ const ts = Date.now();
1269
+ for (const exporter of this.service.exporters.values()) {
1270
+ if ((exporter.levels?.[this.name] ?? exporter.levels?.default ?? this.level ?? 1) < level) continue;
1271
+ const message = {
1272
+ sn,
1273
+ ts,
1274
+ type,
1275
+ level,
1276
+ name: this.name,
1277
+ ...this.meta,
1278
+ args
1279
+ };
1280
+ exporter.export(message);
1281
+ }
1282
+ };
1283
+ }
1284
+ };
1285
+ var c16 = [
1286
+ 6,
1287
+ 2,
1288
+ 3,
1289
+ 4,
1290
+ 5,
1291
+ 1
1292
+ ];
1293
+ var c256 = [
1294
+ 20,
1295
+ 21,
1296
+ 26,
1297
+ 27,
1298
+ 32,
1299
+ 33,
1300
+ 38,
1301
+ 39,
1302
+ 40,
1303
+ 41,
1304
+ 42,
1305
+ 43,
1306
+ 44,
1307
+ 45,
1308
+ 56,
1309
+ 57,
1310
+ 62,
1311
+ 63,
1312
+ 68,
1313
+ 69,
1314
+ 74,
1315
+ 75,
1316
+ 76,
1317
+ 77,
1318
+ 78,
1319
+ 79,
1320
+ 80,
1321
+ 81,
1322
+ 92,
1323
+ 93,
1324
+ 98,
1325
+ 99,
1326
+ 112,
1327
+ 113,
1328
+ 129,
1329
+ 134,
1330
+ 135,
1331
+ 148,
1332
+ 149,
1333
+ 160,
1334
+ 161,
1335
+ 162,
1336
+ 163,
1337
+ 164,
1338
+ 165,
1339
+ 166,
1340
+ 167,
1341
+ 168,
1342
+ 169,
1343
+ 170,
1344
+ 171,
1345
+ 172,
1346
+ 173,
1347
+ 178,
1348
+ 179,
1349
+ 184,
1350
+ 185,
1351
+ 196,
1352
+ 197,
1353
+ 198,
1354
+ 199,
1355
+ 200,
1356
+ 201,
1357
+ 202,
1358
+ 203,
1359
+ 204,
1360
+ 205,
1361
+ 206,
1362
+ 207,
1363
+ 208,
1364
+ 209,
1365
+ 214,
1366
+ 215,
1367
+ 220,
1368
+ 221
1369
+ ];
1370
+ var LoggerService = class LoggerService2 {
1371
+ bufferSize = 1e3;
1372
+ buffer = [];
1373
+ ctx;
1374
+ _snMessage = 0;
1375
+ _snExporter = 0;
1376
+ exporters = /* @__PURE__ */ new Map();
1377
+ constructor(ctx) {
1378
+ const tracker = {
1379
+ property: "ctx",
1380
+ noShadow: true
1381
+ };
1382
+ const self = createCallable("logger", joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker);
1383
+ Object.assign(self, this);
1384
+ self.ctx = ctx;
1385
+ defineProperty(self, symbols.tracker, tracker);
1386
+ self.exporter({
1387
+ colors: 3,
1388
+ export: (message) => {
1389
+ self.buffer.push(message);
1390
+ if (self.buffer.length > self.bufferSize) self.buffer = self.buffer.slice(-self.bufferSize);
1391
+ }
1392
+ });
1393
+ return self;
1394
+ }
1395
+ /**
1396
+ * Register an exporter and dispose it with the current fiber.
1397
+ *
1398
+ * @param exporter — the sink that receives structured log messages.
1399
+ * @returns a disposer that removes the exporter.
1400
+ */
1401
+ exporter(exporter) {
1402
+ return this.ctx.effect(() => {
1403
+ this.exporters.set(++this._snExporter, exporter);
1404
+ return () => this.exporters.delete(this._snExporter);
1405
+ }, "ctx.logger.exporter()");
1406
+ }
1407
+ _resolveConfig() {
1408
+ let intercept = this.ctx[symbols.intercept];
1409
+ const configs = [];
1410
+ while ("logger" in intercept) {
1411
+ if (Object.hasOwn(intercept, "logger")) configs.unshift(intercept["logger"]);
1412
+ intercept = Object.getPrototypeOf(intercept);
1413
+ }
1414
+ return Object.assign({}, ...configs);
1415
+ }
1416
+ [symbols.invoke](name2) {
1417
+ const config = this._resolveConfig();
1418
+ const fiber = (this.ctx[symbols.shadow] ?? this.ctx).fiber;
1419
+ name2 ??= config.name;
1420
+ name2 ??= hyphenate(fiber.name);
1421
+ return new Logger({
1422
+ name: name2,
1423
+ level: config.level,
1424
+ meta: { fiber: new WeakRef(fiber) }
1425
+ }, this);
1426
+ }
1427
+ static {
1428
+ for (const type of [
1429
+ "error",
1430
+ "info",
1431
+ "warn",
1432
+ "debug"
1433
+ ]) LoggerService2.prototype[type] = function(...args) {
1434
+ return this()[type](...args);
1435
+ };
1436
+ }
1437
+ };
1438
+ function enhanceError(error) {
1439
+ const lines = error.stack.split("\n");
1440
+ lines.splice(0, 2, `Error: ${error.message}`);
1441
+ error.stack = lines.join("\n");
1442
+ return error;
1443
+ }
1444
+ var RESERVED_WORDS = ["prototype", "then"];
1445
+ function isSpecialProperty(prop) {
1446
+ return typeof prop === "symbol" || RESERVED_WORDS.includes(prop) || parseInt(prop).toString() === prop || prop.startsWith("_");
1447
+ }
1448
+ var ReflectService = class {
1449
+ ctx;
1450
+ /** Proxy traps implementing service resolution for every context object. */
1451
+ static handler = {
1452
+ get: (target, prop, ctx) => {
1453
+ if (isSpecialProperty(prop)) return Reflect.get(target, prop, ctx);
1454
+ if (Reflect.has(target, prop)) return getTraceable(ctx, Reflect.get(target, prop, ctx));
1455
+ const error = /* @__PURE__ */ new Error(`cannot get property "${prop}" without inject`);
1456
+ try {
1457
+ const def = target.reflect.props[prop];
1458
+ if (def?.type === "accessor") return def.get.call(ctx, ctx[symbols.receiver], error);
1459
+ if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false);
1460
+ return ctx.events.waterfall("internal/get", ctx, prop, error, () => {
1461
+ const key = target[symbols.isolate][prop];
1462
+ let fiber = (ctx[symbols.shadow] ?? ctx).fiber;
1463
+ while (true) {
1464
+ const impl = fiber.store?.[prop];
1465
+ if (impl) return getTraceable(ctx, impl.value);
1466
+ if (prop in fiber.inject) {
1467
+ error.message = `cannot get required service "${prop}" in inactive context`;
1468
+ throw error;
1469
+ }
1470
+ if (!fiber.runtime) throw error;
1471
+ if (fiber.parent[symbols.isolate][prop] !== key) throw error;
1472
+ fiber = fiber.parent.fiber;
1473
+ }
1474
+ });
1475
+ } catch (e) {
1476
+ throw e === error ? enhanceError(e) : e;
1477
+ }
1478
+ },
1479
+ set: (target, prop, value, ctx) => {
1480
+ if (isSpecialProperty(prop)) return Reflect.set(target, prop, value, ctx);
1481
+ const error = /* @__PURE__ */ new Error(`cannot set property "${prop}" without provide`);
1482
+ const def = target.reflect.props[prop];
1483
+ if (!def) {
1484
+ if (!ctx.fiber.runtime) return Reflect.set(target, prop, value, ctx);
1485
+ throw enhanceError(error);
1486
+ }
1487
+ try {
1488
+ if (def.type === "accessor") {
1489
+ if (!def.set) return false;
1490
+ return def.set.call(ctx, value, ctx[symbols.receiver], error);
1491
+ }
1492
+ return ctx.events.waterfall("internal/set", ctx, prop, value, error, () => {
1493
+ return ctx.reflect.set(prop, value, error);
1494
+ });
1495
+ } catch (e) {
1496
+ throw e === error ? enhanceError(e) : e;
1497
+ }
1498
+ },
1499
+ has: (target, prop) => {
1500
+ if (isSpecialProperty(prop)) return Reflect.has(target, prop);
1501
+ if (Reflect.has(target, prop)) return true;
1502
+ return !!target.reflect.props[prop];
1503
+ }
1504
+ };
1505
+ /** Service implementations, keyed by isolation label. */
1506
+ store = /* @__PURE__ */ Object.create(null);
1507
+ /** Declared context properties (services and accessors), by name. */
1508
+ props = /* @__PURE__ */ Object.create(null);
1509
+ constructor(ctx) {
1510
+ this.ctx = ctx;
1511
+ defineProperty(this, symbols.tracker, {
1512
+ property: "ctx",
1513
+ noShadow: true
1514
+ });
1515
+ this.mixin("reflect", [
1516
+ "get",
1517
+ "set",
1518
+ "provide",
1519
+ "accessor",
1520
+ "mixin"
1521
+ ]);
1522
+ this.mixin("fiber", ["runtime", "effect"]);
1523
+ this.mixin("registry", ["inject", "plugin"]);
1524
+ this.mixin("events", [
1525
+ "on",
1526
+ "once",
1527
+ "parallel",
1528
+ "emit",
1529
+ "serial",
1530
+ "bail",
1531
+ "waterfall"
1532
+ ]);
1533
+ }
1534
+ /**
1535
+ * Read a service from the store without the inject requirement.
1536
+ *
1537
+ * @param name — the service name.
1538
+ * @param strict — when `true`, only return implementations whose providing
1539
+ * fiber is currently active.
1540
+ * @returns the service value, or `undefined` when not (yet) provided.
1541
+ */
1542
+ get(name2, strict = true) {
1543
+ return getTraceable(this.ctx, this._getImpl(name2, strict)?.value);
1544
+ }
1545
+ _getImpl(name2, strict = true) {
1546
+ const key = this.ctx[symbols.isolate][name2];
1547
+ const impl = key && this.store[key];
1548
+ if (!impl) return;
1549
+ if (strict && impl.fiber.state !== 2) return;
1550
+ return impl;
1551
+ }
1552
+ /**
1553
+ * Overwrite a provided service's value.
1554
+ *
1555
+ * @param name — the service name.
1556
+ * @param value — the new service value.
1557
+ * @param error — carrier for the caller stack in diagnostics.
1558
+ * @returns `true` on success.
1559
+ * @throws when `name` was never provided, or was provided by another fiber.
1560
+ */
1561
+ set(name2, value, error) {
1562
+ const key = this.ctx[symbols.isolate][name2];
1563
+ const impl = this.store[key];
1564
+ if (!impl) throw new Error(`cannot set property "${name2}" without provide`);
1565
+ if (impl.fiber !== this.ctx.fiber) throw new Error(`cannot set property "${name2}" in multiple fibers`);
1566
+ impl.value = value;
1567
+ return true;
1568
+ }
1569
+ /**
1570
+ * Register a service implementation owned by the current fiber.
1571
+ *
1572
+ * See the `ctx.provide()` overload above for the full contract.
1573
+ *
1574
+ * @param name — the service name.
1575
+ * @param value — the service value.
1576
+ * @param check — optional availability predicate for dependents.
1577
+ * @returns a disposer that unregisters the service.
1578
+ */
1579
+ provide(name2, value, check) {
1580
+ return this.ctx.fiber.effect(() => {
1581
+ if (!this.props[name2]) this.props[name2] ??= { type: "service" };
1582
+ else if (this.props[name2].type !== "service") throw new Error(`property "${name2}" is already declared as ${this.props[name2].type}`);
1583
+ this.props[name2] = { type: "service" };
1584
+ this.ctx.root[symbols.isolate][name2] ??= Symbol(name2);
1585
+ const key = this.ctx[symbols.isolate][name2];
1586
+ const impl = {
1587
+ name: name2,
1588
+ value,
1589
+ fiber: this.ctx.fiber,
1590
+ check
1591
+ };
1592
+ if (this.store[key]) throw new Error(`service "${name2}" has been registered at <${this.store[key].fiber.name}>`);
1593
+ this.store[key] = impl;
1594
+ this.ctx.fiber.store[name2] = impl;
1595
+ if (this.ctx.fiber.state === 2) this.notify([name2]);
1596
+ return async () => {
1597
+ delete this.store[key];
1598
+ const fibers = this.notify([name2]);
1599
+ await Promise.allSettled(fibers.map((fiber) => fiber.await()));
1600
+ delete this.ctx.fiber.store[name2];
1601
+ };
1602
+ }, `ctx.provide(${JSON.stringify(name2)})`);
1603
+ }
1604
+ /**
1605
+ * Re-evaluate every fiber that requires one of the given services.
1606
+ *
1607
+ * @param names — the service names that changed.
1608
+ * @param filter — restricts notification to matching isolation scopes.
1609
+ * @returns the fibers whose dependency state was refreshed.
1610
+ */
1611
+ notify(names, filter = (ctx, name2) => ctx[symbols.isolate][name2] === this.ctx[symbols.isolate][name2]) {
1612
+ const fibers = [];
1613
+ for (const runtime of this.ctx.registry.values()) for (const fiber of runtime.fibers) {
1614
+ let hasUpdate = false;
1615
+ for (const name2 of names) {
1616
+ if (!(name2 in fiber.inject)) continue;
1617
+ if (!filter(fiber.ctx, name2)) continue;
1618
+ hasUpdate = true;
1619
+ fiber._checkImpl(name2);
1620
+ }
1621
+ if (!hasUpdate) continue;
1622
+ fiber._refresh();
1623
+ fibers.push(fiber);
1624
+ }
1625
+ for (const name2 of names) {
1626
+ const self = Object.create(this.ctx);
1627
+ self[symbols.filter] = (target) => filter(target, name2);
1628
+ this.ctx.events.emit(self, "internal/service", name2, this._getImpl(name2, false)?.value);
1629
+ }
1630
+ return fibers;
1631
+ }
1632
+ /**
1633
+ * Define a computed context property backed by get/set hooks.
1634
+ *
1635
+ * @param name — the context property name.
1636
+ * @param options — the `get` hook and optional `set` hook.
1637
+ * @returns a disposer that removes the accessor.
1638
+ */
1639
+ accessor(name2, options) {
1640
+ return this.ctx.fiber.effect(() => {
1641
+ if (name2 in this.props) throw new Error(`property "${name2}" is already declared as ${this.props[name2].type}`);
1642
+ this.props[name2] = {
1643
+ type: "accessor",
1644
+ ...options
1645
+ };
1646
+ return () => delete this.props[name2];
1647
+ }, `ctx.accessor(${JSON.stringify(name2)})`);
1648
+ }
1649
+ /**
1650
+ * Expose selected members of a service directly on `ctx`.
1651
+ *
1652
+ * See the `ctx.mixin()` overload above for the full contract.
1653
+ *
1654
+ * @param source — a context property name or a source object.
1655
+ * @param mixins — keys to forward, or a source-key → ctx-key map.
1656
+ * @returns a disposer that removes all created accessors.
1657
+ */
1658
+ mixin(source, mixins) {
1659
+ const self = this;
1660
+ return this.ctx.fiber.effect(function* () {
1661
+ const entries = Array.isArray(mixins) ? mixins.map((key) => [key, key]) : Object.entries(mixins);
1662
+ const getTarget = (ctx, error) => {
1663
+ return ctx[source];
1664
+ };
1665
+ for (const [key, value] of entries) yield self.accessor(value, {
1666
+ get(receiver, error) {
1667
+ const service = getTarget(this, error);
1668
+ if (isNullable(service)) return service;
1669
+ const mixin = receiver ? withProps(receiver, service) : service;
1670
+ const value2 = Reflect.get(service, key, mixin);
1671
+ if (typeof value2 !== "function") return value2;
1672
+ return value2.bind(mixin ?? service);
1673
+ },
1674
+ set(value2, receiver, error) {
1675
+ const service = getTarget(this, error);
1676
+ const mixin = receiver ? withProps(receiver, service) : service;
1677
+ return Reflect.set(service, key, value2, mixin);
1678
+ }
1679
+ });
1680
+ }, `ctx.mixin(${JSON.stringify(source)})`);
1681
+ }
1682
+ /**
1683
+ * Attach this context's tracing wrapper to a value.
1684
+ *
1685
+ * @param value — the value to wrap.
1686
+ * @returns the traceable wrapper (or the value itself when not applicable).
1687
+ */
1688
+ trace(value) {
1689
+ return getTraceable(this.ctx, value);
1690
+ }
1691
+ /**
1692
+ * Wrap a callback so calls trace `this` and arguments to this context.
1693
+ *
1694
+ * @param callback — the function to wrap.
1695
+ * @returns a proxy delegating to `callback` with traced values.
1696
+ */
1697
+ bind(callback) {
1698
+ return new Proxy(callback, {
1699
+ apply: (target, thisArg, args) => {
1700
+ return Reflect.apply(target, this.trace(thisArg), args.map((arg) => this.trace(arg)));
1701
+ },
1702
+ construct: (target, args, newTarget) => {
1703
+ return Reflect.construct(target, args.map((arg) => this.trace(arg)), newTarget);
1704
+ }
1705
+ });
1706
+ }
1707
+ };
1708
+ var kValidationError2 = Symbol.for("ValidationError");
1709
+ var ValidationError2 = class extends TypeError {
1710
+ name = "ValidationError";
1711
+ /**
1712
+ * Build the aggregated message from schema issues.
1713
+ *
1714
+ * @param issues — the standard-schema issues, one message line each.
1715
+ */
1716
+ constructor(issues) {
1717
+ super(`invalid config:
1718
+ ` + issues.map((issue) => {
1719
+ if (issue.path) return ` - ${issue.message} (at ${issue.path.join(".")})`;
1720
+ else return ` - ${issue.message}`;
1721
+ }).join("\n"));
1722
+ }
1723
+ };
1724
+ Object.defineProperty(ValidationError2.prototype, kValidationError2, { value: true });
1725
+ function resolveConfig(runtime, config) {
1726
+ if (!runtime.Config) return config;
1727
+ const result = runtime.Config["~standard"].validate(config);
1728
+ if ("then" in result) throw new TypeError("Async config validation is not supported");
1729
+ if (result.issues) throw new ValidationError2(result.issues);
1730
+ else return result.value;
1731
+ }
1732
+ var effectInertia = /* @__PURE__ */ new WeakMap();
1733
+ function runDisposable(dispose) {
1734
+ const result = dispose();
1735
+ return effectInertia.get(dispose)?.() ?? result;
1736
+ }
1737
+ function emitPluginDisposed(context, fiber) {
1738
+ const args = ["internal/plugin", fiber];
1739
+ let callbacks;
1740
+ try {
1741
+ callbacks = context.events.dispatch("emit", args);
1742
+ } catch (error) {
1743
+ context.logger.error(error);
1744
+ return;
1745
+ }
1746
+ for (const callback of callbacks) try {
1747
+ const returned = callback(...args);
1748
+ Promise.resolve(returned).catch((error) => context.logger.error(error));
1749
+ } catch (error) {
1750
+ context.logger.error(error);
1751
+ }
1752
+ }
1753
+ var CordisError = class CordisError2 extends Error {
1754
+ code;
1755
+ /**
1756
+ * @param code — the stable error code; also the default message.
1757
+ * @param message — optional human-readable override.
1758
+ */
1759
+ constructor(code, message) {
1760
+ super(message ?? CordisError2.Code[code]);
1761
+ this.code = code;
1762
+ }
1763
+ };
1764
+ (function(CordisError3) {
1765
+ CordisError3.Code = { INACTIVE_EFFECT: "cannot create effect on inactive context" };
1766
+ })(CordisError || (CordisError = {}));
1767
+ var INACTIVE = "__INACTIVE__";
1768
+ var Fiber = class {
1769
+ parent;
1770
+ inject;
1771
+ runtime;
1772
+ /** Unique id within the registry; 0 for the root fiber, `null` once disposed. */
1773
+ uid;
1774
+ /** The context this fiber's plugin runs in (extends the parent context). */
1775
+ ctx;
1776
+ /** The validated plugin config (updated by `update()`). */
1777
+ config;
1778
+ /** The raw plugin config, re-resolved before each activation. */
1779
+ _config;
1780
+ /** Current lifecycle state; transitions emit `internal/status`. */
1781
+ state = 0;
1782
+ /** Dispose this fiber: unload the plugin, then settle once cleanup finished. */
1783
+ dispose;
1784
+ /** Snapshot of required service implementations while loaded; `undefined` otherwise. */
1785
+ store;
1786
+ /** The in-flight load/unload transition, if one is currently running. */
1787
+ inertia;
1788
+ _hooks = /* @__PURE__ */ Object.create(null);
1789
+ _disposables = new DisposableList();
1790
+ context;
1791
+ _error;
1792
+ _runner;
1793
+ _store = /* @__PURE__ */ Object.create(null);
1794
+ /**
1795
+ * Create a fiber. Plugin authors normally obtain fibers from `ctx.plugin()`
1796
+ * rather than constructing them directly.
1797
+ *
1798
+ * @param parent — the context the plugin was loaded from.
1799
+ * @param config — raw config, validated against the runtime's schema.
1800
+ * @param inject — resolved dependency map (service name → intercept config).
1801
+ * @param runtime — the shared plugin runtime, or `null` for the root fiber.
1802
+ * @param getOuterStack — captures the caller stack for effect diagnostics.
1803
+ */
1804
+ constructor(parent, config, inject2, runtime, getOuterStack) {
1805
+ this.parent = parent;
1806
+ this.inject = inject2;
1807
+ this.runtime = runtime;
1808
+ this._config = config;
1809
+ const collect = (dispose) => {
1810
+ this._disposables.push(dispose);
1811
+ };
1812
+ if (runtime) {
1813
+ this.uid = parent.registry.counter;
1814
+ this.ctx = this.context = parent.extend({ fiber: this });
1815
+ const injectEntries = Object.entries(this.inject);
1816
+ if (injectEntries.length) {
1817
+ this.ctx[Context.intercept] = Object.create(parent[Context.intercept]);
1818
+ for (const [name2, config2] of injectEntries) {
1819
+ if (isNullable(config2)) continue;
1820
+ this.ctx[Context.intercept][name2] = config2;
1821
+ }
1822
+ }
1823
+ this._runner = {
1824
+ epoch: INACTIVE,
1825
+ getOuterStack,
1826
+ execute: function() {
1827
+ if (isConstructor(runtime.callback)) {
1828
+ const instance = new runtime.callback(this.ctx, this.config);
1829
+ for (const hook of instance?.[symbols.initHooks] ?? []) hook();
1830
+ return instance?.[symbols.init]?.();
1831
+ } else return runtime.callback(this.ctx, this.config);
1832
+ },
1833
+ collect
1834
+ };
1835
+ this.dispose = parent.fiber.effect(() => {
1836
+ const remove = runtime.fibers.push(this);
1837
+ return async () => {
1838
+ this.uid = null;
1839
+ emitPluginDisposed(this.context, this);
1840
+ if (this.ctx.registry.has(runtime.callback)) {
1841
+ remove();
1842
+ if (!runtime.fibers.length) this.ctx.registry.delete(runtime.callback);
1843
+ }
1844
+ this._setEpoch(INACTIVE);
1845
+ if (!this.inertia) this._updateState(() => {
1846
+ this.inertia = this._unload();
1847
+ return 5;
1848
+ });
1849
+ while (this.inertia) await this.inertia;
1850
+ };
1851
+ }, "ctx.plugin()");
1852
+ try {
1853
+ this.context.emit("internal/plugin", this);
1854
+ } catch (error) {
1855
+ Promise.resolve(this.dispose()).catch((reason) => this.ctx.logger.error(reason));
1856
+ throw error;
1857
+ }
1858
+ if (this.uid !== null && parent.fiber.state !== 5) {
1859
+ for (const name2 of Object.keys(this.inject)) this._checkImpl(name2);
1860
+ this._refresh();
1861
+ }
1862
+ } else {
1863
+ this.uid = 0;
1864
+ this.ctx = this.context = parent;
1865
+ this.state = 2;
1866
+ this.store = /* @__PURE__ */ Object.create(null);
1867
+ this._runner = {
1868
+ epoch: "",
1869
+ getOuterStack,
1870
+ execute: () => {
1871
+ },
1872
+ collect
1873
+ };
1874
+ this.dispose = () => this.restart();
1875
+ }
1876
+ }
1877
+ /** The plugin's display name, inherited from the nearest named ancestor, else `'root'`. */
1878
+ get name() {
1879
+ let fiber = this;
1880
+ do {
1881
+ if (fiber.runtime?.name) return fiber.runtime.name;
1882
+ fiber = fiber.parent.fiber;
1883
+ } while (fiber !== fiber.parent.fiber);
1884
+ return "root";
1885
+ }
1886
+ /**
1887
+ * Throw if the fiber has already been disposed.
1888
+ *
1889
+ * @returns nothing when the fiber is still active.
1890
+ * @throws {CordisError} `INACTIVE_EFFECT` when the fiber's uid has been cleared.
1891
+ */
1892
+ assertActive() {
1893
+ if (this.uid !== null) return;
1894
+ throw new CordisError("INACTIVE_EFFECT");
1895
+ }
1896
+ _execute(runner) {
1897
+ const oldEpoch = runner.epoch;
1898
+ return composeError((info) => {
1899
+ const safeCollect = (dispose) => {
1900
+ if (typeof dispose === "function") runner.collect(dispose);
1901
+ else if (!isNullable(dispose)) throw new TypeError("Invalid effect");
1902
+ };
1903
+ const effect = runner.execute.call(this);
1904
+ if (typeof effect === "function") return runner.collect(effect);
1905
+ else if (isNullable(effect)) {
1906
+ } else if (!isObject(effect)) throw new TypeError("Invalid effect");
1907
+ else if ("then" in effect) return effect.then(safeCollect);
1908
+ else if (Symbol.iterator in effect) {
1909
+ info.error = /* @__PURE__ */ new Error();
1910
+ const iter = effect[Symbol.iterator]();
1911
+ while (true) {
1912
+ const result = iter.next();
1913
+ safeCollect(result.value);
1914
+ if (result.done) return;
1915
+ }
1916
+ } else if (Symbol.asyncIterator in effect) {
1917
+ const iter = effect[Symbol.asyncIterator]();
1918
+ return (async () => {
1919
+ await Promise.resolve();
1920
+ info.error = /* @__PURE__ */ new Error();
1921
+ while (true) {
1922
+ if (runner.epoch !== oldEpoch) return;
1923
+ const result = await iter.next();
1924
+ safeCollect(result.value);
1925
+ if (result.done) return;
1926
+ }
1927
+ })();
1928
+ } else throw new TypeError("Invalid effect");
1929
+ }, runner.getOuterStack);
1930
+ }
1931
+ effect(execute, label = "anonymous") {
1932
+ this.assertActive();
1933
+ if (this.state === 5) throw new CordisError("INACTIVE_EFFECT");
1934
+ const disposables = [];
1935
+ let disposing = false;
1936
+ let disposalTask;
1937
+ const dispose = () => {
1938
+ if (disposing) return disposalTask;
1939
+ disposing = true;
1940
+ let task2;
1941
+ for (const disposable of disposables.splice(0).reverse()) if (task2) task2 = task2.then(() => runDisposable(disposable));
1942
+ else {
1943
+ const result = runDisposable(disposable);
1944
+ if (isObject(result) && "then" in result) task2 = result;
1945
+ }
1946
+ return disposalTask = task2;
1947
+ };
1948
+ const meta = {
1949
+ label,
1950
+ children: []
1951
+ };
1952
+ const runner = {
1953
+ execute,
1954
+ epoch: true,
1955
+ collect: (dispose2) => {
1956
+ disposables.push(dispose2);
1957
+ this._disposables.delete(dispose2);
1958
+ if (dispose2[symbols.effect]) meta.children.push(dispose2[symbols.effect]);
1959
+ },
1960
+ getOuterStack: buildOuterStack()
1961
+ };
1962
+ let task;
1963
+ let executing = true;
1964
+ let resolveSetup;
1965
+ let rejectSetup;
1966
+ let setupBarrier;
1967
+ let setupFailed = false;
1968
+ let inFlight;
1969
+ let removeWrapper = () => false;
1970
+ const waitForSetup = () => {
1971
+ setupBarrier ??= new Promise((resolve2, reject) => {
1972
+ resolveSetup = resolve2;
1973
+ rejectSetup = reject;
1974
+ });
1975
+ return setupBarrier;
1976
+ };
1977
+ const disposeAfter = (setup) => {
1978
+ return Promise.resolve(setup).then(() => dispose(), async (reason) => {
1979
+ await dispose();
1980
+ throw reason;
1981
+ });
1982
+ };
1983
+ const finalizeDisposal = (callback) => {
1984
+ let result;
1985
+ try {
1986
+ result = callback();
1987
+ } catch (error) {
1988
+ removeWrapper();
1989
+ throw error;
1990
+ }
1991
+ if (isObject(result) && "then" in result) {
1992
+ const pending = Promise.resolve(result).finally(() => {
1993
+ removeWrapper();
1994
+ if (inFlight === pending) inFlight = void 0;
1995
+ });
1996
+ return inFlight = pending;
1997
+ }
1998
+ removeWrapper();
1999
+ return result;
2000
+ };
2001
+ const wrapper = defineProperty(() => {
2002
+ if (!runner.epoch) return setupFailed ? inFlight : void 0;
2003
+ runner.epoch = false;
2004
+ return finalizeDisposal(() => {
2005
+ if (executing) return disposeAfter(waitForSetup());
2006
+ return task ? disposeAfter(task) : dispose();
2007
+ });
2008
+ }, symbols.effect, meta);
2009
+ effectInertia.set(wrapper, () => inFlight);
2010
+ removeWrapper = this._disposables.push(wrapper);
2011
+ try {
2012
+ task = this._execute(runner);
2013
+ } catch (reason) {
2014
+ executing = false;
2015
+ setupFailed = true;
2016
+ runner.epoch = false;
2017
+ let cleanup;
2018
+ try {
2019
+ cleanup = finalizeDisposal(dispose);
2020
+ } finally {
2021
+ rejectSetup?.(reason);
2022
+ }
2023
+ if (isObject(cleanup) && "then" in cleanup) cleanup.catch((error) => this.ctx.logger.error(error));
2024
+ throw reason;
2025
+ }
2026
+ executing = false;
2027
+ if (setupBarrier) Promise.resolve(task).then(resolveSetup, rejectSetup);
2028
+ task?.catch(() => {
2029
+ if (!runner.epoch) return dispose();
2030
+ return finalizeDisposal(dispose);
2031
+ }).catch((error) => this.ctx.logger.error(error));
2032
+ const disposeAsync = () => {
2033
+ if (!runner.epoch) return;
2034
+ runner.epoch = false;
2035
+ return finalizeDisposal(dispose);
2036
+ };
2037
+ wrapper.then = async (onFulfilled, onRejected) => {
2038
+ return Promise.resolve(task).then(() => disposeAsync).then(onFulfilled, onRejected);
2039
+ };
2040
+ return wrapper;
2041
+ }
2042
+ /**
2043
+ * Return metadata for currently registered effects.
2044
+ *
2045
+ * @returns one {@link EffectMeta} tree per labeled live effect.
2046
+ */
2047
+ getEffects() {
2048
+ return [...this._disposables].map((dispose) => dispose[symbols.effect]).filter(Boolean);
2049
+ }
2050
+ _getState() {
2051
+ if (this.uid === null) return 4;
2052
+ if (this._error) return 3;
2053
+ if (this._runner.epoch !== INACTIVE) return 2;
2054
+ return 0;
2055
+ }
2056
+ _updateState(callback) {
2057
+ const oldState = this.state;
2058
+ this.state = callback() ?? this._getState();
2059
+ if (oldState === this.state) return;
2060
+ this.context.emit("internal/status", this, oldState);
2061
+ if (oldState !== 2 && this.state !== 2) return;
2062
+ for (const key of Reflect.ownKeys(this.ctx.reflect.store)) {
2063
+ const impl = this.ctx.reflect.store[key];
2064
+ if (impl.fiber !== this) continue;
2065
+ this.ctx.reflect.notify([impl.name]);
2066
+ }
2067
+ }
2068
+ _checkImpl(name2) {
2069
+ const impl = this.ctx.reflect._getImpl(name2, true);
2070
+ if (!impl) return delete this._store[name2];
2071
+ try {
2072
+ if (impl.check && !impl.check.call(getTraceable(this.ctx, impl.value))) return delete this._store[name2];
2073
+ } catch (error) {
2074
+ impl.fiber.ctx.logger.error(error);
2075
+ return delete this._store[name2];
2076
+ }
2077
+ this._store[name2] = impl;
2078
+ }
2079
+ _refresh() {
2080
+ let epoch = false;
2081
+ epoch = "";
2082
+ for (const name2 of Object.keys(this.inject)) {
2083
+ const impl = this._store[name2];
2084
+ if (!impl) {
2085
+ epoch = INACTIVE;
2086
+ break;
2087
+ }
2088
+ epoch += ":" + impl.fiber.uid;
2089
+ }
2090
+ this._setEpoch(epoch);
2091
+ }
2092
+ _setEpoch(epoch) {
2093
+ const oldEpoch = this._runner.epoch;
2094
+ if (epoch === oldEpoch) return;
2095
+ this._runner.epoch = epoch;
2096
+ if (this.inertia) return;
2097
+ this._updateState(() => {
2098
+ if (epoch !== INACTIVE && oldEpoch === INACTIVE) {
2099
+ this.inertia = this._reload();
2100
+ return 1;
2101
+ } else {
2102
+ this.inertia = this._unload();
2103
+ return 5;
2104
+ }
2105
+ });
2106
+ }
2107
+ _resolveConfig(config) {
2108
+ config = this.context.waterfall(this, "internal/config", config, () => config);
2109
+ return this.runtime ? resolveConfig(this.runtime, config) : config;
2110
+ }
2111
+ async _reload() {
2112
+ this.store = { ...this._store };
2113
+ const oldEpoch = this._runner.epoch;
2114
+ try {
2115
+ await Promise.resolve();
2116
+ if (this._runner.epoch === oldEpoch) {
2117
+ this.config = this._resolveConfig(this._config);
2118
+ await this._execute(this._runner);
2119
+ this._error = void 0;
2120
+ }
2121
+ } catch (reason) {
2122
+ this.ctx.logger.error(reason);
2123
+ this._error = reason;
2124
+ this._runner.epoch = INACTIVE;
2125
+ }
2126
+ this._updateState(() => {
2127
+ if (this._runner.epoch === oldEpoch) this.inertia = void 0;
2128
+ else {
2129
+ this.inertia = this._unload();
2130
+ return 5;
2131
+ }
2132
+ });
2133
+ }
2134
+ async _unload() {
2135
+ await Promise.all(this._disposables.clear().map(async (dispose) => {
2136
+ try {
2137
+ await composeError(async (info) => {
2138
+ await Promise.resolve();
2139
+ info.error = /* @__PURE__ */ new Error();
2140
+ await runDisposable(dispose);
2141
+ }, this._runner.getOuterStack);
2142
+ } catch (reason) {
2143
+ this.ctx.logger.error(reason);
2144
+ }
2145
+ }));
2146
+ this.store = void 0;
2147
+ this._updateState(() => {
2148
+ if (this._runner.epoch === INACTIVE) this.inertia = void 0;
2149
+ else {
2150
+ this.inertia = this._reload();
2151
+ return 1;
2152
+ }
2153
+ });
2154
+ }
2155
+ /**
2156
+ * Wait for current lifecycle work and rethrow startup errors.
2157
+ *
2158
+ * @returns this fiber, once it has settled into a stable state.
2159
+ * @throws the config-validation or plugin-startup error, if any.
2160
+ */
2161
+ async await() {
2162
+ while (this.inertia) await this.inertia;
2163
+ if (this._error) throw this._error;
2164
+ return this;
2165
+ }
2166
+ /**
2167
+ * Dispose and immediately reload this plugin with its current config.
2168
+ *
2169
+ * @returns a promise resolving once the reload settled.
2170
+ * @throws {CordisError} `INACTIVE_EFFECT` when the fiber is already disposed.
2171
+ */
2172
+ async restart() {
2173
+ this.assertActive();
2174
+ this._setEpoch(INACTIVE);
2175
+ this._refresh();
2176
+ await this.await();
2177
+ }
2178
+ /**
2179
+ * Validate and apply new config, then restart the plugin.
2180
+ *
2181
+ * Runs the `internal/update` waterfall first, so update hooks (and HMR)
2182
+ * can veto or replace the restart.
2183
+ *
2184
+ * @param config — the new raw config; validated before anything restarts.
2185
+ * @param noSave — hint for persistence hooks not to write the change back.
2186
+ * @returns the update waterfall result; the default restart returns a promise.
2187
+ * @throws when validation, an update listener, or the restarted plugin fails.
2188
+ */
2189
+ update(config, noSave = false) {
2190
+ this.assertActive();
2191
+ this._config = config;
2192
+ if (this.state !== 2) {
2193
+ this._error = void 0;
2194
+ this._setEpoch(INACTIVE);
2195
+ this._refresh();
2196
+ return;
2197
+ }
2198
+ config = this._resolveConfig(config);
2199
+ return this.context.waterfall(this, "internal/update", config, noSave, () => {
2200
+ this.config = config;
2201
+ this._error = void 0;
2202
+ return this.restart();
2203
+ });
2204
+ }
2205
+ };
2206
+ function isApplicable(object) {
2207
+ return object && typeof object === "object" && typeof object.apply === "function";
2208
+ }
2209
+ function Inject(name2, config) {
2210
+ return function(value, decorator) {
2211
+ if (decorator.kind === "class") {
2212
+ if (!Object.hasOwn(value, "inject")) {
2213
+ defineProperty(value, "inject", Object.create(Object.getPrototypeOf(value).inject ?? null));
2214
+ defineProperty(value.inject, symbols.checkProto, true);
2215
+ }
2216
+ value.inject[name2] = config;
2217
+ } else if (decorator.kind === "method") {
2218
+ const inject2 = (value[symbols.metadata] ??= {}).inject ??= /* @__PURE__ */ Object.create(null);
2219
+ inject2[name2] = config;
2220
+ decorator.addInitializer(function() {
2221
+ const property2 = this[symbols.tracker]?.property;
2222
+ (this[symbols.initHooks] ??= []).push(() => {
2223
+ this.ctx.inject(inject2, (ctx) => {
2224
+ return value.call(property2 ? withProps(this, { [property2]: ctx }) : this);
2225
+ });
2226
+ });
2227
+ });
2228
+ } else throw new Error("@Inject() can only be used on class or class methods");
2229
+ };
2230
+ }
2231
+ (function(Inject2) {
2232
+ function resolve2(inject2, result = /* @__PURE__ */ Object.create(null)) {
2233
+ if (!inject2) return result;
2234
+ if (Array.isArray(inject2)) for (const name2 of inject2) result[name2] = null;
2235
+ else if (Reflect.has(inject2, symbols.checkProto)) {
2236
+ Object.assign(result, resolve2(Object.getPrototypeOf(inject2)));
2237
+ for (const name2 of Object.keys(inject2)) result[name2] = inject2[name2] ?? null;
2238
+ } else for (const name2 of Object.keys(inject2)) result[name2] = inject2[name2] ?? null;
2239
+ return result;
2240
+ }
2241
+ Inject2.resolve = resolve2;
2242
+ })(Inject || (Inject = {}));
2243
+ var RegistryService = class {
2244
+ ctx;
2245
+ _counter = 0;
2246
+ _internal = /* @__PURE__ */ new Map();
2247
+ constructor(ctx) {
2248
+ this.ctx = ctx;
2249
+ defineProperty(this, symbols.tracker, {
2250
+ property: "ctx",
2251
+ noShadow: true
2252
+ });
2253
+ }
2254
+ /** Allocate the next fiber uid (increments on every read). */
2255
+ get counter() {
2256
+ return ++this._counter;
2257
+ }
2258
+ /** Number of registered plugin runtimes. */
2259
+ get size() {
2260
+ return this._internal.size;
2261
+ }
2262
+ /**
2263
+ * Resolve a supported plugin shape to its executable callback.
2264
+ *
2265
+ * @param plugin — a function, class, or `{ apply }` object plugin.
2266
+ * @returns the callback identifying the plugin, or `undefined` if invalid.
2267
+ */
2268
+ resolve(plugin) {
2269
+ try {
2270
+ if (typeof plugin === "function") return plugin;
2271
+ if (isApplicable(plugin)) return plugin.apply;
2272
+ } catch {
2273
+ }
2274
+ }
2275
+ /**
2276
+ * Look up the runtime record for a plugin.
2277
+ *
2278
+ * @param plugin — any supported plugin shape.
2279
+ * @returns the runtime, or `undefined` when the plugin is not registered.
2280
+ */
2281
+ get(plugin) {
2282
+ const key = this.resolve(plugin);
2283
+ return key && this._internal.get(key);
2284
+ }
2285
+ /**
2286
+ * Check whether a plugin has a registered runtime.
2287
+ *
2288
+ * @param plugin — any supported plugin shape.
2289
+ * @returns `true` when at least one fiber of the plugin exists.
2290
+ */
2291
+ has(plugin) {
2292
+ const key = this.resolve(plugin);
2293
+ return !!key && this._internal.has(key);
2294
+ }
2295
+ /**
2296
+ * Dispose every running fiber for a plugin and remove its runtime record.
2297
+ *
2298
+ * @param plugin — any supported plugin shape.
2299
+ * @returns the removed runtime, or `undefined` when none was registered.
2300
+ */
2301
+ delete(plugin) {
2302
+ const key = this.resolve(plugin);
2303
+ const runtime = key && this._internal.get(key);
2304
+ if (!runtime) return;
2305
+ this._internal.delete(key);
2306
+ for (const fiber of runtime.fibers) fiber.dispose();
2307
+ return runtime;
2308
+ }
2309
+ /** Iterate the registered plugin callbacks. */
2310
+ keys() {
2311
+ return this._internal.keys();
2312
+ }
2313
+ /** Iterate the registered plugin runtimes. */
2314
+ values() {
2315
+ return this._internal.values();
2316
+ }
2317
+ /** Iterate `[callback, runtime]` pairs. */
2318
+ entries() {
2319
+ return this._internal.entries();
2320
+ }
2321
+ /**
2322
+ * Visit every registered runtime.
2323
+ *
2324
+ * @param callback — receives each runtime and its identifying callback.
2325
+ */
2326
+ forEach(callback) {
2327
+ return this._internal.forEach(callback);
2328
+ }
2329
+ /**
2330
+ * Start a callback once the requested dependencies are available.
2331
+ *
2332
+ * @param inject — required services, as an array or a name → config map.
2333
+ * @param callback — plugin body called with `(ctx, config)`.
2334
+ * @returns the fiber; awaiting it settles once loading finished.
2335
+ */
2336
+ inject(inject2, callback) {
2337
+ return this.plugin({
2338
+ inject: inject2,
2339
+ apply: callback,
2340
+ name: callback.name
2341
+ });
2342
+ }
2343
+ /**
2344
+ * Start a plugin in the current context and return its fiber.
2345
+ *
2346
+ * Creates (or reuses) the plugin's runtime record, then starts a new fiber
2347
+ * under the current context. Throws if `plugin` is not a supported shape or
2348
+ * if the current fiber is already disposed.
2349
+ *
2350
+ * @param plugin — a function, class, or `{ apply }` object plugin.
2351
+ * @param config — the plugin config, validated against its `Config` schema.
2352
+ * @param getOuterStack — captures the caller stack for effect diagnostics.
2353
+ * @returns the fiber; awaiting it settles once loading finished.
2354
+ */
2355
+ plugin(plugin, config, getOuterStack = buildOuterStack()) {
2356
+ const callback = this.resolve(plugin);
2357
+ if (!callback) throw new Error('invalid plugin, expect function or object with an "apply" method, received ' + typeof plugin);
2358
+ this.ctx.fiber.assertActive();
2359
+ let runtime = this._internal.get(callback);
2360
+ if (!runtime) {
2361
+ let name2 = plugin.name;
2362
+ if (name2 === "apply") name2 = void 0;
2363
+ runtime = {
2364
+ name: name2,
2365
+ callback,
2366
+ fibers: new DisposableList(),
2367
+ Config: plugin.Config
2368
+ };
2369
+ this._internal.set(callback, runtime);
2370
+ }
2371
+ const fiber = new Fiber(this.ctx, config, Inject.resolve(plugin.inject), runtime, getOuterStack);
2372
+ const wrapped = Object.create(fiber);
2373
+ wrapped.then = (onFulfilled, onRejected) => {
2374
+ return fiber.await().then(onFulfilled, onRejected);
2375
+ };
2376
+ return wrapped;
2377
+ }
2378
+ };
2379
+ var Context = class Context2 {
2380
+ /** Symbol key under which a disposer exposes its {@link EffectMeta} diagnostics tree. */
2381
+ static effect = symbols.effect;
2382
+ /** Symbol key for a context's listener filter, consulted on every event dispatch. */
2383
+ static filter = symbols.filter;
2384
+ /** Symbol key of the isolation map (see the `Context[symbols.isolate]` property). */
2385
+ static isolate = symbols.isolate;
2386
+ /** Symbol key of the intercept map (see the `Context[symbols.intercept]` property). */
2387
+ static intercept = symbols.intercept;
2388
+ /**
2389
+ * Returns true for Cordis context proxies and context prototypes.
2390
+ *
2391
+ * Works across realms and across multiple copies of cordis, because the
2392
+ * brand is keyed by a global symbol rather than by `instanceof`.
2393
+ *
2394
+ * @param value — the value to test.
2395
+ * @returns `true` if `value` is a Cordis context, narrowing its type.
2396
+ */
2397
+ static is(value) {
2398
+ return !!value?.[Context2.is];
2399
+ }
2400
+ static {
2401
+ Context2.is[Symbol.toPrimitive] = () => Symbol.for("cordis.is");
2402
+ Context2.prototype[Context2.is] = true;
2403
+ }
2404
+ /** Create the root context and install the built-in services. */
2405
+ constructor() {
2406
+ this[symbols.isolate] = /* @__PURE__ */ Object.create(null);
2407
+ this[symbols.intercept] = /* @__PURE__ */ Object.create(null);
2408
+ const self = new Proxy(this, ReflectService.handler);
2409
+ this.root = self;
2410
+ this.baseUrl = void 0;
2411
+ this.fiber = new Fiber(self, {}, /* @__PURE__ */ Object.create(null), null, () => []);
2412
+ this.reflect = new ReflectService(self);
2413
+ this.registry = new RegistryService(self);
2414
+ this.events = new EventsService(self);
2415
+ this.logger = new LoggerService(self);
2416
+ this.fiber._disposables.clear();
2417
+ return self;
2418
+ }
2419
+ [Symbol.for("nodejs.util.inspect.custom")]() {
2420
+ return `Context <${this.fiber.name}>`;
2421
+ }
2422
+ /**
2423
+ * Create a child context with extra metadata on top of the current scope.
2424
+ *
2425
+ * The child prototypally inherits every property of this context; own
2426
+ * properties of `meta` shadow the inherited ones. The parent is not mutated.
2427
+ *
2428
+ * @param meta — own properties (including symbol keys) to define on the child.
2429
+ * @returns a child context inheriting from this one.
2430
+ */
2431
+ extend(meta = {}) {
2432
+ const shadow = Reflect.getOwnPropertyDescriptor(this, symbols.shadow)?.value;
2433
+ const self = Object.create(getTraceable(this, this));
2434
+ for (const prop of Reflect.ownKeys(meta)) Object.defineProperty(self, prop, Reflect.getOwnPropertyDescriptor(meta, prop));
2435
+ if (!shadow) return self;
2436
+ return Object.assign(Object.create(self), { [symbols.shadow]: shadow });
2437
+ }
2438
+ /**
2439
+ * Create a child context with an independent service scope for `name`.
2440
+ *
2441
+ * Below the returned context, reads and writes of the service `name`
2442
+ * resolve against the new label instead of the parent's, so a different
2443
+ * implementation can be provided without affecting the parent scope.
2444
+ * Passing the same `label` to two `isolate()` calls joins their scopes.
2445
+ *
2446
+ * @param name — the service name to isolate.
2447
+ * @param label — scope label to join; defaults to a fresh unique symbol.
2448
+ * @returns a child context whose `name` service resolves in the new scope.
2449
+ */
2450
+ isolate(name2, label) {
2451
+ const shadow = Object.create(this[symbols.isolate]);
2452
+ shadow[name2] = label ?? Symbol(name2);
2453
+ return this.extend({ [symbols.isolate]: shadow });
2454
+ }
2455
+ intercept(name2, config) {
2456
+ const intercept = Object.create(this[symbols.intercept]);
2457
+ intercept[name2] = config;
2458
+ return this.extend({ [symbols.intercept]: intercept });
2459
+ }
2460
+ };
2461
+ var Service = class Service2 {
2462
+ ctx;
2463
+ /** Symbol key of an instance method run after construction (class plugins). */
2464
+ static init = symbols.init;
2465
+ /** Symbol key of the availability predicate passed to `ctx.provide()`. */
2466
+ static check = symbols.check;
2467
+ /** Symbol key of the phantom intercept-config type parameter. */
2468
+ static config = symbols.config;
2469
+ /** Symbol key of the call body making a service callable (e.g. `ctx.logger()`). */
2470
+ static invoke = symbols.invoke;
2471
+ /** Symbol key of the helper deriving an extended service instance. */
2472
+ static extend = symbols.extend;
2473
+ /** Symbol key of the tracker metadata used for context tracing. */
2474
+ static tracker = symbols.tracker;
2475
+ /** Symbol key of the intercept-config resolution helper below. */
2476
+ static resolveConfig = symbols.resolveConfig;
2477
+ /** The service name this instance is registered under. */
2478
+ name;
2479
+ /**
2480
+ * Register this instance as `name` in the current context.
2481
+ *
2482
+ * Calls `ctx.reflect.provide(name, this, this[Service.check])`, so the
2483
+ * service is unregistered automatically when the owning fiber unloads.
2484
+ * Services with a `[Service.invoke]` body return a callable instance.
2485
+ *
2486
+ * @param ctx — the context to register in (stored as `this.ctx`).
2487
+ * @param name — the service name; defaults to the static `provide` field.
2488
+ */
2489
+ constructor(ctx, name2) {
2490
+ this.ctx = ctx;
2491
+ name2 ??= this.constructor["provide"];
2492
+ let self = this;
2493
+ const tracker = {
2494
+ associate: name2,
2495
+ property: "ctx"
2496
+ };
2497
+ if (self[symbols.invoke]) self = createCallable(name2, joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker);
2498
+ self.ctx = ctx;
2499
+ self.name = name2;
2500
+ defineProperty(self, symbols.tracker, tracker);
2501
+ self.ctx.reflect.provide(name2, self, this[symbols.check]);
2502
+ return self;
2503
+ }
2504
+ [symbols.filter](ctx) {
2505
+ return ctx[symbols.isolate][this.name] === this.ctx[symbols.isolate][this.name];
2506
+ }
2507
+ [symbols.extend](props) {
2508
+ let self;
2509
+ if (this[Service2.invoke]) self = createCallable(this.name, this, this[symbols.tracker]);
2510
+ else self = Object.create(this);
2511
+ return Object.assign(self, props);
2512
+ }
2513
+ /**
2514
+ * Merge intercept config from ancestors with optional base and head values.
2515
+ *
2516
+ * Entries added closer to the root apply first; `base` is prepended and
2517
+ * `head` appended. Uses `Config.merge` when the service declares one,
2518
+ * otherwise a shallow `Object.assign`.
2519
+ *
2520
+ * @param base — lowest-precedence config merged before all intercepts.
2521
+ * @param head — highest-precedence config merged after all intercepts.
2522
+ * @returns the merged config.
2523
+ */
2524
+ [symbols.resolveConfig](base, head) {
2525
+ let intercept = this.ctx[Context.intercept];
2526
+ const configs = [];
2527
+ while (this.name in intercept) {
2528
+ if (Object.hasOwn(intercept, this.name)) configs.unshift(intercept[this.name]);
2529
+ intercept = Object.getPrototypeOf(intercept);
2530
+ }
2531
+ if (base) configs.unshift(base);
2532
+ if (head) configs.push(head);
2533
+ if (this["Config"]?.merge) return this["Config"].merge(...configs);
2534
+ else return Object.assign({}, ...configs);
2535
+ }
2536
+ static [Symbol.hasInstance](instance) {
2537
+ if (!instance) return false;
2538
+ let constructor = instance.constructor;
2539
+ while (constructor) {
2540
+ constructor = constructor.prototype?.constructor;
2541
+ if (constructor === this) return true;
2542
+ constructor &&= Object.getPrototypeOf(constructor);
2543
+ }
2544
+ return false;
2545
+ }
2546
+ };
2547
+
2548
+ // node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.2-rc.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-values/lib/index.js
2549
+ function deepEqualJson(a, b) {
2550
+ if (a === b) return true;
2551
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
2552
+ if (Array.isArray(a) || Array.isArray(b)) {
2553
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
2554
+ return a.every((entry, index) => deepEqualJson(entry, b[index]));
2555
+ }
2556
+ const left = a;
2557
+ const right = b;
2558
+ const keys = Object.keys(left);
2559
+ if (keys.length !== Object.keys(right).length) return false;
2560
+ return keys.every((key) => key in right && deepEqualJson(left[key], right[key]));
2561
+ }
2562
+ function deepFreeze(value) {
2563
+ const seen = /* @__PURE__ */ new WeakSet();
2564
+ const pending = [{
2565
+ kind: "visit",
2566
+ node: value
2567
+ }];
2568
+ while (pending.length > 0) {
2569
+ const task = pending.pop();
2570
+ if (task === void 0) continue;
2571
+ if (task.kind === "property") {
2572
+ pending.push({
2573
+ kind: "visit",
2574
+ node: task.source[task.key]
2575
+ });
2576
+ continue;
2577
+ }
2578
+ const node = task.node;
2579
+ if (node === null || typeof node !== "object") continue;
2580
+ if (node instanceof AbortSignal) continue;
2581
+ if (seen.has(node)) continue;
2582
+ seen.add(node);
2583
+ Object.freeze(node);
2584
+ const keys = Object.keys(node);
2585
+ for (let index = keys.length - 1; index >= 0; index--) {
2586
+ const key = keys[index];
2587
+ if (key === void 0) continue;
2588
+ pending.push({
2589
+ kind: "property",
2590
+ source: node,
2591
+ key
2592
+ });
2593
+ }
2594
+ }
2595
+ return value;
2596
+ }
2597
+
2598
+ // node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.2-rc.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-brand@0_1a9c14ce482b5dfab9823d79763d2768/node_modules/@deepseek-ai/dsh-settings/lib/index.js
2599
+ function isRecord(value) {
2600
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2601
+ }
2602
+ function walk(node, value, path, secrets) {
2603
+ if (node === void 0) return value;
2604
+ if (node.meta?.role === "secret") {
2605
+ secrets.push({
2606
+ path,
2607
+ set: value !== void 0
2608
+ });
2609
+ return;
2610
+ }
2611
+ switch (node.type) {
2612
+ case "object": {
2613
+ const properties = node.dict ?? {};
2614
+ const source = isRecord(value) ? value : void 0;
2615
+ const rebuilt = {};
2616
+ if (source !== void 0) for (const [key, entry] of Object.entries(source)) {
2617
+ if (key in properties) continue;
2618
+ rebuilt[key] = entry;
2619
+ }
2620
+ for (const [key, child] of Object.entries(properties)) {
2621
+ const stripped = walk(child, source?.[key], [...path, key], secrets);
2622
+ if (stripped !== void 0) rebuilt[key] = stripped;
2623
+ }
2624
+ return source === void 0 && Object.keys(rebuilt).length === 0 ? value : rebuilt;
2625
+ }
2626
+ case "dict": {
2627
+ if (!isRecord(value)) return value;
2628
+ const rebuilt = {};
2629
+ for (const [key, entry] of Object.entries(value)) {
2630
+ const stripped = walk(node.inner, entry, [...path, key], secrets);
2631
+ if (stripped !== void 0) rebuilt[key] = stripped;
2632
+ }
2633
+ return rebuilt;
2634
+ }
2635
+ case "array":
2636
+ if (!Array.isArray(value)) return value;
2637
+ return value.map((entry, index) => walk(node.inner, entry, [...path, String(index)], secrets));
2638
+ default:
2639
+ return value;
2640
+ }
2641
+ }
2642
+ function redactSecrets(schema, value) {
2643
+ const secrets = [];
2644
+ return {
2645
+ value: walk(schema, value, [], secrets),
2646
+ secrets
2647
+ };
2648
+ }
2649
+ var NAMESPACE_PATTERN = /^[a-z][a-z0-9-]*$/;
2650
+ function parseSettingsNamespace(value) {
2651
+ if (!NAMESPACE_PATTERN.test(value)) throw new TypeError(`settings namespace "${value}" must match ${String(NAMESPACE_PATTERN)}`);
2652
+ return value;
2653
+ }
2654
+ var SettingsConflictError = class extends Error {
2655
+ /** Stable machine code for wire layers mapping this to their own taxonomy. */
2656
+ code = "SETTINGS_CONFLICT";
2657
+ /** The revision the write expected. */
2658
+ expected;
2659
+ /** The revision the namespace actually stands at. */
2660
+ actual;
2661
+ /**
2662
+ * @param ns - the namespace whose write was refused.
2663
+ * @param expected - the revision the caller sent.
2664
+ * @param actual - the revision now stored.
2665
+ */
2666
+ constructor(ns, expected, actual) {
2667
+ super(`settings namespace "${ns}" changed since it was read (expected revision ${String(expected)}, now ${String(actual)})`);
2668
+ this.name = "SettingsConflictError";
2669
+ this.expected = expected;
2670
+ this.actual = actual;
2671
+ }
2672
+ };
2673
+ function isPlainObject2(value) {
2674
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
2675
+ const proto = Object.getPrototypeOf(value);
2676
+ return proto === Object.prototype || proto === null;
2677
+ }
2678
+ function applyPathOp(section, op) {
2679
+ const [head, ...rest] = op.path;
2680
+ if (head === void 0) {
2681
+ if (op.op === "unset") return {};
2682
+ if (!isPlainObject2(op.value)) throw new TypeError("settings mutate: setting the section root requires a plain object");
2683
+ return { ...op.value };
2684
+ }
2685
+ if (rest.length === 0) {
2686
+ if (op.op === "set") return {
2687
+ ...section,
2688
+ [head]: op.value
2689
+ };
2690
+ const { [head]: _removed, ...kept } = section;
2691
+ return kept;
2692
+ }
2693
+ const child = section[head];
2694
+ if (!isPlainObject2(child)) {
2695
+ if (op.op === "unset") return section;
2696
+ return {
2697
+ ...section,
2698
+ [head]: applyPathOp({}, {
2699
+ ...op,
2700
+ path: rest
2701
+ })
2702
+ };
2703
+ }
2704
+ return {
2705
+ ...section,
2706
+ [head]: applyPathOp(child, {
2707
+ ...op,
2708
+ path: rest
2709
+ })
2710
+ };
2711
+ }
2712
+ function describeRejected(value) {
2713
+ if (value === void 0) return "undefined";
2714
+ if (typeof value === "object" && value !== null) {
2715
+ const name2 = Object.getPrototypeOf(value)?.constructor?.name;
2716
+ return name2 === void 0 || name2 === "Object" ? "a non-plain object" : `a ${name2}`;
2717
+ }
2718
+ return `a ${typeof value}`;
2719
+ }
2720
+ function cloneJsonShaped(root, reject) {
2721
+ const visiting = /* @__PURE__ */ new WeakSet();
2722
+ const clone2 = (value, path) => {
2723
+ if (value === null || typeof value === "string" || typeof value === "boolean") return value;
2724
+ if (typeof value === "number") {
2725
+ if (!Number.isFinite(value)) throw reject("a non-finite number", path);
2726
+ return value;
2727
+ }
2728
+ if (Array.isArray(value)) {
2729
+ if (visiting.has(value)) throw reject("a circular reference", path);
2730
+ visiting.add(value);
2731
+ const entries = value.map((entry, index) => clone2(entry, `${path}[${index}]`));
2732
+ visiting.delete(value);
2733
+ return entries;
2734
+ }
2735
+ if (isPlainObject2(value)) {
2736
+ if (visiting.has(value)) throw reject("a circular reference", path);
2737
+ visiting.add(value);
2738
+ const out = {};
2739
+ for (const [key, entry] of Object.entries(value)) {
2740
+ if (entry === void 0) continue;
2741
+ out[key] = clone2(entry, `${path}.${key}`);
2742
+ }
2743
+ visiting.delete(value);
2744
+ return out;
2745
+ }
2746
+ throw reject(describeRejected(value), path);
2747
+ };
2748
+ return clone2(root, "$");
2749
+ }
2750
+ function mergeLayers(under, over) {
2751
+ if (over === void 0) return under;
2752
+ if (!isPlainObject2(under) || !isPlainObject2(over)) return over;
2753
+ const merged = { ...under };
2754
+ for (const [key, value] of Object.entries(over)) merged[key] = key in merged ? mergeLayers(merged[key], value) : value;
2755
+ return merged;
2756
+ }
2757
+ var SettingsProvider = class extends Service {
2758
+ registrations = /* @__PURE__ */ new Map();
2759
+ /** Latest published raw document; empty until the provider's first publish. */
2760
+ document = {};
2761
+ /** Per-namespace write chains; settled tails, so a failure never poisons the queue. */
2762
+ writeQueues = /* @__PURE__ */ new Map();
2763
+ /** In-flight watcher invocation segments, drained by the dispose teardown. */
2764
+ pendingTails = /* @__PURE__ */ new Set();
2765
+ /** Set at service dispose: refuse new writes while queued ones drain. */
2766
+ stopped = false;
2767
+ /** Opaque read of {@link stopped}: control flow cannot narrow it across awaits. */
2768
+ isStopped() {
2769
+ return this.stopped;
2770
+ }
2771
+ constructor(ctx) {
2772
+ super(ctx, "settings");
2773
+ }
2774
+ /**
2775
+ * Load the provider's document once and publish it before the service
2776
+ * becomes injectable, and register the write-drain teardown. Providers with
2777
+ * their own init (watchers, connections) delegate here first via
2778
+ * `yield* super[Service.init]()`; their disposers then run before the drain.
2779
+ */
2780
+ async *[Service.init]() {
2781
+ yield async () => {
2782
+ this.stopped = true;
2783
+ await Promise.allSettled([...this.writeQueues.values(), ...this.pendingTails]);
2784
+ };
2785
+ this.publish(await this.load());
2786
+ }
2787
+ /**
2788
+ * Absolute path of the provider's user-editable document, when its storage
2789
+ * is one local file. Configuration surfaces use this only as availability
2790
+ * metadata; the guarded open operation resolves the path again Host-side.
2791
+ * Non-file providers leave it undefined and expose no open-document affordance.
2792
+ * @returns the absolute local document path, or undefined for non-file storage.
2793
+ */
2794
+ get documentPath() {
2795
+ }
2796
+ /**
2797
+ * Prepare the provider's user-editable document for a native editor. File
2798
+ * providers may materialize an absent document before returning its path;
2799
+ * non-file providers return undefined.
2800
+ * @returns the absolute local document path, or undefined for non-file storage.
2801
+ */
2802
+ prepareDocument() {
2803
+ return Promise.resolve(this.documentPath);
2804
+ }
2805
+ /**
2806
+ * Register a namespace schema and receive its owner scope. The registration
2807
+ * is an effect on the calling plugin's fiber: disposing that fiber removes
2808
+ * the namespace and its observers. An invalid stored section fails the
2809
+ * registration itself — the earliest point where the schema can judge it.
2810
+ * @param ns - unique namespace; duplicate registration fails loud.
2811
+ * @param schema - schemastery schema resolving this namespace's value.
2812
+ * @param options - composition `base` layer and effect timing.
2813
+ * @returns the owner scope for reads, observation, and updates.
2814
+ * @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
2815
+ */
2816
+ register(ns, schema, options) {
2817
+ const parsedNs = parseSettingsNamespace(ns);
2818
+ if (this.registrations.has(parsedNs)) throw new Error(`settings namespace "${parsedNs}" is already registered`);
2819
+ const registration = {
2820
+ ns: parsedNs,
2821
+ schema,
2822
+ base: options?.base,
2823
+ applies: options?.applies ?? "live",
2824
+ ...options?.validate === void 0 ? {} : { validate: options.validate },
2825
+ resolved: deepFreeze(this.resolve(schema, options?.base, this.section(parsedNs), options?.validate)),
2826
+ revision: 0,
2827
+ watchers: /* @__PURE__ */ new Set()
2828
+ };
2829
+ this.ctx.effect(() => {
2830
+ this.registrations.set(parsedNs, registration);
2831
+ return () => this.registrations.delete(parsedNs);
2832
+ }, `settings.register(${JSON.stringify(String(parsedNs))})`);
2833
+ return {
2834
+ get: () => registration.resolved,
2835
+ watch: (callback) => {
2836
+ const watcher = {
2837
+ callback,
2838
+ tail: Promise.resolve(),
2839
+ active: true
2840
+ };
2841
+ registration.watchers.add(watcher);
2842
+ return () => {
2843
+ watcher.active = false;
2844
+ registration.watchers.delete(watcher);
2845
+ };
2846
+ },
2847
+ update: (patch) => this.update(parsedNs, patch),
2848
+ replace: (section) => this.replace(parsedNs, section)
2849
+ };
2850
+ }
2851
+ /**
2852
+ * Attach one optional-settings consumer to this provider. The consumer
2853
+ * registers its composition entry as the base layer while this provider is
2854
+ * present, then falls back to that entry if the provider detaches.
2855
+ * @param owner - consumer context whose unload suppresses fallback work.
2856
+ * @param ns - consumer-owned settings namespace.
2857
+ * @param schema - schema resolving the namespace.
2858
+ * @param entry - composition entry used as the base and fallback value.
2859
+ * @param hooks - source sink, change notification, and optional validation.
2860
+ * @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
2861
+ */
2862
+ installSection(owner, ns, schema, entry, hooks) {
2863
+ const scope = this.register(ns, schema, {
2864
+ base: entry,
2865
+ ...hooks.validate === void 0 ? {} : { validate: hooks.validate }
2866
+ });
2867
+ hooks.setSource(() => scope.get());
2868
+ this.ctx.effect(() => () => {
2869
+ if (isUnloading(owner)) return;
2870
+ hooks.setSource(() => entry);
2871
+ hooks.onChange();
2872
+ });
2873
+ hooks.onChange();
2874
+ scope.watch(() => {
2875
+ if (isUnloading(owner)) return;
2876
+ hooks.onChange();
2877
+ });
2878
+ }
2879
+ /**
2880
+ * Describe every registered namespace for configuration surfaces, including
2881
+ * the composition `base` and raw user layers so a form can mark which fields
2882
+ * the user overrode (presence in `user`) and what a reset returns to.
2883
+ * @param options - redaction switch; wire surfaces must redact.
2884
+ * @returns one descriptor per registered namespace, in registration order.
2885
+ */
2886
+ describe(options) {
2887
+ return [...this.registrations.values()].map((registration) => {
2888
+ let user;
2889
+ try {
2890
+ user = this.section(registration.ns);
2891
+ } catch {
2892
+ user = void 0;
2893
+ }
2894
+ const base = registration.base === void 0 ? void 0 : structuredClone(registration.base);
2895
+ const detachedUser = user === void 0 ? void 0 : structuredClone(user);
2896
+ const descriptor = {
2897
+ ns: registration.ns,
2898
+ schema: registration.schema.toJSON(),
2899
+ value: registration.resolved,
2900
+ revision: registration.revision,
2901
+ ...base === void 0 ? {} : { base },
2902
+ ...detachedUser === void 0 ? {} : { user: detachedUser },
2903
+ applies: registration.applies
2904
+ };
2905
+ if (options?.redactSecrets !== true) return descriptor;
2906
+ const schema = registration.schema;
2907
+ const redacted = redactSecrets(schema, registration.resolved);
2908
+ return {
2909
+ ...descriptor,
2910
+ value: redacted.value,
2911
+ ...base === void 0 ? {} : { base: redactSecrets(schema, base).value },
2912
+ ...detachedUser === void 0 ? {} : { user: redactSecrets(schema, detachedUser).value },
2913
+ secrets: redacted.secrets
2914
+ };
2915
+ });
2916
+ }
2917
+ /**
2918
+ * Read one registered namespace's resolved value.
2919
+ * @param ns - the namespace to read.
2920
+ * @returns the resolved value, or `undefined` while unregistered.
2921
+ * @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
2922
+ */
2923
+ get(ns) {
2924
+ return this.registrations.get(parseSettingsNamespace(ns))?.resolved;
2925
+ }
2926
+ /**
2927
+ * Merge a patch into one registered namespace's user layer, validate the
2928
+ * resolved candidate, persist through the provider, then commit and emit.
2929
+ * A validation failure rejects before anything is persisted. Writes to one
2930
+ * namespace are serialized: concurrent updates apply in call order, each
2931
+ * merging over the previous write's committed section.
2932
+ * @param ns - the registered namespace to update.
2933
+ * @param patch - plain-object patch over the user section.
2934
+ * @param expectedRevision - the descriptor `revision` the caller read; a
2935
+ * namespace that moved past it rejects with {@link SettingsConflictError}.
2936
+ * @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
2937
+ */
2938
+ async update(ns, patch, expectedRevision) {
2939
+ return this.write(parseSettingsNamespace(ns), patch, "merge", expectedRevision);
2940
+ }
2941
+ /**
2942
+ * Replace one registered namespace's user section wholesale, validate,
2943
+ * persist, then commit and emit. Keys absent from `section` fall back to the
2944
+ * composition `base` and schema defaults — this is the removal/reset path a
2945
+ * merge-only patch cannot express (`replace({})` re-inherits everything).
2946
+ * @param ns - the registered namespace to replace.
2947
+ * @param section - the complete next user section.
2948
+ * @param expectedRevision - the descriptor `revision` the caller read; a
2949
+ * namespace that moved past it rejects with {@link SettingsConflictError}.
2950
+ * @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
2951
+ */
2952
+ async replace(ns, section, expectedRevision) {
2953
+ return this.write(parseSettingsNamespace(ns), section, "replace", expectedRevision);
2954
+ }
2955
+ /**
2956
+ * Apply path-addressed edits to one registered namespace's user section,
2957
+ * validate, persist, then commit and emit. The ops are applied to the
2958
+ * section as it stands when the write reaches the front of the queue, so a
2959
+ * caller never has to restate fields it did not touch — and, crucially,
2960
+ * cannot delete fields it never saw. This is the write path for any caller
2961
+ * holding a redacted view; `replace` remains the wholesale reset.
2962
+ * @param ns - the registered namespace to edit.
2963
+ * @param ops - ordered path edits; later ops observe earlier ones.
2964
+ * @param expectedRevision - the descriptor `revision` the caller read; a
2965
+ * namespace that moved past it rejects with {@link SettingsConflictError}.
2966
+ * @throws {TypeError} when `ns` is not a lowercase hyphenated identifier.
2967
+ */
2968
+ async mutate(ns, ops, expectedRevision) {
2969
+ const parsedNs = parseSettingsNamespace(ns);
2970
+ if (!Array.isArray(ops)) throw new TypeError(`settings mutate for "${parsedNs}" must be an array of path ops`);
2971
+ for (const op of ops) {
2972
+ if (!isPlainObject2(op) || op["op"] !== "set" && op["op"] !== "unset") throw new TypeError(`settings mutate for "${parsedNs}" ops must be {op:'set'|'unset', path}`);
2973
+ if (!Array.isArray(op["path"]) || op["path"].some((part) => typeof part !== "string")) throw new TypeError(`settings mutate for "${parsedNs}" op paths must be arrays of strings`);
2974
+ }
2975
+ return this.write(parsedNs, ops, "mutate", expectedRevision);
2976
+ }
2977
+ /** Validate a write, then queue it on the namespace's serialized write chain. */
2978
+ write(ns, input, mode, expectedRevision) {
2979
+ const verb = mode === "merge" ? "update" : mode === "replace" ? "replace" : "mutate";
2980
+ const registration = this.registrations.get(ns);
2981
+ if (registration === void 0) throw new Error(`settings namespace "${ns}" is not registered`);
2982
+ if (this.isStopped()) throw new Error(`settings service is disposed: "${ns}" cannot be written`);
2983
+ if (!this.writable) throw new Error(`settings provider is read-only: "${ns}" cannot be updated in-process`);
2984
+ let payload;
2985
+ if (mode === "mutate") payload = { ops: input };
2986
+ else {
2987
+ if (!isPlainObject2(input)) throw new TypeError(`settings ${verb} for "${ns}" must be a plain object`);
2988
+ payload = input;
2989
+ }
2990
+ const snapshot = cloneJsonShaped(payload, (label, path) => /* @__PURE__ */ new TypeError(`settings ${verb} for "${ns}" must contain only JSON-compatible data (found ${label} at ${path})`));
2991
+ const run = (this.writeQueues.get(ns) ?? Promise.resolve()).catch(() => void 0).then(async () => {
2992
+ if (this.isStopped()) throw new Error(`settings service was disposed before the queued "${ns}" ${verb} ran`);
2993
+ if (this.registrations.get(ns) !== registration) throw new Error(`settings namespace "${ns}" registration was disposed before the queued ${verb} ran`);
2994
+ const current = this.section(ns) ?? {};
2995
+ if (expectedRevision !== void 0 && expectedRevision !== registration.revision) throw new SettingsConflictError(ns, expectedRevision, registration.revision);
2996
+ const section = mode === "merge" ? mergeLayers(current, snapshot) : mode === "replace" ? snapshot : snapshot["ops"].reduce(applyPathOp, current);
2997
+ const next = deepFreeze(this.resolve(registration.schema, registration.base, section, registration.validate));
2998
+ await this.persist(ns, section);
2999
+ this.document[ns] = section;
3000
+ if (this.registrations.get(ns) === registration && !this.isStopped()) {
3001
+ this.bumpRevision(registration, current, section);
3002
+ this.commit(registration, next, "update");
3003
+ }
3004
+ });
3005
+ this.writeQueues.set(ns, run);
3006
+ return run;
3007
+ }
3008
+ /**
3009
+ * Provider hook: commit a complete raw document observed in storage. Each
3010
+ * registered namespace re-resolves; an invalid section keeps that
3011
+ * namespace's last good value and warns, other namespaces still commit.
3012
+ * @param doc - the detached raw document (unregistered sections preserved).
3013
+ * @param source - change origin; defaults to `provider`.
3014
+ */
3015
+ publish(doc, source = "provider") {
3016
+ const before = /* @__PURE__ */ new Map();
3017
+ for (const registration of this.registrations.values()) try {
3018
+ before.set(registration.ns, this.section(registration.ns));
3019
+ } catch {
3020
+ before.set(registration.ns, void 0);
3021
+ }
3022
+ this.document = doc;
3023
+ for (const registration of this.registrations.values()) {
3024
+ let next;
3025
+ try {
3026
+ next = deepFreeze(this.resolve(registration.schema, registration.base, this.section(registration.ns), registration.validate));
3027
+ } catch (error) {
3028
+ this.ctx.logger.warn('settings: keeping last good "%s" after invalid stored section', registration.ns);
3029
+ this.ctx.logger.warn(error);
3030
+ continue;
3031
+ }
3032
+ this.bumpRevision(registration, before.get(registration.ns), this.section(registration.ns));
3033
+ this.commit(registration, next, source);
3034
+ }
3035
+ }
3036
+ /** Read one namespace's raw user section, rejecting non-object sections. */
3037
+ section(ns) {
3038
+ const section = this.document[ns];
3039
+ if (section === void 0) return void 0;
3040
+ if (!isPlainObject2(section)) throw new TypeError(`settings section "${ns}" must be an object of keys`);
3041
+ return section;
3042
+ }
3043
+ /** Resolve one namespace value: schema defaults, then `base`, then the user layer. */
3044
+ resolve(schema, base, section, validate) {
3045
+ const value = schema(mergeLayers(base, section));
3046
+ validate?.(value);
3047
+ return value;
3048
+ }
3049
+ /**
3050
+ * Advance a namespace's revision when its RAW section changed, and announce
3051
+ * it. Deliberately independent of {@link commit}'s resolved-value equality:
3052
+ * storing an override equal to the composition base leaves the resolved
3053
+ * value alone but changes what the document says, which is exactly what a
3054
+ * configuration surface must re-read.
3055
+ */
3056
+ bumpRevision(registration, before, after) {
3057
+ if (deepEqualJson(before, after)) return;
3058
+ registration.revision += 1;
3059
+ this.emitDocumentUpdated(registration.ns, registration.revision);
3060
+ }
3061
+ /** Contained fan-out of `settings/document-updated`, mirroring {@link commit}'s. */
3062
+ emitDocumentUpdated(ns, revision) {
3063
+ let invariantFailure;
3064
+ const args = [
3065
+ "settings/document-updated",
3066
+ ns,
3067
+ revision
3068
+ ];
3069
+ for (const listener of this.ctx.events.dispatch("emit", args)) try {
3070
+ const returned = listener(ns, revision);
3071
+ if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => {
3072
+ this.warnListenerFailure(ns, error);
3073
+ });
3074
+ } catch (error) {
3075
+ if (error?.code === "INVARIANT") {
3076
+ invariantFailure ??= error;
3077
+ continue;
3078
+ }
3079
+ this.warnListenerFailure(ns, error);
3080
+ }
3081
+ if (invariantFailure !== void 0) throw invariantFailure;
3082
+ }
3083
+ /** Commit a resolved value when changed: swap, notify watchers, emit the event. */
3084
+ commit(registration, next, source) {
3085
+ const prev = registration.resolved;
3086
+ if (deepEqualJson(next, prev)) return;
3087
+ registration.resolved = next;
3088
+ for (const watcher of [...registration.watchers]) {
3089
+ const segment = watcher.tail.then(() => {
3090
+ if (!watcher.active || this.isStopped()) return;
3091
+ return watcher.callback(next, prev);
3092
+ }).then(() => void 0, (error) => {
3093
+ this.warnWatcherFailure(registration.ns, error);
3094
+ });
3095
+ watcher.tail = segment;
3096
+ this.pendingTails.add(segment);
3097
+ segment.then(() => this.pendingTails.delete(segment));
3098
+ }
3099
+ let invariantFailure;
3100
+ const args = [
3101
+ "settings/updated",
3102
+ registration.ns,
3103
+ next,
3104
+ prev,
3105
+ source
3106
+ ];
3107
+ for (const listener of this.ctx.events.dispatch("emit", args)) try {
3108
+ const returned = listener(registration.ns, next, prev, source);
3109
+ if (returned != null && typeof returned.then === "function") Promise.resolve(returned).then(void 0, (error) => {
3110
+ this.warnListenerFailure(registration.ns, error);
3111
+ });
3112
+ } catch (error) {
3113
+ if (error?.code === "INVARIANT") {
3114
+ invariantFailure ??= error;
3115
+ continue;
3116
+ }
3117
+ this.warnListenerFailure(registration.ns, error);
3118
+ }
3119
+ if (invariantFailure !== void 0) throw invariantFailure;
3120
+ }
3121
+ /** Contained-watcher diagnostic shared by the sync and async failure paths. */
3122
+ warnWatcherFailure(ns, error) {
3123
+ this.ctx.logger.warn('settings: watcher for "%s" failed', ns);
3124
+ this.ctx.logger.warn(error);
3125
+ }
3126
+ /** Contained-listener diagnostic shared by the sync and async failure paths. */
3127
+ warnListenerFailure(ns, error) {
3128
+ this.ctx.logger.warn('settings: a settings/updated listener for "%s" failed', ns);
3129
+ this.ctx.logger.warn(error);
3130
+ }
3131
+ };
3132
+ var FIBER_DISPOSED = 4;
3133
+ var FIBER_UNLOADING = 5;
3134
+ function isUnloading(ctx) {
3135
+ const state = ctx.fiber.state;
3136
+ return state === FIBER_UNLOADING || state === FIBER_DISPOSED;
3137
+ }
3138
+
3139
+ // src/ai-router-client.ts
3140
+ var GatewayError = class extends Error {
3141
+ constructor(code, message, status) {
3142
+ super(message);
3143
+ this.code = code;
3144
+ this.status = status;
3145
+ this.name = "GatewayError";
3146
+ }
3147
+ };
3148
+ var AiRouterClient = class {
3149
+ constructor(baseURL, timeoutMs = 1e4) {
3150
+ this.baseURL = baseURL;
3151
+ this.timeoutMs = timeoutMs;
3152
+ }
3153
+ async login(username, password) {
3154
+ const res = await this.request("/api/admin/auth/login", { method: "POST", body: { username, password } });
3155
+ const sid = extractSessionId(res.headers);
3156
+ if (res.status === 429) throw new GatewayError("RATE_LIMITED", "\u767B\u5F55\u5C1D\u8BD5\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5", 429);
3157
+ if (res.status === 401) throw new GatewayError("AUTH_FAILED", "\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF", 401);
3158
+ if (!res.ok) throw new GatewayError("GATEWAY_UNREACHABLE", `\u7F51\u5173\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP ${res.status}\uFF09`, res.status);
3159
+ if (sid === void 0) throw new GatewayError("GATEWAY_UNREACHABLE", "\u7F51\u5173\u767B\u5F55\u6210\u529F\u4F46\u672A\u8FD4\u56DE\u4F1A\u8BDD Cookie", res.status);
3160
+ const user = await res.json();
3161
+ return { sessionCookie: `session_id=${sid}`, user };
3162
+ }
3163
+ async getMyKey(sessionCookie, keyId) {
3164
+ const qs = keyId === void 0 ? "" : `?key_id=${encodeURIComponent(keyId)}`;
3165
+ const res = await this.request(`/api/me/key${qs}`, { method: "GET", sessionCookie });
3166
+ if (res.status === 401) throw new GatewayError("SESSION_EXPIRED", "\u7F51\u5173\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55", 401);
3167
+ if (res.status === 403) {
3168
+ throw new GatewayError("NO_KEY_ASSIGNED", "\u5F53\u524D\u8D26\u53F7\u5C1A\u672A\u88AB\u5206\u914D\u865A\u62DF KEY\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5206\u914D KEY \u540E\u518D\u767B\u5F55/\u5237\u65B0", 403);
3169
+ }
3170
+ if (res.status === 400) {
3171
+ throw new GatewayError("KEY_INVALID", "\u6240\u9009 KEY \u65E0\u6548\u6216\u5DF2\u88AB\u5220\u9664\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9 KEY \u540E\u5237\u65B0", 400);
3172
+ }
3173
+ if (!res.ok) throw new GatewayError("GATEWAY_UNREACHABLE", `\u7F51\u5173\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP ${res.status}\uFF09`, res.status);
3174
+ return await res.json();
3175
+ }
3176
+ /** GET /api/me/keys:当前用户全部虚拟 Key 的轻量列表(多 Key 选择器数据源)。 */
3177
+ async getMyKeys(sessionCookie) {
3178
+ const res = await this.request("/api/me/keys", { method: "GET", sessionCookie });
3179
+ if (res.status === 401) throw new GatewayError("SESSION_EXPIRED", "\u7F51\u5173\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55", 401);
3180
+ if (res.status === 403) {
3181
+ throw new GatewayError("NO_KEY_ASSIGNED", "\u5F53\u524D\u8D26\u53F7\u5C1A\u672A\u88AB\u5206\u914D\u865A\u62DF KEY\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5206\u914D KEY \u540E\u518D\u767B\u5F55/\u5237\u65B0", 403);
3182
+ }
3183
+ if (!res.ok) throw new GatewayError("GATEWAY_UNREACHABLE", `\u7F51\u5173\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP ${res.status}\uFF09`, res.status);
3184
+ return await res.json();
3185
+ }
3186
+ async logout(sessionCookie) {
3187
+ try {
3188
+ await this.request("/api/admin/auth/logout", { method: "POST", sessionCookie });
3189
+ } catch {
3190
+ }
3191
+ }
3192
+ async request(path, opts) {
3193
+ const headers = { "user-agent": "hiwork-core/0.1.14" };
3194
+ if (opts.body !== void 0) headers["content-type"] = "application/json";
3195
+ if (opts.sessionCookie !== void 0) headers["cookie"] = opts.sessionCookie;
3196
+ const init = {
3197
+ method: opts.method,
3198
+ headers,
3199
+ signal: AbortSignal.timeout(this.timeoutMs)
3200
+ };
3201
+ if (opts.body !== void 0) init.body = JSON.stringify(opts.body);
3202
+ return fetch(`${this.baseURL}${path}`, init);
3203
+ }
3204
+ };
3205
+ function extractSessionId(headers) {
3206
+ const raws = typeof headers.getSetCookie === "function" ? headers.getSetCookie() : [headers.get("set-cookie")].filter((raw) => raw !== null);
3207
+ for (const raw of raws) {
3208
+ const match = /(?:^|[,;]\s*)session_id=([^;]+)/.exec(raw);
3209
+ if (match !== null) return match[1];
3210
+ }
3211
+ return void 0;
3212
+ }
3213
+
3214
+ // src/default-workspace.ts
3215
+ import { mkdir } from "node:fs/promises";
3216
+ import { homedir } from "node:os";
3217
+ import { join } from "node:path";
3218
+ var DEFAULT_WORKSPACE_DIR = join(homedir(), "HiWork", "Default");
3219
+ var DEFAULT_WORKSPACE_TITLE = "\u9ED8\u8BA4\u5DE5\u4F5C\u533A";
3220
+ async function ensureDefaultWorkspace(registry, warn, dir = DEFAULT_WORKSPACE_DIR) {
3221
+ try {
3222
+ if (registry.list().length > 0) return;
3223
+ await mkdir(dir, { recursive: true });
3224
+ await registry.create(dir, DEFAULT_WORKSPACE_TITLE);
3225
+ } catch (error) {
3226
+ warn(`hiwork-core: ensure default workspace failed: ${error instanceof Error ? error.message : String(error)}`);
3227
+ }
3228
+ }
3229
+
3230
+ // src/provision.ts
3231
+ var API_KEY_REF = "AI_ROUTER_API_KEY";
3232
+ var SESSION_REF = "AI_ROUTER_SESSION";
3233
+ var PENDING_PASSWORD_REF = "AI_ROUTER_PENDING_PASSWORD";
3234
+ var REMEMBERED_PASSWORD_REF = "AI_ROUTER_REMEMBERED_PASSWORD";
3235
+ var PROVIDER_ROUTES = {
3236
+ "ai-router": "openai-responses",
3237
+ "ai-router-anthropic": "anthropic-messages"
3238
+ };
3239
+ var DSH_SUPPORTED_MODALITIES = ["text", "image"];
3240
+ var PROVIDER_ROUTE_NAMES = ["ai-router", "ai-router-anthropic"];
3241
+ var LEGACY_PROVIDER_ROUTE_NAMES = ["ai-router-responses"];
3242
+ var ROUTE_DISPLAY_NAMES = {
3243
+ "ai-router": "AI Router",
3244
+ "ai-router-anthropic": "AI Router \xB7 Anthropic"
3245
+ };
3246
+ var GATEWAY_PROTOCOL_TO_ROUTE = {
3247
+ openai_chat_completions: "ai-router",
3248
+ anthropic_messages: "ai-router-anthropic",
3249
+ openai_responses: "ai-router"
3250
+ };
3251
+ var ROUTE_PRIORITY = ["ai-router", "ai-router-anthropic"];
3252
+ function computeModelIds(budgets) {
3253
+ return [...new Set(
3254
+ budgets.filter((b) => b.model_status !== "inactive").map((b) => b.model_name).filter((id) => typeof id === "string" && id.length > 0)
3255
+ )];
3256
+ }
3257
+ function parseModalities(raw) {
3258
+ const tokens = (raw ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
3259
+ if (tokens.length === 0) return ["text"];
3260
+ const declared = new Set(tokens);
3261
+ const intersect = DSH_SUPPORTED_MODALITIES.filter((m) => declared.has(m));
3262
+ return intersect.length > 0 ? intersect : ["text"];
3263
+ }
3264
+ function computeModelDescriptors(budgets) {
3265
+ const byName = /* @__PURE__ */ new Map();
3266
+ for (const b of budgets) if (b.model_name !== "") byName.set(b.model_name, b);
3267
+ return computeModelIds(budgets).map((id) => ({
3268
+ id,
3269
+ input: parseModalities(byName.get(id)?.input_modalities)
3270
+ }));
3271
+ }
3272
+ function mappingProtocol(item) {
3273
+ return item.protocol === void 0 || item.protocol === "" ? "openai_chat_completions" : item.protocol;
3274
+ }
3275
+ function escapeRegex(text) {
3276
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3277
+ }
3278
+ function sourceMatches(pattern2, model) {
3279
+ const p = pattern2.toLowerCase();
3280
+ const m = model.toLowerCase();
3281
+ if (!p.includes("*")) return p === m;
3282
+ if (p === "*") return false;
3283
+ const re = new RegExp("^" + p.split("*").map((s) => s.split("?").map(escapeRegex).join(".")).join(".*") + "$");
3284
+ return re.test(m);
3285
+ }
3286
+ function matchesRoute(item, route, model) {
3287
+ const target = GATEWAY_PROTOCOL_TO_ROUTE[mappingProtocol(item)];
3288
+ if (target !== route) return false;
3289
+ if (typeof item.source_model !== "string" || item.source_model.length === 0) return false;
3290
+ return sourceMatches(item.source_model, model);
3291
+ }
3292
+ function computeRouteModels(budgets, mapping) {
3293
+ const routes = {};
3294
+ const unmatched = [];
3295
+ for (const model of computeModelDescriptors(budgets)) {
3296
+ const route = ROUTE_PRIORITY.find((r) => mapping.some((item) => matchesRoute(item, r, model.id)));
3297
+ if (route === void 0) {
3298
+ unmatched.push(model);
3299
+ continue;
3300
+ }
3301
+ ;
3302
+ (routes[route] ??= []).push(model);
3303
+ }
3304
+ if (unmatched.length > 0) routes["ai-router"] = [...routes["ai-router"] ?? [], ...unmatched];
3305
+ return routes;
3306
+ }
3307
+ function protocolBaseURL(baseURL, protocol) {
3308
+ const bare = baseURL.replace(/\/+$/, "");
3309
+ return protocol === "anthropic-messages" ? bare : `${bare}/v1`;
3310
+ }
3311
+ function buildPiAiProviderProfile(opts) {
3312
+ const protocol = PROVIDER_ROUTES[opts.route];
3313
+ return {
3314
+ displayName: ROUTE_DISPLAY_NAMES[opts.route],
3315
+ apiKeyEnv: API_KEY_REF,
3316
+ api: protocol,
3317
+ baseURL: protocolBaseURL(opts.baseURL, protocol),
3318
+ // input 显式写出(纯文本 ['text'],视觉 ['text','image']),不依赖路由 defaultInput,
3319
+ // 自描述且对未来路由默认值稳健。
3320
+ models: opts.models.map((m) => ({ id: m.id, input: [...m.input] }))
3321
+ };
3322
+ }
3323
+ function buildPiAiProviderProfiles(opts) {
3324
+ const profiles = {};
3325
+ for (const route of PROVIDER_ROUTE_NAMES) {
3326
+ const models = opts.routeModels[route] ?? [];
3327
+ if (models.length === 0) continue;
3328
+ profiles[route] = buildPiAiProviderProfile({ baseURL: opts.baseURL, route, models });
3329
+ }
3330
+ return profiles;
3331
+ }
3332
+
3333
+ // src/orchestration.ts
3334
+ function computeBudgets(budgets) {
3335
+ return budgets.filter((b) => typeof b.model_name === "string" && b.model_name.length > 0).filter((b) => b.model_status !== "inactive").map((b) => ({
3336
+ model_name: b.model_name,
3337
+ ...b.total_budget === void 0 ? {} : { total_budget: b.total_budget },
3338
+ ...b.consumed_budget === void 0 ? {} : { consumed_budget: b.consumed_budget },
3339
+ ...b.remaining_budget === void 0 ? {} : { remaining_budget: b.remaining_budget }
3340
+ }));
3341
+ }
3342
+ function computeKeys(keys) {
3343
+ return keys.filter((k) => typeof k.id === "string" && k.id.length > 0).map((k) => ({
3344
+ id: k.id,
3345
+ ...k.employee_name === void 0 ? {} : { employee_name: k.employee_name },
3346
+ ...k.team_name === void 0 ? {} : { team_name: k.team_name },
3347
+ ...k.enabled === void 0 ? {} : { enabled: k.enabled },
3348
+ ...k.max_concurrency === void 0 ? {} : { max_concurrency: k.max_concurrency },
3349
+ ...k.key_masked === void 0 ? {} : { key_masked: k.key_masked }
3350
+ }));
3351
+ }
3352
+ function toLoginError(error, fallback) {
3353
+ if (error instanceof GatewayError) return { code: error.code, message: error.message };
3354
+ return { code: "GATEWAY_UNREACHABLE", message: fallback };
3355
+ }
3356
+ async function runLogin(opts) {
3357
+ const pending = opts.value.pendingLogin;
3358
+ const baseURL = opts.value.baseURL;
3359
+ if (pending === void 0) return null;
3360
+ if (baseURL === void 0) {
3361
+ await opts.state.patch({ unset: ["pendingLogin"] });
3362
+ await opts.credentials.unset(pending.passwordRef).catch(() => {
3363
+ });
3364
+ return null;
3365
+ }
3366
+ try {
3367
+ const password = await opts.credentials.resolve(pending.passwordRef);
3368
+ if (password === void 0) throw new GatewayError("AUTH_FAILED", "\u767B\u5F55\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55");
3369
+ const { sessionCookie, user } = await opts.gateway.login(pending.username, password.value);
3370
+ await opts.credentials.set(SESSION_REF, sessionCookie);
3371
+ const keys = await opts.gateway.getMyKeys(sessionCookie);
3372
+ const key = await opts.gateway.getMyKey(sessionCookie, opts.value.keyId);
3373
+ const modelIds = computeModelIds(key.budgets);
3374
+ await opts.credentials.set(API_KEY_REF, key.key.key);
3375
+ if (opts.value.rememberPassword === true) await opts.credentials.set(REMEMBERED_PASSWORD_REF, password.value);
3376
+ else await opts.credentials.unset(REMEMBERED_PASSWORD_REF).catch(() => {
3377
+ });
3378
+ if (pending.passwordRef !== REMEMBERED_PASSWORD_REF) await opts.credentials.unset(pending.passwordRef);
3379
+ await opts.piAi.applyAiRouterProfiles(
3380
+ modelIds.length > 0 ? buildPiAiProviderProfiles({ baseURL, routeModels: computeRouteModels(key.budgets, key.model_mapping ?? []) }) : null
3381
+ );
3382
+ const displayName = user.display_name?.trim() || void 0;
3383
+ const set2 = {
3384
+ username: pending.username,
3385
+ ...displayName === void 0 ? {} : { displayName },
3386
+ lastLogin: {
3387
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3388
+ modelCount: modelIds.length,
3389
+ gatewayName: key.gateway_name ?? ""
3390
+ },
3391
+ budgets: computeBudgets(key.budgets),
3392
+ keys: computeKeys(keys)
3393
+ };
3394
+ const unset = ["pendingLogin"];
3395
+ if (displayName === void 0) unset.push("displayName");
3396
+ if (key.key.enabled === false) {
3397
+ set2.lastError = { code: "KEY_DISABLED", message: "Key \u5F53\u524D\u88AB\u7981\u7528\uFF0C\u8C03\u7528\u4F1A\u5931\u8D25" };
3398
+ } else {
3399
+ unset.push("lastError");
3400
+ }
3401
+ await opts.state.patch({ set: set2, unset });
3402
+ await opts.ensureWorkspace?.();
3403
+ return null;
3404
+ } catch (error) {
3405
+ const loginError = toLoginError(error, "\u65E0\u6CD5\u8FDE\u63A5\u7F51\u5173\uFF0C\u8BF7\u68C0\u67E5 baseURL \u6216\u7F51\u7EDC");
3406
+ if (pending.passwordRef !== REMEMBERED_PASSWORD_REF) {
3407
+ await opts.credentials.unset(pending.passwordRef).catch(() => {
3408
+ });
3409
+ } else if (loginError.code === "AUTH_FAILED") {
3410
+ await opts.credentials.unset(REMEMBERED_PASSWORD_REF).catch(() => {
3411
+ });
3412
+ }
3413
+ await opts.state.patch({ set: { lastError: loginError }, unset: ["pendingLogin"] });
3414
+ return loginError;
3415
+ }
3416
+ }
3417
+ async function runRefresh(opts) {
3418
+ const baseURL = opts.value.baseURL;
3419
+ if (baseURL === void 0) {
3420
+ await opts.state.patch({ unset: ["refreshRequest"] });
3421
+ return null;
3422
+ }
3423
+ try {
3424
+ const session = await opts.credentials.resolve(SESSION_REF);
3425
+ if (session === void 0) throw new GatewayError("SESSION_EXPIRED", "\u7F51\u5173\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55");
3426
+ const keys = await opts.gateway.getMyKeys(session.value);
3427
+ const key = await opts.gateway.getMyKey(session.value, opts.value.keyId);
3428
+ const modelIds = computeModelIds(key.budgets);
3429
+ await opts.credentials.set(API_KEY_REF, key.key.key);
3430
+ await opts.piAi.applyAiRouterProfiles(
3431
+ modelIds.length > 0 ? buildPiAiProviderProfiles({ baseURL, routeModels: computeRouteModels(key.budgets, key.model_mapping ?? []) }) : null
3432
+ );
3433
+ const set2 = {
3434
+ lastLogin: {
3435
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3436
+ modelCount: modelIds.length,
3437
+ gatewayName: key.gateway_name ?? ""
3438
+ },
3439
+ budgets: computeBudgets(key.budgets),
3440
+ keys: computeKeys(keys)
3441
+ };
3442
+ const unset = ["refreshRequest"];
3443
+ if (key.key.enabled === false) {
3444
+ set2.lastError = { code: "KEY_DISABLED", message: "Key \u5F53\u524D\u88AB\u7981\u7528\uFF0C\u8C03\u7528\u4F1A\u5931\u8D25" };
3445
+ } else {
3446
+ unset.push("lastError");
3447
+ }
3448
+ await opts.state.patch({ set: set2, unset });
3449
+ return null;
3450
+ } catch (error) {
3451
+ const refreshError = toLoginError(error, "\u65E0\u6CD5\u8FDE\u63A5\u7F51\u5173\uFF0C\u8BF7\u68C0\u67E5 baseURL \u6216\u7F51\u7EDC");
3452
+ if (refreshError.code === "SESSION_EXPIRED" && opts.value.rememberPassword === true && opts.value.username !== void 0) {
3453
+ const remembered = await opts.credentials.resolve(REMEMBERED_PASSWORD_REF).catch(() => void 0);
3454
+ if (remembered !== void 0) {
3455
+ return runLogin({ ...opts, value: { ...opts.value, pendingLogin: { username: opts.value.username, passwordRef: REMEMBERED_PASSWORD_REF } } });
3456
+ }
3457
+ }
3458
+ if (refreshError.code === "SESSION_EXPIRED") {
3459
+ await opts.credentials.unset(SESSION_REF).catch(() => {
3460
+ });
3461
+ }
3462
+ await opts.state.patch({ set: { lastError: refreshError }, unset: ["refreshRequest"] });
3463
+ return refreshError;
3464
+ }
3465
+ }
3466
+ async function runLogout(opts) {
3467
+ try {
3468
+ const session = await opts.credentials.resolve(SESSION_REF);
3469
+ if (session !== void 0) await opts.gateway.logout(session.value);
3470
+ } catch {
3471
+ }
3472
+ await opts.credentials.unset(API_KEY_REF).catch(() => {
3473
+ });
3474
+ await opts.credentials.unset(SESSION_REF).catch(() => {
3475
+ });
3476
+ await opts.credentials.unset(PENDING_PASSWORD_REF).catch(() => {
3477
+ });
3478
+ await opts.credentials.unset(REMEMBERED_PASSWORD_REF).catch(() => {
3479
+ });
3480
+ await opts.piAi.applyAiRouterProfiles(null);
3481
+ await opts.state.patch({
3482
+ unset: ["pendingLogin", "refreshRequest", "logoutRequest", "username", "displayName", "lastLogin", "lastError", "keyId", "budgets", "keys"]
3483
+ });
3484
+ }
3485
+ async function handleAiRouterSectionChange(opts) {
3486
+ const v = opts.value;
3487
+ if (v.pendingLogin !== void 0) return runLogin(opts);
3488
+ if (v.refreshRequest !== void 0) return runRefresh(opts);
3489
+ if (v.logoutRequest !== void 0) {
3490
+ await runLogout(opts);
3491
+ return null;
3492
+ }
3493
+ return null;
3494
+ }
3495
+
3496
+ // src/index.ts
3497
+ var name = "hiwork-core";
3498
+ var inject = ["settings", "credentials", "workspaceRegistry"];
3499
+ var NS = "ai-router";
3500
+ var PI_AI_NS = "llm-pi-ai";
3501
+ var lastErrorSchema = Schema.object({ code: Schema.string().required(), message: Schema.string().required() }).default(void 0);
3502
+ var Config = Schema.object({
3503
+ baseURL: Schema.string(),
3504
+ keyId: Schema.string(),
3505
+ username: Schema.string(),
3506
+ displayName: Schema.string(),
3507
+ lastLogin: Schema.object({ at: Schema.string().required(), modelCount: Schema.number().required(), gatewayName: Schema.string().required() }).default(void 0),
3508
+ lastError: lastErrorSchema,
3509
+ pendingLogin: Schema.object({ username: Schema.string().required(), passwordRef: Schema.string().required() }).default(void 0),
3510
+ rememberPassword: Schema.boolean().default(false),
3511
+ refreshRequest: Schema.object({ at: Schema.string().required() }).default(void 0),
3512
+ logoutRequest: Schema.object({ at: Schema.string().required() }).default(void 0),
3513
+ budgets: Schema.array(Schema.object({
3514
+ model_name: Schema.string().required(),
3515
+ total_budget: Schema.number(),
3516
+ consumed_budget: Schema.number(),
3517
+ remaining_budget: Schema.number()
3518
+ })).default(void 0),
3519
+ keys: Schema.array(Schema.object({
3520
+ id: Schema.string().required(),
3521
+ employee_name: Schema.string(),
3522
+ team_name: Schema.string(),
3523
+ enabled: Schema.boolean(),
3524
+ max_concurrency: Schema.number(),
3525
+ key_masked: Schema.string()
3526
+ })).default(void 0)
3527
+ });
3528
+ function pathOps(patch) {
3529
+ const ops = [];
3530
+ for (const [key, value] of Object.entries(patch.set ?? {})) {
3531
+ ops.push({ op: "set", path: [key], value });
3532
+ }
3533
+ for (const key of patch.unset ?? []) ops.push({ op: "unset", path: [key] });
3534
+ return ops;
3535
+ }
3536
+ async function writeNamespace(settings, ns, ops) {
3537
+ for (let attempt = 0; attempt < 2; attempt++) {
3538
+ const descriptor = settings.describe().find((d) => d.ns === ns);
3539
+ if (descriptor === void 0) throw new Error(`settings namespace "${ns}" is not registered`);
3540
+ try {
3541
+ await settings.mutate(ns, ops, descriptor.revision);
3542
+ return;
3543
+ } catch (error) {
3544
+ if (error instanceof SettingsConflictError || error instanceof Error && error.name === "SettingsConflictError") continue;
3545
+ throw error;
3546
+ }
3547
+ }
3548
+ throw new Error(`settings namespace "${ns}" write conflicted repeatedly`);
3549
+ }
3550
+ function apply(ctx, config) {
3551
+ let current = () => ({ ...config });
3552
+ const settings = ctx.get("settings");
3553
+ const credentials = ctx.get("credentials");
3554
+ if (settings === void 0) throw new Error("settings service unavailable");
3555
+ const gatewayFor = (baseURL) => new AiRouterClient(baseURL.replace(/\/+$/, ""));
3556
+ const ports = {
3557
+ credentials: {
3558
+ resolve: async (ref) => {
3559
+ if (credentials === void 0) return void 0;
3560
+ const hit = await credentials.resolve(ref);
3561
+ return hit === void 0 ? void 0 : { value: hit.value };
3562
+ },
3563
+ set: (ref, value) => {
3564
+ if (credentials === void 0) throw new Error("credentials service unavailable");
3565
+ return credentials.set(ref, value);
3566
+ },
3567
+ unset: (ref) => {
3568
+ if (credentials === void 0) throw new Error("credentials service unavailable");
3569
+ return credentials.unset(ref);
3570
+ }
3571
+ },
3572
+ piAi: {
3573
+ applyAiRouterProfiles: async (profiles) => {
3574
+ if (settings === void 0) throw new Error("settings service unavailable");
3575
+ const ops = [];
3576
+ for (const route of PROVIDER_ROUTE_NAMES) {
3577
+ const profile = profiles?.[route];
3578
+ if (profile === void 0) ops.push({ op: "unset", path: ["providers", route] });
3579
+ else ops.push({ op: "set", path: ["providers", route], value: profile });
3580
+ }
3581
+ for (const route of LEGACY_PROVIDER_ROUTE_NAMES) {
3582
+ ops.push({ op: "unset", path: ["providers", route] });
3583
+ }
3584
+ await writeNamespace(settings, PI_AI_NS, ops);
3585
+ }
3586
+ },
3587
+ state: {
3588
+ patch: async (patch) => {
3589
+ if (settings === void 0) throw new Error("settings service unavailable");
3590
+ await writeNamespace(settings, NS, pathOps(patch));
3591
+ }
3592
+ },
3593
+ ensureWorkspace: async () => {
3594
+ const registry = ctx.get("workspaceRegistry");
3595
+ if (registry === void 0) return;
3596
+ await ensureDefaultWorkspace(registry, (message) => {
3597
+ ctx.logger.warn(message);
3598
+ });
3599
+ }
3600
+ };
3601
+ let inFlight;
3602
+ settings.installSection(ctx, NS, Config, config, {
3603
+ setSource: (source) => {
3604
+ current = source;
3605
+ },
3606
+ onChange: () => {
3607
+ const value = current();
3608
+ const requested = value.pendingLogin ?? value.refreshRequest ?? value.logoutRequest;
3609
+ if (requested === void 0) return;
3610
+ if (inFlight !== void 0) return;
3611
+ inFlight = (async () => {
3612
+ try {
3613
+ const gateway = gatewayFor(value.baseURL ?? "");
3614
+ await handleAiRouterSectionChange({ gateway, ...ports, value });
3615
+ } catch (error) {
3616
+ ctx.logger.error("hiwork-core: ai-router section change failed", error);
3617
+ await ports.credentials.unset(PENDING_PASSWORD_REF).catch(() => {
3618
+ });
3619
+ await ports.state.patch({
3620
+ set: { lastError: { code: "GATEWAY_UNREACHABLE", message: "\u7F51\u5173\u63D2\u4EF6\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u4E0E\u7F51\u7EDC" } },
3621
+ unset: ["pendingLogin", "refreshRequest", "logoutRequest"]
3622
+ }).catch(() => {
3623
+ });
3624
+ }
3625
+ })().finally(() => {
3626
+ inFlight = void 0;
3627
+ });
3628
+ }
3629
+ });
3630
+ if (config.lastLogin === void 0 && config.rememberPassword === true && config.username !== void 0 && config.baseURL !== void 0 && credentials !== void 0) {
3631
+ void credentials.resolve(REMEMBERED_PASSWORD_REF).then((hit) => {
3632
+ if (hit === void 0 || settings === void 0) return;
3633
+ return ports.state.patch({ set: { pendingLogin: { username: config.username, passwordRef: REMEMBERED_PASSWORD_REF } } });
3634
+ }).catch(() => {
3635
+ });
3636
+ }
3637
+ }
3638
+ export {
3639
+ Config,
3640
+ apply,
3641
+ inject,
3642
+ name
3643
+ };