@jimhoyd/urlcode 0.3.0 → 0.4.0-alpha.1

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 (326) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +106 -0
  2. package/.claude/skills/urlcode-operations/SKILL.md +114 -0
  3. package/.claude-plugin/marketplace.json +18 -0
  4. package/CONTRIBUTING.md +30 -2
  5. package/README.md +157 -230
  6. package/ROADMAP.md +85 -2
  7. package/SECURITY.md +8 -1
  8. package/dist/BUILD-MANIFEST.json +62 -32
  9. package/dist/adapters.js +4 -23
  10. package/dist/agent-lists.js +1 -1
  11. package/dist/agents-guide.js +113 -0
  12. package/dist/authoring-files.js +60 -0
  13. package/dist/authoring.js +11 -1
  14. package/dist/aws.js +4 -3
  15. package/dist/build-cloudflare.js +11 -24
  16. package/dist/bulk.js +37 -0
  17. package/dist/capabilities.js +208 -0
  18. package/dist/capability-query.js +72 -0
  19. package/dist/catalog.js +105 -0
  20. package/dist/cli.js +154 -15
  21. package/dist/client-address.js +1 -1
  22. package/dist/compliance-rules/baseline.js +8 -8
  23. package/dist/compliance-rules/privacy.js +3 -3
  24. package/dist/compliance-rules/strict.js +5 -5
  25. package/dist/conditions.js +88 -0
  26. package/dist/config.js +60 -4
  27. package/dist/context.js +156 -0
  28. package/dist/ecosystem-cli.js +88 -0
  29. package/dist/egress.js +98 -0
  30. package/dist/examples.js +92 -0
  31. package/dist/explain-cli.js +64 -0
  32. package/dist/explain.js +132 -0
  33. package/dist/extensions.js +172 -0
  34. package/dist/function-sources.js +15 -3
  35. package/dist/index.js +37 -0
  36. package/dist/init-with.js +165 -0
  37. package/dist/interchange-cli.js +42 -0
  38. package/dist/interchange.js +189 -0
  39. package/dist/link-cli.js +1 -1
  40. package/dist/management-policy.js +0 -1
  41. package/dist/manifest.js +111 -0
  42. package/dist/match.js +2 -2
  43. package/dist/mcp-authoring.js +147 -0
  44. package/dist/mcp.js +97 -0
  45. package/dist/observability.js +6 -0
  46. package/dist/operator-host.js +29 -0
  47. package/dist/plugins.js +12 -0
  48. package/dist/policies/agents.js +2 -2
  49. package/dist/policies/compression.js +2 -1
  50. package/dist/policies/security.js +0 -0
  51. package/dist/policies.js +1 -1
  52. package/dist/policy.js +29 -7
  53. package/dist/prerender.js +100 -41
  54. package/dist/project-tests.js +3 -3
  55. package/dist/provider-verification.js +92 -0
  56. package/dist/proxy.js +44 -0
  57. package/dist/readiness.js +5 -5
  58. package/dist/recipes.js +41 -0
  59. package/dist/route-diff.js +106 -0
  60. package/dist/router.js +42 -2
  61. package/dist/runtime.js +95 -14
  62. package/dist/schema-query.js +62 -0
  63. package/dist/signals.js +24 -0
  64. package/dist/site.js +0 -0
  65. package/dist/tooling.js +96 -0
  66. package/dist/types/adapters.d.ts +7 -4
  67. package/dist/types/agent-lists.d.ts +0 -1
  68. package/dist/types/agents-guide.d.ts +17 -0
  69. package/dist/types/authoring-files.d.ts +10 -0
  70. package/dist/types/aws.d.ts +3 -1
  71. package/dist/types/build-cloudflare.d.ts +1 -0
  72. package/dist/types/bulk.d.ts +27 -0
  73. package/dist/types/capabilities.d.ts +55 -0
  74. package/dist/types/capability-query.d.ts +24 -0
  75. package/dist/types/catalog.d.ts +65 -0
  76. package/dist/types/client-address.d.ts +0 -1
  77. package/dist/types/compliance-rules/baseline.d.ts +1 -9
  78. package/dist/types/compliance-rules/privacy.d.ts +1 -4
  79. package/dist/types/compliance-rules/strict.d.ts +0 -5
  80. package/dist/types/conditions.d.ts +19 -0
  81. package/dist/types/config.d.ts +20 -2
  82. package/dist/types/context.d.ts +65 -0
  83. package/dist/types/ecosystem-cli.d.ts +17 -0
  84. package/dist/types/egress.d.ts +46 -0
  85. package/dist/types/examples.d.ts +50 -0
  86. package/dist/types/explain-cli.d.ts +11 -0
  87. package/dist/types/explain.d.ts +95 -0
  88. package/dist/types/extensions.d.ts +122 -0
  89. package/dist/types/function-sources.d.ts +5 -0
  90. package/dist/types/index.d.ts +33 -0
  91. package/dist/types/init-with.d.ts +30 -0
  92. package/dist/types/interchange-cli.d.ts +16 -0
  93. package/dist/types/interchange.d.ts +42 -0
  94. package/dist/types/link-cli.d.ts +2 -1
  95. package/dist/types/management-policy.d.ts +0 -1
  96. package/dist/types/manifest.d.ts +81 -0
  97. package/dist/types/match.d.ts +1 -0
  98. package/dist/types/mcp-authoring.d.ts +92 -0
  99. package/dist/types/mcp.d.ts +12 -0
  100. package/dist/types/observability.d.ts +2 -0
  101. package/dist/types/operator-host.d.ts +8 -0
  102. package/dist/types/plugins.d.ts +2 -0
  103. package/dist/types/policies/agents.d.ts +0 -2
  104. package/dist/types/policies/compression.d.ts +2 -0
  105. package/dist/types/policies/security.d.ts +0 -1
  106. package/dist/types/policy.d.ts +15 -4
  107. package/dist/types/project-tests.d.ts +3 -1
  108. package/dist/types/provider-verification.d.ts +53 -0
  109. package/dist/types/proxy.d.ts +21 -0
  110. package/dist/types/readiness.d.ts +1 -1
  111. package/dist/types/recipes.d.ts +30 -0
  112. package/dist/types/route-diff.d.ts +27 -0
  113. package/dist/types/runtime.d.ts +11 -0
  114. package/dist/types/schema-query.d.ts +12 -0
  115. package/dist/types/signals.d.ts +25 -0
  116. package/dist/types/site.d.ts +0 -1
  117. package/dist/types/tooling.d.ts +115 -0
  118. package/dist/types/types.d.ts +57 -0
  119. package/dist/types/typescript-authoring.d.ts +12 -0
  120. package/dist/types/vercel.d.ts +3 -1
  121. package/dist/types/verify-deployment.d.ts +47 -0
  122. package/dist/types.js +21 -2
  123. package/dist/typescript-authoring.js +104 -0
  124. package/dist/vercel.js +4 -3
  125. package/dist/verify-deployment.js +270 -0
  126. package/docs/AI-AUTHORING.md +130 -8
  127. package/docs/BULK.md +79 -0
  128. package/docs/CAPABILITIES.md +179 -0
  129. package/docs/CAPACITY.md +1 -1
  130. package/docs/CI.md +142 -0
  131. package/docs/CONDITIONS.md +74 -0
  132. package/docs/DEPLOYMENT-CHECKS.md +108 -0
  133. package/docs/DYNAMIC-LINKS.md +18 -518
  134. package/docs/EGRESS.md +125 -0
  135. package/docs/EXTENSIONS.md +226 -0
  136. package/docs/FRAMEWORK.md +182 -0
  137. package/docs/INSTALL.md +45 -7
  138. package/docs/INTERCHANGE.md +134 -0
  139. package/docs/MIDDLEWARE-EXAMPLES.md +75 -0
  140. package/docs/MIDDLEWARE.md +2 -0
  141. package/docs/NEXT-PHASE-PLAN.md +90 -0
  142. package/docs/NEXT-STEPS.md +415 -0
  143. package/docs/OBSERVABILITY.md +4 -2
  144. package/docs/OPERATIONAL-PROOF.md +4 -1
  145. package/docs/OPERATIONS.md +6 -3
  146. package/docs/PLUGINS.md +37 -0
  147. package/docs/POLICIES.md +12 -309
  148. package/docs/PRERENDER.md +40 -0
  149. package/docs/PROJECT-DIRECTION.md +42 -0
  150. package/docs/PROVIDER-VERIFICATION.md +84 -0
  151. package/docs/READINESS.md +21 -1
  152. package/docs/README.md +82 -31
  153. package/docs/RECIPES.md +99 -0
  154. package/docs/RELEASE-READINESS.md +11 -9
  155. package/docs/RELEASE-SECURITY.md +27 -4
  156. package/docs/SECURITY-AUDIT.md +1 -1
  157. package/docs/SPECIFICATION.md +95 -8
  158. package/docs/SPIKE-BUSINESS-SUITE.md +1013 -0
  159. package/docs/SPIKE-EXTENSION-MODEL.md +419 -0
  160. package/docs/SPIKE-EXTENSIONS.md +1 -0
  161. package/docs/SPIKE-LAMBDA-COMPILE.md +199 -0
  162. package/docs/STANDARDS.md +150 -142
  163. package/docs/STARTERS.md +21 -1
  164. package/docs/TOOLING.md +291 -0
  165. package/docs/TYPESCRIPT-AUTHORING.md +67 -0
  166. package/docs/TYPESCRIPT.md +1 -1
  167. package/docs/USABILITY-REVIEW.md +123 -0
  168. package/docs/YAML-GUIDE.md +18 -479
  169. package/docs/YAML-REFERENCE.md +127 -16
  170. package/docs/links/cli.md +110 -0
  171. package/docs/links/limits.md +175 -0
  172. package/docs/links/management-api.md +80 -0
  173. package/docs/links/pools.md +75 -0
  174. package/docs/links/setup.md +135 -0
  175. package/docs/policies/agents.md +1 -1
  176. package/docs/policies/contract.md +52 -0
  177. package/docs/policies/hardened.md +56 -0
  178. package/docs/policies/interoperability.md +169 -0
  179. package/docs/policies/operations.md +45 -0
  180. package/docs/yaml/assets.md +36 -0
  181. package/docs/yaml/conditions.md +20 -0
  182. package/docs/yaml/functions.md +160 -0
  183. package/docs/yaml/links.md +30 -0
  184. package/docs/yaml/middleware.md +29 -0
  185. package/docs/yaml/organization.md +74 -0
  186. package/docs/yaml/policies.md +37 -0
  187. package/docs/yaml/redirects.md +64 -0
  188. package/docs/yaml/responses.md +57 -0
  189. package/docs/yaml/site.md +24 -0
  190. package/examples/assets/example.yaml +17 -0
  191. package/examples/aws/example.yaml +20 -0
  192. package/examples/cloudflare/example.yaml +19 -0
  193. package/examples/compliance/example.yaml +11 -0
  194. package/examples/conditions/README.md +12 -0
  195. package/examples/conditions/example.yaml +19 -0
  196. package/examples/conditions/tests/requests.json +13 -0
  197. package/examples/conditions/urlcode.yaml +24 -0
  198. package/examples/cookbook/README.md +8 -4
  199. package/examples/cookbook/example.yaml +17 -0
  200. package/examples/cookbook/functions/catalog.mjs +3 -0
  201. package/examples/cookbook/functions/fail.mjs +4 -0
  202. package/examples/cookbook/functions/items.mjs +3 -0
  203. package/examples/cookbook/functions/profile.mjs +3 -0
  204. package/examples/cookbook/functions/resource.mjs +3 -0
  205. package/examples/cookbook/functions/status.mjs +3 -0
  206. package/examples/cookbook/middleware/auth.mjs +48 -0
  207. package/examples/cookbook/middleware/body.mjs +15 -0
  208. package/examples/cookbook/middleware/bucket.mjs +19 -0
  209. package/examples/cookbook/middleware/cors.mjs +21 -0
  210. package/examples/cookbook/middleware/debug.mjs +13 -0
  211. package/examples/cookbook/middleware/envelope.mjs +11 -0
  212. package/examples/cookbook/middleware/errors.mjs +11 -0
  213. package/examples/cookbook/middleware/etag.mjs +18 -0
  214. package/examples/cookbook/middleware/locale.mjs +16 -0
  215. package/examples/cookbook/middleware/maintenance.mjs +10 -0
  216. package/examples/cookbook/middleware/methods.mjs +15 -0
  217. package/examples/cookbook/middleware/negotiate.mjs +20 -0
  218. package/examples/cookbook/middleware/referer.mjs +12 -0
  219. package/examples/cookbook/middleware/request-id.mjs +16 -0
  220. package/examples/cookbook/route-index.json +676 -0
  221. package/examples/cookbook/routes/middleware.yaml +126 -0
  222. package/examples/cookbook/tests/requests.json +526 -0
  223. package/examples/cookbook/urlcode.yaml +1 -0
  224. package/examples/egress/README.md +22 -0
  225. package/examples/egress/example.yaml +19 -0
  226. package/examples/egress/urlcode.yaml +19 -0
  227. package/examples/extensions/README.md +7 -0
  228. package/examples/extensions/example.yaml +21 -0
  229. package/examples/extensions/urlcode.yaml +25 -0
  230. package/examples/live-links/example.yaml +21 -0
  231. package/examples/monitoring/example.yaml +8 -0
  232. package/examples/prerender/example.yaml +16 -0
  233. package/examples/provider-conformance/README.md +12 -0
  234. package/examples/provider-conformance/example.yaml +14 -0
  235. package/examples/provider-conformance/urlcode.yaml +34 -0
  236. package/examples/tunnel/example.yaml +8 -0
  237. package/examples/vercel/example.yaml +19 -0
  238. package/llms-full.txt +2709 -0
  239. package/llms.txt +48 -19
  240. package/package.json +29 -7
  241. package/packaging/claude-plugin/.claude-plugin/plugin.json +19 -0
  242. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +106 -0
  243. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +114 -0
  244. package/recipes/authenticated-json-api/README.md +51 -0
  245. package/recipes/authenticated-json-api/functions/profile.mjs +5 -0
  246. package/recipes/authenticated-json-api/recipe.yaml +34 -0
  247. package/recipes/authenticated-json-api/tests/requests.json +39 -0
  248. package/recipes/authenticated-json-api/urlcode.yaml +12 -0
  249. package/recipes/contact-form/README.md +25 -0
  250. package/recipes/contact-form/functions/contact.mjs +17 -0
  251. package/recipes/contact-form/recipe.yaml +33 -0
  252. package/recipes/contact-form/tests/requests.json +47 -0
  253. package/recipes/contact-form/urlcode.yaml +18 -0
  254. package/recipes/cors-api/README.md +16 -0
  255. package/recipes/cors-api/functions/items.mjs +3 -0
  256. package/recipes/cors-api/middleware/cors.mjs +21 -0
  257. package/recipes/cors-api/recipe.yaml +26 -0
  258. package/recipes/cors-api/tests/requests.json +65 -0
  259. package/recipes/cors-api/urlcode.yaml +12 -0
  260. package/recipes/health-page/README.md +13 -0
  261. package/recipes/health-page/recipe.yaml +23 -0
  262. package/recipes/health-page/tests/requests.json +36 -0
  263. package/recipes/health-page/urlcode.yaml +19 -0
  264. package/recipes/json-api/README.md +6 -0
  265. package/recipes/json-api/functions/echo.mjs +3 -0
  266. package/recipes/json-api/recipe.yaml +25 -0
  267. package/recipes/json-api/tests/requests.json +34 -0
  268. package/recipes/json-api/urlcode.yaml +12 -0
  269. package/recipes/middleware/README.md +34 -0
  270. package/recipes/middleware/functions/catalog.mjs +3 -0
  271. package/recipes/middleware/functions/fail.mjs +4 -0
  272. package/recipes/middleware/functions/items.mjs +3 -0
  273. package/recipes/middleware/functions/profile.mjs +3 -0
  274. package/recipes/middleware/functions/resource.mjs +3 -0
  275. package/recipes/middleware/functions/status.mjs +3 -0
  276. package/recipes/middleware/middleware/auth.mjs +48 -0
  277. package/recipes/middleware/middleware/body.mjs +15 -0
  278. package/recipes/middleware/middleware/bucket.mjs +19 -0
  279. package/recipes/middleware/middleware/cors.mjs +21 -0
  280. package/recipes/middleware/middleware/debug.mjs +13 -0
  281. package/recipes/middleware/middleware/envelope.mjs +11 -0
  282. package/recipes/middleware/middleware/errors.mjs +11 -0
  283. package/recipes/middleware/middleware/etag.mjs +18 -0
  284. package/recipes/middleware/middleware/locale.mjs +16 -0
  285. package/recipes/middleware/middleware/maintenance.mjs +10 -0
  286. package/recipes/middleware/middleware/methods.mjs +15 -0
  287. package/recipes/middleware/middleware/negotiate.mjs +20 -0
  288. package/recipes/middleware/middleware/referer.mjs +12 -0
  289. package/recipes/middleware/middleware/request-id.mjs +16 -0
  290. package/recipes/middleware/public/guide.txt +1 -0
  291. package/recipes/middleware/recipe.yaml +50 -0
  292. package/recipes/middleware/tests/requests.json +528 -0
  293. package/recipes/middleware/urlcode.yaml +127 -0
  294. package/recipes/protected-download/README.md +22 -0
  295. package/recipes/protected-download/files/report.txt +1 -0
  296. package/recipes/protected-download/recipe.yaml +31 -0
  297. package/recipes/protected-download/tests/requests.json +32 -0
  298. package/recipes/protected-download/urlcode.yaml +15 -0
  299. package/recipes/redirect/README.md +7 -0
  300. package/recipes/redirect/recipe.yaml +25 -0
  301. package/recipes/redirect/tests/requests.json +19 -0
  302. package/recipes/redirect/urlcode.yaml +9 -0
  303. package/recipes/static-plus-api/README.md +15 -0
  304. package/recipes/static-plus-api/functions/info.mjs +3 -0
  305. package/recipes/static-plus-api/public/assets/index.html +3 -0
  306. package/recipes/static-plus-api/public/assets/site.css +1 -0
  307. package/recipes/static-plus-api/public/index.html +8 -0
  308. package/recipes/static-plus-api/recipe.yaml +29 -0
  309. package/recipes/static-plus-api/tests/requests.json +56 -0
  310. package/recipes/static-plus-api/urlcode.yaml +23 -0
  311. package/recipes/typescript/README.md +7 -0
  312. package/recipes/typescript/functions/hello.ts +5 -0
  313. package/recipes/typescript/recipe.yaml +23 -0
  314. package/recipes/typescript/tests/requests.json +18 -0
  315. package/recipes/typescript/urlcode.yaml +5 -0
  316. package/recipes/webhook-receiver/README.md +16 -0
  317. package/recipes/webhook-receiver/functions/receive.mjs +16 -0
  318. package/recipes/webhook-receiver/recipe.yaml +26 -0
  319. package/recipes/webhook-receiver/tests/requests.json +59 -0
  320. package/recipes/webhook-receiver/urlcode.yaml +16 -0
  321. package/schemas/recipe.schema.json +138 -0
  322. package/schemas/urlcode.schema.json +656 -80
  323. package/skills/urlcode/SKILL.md +98 -0
  324. package/starters/default/.github/workflows/urlcode.yml +23 -0
  325. package/starters/default/.mcp.json +12 -0
  326. package/starters/default/AGENTS.md +79 -0
@@ -1,60 +1,90 @@
1
1
  {
2
- "node": "v26.8.2",
2
+ "node": "v26.9.0",
3
3
  "files": {
4
- "dist/adapters.js": "40e5c2d0ff4be8b11752418f063a9e79e29e31b6a64c92a19a514f182268133c",
5
- "dist/agent-lists.js": "fa1e87b928bf7178d7e910584018ef330a164be834156a8728f8d33ed7353211",
4
+ "dist/adapters.js": "a7153ec52f2ed7e0cdd8ed7d433504815f402ec53b2b1c3d38d0cf0e2fcf6509",
5
+ "dist/agent-lists.js": "35ab484198897501d011cb6cc00b5a6787192e19df29c97646e8c118fcc19eef",
6
+ "dist/agents-guide.js": "9cecc60690fe91e1f09a5298273c1d918428f114b5abb11f40f37f341668309c",
6
7
  "dist/assets.js": "0833b093d2fe457ce68281110dc07d47914992753607741c13b339d92c76cf5c",
7
- "dist/authoring.js": "99c3fe70df840ccc2a57b887b6b5886998a1155e848c3b6804a89bd1e257b05b",
8
- "dist/aws.js": "1384e417de68404b5f1f35ee8a9148271b6efa0965a64e458d7bbda0234cc564",
9
- "dist/build-cloudflare.js": "65af88384795bd7a4e2374c2cd9e5be174e3ffd4142f705723a3f5115a28eb27",
10
- "dist/cli.js": "4cb9a0a6d85ac4b101b72cd71dbdb3ca17c8ab1d064986f9923e4a5254b8b7a9",
11
- "dist/client-address.js": "292b86165def33247b05ef619e15245b70765522c8d9dc0ca4fac6e22e531de8",
8
+ "dist/authoring-files.js": "ad32814f9ae9c549c6247396f982aa700d13a293cc0a589609eccc68f8965550",
9
+ "dist/authoring.js": "ec5240e8686c124f4601229b45f89ce112d9eeb9d35e3059fe55e93056c45209",
10
+ "dist/aws.js": "7d8e3a97b4f6dbefbd68da058f05192469d1efcaed5458b284863ebe462e060e",
11
+ "dist/build-cloudflare.js": "af4f49ad45287d7c4105bb84b1592b5b8e76c930f7159505338298f7c5fd5651",
12
+ "dist/bulk.js": "aac88d422bd9a7a341a421fb4e29ff5580b28d39250b7f1f5315ba20ae92da8a",
13
+ "dist/capabilities.js": "c1e28c7de676c3b43c154d6f767749a1b34df78a64c58b5c23ad95339f964608",
14
+ "dist/capability-query.js": "850525d542aeeaeb4f89397ac57c6f89daad3fe3fa02ecb0332ea9f75d140b32",
15
+ "dist/catalog.js": "ab1c01c9296cc277d2bd4fd682aeb053656a7d9f91c61974f4b78feea0211de8",
16
+ "dist/cli.js": "4cba007ed3666fdfdf9fc676de1e346ab8196e3907dc2541eeb3e59842d9891a",
17
+ "dist/client-address.js": "9d0d01466aab23124330605c5a0e0f981f87c897858acfad909f546a63df165b",
12
18
  "dist/cloudflare.js": "17b43b0a6b6a0ef8a893415c989e4ae3976d97cc966adbf897b785f9adc472e3",
13
- "dist/compliance-rules/baseline.js": "6746ed9717fcbc414d4892ec54afca74496dcc725f2c80d417e382c190294811",
14
- "dist/compliance-rules/privacy.js": "fe8330fd4c5068645e5c41db389fd190d7423e822397bf3938ca48d275bd449c",
19
+ "dist/compliance-rules/baseline.js": "0a0c03d932f30797c4837c78c6b64ca6bb88f2ca947eb7f6adf5fdcdd280616d",
20
+ "dist/compliance-rules/privacy.js": "0e4d12106cf777299a7d30451f53c7b996f202fe53d7e1047b69f5df2a74a53d",
15
21
  "dist/compliance-rules/shared.js": "595a7ee3a5af8c52197c5c9cbf09f4289a234e52b7a198afdd498be9be8d28a1",
16
- "dist/compliance-rules/strict.js": "937b55f4574eb5ca9f238b1a9658b089d006372328da35a329e4359719e6c3d0",
22
+ "dist/compliance-rules/strict.js": "73ee13c2f893acf20cc3d44bf054e58c1474dec52eafe0cf2ce7f4eb96a3bc53",
17
23
  "dist/compliance.js": "e956dc89b0b729fed7031297b8d7554141110334e670edf5cedc3d052a8fb3e4",
24
+ "dist/conditions.js": "ff25e97da550a3bdd80af55522045669438aa31a77d2bc83ad602bcefdee0475",
18
25
  "dist/config-worker.js": "bc2170d60c35f8d5de227cbfc4c5067dc61d7cbc5b98aed88e68a11797072da5",
19
- "dist/config.js": "d0e0d100f3f97d3cefd17d898dddea463773092569a7cd7c3384bd547847659f",
26
+ "dist/config.js": "8efc2cfc24e9a958770d73aa8464d18c81d7a9a1d2398398cd9cc2776e639127",
27
+ "dist/context.js": "a6b0278b4fd478175f43b1ef5ae640ce6e0782c906c6fd2c7d1aebaf5a31c918",
28
+ "dist/ecosystem-cli.js": "1e71bacd53d6fa8c7857cfcce3c3012ce054771a434b78d1f39e892e32642edd",
29
+ "dist/egress.js": "2ae29fe2cb4590fd2f715abe6817db47fed2f50dd31f37946ecf42eafbb0dd9e",
20
30
  "dist/errors.js": "a908e66496afebbdd632a8c159a6e14d23f8f38798a0b4342ca122f2511c6cde",
21
- "dist/function-sources.js": "48b470fbdcef2ad2c83e61a6476d5499210d0937b72518ae01fb2b9225b0e16b",
31
+ "dist/examples.js": "8de9917a82fb04e44a3182d57c6a95cc730feb8b22a37d54b9b3c4177aa83111",
32
+ "dist/explain-cli.js": "c5414e9627f428f0d8efa4e4f3f89951ea10a6b3fe1d7f633e48f71a792406d2",
33
+ "dist/explain.js": "5dd271b699c9b852fbaa4db271d9a370fe98fca43b1d0ac018de0c0b047bf7b8",
34
+ "dist/extensions.js": "7402ff86017fca83a0e08a50b402bc428056566d63511aa84d609e252dc456e8",
35
+ "dist/function-sources.js": "f6e8bdd9d4ef728b44c6e1f08c601b11fc4ad3e0c104dacf4fea0b71874ea4e7",
22
36
  "dist/function-worker.js": "3f5bad4f1b5cb812924c2dcc73ece6f816cf6aac26cd471fd1030dcfbf009c3b",
23
37
  "dist/functions.js": "6b1e5d4a3f8db17d4e5df261b98ed15f5f0c5e5507a6fc0f472e9f94ed2b6090",
24
38
  "dist/guest-api.js": "bc2501496a6ef9fd20dddb606fbc6fd557d534dd075e7ad38406248b230013ed",
25
39
  "dist/header-validation.js": "465181dbb08ff05f52defdd29fda025c0c64589bf319fa87fa6d3ab4b68216d5",
26
40
  "dist/http-policy.js": "4cb187642269078ddf3460a3f1813dc57878a616a6f8132ef8f8d3b4b91ebb56",
27
41
  "dist/http-response.js": "5fc3bb9eb932a3fd2fbc72c361416a5f1439b8bf45b2be37baca1c6446abf40c",
28
- "dist/index.js": "648878ef26cb3a8eb075a5ddd4d044022afe6cf5e5e38d1bd6ea418b82791371",
42
+ "dist/index.js": "53648d88b0db7d9168d2f212ea4a28b7fd3ead6238c99c0b8d7d41536274d6d4",
43
+ "dist/init-with.js": "8371f568867ebdc6ab8e9aa762234ae2aa015865f46aa901254528e20d69b791",
44
+ "dist/interchange-cli.js": "35bd70ba8077af5c3e39404ff0e5d28707632090a59a90645141252449fd3f04",
45
+ "dist/interchange.js": "26789420af33344d9a08c00fe6b2708aa71994224df527b3075295be2151611e",
29
46
  "dist/link-api.js": "0d1f2fb5ef8cd6fda7b071d3e08c53eb4b1c01d4003167af2f400949b70dea4f",
30
- "dist/link-cli.js": "5f45e62a6b935112cabfcd12691a5ebc01d9c87f92e4befb655380d9e752323b",
47
+ "dist/link-cli.js": "c4e2121a3e66f33c640832a7cb362a6a1db8b6d91d55a4239ce38ba0ced67b22",
31
48
  "dist/link-events.js": "502a6038a538fa43094a9ba9c7546f504b4a1832a1377f26ca8cb69c2326670e",
32
49
  "dist/link-records.js": "ef67a58cd107db0c3ac1c0ffd7b32817553606cf69bb3002da4ca0138c272f69",
33
50
  "dist/link-store-worker.js": "0080452bbada2154b923449cd14596579bde94ad5f8dab94ecc84aa0d59c089b",
34
51
  "dist/link-store.js": "526cdbe1b917cc7a74fb6edbbf13717d823ace5b5d6a5f89bc91438056a10b37",
35
52
  "dist/logging.js": "8ec57fea26983aa071b05fe15d680d6550b03488101163ed9666da674118cf31",
36
- "dist/management-policy.js": "ad573627de0e9f9b5368d701966468f391f53d64d2a82bfd8083bca412b01721",
37
- "dist/match.js": "a0935ee5a3c68d85c268abbdcecd30a7ebd68e37bbecb68136479b1f94fc3705",
38
- "dist/observability.js": "28a446ad867329e58cbccb9215a343a390e8599dad6a31c1db0e702d3df67e27",
39
- "dist/plugins.js": "c228ec42cd727f259193fe905ae247f9fba34f695dd1364d8e3ee6683262da7c",
40
- "dist/policies/agents.js": "761920214db2ada60733743541f134928ba1d2f0bc763660bd0d1112a725c887",
53
+ "dist/management-policy.js": "bd5563da52c53ace71b01daed0d2a492baeb3f26f5ec5ee1b0981c2b88df9ffa",
54
+ "dist/manifest.js": "d4f58f936febbabf09ec1706baae7c1cb186dcd8a3d29b5725dad5b6eaf43a3f",
55
+ "dist/match.js": "53ebcc2cda529a8d07fb83f8cb69a1446036ffc1641af3c4bd45a55851bded28",
56
+ "dist/mcp-authoring.js": "5030f52ef9c7ebc7b97305fcce687eb0a0d6164e34fda87f8278135a1e6f3d65",
57
+ "dist/mcp.js": "ac96c5a094d7cc88cf16d1d1e3c23f45773729fe28855f921581badb2b95eb89",
58
+ "dist/observability.js": "13a22b9e34cf8da3739856eeada8522fb6c43765386cae07c6aa0981447fcb83",
59
+ "dist/operator-host.js": "e3dac9d43a83beb775202b4ab9eeeba7ac63cebfc5dcc669be38d825be587bd0",
60
+ "dist/plugins.js": "a61aa933cd9e1b41020b86fae78aa3a7f45f5313124aa11b50cb57898722385e",
61
+ "dist/policies/agents.js": "c1dbc1e90339f472eeeb2372f7f4637f59a5d210797ea680ac8120a02aa20c10",
41
62
  "dist/policies/cache.js": "ef16d7e592526c29f865b2693faa2c8afbea41c6526687563dffcb13a77fc1f7",
42
- "dist/policies/compression.js": "d342c6db4a9bee63b62b35654dde28fa163bfd82510bb85331bb9b072f856781",
43
- "dist/policies/security.js": "119fb37bd0e994ddabf3feacbc52d481c8e8c65b0ac6b71c8d3533b8c3e2cedb",
63
+ "dist/policies/compression.js": "800f3ae3b1a4c1fe58c3d9908364ea9d78f655ff50c7f7589f584378e7f194b0",
64
+ "dist/policies/security.js": "2b3bfdf82140156fea4b162adc28ee43ccd85c402fb200680dbb8d8706417420",
44
65
  "dist/policies/throttle.js": "bbb0cb1c24cf70d0a1ac32fc0618efb6c44e5b5d42564842f9c585ff7e501603",
45
- "dist/policies.js": "e3f48ad730d1d7b1435bff2f2bd7091e24a0c46dd0e1393d53337d64e3a7d83d",
46
- "dist/policy.js": "280f94593c9e376726e2b3d34f4c1e9817802d67134bd6a2d1afe466244b3fdc",
47
- "dist/prerender.js": "f568e2773be6fe67b547739f609c0287f429451ab31187f48ffe4560df3f877b",
48
- "dist/project-tests.js": "91aa9c22d9f40efb0c5318b7a05b4aee753fc1ab591fe90e8d94f24fa60697f5",
49
- "dist/readiness.js": "64eedecc9405db253e2bd39819c7f5640c6017f13cf23d2a193656dda095ca45",
50
- "dist/router.js": "a102132362177bb8690bde11ce2b6ea9719a79601a25165d5d36dc736b1b888b",
51
- "dist/runtime.js": "1d22cdb83703e0fc15da63d28b02fbd419051894063cb2fde5072b186c98ec62",
66
+ "dist/policies.js": "23fa019b7bf1cdedcc5f7772d2f157e4b381a554bce9e84594c2be4a0f8f76b8",
67
+ "dist/policy.js": "8285ed144ba42fd34e926e526cd4dcf60d5ab3668adf4f0b797f074ebd5243ce",
68
+ "dist/prerender.js": "0386ea2411e00b9563b5349133f1d723947b01f837fa92d4c61a699c9cfb5cdb",
69
+ "dist/project-tests.js": "225761d36bbe7e185c49c10c0334e579caf7d98647c9941faa4b0ea6406522fa",
70
+ "dist/provider-verification.js": "ffcf9f05e8cb5f71ea46a97e279e8a613fdfdf9435ab02bd57af11e2680a9107",
71
+ "dist/proxy.js": "34107e59ac0dbbea090efa3cf5badf3226c5302ba25e8f8ff9b2b5596ed80e50",
72
+ "dist/readiness.js": "d419b09a83dc8e6790be7c91ba4e1a2a5cf9b141577c98bd24e99a3609553649",
73
+ "dist/recipes.js": "11853f23e63c3c65c5bed03a278cde0349d28c9fa23266c9907a2df318bb5fc3",
74
+ "dist/route-diff.js": "eebac076a886ddfb2bf5b97ea09d81f888e7bb0063d482eddb8e5fef9acea107",
75
+ "dist/router.js": "4315585232561c1737e579a2cbd990596d337b37565dd449bcb1bbaa6abbfb13",
76
+ "dist/runtime.js": "f6f1bfa320a427423d66be845de3368552b1f4cca4a28136b913ac26fb9d6169",
52
77
  "dist/scaffold.js": "9dd30112e070ec554bd7cae1ca0a8b03642632be57411ba76a72972f4ba49b3e",
78
+ "dist/schema-query.js": "bfd1844acd8d54ac361115191fcfbaf828a67e223b9ec6e9c22f158761af149b",
53
79
  "dist/server.js": "d8c78d1695b3c11328f3f983281fba78c2aca6a66cf755b39ecf4ec2ec4b6f29",
54
- "dist/site.js": "f34b023c9bcd403d38b8a2bf4d8ba184e0ff00cbd98405b49c68747466d995cd",
80
+ "dist/signals.js": "b55e54efc8fb6703e08f2a1e808ec8e011bda67738db8ceadf1b248f695795be",
81
+ "dist/site.js": "c40a06a6f9e2d6d3bea94727783c115fed4309bb0190787f58434eed64cbde84",
55
82
  "dist/sqlite-version.js": "a3a08d99064bd0f35847e288027e00a516efdd61c675bfbbe7726e3aa900f0d1",
56
- "dist/types.js": "96650efc60f2400b7b1a6622798f0f42d43f451fa5bf18a93d06482feb2e0283",
57
- "dist/vercel.js": "76092b83e4d80e29541589682e00237701a3d3f096a8045fa2cf104b6d1b6725",
83
+ "dist/tooling.js": "eaf9aa49df17b5ab3bc538976b2849fac52b5ca779b6e814fd7ca592ecd757b7",
84
+ "dist/types.js": "8579202bf322e542969bbd9e5b98774963b12ac69bdf362eebfcb068de2d5421",
85
+ "dist/typescript-authoring.js": "156c617c2cbf992c299dbbbd5398500f0f30d1c90df8630509036da4ffd7cae9",
86
+ "dist/vercel.js": "a0da20c095d0c7fa8f579ed4dd5951e7a34191f8a72a57c5e782c9eab39f6f08",
87
+ "dist/verify-deployment.js": "cac5d10ea18ae5f699df0eb0a5229837297c7627b47e65140f053820cae2414d",
58
88
  "dist/scripts/operational-drills.js": "b7e9448279c59ee9de62023055a9ff5c7a60bcceed4c33d023edc612f5575af9"
59
89
  }
60
90
  }
package/dist/adapters.js CHANGED
@@ -1,19 +1,12 @@
1
+
1
2
  import { createRuntime } from './runtime.js';
2
3
 
3
4
  import { validatePolicy } from './policy.js';
4
5
  import { ConfigError } from './errors.js';
5
-
6
6
 
7
7
  /** The subset of process.env a hosted adapter reads. */
8
8
 
9
-
10
-
11
- // Handlers a stateless per-request invocation cannot honour. Functions and
12
- // middleware need worker threads and the WASM engine on every cold start;
13
- // stored links need a durable writable file that instances share. Adapters
14
- // refuse them identically, so a project's supported surface does not depend on
15
- // which provider is serving it.
16
- const unsupported = { function:'isolated functions', link:'stored live links' };
9
+
17
10
 
18
11
  export function readPolicyFromEnvironment(environment ) {
19
12
  if (!environment.URLCODE_POLICY) return undefined;
@@ -27,20 +20,8 @@ export function readPolicyFromEnvironment(environment )
27
20
 
28
21
  // Activates a project for a native-handler-only host, refusing the whole
29
22
  // deployment rather than letting individual routes fail at request time.
30
- export async function activateNativeOnly(project , environment , { target = 'node', plugins } = {}) {
31
- const runtime = await createRuntime(project, { permissions: readPolicyFromEnvironment(environment), environment, target, plugins });
32
- const refused = runtime.testPlan().inventory.flatMap(route => {
33
- const reason = route.handler === undefined ? undefined : unsupported[route.handler];
34
- return [
35
- ...(reason ? [`${route.path} uses ${reason}`] : []),
36
- ...(route.middleware ? [`${route.path} declares middleware`] : []),
37
- ];
38
- });
39
- if (refused.length) {
40
- await runtime.close();
41
- throw new ConfigError(`This adapter serves native handlers only: ${refused.join('; ')}`);
42
- }
43
- return runtime;
23
+ export async function activateNativeOnly(project , environment , { target, plugins, extensions, origin } ) {
24
+ return createRuntime(project, { permissions: readPolicyFromEnvironment(environment), environment, target, plugins, extensions, origin });
44
25
  }
45
26
 
46
27
  // Caches a successful activation for the life of the instance. A failure is not
@@ -10,7 +10,7 @@ import { isListFile, isBundled, validatePattern } from './policies/agents.js';
10
10
  //
11
11
  // A list file is the schema data/agents/*.json uses: either an array of
12
12
  // entries or `{ entries: [...] }`, each entry `{ name?, pattern, ... }`.
13
- export const MAX_LIST_ENTRIES = 4096;
13
+ const MAX_LIST_ENTRIES = 4096;
14
14
 
15
15
  function listPath(root , reference , routePattern ) {
16
16
  assert(isListFile(reference) && !isAbsolute(reference), `${routePattern}: policies.agents list ${JSON.stringify(reference)} must be a project-relative path ending in .json`);
@@ -0,0 +1,113 @@
1
+ import { getCapabilities } from './capabilities.js';
2
+
3
+ import { registry } from './policies.js';
4
+ import { generatedPaths } from './site.js';
5
+ import { assert } from './errors.js';
6
+
7
+ /** Where the packaged agent skill lives, relative to the installed @jimhoyd/urlcode package. */
8
+ export const skillPath = 'skills/urlcode/SKILL.md';
9
+ /** The MCP registration file `urlcode init` writes beside the project (Claude Code and Codex read this shape). */
10
+ export const mcpConfigFile = '.mcp.json';
11
+ /**
12
+ * Renders `.mcp.json` registering the read-only `urlcode mcp` server for the project at `project`, relative
13
+ * to the file. `--allow-authoring` is deliberately absent: the operator adds it by hand when they want it.
14
+ */
15
+ export function renderMcpConfig(project = '.') {
16
+ assert(/^[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*$/.test(project) && !project.split('/').includes('..'), 'MCP project path must be a relative path without ..');
17
+ return JSON.stringify({ mcpServers: { urlcode: { command: 'urlcode', args: ['mcp', '--project', project] } } }, null, 2) + '\n';
18
+ }
19
+ const handlerNames = ['redirect','respond','page','static','download','function','link','proxy','conditional','extension'];
20
+
21
+ /**
22
+ * The application-level AGENTS.md written by `urlcode init`. Built from the
23
+ * installed runtime's capability catalog, so it names only the handlers,
24
+ * policies and site keys this version implements. Under 80 lines by design.
25
+ */
26
+ export function renderAgentsGuide({ routes } ) {
27
+ assert(Number.isInteger(routes) && routes >= 0 && routes <= 100000, 'Route count must be a non-negative integer');
28
+ const catalog = getCapabilities('self-hosted');
29
+ const native = new Set(catalog.capabilities.filter(row => row.targets['self-hosted']?.support === 'native').map(row => row.capability));
30
+ const handlers = handlerNames.filter(name => native.has(name));
31
+ const policies = Object.keys(registry).filter(name => native.has(`policies.${name}` ));
32
+ const site = Object.entries(generatedPaths).map(([key, path]) => `\`${key}\` (${path})`);
33
+ return `# Working on this project
34
+
35
+ This project uses URLCode: URL behavior is declared in \`urlcode.yaml\`, and the
36
+ installed \`@jimhoyd/urlcode\` runtime serves it. There is no framework code to
37
+ write for routing, validation, middleware wiring, policies, static serving or
38
+ authentication; the runtime provides them. Read this file before changing anything.
39
+
40
+ ## Before writing code
41
+
42
+ 1. Inspect \`urlcode.yaml\` first, then every file its \`includes\` list names,
43
+ the referenced functions, middleware and \`tests/requests.json\`. Preserve the
44
+ existing organization and every route you were not asked to change.
45
+ 2. Run \`urlcode capabilities\` to see what this runtime version implements and
46
+ which targets support it; \`urlcode capabilities --target NAME\` before
47
+ promising any provider deployment.
48
+ 3. Run \`urlcode recipes list\` and \`urlcode recipes show NAME\` before writing a
49
+ route from scratch. If a recipe covers the need, add it with
50
+ \`urlcode recipes add NAME --out DIR\` and adapt the copy.
51
+ 4. Prefer YAML over code. Prefer native handlers over functions.
52
+
53
+ ## Ask the runtime through MCP first
54
+
55
+ \`${mcpConfigFile}\` registers the read-only \`urlcode mcp\` server. When it is
56
+ available, prefer its tools over reading documents: \`get_context\`,
57
+ \`get_capability\`, \`get_schema\`, \`search_recipes\`, \`explain\`, \`get_manifest\`.
58
+ The CLI equivalents are the fallback: \`urlcode context\`, \`urlcode capabilities NAME\`,
59
+ \`urlcode schema PATH\`, \`urlcode recipes search TEXT\`, \`urlcode explain PATH\`,
60
+ \`urlcode manifest\`. \`--allow-authoring\` is an operator opt-in; never add it yourself.
61
+
62
+ ## What the runtime provides (this version)
63
+
64
+ - Handlers, exactly one per route: ${handlers.map(name => `\`${name}\``).join(', ')}.
65
+ - Ordered \`middleware\` around any handler, declared in YAML, run in the sandbox.
66
+ - Validated inputs: \`parameters\`, \`request.body\` and \`methods\` on the route;
67
+ functions receive validated \`args\`, never raw user input.
68
+ - Policies, host-enforced and off by default: ${policies.map(name => `\`${name}\``).join(', ')}.
69
+ - Site conventions under \`site\`, each generating one native route: ${site.join(', ')}.
70
+ - Bindings: named \`env\` and \`secrets\` references resolved by the operator, never values in YAML.
71
+
72
+ Never recreate any of these in a function. If a requirement seems to need one
73
+ of them and it is missing, that is a report, not an invitation to reimplement.
74
+
75
+ ## Functions and middleware are sandboxed
76
+
77
+ Guest code runs in an isolated JavaScript engine with a fresh heap per call.
78
+ It sees a text/JSON \`Request\`/\`Response\` subset, validated \`args\` and granted
79
+ \`env\`. There is no \`fetch\`, no Node API, no filesystem, no timers and no
80
+ imports outside the project. Do not write code that needs them; declare a
81
+ \`proxy\` route or a binding instead and say why.
82
+
83
+ ## Checks that count as evidence
84
+
85
+ \`\`\`sh
86
+ urlcode validate --local
87
+ urlcode test
88
+ urlcode audit --expect-routes ${routes}
89
+ \`\`\`
90
+
91
+ Run all three after every change. Update the expected route count deliberately
92
+ when you add or remove a route, and add fixtures to \`tests/requests.json\` for
93
+ every new route (positive and negative cases, every active method, HEAD).
94
+ Without a global install, invoke \`node /path/to/urlcode/src/cli.ts\` instead of \`urlcode\`.
95
+
96
+ ## Rules
97
+
98
+ - Report unsupported requirements instead of inventing fields. The schema is
99
+ exact; a field the validator rejects does not exist. Say what is missing.
100
+ - Never create or approve operator grants. Request a named binding in YAML and
101
+ stop; the operator grants it outside this project, pinned to the revision.
102
+ - Secrets stay out of the project: no keys, tokens or credentials in YAML,
103
+ functions, fixtures, \`.env\` files that are not ignored, or commit messages.
104
+ - Authentication is host processing: declare \`auth\` on the route, never build
105
+ login forms, sessions or password checks in functions.
106
+ - Validation, tests and the audit are the evidence. Local checks are not a
107
+ deployment, a soak test or a security review; do not claim otherwise.
108
+
109
+ The installed package ships an agent skill with the same loop at
110
+ \`${skillPath}\` inside \`@jimhoyd/urlcode\` (for example
111
+ \`node_modules/@jimhoyd/urlcode/${skillPath}\`).
112
+ `;
113
+ }
@@ -0,0 +1,60 @@
1
+ import {lstat,realpath,open,mkdir,rm,rename} from 'node:fs/promises';
2
+ import {resolve,join,dirname,basename,parse} from 'node:path';
3
+ import {assert} from './errors.js';
4
+
5
+ /** Authoring output never copies hidden state, package hooks, or credential files. */
6
+ export function authoringPath(path ) {
7
+ const parts=path.split('/');
8
+ assert(path.length>0 && path.length<=1024 && parts.length<=32 && parts.every(part=>
9
+ part && !part.startsWith('.') && !/[. ]$/.test(part) && !/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part) && !/[\\:*?"<>|\u0000-\u001f\u007f]/u.test(part) &&
10
+ !/^(?:node_modules|package(?:-lock)?\.json|.*\.(?:pem|key|p12|pfx|env))$/i.test(part)), 'Authoring paths must be safe non-sensitive project-relative paths');
11
+ return path;
12
+ }
13
+ export async function authoringFile(root ,path ,directory=false) {
14
+ authoringPath(path);let file=root;
15
+ for(const [index,part] of path.split('/').entries()){
16
+ file=join(file,part);const info=await lstat(file);
17
+ assert(!info.isSymbolicLink(),'Authoring through symlinks is forbidden');
18
+ assert(index<path.split('/').length-1 || directory ? info.isDirectory() : info.isFile() && info.nlink===1,'Authoring requires ordinary files and directories');
19
+ }
20
+ return file;
21
+ }
22
+ export async function readAuthoringFile(root ,path ,limit ) {
23
+ const file=await authoringFile(root,path),handle=await open(file,'r');
24
+ try {
25
+ const info=await handle.stat();assert(info.isFile() && info.nlink===1 && info.size<=limit,'Authoring source size limit exceeded');
26
+ const bytes=Buffer.alloc(info.size+1);let offset=0;
27
+ while(offset<bytes.length){const read=await handle.read(bytes,offset,bytes.length-offset,null);if(!read.bytesRead)break;offset+=read.bytesRead;}
28
+ assert(offset<=info.size,'Authoring source changed during read');return bytes.subarray(0,offset);
29
+ }finally{await handle.close();}
30
+ }
31
+ /** Reserve a fresh directory exclusively, then publish the entry config last.
32
+ * Failed writes remove only the directory created by this invocation. No existing
33
+ * directory (even an empty one) is accepted; consumers see no activatable project
34
+ * until every dependency has been written. Callers must own the output parent.
35
+ */
36
+ export async function publishAuthoringProject(output ,files ,dryRun=false) {
37
+ assert(files.has('urlcode.yaml'),'Authoring output requires urlcode.yaml');
38
+ assert(files.size<=10000,'Authoring file limit exceeded');
39
+ const paths=new Set ();
40
+ for(const path of files.keys()){
41
+ authoringPath(path);const key=path.toLowerCase();assert(!paths.has(key),'Conflicting authoring output paths');paths.add(key);
42
+ }
43
+ for(const path of paths){let parent=dirname(path);while(parent!=='.'){assert(!paths.has(parent),'Authoring file/directory conflict');parent=dirname(parent);}}
44
+ const target=resolve(output),parent=dirname(target);assert(target!==parse(target).root,'Invalid authoring output');
45
+ assert(!(await lstat(parent)).isSymbolicLink(),'Authoring output parent must not be a symlink');
46
+ const destination=join(await realpath(parent),basename(target));
47
+ let exists=false;try{await lstat(destination);exists=true;}catch(error){if(!(error instanceof Error && 'code' in error && error.code==='ENOENT'))throw error;}
48
+ assert(!exists,'Authoring output already exists');
49
+ if(dryRun)return destination;
50
+ await mkdir(destination,{mode:0o700});
51
+ try {
52
+ const entries=[...files].sort(([a],[b])=>a==='urlcode.yaml'?1:b==='urlcode.yaml'?-1:a.localeCompare(b));
53
+ for(const [path,content] of entries){
54
+ const file=join(destination,path==='urlcode.yaml'?'.urlcode.yaml.pending':path);await mkdir(dirname(file),{recursive:true,mode:0o700});
55
+ const handle=await open(file,'wx',0o600);try{await handle.writeFile(content);await handle.sync();}finally{await handle.close();}
56
+ if(path==='urlcode.yaml')await rename(file,join(destination,'urlcode.yaml'));
57
+ }
58
+ return destination;
59
+ }catch(error){await rm(destination,{recursive:true,force:true});throw error;}
60
+ }
package/dist/authoring.js CHANGED
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
4
4
  import { randomBytes } from 'node:crypto';
5
5
  import { parseDocument } from 'yaml';
6
6
  import { loadDocument, validateDocument } from './config.js';
7
+ import { renderAgentsGuide, renderMcpConfig, mcpConfigFile } from './agents-guide.js';
7
8
  import { compileRoutes } from './router.js';
8
9
  import { prepareFunctionSnapshot, requestedPermissions } from './policy.js';
9
10
  import { assert } from './errors.js';
@@ -17,9 +18,18 @@ export async function initProject(destination ) {
17
18
  try {
18
19
  const source = fileURLToPath(new URL('../starters/default/', import.meta.url));
19
20
  for (const file of await readdir(source)) {
20
- if (file === '.gitignore') continue;
21
+ if (file === '.gitignore' || file === 'AGENTS.md' || file === mcpConfigFile) continue;
21
22
  await cp(join(source,file), join(target,file === 'gitignore.template' ? '.gitignore' : file), { recursive: true, force: false, errorOnExist: true });
22
23
  }
24
+ // AGENTS.md is generated from the installed runtime's capability catalog so
25
+ // it names only what this version implements; the starter carries a
26
+ // committed copy for clones, kept identical by test.
27
+ const routes = Object.keys((await loadDocument(target)).routes).length;
28
+ const guide = await open(join(target,'AGENTS.md'), 'wx', 0o644);
29
+ try { await guide.writeFile(renderAgentsGuide({ routes })); } finally { await guide.close(); }
30
+ // .mcp.json registers the read-only server for repository-aware agents; the starter carries the same bytes.
31
+ const mcp = await open(join(target,mcpConfigFile), 'wx', 0o644);
32
+ try { await mcp.writeFile(renderMcpConfig('.')); } finally { await mcp.close(); }
23
33
  } catch (error) { await rm(target, { recursive: true, force: true }); throw error; }
24
34
  return target;
25
35
  }
package/dist/aws.js CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  import { randomUUID } from 'node:crypto';
2
3
  import { activateNativeOnly, lazyRuntime, resolveOrigin } from './adapters.js';
3
4
 
@@ -6,7 +7,7 @@ import { prepareResponse, errorResponse } from './http-response.js';
6
7
 
7
8
  import { assert, ConfigError, HttpError } from './errors.js';
8
9
 
9
-
10
+
10
11
  /** A Lambda payload format 2.0 event, as far as this adapter reads it. */
11
12
 
12
13
 
@@ -64,9 +65,9 @@ function requestBody(event , limit ) {
64
65
  // Builds a Lambda handler for payload format 2.0. The runtime is created once
65
66
  // per execution environment and reused across warm invocations.
66
67
  export function createLambdaHandler({ project = process.cwd(), origin, environment = process.env,
67
- maxBodyBytes = 1048576, plugins } = {}) {
68
+ maxBodyBytes = 1048576, plugins, extensions } = {}) {
68
69
  assert(Number.isInteger(maxBodyBytes) && maxBodyBytes >= 1 && maxBodyBytes <= 16777216, 'Request limit must be 1–16777216 bytes');
69
- const ready = lazyRuntime(() => activateNativeOnly(project, environment, { target: 'aws', plugins }));
70
+ const ready = lazyRuntime(() => activateNativeOnly(project, environment, { target: 'aws', plugins, extensions, origin:resolveOrigin(origin,environment,platformOrigins) }));
70
71
 
71
72
  return async function handler(raw) {
72
73
  const requestId = randomUUID();
@@ -1,3 +1,4 @@
1
+ import { analyzeProjectCapabilities, analyzeCompiledCapabilities, assertTargetCompatibility } from './capabilities.js';
1
2
  import { mkdir, writeFile } from 'node:fs/promises';
2
3
  import { join } from 'node:path';
3
4
  import Ajv from 'ajv/dist/2020.js';
@@ -8,23 +9,12 @@ import { assert } from './errors.js';
8
9
  import { effectivePolicies, registry } from './policies.js';
9
10
  import { resolveLists } from './agent-lists.js';
10
11
  import { applySite } from './site.js';
12
+ import { buildManifest, renderManifest, manifestPath } from './manifest.js';
11
13
 
12
14
 
13
15
 
14
16
 
15
-
16
-
17
- // Handlers this target cannot serve, and why. Declarative routes only in this
18
- // slice: assets need a platform binding rather than an inline copy, and the
19
- // sandbox needs facilities the platform does not provide.
20
- const unsupported = {
21
- function:'isolated functions need worker threads and the WASM engine',
22
- link:'stored live links need a durable writable store',
23
- page:'pages need a static-asset binding',
24
- static:'static directories need a static-asset binding',
25
- download:'downloads need a static-asset binding',
26
- } ;
27
- const unsupportedHandlers = ['function','link','page','static','download'] ;
17
+
28
18
 
29
19
  // The artifact is this runtime's build output, not a published contract: the
30
20
  // format may change with any release, and the runtime refuses a version it does
@@ -80,24 +70,21 @@ export async function buildCloudflare(project , { out = 'dist/cloudflare'
80
70
  // Generated site routes are built like declared ones; the ones that need
81
71
  // an origin get it from --origin, exactly as the server does.
82
72
  await applySite(loaded, { origin, log });
73
+ assertTargetCompatibility(analyzeProjectCapabilities(loaded, 'cloudflare'));
83
74
  // No bindings are resolved: a build artifact must never carry a secret, and
84
75
  // this target has no per-request operator policy to pin one to.
85
76
  const compiled = await compileRoutes(loaded, {}, {}, undefined);
86
77
  const routes = [...compiled.exact.values(), ...[...compiled.byLength.values()].flat(), ...compiled.mounts];
87
78
 
88
- const refused = [];
79
+ assertTargetCompatibility(analyzeCompiledCapabilities(loaded.document, compiled, 'cloudflare'));
89
80
  for (const route of routes) {
90
- for (const handler of unsupportedHandlers) {
91
- if (route[handler]) refused.push(`${route.pattern}: ${unsupported[handler]}`);
92
- }
93
- if (route.middleware?.length) refused.push(`${route.pattern}: middleware needs the sandbox`);
94
81
  const policies = effectivePolicies(loaded.document, route);
95
82
  for (const name of Object.keys(policies)) {
96
83
  assert(isPolicyName(name), `Unknown policy "${name}"`);
97
84
  const support = policyModule(name).targets(policies[name]).cloudflare;
98
85
  // The platform provides it: accepted and dropped, never carried.
99
86
  if (support === 'delegated') { delete policies[name]; continue; }
100
- if (!compilablePolicies.has(name) || support !== 'compiled') refused.push(`${route.pattern}: policies.${name} cannot be compiled for this target`);
87
+ assert(compilablePolicies.has(name) && support === 'compiled', `${route.pattern}: policies.${name} cannot be compiled for this target`);
101
88
  }
102
89
  // Project-relative agent lists are read here, once, so the artifact
103
90
  // carries the patterns and the Worker never needs a filesystem.
@@ -109,11 +96,7 @@ export async function buildCloudflare(project , { out = 'dist/cloudflare'
109
96
  // evaluates a configuration the runtime would have rejected.
110
97
  for (const name of Object.keys(policies)) if (isPolicyName(name) && compilablePolicies.has(name)) await policyModule(name).compile(policies[name], { route, shared: {}, target: 'cloudflare', document: loaded.document, root: loaded.root });
111
98
  if (Object.keys(policies).length) route.compiledPolicies = policies; else delete route.compiledPolicies;
112
- if (Object.keys(route.env).length || Object.keys(route.secrets).length) {
113
- refused.push(`${route.pattern}: env and secret bindings would have to be baked into the artifact`);
114
- }
115
99
  }
116
- assert(!refused.length, `This target serves declarative routes only:\n ${refused.join('\n ')}`);
117
100
  assert(routes.length, 'No routes to build');
118
101
 
119
102
  const ajv = new Ajv.default({ code:{ source:true, esm:true }, strict:false, allErrors:false });
@@ -159,6 +142,10 @@ import * as validators from './validators.js';
159
142
 
160
143
  export default { fetch: createFetchHandler(artifact, validators) };
161
144
  `);
145
+ // The semantic manifest travels with the artifact so a reviewer can read
146
+ // what was built without the project checkout (docs/TOOLING.md).
147
+ const manifest = manifestPath(out);
148
+ await writeFile(manifest, renderManifest(await buildManifest(project, origin === undefined ? {} : { origin })));
162
149
  return { out, format:FORMAT, version:loaded.version, routes:serialised.length,
163
- validators:Object.keys(validators).length };
150
+ validators:Object.keys(validators).length, manifest };
164
151
  }
package/dist/bulk.js ADDED
@@ -0,0 +1,37 @@
1
+ import {createHash} from 'node:crypto';
2
+ import {stringify} from 'yaml';
3
+ import {importRoutes} from './interchange.js';
4
+
5
+ import {publishAuthoringProject} from './authoring-files.js';
6
+ import {assert} from './errors.js';
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+ /** Import ordinary redirect rows into small, portable include files. There is no
15
+ * merge mode: duplicate rules and existing output directories are refused. */
16
+ export async function importBulkProject(text ,format ,output ,{dryRun=false,source='<input>'} ={}) {
17
+ assert(['csv','json','yaml'].includes(format),'Bulk input must be csv, json or yaml');
18
+ assert(source.length<=1024 && !/[\u0000-\u001f\u007f]/u.test(source),'Invalid bulk provenance source name');
19
+ const provenance={name:source,format,sha256:createHash('sha256').update(text).digest('hex')};
20
+ const converted=await importRoutes({text,format,source});
21
+ const report ={ok:converted.ok,dryRun,routeCount:converted.routeCount,diagnostics:converted.diagnostics,files:[],source:provenance};
22
+ if(!converted.ok || !converted.document)return report;
23
+ const files=new Map (),entries=Object.entries(converted.document.routes),includes =[];
24
+ // 100 includes at the 100,000-route cap; each parser AST stays small without
25
+ // changing the configuration worker heap, wall deadline or include limits.
26
+ for(let offset=0;offset<entries.length;offset+=1000){
27
+ const group=entries.slice(offset,offset+1000),path=`routes/redirects-${String(includes.length+1).padStart(3,'0')}.yaml`;
28
+ includes.push(path);files.set(path,stringify({version:'1',routes:Object.fromEntries(group)}));
29
+ report.files.push({path,routeCount:group.length,firstPath:group[0] [0],lastPath:group.at(-1) [0]});
30
+ }
31
+ files.set('urlcode.yaml',stringify({version:'1',...(includes.length?{includes}:{}),routes:{}}));
32
+ report.files.unshift({path:'urlcode.yaml',routeCount:0});
33
+ const metadata={version:1,source:provenance,routeCount:report.routeCount,files:report.files};
34
+ files.set('provenance.json',JSON.stringify(metadata,null,2)+'\n');report.files.push({path:'provenance.json',routeCount:0});
35
+ report.output=await publishAuthoringProject(output,files,dryRun);
36
+ return report;
37
+ }