@jimhoyd/urlcode 0.5.6 → 0.5.9
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.
- package/.claude/skills/urlcode-authoring/SKILL.md +15 -0
- package/.claude/skills/urlcode-operations/SKILL.md +4 -0
- package/README.md +24 -14
- package/dist/BUILD-MANIFEST.json +51 -50
- package/dist/agent-context.js +9 -0
- package/dist/agents-guide.js +5 -2
- package/dist/assets.js +2 -2
- package/dist/authoring.js +3 -58
- package/dist/aws.js +21 -4
- package/dist/body-schema.js +2 -3
- package/dist/capability-query.js +3 -3
- package/dist/catalog.js +1 -1
- package/dist/cli.js +42 -15
- package/dist/cloudflare.js +26 -1
- package/dist/config.js +1 -1
- package/dist/context.js +6 -6
- package/dist/egress.js +1 -1
- package/dist/examples.js +2 -2
- package/dist/explain.js +4 -6
- package/dist/extension-artifacts.js +8 -8
- package/dist/extension-transport.js +6 -4
- package/dist/function-worker.js +5 -2
- package/dist/functions.js +1 -1
- package/dist/guest-api.js +22 -15
- package/dist/http-policy.js +1 -3
- package/dist/http-response.js +61 -10
- package/dist/init-with.js +8 -8
- package/dist/interchange.js +3 -2
- package/dist/logging.js +4 -4
- package/dist/match.js +1 -1
- package/dist/mcp-authoring.js +1 -2
- package/dist/mcp.js +6 -3
- package/dist/object-guards.js +17 -0
- package/dist/pattern-guard.js +33 -3
- package/dist/policies/cache.js +16 -4
- package/dist/policies/compression.js +1 -1
- package/dist/policies/throttle.js +1 -1
- package/dist/policy.js +3 -3
- package/dist/prerender.js +1 -2
- package/dist/project-dependencies.js +8 -8
- package/dist/proxy.js +1 -1
- package/dist/readiness.js +16 -17
- package/dist/review.js +2 -2
- package/dist/route-diff.js +4 -4
- package/dist/router.js +1 -1
- package/dist/runtime.js +4 -1
- package/dist/scaffold.js +1 -1
- package/dist/schema-query.js +1 -1
- package/dist/server.js +49 -7
- package/dist/signals.js +2 -2
- package/dist/site.js +2 -2
- package/dist/trusted-functions.js +1 -1
- package/dist/types/assets.d.ts +3 -2
- package/dist/types/authoring.d.ts +3 -6
- package/dist/types/body-schema.d.ts +2 -1
- package/dist/types/catalog.d.ts +2 -1
- package/dist/types/config.d.ts +0 -8
- package/dist/types/context.d.ts +3 -1
- package/dist/types/egress.d.ts +1 -1
- package/dist/types/explain.d.ts +4 -4
- package/dist/types/extension-artifacts.d.ts +4 -13
- package/dist/types/extension-transport.d.ts +6 -4
- package/dist/types/functions.d.ts +1 -1
- package/dist/types/http-response.d.ts +7 -3
- package/dist/types/init-with.d.ts +3 -9
- package/dist/types/logging.d.ts +4 -3
- package/dist/types/match.d.ts +2 -1
- package/dist/types/object-guards.d.ts +7 -0
- package/dist/types/pattern-guard.d.ts +0 -1
- package/dist/types/policies/cache.d.ts +4 -3
- package/dist/types/policies/compression.d.ts +1 -1
- package/dist/types/policies/throttle.d.ts +1 -1
- package/dist/types/policy.d.ts +4 -3
- package/dist/types/project-dependencies.d.ts +1 -40
- package/dist/types/proxy.d.ts +2 -1
- package/dist/types/readiness.d.ts +12 -16
- package/dist/types/review.d.ts +0 -2
- package/dist/types/route-diff.d.ts +4 -3
- package/dist/types/router.d.ts +1 -1
- package/dist/types/server.d.ts +22 -0
- package/dist/types/signals.d.ts +3 -2
- package/dist/types/site.d.ts +1 -2
- package/dist/types/trusted-functions.d.ts +1 -1
- package/dist/types/types.d.ts +17 -11
- package/dist/types/vercel.d.ts +1 -0
- package/dist/types/verify-deployment.d.ts +1 -1
- package/dist/types.js +18 -11
- package/dist/vercel.js +12 -3
- package/dist/verify-deployment.js +29 -11
- package/docs/AI-AUTHORING.md +9 -0
- package/docs/FUNCTION-SECURITY.md +4 -0
- package/docs/README.md +2 -2
- package/docs/TOOLING.md +35 -1
- package/examples/assets/Makefile +1 -1
- package/examples/compliance/rules.mjs +2 -2
- package/llms-full.txt +44 -13
- package/llms.txt +9 -2
- package/package.json +8 -3
- package/skills/urlcode/SKILL.md +6 -6
- package/starters/default/.github/workflows/urlcode.yml +2 -1
- package/starters/default/AGENTS.md +3 -3
- package/starters/default/Makefile +1 -1
- package/starters/default/README.md +13 -11
- package/starters/default/tests/requests.json +0 -50
- package/starters/default/urlcode.yaml +1 -4
- package/dist/scripts/operational-drills.js +0 -33
- package/starters/default/functions/hello.mjs +0 -3
- package/starters/default/middleware/headers.mjs +0 -6
- package/starters/default/routes/functions.yaml +0 -20
- package/starters/default/routes/marketing/links.yaml +0 -7
- package/starters/page/README.md +0 -14
- package/starters/page/public/index.html +0 -12
- package/starters/page/tests/requests.json +0 -17
- package/starters/page/urlcode.yaml +0 -6
|
@@ -11,6 +11,15 @@ validates. Features outside that contract do not silently degrade — they fail
|
|
|
11
11
|
validation. So the cost of guessing is a broken project, and the whole job here
|
|
12
12
|
is to author only what the pinned revision implements and then prove it.
|
|
13
13
|
|
|
14
|
+
## No project yet? Install the scoped package
|
|
15
|
+
|
|
16
|
+
The npm package is `@jimhoyd/urlcode` — always scoped. There is no unscoped
|
|
17
|
+
`urlcode` package on the registry; `npm view urlcode` 404s. Install with
|
|
18
|
+
`npm install @jimhoyd/urlcode`, then scaffold with
|
|
19
|
+
`npx urlcode init .` (works in a directory holding only
|
|
20
|
+
`package.json`, `package-lock.json`, `node_modules` or `.git`). Once installed,
|
|
21
|
+
the rest of this skill and `urlcode context --project DIR` take over.
|
|
22
|
+
|
|
14
23
|
## Declarative-first default
|
|
15
24
|
|
|
16
25
|
> Use URLCode's highest-level declarative features whenever possible. Generate custom code only when the framework cannot express the requirement.
|
|
@@ -38,6 +47,12 @@ supplies a host file, `get_extensions`. Bare `urlcode capabilities`, `recipes
|
|
|
38
47
|
list`, the compact `llms.txt` index and `llms-full.txt` remain deliberate
|
|
39
48
|
fallback/reference: in a source checkout read the matching task guide from
|
|
40
49
|
`docs/`; in an npm installation search the heading in `llms-full.txt`.
|
|
50
|
+
[URLCode AI](https://urlcode.ai/) is an optional, separate hosted service for
|
|
51
|
+
shared skills and LLM tooling. Its remote MCP supplements the local
|
|
52
|
+
project-aware `urlcode` server; never replace `.mcp.json` or put its bearer
|
|
53
|
+
token in project files. Configure it only through the MCP client's secret
|
|
54
|
+
facility; see the URLCode tooling guide for connection details. Its
|
|
55
|
+
machine-readable entry point is `https://urlcode.ai/llms.txt`.
|
|
41
56
|
When the project has an operator host file, inspect `urlcode extensions
|
|
42
57
|
--project <dir> --host-file <absolute-file> --json` (MCP: `get_extensions`)
|
|
43
58
|
before writing extension configuration or project hooks. The report is the
|
|
@@ -40,6 +40,10 @@ does not duplicate the repository's authored documentation tree.
|
|
|
40
40
|
|
|
41
41
|
`llms.txt` at the repository root indexes all of the above alongside the
|
|
42
42
|
authoring docs.
|
|
43
|
+
[URLCode AI](https://urlcode.ai/) is the optional hosted companion for shared
|
|
44
|
+
skills and LLM tooling. It does not replace local deployment checks or the
|
|
45
|
+
project-aware `urlcode mcp` server. Its machine-readable entry point is
|
|
46
|
+
`https://urlcode.ai/llms.txt`.
|
|
43
47
|
|
|
44
48
|
## Workflow
|
|
45
49
|
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ console as operator-installed extensions instead of building them again.
|
|
|
10
10
|
|
|
11
11
|
[](https://github.com/jimhoyd-com/urlcode/actions/workflows/ci.yml)
|
|
12
12
|
|
|
13
|
-
[Documentation](docs/README.md) · [The framework](docs/FRAMEWORK.md) · [For AI agents](llms.txt) · [Starter](https://github.com/jimhoyd-com/urlcode-template) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md)
|
|
13
|
+
[Documentation](docs/README.md) · [The framework](docs/FRAMEWORK.md) · [For AI agents](llms.txt) · [URLCode AI](https://urlcode.ai/) · [Starter](https://github.com/jimhoyd-com/urlcode-template) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md)
|
|
14
14
|
|
|
15
15
|
**Your AI should build your application, not your framework.** Coding agents
|
|
16
16
|
rebuild the same routing, validation, middleware, policies and authentication
|
|
@@ -37,8 +37,8 @@ come only from operator grants pinned to the project revision; grants govern
|
|
|
37
37
|
that injected context, not the ambient Node environment a trusted, in-process
|
|
38
38
|
module can reach on its own like any other code in the host.
|
|
39
39
|
|
|
40
|
-
URLCode is not a URL shortener: stored short links are
|
|
41
|
-
extension, not core's job. It is not a
|
|
40
|
+
URLCode is not a URL shortener: stored short links are declared through the
|
|
41
|
+
operator-installed `store` extension's collections, not core's job. It is not a
|
|
42
42
|
general Node web framework: routing, validation, middleware wiring and
|
|
43
43
|
policies are declared in YAML, not hand-wired; isolating a specific route's
|
|
44
44
|
code from the host is an explicit `sandbox: true` opt-in, not something every
|
|
@@ -48,7 +48,7 @@ See [project direction](docs/PROJECT-DIRECTION.md).
|
|
|
48
48
|
|
|
49
49
|
## The framework
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
Six packages, one project shape. A project climbs from redirects to a full
|
|
52
52
|
application by adding YAML; the operator wires trusted packages in one host
|
|
53
53
|
file outside the project. The full map, the composition contract and the rules
|
|
54
54
|
an AI agent must follow are in [the framework](docs/FRAMEWORK.md).
|
|
@@ -59,6 +59,8 @@ an AI agent must follow are in [the framework](docs/FRAMEWORK.md).
|
|
|
59
59
|
| [urlcode-ui](packages/ui) (workspace source) | Shared presentation: escaped templates, shadcn/ui partials, themes, translations | signed `extension-bundles@v…` GitHub Release |
|
|
60
60
|
| [urlcode-auth](packages/auth) (workspace source) | Accounts: password, passkeys, OIDC, email codes, TOTP, sessions, roles, account page | signed `extension-bundles@v…` GitHub Release |
|
|
61
61
|
| [urlcode-admin](packages/admin) (workspace source) | Administration: users, sessions, roles, audit, approvals, cases, impersonation | signed `extension-bundles@v…` GitHub Release |
|
|
62
|
+
| [urlcode-store](packages/store) (workspace source) | Durable bounded JSON collections exposed as a typed CRUD API | signed `extension-bundles@v…` GitHub Release |
|
|
63
|
+
| [urlcode-forms](packages/forms) (workspace source) | Bounded server-rendered form flows: escaped controls, admission, CSRF, validation | unreleased bundle source |
|
|
62
64
|
|
|
63
65
|
Core stays available from npm, GitHub Releases and Homebrew. New sites install
|
|
64
66
|
extensions from an immutable, attested `extension-bundles@v…` GitHub Release;
|
|
@@ -69,9 +71,10 @@ and channel alignment](docs/VERSION-ALIGNMENT.md).
|
|
|
69
71
|
|
|
70
72
|
`urlcode-dynamic-link` and `urlcode-short` were published once as
|
|
71
73
|
`0.1.0-alpha.1` and have since been retired: both were unpublished from npm and
|
|
72
|
-
their repositories deleted, and neither has a successor.
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
their repositories deleted, and neither has a direct successor. A project that
|
|
75
|
+
wants stored short links declares a collection through the `store` extension
|
|
76
|
+
(see [docs/STORE.md](docs/STORE.md)) instead. Anything still pinned to
|
|
77
|
+
`@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1`
|
|
75
78
|
also has to deal with its exact declared peer `@jimhoyd/urlcode: 0.4.0-alpha.1`,
|
|
76
79
|
which cannot be installed beside core `0.4.0-alpha.2` and never will be.
|
|
77
80
|
|
|
@@ -107,7 +110,7 @@ it. Cross-repository acceptance is tracked in
|
|
|
107
110
|
## Status
|
|
108
111
|
|
|
109
112
|
<!-- urlcode-current-version:start -->
|
|
110
|
-
This checkout prepares the coordinated `0.5.
|
|
113
|
+
This checkout prepares the coordinated `0.5.9` core, UI, auth, admin and store
|
|
111
114
|
release. Package availability remains a live registry fact: use `npm run
|
|
112
115
|
release:status` or the release's signed `train.json` before selecting an
|
|
113
116
|
install combination. Independent package versioning remains enabled, and a
|
|
@@ -130,7 +133,8 @@ remain open.
|
|
|
130
133
|
|
|
131
134
|
Core has no native `link` handler. Stored short links moved out to a
|
|
132
135
|
mount-based `urlcode-dynamic-link` extension, which has since been retired and
|
|
133
|
-
unpublished;
|
|
136
|
+
unpublished; a project that needs them declares a collection through the
|
|
137
|
+
`store` extension instead (see [docs/STORE.md](docs/STORE.md)).
|
|
134
138
|
|
|
135
139
|
URLCode is free and open-source software licensed under the
|
|
136
140
|
[Apache License 2.0](LICENSE). Commercial use, modification, redistribution and
|
|
@@ -144,6 +148,8 @@ Start with the [YAML guide and recipe book](docs/YAML-GUIDE.md),
|
|
|
144
148
|
authoring, use [the AI guide](docs/AI-AUTHORING.md), the bundled agent skills
|
|
145
149
|
([authoring](.claude/skills/urlcode-authoring/SKILL.md),
|
|
146
150
|
[operations](.claude/skills/urlcode-operations/SKILL.md)) and [llms.txt](llms.txt).
|
|
151
|
+
For optional shared skills and hosted LLM tooling, use [URLCode AI](https://urlcode.ai/);
|
|
152
|
+
its remote MCP augments, rather than replaces, the local project server.
|
|
147
153
|
Agents can also read project-pinned, signed declarative extension schemas through
|
|
148
154
|
the read-only MCP tools described in [extensions](docs/EXTENSIONS.md#signed-declarative-artifacts);
|
|
149
155
|
those artifacts are inert data, not an alternate executable package channel.
|
|
@@ -211,11 +217,12 @@ urlcode init my-urls && cd my-urls
|
|
|
211
217
|
urlcode dev
|
|
212
218
|
```
|
|
213
219
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
The starter deliberately has no routes. Ask the local MCP `get_context` tool
|
|
221
|
+
(or run `urlcode context --project .`), then add the smallest declarative route
|
|
222
|
+
or custom code the application needs. `urlcode test` runs the project's HTTP
|
|
223
|
+
fixtures. The [install guide](docs/INSTALL.md) covers the checksum-verified
|
|
224
|
+
script, project-local installs, the container image and signed provenance. To
|
|
225
|
+
work from a clone: `git clone … && make dev`.
|
|
219
226
|
|
|
220
227
|
## A URL that runs your function
|
|
221
228
|
|
|
@@ -283,6 +290,9 @@ capability matrix and a copyable task prompt. `urlcode mcp` exposes read-only
|
|
|
283
290
|
inspection, validation and conversion previews over stdio, and
|
|
284
291
|
`--allow-authoring` adds project-confined authoring tools
|
|
285
292
|
([tooling](docs/TOOLING.md)).
|
|
293
|
+
[URLCode AI](https://urlcode.ai/) is the optional hosted companion for shared
|
|
294
|
+
skills and LLM tooling; its authenticated remote MCP setup is documented in
|
|
295
|
+
[tooling](docs/TOOLING.md#optional-hosted-ai-mcp).
|
|
286
296
|
|
|
287
297
|
## Built with URLCode
|
|
288
298
|
|
package/dist/BUILD-MANIFEST.json
CHANGED
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
"node": "v26.9.0",
|
|
3
3
|
"files": {
|
|
4
4
|
"dist/adapters.js": "a7153ec52f2ed7e0cdd8ed7d433504815f402ec53b2b1c3d38d0cf0e2fcf6509",
|
|
5
|
-
"dist/agent-context.js": "
|
|
5
|
+
"dist/agent-context.js": "cdad0c535ea2771d993f5d9b10bc35aee563d3a6db9618cf97ed072f610164df",
|
|
6
6
|
"dist/agent-lists.js": "35ab484198897501d011cb6cc00b5a6787192e19df29c97646e8c118fcc19eef",
|
|
7
|
-
"dist/agents-guide.js": "
|
|
8
|
-
"dist/assets.js": "
|
|
7
|
+
"dist/agents-guide.js": "307d92879034ef019213ab5c15ff5806de3333da4bb263d46fa87049d1a85d5c",
|
|
8
|
+
"dist/assets.js": "85d8e379dab466bc406b2ea1a9385f1fcecb35d05d825eb83089c55a62f6d1a4",
|
|
9
9
|
"dist/authoring-files.js": "ad32814f9ae9c549c6247396f982aa700d13a293cc0a589609eccc68f8965550",
|
|
10
|
-
"dist/authoring.js": "
|
|
11
|
-
"dist/aws.js": "
|
|
12
|
-
"dist/body-schema.js": "
|
|
10
|
+
"dist/authoring.js": "a5620752a79d70525d36718411470fbc7ac9c7b4c8abb09a53355f92f9805393",
|
|
11
|
+
"dist/aws.js": "34bdbb85657426dc54a8301b5bcfa38c7559371215c430939438cc6b71dfa29e",
|
|
12
|
+
"dist/body-schema.js": "1c42bcd24187dfe0a7c5326f110081b714595fdfe577c2faea35cab3ca31d45a",
|
|
13
13
|
"dist/build-cloudflare.js": "ff92e72d0a63d70dd8c28b52978edd9fb23cb16601e4dfebd07c2cef7bd73661",
|
|
14
14
|
"dist/build-static.js": "3920b54bad9a44c75de79f0bef2b2a919bfb3e20a8619eaf8d48cad2856978ac",
|
|
15
15
|
"dist/bulk.js": "aac88d422bd9a7a341a421fb4e29ff5580b28d39250b7f1f5315ba20ae92da8a",
|
|
16
16
|
"dist/capabilities.js": "f14c17de63764f6f4686fc1404bf21aa5cf56125ad81e6d6157a429438fc0cbf",
|
|
17
|
-
"dist/capability-query.js": "
|
|
18
|
-
"dist/catalog.js": "
|
|
19
|
-
"dist/cli.js": "
|
|
17
|
+
"dist/capability-query.js": "00fbd8b592dea05de7487f3de21e6aa8808a6d2a90e8808811abeb843375dab3",
|
|
18
|
+
"dist/catalog.js": "629ed1d3580d5c5e238a4293e5b8491ba99d6948accda316bbd2ee3d7902cc0f",
|
|
19
|
+
"dist/cli.js": "98f0209fab9204401ad6950a3b9fea9f6029546ca905977ee5492d33b390b6f1",
|
|
20
20
|
"dist/client-address.js": "9d0d01466aab23124330605c5a0e0f981f87c897858acfad909f546a63df165b",
|
|
21
|
-
"dist/cloudflare.js": "
|
|
21
|
+
"dist/cloudflare.js": "b236918e499215ee42c2865181b3ed92decba0bf9d604f17f8b08736c86751d9",
|
|
22
22
|
"dist/compliance-rules/baseline.js": "6296dea6bcb9f9bb80ed6ed5ab2f456e7f74e6de2be5d2d98ca8c983fb4df3ab",
|
|
23
23
|
"dist/compliance-rules/privacy.js": "4cfb1c07d7df698c362dfc8761cd3bba893769e92d7fb0a3901e1c2d25e801f1",
|
|
24
24
|
"dist/compliance-rules/shared.js": "86fd6db6a93375689acc64975cbc394ce9452dea21ae5941e743f99822515995",
|
|
@@ -26,69 +26,70 @@
|
|
|
26
26
|
"dist/compliance.js": "29a18da3cefea94802ac7d817d1ab4e3674abd5c3ac4ef893cb8b01c6a23fb61",
|
|
27
27
|
"dist/conditions.js": "ff25e97da550a3bdd80af55522045669438aa31a77d2bc83ad602bcefdee0475",
|
|
28
28
|
"dist/config-worker.js": "bc2170d60c35f8d5de227cbfc4c5067dc61d7cbc5b98aed88e68a11797072da5",
|
|
29
|
-
"dist/config.js": "
|
|
30
|
-
"dist/context.js": "
|
|
29
|
+
"dist/config.js": "b5e6d30dd5679da001203772a15e3ed5da735d9115082344e2cc397c020d2aa4",
|
|
30
|
+
"dist/context.js": "4061e18ecbcf1db69c6c76070349d0621774c419f2f775f06952470191e64e44",
|
|
31
31
|
"dist/ecosystem-cli.js": "553911bf7e51c579ecd9d806f2ccfcba03ac601b87aa677c35147af36840e24d",
|
|
32
|
-
"dist/egress.js": "
|
|
32
|
+
"dist/egress.js": "d7e3a2a92c9fcb5a1a1a038ff39df0b3a1d72978d84c36c7de295fa1e5af861b",
|
|
33
33
|
"dist/errors.js": "fef26eb834dd61b8b5f587eb7ab265d216122d182545f0a1c5b19c20840dffb0",
|
|
34
|
-
"dist/examples.js": "
|
|
34
|
+
"dist/examples.js": "22f36ceaa0ce4455b31d05d453d26a6c865009cfc3ad66c5519e82353b78e24a",
|
|
35
35
|
"dist/explain-cli.js": "59050ad1139d419a23af4a844f2dc6b927c2bfd6599af7a2130b304733485f2d",
|
|
36
|
-
"dist/explain.js": "
|
|
37
|
-
"dist/extension-artifacts.js": "
|
|
36
|
+
"dist/explain.js": "29d0416dcbbc3ea349c9f927ea7f8d0f8f1cc0b6d25346a4deabc140aa517711",
|
|
37
|
+
"dist/extension-artifacts.js": "8c41bd33eea467869bf73b32dcce5ea7b533042058afd333102b53db6326b477",
|
|
38
38
|
"dist/extension-bundles.js": "48d4cb64d2bbee8010447845eef491ee0be994e4867755f69ad8ee9105afbb29",
|
|
39
|
-
"dist/extension-transport.js": "
|
|
39
|
+
"dist/extension-transport.js": "8e56d20eb68dadf05026436af2eef19fed5296884c73834b1623333275c8900e",
|
|
40
40
|
"dist/extensions.js": "ec4b1784fe278a5293ec12651765184bf57dac7146c0627dc9cb31deeb01a928",
|
|
41
41
|
"dist/feature-plan.js": "214af2d3aac042386df2ca7ce06ee505a78d2e80a38bb4ef0e5b96a4a9866a97",
|
|
42
42
|
"dist/function-sources.js": "16fad4abc81c7ee07b6cbcef2d23a9fc50e97a17cb4dde1db53469bbb555c96f",
|
|
43
|
-
"dist/function-worker.js": "
|
|
44
|
-
"dist/functions.js": "
|
|
45
|
-
"dist/guest-api.js": "
|
|
43
|
+
"dist/function-worker.js": "17f8c81d3e1ad7e509266ba30b8975adc3e845e4d873f805e59369b8cf09f3ec",
|
|
44
|
+
"dist/functions.js": "9a12458423bbaad1b5073447e4305002d63348949c8bc07878dc9671a2c51a9f",
|
|
45
|
+
"dist/guest-api.js": "7668bb0e8bbbfc05c5e34bace436727735f5aa52f776fbc3e9edca3e7ff91fcb",
|
|
46
46
|
"dist/header-validation.js": "465181dbb08ff05f52defdd29fda025c0c64589bf319fa87fa6d3ab4b68216d5",
|
|
47
|
-
"dist/http-policy.js": "
|
|
48
|
-
"dist/http-response.js": "
|
|
47
|
+
"dist/http-policy.js": "4fc00bc235ec70b0ed0a71e4af7501cc255a7e02268fd59387d7498075cfc284",
|
|
48
|
+
"dist/http-response.js": "c34d3e1436284f1339de411c6839419d1118f993ad67a8caa17da0268a779f66",
|
|
49
49
|
"dist/index.js": "5e535104c672e70fa42f847ce6722c3b0bb2e3a9eac37f6a3c45d1a771f65f50",
|
|
50
|
-
"dist/init-with.js": "
|
|
50
|
+
"dist/init-with.js": "3e642ee85b0b51887b6fc877d6c8099500446376641d9f60bf31f64f407bbf8b",
|
|
51
51
|
"dist/interchange-cli.js": "35bd70ba8077af5c3e39404ff0e5d28707632090a59a90645141252449fd3f04",
|
|
52
|
-
"dist/interchange.js": "
|
|
53
|
-
"dist/logging.js": "
|
|
52
|
+
"dist/interchange.js": "3d9c79ca946b6cc3d14895c5bb3fdb3064ed0ca750cd326270fec2ba8c287403",
|
|
53
|
+
"dist/logging.js": "92f7a2cafc75be0cce560e0797bcaf8c98ab4d67338eda1dfc8c3a914f1b03a3",
|
|
54
54
|
"dist/manifest.js": "83eed0d59621039ef364cf6e7b54c5bd47e0d8cf0a5abe7b07344bfc1db56ed8",
|
|
55
|
-
"dist/match.js": "
|
|
56
|
-
"dist/mcp-authoring.js": "
|
|
57
|
-
"dist/mcp.js": "
|
|
55
|
+
"dist/match.js": "9069dfc59d485c7ed3b618d4ab4cfabcd67299ea4c45c646565e44a57b4bd51d",
|
|
56
|
+
"dist/mcp-authoring.js": "0753fb4f330ab710c7ee115315d7beb33b11faa80ca1b4fc114f5561c8abf7a7",
|
|
57
|
+
"dist/mcp.js": "fe94c09e0e57d18fa23ecb79b872c267f3644fc4ab3e00f9167f9ad9035b418c",
|
|
58
|
+
"dist/object-guards.js": "5af6012c803e9d587cb4270f52011bd2ba3e4655f73198dddc4ca327cdf89675",
|
|
58
59
|
"dist/observability.js": "f4b1ab496f051fe3ef2ed36b2b2e469c63a8940700e2df852e6ff2d9cccdd5ae",
|
|
59
60
|
"dist/operator-host.js": "e3dac9d43a83beb775202b4ab9eeeba7ac63cebfc5dcc669be38d825be587bd0",
|
|
60
|
-
"dist/pattern-guard.js": "
|
|
61
|
+
"dist/pattern-guard.js": "cebd2af729d7999fffea489bb9bf9d5af945bd08b32b77f0463fb89af86fb167",
|
|
61
62
|
"dist/plugins.js": "a61aa933cd9e1b41020b86fae78aa3a7f45f5313124aa11b50cb57898722385e",
|
|
62
63
|
"dist/policies/agents.js": "b07f162fa8bfadf8866c09f9499a84c01740834703085e9ccf5a8cd1e02f6113",
|
|
63
|
-
"dist/policies/cache.js": "
|
|
64
|
-
"dist/policies/compression.js": "
|
|
64
|
+
"dist/policies/cache.js": "a52da3590b60048e4f5888591d26b16155c5250cacc212a9a2329d0f2a2149b2",
|
|
65
|
+
"dist/policies/compression.js": "afd6ee2b9c8122878b9f0e56b3d09613b44297b2297f6b76225979cbd4148ca5",
|
|
65
66
|
"dist/policies/security.js": "56dae854eb612cb83f3f81b144dd54034d45fefe7801afbfa4129b1e1609f1c0",
|
|
66
|
-
"dist/policies/throttle.js": "
|
|
67
|
+
"dist/policies/throttle.js": "c3406b979d1144cfa96058b7874055de926bcea4fae240585b918092c987418a",
|
|
67
68
|
"dist/policies.js": "790694d06edb0a986a8a95e4eb6dcad0dc006cc53d84d4511b9e125a9b09a563",
|
|
68
|
-
"dist/policy.js": "
|
|
69
|
-
"dist/prerender.js": "
|
|
70
|
-
"dist/project-dependencies.js": "
|
|
69
|
+
"dist/policy.js": "2712abe24088ded09594dc8f048b47b94bd3dd85cc986c3a7a5b0c3ce7178796",
|
|
70
|
+
"dist/prerender.js": "363a369409323866d22aa3997ba57a27bae5b617d775fc3c74ba8944f02d4aa5",
|
|
71
|
+
"dist/project-dependencies.js": "d773224590221e9088444254d8e4e2aad63d968f39facac248f5084f29f92a03",
|
|
71
72
|
"dist/project-tests.js": "63562978411ee94a69dcf45d4d47e84fba009d8654ac421c2a02a418cd80b4db",
|
|
72
73
|
"dist/provider-verification.js": "ffcf9f05e8cb5f71ea46a97e279e8a613fdfdf9435ab02bd57af11e2680a9107",
|
|
73
|
-
"dist/proxy.js": "
|
|
74
|
-
"dist/readiness.js": "
|
|
74
|
+
"dist/proxy.js": "b48f24fcee5fd425ae96b6617882be3861cb310988ac456df0f0fa7e53134ac9",
|
|
75
|
+
"dist/readiness.js": "862c6d5caf6a1e00217425348801616c8355ada7d3fa0e5f0caab8899346e672",
|
|
75
76
|
"dist/recipes.js": "7af62ea9f612c82ea21e97e9d14451f05e0b509d6e420fb99fec96b22e3533f1",
|
|
76
|
-
"dist/review.js": "
|
|
77
|
-
"dist/route-diff.js": "
|
|
78
|
-
"dist/router.js": "
|
|
79
|
-
"dist/runtime.js": "
|
|
77
|
+
"dist/review.js": "102da9cea5a0edbd2ff2c8c26f5c25a9252832197c9fe19c54b754011a87d537",
|
|
78
|
+
"dist/route-diff.js": "f6e5b8965ededdcc76df431648751787af0b108141590744f248a69886c5f040",
|
|
79
|
+
"dist/router.js": "e8ffb65f6dc594439f032186b096788f5450ed5a2653f0a74eafbfc2505141e8",
|
|
80
|
+
"dist/runtime.js": "aa05e127b28e4f94b6802b01a2f74362d5a97b98cb9ed8b49dcfc0040159b812",
|
|
80
81
|
"dist/sandbox.js": "c88c5aa5dd95b4f55f1ba62da7969ad66dbd97c30f72e5b5f2817a2098ac1c65",
|
|
81
|
-
"dist/scaffold.js": "
|
|
82
|
-
"dist/schema-query.js": "
|
|
83
|
-
"dist/server.js": "
|
|
84
|
-
"dist/signals.js": "
|
|
85
|
-
"dist/site.js": "
|
|
82
|
+
"dist/scaffold.js": "378f0d21351c0e4c69c6bb31bd8b55735fa01d056f4a9b150462fea74f5e8867",
|
|
83
|
+
"dist/schema-query.js": "becded534b3a85a60f5b2ee819252a973bc8ff3890bdfece0428877453fbcb12",
|
|
84
|
+
"dist/server.js": "b3b66948fc8cd6be791529994fc765d77a20990f181bf19517d51e03726cab59",
|
|
85
|
+
"dist/signals.js": "81476f857b053696cddc5ed0d3f219ae48ba9523681bf13bc93830d03896d6eb",
|
|
86
|
+
"dist/site.js": "0b8d5e25bb0e2357e4f8b6995f45f7898087c7f37cdc5302e4c83ec5a4caa43d",
|
|
86
87
|
"dist/tooling.js": "9fa72ac5fdcdb56c9e17ee5d8efae83e100d3ad862f90e855dd5766424830b57",
|
|
87
|
-
"dist/trusted-functions.js": "
|
|
88
|
-
"dist/types.js": "
|
|
88
|
+
"dist/trusted-functions.js": "0f5f6038c8ae96ccca3a4ec6da17910c8872dc6e9a2da8753e1b6e2a1fcef0a9",
|
|
89
|
+
"dist/types.js": "a378e6bb6ffbcbe6d703a36949f7bf6c00973ade4808575828be4f90841e1120",
|
|
89
90
|
"dist/typescript-authoring.js": "df3d9c82e6b545cae5caae04c443ed4d2feae96def5e5cde250c0a90d83ae98c",
|
|
90
|
-
"dist/vercel.js": "
|
|
91
|
-
"dist/verify-deployment.js": "
|
|
91
|
+
"dist/vercel.js": "fa4034aa1582f41c8b9d380ad4e068dded6adb002155b5079e2c858b0e34f90f",
|
|
92
|
+
"dist/verify-deployment.js": "85b4318efaf65608d193010c8904bc337f472bd5eac97ff3a7d52bbf017f81cd",
|
|
92
93
|
"dist/scripts/operational-drills.js": "26f487454f7602b26d17c28eccd78aa59954cd7975791ac140092c614b36bc19"
|
|
93
94
|
}
|
|
94
95
|
}
|
package/dist/agent-context.js
CHANGED
|
@@ -7,6 +7,15 @@ import {listExamples} from './examples.js';
|
|
|
7
7
|
* Fixed, package-owned agent material. This is intentionally a manifest rather
|
|
8
8
|
* than an arbitrary file reader: MCP clients cannot use it to enumerate or
|
|
9
9
|
* exfiltrate a local project.
|
|
10
|
+
*
|
|
11
|
+
* Every export here is public API, published as `@jimhoyd/urlcode/agent-context`
|
|
12
|
+
* (see docs/TOOLING.md and docs/TYPESCRIPT.md) so a host building its own MCP
|
|
13
|
+
* server or agent-tooling surface can reuse the same deterministic docs
|
|
14
|
+
* search, YAML validation and error-remediation guidance this package's own
|
|
15
|
+
* `serveMcp` (mcp.ts) uses, rather than re-implementing it or reaching into
|
|
16
|
+
* `dist/` directly. Signatures take only plain strings and return plain data;
|
|
17
|
+
* keep them that way so the subpath stays stable independent of internal
|
|
18
|
+
* types like `validateDocument`'s return shape.
|
|
10
19
|
*/
|
|
11
20
|
const packageRoot=fileURLToPath(new URL('../',import.meta.url));
|
|
12
21
|
const docs=[
|
package/dist/agents-guide.js
CHANGED
|
@@ -34,6 +34,9 @@ export function renderAgentsGuide({ routes } ) {
|
|
|
34
34
|
const handlers = handlerNames.filter(name => native.has(name));
|
|
35
35
|
const policies = Object.keys(registry).filter(name => native.has(`policies.${name}` ));
|
|
36
36
|
const site = Object.entries(generatedPaths).map(([key, path]) => `\`${key}\` (${path})`);
|
|
37
|
+
const auditGuidance = routes === 0
|
|
38
|
+
? 'With no active routes, this initial audit intentionally exits nonzero with `no-active-routes`. Add the first route and its fixture, then make the audit pass; remove `allow-empty-project: true` from the generated GitHub workflow at that point.'
|
|
39
|
+
: 'Run all three after every change.';
|
|
37
40
|
return `# Working on this project
|
|
38
41
|
|
|
39
42
|
This project uses URLCode: URL behavior is declared in \`urlcode.yaml\`, and the
|
|
@@ -58,7 +61,7 @@ static serving and authentication. Read this file before changing anything.
|
|
|
58
61
|
|
|
59
62
|
When present, \`${mcpConfigFile}\` registers the read-only \`urlcode mcp\` server; prefer its
|
|
60
63
|
tools (also \`get_manifest\`) to reading documents. Inspect \`get_extensions\` before
|
|
61
|
-
replacing extension behavior. \`--allow-authoring\` is an operator opt-in; never add it. For a committed artifact lock, use \`get_extension_artifacts\`/\`get_extension_artifact\`; they expose verified inert data and never activate an extension.
|
|
64
|
+
replacing extension behavior. \`--allow-authoring\` is an operator opt-in; never add it. For a committed artifact lock, use \`get_extension_artifacts\`/\`get_extension_artifact\`; they expose verified inert data and never activate an extension. [URLCode AI](https://urlcode.ai/) is a separate optional hosted service for shared skills and LLM tooling; its remote MCP never replaces this local project server, and its credential belongs only in a client secret facility, never project files. Its machine-readable entry point is \`https://urlcode.ai/llms.txt\`.
|
|
62
65
|
|
|
63
66
|
## What the runtime provides (this version)
|
|
64
67
|
|
|
@@ -95,7 +98,7 @@ urlcode test
|
|
|
95
98
|
urlcode audit --expect-routes ${routes}
|
|
96
99
|
\`\`\`
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
${auditGuidance} \`N\` counts declared routes plus one route for each active \`site.*\` convention; an audit mismatch reports the declared/generated split. Update it deliberately and add \`tests/requests.json\` fixtures for every new route (positive/negative, every active method, HEAD). No global install: use \`node /path/to/urlcode/packages/core/src/cli.ts\`.
|
|
99
102
|
|
|
100
103
|
## Feedback
|
|
101
104
|
|
package/dist/assets.js
CHANGED
|
@@ -9,8 +9,8 @@ import { assert, HttpError } from './errors.js';
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
/** The header surface assetResponse reads for conditional and range requests. */
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
|
|
14
14
|
|
|
15
15
|
// Asset bytes are immutable between successful reloads. No request opens a file.
|
|
16
16
|
const denied = /^(?:node_modules|urlcode\.ya?ml|package(?:-lock)?\.json|.*\.(?:pem|key|p12|pfx|env))$/i;
|
package/dist/authoring.js
CHANGED
|
@@ -10,17 +10,14 @@ import { prepareFunctionSnapshot, requestedPermissions } from './policy.js';
|
|
|
10
10
|
import { assert } from './errors.js';
|
|
11
11
|
import { renderPackageManifest } from './project-dependencies.js';
|
|
12
12
|
|
|
13
|
-
import { redirectStarter } from './context.js';
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
21
|
|
|
25
22
|
// Agents install the runtime before they can read its docs, so `init .` has to work after `npm init` and `npm install`.
|
|
26
23
|
// A directory is accepted in place only when it holds nothing but what npm and git create; anything else is user work
|
|
@@ -41,18 +38,7 @@ async function inspectExisting(target )
|
|
|
41
38
|
}
|
|
42
39
|
return { entries: new Set(names), packageJson, pinned };
|
|
43
40
|
}
|
|
44
|
-
|
|
45
|
-
export function mergePackageJson(text , scripts , dependency , version ) {
|
|
46
|
-
const manifest = JSON.parse(text) ;
|
|
47
|
-
for (const [name, command] of Object.entries(scripts)) {
|
|
48
|
-
const current = manifest.scripts?.[name];
|
|
49
|
-
assert(current === undefined || current === command, `package.json already defines scripts.${name}; remove it or set it to: ${command}`);
|
|
50
|
-
manifest.scripts = { ...manifest.scripts, [name]: command };
|
|
51
|
-
}
|
|
52
|
-
if (manifest.dependencies?.[dependency] === undefined && manifest.devDependencies?.[dependency] === undefined) manifest.dependencies = { ...manifest.dependencies, [dependency]: version };
|
|
53
|
-
return JSON.stringify(manifest, null, 2) + '\n';
|
|
54
|
-
}
|
|
55
|
-
export async function initProject(destination , { manifest, template = 'default' } = {}) {
|
|
41
|
+
export async function initProject(destination , { manifest } = {}) {
|
|
56
42
|
const target = resolve(destination);
|
|
57
43
|
await mkdir(dirname(target), { recursive: true });
|
|
58
44
|
const existing = await inspectExisting(target);
|
|
@@ -60,23 +46,11 @@ export async function initProject(destination , { manifest, template = 'd
|
|
|
60
46
|
// A new directory is reserved exclusively before copying; an existing one is only ever added to.
|
|
61
47
|
if (!existing) await mkdir(target);
|
|
62
48
|
try {
|
|
63
|
-
|
|
64
|
-
const source = fileURLToPath(new URL(`../starters/${template === 'page' ? 'page' : 'default'}/`, import.meta.url));
|
|
49
|
+
const source = fileURLToPath(new URL('../starters/default/', import.meta.url));
|
|
65
50
|
for (const file of await readdir(source)) {
|
|
66
51
|
if (file === '.gitignore' || file === 'AGENTS.md' || file === mcpConfigFile) continue;
|
|
67
52
|
await cp(join(source,file), join(target,file === 'gitignore.template' ? '.gitignore' : file), { recursive: true, force: false, errorOnExist: true });
|
|
68
53
|
}
|
|
69
|
-
if (template === 'page') {
|
|
70
|
-
const routes = Object.keys((await loadDocument(target)).routes).length;
|
|
71
|
-
// The page starter is the smallest project, but an agent opened in it still needs the same first-step guidance and MCP registration.
|
|
72
|
-
await writeExclusive(join(target, 'AGENTS.md'), renderAgentsGuide({ routes }));
|
|
73
|
-
await writeExclusive(join(target, mcpConfigFile), renderMcpConfig('.', { local: manifest !== undefined || existing?.pinned === true }));
|
|
74
|
-
if (manifest) {
|
|
75
|
-
const pkg = await open(join(target,'package.json'), 'wx', 0o644);
|
|
76
|
-
try { await pkg.writeFile(renderPackageManifest(target, manifest)); } finally { await pkg.close(); }
|
|
77
|
-
}
|
|
78
|
-
return target;
|
|
79
|
-
}
|
|
80
54
|
// AGENTS.md is generated from the installed runtime's capability catalog so
|
|
81
55
|
// it names only what this version implements; the starter carries a
|
|
82
56
|
// committed copy for clones, kept identical by test.
|
|
@@ -102,35 +76,6 @@ export async function initProject(destination , { manifest, template = 'd
|
|
|
102
76
|
}
|
|
103
77
|
return target;
|
|
104
78
|
}
|
|
105
|
-
const redirectFixtures = [
|
|
106
|
-
{ path: '/old', status: 301, expectHeaders: { location: 'https://example.com/new' } },
|
|
107
|
-
{ path: '/users/42', status: 308, expectHeaders: { location: 'https://example.com/profiles/42' } },
|
|
108
|
-
{ path: '/people/7', status: 302, expectHeaders: { location: '/profiles/7' } },
|
|
109
|
-
{ path: '/legacy/a/b/c/d/e/f/g/h/i', status: 302, expectHeaders: { location: 'https://example.com/modern/a/b/c/d/e/f/g/h/i' } },
|
|
110
|
-
{ path: '/search?q=tea', status: 302, expectHeaders: { location: 'https://example.com/find?q=tea' } },
|
|
111
|
-
{ path: '/missing', status: 404 },
|
|
112
|
-
];
|
|
113
|
-
/** The redirect starter is the `--task redirects` starter, so init and `urlcode context` cannot disagree. */
|
|
114
|
-
async function writeRedirectsStarter(target , existing ) {
|
|
115
|
-
const starter = redirectStarter();
|
|
116
|
-
const version = (JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')) ).version;
|
|
117
|
-
const files = {
|
|
118
|
-
[starter.file]: starter.yaml,
|
|
119
|
-
...starter.companions,
|
|
120
|
-
'tests/requests.json': JSON.stringify(redirectFixtures, null, 2) + '\n',
|
|
121
|
-
};
|
|
122
|
-
await mkdir(join(target, 'tests'));
|
|
123
|
-
for (const [name, body] of Object.entries(files)) await writeExclusive(join(target, name), body);
|
|
124
|
-
if (existing?.packageJson !== undefined) await writeFile(join(target, 'package.json'), mergePackageJson(existing.packageJson, starter.packageScripts, '@jimhoyd/urlcode', version));
|
|
125
|
-
else await writeExclusive(join(target, 'package.json'), JSON.stringify({ name: 'redirects', version: '1.0.0', private: true, scripts: starter.packageScripts, dependencies: { '@jimhoyd/urlcode': version } }, null, 2) + '\n');
|
|
126
|
-
const routes = Object.keys((await loadDocument(target)).routes).length;
|
|
127
|
-
await writeExclusive(join(target, 'AGENTS.md'), renderAgentsGuide({ routes }));
|
|
128
|
-
await writeExclusive(join(target, mcpConfigFile), renderMcpConfig('.', { local: true }));
|
|
129
|
-
}
|
|
130
|
-
async function writeExclusive(file , body ) {
|
|
131
|
-
const handle = await open(file, 'wx', 0o644);
|
|
132
|
-
try { await handle.writeFile(body); } finally { await handle.close(); }
|
|
133
|
-
}
|
|
134
79
|
export async function addRedirect(project , destination , alias ) {
|
|
135
80
|
const loaded = await loadDocument(project);
|
|
136
81
|
const slug = alias || randomBytes(6).toString('base64url');
|
package/dist/aws.js
CHANGED
|
@@ -6,6 +6,7 @@ import { activateNativeOnly, lazyRuntime, resolveOrigin } from './adapters.js';
|
|
|
6
6
|
import { prepareResponse, errorResponse } from './http-response.js';
|
|
7
7
|
|
|
8
8
|
import { assert, ConfigError, HttpError } from './errors.js';
|
|
9
|
+
import { isRecord } from './object-guards.js';
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
/** A Lambda payload format 2.0 event, as far as this adapter reads it. */
|
|
@@ -18,7 +19,20 @@ import { assert, ConfigError, HttpError } from './errors.js';
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
const platformOrigins = ['URLCODE_PUBLIC_HOST'];
|
|
21
|
-
|
|
22
|
+
// Payload format 2.0 joins every repeated header with a comma before this
|
|
23
|
+
// adapter ever sees it (there is no `multiValueHeaders` on this format), so a
|
|
24
|
+
// client that sent one occurrence with a comma in its value is
|
|
25
|
+
// indistinguishable, at this layer, from two occurrences API Gateway joined.
|
|
26
|
+
// Splitting unconditionally corrupts the former and inflates its count. Only
|
|
27
|
+
// the headers RFC 7230/9110 define as a comma-separated list are safe to
|
|
28
|
+
// split; every other header (including any project-declared one) is kept as
|
|
29
|
+
// the single value the platform handed over, whatever characters it holds.
|
|
30
|
+
const listValuedHeaders = new Set([
|
|
31
|
+
'accept','accept-charset','accept-encoding','accept-language','access-control-allow-headers','access-control-allow-methods',
|
|
32
|
+
'access-control-expose-headers','access-control-request-headers','allow','cache-control','connection','content-encoding',
|
|
33
|
+
'content-language','expect','forwarded','if-match','if-none-match','pragma','te','trailer','transfer-encoding','upgrade',
|
|
34
|
+
'vary','via','warning','www-authenticate','x-forwarded-for',
|
|
35
|
+
]);
|
|
22
36
|
|
|
23
37
|
// Payload format 2.0 only, as used by Lambda Function URLs and API Gateway
|
|
24
38
|
// HTTP APIs. Format 1.0 supplies the path and query already decoded, so the
|
|
@@ -44,9 +58,12 @@ function requestHeaders(event )
|
|
|
44
58
|
for (const [name,value] of Object.entries(event.headers || {})) {
|
|
45
59
|
if (value === undefined) continue;
|
|
46
60
|
const key = name.toLowerCase();
|
|
47
|
-
// API Gateway joins repeats with a comma; the
|
|
48
|
-
// sent more than one, which route
|
|
49
|
-
|
|
61
|
+
// API Gateway joins repeats of a *list-valued* header with a comma; the
|
|
62
|
+
// count then reflects that a client sent more than one, which route
|
|
63
|
+
// policy uses to reject ambiguous inputs. Any other header is scalar as
|
|
64
|
+
// far as this adapter is concerned: splitting it on comma would mangle a
|
|
65
|
+
// legitimate value and miscount a single occurrence as several.
|
|
66
|
+
const parts = listValuedHeaders.has(key) ? String(value).split(',') : [String(value)];
|
|
50
67
|
for (const part of parts) headers.append(key, part.trim());
|
|
51
68
|
counts[key] = parts.length;
|
|
52
69
|
}
|
package/dist/body-schema.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assert } from './errors.js';
|
|
2
2
|
import { assertSafePattern, maxPatternInputLength } from './pattern-guard.js';
|
|
3
|
+
import { isRecord, own } from './object-guards.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The JSON Schema subset a route may declare for `request.body.schema`.
|
|
@@ -18,8 +19,6 @@ export const uuidFormat = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a
|
|
|
18
19
|
const types = ['object', 'array', 'string', 'integer', 'number', 'boolean', 'null'];
|
|
19
20
|
const keywords = new Set(['type','properties','required','additionalProperties','items','enum','minLength','maxLength','pattern','format','minimum','maximum','minItems','maxItems']);
|
|
20
21
|
const limits = { depth: 6, nodes: 128, properties: 64, enums: 64, length: 8192, items: 10000 };
|
|
21
|
-
const isRecord = (value ) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
22
|
-
const own = (object , key ) => Object.hasOwn(object, key);
|
|
23
22
|
const patterns = new WeakMap ();
|
|
24
23
|
|
|
25
24
|
/** Rejects, at load time, any schema outside the supported subset or its limits. */
|
|
@@ -75,7 +74,7 @@ const describe = (value ) => value === null ? 'null' : Array.isA
|
|
|
75
74
|
* is the schema keyword that failed, and `expected` is the schema's own
|
|
76
75
|
* constraint. Nothing the client sent is ever placed in an issue.
|
|
77
76
|
*/
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
const escapePointer = (name ) => name.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
80
79
|
/** Structured failures for `value`; `checkBodySchema` renders the same list as text. */
|
|
81
80
|
export function bodySchemaIssues(schema , value , path = '', issues = [], max = 8) {
|
package/dist/capability-query.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {readdirSync,readFileSync,statSync} from 'node:fs';
|
|
2
2
|
import {fileURLToPath} from 'node:url';
|
|
3
|
-
import {parse} from 'yaml';
|
|
4
3
|
import {capabilityDetails,capabilityNames,capabilityTargets,formatCapabilities,getCapabilities,routeCapabilities} from './capabilities.js';
|
|
5
4
|
|
|
6
5
|
import {ConfigError} from './errors.js';
|
|
6
|
+
import {parseYaml} from './config.js';
|
|
7
7
|
import {getSchemaFragment} from './schema-query.js';
|
|
8
8
|
|
|
9
|
+
import {isRecord as object} from './object-guards.js';
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
@@ -18,7 +19,6 @@ import {getSchemaFragment} from './schema-query.js';
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
const root=(...parts )=>fileURLToPath(new URL('../'+parts.join('/'),import.meta.url));
|
|
21
|
-
const object=(value ) =>value!==null&&typeof value==='object'&&!Array.isArray(value);
|
|
22
22
|
function yamlFiles(directory ) {
|
|
23
23
|
const out =[];
|
|
24
24
|
for(const entry of readdirSync(directory,{withFileTypes:true}).sort((a,b)=>a.name.localeCompare(b.name))) {
|
|
@@ -32,7 +32,7 @@ function yamlFiles(directory ) {
|
|
|
32
32
|
function usage(base ,files ,name ) {
|
|
33
33
|
const result =[];
|
|
34
34
|
for(const file of files) {
|
|
35
|
-
let document ;try{document=
|
|
35
|
+
let document ;try{document=parseYaml(readFileSync(file,'utf8'));}catch{continue;}
|
|
36
36
|
if(!object(document))continue;
|
|
37
37
|
const routes =[];
|
|
38
38
|
if(name==='extension'&&object(document.extensions)&&Object.keys(document.extensions).length)routes.push('(project)');
|
package/dist/catalog.js
CHANGED
|
@@ -23,7 +23,7 @@ import {assert} from './errors.js';
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
/** The fields the capability preflight determines; `npm run check` refuses hand-written values that differ. */
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
const schemaFile=fileURLToPath(new URL('../schemas/recipe.schema.json',import.meta.url));
|