devframe 0.8.2 → 0.9.0-beta.10

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 (127) hide show
  1. package/dist/_shared-BPmX9fqK.d.mts +41 -0
  2. package/dist/_shared-CbZ_yhbz.mjs +68 -0
  3. package/dist/adapters/build.d.mts +10 -12
  4. package/dist/adapters/build.mjs +26 -29
  5. package/dist/adapters/cac.d.mts +1 -1
  6. package/dist/adapters/cac.mjs +156 -1
  7. package/dist/adapters/dev.d.mts +38 -46
  8. package/dist/adapters/dev.mjs +2 -1
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +224 -0
  11. package/dist/adapters/initiate.mjs +2 -0
  12. package/dist/adapters/mcp.d.mts +24 -7
  13. package/dist/adapters/mcp.mjs +2 -2
  14. package/dist/{agent-tool-name-C3b5vEwJ.mjs → agent-tool-name-EgfoFO8C.mjs} +0 -3
  15. package/dist/cli/main.d.mts +0 -2
  16. package/dist/cli/main.mjs +4 -8
  17. package/dist/client/index.d.mts +71 -7
  18. package/dist/client/index.mjs +720 -1540
  19. package/dist/constants.d.mts +28 -7
  20. package/dist/constants.mjs +28 -7
  21. package/dist/{context-DoSozfvx.d.mts → context-B3YUu_95.d.mts} +19 -1
  22. package/dist/{host-h3-D2hYZvDK.mjs → context-CEe4PBz1.mjs} +25 -557
  23. package/dist/{context-CBg8iRbQ.mjs → context-xdynGSLP.mjs} +10 -1
  24. package/dist/dev--rAPzbvO.mjs +239 -0
  25. package/dist/{devframe-mQ4qZAuo.d.mts → devframe-DJMg0WLe.d.mts} +181 -134
  26. package/dist/{diagnostics-hwjXp_UV.mjs → diagnostics-CD8nlgll.mjs} +1 -3
  27. package/dist/{diagnostics-D7wM2cwM.mjs → diagnostics-DOQPnQmX.mjs} +51 -5
  28. package/dist/dist-eNI9qM_I.mjs +228 -0
  29. package/dist/host-agent-xLCSe65D.mjs +264 -0
  30. package/dist/host-h3-Crkzm42q.mjs +26 -0
  31. package/dist/{fetch-BKaD0Vb3.mjs → http-DYpK0cUi.mjs} +42 -11
  32. package/dist/{index-b64Uuhy2.d.mts → index-CB-fSUyn.d.mts} +2 -2
  33. package/dist/{index-Dbw1p5ch.d.mts → index-tdrk1bzV.d.mts} +3 -32
  34. package/dist/index.d.mts +12 -5
  35. package/dist/index.mjs +8 -1
  36. package/dist/{instance-registry-BnnA2Eoh.mjs → instance-registry-WvQkt42E.mjs} +9 -8
  37. package/dist/instance-shell-CMFyszWJ.mjs +486 -0
  38. package/dist/instance-shell-CljiKq1c.d.mts +255 -0
  39. package/dist/internal/index.d.mts +397 -0
  40. package/dist/internal/index.mjs +9 -0
  41. package/dist/node/auth.d.mts +2 -2
  42. package/dist/node/auth.mjs +1 -1
  43. package/dist/node/hub-internals.d.mts +2 -14
  44. package/dist/node/hub-internals.mjs +2 -2
  45. package/dist/node/index.d.mts +4 -268
  46. package/dist/node/index.mjs +3 -5
  47. package/dist/nostics-CzECRXpE.mjs +59 -0
  48. package/dist/nostics-SPGDgHEP.d.mts +33 -0
  49. package/dist/recipes/common-rpc-functions.d.mts +4 -4
  50. package/dist/recipes/interactive-auth.d.mts +3 -3
  51. package/dist/recipes/interactive-auth.mjs +8 -8
  52. package/dist/remote-assets-Bg4gCUZ_.d.mts +123 -0
  53. package/dist/remote-assets-nTTxY2MU.mjs +636 -0
  54. package/dist/rolldown-runtime-JspESFgx.mjs +35 -0
  55. package/dist/rpc/dump.d.mts +77 -1
  56. package/dist/rpc/dump.mjs +1 -1
  57. package/dist/rpc/index.d.mts +3 -3
  58. package/dist/rpc/index.mjs +4 -18
  59. package/dist/rpc/transports/sse-client.d.mts +2 -0
  60. package/dist/rpc/transports/sse-client.mjs +142 -0
  61. package/dist/rpc/transports/sse-server.d.mts +61 -0
  62. package/dist/rpc/transports/sse-server.mjs +209 -0
  63. package/dist/rpc/transports/ws-bun.d.mts +35 -0
  64. package/dist/rpc/transports/ws-bun.mjs +31 -0
  65. package/dist/rpc/transports/ws-client.d.mts +1 -1
  66. package/dist/rpc/transports/ws-client.mjs +10 -18
  67. package/dist/rpc/transports/ws-server.d.mts +2 -2
  68. package/dist/rpc/transports/ws-server.mjs +2 -235
  69. package/dist/rpc-core-Cc4lucI0.d.mts +48 -0
  70. package/dist/rpc-core-DMTe-hLo.mjs +81 -0
  71. package/dist/{serialization-C8Mnw9hK.mjs → serialization-BGzEwAdr.mjs} +2 -2
  72. package/dist/{shared-state-6kHolYZy.mjs → shared-state-fRRbRUtD.mjs} +1 -1
  73. package/dist/sse-client-CFBOIaUi.d.mts +37 -0
  74. package/dist/state-Cc1IeSmQ.mjs +1291 -0
  75. package/dist/{dump-CgZShDRB.mjs → static-BPZ1_OPA.mjs} +3 -266
  76. package/dist/storage-CYye7P7L.mjs +137 -0
  77. package/dist/types/index.d.mts +6 -4
  78. package/dist/types/index.mjs +1 -6
  79. package/dist/{types-CnJSgRVa.d.mts → types-Djq7CBXh.d.mts} +0 -7
  80. package/dist/utils/agent-tool-name.d.mts +0 -3
  81. package/dist/utils/agent-tool-name.mjs +0 -3
  82. package/dist/utils/events.d.mts +1 -1
  83. package/dist/utils/get-port.d.mts +17 -0
  84. package/dist/utils/get-port.mjs +2 -0
  85. package/dist/utils/launch-editor.mjs +1 -25
  86. package/dist/utils/nostics.d.mts +2 -0
  87. package/dist/utils/nostics.mjs +2 -0
  88. package/dist/utils/open.d.mts +2 -10
  89. package/dist/utils/open.mjs +56 -1
  90. package/dist/utils/remote-assets.d.mts +15 -0
  91. package/dist/utils/remote-assets.mjs +2 -0
  92. package/dist/utils/serve-static.d.mts +13 -5
  93. package/dist/utils/serve-static.mjs +119 -9
  94. package/dist/utils/shared-state.d.mts +1 -1
  95. package/dist/utils/shared-state.mjs +1 -1
  96. package/dist/utils/simple-schema.d.mts +101 -1
  97. package/dist/utils/streaming-channel.d.mts +1 -1
  98. package/dist/validation-CpXFB6Dz.mjs +266 -0
  99. package/dist/wire-codec-0K-o5MYW.mjs +56 -0
  100. package/dist/{ws-client-B6Tnr0ic.d.mts → ws-client-DhjNyQo3.d.mts} +7 -2
  101. package/dist/ws-server-BdSLrhxE.mjs +267 -0
  102. package/dist/{ws-server-uKQcClcJ.d.mts → ws-server-D1d3QM9f.d.mts} +90 -9
  103. package/package.json +13 -12
  104. package/skills/devframe/SKILL.md +91 -93
  105. package/dist/_shared-bWRzeSa0.mjs +0 -19
  106. package/dist/adapters/cli.d.mts +0 -11
  107. package/dist/adapters/cli.mjs +0 -6
  108. package/dist/cac-D4_9ok0z.mjs +0 -157
  109. package/dist/dev-Bc49u3qg.mjs +0 -439
  110. package/dist/diagnostics-reporter-CsIG85Q5.mjs +0 -38
  111. package/dist/helpers/vite.d.mts +0 -100
  112. package/dist/helpers/vite.mjs +0 -105
  113. package/dist/http-C4T68YV6.mjs +0 -38
  114. package/dist/index-vAX6bYuc.d.mts +0 -78
  115. package/dist/open-Deb5xmIT.mjs +0 -547
  116. package/dist/recipes/open-helpers.d.mts +0 -6
  117. package/dist/recipes/open-helpers.mjs +0 -6
  118. package/dist/server-CD8XmBXl.mjs +0 -167
  119. package/dist/server-UHWae43Q.d.mts +0 -149
  120. package/dist/simple-schema-BDzLeJDk.d.mts +0 -102
  121. package/dist/state-BeUHDDjk.mjs +0 -108
  122. package/dist/storage-CTNVbuFB.mjs +0 -1122
  123. package/dist/utils/promise.d.mts +0 -8
  124. package/dist/utils/promise.mjs +0 -15
  125. package/dist/utils/scope.d.mts +0 -11
  126. package/dist/utils/scope.mjs +0 -15
  127. package/skills/devframe/templates/spa-devframe.ts +0 -38
@@ -0,0 +1,15 @@
1
+ import { a as RemoteAssetsStore, o as StaticAssetsSource } from "../remote-assets-Bg4gCUZ_.mjs";
2
+ //#region src/utils/remote-assets.d.ts
3
+ /**
4
+ * Normalize a {@link StaticAssetsSource} into something servable: a local
5
+ * directory (strings pass through; a remote source short-circuits to a
6
+ * locally installed copy of its package when present) or a caching
7
+ * {@link RemoteAssetsStore} back-proxy. Remote caches live under
8
+ * `<projectStorageDir>/.remote-assets/<package>@<version>/`.
9
+ *
10
+ * A remote source's `package`/`version` are validated first (`DF0065`) — both
11
+ * are interpolated into CDN URLs and the cache path.
12
+ */
13
+ declare function resolveStaticAssetsSource(source: StaticAssetsSource, projectStorageDir: string): string | RemoteAssetsStore;
14
+ //#endregion
15
+ export { resolveStaticAssetsSource };
@@ -0,0 +1,2 @@
1
+ import { t as resolveStaticAssetsSource } from "../remote-assets-nTTxY2MU.mjs";
2
+ export { resolveStaticAssetsSource };
@@ -1,6 +1,12 @@
1
+ import { a as RemoteAssetsStore } from "../remote-assets-Bg4gCUZ_.mjs";
1
2
  import { IncomingMessage, ServerResponse } from "node:http";
2
3
  import { EventHandler, H3 } from "h3";
3
4
  //#region src/utils/serve-static.d.ts
5
+ /**
6
+ * What the static-serving engine accepts: a local directory, or a resolved
7
+ * {@link RemoteAssetsStore} back-proxy (from `devframe/utils/remote-assets`).
8
+ */
9
+ type ServableAssets = string | RemoteAssetsStore;
4
10
  interface ServeStaticOptions {
5
11
  /** Default: `['index.html']`. */
6
12
  indexNames?: string[];
@@ -8,7 +14,9 @@ interface ServeStaticOptions {
8
14
  single?: boolean;
9
15
  }
10
16
  /**
11
- * h3 event handler that serves files from `dir` with SPA fallback.
17
+ * h3 event handler that serves files from `source` with SPA fallback — a
18
+ * local directory, or a {@link RemoteAssetsStore} whose files stream through
19
+ * the CDN back-proxy into the local cache.
12
20
  *
13
21
  * Drop-in replacement for `fromNodeMiddleware(sirv(dir, { dev: true, single: true }))`
14
22
  * when the surrounding server is an h3 app — no `Cache-Control` beyond
@@ -16,7 +24,7 @@ interface ServeStaticOptions {
16
24
  * file extension falls back to `<dir>/index.html` so client-side routing
17
25
  * works.
18
26
  */
19
- declare function serveStaticHandler(dir: string, options?: ServeStaticOptions): EventHandler;
27
+ declare function serveStaticHandler(source: ServableAssets, options?: ServeStaticOptions): EventHandler;
20
28
  /**
21
29
  * Mount {@link serveStaticHandler} on an h3 app at `base`.
22
30
  *
@@ -24,7 +32,7 @@ declare function serveStaticHandler(dir: string, options?: ServeStaticOptions):
24
32
  * from `event.url.pathname`, so the file resolver sees paths relative to
25
33
  * `dir`.
26
34
  */
27
- declare function mountStaticHandler(app: H3, base: string, dir: string, options?: ServeStaticOptions): void;
35
+ declare function mountStaticHandler(app: H3, base: string, source: ServableAssets, options?: ServeStaticOptions): void;
28
36
  /**
29
37
  * Connect/Express-style Node middleware variant of {@link serveStaticHandler}.
30
38
  *
@@ -32,6 +40,6 @@ declare function mountStaticHandler(app: H3, base: string, dir: string, options?
32
40
  * Connect stack — avoids forcing the host package to depend on h3 just to
33
41
  * adapt an event handler back into Node middleware.
34
42
  */
35
- declare function serveStaticNodeMiddleware(dir: string, options?: ServeStaticOptions): (req: IncomingMessage, res: ServerResponse, next?: (err?: Error) => void) => void;
43
+ declare function serveStaticNodeMiddleware(source: ServableAssets, options?: ServeStaticOptions): (req: IncomingMessage, res: ServerResponse, next?: (err?: Error) => void) => void;
36
44
  //#endregion
37
- export { ServeStaticOptions, mountStaticHandler, serveStaticHandler, serveStaticNodeMiddleware };
45
+ export { ServableAssets, ServeStaticOptions, mountStaticHandler, serveStaticHandler, serveStaticNodeMiddleware };
@@ -1,9 +1,10 @@
1
+ import { DEVFRAME_REMOTE_ASSETS_ERROR_MESSAGE_TYPE } from "../constants.mjs";
1
2
  import { createReadStream } from "node:fs";
2
- import { extname, join, normalize, resolve, sep } from "pathe";
3
- import { H3, defineHandler } from "h3";
4
3
  import { stat } from "node:fs/promises";
5
4
  import { Readable } from "node:stream";
6
5
  import { lookup } from "mrmime";
6
+ import { extname, join, normalize, resolve, sep } from "pathe";
7
+ import { H3, defineHandler } from "h3";
7
8
  //#region src/utils/serve-static.ts
8
9
  const HTML_EXTENSIONS = [".html", ".htm"];
9
10
  async function statFile(abs) {
@@ -74,7 +75,43 @@ function normalizeOptions(options) {
74
75
  };
75
76
  }
76
77
  /**
77
- * h3 event handler that serves files from `dir` with SPA fallback.
78
+ * Drive one request through a {@link RemoteAssetsStore}: the store's
79
+ * `Response` on a hit, a 404 on a miss, or a 502 (styled error page for HTML
80
+ * navigations) on provider failure — shared between the h3 and connect flavors.
81
+ */
82
+ async function remoteResponse(store, urlPath, accept) {
83
+ try {
84
+ return await store.serve(urlPath) ?? new Response(null, { status: 404 });
85
+ } catch (error) {
86
+ if (typeof accept === "string" && accept.includes("text/html")) return new Response(remoteErrorPage(store.assets.package, store.assets.version, error instanceof Error ? error.message : String(error)), {
87
+ status: 502,
88
+ headers: { "Content-Type": "text/html; charset=utf-8" }
89
+ });
90
+ return new Response(null, { status: 502 });
91
+ }
92
+ }
93
+ function serveRemoteAssetsHandler(store) {
94
+ return defineHandler(async (event) => {
95
+ const method = event.req.method;
96
+ if (method !== "GET" && method !== "HEAD") {
97
+ event.res.status = 405;
98
+ event.res.headers.set("Allow", "GET, HEAD");
99
+ return "";
100
+ }
101
+ const res = await remoteResponse(store, event.url.pathname, event.req.headers.get("accept"));
102
+ event.res.status = res.status;
103
+ res.headers.forEach((v, k) => event.res.headers.set(k, v));
104
+ if (method === "HEAD") {
105
+ await res.body?.cancel().catch(() => {});
106
+ return "";
107
+ }
108
+ return res.body ?? "";
109
+ });
110
+ }
111
+ /**
112
+ * h3 event handler that serves files from `source` with SPA fallback — a
113
+ * local directory, or a {@link RemoteAssetsStore} whose files stream through
114
+ * the CDN back-proxy into the local cache.
78
115
  *
79
116
  * Drop-in replacement for `fromNodeMiddleware(sirv(dir, { dev: true, single: true }))`
80
117
  * when the surrounding server is an h3 app — no `Cache-Control` beyond
@@ -82,8 +119,9 @@ function normalizeOptions(options) {
82
119
  * file extension falls back to `<dir>/index.html` so client-side routing
83
120
  * works.
84
121
  */
85
- function serveStaticHandler(dir, options) {
86
- const absDir = resolve(dir);
122
+ function serveStaticHandler(source, options) {
123
+ if (typeof source !== "string") return serveRemoteAssetsHandler(source);
124
+ const absDir = resolve(source);
87
125
  const opts = normalizeOptions(options);
88
126
  return defineHandler(async (event) => {
89
127
  const method = event.req.method;
@@ -109,9 +147,9 @@ function serveStaticHandler(dir, options) {
109
147
  * from `event.url.pathname`, so the file resolver sees paths relative to
110
148
  * `dir`.
111
149
  */
112
- function mountStaticHandler(app, base, dir, options) {
150
+ function mountStaticHandler(app, base, source, options) {
113
151
  const staticApp = new H3();
114
- staticApp.use(serveStaticHandler(dir, options));
152
+ staticApp.use(serveStaticHandler(source, options));
115
153
  app.mount(base.replace(/\/$/, ""), staticApp);
116
154
  }
117
155
  /**
@@ -121,8 +159,8 @@ function mountStaticHandler(app, base, dir, options) {
121
159
  * Connect stack — avoids forcing the host package to depend on h3 just to
122
160
  * adapt an event handler back into Node middleware.
123
161
  */
124
- function serveStaticNodeMiddleware(dir, options) {
125
- const absDir = resolve(dir);
162
+ function serveStaticNodeMiddleware(source, options) {
163
+ const absDir = typeof source === "string" ? resolve(source) : void 0;
126
164
  const opts = normalizeOptions(options);
127
165
  return (req, res, next) => {
128
166
  (async () => {
@@ -138,6 +176,22 @@ function serveStaticNodeMiddleware(dir, options) {
138
176
  return;
139
177
  }
140
178
  const url = req.url ?? "/";
179
+ if (absDir === void 0) {
180
+ const response = await remoteResponse(source, url, req.headers.accept);
181
+ if (response.status === 404 && next) {
182
+ next();
183
+ return;
184
+ }
185
+ res.statusCode = response.status;
186
+ response.headers.forEach((v, k) => res.setHeader(k, v));
187
+ if (method === "HEAD" || !response.body) {
188
+ await response.body?.cancel().catch(() => {});
189
+ res.end();
190
+ return;
191
+ }
192
+ Readable.fromWeb(response.body).pipe(res);
193
+ return;
194
+ }
141
195
  const file = await resolveTarget(absDir, url, opts.indexNames, opts.single);
142
196
  if (!file) {
143
197
  if (next) {
@@ -164,5 +218,61 @@ function serveStaticNodeMiddleware(dir, options) {
164
218
  });
165
219
  };
166
220
  }
221
+ /**
222
+ * Minimal, dependency-free HTML shown when a remote-assets request cannot
223
+ * be satisfied (no installed package, no cache, provider unreachable).
224
+ *
225
+ * The page stands on its own when a devframe is opened directly, and
226
+ * announces itself over `postMessage` when it loads inside a viewer's iframe
227
+ * ({@link DEVFRAME_REMOTE_ASSETS_ERROR_MESSAGE_TYPE}) so the viewer can show
228
+ * the same failure in its own UI instead.
229
+ */
230
+ function remoteErrorPage(pkg, version, reason) {
231
+ const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
232
+ const name = esc(pkg);
233
+ const ver = esc(version);
234
+ const payload = JSON.stringify({
235
+ type: DEVFRAME_REMOTE_ASSETS_ERROR_MESSAGE_TYPE,
236
+ package: pkg,
237
+ version,
238
+ reason
239
+ }).replace(/</g, "\\u003c");
240
+ return `<!doctype html>
241
+ <html lang="en">
242
+ <head>
243
+ <meta charset="utf-8">
244
+ <meta name="viewport" content="width=device-width, initial-scale=1">
245
+ <title>Client assets unavailable</title>
246
+ <style>
247
+ :root { color-scheme: light dark; }
248
+ body { margin: 0; min-height: 100vh; display: grid; place-items: center; font: 14px/1.6 ui-sans-serif, system-ui, sans-serif; background: #fafafa; color: #27272a; }
249
+ main { max-width: 32rem; padding: 2rem; }
250
+ h1 { font-size: 1rem; font-weight: 600; margin: 0 0 .5rem; }
251
+ p { margin: .5rem 0; opacity: .8; }
252
+ pre { font: 12px/1.6 ui-monospace, monospace; background: rgb(125 125 125 / .12); border-radius: 6px; padding: .75rem 1rem; overflow-x: auto; }
253
+ button { font: inherit; padding: .35rem 1rem; border-radius: 6px; border: 1px solid rgb(125 125 125 / .3); background: transparent; color: inherit; cursor: pointer; }
254
+ button:hover { background: rgb(125 125 125 / .08); }
255
+ .muted { opacity: .55; font-size: 12px; }
256
+ @media (prefers-color-scheme: dark) { body { background: #111; color: #d4d4d8; } }
257
+ </style>
258
+ </head>
259
+ <body>
260
+ <main>
261
+ <h1>Client assets unavailable</h1>
262
+ <p>The UI for this tool is served from <code>${name}@${ver}</code>, which could not be reached.</p>
263
+ <pre>${esc(reason)}</pre>
264
+ <p>To use it without network access, install the assets package locally:</p>
265
+ <pre>npm install ${name}@${ver}</pre>
266
+ <button onclick="location.reload()">Retry</button>
267
+ <p class="muted">devframe remote assets</p>
268
+ </main>
269
+ <script>
270
+ if (window.parent !== window)
271
+ window.parent.postMessage(${payload}, '*')
272
+ <\/script>
273
+ </body>
274
+ </html>
275
+ `;
276
+ }
167
277
  //#endregion
168
278
  export { mountStaticHandler, serveStaticHandler, serveStaticNodeMiddleware };
@@ -1,2 +1,2 @@
1
- import { _t as SharedStateOptions, dt as ImmutableArray, ft as ImmutableMap, gt as SharedStateEvents, ht as SharedState, mt as ImmutableSet, pt as ImmutableObject, ut as Immutable, vt as SharedStatePatch, yt as createSharedState } from "../devframe-mQ4qZAuo.mjs";
1
+ import { at as ImmutableArray, ct as ImmutableSet, dt as SharedStateOptions, ft as SharedStatePatch, it as Immutable, lt as SharedState, ot as ImmutableMap, pt as createSharedState, st as ImmutableObject, ut as SharedStateEvents } from "../devframe-DJMg0WLe.mjs";
2
2
  export { Immutable, ImmutableArray, ImmutableMap, ImmutableObject, ImmutableSet, SharedState, SharedStateEvents, SharedStateOptions, SharedStatePatch, createSharedState };
@@ -1,2 +1,2 @@
1
- import { t as createSharedState } from "../shared-state-6kHolYZy.mjs";
1
+ import { t as createSharedState } from "../shared-state-fRRbRUtD.mjs";
2
2
  export { createSharedState };
@@ -1,2 +1,102 @@
1
- import { a as literal, c as number, d as picklist, f as record, g as voidType, h as union, i as describe, l as object, m as string, n as array, o as nullType, p as s, r as boolean, s as nullable, t as SimpleSchema, u as optional } from "../simple-schema-BDzLeJDk.mjs";
1
+ import { StandardSchemaV1 } from "@standard-schema/spec";
2
+ //#region src/utils/simple-schema.d.ts
3
+ /**
4
+ * A tiny, zero-dependency [Standard Schema](https://standardschema.dev/)
5
+ * builder.
6
+ *
7
+ * ⚠️ **Discouraged for app code.** This is a deliberately minimal,
8
+ * best-effort validator that exists only so devframe's own first-party
9
+ * packages (recipes, built-in plugins) can declare `args`/`returns`/flag
10
+ * schemas without taking on a validator dependency. It implements a small
11
+ * subset of primitives and approximates refinements — it is not a
12
+ * general-purpose validator.
13
+ *
14
+ * For your own code, prefer a real Standard Schema validator — **valibot**,
15
+ * **zod**, or **arktype**. Devframe's RPC and CLI-flag layers accept any of
16
+ * them; install the one you like and use it directly:
17
+ *
18
+ * ```ts
19
+ * import * as v from 'valibot' // npm i valibot
20
+ *
21
+ * defineRpcFunction({
22
+ * name: 'greet',
23
+ * args: [v.object({ name: v.string() })],
24
+ * returns: v.string(),
25
+ * handler: ({ name }) => `hi ${name}`,
26
+ * })
27
+ * ```
28
+ */
29
+ /**
30
+ * A Standard Schema produced by the {@link s} builder. It carries a
31
+ * duck-typed `type` marker (and `wrapped` for wrappers) alongside the
32
+ * standard `~standard` prop so the CLI-flags adapter can introspect the
33
+ * schema kind without importing any validator.
34
+ */
35
+ interface SimpleSchema<Input, Output = Input> extends StandardSchemaV1<Input, Output> {
36
+ /** Schema kind marker, e.g. `'string'`, `'boolean'`, `'optional'`. */
37
+ readonly type: string;
38
+ /** Inner schema for wrapper kinds (`optional` / `nullable`). */
39
+ readonly wrapped?: StandardSchemaV1;
40
+ /** Optional human description (surfaced as CLI option help). */
41
+ readonly description?: string;
42
+ }
43
+ /** Any string. */
44
+ declare function string(): SimpleSchema<string>;
45
+ /** A finite number (rejects `NaN`). */
46
+ declare function number(): SimpleSchema<number>;
47
+ /** A boolean. */
48
+ declare function boolean(): SimpleSchema<boolean>;
49
+ /** `undefined` — mirrors valibot's `void`. */
50
+ declare function voidType(): SimpleSchema<void>;
51
+ /** `null`. */
52
+ declare function nullType(): SimpleSchema<null>;
53
+ /** One of a fixed set of literal values. */
54
+ declare function picklist<const T extends readonly (string | number | boolean)[]>(values: T): SimpleSchema<T[number]>;
55
+ /** A single literal value (string / number / boolean). */
56
+ declare function literal<const T extends string | number | boolean>(value: T): SimpleSchema<T>;
57
+ /** A value matching any one of the given schemas. */
58
+ declare function union<const T extends readonly StandardSchemaV1[]>(options: T): SimpleSchema<StandardSchemaV1.InferInput<T[number]>, StandardSchemaV1.InferOutput<T[number]>>;
59
+ /** A record with string keys whose values each satisfy the value schema. */
60
+ declare function record<V extends StandardSchemaV1>(_key: StandardSchemaV1, value: V): SimpleSchema<Record<string, StandardSchemaV1.InferInput<V>>, Record<string, StandardSchemaV1.InferOutput<V>>>;
61
+ /** An array whose every element satisfies the item schema. */
62
+ declare function array<T extends StandardSchemaV1>(item: T): SimpleSchema<StandardSchemaV1.InferInput<T>[], StandardSchemaV1.InferOutput<T>[]>;
63
+ /** Flatten an intersection into a single object literal for readable types. */
64
+ type Prettify<T> = { [K in keyof T]: T[K]; } & {};
65
+ /**
66
+ * Map a shape to its object type, turning fields whose type includes
67
+ * `undefined` (i.e. `optional()`) into optional keys — mirroring how
68
+ * valibot/zod render `optional` object entries.
69
+ */
70
+ type InferField<T extends StandardSchemaV1, Mode extends 'input' | 'output'> = Mode extends 'input' ? StandardSchemaV1.InferInput<T> : StandardSchemaV1.InferOutput<T>;
71
+ type InferObject<T extends Record<string, StandardSchemaV1>, Mode extends 'input' | 'output'> = Prettify<{ [K in keyof T as undefined extends InferField<T[K], Mode> ? never : K]: InferField<T[K], Mode>; } & { [K in keyof T as undefined extends InferField<T[K], Mode> ? K : never]?: InferField<T[K], Mode>; }>;
72
+ /** An object whose known keys each satisfy their schema (extra keys are kept). */
73
+ declare function object<T extends Record<string, StandardSchemaV1>>(shape: T): SimpleSchema<InferObject<T, 'input'>, InferObject<T, 'output'>>;
74
+ /** Allow `undefined` in addition to the inner schema. */
75
+ declare function optional<T extends StandardSchemaV1>(inner: T): SimpleSchema<StandardSchemaV1.InferInput<T> | undefined, StandardSchemaV1.InferOutput<T> | undefined>;
76
+ /** Allow `null` in addition to the inner schema. */
77
+ declare function nullable<T extends StandardSchemaV1>(inner: T): SimpleSchema<StandardSchemaV1.InferInput<T> | null, StandardSchemaV1.InferOutput<T> | null>;
78
+ /** Attach a human-readable description (used for CLI option help). */
79
+ declare function describe<T extends SimpleSchema<any, any>>(schema: T, description: string): T;
80
+ /**
81
+ * Grouped access to every builder — `s.string()`, `s.object({ ... })`,
82
+ * `s.void()`, etc. Handy for a valibot-like `import { s } from
83
+ * 'devframe/utils/simple-schema'` call site.
84
+ */
85
+ declare const s: {
86
+ readonly string: typeof string;
87
+ readonly number: typeof number;
88
+ readonly boolean: typeof boolean;
89
+ readonly void: typeof voidType;
90
+ readonly null: typeof nullType;
91
+ readonly literal: typeof literal;
92
+ readonly picklist: typeof picklist;
93
+ readonly union: typeof union;
94
+ readonly record: typeof record;
95
+ readonly array: typeof array;
96
+ readonly object: typeof object;
97
+ readonly optional: typeof optional;
98
+ readonly nullable: typeof nullable;
99
+ readonly describe: typeof describe;
100
+ };
101
+ //#endregion
2
102
  export { SimpleSchema, array, boolean, describe, literal, nullType, nullable, number, object, optional, picklist, record, s, string, union, voidType };
@@ -1,2 +1,2 @@
1
- import { at as StreamReader, ct as createStreamReader, it as StreamErrorPayload, lt as createStreamSink, nt as CreateStreamReaderOptions, ot as StreamSink, rt as CreateStreamSinkOptions, st as StreamSinkEvents, tt as BufferedChunk } from "../devframe-mQ4qZAuo.mjs";
1
+ import { $ as StreamReader, Q as StreamErrorPayload, X as CreateStreamReaderOptions, Y as BufferedChunk, Z as CreateStreamSinkOptions, et as StreamSink, nt as createStreamReader, rt as createStreamSink, tt as StreamSinkEvents } from "../devframe-DJMg0WLe.mjs";
2
2
  export { BufferedChunk, CreateStreamReaderOptions, CreateStreamSinkOptions, StreamErrorPayload, StreamReader, StreamSink, StreamSinkEvents, createStreamReader, createStreamSink };
@@ -0,0 +1,266 @@
1
+ import { t as diagnostics } from "./diagnostics-CD8nlgll.mjs";
2
+ import { createHash } from "node:crypto";
3
+ //#region ../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/shared/ohash.D__AXeF1.mjs
4
+ function serialize(o) {
5
+ return typeof o == "string" ? `'${o}'` : new c().serialize(o);
6
+ }
7
+ const c = /*@__PURE__*/ function() {
8
+ class o {
9
+ #t = /* @__PURE__ */ new Map();
10
+ compare(t, r) {
11
+ const e = typeof t, n = typeof r;
12
+ return e === "string" && n === "string" ? t.localeCompare(r) : e === "number" && n === "number" ? t - r : String.prototype.localeCompare.call(this.serialize(t, true), this.serialize(r, true));
13
+ }
14
+ serialize(t, r) {
15
+ if (t === null) return "null";
16
+ switch (typeof t) {
17
+ case "string": return r ? t : `'${t}'`;
18
+ case "bigint": return `${t}n`;
19
+ case "object": return this.$object(t);
20
+ case "function": return this.$function(t);
21
+ }
22
+ return String(t);
23
+ }
24
+ serializeObject(t) {
25
+ const r = Object.prototype.toString.call(t);
26
+ if (r !== "[object Object]") return this.serializeBuiltInType(r.length < 10 ? `unknown:${r}` : r.slice(8, -1), t);
27
+ const e = t.constructor, n = e === Object || e === void 0 ? "" : e.name;
28
+ if (n !== "" && globalThis[n] === e) return this.serializeBuiltInType(n, t);
29
+ if (typeof t.toJSON == "function") {
30
+ const i = t.toJSON();
31
+ return n + (i !== null && typeof i == "object" ? this.$object(i) : `(${this.serialize(i)})`);
32
+ }
33
+ return this.serializeObjectEntries(n, Object.entries(t));
34
+ }
35
+ serializeBuiltInType(t, r) {
36
+ const e = this["$" + t];
37
+ if (e) return e.call(this, r);
38
+ if (typeof r?.entries == "function") return this.serializeObjectEntries(t, r.entries());
39
+ throw new Error(`Cannot serialize ${t}`);
40
+ }
41
+ serializeObjectEntries(t, r) {
42
+ const e = Array.from(r).sort((i, a) => this.compare(i[0], a[0]));
43
+ let n = `${t}{`;
44
+ for (let i = 0; i < e.length; i++) {
45
+ const [a, l] = e[i];
46
+ n += `${this.serialize(a, true)}:${this.serialize(l)}`, i < e.length - 1 && (n += ",");
47
+ }
48
+ return n + "}";
49
+ }
50
+ $object(t) {
51
+ let r = this.#t.get(t);
52
+ return r === void 0 && (this.#t.set(t, `#${this.#t.size}`), r = this.serializeObject(t), this.#t.set(t, r)), r;
53
+ }
54
+ $function(t) {
55
+ const r = Function.prototype.toString.call(t);
56
+ return r.slice(-15) === "[native code] }" ? `${t.name || ""}()[native]` : `${t.name}(${t.length})${r.replace(/\s*\n\s*/g, "")}`;
57
+ }
58
+ $Array(t) {
59
+ let r = "[";
60
+ for (let e = 0; e < t.length; e++) r += this.serialize(t[e]), e < t.length - 1 && (r += ",");
61
+ return r + "]";
62
+ }
63
+ $Date(t) {
64
+ try {
65
+ return `Date(${t.toISOString()})`;
66
+ } catch {
67
+ return "Date(null)";
68
+ }
69
+ }
70
+ $ArrayBuffer(t) {
71
+ return `ArrayBuffer[${new Uint8Array(t).join(",")}]`;
72
+ }
73
+ $Set(t) {
74
+ return `Set${this.$Array(Array.from(t).sort((r, e) => this.compare(r, e)))}`;
75
+ }
76
+ $Map(t) {
77
+ return this.serializeObjectEntries("Map", t.entries());
78
+ }
79
+ }
80
+ for (const s of [
81
+ "Error",
82
+ "RegExp",
83
+ "URL"
84
+ ]) o.prototype["$" + s] = function(t) {
85
+ return `${s}(${t})`;
86
+ };
87
+ for (const s of [
88
+ "Int8Array",
89
+ "Uint8Array",
90
+ "Uint8ClampedArray",
91
+ "Int16Array",
92
+ "Uint16Array",
93
+ "Int32Array",
94
+ "Uint32Array",
95
+ "Float32Array",
96
+ "Float64Array"
97
+ ]) o.prototype["$" + s] = function(t) {
98
+ return `${s}[${t.join(",")}]`;
99
+ };
100
+ for (const s of ["BigInt64Array", "BigUint64Array"]) o.prototype["$" + s] = function(t) {
101
+ return `${s}[${t.join("n,")}${t.length > 0 ? "n" : ""}]`;
102
+ };
103
+ return o;
104
+ }();
105
+ //#endregion
106
+ //#region ../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/crypto/node/index.mjs
107
+ const e = globalThis.process?.getBuiltinModule?.("crypto")?.hash;
108
+ const r = "sha256";
109
+ const s = "base64url";
110
+ function digest(t) {
111
+ if (e) return e(r, t, s);
112
+ const o = createHash(r).update(t);
113
+ return globalThis.process?.versions?.webcontainer ? o.digest().toString(s) : o.digest(s);
114
+ }
115
+ //#endregion
116
+ //#region ../../node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/index.mjs
117
+ function hash$1(input) {
118
+ return digest(serialize(input));
119
+ }
120
+ //#endregion
121
+ //#region src/utils/hash.ts
122
+ /**
123
+ * Stable, deterministic hash of any structured-cloneable value.
124
+ */
125
+ function hash(value) {
126
+ return hash$1(value);
127
+ }
128
+ //#endregion
129
+ //#region src/rpc/validate-io.ts
130
+ /**
131
+ * Run a single [Standard Schema](https://standardschema.dev) validator,
132
+ * awaiting the result when the validator is asynchronous.
133
+ */
134
+ async function runStandardSchema(schema, value) {
135
+ const result = schema["~standard"].validate(value);
136
+ return result instanceof Promise ? await result : result;
137
+ }
138
+ /**
139
+ * Render Standard Schema issues into a single human-readable line for a
140
+ * diagnostic message, prefixing each with its dotted path when present.
141
+ */
142
+ function formatIssues(issues) {
143
+ return issues.map((issue) => {
144
+ const path = issue.path?.map((segment) => typeof segment === "object" ? segment.key : segment).join(".");
145
+ return path ? `${path}: ${issue.message}` : issue.message;
146
+ }).join("; ");
147
+ }
148
+ /**
149
+ * Validate positional arguments against their declared schemas. Only
150
+ * indices with a schema are checked; extra arguments pass through
151
+ * untouched. Throws `DF0038` on the first failing argument.
152
+ *
153
+ * Validation guards the payload without rewriting it: the original values
154
+ * are handed to the handler unchanged, so a schema that describes a subset
155
+ * of an object never silently strips the sender's extra fields (and any
156
+ * declared transforms stay a purely type-level concern).
157
+ *
158
+ * @internal
159
+ */
160
+ async function validateRpcArgs(name, argsSchema, args) {
161
+ const original = args.slice();
162
+ if (!argsSchema || argsSchema.length === 0) return original;
163
+ for (let index = 0; index < argsSchema.length; index++) {
164
+ const schema = argsSchema[index];
165
+ if (!schema) continue;
166
+ const result = await runStandardSchema(schema, args[index]);
167
+ if (result.issues) throw diagnostics.DF0043({
168
+ name,
169
+ index,
170
+ issues: formatIssues(result.issues)
171
+ });
172
+ }
173
+ return original;
174
+ }
175
+ /**
176
+ * Validate a handler's resolved return value against its declared schema.
177
+ * Throws `DF0039` when the value fails the schema, otherwise returns the
178
+ * original value unchanged (guard-only, never rewriting the payload — see
179
+ * {@link validateRpcArgs}). Passes through when no return schema is set.
180
+ *
181
+ * @internal
182
+ */
183
+ async function validateRpcReturn(name, returnSchema, value) {
184
+ if (!returnSchema) return value;
185
+ const result = await runStandardSchema(returnSchema, value);
186
+ if (result.issues) throw diagnostics.DF0044({
187
+ name,
188
+ issues: formatIssues(result.issues)
189
+ });
190
+ return value;
191
+ }
192
+ //#endregion
193
+ //#region src/rpc/handler.ts
194
+ async function getRpcResolvedSetupResult(definition, context) {
195
+ if (!definition.setup) return {};
196
+ if (typeof context === "object" && context !== null) {
197
+ definition.__cache ??= /* @__PURE__ */ new WeakMap();
198
+ const cache = definition.__cache;
199
+ let promise = cache.get(context);
200
+ if (!promise) {
201
+ promise = Promise.resolve(definition.setup(context));
202
+ promise.catch(() => {
203
+ if (cache.get(context) === promise) cache.delete(context);
204
+ });
205
+ cache.set(context, promise);
206
+ }
207
+ return await promise;
208
+ }
209
+ if (!definition.__promise) {
210
+ const promise = Promise.resolve(definition.setup(context));
211
+ promise.catch(() => {
212
+ if (definition.__promise === promise) definition.__promise = void 0;
213
+ });
214
+ definition.__promise = promise;
215
+ }
216
+ return await definition.__promise;
217
+ }
218
+ async function getRpcHandler(definition, context) {
219
+ let handler = definition.handler;
220
+ if (!handler) {
221
+ const result = await getRpcResolvedSetupResult(definition, context);
222
+ if (!result.handler) throw diagnostics.DF0024({ name: definition.name });
223
+ handler = result.handler;
224
+ }
225
+ const argsSchema = definition.args;
226
+ const returnSchema = definition.returns;
227
+ if (!argsSchema && !returnSchema) return handler;
228
+ const inner = handler;
229
+ const validating = async (...args) => {
230
+ const validatedArgs = await validateRpcArgs(definition.name, argsSchema, args);
231
+ const output = await inner(...validatedArgs);
232
+ return await validateRpcReturn(definition.name, returnSchema, output);
233
+ };
234
+ return validating;
235
+ }
236
+ //#endregion
237
+ //#region src/rpc/validation.ts
238
+ /**
239
+ * Validates RPC function definitions.
240
+ * Action and event functions cannot have dumps (side effects should not be cached).
241
+ *
242
+ * @throws {Error} If an action or event function has a dump configuration
243
+ */
244
+ function validateDefinitions(definitions) {
245
+ for (const definition of definitions) {
246
+ const type = definition.type || "query";
247
+ if ((type === "action" || type === "event") && definition.dump) throw diagnostics.DF0027({
248
+ name: definition.name,
249
+ type
250
+ });
251
+ if (definition.snapshot && type !== "query") throw diagnostics.DF0028({
252
+ name: definition.name,
253
+ type
254
+ });
255
+ }
256
+ }
257
+ /**
258
+ * Validates a single RPC function definition.
259
+ *
260
+ * @throws {Error} If an action or event function has a dump configuration
261
+ */
262
+ function validateDefinition(definition) {
263
+ validateDefinitions([definition]);
264
+ }
265
+ //#endregion
266
+ export { validateRpcArgs as a, getRpcResolvedSetupResult as i, validateDefinitions as n, validateRpcReturn as o, getRpcHandler as r, hash as s, validateDefinition as t };