@jimhoyd/urlcode 0.4.0-alpha.1 → 0.4.0-alpha.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 (191) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +24 -8
  2. package/.claude/skills/urlcode-operations/SKILL.md +10 -16
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/README.md +75 -62
  5. package/ROADMAP.md +61 -16
  6. package/SECURITY.md +23 -8
  7. package/dist/BUILD-MANIFEST.json +38 -43
  8. package/dist/agents-guide.js +18 -18
  9. package/dist/build-static.js +134 -0
  10. package/dist/capabilities.js +85 -31
  11. package/dist/capability-query.js +0 -1
  12. package/dist/cli.js +23 -31
  13. package/dist/compliance-rules/baseline.js +2 -10
  14. package/dist/compliance-rules/privacy.js +5 -16
  15. package/dist/compliance-rules/shared.js +0 -2
  16. package/dist/compliance.js +6 -8
  17. package/dist/config.js +15 -8
  18. package/dist/context.js +9 -10
  19. package/dist/examples.js +2 -2
  20. package/dist/explain-cli.js +3 -3
  21. package/dist/explain.js +5 -6
  22. package/dist/extensions.js +61 -2
  23. package/dist/function-sources.js +34 -2
  24. package/dist/function-worker.js +3 -1
  25. package/dist/functions.js +84 -13
  26. package/dist/guest-api.js +29 -3
  27. package/dist/index.js +3 -6
  28. package/dist/manifest.js +5 -7
  29. package/dist/mcp.js +1 -1
  30. package/dist/observability.js +1 -21
  31. package/dist/policies/cache.js +8 -3
  32. package/dist/policy.js +28 -9
  33. package/dist/project-tests.js +3 -3
  34. package/dist/readiness.js +32 -9
  35. package/dist/router.js +5 -7
  36. package/dist/runtime.js +77 -58
  37. package/dist/sandbox.js +48 -0
  38. package/dist/scaffold.js +0 -0
  39. package/dist/scripts/operational-drills.js +12 -54
  40. package/dist/server.js +3 -29
  41. package/dist/tooling.js +1 -1
  42. package/dist/trusted-functions.js +210 -0
  43. package/dist/types/build-static.d.ts +43 -0
  44. package/dist/types/capabilities.d.ts +14 -5
  45. package/dist/types/compliance-rules/shared.d.ts +0 -2
  46. package/dist/types/compliance.d.ts +0 -3
  47. package/dist/types/config.d.ts +2 -1
  48. package/dist/types/context.d.ts +2 -1
  49. package/dist/types/examples.d.ts +1 -1
  50. package/dist/types/extensions.d.ts +55 -0
  51. package/dist/types/function-sources.d.ts +4 -0
  52. package/dist/types/functions.d.ts +48 -5
  53. package/dist/types/guest-api.d.ts +1 -0
  54. package/dist/types/index.d.ts +3 -6
  55. package/dist/types/manifest.d.ts +1 -3
  56. package/dist/types/observability.d.ts +1 -14
  57. package/dist/types/project-tests.d.ts +1 -2
  58. package/dist/types/readiness.d.ts +10 -3
  59. package/dist/types/router.d.ts +2 -1
  60. package/dist/types/runtime.d.ts +0 -27
  61. package/dist/types/sandbox.d.ts +12 -0
  62. package/dist/types/scaffold.d.ts +0 -2
  63. package/dist/types/server.d.ts +1 -4
  64. package/dist/types/tooling.d.ts +3 -3
  65. package/dist/types/trusted-functions.d.ts +29 -0
  66. package/dist/types/types.d.ts +14 -7
  67. package/dist/types/verify-deployment.d.ts +2 -2
  68. package/dist/types.js +17 -4
  69. package/dist/typescript-authoring.js +55 -17
  70. package/dist/verify-deployment.js +3 -3
  71. package/docs/AI-AUTHORING.md +104 -9
  72. package/docs/AWS.md +4 -4
  73. package/docs/BEST-PRACTICES.md +3 -2
  74. package/docs/CAPABILITIES.md +29 -16
  75. package/docs/CAPACITY.md +128 -31
  76. package/docs/CLOUDFLARE.md +1 -2
  77. package/docs/COMPLIANCE.md +6 -9
  78. package/docs/DEPLOYMENT-CHECKS.md +1 -1
  79. package/docs/EXTENSIONS.md +183 -11
  80. package/docs/FRAMEWORK.md +35 -19
  81. package/docs/FUNCTION-SECURITY.md +129 -32
  82. package/docs/INSTALL.md +0 -5
  83. package/docs/LOAD-TESTING.md +4 -4
  84. package/docs/MIDDLEWARE.md +27 -16
  85. package/docs/MONITORING.md +2 -19
  86. package/docs/NEXT-PHASE-PLAN.md +12 -4
  87. package/docs/NEXT-STEPS.md +259 -40
  88. package/docs/OBSERVABILITY.md +7 -16
  89. package/docs/OPEN-DECISIONS.md +212 -0
  90. package/docs/OPERATIONAL-PROOF.md +26 -30
  91. package/docs/OPERATIONS.md +23 -32
  92. package/docs/POLICIES.md +15 -4
  93. package/docs/PRERENDER.md +2 -2
  94. package/docs/PROJECT-DIRECTION.md +34 -9
  95. package/docs/README.md +13 -11
  96. package/docs/RELEASE-READINESS.md +49 -29
  97. package/docs/RELEASE-SECURITY.md +89 -3
  98. package/docs/RESILIENCE.md +16 -15
  99. package/docs/ROUTING.md +8 -10
  100. package/docs/SANDBOX-REVIEW.md +19 -6
  101. package/docs/SCAFFOLDING.md +0 -2
  102. package/docs/SECURITY-AUDIT.md +40 -0
  103. package/docs/SPECIFICATION.md +60 -26
  104. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
  105. package/docs/SPIKE-BUSINESS-SUITE.md +8 -0
  106. package/docs/SPIKE-CORE-LAYERING.md +337 -0
  107. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
  108. package/docs/SPIKE-EXTENSION-MODEL.md +2 -2
  109. package/docs/SPIKE-EXTENSIONS.md +5 -0
  110. package/docs/SPIKE-LAMBDA-COMPILE.md +4 -2
  111. package/docs/SPIKE-MONOREPO.md +322 -0
  112. package/docs/STARTERS.md +1 -1
  113. package/docs/STATIC.md +94 -0
  114. package/docs/TOOLING.md +13 -9
  115. package/docs/TUNNELS.md +0 -3
  116. package/docs/TYPESCRIPT-AUTHORING.md +27 -12
  117. package/docs/TYPESCRIPT.md +25 -4
  118. package/docs/USABILITY-REVIEW.md +7 -1
  119. package/docs/VERCEL.md +4 -5
  120. package/docs/VERSION-ALIGNMENT.md +205 -0
  121. package/docs/YAML-GUIDE.md +0 -3
  122. package/docs/YAML-REFERENCE.md +16 -6
  123. package/docs/policies/cache.md +13 -0
  124. package/examples/assets/example.yaml +1 -1
  125. package/examples/aws/example.yaml +1 -1
  126. package/examples/cloudflare/example.yaml +1 -1
  127. package/examples/conditions/example.yaml +1 -1
  128. package/examples/cookbook/example.yaml +1 -1
  129. package/examples/cookbook/middleware/bucket.mjs +12 -2
  130. package/examples/cookbook/middleware/locale.mjs +7 -3
  131. package/examples/egress/example.yaml +1 -1
  132. package/examples/extensions/example.yaml +1 -1
  133. package/examples/prerender/README.md +2 -2
  134. package/examples/prerender/example.yaml +1 -1
  135. package/examples/provider-conformance/example.yaml +1 -1
  136. package/examples/vercel/example.yaml +1 -1
  137. package/llms-full.txt +594 -219
  138. package/llms.txt +23 -12
  139. package/package.json +10 -3
  140. package/packaging/claude-plugin/.claude-plugin/plugin.json +1 -1
  141. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +24 -8
  142. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +10 -16
  143. package/recipes/authenticated-json-api/recipe.yaml +1 -1
  144. package/recipes/contact-form/recipe.yaml +1 -1
  145. package/recipes/cors-api/recipe.yaml +1 -1
  146. package/recipes/health-page/recipe.yaml +1 -1
  147. package/recipes/json-api/recipe.yaml +1 -1
  148. package/recipes/middleware/middleware/bucket.mjs +12 -2
  149. package/recipes/middleware/middleware/locale.mjs +7 -3
  150. package/recipes/middleware/recipe.yaml +1 -1
  151. package/recipes/protected-download/recipe.yaml +1 -1
  152. package/recipes/redirect/recipe.yaml +1 -1
  153. package/recipes/static-plus-api/recipe.yaml +1 -1
  154. package/recipes/typescript/README.md +2 -1
  155. package/recipes/typescript/recipe.yaml +1 -1
  156. package/recipes/webhook-receiver/README.md +5 -1
  157. package/recipes/webhook-receiver/recipe.yaml +2 -1
  158. package/recipes/webhook-receiver/urlcode.yaml +7 -0
  159. package/schemas/recipe.schema.json +4 -3
  160. package/schemas/urlcode.schema.json +14 -41
  161. package/skills/urlcode/SKILL.md +29 -8
  162. package/starters/default/AGENTS.md +18 -18
  163. package/starters/default/urlcode.yaml +0 -1
  164. package/dist/link-api.js +0 -136
  165. package/dist/link-cli.js +0 -141
  166. package/dist/link-events.js +0 -76
  167. package/dist/link-records.js +0 -31
  168. package/dist/link-store-worker.js +0 -150
  169. package/dist/link-store.js +0 -250
  170. package/dist/management-policy.js +0 -40
  171. package/dist/sqlite-version.js +0 -6
  172. package/dist/types/link-api.d.ts +0 -30
  173. package/dist/types/link-cli.d.ts +0 -37
  174. package/dist/types/link-events.d.ts +0 -27
  175. package/dist/types/link-records.d.ts +0 -11
  176. package/dist/types/link-store-worker.d.ts +0 -1
  177. package/dist/types/link-store.d.ts +0 -130
  178. package/dist/types/management-policy.d.ts +0 -8
  179. package/dist/types/sqlite-version.d.ts +0 -1
  180. package/docs/DYNAMIC-LINKS.md +0 -61
  181. package/docs/MANAGEMENT-SECURITY.md +0 -82
  182. package/docs/links/cli.md +0 -110
  183. package/docs/links/limits.md +0 -175
  184. package/docs/links/management-api.md +0 -80
  185. package/docs/links/pools.md +0 -75
  186. package/docs/links/setup.md +0 -135
  187. package/docs/yaml/links.md +0 -30
  188. package/examples/live-links/README.md +0 -11
  189. package/examples/live-links/example.yaml +0 -21
  190. package/examples/live-links/tests/requests.json +0 -6
  191. package/examples/live-links/urlcode.yaml +0 -16
@@ -1,12 +1,28 @@
1
1
  import { Worker } from 'node:worker_threads';
2
- import type { FunctionRoute, FunctionSources } from './function-sources.ts';
2
+ import type { FunctionDefinition, FunctionRoute, FunctionSources } from './function-sources.ts';
3
3
  import type { HandlerResult, HeaderPair } from './http-response.ts';
4
4
  import type { ParameterValue, RequestContext } from './match.ts';
5
5
  import type { LogFn } from './types.ts';
6
6
  import type { GuestRequestPayload } from './guest-api.ts';
7
7
  export type { FunctionDefinition, FunctionRoute } from './function-sources.ts';
8
8
  export type { GuestRequestPayload, GuestResponsePayload } from './guest-api.ts';
9
- export interface FunctionPoolOptions {
9
+ /** A module entry point the sandbox must load: an absolute source file path
10
+ * (already resolved and validated, e.g. via `functionFile()`) plus which
11
+ * export of it needs to be reachable. The same shape a `FunctionDefinition`
12
+ * already uses for `function`/`middleware` routes. */
13
+ export type SandboxEntry = FunctionDefinition;
14
+ /** What one `SandboxPool.execute()` call invokes: the same `{source, export}`
15
+ * shape as a `SandboxEntry`, naming one of the pool's declared entries. */
16
+ export type SandboxTarget = FunctionDefinition;
17
+ /** `entry` runs last (the route's `function`/handler); `chain` runs first, in
18
+ * order, each with `(request, context, next)` — the same wrap/middleware
19
+ * semantics `__invokePipeline` already gives sandboxed routes. Neither is
20
+ * required: an empty invocation with a `native` reply just returns it. */
21
+ export interface SandboxInvocation {
22
+ entry?: SandboxTarget | undefined;
23
+ chain?: SandboxTarget[] | undefined;
24
+ }
25
+ export interface SandboxPoolOptions {
10
26
  root?: string | undefined;
11
27
  snapshot?: FunctionSources | undefined;
12
28
  workers?: number | undefined;
@@ -14,6 +30,7 @@ export interface FunctionPoolOptions {
14
30
  maxBytes?: number | undefined;
15
31
  log?: LogFn | undefined;
16
32
  }
33
+ export type FunctionPoolOptions = SandboxPoolOptions;
17
34
  export interface FunctionWorkerData {
18
35
  sources: Record<string, string>;
19
36
  dependencies: Record<string, string[]>;
@@ -52,6 +69,7 @@ export type FunctionWorkerMessage = {
52
69
  headers: HeaderPair[];
53
70
  body: Uint8Array;
54
71
  nativeBody: boolean;
72
+ contentLength?: number;
55
73
  } | {
56
74
  id: string;
57
75
  error: true;
@@ -67,9 +85,9 @@ interface Slot {
67
85
  ready: boolean;
68
86
  pending: Pending | null;
69
87
  }
70
- export declare class FunctionPool {
88
+ export declare class SandboxPool {
71
89
  root: string | undefined;
72
- routes: FunctionRoute[];
90
+ entries: SandboxEntry[];
73
91
  preparedSnapshot: FunctionSources | undefined;
74
92
  snapshot: FunctionSources | undefined;
75
93
  restarts: Map<number, number>;
@@ -81,12 +99,37 @@ export declare class FunctionPool {
81
99
  size: number;
82
100
  slots: (Slot | undefined)[];
83
101
  closed: boolean;
84
- constructor(routes: FunctionRoute[], { root, snapshot, workers, timeoutMs, maxBytes, log }?: FunctionPoolOptions);
102
+ constructor(entries: SandboxEntry[], { root, snapshot, workers, timeoutMs, maxBytes, log }?: SandboxPoolOptions);
85
103
  start(): Promise<this>;
86
104
  spawn(index: number): Promise<void>;
87
105
  report(status: string, index: number, extra?: object): void;
88
106
  scheduleRespawn(index: number): void;
89
107
  get healthy(): boolean;
108
+ /** `invocation.entry` runs last (chain-wrapped), `invocation.chain` first, in
109
+ * declared order — the same `__invokePipeline` wrap/middleware discipline
110
+ * (`next()` callable at most once) the sandboxed route path already
111
+ * enforces; there is no second dispatch mechanism for this. Every entry and
112
+ * chain source named here must already be one of this pool's declared
113
+ * `entries` (constructor), or the worker's own module allowlist denies it. */
114
+ execute(invocation: SandboxInvocation, request: GuestRequestPayload, context: FunctionContext, native: HandlerResult | undefined): Promise<FunctionResult>;
115
+ close(): Promise<void>;
116
+ }
117
+ export declare class FunctionPool {
118
+ routes: FunctionRoute[];
119
+ private pool;
120
+ constructor(routes: FunctionRoute[], options?: FunctionPoolOptions);
121
+ start(): Promise<this>;
90
122
  execute(route: FunctionRoute, request: GuestRequestPayload, context: FunctionContext, native: HandlerResult | undefined): Promise<FunctionResult>;
123
+ scheduleRespawn(index: number): void;
91
124
  close(): Promise<void>;
125
+ get healthy(): boolean;
126
+ get restarts(): Map<number, number>;
127
+ get restartTimers(): Set<NodeJS.Timeout>;
128
+ get slots(): (Slot | undefined)[];
129
+ get size(): number;
130
+ get closed(): boolean;
131
+ get snapshot(): FunctionSources | undefined;
132
+ get log(): LogFn;
133
+ get timeoutMs(): number;
134
+ get maxBytes(): number;
92
135
  }
@@ -12,5 +12,6 @@ export interface GuestResponsePayload {
12
12
  headers: HeaderPair[];
13
13
  body: string;
14
14
  nativeBody?: boolean;
15
+ contentLength?: number;
15
16
  }
16
17
  export declare const guestBootstrap: string;
@@ -1,13 +1,8 @@
1
1
  export { createRuntime } from './runtime.ts';
2
- export type { Runtime, RuntimeOptions, RuntimeRequest, RequestTrace, LinkReader, LinkStoreBinding, HostPlugin, Observer, TestPlan } from './runtime.ts';
2
+ export type { Runtime, RuntimeOptions, RuntimeRequest, RequestTrace, HostPlugin, Observer, TestPlan } from './runtime.ts';
3
3
  export { startServer } from './server.ts';
4
4
  export type { Server, ServerOptions } from './server.ts';
5
5
  export { loadDocument, validateDocument, parseYaml } from './config.ts';
6
- export { openLinkStore } from './link-store.ts';
7
- export type { LinkStore, LinkRow, LinkStoreOptions } from './link-store.ts';
8
- export { startLinkApi } from './link-api.ts';
9
- export type { LinkApi, LinkApiOptions } from './link-api.ts';
10
- export type { LinkEvent, LinkObserverOptions, LinkObserverStats } from './link-events.ts';
11
6
  export { events as observabilityEvents, validateObservers, createObserverSink, createMetrics, renderPrometheus } from './observability.ts';
12
7
  export { getCapabilities, routeCapabilities, analyzeProjectCapabilities, analyzeCompiledCapabilities, assertTargetCompatibility, normalizeCapabilityTarget } from './capabilities.ts';
13
8
  export { capabilityDetails } from './capabilities.ts';
@@ -35,6 +30,8 @@ export { normalizeMatch, assertDisjointMatches, matchesRoute } from './condition
35
30
  export type { RouteMatch, ConditionRequest } from './conditions.ts';
36
31
  export { buildCloudflare } from './build-cloudflare.ts';
37
32
  export type { BuildOptions as CloudflareBuildOptions, BuildReport as CloudflareBuildReport } from './build-cloudflare.ts';
33
+ export { buildStatic } from './build-static.ts';
34
+ export type { BuildOptions as StaticBuildOptions, BuildReport as StaticBuildReport, StaticRedirect, StaticObject, RedirectManifest, ObjectManifest } from './build-static.ts';
38
35
  export { runProjectTests } from './project-tests.ts';
39
36
  export type { ProjectTestOptions, ProjectTestResult } from './project-tests.ts';
40
37
  export { scaffoldProject } from './scaffold.ts';
@@ -1,7 +1,7 @@
1
1
  import type { CapabilityName, CapabilityTarget } from './capabilities.ts';
2
2
  import type { InspectOptions } from './tooling.ts';
3
3
  import type { RouteExplanation } from './explain.ts';
4
- export declare const MANIFEST_SCHEMA_VERSION = 1;
4
+ export declare const MANIFEST_SCHEMA_VERSION = 2;
5
5
  export interface ManifestRoute {
6
6
  path: string;
7
7
  methods: string[];
@@ -63,8 +63,6 @@ export interface Manifest {
63
63
  signals: string[];
64
64
  };
65
65
  extensions: string[];
66
- linkStores: string[];
67
- dynamicLinks: boolean;
68
66
  };
69
67
  functions: ManifestModule[];
70
68
  middleware: ManifestModule[];
@@ -4,12 +4,8 @@ export declare const events: Readonly<{
4
4
  reload: readonly string[];
5
5
  watch: readonly string[];
6
6
  function_worker: readonly string[];
7
- link_store_worker: readonly string[];
8
- link_request: readonly string[];
9
- link_observer: readonly string[];
10
7
  logs_dropped: readonly string[];
11
8
  observer: readonly string[];
12
- management_request: readonly string[];
13
9
  throttle: readonly string[];
14
10
  agents: readonly string[];
15
11
  cache: readonly string[];
@@ -62,21 +58,12 @@ export interface MetricsSnapshot {
62
58
  healthySlots: number;
63
59
  slots: number;
64
60
  };
65
- linkStoreWorkers: {
66
- started: number;
67
- restarts: number;
68
- };
69
61
  policies: {
70
62
  throttle: Counters;
71
63
  agents: Counters;
72
64
  cache: Counters;
73
65
  };
74
66
  signals: Counters;
75
- linkRequests: Counters;
76
- linkObserver: {
77
- failed: number;
78
- dropped: number;
79
- };
80
67
  logsDropped: number;
81
68
  observers: {
82
69
  errors: number;
@@ -99,7 +86,7 @@ export type ObserverSink = ((event: ObserverEvent, context?: RecordContext) => v
99
86
  close(): Promise<void>;
100
87
  };
101
88
  export declare function validateObservers(observers?: unknown): Observer[];
102
- export declare const SNAPSHOT_VERSION = 1;
89
+ export declare const SNAPSHOT_VERSION = 2;
103
90
  export declare function createMetrics(): Metrics;
104
91
  export declare function createObserverSink(observers?: unknown, fallbackLog?: (event: ObserverEvent) => void, metrics?: Metrics): ObserverSink;
105
92
  export declare function renderPrometheus(snapshot: Partial<MetricsSnapshot>): string;
@@ -5,11 +5,10 @@ export interface ProjectTestOptions {
5
5
  plugins?: ServerOptions['plugins'];
6
6
  log?: LogFn | undefined;
7
7
  permissions?: ServerOptions['permissions'];
8
- linkStore?: ServerOptions['linkStore'];
9
8
  origin?: string | undefined;
10
9
  }
11
10
  export interface ProjectTestResult {
12
11
  total: number;
13
12
  failed: number;
14
13
  }
15
- export declare function runProjectTests(project: string, { log, permissions, linkStore, origin, extensions, plugins }?: ProjectTestOptions): Promise<ProjectTestResult>;
14
+ export declare function runProjectTests(project: string, { log, permissions, origin, extensions, plugins }?: ProjectTestOptions): Promise<ProjectTestResult>;
@@ -4,10 +4,13 @@ import type { CompiledRedirect, CompiledRoute, LogFn, PlanInventoryEntry, Policy
4
4
  import type { ComplianceOptions, ComplianceReport } from './compliance.ts';
5
5
  import type { CompiledRoutes } from './match.ts';
6
6
  export type { RouteState } from './types.ts';
7
- export type HandlerName = 'extension' | 'proxy' | 'conditional' | 'redirect' | 'function' | 'page' | 'static' | 'download' | 'respond' | 'link';
7
+ export type HandlerName = 'extension' | 'proxy' | 'conditional' | 'redirect' | 'function' | 'page' | 'static' | 'download' | 'respond';
8
8
  /** One configured route as the inventory reports it: a PlanInventoryEntry with the handler kind named. */
9
9
  export interface RouteInventory extends PlanInventoryEntry {
10
10
  handler: HandlerName | undefined;
11
+ /** Non-blocking `audit` observations about this route (e.g. a webhook-shaped
12
+ * route with no declared `sandbox`/`sandboxReason`); never affects `ready`. */
13
+ advisories?: string[];
11
14
  }
12
15
  /** One request case: a generated probe or a `tests/requests.json` fixture. */
13
16
  export interface RequestCase {
@@ -40,7 +43,6 @@ export interface AuditableApp {
40
43
  address: AddressInfo;
41
44
  root: string;
42
45
  testPlan(): ProjectPlan & {
43
- dynamicLinks?: boolean;
44
46
  policies?: Record<string, PolicyInventory>;
45
47
  };
46
48
  }
@@ -51,7 +53,6 @@ export interface AuditOptions {
51
53
  compliance?: ComplianceOptions | undefined;
52
54
  }
53
55
  export interface AuditReport {
54
- dynamicLinks: boolean | undefined;
55
56
  elapsedMs: number;
56
57
  ready: boolean;
57
58
  counts: {
@@ -74,6 +75,12 @@ export interface AuditReport {
74
75
  }[];
75
76
  policies: Record<string, PolicyInventory>;
76
77
  compliance: ComplianceReport | null;
78
+ /** Non-blocking `audit` observations, e.g. a route that looks webhook-shaped
79
+ * but declares neither `sandbox: true` nor `sandboxReason`. Never affects `ready`. */
80
+ advisories: {
81
+ route: string;
82
+ message: string;
83
+ }[];
77
84
  }
78
85
  export interface BenchmarkOptions {
79
86
  requests?: number | undefined;
@@ -1,3 +1,4 @@
1
+ import type { RuntimeExtension } from './extensions.ts';
1
2
  import type { CompiledRouteTable, LoadedDocument } from './types.ts';
2
3
  export { parseTarget, matchRoute, contextFor, resolveValue, redirectLocation } from './match.ts';
3
4
  /** The grants compileRoutes consults: a validated OperatorPolicy (policy.ts) or nothing, which denies every binding. */
@@ -8,4 +9,4 @@ export interface BindingPermissions {
8
9
  secrets?: string[];
9
10
  }>;
10
11
  }
11
- export declare function compileRoutes(loaded: LoadedDocument, bindings: Record<string, string | undefined>, permissions?: BindingPermissions, projectSha256?: string): Promise<CompiledRouteTable>;
12
+ export declare function compileRoutes(loaded: LoadedDocument, bindings: Record<string, string | undefined>, permissions?: BindingPermissions, projectSha256?: string, extensions?: readonly Pick<RuntimeExtension, 'name' | 'cacheSensitive'>[]): Promise<CompiledRouteTable>;
@@ -2,34 +2,15 @@ import type { RuntimeExtension } from './extensions.ts';
2
2
  import type { EgressDependencies } from './egress.ts';
3
3
  import type { ProjectPlan } from './readiness.ts';
4
4
  import type { OperatorPolicy } from './policy.ts';
5
- import type { LinkStoreOptions } from './link-store.ts';
6
5
  import type { Plugin } from './plugins.ts';
7
6
  import type { MetricsSnapshot, Observer } from './observability.ts';
8
7
  import type { HandlerResult, HeaderPair } from './http-response.ts';
9
8
  import type { LogFn, PolicyInventory, TargetName } from './types.ts';
10
- /** A stored link as a link store returns it; the runtime validates the fields it uses. */
11
- export interface LinkLookup {
12
- url?: unknown;
13
- status?: unknown;
14
- enabled?: unknown;
15
- expires?: unknown;
16
- }
17
- /** What a `linkStores` binding must provide: a reader and, optionally, its health. */
18
- export interface LinkReader {
19
- get(collection: string, code: string): Promise<LinkLookup | null | undefined>;
20
- readonly readHealthy?: boolean;
21
- readonly healthy?: boolean;
22
- }
23
- /** An operator-owned SQLite link store the runtime opens read-only for one collection. */
24
- export interface LinkStoreBinding extends LinkStoreOptions {
25
- collection: string;
26
- }
27
9
  export type { OperatorPolicy } from './policy.ts';
28
10
  /** An operator plugin (src/plugins.ts). */
29
11
  export type HostPlugin = Plugin;
30
12
  export type { Observer, MetricsSnapshot } from './observability.ts';
31
13
  export interface TestPlan extends ProjectPlan {
32
- dynamicLinks: boolean;
33
14
  policies: Record<string, PolicyInventory>;
34
15
  }
35
16
  export interface RuntimeOptions {
@@ -42,8 +23,6 @@ export interface RuntimeOptions {
42
23
  local?: boolean | undefined;
43
24
  environment?: NodeJS.ProcessEnv | undefined;
44
25
  permissions?: OperatorPolicy | undefined;
45
- linkStore?: LinkStoreBinding | undefined;
46
- linkStores?: Record<string, LinkReader> | undefined;
47
26
  target?: TargetName | undefined;
48
27
  plugins?: HostPlugin[] | undefined;
49
28
  workers?: number | undefined;
@@ -57,16 +36,10 @@ export interface RuntimeOptions {
57
36
  only?: readonly string[] | undefined;
58
37
  }
59
38
  /** Per-request facts the host may read after handle() settles; never request text. */
60
- export interface LinkTrace {
61
- collection: string;
62
- code: string | null;
63
- result: string;
64
- }
65
39
  export interface RequestTrace {
66
40
  route?: string;
67
41
  probe?: boolean;
68
42
  client?: string | null;
69
- link?: LinkTrace;
70
43
  }
71
44
  export interface RuntimeRequest {
72
45
  target: string;
@@ -0,0 +1,12 @@
1
+ export { SandboxPool } from './functions.ts';
2
+ export type { SandboxEntry, SandboxTarget, SandboxInvocation, SandboxPoolOptions, FunctionContext, FunctionResult, } from './functions.ts';
3
+ export type { GuestRequestPayload, GuestResponsePayload } from './guest-api.ts';
4
+ export type { HandlerResult, HeaderPair } from './http-response.ts';
5
+ /**
6
+ * Resolves a project-relative hook source string the same way a native
7
+ * `function`/`middleware` route's `source` is resolved (`.mjs`/`.js` only, no
8
+ * path traversal outside the project root) into the absolute path
9
+ * `SandboxPool`'s entries and `execute()` targets expect. `root` must be the
10
+ * project's resolved directory (`ExtensionActivation.root`, never `cwd()`).
11
+ */
12
+ export { functionFile } from './config.ts';
@@ -1,11 +1,9 @@
1
1
  export interface Unresolved {
2
2
  path?: string;
3
3
  reason: string;
4
- collection?: string;
5
4
  }
6
5
  export interface ScaffoldReport {
7
6
  dryRun: boolean;
8
- dynamicLinks: boolean;
9
7
  created: string[];
10
8
  preserved: string[];
11
9
  unresolved: Unresolved[];
@@ -1,7 +1,6 @@
1
1
  import http from 'node:http';
2
2
  import type { AddressInfo } from 'node:net';
3
3
  import type { RuntimeOptions, TestPlan } from './runtime.ts';
4
- import type { LinkObserverStats } from './link-events.ts';
5
4
  import type { MetricsSnapshot, Observer } from './observability.ts';
6
5
  export interface ServerOptions extends Omit<RuntimeOptions, 'observers'> {
7
6
  project?: string | undefined;
@@ -13,7 +12,6 @@ export interface ServerOptions extends Omit<RuntimeOptions, 'observers'> {
13
12
  maxInFlightHealthRequests?: number | undefined;
14
13
  requestLog?: string | undefined;
15
14
  trustRequestId?: boolean | undefined;
16
- linkEvents?: unknown;
17
15
  trustedProxies?: string | string[] | undefined;
18
16
  observers?: Observer[] | undefined;
19
17
  metrics?: boolean | undefined;
@@ -25,7 +23,6 @@ export interface Server {
25
23
  address: AddressInfo;
26
24
  root: string;
27
25
  testPlan(): TestPlan;
28
- linkEventStats(): LinkObserverStats | undefined;
29
26
  metrics(): MetricsSnapshot;
30
27
  readonly observers: {
31
28
  name: string;
@@ -34,4 +31,4 @@ export interface Server {
34
31
  origin: string;
35
32
  close(): Promise<void>;
36
33
  }
37
- export declare function startServer({ project, host, port, watch, local, log, maxBodyBytes, maxInFlightRequests, maxInFlightHealthRequests, requestLog, trustRequestId, origin, linkEvents, trustedProxies, observers, metrics, metricsIntervalMs, ...runtimeOptions }?: ServerOptions): Promise<Server>;
34
+ export declare function startServer({ project, host, port, watch, local, log, maxBodyBytes, maxInFlightRequests, maxInFlightHealthRequests, requestLog, trustRequestId, origin, trustedProxies, observers, metrics, metricsIntervalMs, ...runtimeOptions }?: ServerOptions): Promise<Server>;
@@ -39,14 +39,14 @@ export declare function inspectProject(project: string, options?: InspectOptions
39
39
  path: string;
40
40
  methods: string[];
41
41
  enabled: boolean;
42
- capabilities: ("function" | "link" | "expires" | "middleware" | "extension" | "proxy" | "signals" | "conditional" | "methods" | "enabled" | "parameters" | "redirect" | "page" | "download" | "static" | "respond" | "dynamicLinks" | "policies.extensions" | "conditions" | "request.body" | "response.headers" | "bindings" | "policies.agents" | "policies.security" | "policies.cache" | "policies.compression" | "policies.throttle")[];
42
+ capabilities: ("function" | "expires" | "middleware" | "extension" | "proxy" | "signals" | "conditional" | "methods" | "enabled" | "parameters" | "redirect" | "page" | "download" | "static" | "respond" | "policies.extensions" | "conditions" | "request.body" | "response.headers" | "bindings" | "policies.agents" | "policies.security" | "policies.cache" | "policies.compression" | "policies.throttle")[];
43
43
  }[];
44
44
  compatibility: {
45
45
  offset: number;
46
46
  limit: number;
47
47
  hasMore: boolean;
48
48
  issues: import("./capabilities.ts").CapabilityRequirement[];
49
- target: "vercel" | "aws" | "cloudflare" | "self-hosted";
49
+ target: "vercel" | "aws" | "cloudflare" | "static" | "self-hosted";
50
50
  compatible: boolean;
51
51
  deployment: "local-runtime" | "unverified";
52
52
  requirementCount: number;
@@ -58,7 +58,7 @@ export declare function validateProject(project: string, options?: InspectOption
58
58
  projectSha256: string;
59
59
  routeCount: number;
60
60
  compatibility: {
61
- target: "vercel" | "aws" | "cloudflare" | "self-hosted";
61
+ target: "vercel" | "aws" | "cloudflare" | "static" | "self-hosted";
62
62
  compatible: boolean;
63
63
  deployment: "local-runtime" | "unverified";
64
64
  requirementCount: number;
@@ -0,0 +1,29 @@
1
+ import type { FunctionRoute } from './function-sources.ts';
2
+ import type { FunctionContext, FunctionResult } from './functions.ts';
3
+ import type { GuestRequestPayload } from './guest-api.ts';
4
+ import type { HandlerResult } from './http-response.ts';
5
+ import type { LogFn } from './types.ts';
6
+ export interface TrustedFunctionsOptions {
7
+ timeoutMs?: number | undefined;
8
+ maxBytes?: number | undefined;
9
+ log?: LogFn | undefined;
10
+ }
11
+ interface TrustedDefinition {
12
+ source: string;
13
+ export: string;
14
+ }
15
+ export type TrustedRoute = FunctionRoute<TrustedDefinition>;
16
+ export declare class TrustedFunctions {
17
+ timeoutMs: number;
18
+ maxBytes: number;
19
+ log: LogFn;
20
+ private readonly epoch;
21
+ constructor({ timeoutMs, maxBytes, log }?: TrustedFunctionsOptions);
22
+ start(routes: TrustedRoute[]): Promise<this>;
23
+ private loadExport;
24
+ execute(route: TrustedRoute, request: GuestRequestPayload, context: FunctionContext, native: HandlerResult | undefined): Promise<FunctionResult>;
25
+ private readBody;
26
+ private invoke;
27
+ close(): Promise<void>;
28
+ }
29
+ export {};
@@ -42,10 +42,6 @@ export type AuthoredRouteConfig = Omit<RouteConfig, 'function' | 'middleware'> &
42
42
  function?: string | FunctionConfig;
43
43
  middleware?: (string | MiddlewareConfig)[];
44
44
  };
45
- export interface LinkConfig {
46
- collection: string;
47
- code: ValueRef;
48
- }
49
45
  export interface PageConfig {
50
46
  file: string;
51
47
  contentType?: string;
@@ -151,6 +147,8 @@ export interface RouteAuthConfig {
151
147
  export interface RouteConfig {
152
148
  extension?: string;
153
149
  auth?: true | RouteAuthConfig;
150
+ /** Route-level `cache` short form: the same object accepted by `policies.cache`, expanded to it before anything else reads the project. */
151
+ cache?: CacheConfig;
154
152
  proxy?: ProxyConfig;
155
153
  signals?: SignalConfig[];
156
154
  match?: RouteMatch;
@@ -159,6 +157,18 @@ export interface RouteConfig {
159
157
  enabled?: boolean;
160
158
  expires?: string;
161
159
  description?: string;
160
+ /** Opt into the isolated QuickJS/WASM worker pool for this route's `function`/`middleware`
161
+ * chain (docs/FUNCTION-SECURITY.md). Default false: trusted, in-process, unsandboxed
162
+ * execution (docs/SPIKE-DEFAULT-TRUST-MODEL.md). Applies uniformly to the whole
163
+ * chain — `function` and any `middleware` on the same route run in the same mode. */
164
+ sandbox?: boolean;
165
+ /** Optional, human-authored justification for this route's sandbox decision — why it
166
+ * needs isolation when `sandbox: true`, or why it is safe to trust when it is not.
167
+ * Parsed and schema-validated (max 500 characters, schemas/urlcode.schema.json), stored
168
+ * on the compiled route and surfaced by `explain`/`context`/manifest next to `sandbox`.
169
+ * Never inferred or enforced: the trust decision remains the author's judgment call
170
+ * (docs/AI-AUTHORING.md, "Deciding when a route needs sandbox: true"). */
171
+ sandboxReason?: string;
162
172
  parameters?: ParameterConfig[];
163
173
  redirect?: RedirectConfig;
164
174
  function?: FunctionConfig;
@@ -175,7 +185,6 @@ export interface RouteConfig {
175
185
  };
176
186
  respond?: RespondSpec;
177
187
  middleware?: MiddlewareConfig[];
178
- link?: LinkConfig;
179
188
  policies?: PoliciesConfig;
180
189
  /** Set by site.ts on a route it generated (`site.<key>`); never declared in YAML. */
181
190
  generated?: string;
@@ -185,7 +194,6 @@ export interface ProjectDocument {
185
194
  extensions?: Record<string, ExtensionDeclaration>;
186
195
  routes: Record<string, RouteConfig>;
187
196
  includes?: string[];
188
- dynamicLinks?: boolean;
189
197
  policies?: PoliciesConfig;
190
198
  profiles?: Record<string, PolicyLayer>;
191
199
  site?: SiteConfig;
@@ -384,6 +392,5 @@ export interface TestPlan {
384
392
  inventory: PlanInventoryEntry[];
385
393
  cases: unknown[];
386
394
  resolve?(path: string): string | undefined;
387
- dynamicLinks?: boolean;
388
395
  policies?: Record<string, PolicyInventory>;
389
396
  }
@@ -12,7 +12,7 @@ export interface VerifyFinding {
12
12
  expected?: string;
13
13
  observed?: string;
14
14
  }
15
- export interface VerifyOptions extends Pick<RuntimeOptions, 'permissions' | 'linkStore'> {
15
+ export interface VerifyOptions extends Pick<RuntimeOptions, 'permissions'> {
16
16
  target: string;
17
17
  origin?: string | undefined;
18
18
  expectRoutes?: number | undefined;
@@ -44,4 +44,4 @@ export interface VerifyReport {
44
44
  compliance: ComplianceReport | null;
45
45
  }
46
46
  export declare const failLevels: readonly FailOn[];
47
- export declare function verifyDeployment(project: string, { target, origin, expectRoutes, timeoutMs, expectMetrics, failOn, compliance, complianceWarn, log, permissions, linkStore }: VerifyOptions): Promise<VerifyReport>;
47
+ export declare function verifyDeployment(project: string, { target, origin, expectRoutes, timeoutMs, expectMetrics, failOn, compliance, complianceWarn, log, permissions }: VerifyOptions): Promise<VerifyReport>;
package/dist/types.js CHANGED
@@ -34,7 +34,6 @@
34
34
 
35
35
  /** A route as YAML may spell it before normalization: `function` and middleware entries may be short-form module paths. */
36
36
 
37
-
38
37
 
39
38
 
40
39
 
@@ -67,19 +66,33 @@
67
66
 
68
67
 
69
68
 
69
+
70
+
70
71
 
71
72
 
72
73
 
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
73
86
 
74
87
 
75
88
 
76
89
 
77
-
90
+
78
91
 
79
92
 
80
93
 
81
94
 
82
-
95
+
83
96
 
84
97
 
85
98
  /** What config.ts returns: the entry document, the merged route table and the files it came from. */
@@ -192,5 +205,5 @@
192
205
 
193
206
 
194
207
 
195
-
208
+
196
209