devframe 0.0.0 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +62 -0
  3. package/dist/_shared-CU6dE-VX.mjs +20 -0
  4. package/dist/adapters/build.d.mts +37 -0
  5. package/dist/adapters/build.mjs +61 -0
  6. package/dist/adapters/cli.d.mts +35 -0
  7. package/dist/adapters/cli.mjs +357 -0
  8. package/dist/adapters/embedded.d.mts +19 -0
  9. package/dist/adapters/embedded.mjs +15 -0
  10. package/dist/adapters/kit.d.mts +23 -0
  11. package/dist/adapters/kit.mjs +16 -0
  12. package/dist/adapters/mcp.d.mts +39 -0
  13. package/dist/adapters/mcp.mjs +278 -0
  14. package/dist/adapters/vite.d.mts +32 -0
  15. package/dist/adapters/vite.mjs +31 -0
  16. package/dist/client/index.d.mts +227 -0
  17. package/dist/client/index.mjs +2 -0
  18. package/dist/client-4WrEozlH.mjs +1561 -0
  19. package/dist/constants.d.mts +20 -0
  20. package/dist/constants.mjs +34 -0
  21. package/dist/context-BrePWeyd.mjs +6776 -0
  22. package/dist/define-Bb4zh-Dc.mjs +11 -0
  23. package/dist/devtool-OJ3QW0ns.d.mts +1125 -0
  24. package/dist/helpers/nuxt/index.d.mts +46 -0
  25. package/dist/helpers/nuxt/index.mjs +58 -0
  26. package/dist/helpers/nuxt/runtime/plugin.client.d.mts +8 -0
  27. package/dist/helpers/nuxt/runtime/plugin.client.mjs +12 -0
  28. package/dist/human-id-CHS0s28X.mjs +844 -0
  29. package/dist/immer-HjMAm3b6.mjs +894 -0
  30. package/dist/index-DvKDO5H8.d.mts +333 -0
  31. package/dist/index.d.mts +10 -0
  32. package/dist/index.mjs +2 -0
  33. package/dist/main-DpINGndA.mjs +601 -0
  34. package/dist/node/index.d.mts +365 -0
  35. package/dist/node/index.mjs +69 -0
  36. package/dist/open-BtOOEldu.mjs +533 -0
  37. package/dist/recipes/open-helpers.d.mts +104 -0
  38. package/dist/recipes/open-helpers.mjs +69 -0
  39. package/dist/rpc/client.d.mts +9 -0
  40. package/dist/rpc/client.mjs +13 -0
  41. package/dist/rpc/index.d.mts +2 -0
  42. package/dist/rpc/index.mjs +3 -0
  43. package/dist/rpc/server.d.mts +8 -0
  44. package/dist/rpc/server.mjs +10 -0
  45. package/dist/rpc/transports/ws-client.d.mts +2 -0
  46. package/dist/rpc/transports/ws-client.mjs +43 -0
  47. package/dist/rpc/transports/ws-server.d.mts +2 -0
  48. package/dist/rpc/transports/ws-server.mjs +58 -0
  49. package/dist/rpc-9FNa3Inb.mjs +474 -0
  50. package/dist/server-DrBxa6ZV.mjs +49 -0
  51. package/dist/src-BoIqXRc9.mjs +85 -0
  52. package/dist/static-dump-CQUC1aIW.mjs +82 -0
  53. package/dist/transports-BPUzHhI2.mjs +15 -0
  54. package/dist/types/index.d.mts +4 -0
  55. package/dist/types/index.mjs +6 -0
  56. package/dist/utils/events.d.mts +9 -0
  57. package/dist/utils/events.mjs +40 -0
  58. package/dist/utils/human-id.d.mts +10 -0
  59. package/dist/utils/human-id.mjs +3 -0
  60. package/dist/utils/nanoid.d.mts +4 -0
  61. package/dist/utils/nanoid.mjs +10 -0
  62. package/dist/utils/promise.d.mts +8 -0
  63. package/dist/utils/promise.mjs +15 -0
  64. package/dist/utils/shared-state.d.mts +2 -0
  65. package/dist/utils/shared-state.mjs +36 -0
  66. package/dist/utils/state.d.mts +49 -0
  67. package/dist/utils/state.mjs +26 -0
  68. package/dist/utils/when.d.mts +2 -0
  69. package/dist/utils/when.mjs +424 -0
  70. package/dist/when-CGLewRtm.d.mts +401 -0
  71. package/dist/ws-client-CklfxUHE.d.mts +17 -0
  72. package/dist/ws-server--IuUAaGi.d.mts +37 -0
  73. package/package.json +116 -8
@@ -0,0 +1,474 @@
1
+ import { hash } from "ohash";
2
+ import { consoleReporter, createLogger, defineDiagnostics, plainFormatter } from "logs-sdk";
3
+ //#region src/rpc/cache.ts
4
+ /**
5
+ * @experimental API is expected to change.
6
+ */
7
+ var RpcCacheManager = class {
8
+ cacheMap = /* @__PURE__ */ new Map();
9
+ options;
10
+ keySerializer;
11
+ constructor(options) {
12
+ this.options = options;
13
+ this.keySerializer = options.keySerializer || ((args) => hash(args));
14
+ }
15
+ updateOptions(options) {
16
+ this.options = {
17
+ ...this.options,
18
+ ...options
19
+ };
20
+ }
21
+ cached(m, a) {
22
+ const methodCache = this.cacheMap.get(m);
23
+ if (methodCache) return methodCache.get(this.keySerializer(a));
24
+ }
25
+ apply(req, res) {
26
+ const methodCache = this.cacheMap.get(req.m) || /* @__PURE__ */ new Map();
27
+ methodCache.set(this.keySerializer(req.a), res);
28
+ this.cacheMap.set(req.m, methodCache);
29
+ }
30
+ validate(m) {
31
+ return this.options.functions.includes(m);
32
+ }
33
+ clear(fn) {
34
+ if (fn) this.cacheMap.delete(fn);
35
+ else this.cacheMap.clear();
36
+ }
37
+ };
38
+ const logger = createLogger({
39
+ diagnostics: [defineDiagnostics({
40
+ docsBase: "https://devtools.vite.dev/errors",
41
+ codes: {
42
+ DTK0001: {
43
+ message: (p) => `RPC function "${p.name}" is already registered`,
44
+ hint: "Use the `force` parameter to overwrite an existing registration."
45
+ },
46
+ DTK0002: { message: (p) => `RPC function "${p.name}" is not registered. Use register() to add new functions.` },
47
+ DTK0003: { message: (p) => `RPC function "${p.name}" is not registered` },
48
+ DTK0004: { message: (p) => `Either handler or setup function must be provided for RPC function "${p.name}"` },
49
+ DTK0005: { message: (p) => `Function "${p.name}" not found in dump store` },
50
+ DTK0006: { message: (p) => `No dump match for "${p.name}" with args: ${p.args}` },
51
+ DTK0007: { message: (p) => `Function "${p.name}" with type "${p.type}" cannot have dump configuration. Only "static" and "query" types support dumps.` },
52
+ DTK0008: {
53
+ message: (p) => `Function "${p.name}" with type "${p.type}" cannot use \`snapshot: true\`. Only "query" functions support this sugar; "static" functions have equivalent default behavior already.`,
54
+ hint: "Remove `snapshot: true`, or change the function type to `query`."
55
+ }
56
+ }
57
+ })],
58
+ formatter: plainFormatter,
59
+ reporters: consoleReporter
60
+ });
61
+ //#endregion
62
+ //#region src/rpc/handler.ts
63
+ async function getRpcResolvedSetupResult(definition, context) {
64
+ if (definition.__resolved) return definition.__resolved;
65
+ if (!definition.setup) return {};
66
+ definition.__promise ??= Promise.resolve(definition.setup(context)).then((r) => {
67
+ definition.__resolved = r;
68
+ definition.__promise = void 0;
69
+ return r;
70
+ });
71
+ return definition.__resolved ??= await definition.__promise;
72
+ }
73
+ async function getRpcHandler(definition, context) {
74
+ if (definition.handler) return definition.handler;
75
+ const result = await getRpcResolvedSetupResult(definition, context);
76
+ if (!result.handler) throw logger.DTK0004({ name: definition.name }).throw();
77
+ return result.handler;
78
+ }
79
+ //#endregion
80
+ //#region src/rpc/collector.ts
81
+ var RpcFunctionsCollectorBase = class {
82
+ definitions = /* @__PURE__ */ new Map();
83
+ functions;
84
+ _onChanged = [];
85
+ constructor(context) {
86
+ this.context = context;
87
+ const definitions = this.definitions;
88
+ const self = this;
89
+ this.functions = new Proxy({}, {
90
+ get(_, prop) {
91
+ const definition = definitions.get(prop);
92
+ if (!definition) return void 0;
93
+ return getRpcHandler(definition, self.context);
94
+ },
95
+ has(_, prop) {
96
+ return definitions.has(prop);
97
+ },
98
+ getOwnPropertyDescriptor(_, prop) {
99
+ return {
100
+ value: definitions.get(prop)?.handler,
101
+ configurable: true,
102
+ enumerable: true
103
+ };
104
+ },
105
+ ownKeys() {
106
+ return Array.from(definitions.keys());
107
+ }
108
+ });
109
+ }
110
+ register(fn, force = false) {
111
+ if (this.definitions.has(fn.name) && !force) throw logger.DTK0001({ name: fn.name }).throw();
112
+ this.definitions.set(fn.name, fn);
113
+ this._onChanged.forEach((cb) => cb(fn.name));
114
+ }
115
+ update(fn, force = false) {
116
+ if (!this.definitions.has(fn.name) && !force) throw logger.DTK0002({ name: fn.name }).throw();
117
+ this.definitions.set(fn.name, fn);
118
+ this._onChanged.forEach((cb) => cb(fn.name));
119
+ }
120
+ onChanged(fn) {
121
+ this._onChanged.push(fn);
122
+ return () => {
123
+ const index = this._onChanged.indexOf(fn);
124
+ if (index !== -1) this._onChanged.splice(index, 1);
125
+ };
126
+ }
127
+ async getHandler(name) {
128
+ return await getRpcHandler(this.definitions.get(name), this.context);
129
+ }
130
+ getSchema(name) {
131
+ const definition = this.definitions.get(name);
132
+ if (!definition) throw logger.DTK0003({ name: String(name) }).throw();
133
+ return {
134
+ args: definition.args,
135
+ returns: definition.returns
136
+ };
137
+ }
138
+ has(name) {
139
+ return this.definitions.has(name);
140
+ }
141
+ get(name) {
142
+ return this.definitions.get(name);
143
+ }
144
+ list() {
145
+ return Array.from(this.definitions.keys());
146
+ }
147
+ };
148
+ //#endregion
149
+ //#region ../../../node_modules/.pnpm/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
150
+ var Node = class {
151
+ value;
152
+ next;
153
+ constructor(value) {
154
+ this.value = value;
155
+ }
156
+ };
157
+ var Queue = class {
158
+ #head;
159
+ #tail;
160
+ #size;
161
+ constructor() {
162
+ this.clear();
163
+ }
164
+ enqueue(value) {
165
+ const node = new Node(value);
166
+ if (this.#head) {
167
+ this.#tail.next = node;
168
+ this.#tail = node;
169
+ } else {
170
+ this.#head = node;
171
+ this.#tail = node;
172
+ }
173
+ this.#size++;
174
+ }
175
+ dequeue() {
176
+ const current = this.#head;
177
+ if (!current) return;
178
+ this.#head = this.#head.next;
179
+ this.#size--;
180
+ if (!this.#head) this.#tail = void 0;
181
+ return current.value;
182
+ }
183
+ peek() {
184
+ if (!this.#head) return;
185
+ return this.#head.value;
186
+ }
187
+ clear() {
188
+ this.#head = void 0;
189
+ this.#tail = void 0;
190
+ this.#size = 0;
191
+ }
192
+ get size() {
193
+ return this.#size;
194
+ }
195
+ *[Symbol.iterator]() {
196
+ let current = this.#head;
197
+ while (current) {
198
+ yield current.value;
199
+ current = current.next;
200
+ }
201
+ }
202
+ *drain() {
203
+ while (this.#head) yield this.dequeue();
204
+ }
205
+ };
206
+ //#endregion
207
+ //#region ../../../node_modules/.pnpm/p-limit@7.3.0/node_modules/p-limit/index.js
208
+ function pLimit(concurrency) {
209
+ let rejectOnClear = false;
210
+ if (typeof concurrency === "object") ({concurrency, rejectOnClear = false} = concurrency);
211
+ validateConcurrency(concurrency);
212
+ if (typeof rejectOnClear !== "boolean") throw new TypeError("Expected `rejectOnClear` to be a boolean");
213
+ const queue = new Queue();
214
+ let activeCount = 0;
215
+ const resumeNext = () => {
216
+ if (activeCount < concurrency && queue.size > 0) {
217
+ activeCount++;
218
+ queue.dequeue().run();
219
+ }
220
+ };
221
+ const next = () => {
222
+ activeCount--;
223
+ resumeNext();
224
+ };
225
+ const run = async (function_, resolve, arguments_) => {
226
+ const result = (async () => function_(...arguments_))();
227
+ resolve(result);
228
+ try {
229
+ await result;
230
+ } catch {}
231
+ next();
232
+ };
233
+ const enqueue = (function_, resolve, reject, arguments_) => {
234
+ const queueItem = { reject };
235
+ new Promise((internalResolve) => {
236
+ queueItem.run = internalResolve;
237
+ queue.enqueue(queueItem);
238
+ }).then(run.bind(void 0, function_, resolve, arguments_));
239
+ if (activeCount < concurrency) resumeNext();
240
+ };
241
+ const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
242
+ enqueue(function_, resolve, reject, arguments_);
243
+ });
244
+ Object.defineProperties(generator, {
245
+ activeCount: { get: () => activeCount },
246
+ pendingCount: { get: () => queue.size },
247
+ clearQueue: { value() {
248
+ if (!rejectOnClear) {
249
+ queue.clear();
250
+ return;
251
+ }
252
+ const abortError = AbortSignal.abort().reason;
253
+ while (queue.size > 0) queue.dequeue().reject(abortError);
254
+ } },
255
+ concurrency: {
256
+ get: () => concurrency,
257
+ set(newConcurrency) {
258
+ validateConcurrency(newConcurrency);
259
+ concurrency = newConcurrency;
260
+ queueMicrotask(() => {
261
+ while (activeCount < concurrency && queue.size > 0) resumeNext();
262
+ });
263
+ }
264
+ },
265
+ map: { async value(iterable, function_) {
266
+ const promises = Array.from(iterable, (value, index) => this(function_, value, index));
267
+ return Promise.all(promises);
268
+ } }
269
+ });
270
+ return generator;
271
+ }
272
+ function validateConcurrency(concurrency) {
273
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
274
+ }
275
+ //#endregion
276
+ //#region src/rpc/validation.ts
277
+ /**
278
+ * Validates RPC function definitions.
279
+ * Action and event functions cannot have dumps (side effects should not be cached).
280
+ *
281
+ * @throws {Error} If an action or event function has a dump configuration
282
+ */
283
+ function validateDefinitions(definitions) {
284
+ for (const definition of definitions) {
285
+ const type = definition.type || "query";
286
+ if ((type === "action" || type === "event") && definition.dump) throw logger.DTK0007({
287
+ name: definition.name,
288
+ type
289
+ }).throw();
290
+ if (definition.snapshot && type !== "query") throw logger.DTK0008({
291
+ name: definition.name,
292
+ type
293
+ }).throw();
294
+ }
295
+ }
296
+ /**
297
+ * Validates a single RPC function definition.
298
+ *
299
+ * @throws {Error} If an action or event function has a dump configuration
300
+ */
301
+ function validateDefinition(definition) {
302
+ validateDefinitions([definition]);
303
+ }
304
+ //#endregion
305
+ //#region src/rpc/dumps.ts
306
+ function getDumpRecordKey(functionName, args) {
307
+ return `${functionName}---${hash(args)}`;
308
+ }
309
+ function getDumpFallbackKey(functionName) {
310
+ return `${functionName}---fallback`;
311
+ }
312
+ async function resolveGetter(valueOrGetter) {
313
+ return typeof valueOrGetter === "function" ? await valueOrGetter() : valueOrGetter;
314
+ }
315
+ /**
316
+ * Collects pre-computed dumps by executing functions with their defined input combinations.
317
+ * Static functions without dump config automatically get `{ inputs: [[]] }`.
318
+ *
319
+ * @example
320
+ * ```ts
321
+ * const store = await dumpFunctions([greet], context, { concurrency: 10 })
322
+ * ```
323
+ */
324
+ async function dumpFunctions(definitions, context, options = {}) {
325
+ validateDefinitions(definitions);
326
+ const concurrency = options.concurrency === true ? 5 : options.concurrency === false || options.concurrency == null ? 1 : options.concurrency;
327
+ const store = {
328
+ definitions: {},
329
+ records: {}
330
+ };
331
+ const tasksResolutions = definitions.map((definition) => async () => {
332
+ if (definition.type === "event" || definition.type === "action") return;
333
+ const setupResult = definition.setup ? await Promise.resolve(definition.setup(context)) : {};
334
+ const handler = setupResult.handler || definition.handler;
335
+ if (!handler) throw logger.DTK0004({ name: definition.name }).throw();
336
+ let dump = setupResult.dump ?? definition.dump;
337
+ if (!dump && definition.type === "static") dump = { inputs: [[]] };
338
+ if (!dump && definition.snapshot) dump = async (_ctx, h) => {
339
+ const output = await Promise.resolve(h(...[]));
340
+ return {
341
+ records: [{
342
+ inputs: [],
343
+ output
344
+ }],
345
+ fallback: output
346
+ };
347
+ };
348
+ if (!dump) return;
349
+ if (typeof dump === "function") dump = await Promise.resolve(dump(context, handler));
350
+ store.definitions[definition.name] = {
351
+ name: definition.name,
352
+ type: definition.type
353
+ };
354
+ return {
355
+ handler,
356
+ dump,
357
+ definition
358
+ };
359
+ });
360
+ let functionsToDump = [];
361
+ if (concurrency <= 1) for (const task of tasksResolutions) {
362
+ const resolution = await task();
363
+ if (resolution) functionsToDump.push(resolution);
364
+ }
365
+ else {
366
+ const limit = pLimit(concurrency);
367
+ functionsToDump = (await Promise.all(tasksResolutions.map((task) => limit(task)))).filter((x) => !!x);
368
+ }
369
+ const dumpTasks = [];
370
+ for (const { definition, handler, dump } of functionsToDump) {
371
+ const { inputs, records, fallback } = dump;
372
+ if (records) for (const record of records) {
373
+ const recordKey = getDumpRecordKey(definition.name, record.inputs);
374
+ store.records[recordKey] = record;
375
+ }
376
+ if ("fallback" in dump) {
377
+ const fallbackKey = getDumpFallbackKey(definition.name);
378
+ store.records[fallbackKey] = {
379
+ inputs: [],
380
+ output: fallback
381
+ };
382
+ }
383
+ if (inputs) for (const input of inputs) dumpTasks.push(async () => {
384
+ const recordKey = getDumpRecordKey(definition.name, input);
385
+ try {
386
+ const output = await Promise.resolve(handler(...input));
387
+ store.records[recordKey] = {
388
+ inputs: input,
389
+ output
390
+ };
391
+ } catch (error) {
392
+ store.records[recordKey] = {
393
+ inputs: input,
394
+ error: {
395
+ message: error.message,
396
+ name: error.name
397
+ }
398
+ };
399
+ }
400
+ });
401
+ }
402
+ if (concurrency <= 1) for (const task of dumpTasks) await task();
403
+ else {
404
+ const limit = pLimit(concurrency);
405
+ await Promise.all(dumpTasks.map((task) => limit(task)));
406
+ }
407
+ return store;
408
+ }
409
+ /**
410
+ * Creates a client that serves pre-computed results from a dump store.
411
+ * Uses argument hashing to match calls to stored records.
412
+ *
413
+ * @example
414
+ * ```ts
415
+ * const client = createClientFromDump(store)
416
+ * await client.greet('Alice')
417
+ * ```
418
+ */
419
+ function createClientFromDump(store, options = {}) {
420
+ const { onMiss } = options;
421
+ return new Proxy({}, {
422
+ get(_, functionName) {
423
+ if (!(functionName in store.definitions)) throw logger.DTK0005({ name: functionName }).throw();
424
+ return async (...args) => {
425
+ const recordKey = getDumpRecordKey(functionName, args);
426
+ const recordOrGetter = store.records[recordKey];
427
+ if (recordOrGetter) {
428
+ const record = await resolveGetter(recordOrGetter);
429
+ if (record.error) {
430
+ const error = new Error(record.error.message);
431
+ error.name = record.error.name;
432
+ throw error;
433
+ }
434
+ if (typeof record.output === "function") return await record.output();
435
+ return record.output;
436
+ }
437
+ onMiss?.(functionName, args);
438
+ const fallbackKey = getDumpFallbackKey(functionName);
439
+ if (fallbackKey in store.records) {
440
+ const fallbackOrGetter = store.records[fallbackKey];
441
+ const fallbackRecord = await resolveGetter(fallbackOrGetter);
442
+ if (fallbackRecord && typeof fallbackRecord.output === "function") return await fallbackRecord.output();
443
+ if (fallbackRecord) return fallbackRecord.output;
444
+ }
445
+ throw logger.DTK0006({
446
+ name: functionName,
447
+ args: JSON.stringify(args)
448
+ }).throw();
449
+ };
450
+ },
451
+ has(_, functionName) {
452
+ return functionName in store.definitions;
453
+ },
454
+ ownKeys() {
455
+ return Object.keys(store.definitions);
456
+ },
457
+ getOwnPropertyDescriptor(_, functionName) {
458
+ return functionName in store.definitions ? {
459
+ configurable: true,
460
+ enumerable: true,
461
+ value: void 0
462
+ } : void 0;
463
+ }
464
+ });
465
+ }
466
+ /**
467
+ * Filters function definitions to only those with dump definitions.
468
+ * Note: Only checks the definition itself, not setup results.
469
+ */
470
+ function getDefinitionsWithDumps(definitions) {
471
+ return definitions.filter((def) => def.dump !== void 0);
472
+ }
473
+ //#endregion
474
+ export { validateDefinitions as a, getRpcResolvedSetupResult as c, validateDefinition as i, RpcCacheManager as l, dumpFunctions as n, RpcFunctionsCollectorBase as o, getDefinitionsWithDumps as r, getRpcHandler as s, createClientFromDump as t };
@@ -0,0 +1,49 @@
1
+ import { createRpcServer } from "./rpc/server.mjs";
2
+ import { attachWsRpcTransport } from "./rpc/transports/ws-server.mjs";
3
+ import { WebSocketServer } from "ws";
4
+ import { AsyncLocalStorage } from "node:async_hooks";
5
+ import { createServer } from "node:http";
6
+ import { createApp, toNodeListener } from "h3";
7
+ //#region src/node/server.ts
8
+ /**
9
+ * Compose an h3 + WebSocket server for a devtool context. The RPC
10
+ * group is bound to `context.rpc.functions`; the WS endpoint lives on
11
+ * the same port as the HTTP server.
12
+ */
13
+ async function startHttpAndWs(options) {
14
+ const { context, port } = options;
15
+ const bindHost = options.host ?? "localhost";
16
+ const app = options.app ?? createApp();
17
+ const httpServer = createServer(toNodeListener(app));
18
+ const wss = new WebSocketServer({ server: httpServer });
19
+ const rpcHost = context.rpc;
20
+ const asyncStorage = new AsyncLocalStorage();
21
+ const rpcGroup = createRpcServer(rpcHost.functions);
22
+ attachWsRpcTransport(rpcGroup, { wss });
23
+ rpcHost._rpcGroup = rpcGroup;
24
+ rpcHost._asyncStorage = asyncStorage;
25
+ rpcHost._authDisabled = options.auth === false;
26
+ await new Promise((resolveListen) => {
27
+ httpServer.listen(port, bindHost, () => resolveListen());
28
+ });
29
+ const origin = `http://${bindHost}:${port}`;
30
+ if (options.onReady) await options.onReady({
31
+ origin,
32
+ port,
33
+ app
34
+ });
35
+ return {
36
+ origin,
37
+ port,
38
+ app,
39
+ wss,
40
+ rpcGroup,
41
+ async close() {
42
+ for (const ws of wss.clients) ws.terminate();
43
+ await new Promise((r) => wss.close(() => r()));
44
+ await new Promise((r) => httpServer.close(() => r()));
45
+ }
46
+ };
47
+ }
48
+ //#endregion
49
+ export { startHttpAndWs as t };
@@ -0,0 +1,85 @@
1
+ import { t as createDefineWrapperWithContext } from "./define-Bb4zh-Dc.mjs";
2
+ import { safeParse } from "valibot";
3
+ //#region src/adapters/flags.ts
4
+ /**
5
+ * Identity helper that preserves the literal schema-map type — use this
6
+ * so `InferCliFlags<typeof myFlags>` resolves to the right object shape.
7
+ *
8
+ * ```ts
9
+ * const appFlags = defineCliFlags({
10
+ * depth: v.pipe(v.number(), v.integer()),
11
+ * config: v.optional(v.string()),
12
+ * })
13
+ *
14
+ * defineDevtool({
15
+ * cli: { flags: appFlags },
16
+ * setup(ctx, info) {
17
+ * const flags = info.flags as InferCliFlags<typeof appFlags>
18
+ * flags.depth // number
19
+ * flags.config // string | undefined
20
+ * },
21
+ * })
22
+ * ```
23
+ */
24
+ function defineCliFlags(flags) {
25
+ return flags;
26
+ }
27
+ /**
28
+ * Best-effort probe of a valibot schema to decide whether the
29
+ * corresponding CAC option takes a value. Unwraps `optional` / `nullable`
30
+ * / `nullish` / `default` / `pipe` wrappers then matches on the inner
31
+ * type's kind.
32
+ */
33
+ function getSchemaKind(schema) {
34
+ let current = schema;
35
+ while (current) {
36
+ const kind = current.type;
37
+ if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") {
38
+ current = current.wrapped ?? current.inner;
39
+ continue;
40
+ }
41
+ if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) {
42
+ current = current.pipe[0];
43
+ continue;
44
+ }
45
+ return kind;
46
+ }
47
+ return "unknown";
48
+ }
49
+ /** Whether the CAC option for this schema should be a boolean flag. */
50
+ function isBooleanFlag(schema) {
51
+ return getSchemaKind(schema) === "boolean";
52
+ }
53
+ /** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */
54
+ function parseCliFlags(schema, raw) {
55
+ const flags = {};
56
+ const issues = [];
57
+ for (const [key, fieldSchema] of Object.entries(schema)) {
58
+ const result = safeParse(fieldSchema, raw[key]);
59
+ if (result.success) flags[key] = result.output;
60
+ else issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`);
61
+ }
62
+ for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value;
63
+ return issues.length ? {
64
+ flags,
65
+ issues
66
+ } : { flags };
67
+ }
68
+ function toKebab(camel) {
69
+ return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
70
+ }
71
+ /** Kebab-case a schema key for CAC option registration. */
72
+ function flagKeyToOption(camel) {
73
+ return toKebab(camel);
74
+ }
75
+ //#endregion
76
+ //#region src/define.ts
77
+ const defineRpcFunction = createDefineWrapperWithContext();
78
+ function defineCommand(command) {
79
+ return command;
80
+ }
81
+ function defineJsonRenderSpec(spec) {
82
+ return spec;
83
+ }
84
+ //#endregion
85
+ export { flagKeyToOption as a, defineCliFlags as i, defineJsonRenderSpec as n, isBooleanFlag as o, defineRpcFunction as r, parseCliFlags as s, defineCommand as t };
@@ -0,0 +1,82 @@
1
+ import { n as dumpFunctions, s as getRpcHandler } from "./rpc-9FNa3Inb.mjs";
2
+ import { DEVTOOLS_RPC_DUMP_DIRNAME } from "./constants.mjs";
3
+ //#region src/node/host-h3.ts
4
+ /**
5
+ * h3-backed {@link DevToolsHost} — used by the standalone CLI adapter.
6
+ * This commit adds the shell; the CLI adapter in commit 5 wires it up
7
+ * with a real h3 app and sirv handler.
8
+ */
9
+ function createH3DevToolsHost(options) {
10
+ return {
11
+ mountStatic(base, distDir) {
12
+ return options.mount?.(base, distDir);
13
+ },
14
+ resolveOrigin() {
15
+ return options.origin;
16
+ }
17
+ };
18
+ }
19
+ //#endregion
20
+ //#region src/node/static-dump.ts
21
+ function makeDumpKey(name) {
22
+ return encodeURIComponent(name.replaceAll(":", "~"));
23
+ }
24
+ function makeStaticPath(name) {
25
+ return `${DEVTOOLS_RPC_DUMP_DIRNAME}/${makeDumpKey(name)}.static.json`;
26
+ }
27
+ function makeQueryRecordPath(name, hash) {
28
+ return `${DEVTOOLS_RPC_DUMP_DIRNAME}/${makeDumpKey(name)}.record.${hash}.json`;
29
+ }
30
+ function makeQueryFallbackPath(name) {
31
+ return `${DEVTOOLS_RPC_DUMP_DIRNAME}/${makeDumpKey(name)}.fallback.json`;
32
+ }
33
+ async function resolveRecord(record) {
34
+ return typeof record === "function" ? await record() : record;
35
+ }
36
+ async function collectStaticRpcDump(definitions, context) {
37
+ const manifest = {};
38
+ const files = {};
39
+ for (const definition of definitions) {
40
+ const type = definition.type ?? "query";
41
+ if (type === "static") {
42
+ const handler = await getRpcHandler(definition, context);
43
+ const path = makeStaticPath(definition.name);
44
+ files[path] = { output: await Promise.resolve(handler()) };
45
+ manifest[definition.name] = {
46
+ type: "static",
47
+ path
48
+ };
49
+ continue;
50
+ }
51
+ if (type !== "query") continue;
52
+ const store = await dumpFunctions([definition], context);
53
+ if (!(definition.name in store.definitions)) continue;
54
+ const queryEntry = {
55
+ type: "query",
56
+ records: {}
57
+ };
58
+ const prefix = `${definition.name}---`;
59
+ for (const [recordKey, recordOrGetter] of Object.entries(store.records)) {
60
+ if (!recordKey.startsWith(prefix)) continue;
61
+ const key = recordKey.slice(prefix.length);
62
+ const record = await resolveRecord(recordOrGetter);
63
+ if (key === "fallback") {
64
+ const path = makeQueryFallbackPath(definition.name);
65
+ files[path] = record;
66
+ queryEntry.fallback = path;
67
+ } else {
68
+ const path = makeQueryRecordPath(definition.name, key);
69
+ files[path] = record;
70
+ queryEntry.records[key] = path;
71
+ }
72
+ }
73
+ if (!Object.keys(queryEntry.records).length && !queryEntry.fallback) continue;
74
+ manifest[definition.name] = queryEntry;
75
+ }
76
+ return {
77
+ manifest,
78
+ files
79
+ };
80
+ }
81
+ //#endregion
82
+ export { createH3DevToolsHost as n, collectStaticRpcDump as t };
@@ -0,0 +1,15 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ //#region src/node/mcp/transports.ts
3
+ /**
4
+ * Start the MCP server on stdio. Returns a stop function.
5
+ * @internal
6
+ */
7
+ async function startStdioTransport(server) {
8
+ const transport = new StdioServerTransport();
9
+ await server.connect(transport);
10
+ return async () => {
11
+ await server.close();
12
+ };
13
+ }
14
+ //#endregion
15
+ export { startStdioTransport };