@spfn/core 0.3.0-beta.1 → 0.3.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 (68) hide show
  1. package/README.md +301 -26
  2. package/dist/app-config/index.d.ts +96 -0
  3. package/dist/app-config/index.js +58 -0
  4. package/dist/app-config/index.js.map +1 -0
  5. package/dist/authz/index.js +1 -381
  6. package/dist/authz/index.js.map +1 -1
  7. package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
  8. package/dist/config/index.d.ts +0 -63
  9. package/dist/config/index.js +12 -12
  10. package/dist/config/index.js.map +1 -1
  11. package/dist/contract/index.d.ts +5 -4
  12. package/dist/db/index.d.ts +201 -34
  13. package/dist/db/index.js +294 -158
  14. package/dist/db/index.js.map +1 -1
  15. package/dist/{define-middleware-DfDP39Nq.d.ts → define-middleware-CVKgqo8S.d.ts} +1 -1
  16. package/dist/env/loader.js +24 -1
  17. package/dist/env/loader.js.map +1 -1
  18. package/dist/errors/index.js +1 -381
  19. package/dist/errors/index.js.map +1 -1
  20. package/dist/event/sse/client.d.ts +15 -2
  21. package/dist/event/sse/client.js +38 -2
  22. package/dist/event/sse/client.js.map +1 -1
  23. package/dist/job/index.d.ts +48 -3
  24. package/dist/job/index.js +118 -40
  25. package/dist/job/index.js.map +1 -1
  26. package/dist/logger/index.js +0 -12
  27. package/dist/logger/index.js.map +1 -1
  28. package/dist/middleware/index.d.ts +6 -2
  29. package/dist/middleware/index.js +7 -388
  30. package/dist/middleware/index.js.map +1 -1
  31. package/dist/nextjs/index.d.ts +37 -1
  32. package/dist/nextjs/index.js +40 -1
  33. package/dist/nextjs/index.js.map +1 -1
  34. package/dist/nextjs/server.d.ts +34 -1
  35. package/dist/nextjs/server.js +14 -0
  36. package/dist/nextjs/server.js.map +1 -1
  37. package/dist/ops/index.d.ts +115 -14
  38. package/dist/ops/index.js +339 -15
  39. package/dist/ops/index.js.map +1 -1
  40. package/dist/route/index.d.ts +5 -3
  41. package/dist/route/index.js +1 -1
  42. package/dist/route/index.js.map +1 -1
  43. package/dist/{router-ukNdAZcN.d.ts → route-builder-2ani2jEI.d.ts} +3 -126
  44. package/dist/router-DJdpwuB6.d.ts +127 -0
  45. package/dist/server/index.d.ts +130 -11
  46. package/dist/server/index.js +714 -70
  47. package/dist/server/index.js.map +1 -1
  48. package/dist/{types-Bvvig_tT.d.ts → types-ClQVomgV.d.ts} +1 -1
  49. package/docs/file-upload.md +195 -333
  50. package/package.json +14 -8
  51. package/src/cache/README.md +330 -0
  52. package/src/codegen/README.md +516 -0
  53. package/src/config/README.md +326 -0
  54. package/src/contract/README.md +326 -0
  55. package/src/db/README.md +589 -0
  56. package/src/db/manager/README.md +500 -0
  57. package/src/db/schema/README.md +354 -0
  58. package/src/db/transaction/README.md +822 -0
  59. package/src/env/README.md +651 -0
  60. package/src/errors/README.md +429 -0
  61. package/src/event/README.md +741 -0
  62. package/src/job/README.md +613 -0
  63. package/src/logger/README.md +321 -0
  64. package/src/middleware/README.md +634 -0
  65. package/src/nextjs/README.md +608 -0
  66. package/src/route/README.md +738 -0
  67. package/src/security/README.md +100 -0
  68. package/src/server/README.md +704 -0
package/dist/ops/index.js CHANGED
@@ -138,7 +138,7 @@ var RouteBuilder = class _RouteBuilder {
138
138
  * @example
139
139
  * ```ts
140
140
  * // Skip specific middlewares
141
- * route.get('/health')
141
+ * route.get('/status')
142
142
  * .skip(['auth', 'rateLimit'])
143
143
  * .handler(async (c) => c.json({ status: 'ok' }));
144
144
  *
@@ -319,13 +319,15 @@ function defineRouter(routes) {
319
319
  return createRouterInstance(routes);
320
320
  }
321
321
 
322
- // src/ops/manifest.ts
322
+ // src/ops/error.ts
323
323
  var OpsRouterError = class extends Error {
324
324
  constructor(message) {
325
325
  super(message);
326
326
  this.name = "OpsRouterError";
327
327
  }
328
328
  };
329
+
330
+ // src/ops/manifest.ts
329
331
  function isRouter(value) {
330
332
  return value !== null && typeof value === "object" && "routes" in value && "_routes" in value;
331
333
  }
@@ -383,6 +385,242 @@ function assertUnclaimedName(name, path, claimed) {
383
385
  claimed.set(name, path);
384
386
  }
385
387
 
388
+ // src/ops/ops-route.ts
389
+ var OPS_PATH_ROOT = "/_ops";
390
+ function toOpsPath(path) {
391
+ if (!path.startsWith("/")) {
392
+ throw new OpsRouterError(
393
+ `Ops route path "${path}" must start with "/". It is appended to "${OPS_PATH_ROOT}", so "${path}" would read as "${OPS_PATH_ROOT}${path}".`
394
+ );
395
+ }
396
+ if (path === "/") {
397
+ throw new OpsRouterError(
398
+ `Ops route path "/" names no command \u2014 "${OPS_PATH_ROOT}" itself is not a command.`
399
+ );
400
+ }
401
+ return OPS_PATH_ROOT + path;
402
+ }
403
+ function opsMethod(method) {
404
+ return (path) => route[method](toOpsPath(path));
405
+ }
406
+ var opsRoute = {
407
+ get: opsMethod("get"),
408
+ post: opsMethod("post"),
409
+ put: opsMethod("put"),
410
+ patch: opsMethod("patch"),
411
+ delete: opsMethod("delete")
412
+ };
413
+
414
+ // src/ops/route-overlap.ts
415
+ function routeSegments(path) {
416
+ return path.split("/").slice(1).map((raw) => {
417
+ if (raw === "*" || raw.endsWith("*")) {
418
+ return { kind: "wildcard", value: raw, optional: true };
419
+ }
420
+ if (raw.startsWith(":")) {
421
+ return {
422
+ kind: "parameter",
423
+ value: raw.slice(1).replace(/\?$/, ""),
424
+ optional: raw.endsWith("?")
425
+ };
426
+ }
427
+ return { kind: "static", value: raw, optional: false };
428
+ });
429
+ }
430
+ function customPattern(parameter) {
431
+ const openingBrace = parameter.indexOf("{");
432
+ return openingBrace >= 0 && parameter.endsWith("}") ? parameter.slice(openingBrace + 1, -1) : null;
433
+ }
434
+ function parameterAccepts(parameter, value) {
435
+ const pattern = customPattern(parameter);
436
+ if (pattern === null) {
437
+ return value.length > 0 && !value.includes("/");
438
+ }
439
+ try {
440
+ return new RegExp(`^(?:${pattern})$`).test(value);
441
+ } catch {
442
+ return true;
443
+ }
444
+ }
445
+ function remainingStaticPath(segments, from) {
446
+ const remaining = segments.slice(from);
447
+ return remaining.every((segment) => segment.kind === "static") ? remaining.map((segment) => segment.value).join("/") : null;
448
+ }
449
+ function opsRoutePatternsOverlap(firstPath, secondPath) {
450
+ const first = routeSegments(firstPath);
451
+ const second = routeSegments(secondPath);
452
+ const length = Math.max(first.length, second.length);
453
+ for (let index = 0; index < length; index++) {
454
+ const left = first[index];
455
+ const right = second[index];
456
+ if (!left || !right) {
457
+ const remaining = left ? first.slice(index) : second.slice(index);
458
+ return remaining.every((segment) => segment.optional || segment.kind === "wildcard");
459
+ }
460
+ if (left.kind === "wildcard" || right.kind === "wildcard") {
461
+ return true;
462
+ }
463
+ if (left.kind === "static" && right.kind === "static") {
464
+ if (left.value !== right.value) {
465
+ return false;
466
+ }
467
+ continue;
468
+ }
469
+ if (left.kind === "parameter" && right.kind === "static") {
470
+ const remaining = remainingStaticPath(second, index);
471
+ if (customPattern(left.value) !== null && remaining !== null && parameterAccepts(left.value, remaining)) {
472
+ return true;
473
+ }
474
+ if (!parameterAccepts(left.value, right.value)) {
475
+ return customPattern(left.value) !== null && remaining === null;
476
+ }
477
+ if (customPattern(left.value) !== null && first.length !== second.length) {
478
+ return true;
479
+ }
480
+ continue;
481
+ }
482
+ if (left.kind === "static" && right.kind === "parameter") {
483
+ const remaining = remainingStaticPath(first, index);
484
+ if (customPattern(right.value) !== null && remaining !== null && parameterAccepts(right.value, remaining)) {
485
+ return true;
486
+ }
487
+ if (!parameterAccepts(right.value, left.value)) {
488
+ return customPattern(right.value) !== null && remaining === null;
489
+ }
490
+ if (customPattern(right.value) !== null && first.length !== second.length) {
491
+ return true;
492
+ }
493
+ continue;
494
+ }
495
+ return true;
496
+ }
497
+ return true;
498
+ }
499
+
500
+ // src/ops/module.ts
501
+ var MODULE_ID = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
502
+ var COMMAND_NAME = /^[A-Za-z][A-Za-z0-9]*(?:\.[A-Za-z][A-Za-z0-9]*)*$/;
503
+ var CONTRACT_VERSION = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)*$/;
504
+ var EFFECTS = /* @__PURE__ */ new Set(["read", "write", "destructive"]);
505
+ var OPS_PATH_BASE = "https://spfn.invalid";
506
+ function assertText(label, value) {
507
+ if (typeof value !== "string" || value.trim().length === 0) {
508
+ throw new OpsRouterError(`${label} must be a non-empty string.`);
509
+ }
510
+ }
511
+ function assertStableModulePath(moduleId, commandName, path) {
512
+ const label = `Ops command "${moduleId}.${commandName}" path "${path}"`;
513
+ const transportPath = path.replace(/[{}?#]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
514
+ let url;
515
+ try {
516
+ url = new URL(transportPath, OPS_PATH_BASE);
517
+ } catch {
518
+ throw new OpsRouterError(`${label} is not a valid URL path.`);
519
+ }
520
+ if (url.origin !== OPS_PATH_BASE || url.search !== "" || url.hash !== "" || url.pathname !== transportPath) {
521
+ throw new OpsRouterError(`${label} is not a stable plain absolute path.`);
522
+ }
523
+ const slashCount = (path.match(/\//g) ?? []).length;
524
+ let decoded = path;
525
+ for (let depth = 0; depth < 8; depth++) {
526
+ let next;
527
+ try {
528
+ next = decodeURIComponent(decoded);
529
+ } catch {
530
+ throw new OpsRouterError(`${label} contains malformed percent encoding.`);
531
+ }
532
+ if (next.includes("\\") || (next.match(/\//g) ?? []).length !== slashCount || next.split("/").some((segment) => segment === "." || segment === "..")) {
533
+ throw new OpsRouterError(`${label} contains encoded path separators or dot segments.`);
534
+ }
535
+ if (next === decoded) {
536
+ return;
537
+ }
538
+ decoded = next;
539
+ }
540
+ throw new OpsRouterError(`${label} uses too many percent-encoding layers.`);
541
+ }
542
+ function assertCliCallableModulePath(moduleId, commandName, path) {
543
+ const unsupported = path.split("/").slice(1).find((segment) => segment === "*" || segment.includes("*") || (segment.startsWith(":") ? !/^:[A-Za-z0-9_]+$/.test(segment) : !/^[A-Za-z0-9._~-]+$/.test(segment)));
544
+ if (unsupported !== void 0) {
545
+ throw new OpsRouterError(
546
+ `Ops command "${moduleId}.${commandName}" path segment "${unsupported}" is not CLI-callable. Module routes support URL-safe static segments and simple :name parameters only; optional, wildcard, and custom-regex parameters are not supported.`
547
+ );
548
+ }
549
+ }
550
+ function assertCommand(moduleId, name, command) {
551
+ if (!COMMAND_NAME.test(name)) {
552
+ throw new OpsRouterError(
553
+ `Ops module "${moduleId}" has invalid command name "${name}". Use dot-separated alphanumeric names.`
554
+ );
555
+ }
556
+ assertText(`Ops command "${moduleId}.${name}" summary`, command?.summary);
557
+ if (!EFFECTS.has(command?.effect)) {
558
+ throw new OpsRouterError(
559
+ `Ops command "${moduleId}.${name}" has invalid effect ${JSON.stringify(command?.effect)}.`
560
+ );
561
+ }
562
+ if (!Array.isArray(command?.scopes) || command.scopes.length === 0 || command.scopes.some((scope) => typeof scope !== "string" || scope.trim().length === 0)) {
563
+ throw new OpsRouterError(`Ops command "${moduleId}.${name}" must declare at least one non-empty scope.`);
564
+ }
565
+ const route2 = command?.route;
566
+ if (!route2 || typeof route2.handler !== "function" || !route2.method || !route2.path) {
567
+ throw new OpsRouterError(`Ops command "${moduleId}.${name}" must carry a complete ops route.`);
568
+ }
569
+ assertStableModulePath(moduleId, name, route2.path);
570
+ assertCliCallableModulePath(moduleId, name, route2.path);
571
+ const modulePath = `${OPS_PATH_ROOT}/${moduleId}/`;
572
+ if (!route2.path.startsWith(modulePath)) {
573
+ throw new OpsRouterError(
574
+ `Ops command "${moduleId}.${name}" is at "${route2.path}", outside "${modulePath}".`
575
+ );
576
+ }
577
+ if (route2.path.split("/").includes("..")) {
578
+ throw new OpsRouterError(`Ops command "${moduleId}.${name}" path climbs out of its module namespace.`);
579
+ }
580
+ }
581
+ function defineOpsModule(module) {
582
+ if (!MODULE_ID.test(module?.id ?? "")) {
583
+ throw new OpsRouterError(
584
+ `Ops module id ${JSON.stringify(module?.id)} is invalid. Use lower-kebab-case.`
585
+ );
586
+ }
587
+ assertText(`Ops module "${module.id}" source`, module.source);
588
+ assertText(`Ops module "${module.id}" summary`, module.summary);
589
+ if (!CONTRACT_VERSION.test(module.contractVersion)) {
590
+ throw new OpsRouterError(
591
+ `Ops module "${module.id}" contractVersion must be a semantic version.`
592
+ );
593
+ }
594
+ if (!module.commands || typeof module.commands !== "object" || Array.isArray(module.commands)) {
595
+ throw new OpsRouterError(`Ops module "${module.id}" commands must be an object.`);
596
+ }
597
+ const signatures = /* @__PURE__ */ new Map();
598
+ const claimedRoutes = [];
599
+ for (const [name, command] of Object.entries(module.commands)) {
600
+ assertCommand(module.id, name, command);
601
+ const signature = `${command.route.method} ${command.route.path}`;
602
+ const existing = signatures.get(signature);
603
+ if (existing) {
604
+ throw new OpsRouterError(
605
+ `Ops module "${module.id}" commands "${existing}" and "${name}" both use ${signature}.`
606
+ );
607
+ }
608
+ signatures.set(signature, name);
609
+ const overlapping = claimedRoutes.find((claim) => claim.method === command.route.method && opsRoutePatternsOverlap(claim.path, command.route.path));
610
+ if (overlapping) {
611
+ throw new OpsRouterError(
612
+ `Ops module "${module.id}" commands "${overlapping.name}" and "${name}" have overlapping ${command.route.method} routes ("${overlapping.path}" and "${command.route.path}").`
613
+ );
614
+ }
615
+ claimedRoutes.push({
616
+ name,
617
+ method: command.route.method,
618
+ path: command.route.path
619
+ });
620
+ }
621
+ return module;
622
+ }
623
+
386
624
  // src/ops/create-ops-router.ts
387
625
  var OPS_PATH_PREFIX = "/_ops/";
388
626
  var OPS_MANIFEST_PATH = "/_ops/_manifest";
@@ -401,12 +639,12 @@ function assertOpsRoute(name, def) {
401
639
  }
402
640
  if (!def.path.startsWith(OPS_PATH_PREFIX)) {
403
641
  throw new OpsRouterError(
404
- `Ops route "${name}" is at "${def.path}", outside "${OPS_PATH_PREFIX}". Every ops route lives under the prefix so the surface stays recognizable and can never shadow an app route.`
642
+ `Ops route "${name}" is at "${def.path}", outside "${OPS_PATH_PREFIX}". Build ops routes with \`opsRoute\` rather than \`route\` \u2014 it applies the namespace, so the path a definition carries is only the part the app owns.`
405
643
  );
406
644
  }
407
645
  if (def.path === OPS_MANIFEST_PATH) {
408
646
  throw new OpsRouterError(
409
- `Ops route "${name}" claims "${OPS_MANIFEST_PATH}", which is reserved for the manifest.`
647
+ `Ops route "${name}" claims "${OPS_MANIFEST_PATH}", which is reserved for the manifest. The manifest is registered first, so this route would never answer.`
410
648
  );
411
649
  }
412
650
  }
@@ -417,29 +655,27 @@ function assertOpsName(name) {
417
655
  );
418
656
  }
419
657
  }
420
- function rebuildNestedRouter(name, router, auth) {
658
+ function rebuildNestedRouter(name, router, auth, inherited) {
421
659
  if (router._packageRouters?.length > 0) {
422
660
  throw new OpsRouterError(
423
661
  `Ops router "${name}" mounts package routers with .packages(). Their routes bypass the prefix check and the auth injection, so an ops surface cannot carry them.`
424
662
  );
425
663
  }
664
+ const handedDown = [...inherited, ...router._globalMiddlewares ?? []];
426
665
  let rebuilt = defineRouter(
427
- secureRoutes(router.routes, auth)
666
+ secureRoutes(router.routes, auth, handedDown)
428
667
  );
429
- if (router._globalMiddlewares?.length > 0) {
430
- rebuilt = rebuilt.use(router._globalMiddlewares);
431
- }
432
668
  if (router._contractVersion) {
433
669
  rebuilt = rebuilt.contractVersion(router._contractVersion);
434
670
  }
435
671
  return rebuilt;
436
672
  }
437
- function secureRoutes(routes, auth) {
673
+ function secureRoutes(routes, auth, inherited = []) {
438
674
  const secured = {};
439
675
  for (const [name, entry] of Object.entries(routes)) {
440
676
  assertOpsName(name);
441
677
  if (isRouter2(entry)) {
442
- secured[name] = rebuildNestedRouter(name, entry, auth);
678
+ secured[name] = rebuildNestedRouter(name, entry, auth, inherited);
443
679
  continue;
444
680
  }
445
681
  if (!isRouteDef2(entry)) {
@@ -448,7 +684,83 @@ function secureRoutes(routes, auth) {
448
684
  assertOpsRoute(name, entry);
449
685
  secured[name] = {
450
686
  ...entry,
451
- middlewares: [auth, ...entry.middlewares ?? []]
687
+ middlewares: [auth, ...inherited, ...entry.middlewares ?? []]
688
+ };
689
+ }
690
+ return secured;
691
+ }
692
+ function compileModules(modules, appCommands) {
693
+ const descriptors = [];
694
+ const commands = [];
695
+ const routes = {};
696
+ const moduleIds = /* @__PURE__ */ new Set();
697
+ const commandNames = new Set(appCommands.map((command) => command.name));
698
+ const routeSignatures = new Map(
699
+ appCommands.map((command) => [`${command.method} ${command.path}`, command.name])
700
+ );
701
+ for (const rawModule of modules) {
702
+ const module = defineOpsModule(rawModule);
703
+ if (moduleIds.has(module.id)) {
704
+ throw new OpsRouterError(`Two ops modules use id "${module.id}".`);
705
+ }
706
+ moduleIds.add(module.id);
707
+ descriptors.push({
708
+ id: module.id,
709
+ source: module.source,
710
+ contractVersion: module.contractVersion,
711
+ summary: module.summary
712
+ });
713
+ for (const [localName, definition] of Object.entries(module.commands)) {
714
+ const name = `${module.id}.${localName}`;
715
+ if (commandNames.has(name)) {
716
+ throw new OpsRouterError(`Two ops commands are named "${name}".`);
717
+ }
718
+ commandNames.add(name);
719
+ const method = definition.route.method;
720
+ const path = definition.route.path;
721
+ const signature = `${method} ${path}`;
722
+ const existing = routeSignatures.get(signature);
723
+ if (existing) {
724
+ throw new OpsRouterError(
725
+ `Ops commands "${existing}" and "${name}" both use ${signature}.`
726
+ );
727
+ }
728
+ const overlappingAppCommand = appCommands.find((command) => command.method === method && opsRoutePatternsOverlap(command.path, path));
729
+ if (overlappingAppCommand) {
730
+ throw new OpsRouterError(
731
+ `App ops command "${overlappingAppCommand.name}" at ${method} ${overlappingAppCommand.path} overlaps module command "${name}" at ${method} ${path}. Which one answers cannot depend on route registration order.`
732
+ );
733
+ }
734
+ routeSignatures.set(signature, name);
735
+ commands.push({
736
+ name,
737
+ module: module.id,
738
+ summary: definition.summary,
739
+ effect: definition.effect,
740
+ scopes: [...definition.scopes],
741
+ method,
742
+ path,
743
+ input: collectOpsCommands({ [localName]: definition.route })[0].input
744
+ });
745
+ routes[name] = { route: definition.route, scopes: definition.scopes };
746
+ }
747
+ }
748
+ descriptors.sort((a, b) => a.id.localeCompare(b.id));
749
+ commands.sort((a, b) => a.name.localeCompare(b.name));
750
+ return { descriptors, commands, routes };
751
+ }
752
+ function secureModuleRoutes(routes, auth, authorize) {
753
+ const secured = {};
754
+ for (const [name, definition] of Object.entries(routes)) {
755
+ assertOpsName(name);
756
+ assertOpsRoute(name, definition.route);
757
+ secured[name] = {
758
+ ...definition.route,
759
+ middlewares: [
760
+ auth,
761
+ authorize(...definition.scopes),
762
+ ...definition.route.middlewares ?? []
763
+ ]
452
764
  };
453
765
  }
454
766
  return secured;
@@ -459,18 +771,30 @@ function createOpsRouter(routes, options) {
459
771
  "createOpsRouter requires an auth middleware ({ auth: ... }). An ops surface reachable without authentication cannot be created."
460
772
  );
461
773
  }
774
+ const modules = options.modules ?? [];
775
+ if (modules.length > 0 && !options.authorize) {
776
+ throw new OpsRouterError(
777
+ "createOpsRouter requires an authorize scope factory when modules are mounted."
778
+ );
779
+ }
780
+ const appCommands = collectOpsCommands(routes);
781
+ const moduleSurface = compileModules(modules, appCommands);
782
+ const commands = [...appCommands, ...moduleSurface.commands].sort((a, b) => a.name.localeCompare(b.name));
462
783
  const manifest = {
463
784
  manifestVersion: 1,
464
- commands: collectOpsCommands(routes)
785
+ ...moduleSurface.descriptors.length > 0 ? { modules: moduleSurface.descriptors } : {},
786
+ commands
465
787
  };
466
788
  const secured = secureRoutes(routes, options.auth);
789
+ const securedModules = moduleSurface.descriptors.length > 0 ? secureModuleRoutes(moduleSurface.routes, options.auth, options.authorize) : {};
467
790
  const manifestRoute = route.get(OPS_MANIFEST_PATH).use([options.auth]).handler(async () => manifest);
468
791
  return defineRouter({
792
+ [OPS_MANIFEST_NAME]: manifestRoute,
469
793
  ...secured,
470
- [OPS_MANIFEST_NAME]: manifestRoute
794
+ ...securedModules
471
795
  });
472
796
  }
473
797
 
474
- export { OPS_MANIFEST_PATH, OPS_PATH_PREFIX, OpsRouterError, collectOpsCommands, createOpsRouter };
798
+ export { OPS_MANIFEST_PATH, OPS_PATH_PREFIX, OPS_PATH_ROOT, OpsRouterError, collectOpsCommands, createOpsRouter, defineOpsModule, opsRoute };
475
799
  //# sourceMappingURL=index.js.map
476
800
  //# sourceMappingURL=index.js.map