devframe 0.5.4 → 0.6.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/{_shared-CUFqO4kJ.mjs → _shared-bWRzeSa0.mjs} +2 -3
  2. package/dist/adapters/build.d.mts +1 -1
  3. package/dist/adapters/build.mjs +7 -7
  4. package/dist/adapters/cli.d.mts +1 -1
  5. package/dist/adapters/cli.mjs +2 -2
  6. package/dist/adapters/dev.d.mts +8 -2
  7. package/dist/adapters/dev.mjs +1 -1
  8. package/dist/adapters/embedded.d.mts +1 -1
  9. package/dist/adapters/mcp.d.mts +1 -1
  10. package/dist/adapters/mcp.mjs +4 -4
  11. package/dist/client/index.d.mts +148 -6
  12. package/dist/client/index.mjs +257 -44
  13. package/dist/constants.d.mts +17 -1
  14. package/dist/constants.mjs +17 -1
  15. package/dist/context-3x_bgBgZ.mjs +48 -0
  16. package/dist/{context-DTRcO_UH.d.mts → context-BEVByy_Z.d.mts} +1 -1
  17. package/dist/{dev-Cv43GfqM.mjs → dev-BaX8fLH2.mjs} +39 -13
  18. package/dist/{devframe-BuR6n9ZD.d.mts → devframe-D-gr9sBx.d.mts} +365 -15
  19. package/dist/{diagnostics-GitRGKbr.mjs → diagnostics-BXwBQmoN.mjs} +1 -1
  20. package/dist/{dump-9lKIJTLh.mjs → dump-DoXkj4ku.mjs} +1 -1
  21. package/dist/helpers/vite.d.mts +1 -1
  22. package/dist/helpers/vite.mjs +11 -11
  23. package/dist/{host-h3-Dgpgr1Ul.mjs → host-h3-C5SZlk03.mjs} +134 -6
  24. package/dist/{index-C7M1hnvL.d.mts → index-CxaPKDXX.d.mts} +2 -2
  25. package/dist/{index-DH2sBIwd.d.mts → index-DXHWuwJk.d.mts} +1 -1
  26. package/dist/index.d.mts +4 -4
  27. package/dist/index.mjs +1 -1
  28. package/dist/{launch-editor-BbNhtg7b.mjs → launch-editor-DPfltGA4.mjs} +88 -13
  29. package/dist/node/auth.d.mts +43 -23
  30. package/dist/node/auth.mjs +84 -37
  31. package/dist/node/hub-internals.d.mts +2 -2
  32. package/dist/node/hub-internals.mjs +2 -2
  33. package/dist/node/index.d.mts +22 -6
  34. package/dist/node/index.mjs +4 -4
  35. package/dist/recipes/open-helpers.d.mts +1 -1
  36. package/dist/recipes/open-helpers.mjs +3 -3
  37. package/dist/revoke-ENfxWkFK.mjs +79 -0
  38. package/dist/rpc/dump.d.mts +1 -1
  39. package/dist/rpc/dump.mjs +1 -1
  40. package/dist/rpc/index.d.mts +3 -3
  41. package/dist/rpc/index.mjs +4 -4
  42. package/dist/rpc/transports/ws-client.d.mts +1 -1
  43. package/dist/rpc/transports/ws-client.mjs +2 -2
  44. package/dist/rpc/transports/ws-server.d.mts +2 -2
  45. package/dist/rpc/transports/ws-server.mjs +154 -61
  46. package/dist/{serialization-BD_qXGjd.mjs → serialization-DpLXCy13.mjs} +1 -1
  47. package/dist/{server-BBaBJaUL.mjs → server-Dl6TU5LE.mjs} +19 -14
  48. package/dist/server-rX781kz-.d.mts +90 -0
  49. package/dist/{shared-state-u0y123fi.mjs → shared-state-D4PPieA0.mjs} +4 -4
  50. package/dist/{shared-state-BlBNYziY.mjs → storage-l2ezeend.mjs} +128 -6
  51. package/dist/types/index.d.mts +4 -4
  52. package/dist/{types-BkkQ0Txg.d.mts → types-DZEx4ffs.d.mts} +9 -1
  53. package/dist/utils/crypto-token.d.mts +24 -0
  54. package/dist/utils/crypto-token.mjs +45 -0
  55. package/dist/utils/events.d.mts +1 -1
  56. package/dist/utils/hash.mjs +1 -1
  57. package/dist/utils/launch-editor.mjs +1 -1
  58. package/dist/utils/open.mjs +1 -1
  59. package/dist/utils/scope.d.mts +11 -0
  60. package/dist/utils/scope.mjs +15 -0
  61. package/dist/utils/shared-state.d.mts +1 -1
  62. package/dist/utils/shared-state.mjs +1 -1
  63. package/dist/utils/streaming-channel.d.mts +1 -1
  64. package/dist/utils/structured-clone.mjs +1 -1
  65. package/dist/{ws-client-CVYX9niP.d.mts → ws-client-D0z0pOhn.d.mts} +1 -1
  66. package/dist/ws-server-Bc2wBHl-.d.mts +119 -0
  67. package/package.json +12 -7
  68. package/skills/devframe/SKILL.md +123 -23
  69. package/skills/devframe/templates/counter-devframe.ts +14 -4
  70. package/skills/devframe/templates/spa-devframe.ts +13 -3
  71. package/skills/devframe/templates/vite-client.ts +3 -2
  72. package/dist/context-DaKmhhHY.mjs +0 -164
  73. package/dist/revoke-CL0LSAN9.mjs +0 -803
  74. package/dist/server-wHlpcdZ9.d.mts +0 -55
  75. package/dist/utils/human-id.d.mts +0 -8
  76. package/dist/utils/human-id.mjs +0 -769
  77. package/dist/ws-server-C1LjmRnp.d.mts +0 -61
  78. /package/dist/{define-CW9gLnyG.mjs → define-BLWPsH6y.mjs} +0 -0
  79. /package/dist/{diagnostics-reporter-CBBZwoMv.mjs → diagnostics-reporter-CsIG85Q5.mjs} +0 -0
  80. /package/dist/{hash-bwOD8RgU.mjs → hash-DFc5WwhO.mjs} +0 -0
  81. /package/dist/{open-DiQn6zCH.mjs → open-Dusa2Zzd.mjs} +0 -0
  82. /package/dist/{structured-clone-PdCZwt7F.mjs → structured-clone-CeZOHvkd.mjs} +0 -0
  83. /package/dist/{structured-clone-jegjz0hM.mjs → structured-clone-XpHLZ8nr.mjs} +0 -0
  84. /package/dist/{transports-DTFoMUbE.mjs → transports-BmDVn4SF.mjs} +0 -0
@@ -1,15 +1,15 @@
1
- import { t as devframeReporter } from "./diagnostics-reporter-CBBZwoMv.mjs";
2
- import { t as diagnostics } from "./diagnostics-GitRGKbr.mjs";
1
+ import { t as devframeReporter } from "./diagnostics-reporter-CsIG85Q5.mjs";
2
+ import { t as diagnostics } from "./diagnostics-BXwBQmoN.mjs";
3
3
  import { RpcFunctionsCollectorBase } from "./rpc/index.mjs";
4
4
  import { defineRpcFunction } from "./index.mjs";
5
- import { i as diagnostics$1, n as nanoid, r as createEventEmitter, t as createSharedState } from "./shared-state-BlBNYziY.mjs";
5
+ import { a as diagnostics$1, i as createEventEmitter, n as createSharedState, r as nanoid, t as createStorage } from "./storage-l2ezeend.mjs";
6
6
  import { defineDiagnostics } from "nostics";
7
7
  import { isatty } from "node:tty";
8
8
  import { formatWithOptions, inspect } from "node:util";
9
9
  import { existsSync } from "node:fs";
10
+ import { join } from "pathe";
10
11
  import { homedir } from "node:os";
11
12
  import process$1 from "node:process";
12
- import { join } from "pathe";
13
13
  //#region src/node/host-agent.ts
14
14
  /**
15
15
  * Framework-neutral host aggregating the agent-exposed surface of a
@@ -1240,6 +1240,123 @@ const BUILTIN_AGENT_RPC = [
1240
1240
  })
1241
1241
  ];
1242
1242
  //#endregion
1243
+ //#region src/utils/scope.ts
1244
+ /** Whether a name is already namespaced (contains a `:` separator). */
1245
+ function isQualifiedName(name) {
1246
+ return name.includes(":");
1247
+ }
1248
+ /**
1249
+ * Prefix a bare name with `<namespace>:`. Names that already contain a
1250
+ * `:` are returned unchanged, so callers can reference another scope's
1251
+ * ids explicitly (e.g. `ctx.rpc.call('other-plugin:fn')`).
1252
+ */
1253
+ function qualifyName(namespace, name) {
1254
+ return isQualifiedName(name) ? name : `${namespace}:${name}`;
1255
+ }
1256
+ //#endregion
1257
+ //#region src/node/settings.ts
1258
+ const STORAGE_SCOPE = {
1259
+ global: "global",
1260
+ project: "workspace"
1261
+ };
1262
+ function createNodeSettingsStore(context, namespace, scope) {
1263
+ const stateKey = `devframe:settings:${scope}:${namespace}`;
1264
+ let statePromise;
1265
+ function store() {
1266
+ if (!statePromise) {
1267
+ const filepath = join(context.host.getStorageDir(STORAGE_SCOPE[scope]), "settings", `${namespace}.json`);
1268
+ statePromise = context.rpc.sharedState.get(stateKey, { sharedState: createStorage({
1269
+ filepath,
1270
+ initialValue: {}
1271
+ }) });
1272
+ }
1273
+ return statePromise;
1274
+ }
1275
+ return {
1276
+ async get(key) {
1277
+ return (await store()).value()[key];
1278
+ },
1279
+ async set(key, value) {
1280
+ (await store()).mutate((draft) => {
1281
+ draft[key] = value;
1282
+ });
1283
+ },
1284
+ async delete(key) {
1285
+ (await store()).mutate((draft) => {
1286
+ delete draft[key];
1287
+ });
1288
+ },
1289
+ async all() {
1290
+ return (await store()).value();
1291
+ },
1292
+ async onChange(fn) {
1293
+ return (await store()).on("updated", (full) => fn(full));
1294
+ }
1295
+ };
1296
+ }
1297
+ /**
1298
+ * Build the node-side `settings` surface for a scope namespace. `project`
1299
+ * persists under the host's `workspace` storage dir, `global` under its
1300
+ * `global` dir. Each is a file-backed, client-synced key-value store.
1301
+ */
1302
+ function createNodeSettings(context, namespace) {
1303
+ return {
1304
+ global: createNodeSettingsStore(context, namespace, "global"),
1305
+ project: createNodeSettingsStore(context, namespace, "project")
1306
+ };
1307
+ }
1308
+ //#endregion
1309
+ //#region src/node/scope.ts
1310
+ function prefixDefinition(namespace, fn) {
1311
+ if (isQualifiedName(fn.name)) throw diagnostics$1.DF0034({
1312
+ namespace,
1313
+ name: fn.name
1314
+ });
1315
+ return {
1316
+ ...fn,
1317
+ name: `${namespace}:${fn.name}`
1318
+ };
1319
+ }
1320
+ /**
1321
+ * Build a namespace-scoped view of a {@link DevframeNodeContext}. Every
1322
+ * RPC id, shared-state key, and streaming channel passed through the
1323
+ * returned `rpc` surface is auto-namespaced with `<namespace>:`.
1324
+ */
1325
+ function createScopedNodeContext(context, namespace) {
1326
+ const base = context.rpc;
1327
+ const rpc = {
1328
+ namespace,
1329
+ register(fn, force) {
1330
+ base.register(prefixDefinition(namespace, fn), force);
1331
+ },
1332
+ update(fn, force) {
1333
+ base.update(prefixDefinition(namespace, fn), force);
1334
+ },
1335
+ call: ((method, ...args) => base.invokeLocal(qualifyName(namespace, method), ...args)),
1336
+ broadcast: ((options) => base.broadcast({
1337
+ ...options,
1338
+ method: qualifyName(namespace, options.method)
1339
+ })),
1340
+ sharedState: ((key, options) => base.sharedState.get(qualifyName(namespace, key), options)),
1341
+ streaming: { create: (name, opts) => base.streaming.create(qualifyName(namespace, name), opts) },
1342
+ getCurrentRpcSession: () => base.getCurrentRpcSession()
1343
+ };
1344
+ return {
1345
+ namespace,
1346
+ base: context,
1347
+ cwd: context.cwd,
1348
+ workspaceRoot: context.workspaceRoot,
1349
+ mode: context.mode,
1350
+ host: context.host,
1351
+ rpc,
1352
+ settings: createNodeSettings(context, namespace),
1353
+ views: context.views,
1354
+ diagnostics: context.diagnostics,
1355
+ agent: context.agent,
1356
+ scope: context.scope
1357
+ };
1358
+ }
1359
+ //#endregion
1243
1360
  //#region src/node/context.ts
1244
1361
  /**
1245
1362
  * Framework- and build-tool-agnostic core of the Devframe node context.
@@ -1259,7 +1376,8 @@ async function createHostContext(options) {
1259
1376
  rpc: void 0,
1260
1377
  views: void 0,
1261
1378
  diagnostics: void 0,
1262
- agent: void 0
1379
+ agent: void 0,
1380
+ scope: void 0
1263
1381
  };
1264
1382
  const rpcHost = new RpcFunctionsHost(context);
1265
1383
  const viewsHost = new DevframeViewHost(context);
@@ -1268,6 +1386,16 @@ async function createHostContext(options) {
1268
1386
  context.views = viewsHost;
1269
1387
  context.diagnostics = diagnosticsHost;
1270
1388
  context.agent = new DevframeAgentHost(context);
1389
+ const scopedCache = /* @__PURE__ */ new Map();
1390
+ context.scope = ((namespace) => {
1391
+ if (!namespace) return context;
1392
+ let scoped = scopedCache.get(namespace);
1393
+ if (!scoped) {
1394
+ scoped = createScopedNodeContext(context, namespace);
1395
+ scopedCache.set(namespace, scoped);
1396
+ }
1397
+ return scoped;
1398
+ });
1271
1399
  for (const fn of BUILTIN_AGENT_RPC) rpcHost.register(fn);
1272
1400
  for (const fn of builtinRpcDeclarations) rpcHost.register(fn);
1273
1401
  return context;
@@ -1293,4 +1421,4 @@ function createH3DevframeHost(options) {
1293
1421
  };
1294
1422
  }
1295
1423
  //#endregion
1296
- export { createRpcStreamingServerHost as a, DevframeAgentHost as c, RpcFunctionsHost as i, createHostContext as n, createRpcSharedStateServerHost as o, DevframeViewHost as r, DevframeDiagnosticsHost as s, createH3DevframeHost as t };
1424
+ export { DevframeViewHost as a, createRpcSharedStateServerHost as c, createNodeSettings as i, DevframeDiagnosticsHost as l, createHostContext as n, RpcFunctionsHost as o, createScopedNodeContext as r, createRpcStreamingServerHost as s, createH3DevframeHost as t, DevframeAgentHost as u };
@@ -1,5 +1,5 @@
1
- import { C as RpcFunctionsCollector, S as RpcFunctionType, _ as RpcFunctionDefinitionAny, g as RpcFunctionDefinition, i as RpcArgsSchema, w as RpcReturnSchema, x as RpcFunctionSetupResult } from "./types-BkkQ0Txg.mjs";
2
- import { a as getDefinitionsWithDumps$1, c as StaticRpcDumpManifest$1, d as StaticRpcDumpManifestValue$1, f as StaticRpcDumpSerialization$1, i as dumpFunctions$1, l as StaticRpcDumpManifestQueryEntry$1, n as serializeDumpError$1, o as StaticRpcDumpCollection$1, p as collectStaticRpcDump$1, r as createClientFromDump$1, s as StaticRpcDumpFile$1, t as reviveDumpError$1, u as StaticRpcDumpManifestStaticEntry$1 } from "./index-DH2sBIwd.mjs";
1
+ import { C as RpcFunctionType, S as RpcFunctionSetupResult, T as RpcReturnSchema, _ as RpcFunctionDefinition, i as RpcArgsSchema, v as RpcFunctionDefinitionAny, w as RpcFunctionsCollector } from "./types-DZEx4ffs.mjs";
2
+ import { a as getDefinitionsWithDumps$1, c as StaticRpcDumpManifest$1, d as StaticRpcDumpManifestValue$1, f as StaticRpcDumpSerialization$1, i as dumpFunctions$1, l as StaticRpcDumpManifestQueryEntry$1, n as serializeDumpError$1, o as StaticRpcDumpCollection$1, p as collectStaticRpcDump$1, r as createClientFromDump$1, s as StaticRpcDumpFile$1, t as reviveDumpError$1, u as StaticRpcDumpManifestStaticEntry$1 } from "./index-DXHWuwJk.mjs";
3
3
 
4
4
  //#region src/rpc/cache.d.ts
5
5
  interface RpcCacheOptions {
@@ -1,4 +1,4 @@
1
- import { _ as RpcFunctionDefinitionAny, c as RpcDumpClientOptions, l as RpcDumpCollectionOptions, m as RpcDumpStore, n as BirpcReturn, o as RpcDefinitionsToFunctions, p as RpcDumpRecordError } from "./types-BkkQ0Txg.mjs";
1
+ import { h as RpcDumpStore, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny } from "./types-DZEx4ffs.mjs";
2
2
 
3
3
  //#region src/rpc/dump/static.d.ts
4
4
  type StaticRpcDumpSerialization = 'json' | 'structured-clone';
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as AgentResource, B as EntriesToObject, G as DevframeRpcSharedStates, H as Thenable, J as DevframeDiagnosticsDefinition, K as DevframeHost, Q as AgentManifest, U as DevframeRpcClientFunctions, V as PartialWithoutId, W as DevframeRpcServerFunctions, X as DevframeDiagnosticsLogger, Y as DevframeDiagnosticsHost, Z as AgentHandle, _ as RpcStreamingChannel, a as DevframeRuntime, at as DevframeAgentHostEvents, c as defineDevframe, ct as EventsMap, d as DevframeNodeContext, et as AgentResourceContent, f as DevframeNodeRpcSession, g as RpcSharedStateHost, h as RpcSharedStateGetOptions, i as DevframeDeploymentKind, it as DevframeAgentHost, l as ConnectionMeta, m as RpcFunctionsHost, n as DevframeCliOptions, nt as AgentTool, o as DevframeSetupInfo, ot as EventEmitter, p as RpcBroadcastOptions, q as DevframeDefineDiagnosticsOptions, r as DevframeDefinition, rt as AgentToolInput, s as DevframeSpaOptions, st as EventUnsubscribe, t as DevframeBrowserContext, tt as AgentResourceInput, u as DevframeCapabilities, v as RpcStreamingChannelOptions, y as RpcStreamingHost, z as DevframeViewHost } from "./devframe-BuR6n9ZD.mjs";
2
- import { S as RpcFunctionType, g as RpcFunctionDefinition, h as RpcFunctionAgentOptions, i as RpcArgsSchema, w as RpcReturnSchema } from "./types-BkkQ0Txg.mjs";
3
- import { t as DevframeNodeRpcSessionMeta } from "./ws-server-C1LjmRnp.mjs";
1
+ import { $ as ScopedServerFunctions, G as DevframeScopedNodeContext, H as EntriesToObject, J as DevframeSettings, K as DevframeScopedNodeRpc, Q as ScopedClientFunctions, S as RpcStreamingHost, St as EventsMap, U as PartialWithoutId, W as Thenable, X as DevframeSettingsStore, Y as DevframeSettingsRegistry, Z as ScopedBroadcastOptions, _ as RpcFunctionsHost, _t as AgentToolInput, a as DevframeDuplicationStrategy, at as DevframeRpcSharedStates, b as RpcStreamingChannel, bt as EventEmitter, c as DevframeSpaOptions, ct as DevframeDiagnosticsDefinition, d as ConnectionMeta, dt as AgentHandle, et as ScopedSharedStates, f as ConnectionMetaWebsocket, ft as AgentManifest, g as RpcBroadcastOptions, gt as AgentTool, h as DevframeNodeRpcSession, ht as AgentResourceInput, i as DevframeDeploymentKind, it as DevframeRpcServerFunctions, l as DevframeWsOptions, lt as DevframeDiagnosticsHost, m as DevframeNodeContext, mt as AgentResourceContent, n as DevframeCliOptions, nt as DevframeViewHost, o as DevframeRuntime, ot as DevframeHost, p as DevframeCapabilities, pt as AgentResource, q as DevframeScopedStreamingHost, r as DevframeDefinition, rt as DevframeRpcClientFunctions, s as DevframeSetupInfo, st as DevframeDefineDiagnosticsOptions, t as DevframeBrowserContext, tt as SettingsForNamespace, u as defineDevframe, ut as DevframeDiagnosticsLogger, v as RpcSharedStateGetOptions, vt as DevframeAgentHost, x as RpcStreamingChannelOptions, xt as EventUnsubscribe, y as RpcSharedStateHost, yt as DevframeAgentHostEvents } from "./devframe-D-gr9sBx.mjs";
2
+ import { C as RpcFunctionType, T as RpcReturnSchema, _ as RpcFunctionDefinition, g as RpcFunctionAgentOptions, i as RpcArgsSchema } from "./types-DZEx4ffs.mjs";
3
+ import { t as DevframeNodeRpcSessionMeta } from "./ws-server-Bc2wBHl-.mjs";
4
4
 
5
5
  //#region src/define.d.ts
6
6
  declare const defineRpcFunction: <NAME extends string, TYPE extends RpcFunctionType, ARGS extends any[], RETURN = void, const AS extends RpcArgsSchema | undefined = undefined, const RS extends RpcReturnSchema | undefined = undefined>(definition: RpcFunctionDefinition<NAME, TYPE, ARGS, RETURN, AS, RS, DevframeNodeContext>) => RpcFunctionDefinition<NAME, TYPE, ARGS, RETURN, AS, RS, DevframeNodeContext>;
7
7
  //#endregion
8
- export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeSetupInfo, DevframeSpaOptions, DevframeViewHost, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, PartialWithoutId, RpcBroadcastOptions, RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, Thenable, defineDevframe, defineRpcFunction };
8
+ export { AgentHandle, AgentManifest, AgentResource, AgentResourceContent, AgentResourceInput, AgentTool, AgentToolInput, ConnectionMeta, ConnectionMetaWebsocket, DevframeAgentHost, DevframeAgentHostEvents, DevframeBrowserContext, DevframeCapabilities, DevframeCliOptions, DevframeDefineDiagnosticsOptions, DevframeDefinition, DevframeDeploymentKind, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeDuplicationStrategy, DevframeHost, DevframeNodeContext, DevframeNodeRpcSession, DevframeNodeRpcSessionMeta, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeRuntime, DevframeScopedNodeContext, DevframeScopedNodeRpc, DevframeScopedStreamingHost, DevframeSettings, DevframeSettingsRegistry, DevframeSettingsStore, DevframeSetupInfo, DevframeSpaOptions, DevframeViewHost, DevframeWsOptions, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, PartialWithoutId, RpcBroadcastOptions, RpcFunctionAgentOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, ScopedBroadcastOptions, ScopedClientFunctions, ScopedServerFunctions, ScopedSharedStates, SettingsForNamespace, Thenable, defineDevframe, defineRpcFunction };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createDefineWrapperWithContext } from "./define-CW9gLnyG.mjs";
1
+ import { t as createDefineWrapperWithContext } from "./define-BLWPsH6y.mjs";
2
2
  //#region src/define.ts
3
3
  const defineRpcFunction = createDefineWrapperWithContext();
4
4
  //#endregion
@@ -91,21 +91,66 @@ var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
91
91
  module.exports.createColors = createColors;
92
92
  }));
93
93
  //#endregion
94
- //#region ../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/quote.js
94
+ //#region ../../node_modules/.pnpm/shell-quote@1.9.0/node_modules/shell-quote/quote.js
95
95
  var require_quote = /* @__PURE__ */ __commonJSMin(((exports, module) => {
96
+ /** @import { ControlOperator } from './parse' */
97
+ /** @type {ControlOperator['op'][]} */
98
+ var OPS = [
99
+ "||",
100
+ "&&",
101
+ ";;",
102
+ "|&",
103
+ "<(",
104
+ "<<<",
105
+ ">>",
106
+ ">&",
107
+ "<&",
108
+ "&",
109
+ ";",
110
+ "(",
111
+ ")",
112
+ "|",
113
+ "<",
114
+ ">"
115
+ ];
116
+ var LINE_TERMINATORS = /[\n\r\u2028\u2029]/;
117
+ var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|]/g;
118
+ /** @type {import('./quote')} */
96
119
  module.exports = function quote(xs) {
97
120
  return xs.map(function(s) {
98
121
  if (s === "") return "''";
99
- if (s && typeof s === "object") return s.op.replace(/(.)/g, "\\$1");
122
+ if (s && typeof s === "object") {
123
+ if ("op" in s && s.op === "glob") {
124
+ if (typeof s.pattern !== "string") throw new TypeError("glob token requires a string `pattern`");
125
+ if (LINE_TERMINATORS.test(s.pattern)) throw new TypeError("glob `pattern` must not contain line terminators");
126
+ return s.pattern.replace(GLOB_SHELL_SPECIAL, "\\$&");
127
+ }
128
+ if ("op" in s && typeof s.op === "string") {
129
+ if (OPS.indexOf(s.op) < 0) throw new TypeError("invalid `op` value: " + JSON.stringify(s.op));
130
+ return s.op.replace(/[\s\S]/g, "\\$&");
131
+ }
132
+ if ("comment" in s && typeof s.comment === "string") {
133
+ if (LINE_TERMINATORS.test(s.comment)) throw new TypeError("`comment` must not contain line terminators");
134
+ return "#" + s.comment;
135
+ }
136
+ throw new TypeError("unrecognized object token shape");
137
+ }
100
138
  if (/["\s\\]/.test(s) && !/'/.test(s)) return "'" + s.replace(/(['])/g, "\\$1") + "'";
101
139
  if (/["'\s]/.test(s)) return "\"" + s.replace(/(["\\$`!])/g, "\\$1") + "\"";
102
- return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
140
+ return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}~])/g, "$1\\$2");
103
141
  }).join(" ");
104
142
  };
105
143
  }));
106
144
  //#endregion
107
- //#region ../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/parse.js
145
+ //#region ../../node_modules/.pnpm/shell-quote@1.9.0/node_modules/shell-quote/parse.js
108
146
  var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
147
+ /**
148
+ * @import {
149
+ * ControlOperator,
150
+ * Env,
151
+ * GlobPattern,
152
+ * ParseEntry,
153
+ * } from './parse' */
109
154
  var CONTROL = "(?:" + [
110
155
  "\\|\\|",
111
156
  "\\&\\&",
@@ -130,17 +175,26 @@ var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
130
175
  var mult = 4294967296;
131
176
  for (var i = 0; i < 4; i++) TOKEN += (mult * Math.random()).toString(16);
132
177
  var startsWithToken = new RegExp("^" + TOKEN);
178
+ /**
179
+ * @param {string} s
180
+ * @param {RegExp} r
181
+ */
133
182
  function matchAll(s, r) {
134
183
  var origIndex = r.lastIndex;
135
184
  var matches = [];
136
185
  var matchObj;
137
186
  while (matchObj = r.exec(s)) {
138
- matches.push(matchObj);
187
+ matches[matches.length] = matchObj;
139
188
  if (r.lastIndex === matchObj.index) r.lastIndex += 1;
140
189
  }
141
190
  r.lastIndex = origIndex;
142
191
  return matches;
143
192
  }
193
+ /**
194
+ * @param {Env} env
195
+ * @param {string} pre
196
+ * @param {string} key
197
+ */
144
198
  function getVar(env, pre, key) {
145
199
  var r = typeof env === "function" ? env(key) : env[key];
146
200
  if (typeof r === "undefined" && key != "") r = "";
@@ -148,6 +202,12 @@ var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
148
202
  if (typeof r === "object") return pre + TOKEN + JSON.stringify(r) + TOKEN;
149
203
  return pre + r;
150
204
  }
205
+ /**
206
+ * @param {string} string
207
+ * @param {Env} [env]
208
+ * @param {{ escape?: string }} [opts]
209
+ * @returns {ParseEntry[]}
210
+ */
151
211
  function parseInternal(string, env, opts) {
152
212
  if (!opts) opts = {};
153
213
  var BS = opts.escape || "\\";
@@ -160,14 +220,18 @@ var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
160
220
  var s = match[0];
161
221
  if (!s || commented) return;
162
222
  if (controlRE.test(s)) return { op: s };
223
+ /** @type {string | boolean} */
163
224
  var quote = false;
164
225
  var esc = false;
165
226
  var out = "";
166
227
  var isGlob = false;
228
+ /** @type {number} */
167
229
  var i;
168
230
  function parseEnvVar() {
169
231
  i += 1;
232
+ /** @type {number | RegExpMatchArray | null} */
170
233
  var varend;
234
+ /** @type {string} */
171
235
  var varname;
172
236
  var char = s.charAt(i);
173
237
  if (char === "{") {
@@ -225,25 +289,36 @@ var require_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
225
289
  };
226
290
  return out;
227
291
  }).reduce(function(prev, arg) {
228
- return typeof arg === "undefined" ? prev : prev.concat(arg);
292
+ if (typeof arg === "undefined") return prev;
293
+ /** @type {ParseEntry[]} */ [].concat(arg).forEach(function(entry) {
294
+ prev[prev.length] = entry;
295
+ });
296
+ return prev;
229
297
  }, []);
230
298
  }
299
+ /** @type {import('./parse')} */
231
300
  module.exports = function parse(s, env, opts) {
232
301
  var mapped = parseInternal(s, env, opts);
233
302
  if (typeof env !== "function") return mapped;
234
303
  return mapped.reduce(function(acc, s) {
235
- if (typeof s === "object") return acc.concat(s);
304
+ if (typeof s === "object") {
305
+ acc[acc.length] = s;
306
+ return acc;
307
+ }
236
308
  var xs = s.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
237
- if (xs.length === 1) return acc.concat(xs[0]);
238
- return acc.concat(xs.filter(Boolean).map(function(x) {
239
- if (startsWithToken.test(x)) return JSON.parse(x.split(TOKEN)[1]);
240
- return x;
241
- }));
309
+ if (xs.length === 1) {
310
+ acc[acc.length] = xs[0];
311
+ return acc;
312
+ }
313
+ xs.filter(Boolean).forEach(function(x) {
314
+ acc[acc.length] = startsWithToken.test(x) ? JSON.parse(x.split(TOKEN)[1]) : x;
315
+ });
316
+ return acc;
242
317
  }, []);
243
318
  };
244
319
  }));
245
320
  //#endregion
246
- //#region ../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/index.js
321
+ //#region ../../node_modules/.pnpm/shell-quote@1.9.0/node_modules/shell-quote/index.js
247
322
  var require_shell_quote = /* @__PURE__ */ __commonJSMin(((exports) => {
248
323
  exports.quote = require_quote();
249
324
  exports.parse = require_parse();
@@ -1,5 +1,5 @@
1
- import { P as SharedState, d as DevframeNodeContext, f as DevframeNodeRpcSession } from "../devframe-BuR6n9ZD.mjs";
2
- import { n as InternalAnonymousAuthStorage } from "../context-DTRcO_UH.mjs";
1
+ import { L as SharedState, h as DevframeNodeRpcSession, m as DevframeNodeContext } from "../devframe-D-gr9sBx.mjs";
2
+ import { n as InternalAnonymousAuthStorage } from "../context-BEVByy_Z.mjs";
3
3
 
4
4
  //#region src/node/auth/revoke.d.ts
5
5
  /**
@@ -16,29 +16,49 @@ declare function revokeActiveConnectionsForToken(context: DevframeNodeContext, t
16
16
  declare function revokeAuthToken(context: DevframeNodeContext, storage: SharedState<InternalAnonymousAuthStorage>, token: string): Promise<void>;
17
17
  //#endregion
18
18
  //#region src/node/auth/state.d.ts
19
- interface PendingAuthRequest {
20
- clientAuthToken: string;
21
- session: DevframeNodeRpcSession;
22
- ua: string;
23
- origin: string;
24
- resolve: (result: {
25
- isTrusted: boolean;
26
- }) => void;
27
- abortController: AbortController;
28
- timeout: ReturnType<typeof setTimeout>;
29
- }
30
- declare function getTempAuthToken(): string;
31
- declare function refreshTempAuthToken(): string;
32
- declare function getPendingAuth(): PendingAuthRequest | null;
33
- declare function setPendingAuth(request: PendingAuthRequest | null): void;
34
19
  /**
35
- * Abort and clean up any existing pending auth request.
20
+ * The current one-time authentication code. Display this to the user (e.g. in
21
+ * the dev-server terminal) so they can type it into the browser to authenticate.
22
+ */
23
+ declare function getTempAuthCode(): string;
24
+ /**
25
+ * Rotate the authentication code, resetting its expiry window and failed-attempt
26
+ * counter. Call this when a new authentication flow begins (e.g. when an
27
+ * untrusted client starts authenticating) so the displayed code is freshly
28
+ * valid for its full TTL.
36
29
  */
37
- declare function abortPendingAuth(): void;
30
+ declare function refreshTempAuthCode(): string;
38
31
  /**
39
- * Consume the temp auth ID: verify it matches, trust the pending client, and clean up.
40
- * Returns the client's authToken if successful, null otherwise.
32
+ * Build a "magic link" authentication URL that embeds a one-time code (OTP) as
33
+ * a query parameter. Opening it authenticates the client without typing print
34
+ * it on startup (devframe stays headless, so the host prints its own banner).
35
+ * Defaults to the current code; the link is subject to the same TTL.
36
+ */
37
+ declare function buildOtpAuthUrl(baseUrl: string, code?: string): string;
38
+ /**
39
+ * Re-authenticate a connection that presents a previously-issued bearer token.
40
+ * Returns `true` and marks the session trusted when the token is known.
41
+ *
42
+ * Used by the `devframe:anonymous:auth` handler so a client that already
43
+ * authenticated (token persisted in the browser) is trusted on reconnect
44
+ * without entering the code again.
41
45
  */
42
- declare function consumeTempAuthToken(id: string, storage: SharedState<InternalAnonymousAuthStorage>): string | null;
46
+ declare function verifyAuthToken(token: string, session: DevframeNodeRpcSession, storage: SharedState<InternalAnonymousAuthStorage>): boolean;
47
+ /**
48
+ * Exchange a one-time authentication code for a fresh, node-issued bearer token.
49
+ *
50
+ * On success this mints a high-entropy token, records it in the trusted store,
51
+ * marks the calling session trusted, rotates the code, and returns the token
52
+ * for the client to persist. Returns `null` on any failure.
53
+ *
54
+ * Because the code is short and human-typed, verification is hardened against
55
+ * brute force: it enforces a time-to-live, compares in constant time, and
56
+ * rotates the code after {@link TEMP_AUTH_MAX_ATTEMPTS} failed attempts so an
57
+ * attacker cannot keep guessing against the same code.
58
+ */
59
+ declare function exchangeTempAuthCode(code: string, session: DevframeNodeRpcSession, info: {
60
+ ua: string;
61
+ origin: string;
62
+ }, storage: SharedState<InternalAnonymousAuthStorage>): string | null;
43
63
  //#endregion
44
- export { PendingAuthRequest, abortPendingAuth, consumeTempAuthToken, getPendingAuth, getTempAuthToken, refreshTempAuthToken, revokeActiveConnectionsForToken, revokeAuthToken, setPendingAuth };
64
+ export { buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken };
@@ -1,54 +1,101 @@
1
- import { n as revokeAuthToken, r as humanId, t as revokeActiveConnectionsForToken } from "../revoke-CL0LSAN9.mjs";
1
+ import { DEVFRAME_OTP_URL_PARAM } from "../constants.mjs";
2
+ import { a as timingSafeEqual, i as randomToken, n as revokeAuthToken, r as randomDigits, t as revokeActiveConnectionsForToken } from "../revoke-ENfxWkFK.mjs";
2
3
  //#region src/node/auth/state.ts
3
- let pendingAuth = null;
4
- let tempAuthToken = generateTempId();
5
- function generateTempId() {
6
- return humanId();
7
- }
8
- function getTempAuthToken() {
9
- return tempAuthToken;
4
+ /** Number of decimal digits in a human-typed one-time authentication code. */
5
+ const TEMP_AUTH_CODE_LENGTH = 6;
6
+ /**
7
+ * How long an authentication code stays valid after it is (re)generated. A
8
+ * 6-digit code only has ~20 bits of entropy, so a short lifetime plus the
9
+ * attempt cap below are what keep it brute-force resistant.
10
+ */
11
+ const TEMP_AUTH_CODE_TTL = 5 * 6e4;
12
+ /** Failed attempts allowed against a single code before it is rotated. */
13
+ const TEMP_AUTH_MAX_ATTEMPTS = 5;
14
+ let tempAuthCode = generateTempCode();
15
+ let tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
16
+ let tempAuthFailedAttempts = 0;
17
+ function generateTempCode() {
18
+ return randomDigits(TEMP_AUTH_CODE_LENGTH);
10
19
  }
11
- function refreshTempAuthToken() {
12
- tempAuthToken = generateTempId();
13
- return tempAuthToken;
20
+ /**
21
+ * The current one-time authentication code. Display this to the user (e.g. in
22
+ * the dev-server terminal) so they can type it into the browser to authenticate.
23
+ */
24
+ function getTempAuthCode() {
25
+ return tempAuthCode;
14
26
  }
15
- function getPendingAuth() {
16
- return pendingAuth;
27
+ /**
28
+ * Rotate the authentication code, resetting its expiry window and failed-attempt
29
+ * counter. Call this when a new authentication flow begins (e.g. when an
30
+ * untrusted client starts authenticating) so the displayed code is freshly
31
+ * valid for its full TTL.
32
+ */
33
+ function refreshTempAuthCode() {
34
+ tempAuthCode = generateTempCode();
35
+ tempAuthCodeExpiresAt = Date.now() + TEMP_AUTH_CODE_TTL;
36
+ tempAuthFailedAttempts = 0;
37
+ return tempAuthCode;
17
38
  }
18
- function setPendingAuth(request) {
19
- pendingAuth = request;
39
+ /**
40
+ * Build a "magic link" authentication URL that embeds a one-time code (OTP) as
41
+ * a query parameter. Opening it authenticates the client without typing — print
42
+ * it on startup (devframe stays headless, so the host prints its own banner).
43
+ * Defaults to the current code; the link is subject to the same TTL.
44
+ */
45
+ function buildOtpAuthUrl(baseUrl, code = tempAuthCode) {
46
+ const url = new URL(baseUrl);
47
+ url.searchParams.set(DEVFRAME_OTP_URL_PARAM, code);
48
+ return url.href;
20
49
  }
21
50
  /**
22
- * Abort and clean up any existing pending auth request.
51
+ * Re-authenticate a connection that presents a previously-issued bearer token.
52
+ * Returns `true` and marks the session trusted when the token is known.
53
+ *
54
+ * Used by the `devframe:anonymous:auth` handler so a client that already
55
+ * authenticated (token persisted in the browser) is trusted on reconnect
56
+ * without entering the code again.
23
57
  */
24
- function abortPendingAuth() {
25
- if (pendingAuth) {
26
- pendingAuth.abortController.abort();
27
- clearTimeout(pendingAuth.timeout);
28
- pendingAuth = null;
29
- }
58
+ function verifyAuthToken(token, session, storage) {
59
+ if (!token || !storage.value().trusted[token]) return false;
60
+ session.meta.clientAuthToken = token;
61
+ session.meta.isTrusted = true;
62
+ return true;
30
63
  }
31
64
  /**
32
- * Consume the temp auth ID: verify it matches, trust the pending client, and clean up.
33
- * Returns the client's authToken if successful, null otherwise.
65
+ * Exchange a one-time authentication code for a fresh, node-issued bearer token.
66
+ *
67
+ * On success this mints a high-entropy token, records it in the trusted store,
68
+ * marks the calling session trusted, rotates the code, and returns the token
69
+ * for the client to persist. Returns `null` on any failure.
70
+ *
71
+ * Because the code is short and human-typed, verification is hardened against
72
+ * brute force: it enforces a time-to-live, compares in constant time, and
73
+ * rotates the code after {@link TEMP_AUTH_MAX_ATTEMPTS} failed attempts so an
74
+ * attacker cannot keep guessing against the same code.
34
75
  */
35
- function consumeTempAuthToken(id, storage) {
36
- if (id !== tempAuthToken || !pendingAuth) return null;
37
- const { clientAuthToken, session, ua, origin, resolve } = pendingAuth;
76
+ function exchangeTempAuthCode(code, session, info, storage) {
77
+ if (Date.now() > tempAuthCodeExpiresAt) {
78
+ refreshTempAuthCode();
79
+ return null;
80
+ }
81
+ if (!timingSafeEqual(code, tempAuthCode)) {
82
+ tempAuthFailedAttempts += 1;
83
+ if (tempAuthFailedAttempts >= TEMP_AUTH_MAX_ATTEMPTS) refreshTempAuthCode();
84
+ return null;
85
+ }
86
+ const authToken = randomToken();
38
87
  storage.mutate((state) => {
39
- state.trusted[clientAuthToken] = {
40
- authToken: clientAuthToken,
41
- ua,
42
- origin,
88
+ state.trusted[authToken] = {
89
+ authToken,
90
+ ua: info.ua,
91
+ origin: info.origin,
43
92
  timestamp: Date.now()
44
93
  };
45
94
  });
46
- session.meta.clientAuthToken = clientAuthToken;
95
+ session.meta.clientAuthToken = authToken;
47
96
  session.meta.isTrusted = true;
48
- resolve({ isTrusted: true });
49
- abortPendingAuth();
50
- refreshTempAuthToken();
51
- return clientAuthToken;
97
+ refreshTempAuthCode();
98
+ return authToken;
52
99
  }
53
100
  //#endregion
54
- export { abortPendingAuth, consumeTempAuthToken, getPendingAuth, getTempAuthToken, refreshTempAuthToken, revokeActiveConnectionsForToken, revokeAuthToken, setPendingAuth };
101
+ export { buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken };
@@ -1,5 +1,5 @@
1
- import { i as DevframeDeploymentKind, r as DevframeDefinition } from "../devframe-BuR6n9ZD.mjs";
2
- import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-DTRcO_UH.mjs";
1
+ import { i as DevframeDeploymentKind, r as DevframeDefinition } from "../devframe-D-gr9sBx.mjs";
2
+ import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-BEVByy_Z.mjs";
3
3
 
4
4
  //#region src/adapters/_shared.d.ts
5
5
  /**
@@ -1,3 +1,3 @@
1
- import { n as internalContextMap, t as getInternalContext } from "../context-DaKmhhHY.mjs";
2
- import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-CUFqO4kJ.mjs";
1
+ import { n as internalContextMap, t as getInternalContext } from "../context-3x_bgBgZ.mjs";
2
+ import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-bWRzeSa0.mjs";
3
3
  export { getInternalContext, internalContextMap, normalizeBasePath, resolveBasePath };