@com55/node-red-ai-access 0.1.0 → 0.1.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.
- package/CHANGELOG.md +69 -0
- package/README.md +64 -0
- package/ai-access.html +1 -1
- package/dist/plugin.cjs +94 -78
- package/dist/plugin.d.cts +15 -1
- package/docs/README.md +2 -0
- package/docs/api/openapi.yaml +16 -6
- package/docs/errors.md +1 -1
- package/docs/releasing.md +82 -0
- package/package.json +1 -1
package/dist/plugin.d.cts
CHANGED
|
@@ -470,6 +470,18 @@ interface AiAccessSettings {
|
|
|
470
470
|
* Max requests per access-link token per window (default: 300).
|
|
471
471
|
*/
|
|
472
472
|
rateLimitMaxPerToken?: number;
|
|
473
|
+
/**
|
|
474
|
+
* Explicit public base URL (e.g. `https://nodered.example.com`) used for
|
|
475
|
+
* absolute URLs (access-link `url`, proposal `reviewUrl`, `accessLinksUrl`).
|
|
476
|
+
* Overrides `Host` / `X-Forwarded-*`. settings.js only.
|
|
477
|
+
*/
|
|
478
|
+
publicBaseUrl?: string;
|
|
479
|
+
/**
|
|
480
|
+
* Browser origins allowed to call the AI-facing endpoints (`/mcp/a`,
|
|
481
|
+
* `/mcp/api`, `/mcp/rpc`) cross-origin, e.g. `['https://app.example.com']`.
|
|
482
|
+
* Default: none (no CORS headers). settings.js only.
|
|
483
|
+
*/
|
|
484
|
+
corsAllowedOrigins?: string[];
|
|
473
485
|
}
|
|
474
486
|
type AiAccessPermission = 'read' | '*';
|
|
475
487
|
interface AiAccessCapabilities {
|
|
@@ -488,6 +500,8 @@ interface AiAccessStatusCallerBaseUrls {
|
|
|
488
500
|
rpc: string;
|
|
489
501
|
/** OpenAPI YAML URL. */
|
|
490
502
|
openapi: string;
|
|
503
|
+
/** OpenAPI JSON URL (same spec as `openapi`). */
|
|
504
|
+
openapiJson: string;
|
|
491
505
|
/** Unauthenticated JSON discovery index. */
|
|
492
506
|
discovery: string;
|
|
493
507
|
}
|
|
@@ -530,7 +544,7 @@ interface AiAccessStatus {
|
|
|
530
544
|
*/
|
|
531
545
|
permission: AiAccessPermission | null;
|
|
532
546
|
capabilities: AiAccessCapabilities;
|
|
533
|
-
storageDir
|
|
547
|
+
storageDir?: string;
|
|
534
548
|
/** Effective default access-link TTL (seconds). */
|
|
535
549
|
defaultLinkTtlSeconds: number;
|
|
536
550
|
/** Effective max concurrent active access links. */
|
package/docs/README.md
CHANGED
|
@@ -18,6 +18,8 @@ bodies. Use a **GET link** only as a fallback for headerless GET-only clients.
|
|
|
18
18
|
- [MCP tools reference](./mcp-tools.md) — generated from live `tools/list`
|
|
19
19
|
schemas
|
|
20
20
|
- [Error codes](./errors.md) — code, HTTP status, meaning, hint, channels
|
|
21
|
+
- [Releasing](./releasing.md) — version bump, CHANGELOG, tag, npm trusted
|
|
22
|
+
publishing
|
|
21
23
|
- [OpenAPI 3.1](./api/openapi.yaml) — also served at
|
|
22
24
|
`GET /mcp/api/v1/openapi.yaml` (JSON: `GET /mcp/api/v1/openapi.json`)
|
|
23
25
|
- Discovery guide — `GET /mcp/api/v1` (unauthenticated JSON index)
|
package/docs/api/openapi.yaml
CHANGED
|
@@ -2,7 +2,7 @@ openapi: 3.1.0
|
|
|
2
2
|
|
|
3
3
|
info:
|
|
4
4
|
title: Node-RED AI Access Plugin API
|
|
5
|
-
version: 0.1.
|
|
5
|
+
version: 0.1.1
|
|
6
6
|
summary: Temporary, owner-approved Node-RED access for AI clients
|
|
7
7
|
description: |
|
|
8
8
|
REST surface exposed by the `@com55/node-red-ai-access` Node-RED plugin
|
|
@@ -30,10 +30,16 @@ info:
|
|
|
30
30
|
|
|
31
31
|
**GET `/mcp/a/<token>/…` never mints tokens.** There is no link-create
|
|
32
32
|
operation under the get-link surface (no `POST …/links`). Attempted mint
|
|
33
|
-
paths return **
|
|
33
|
+
paths return **403** `link_create_not_supported`. Only admins with `*`
|
|
34
34
|
may create tokens on `POST /mcp/api/v1/links`.
|
|
35
35
|
|
|
36
|
-
1. `GET {url}` — markdown docs (workflow, exact paths, errors, limits)
|
|
36
|
+
1. `GET {url}` — markdown docs (workflow, exact paths, errors, limits),
|
|
37
|
+
served by default as `text/html; charset=utf-8` (the same text escaped in
|
|
38
|
+
a `<pre>`), because some AI web fetchers only read HTML. Every response
|
|
39
|
+
under `/mcp/a/<token>` follows the same rule: `Accept: text/markdown`
|
|
40
|
+
or `application/json`, or `?format=md` / `?format=json`, return the
|
|
41
|
+
raw representation; `Accept: text/plain` returns the raw text as
|
|
42
|
+
`text/plain` (`Vary: Accept`).
|
|
37
43
|
2. `GET {url}/status`, `/flows`, …
|
|
38
44
|
3. Layered read (prefer before loading whole tabs):
|
|
39
45
|
`GET {url}/flows/{id}?summary=1` → `GET {url}/search?q=&flow=` →
|
|
@@ -1426,7 +1432,7 @@ components:
|
|
|
1426
1432
|
- `invalid_ttl` (400): `ttlSeconds` is zero, negative, not a number, or over the cap for the kind
|
|
1427
1433
|
- `access_link_limit` (409): Too many active links
|
|
1428
1434
|
- `access_link_not_found` (404): Unknown link id on revoke
|
|
1429
|
-
- `link_create_not_supported` (
|
|
1435
|
+
- `link_create_not_supported` (403): Attempted mint under a GET link
|
|
1430
1436
|
- `rate_limited` (429): Per-IP or per-token limit
|
|
1431
1437
|
- `payload_too_large` (413): Body / proposal over ~1.5MB
|
|
1432
1438
|
- `invalid_json` (400): Malformed JSON body
|
|
@@ -1777,7 +1783,6 @@ components:
|
|
|
1777
1783
|
- allowWithoutAdminAuth
|
|
1778
1784
|
- permission
|
|
1779
1785
|
- capabilities
|
|
1780
|
-
- storageDir
|
|
1781
1786
|
- defaultLinkTtlSeconds
|
|
1782
1787
|
- maxActiveLinks
|
|
1783
1788
|
- defaultDeploymentType
|
|
@@ -1807,6 +1812,9 @@ components:
|
|
|
1807
1812
|
$ref: '#/components/schemas/Capabilities'
|
|
1808
1813
|
storageDir:
|
|
1809
1814
|
type: string
|
|
1815
|
+
description: |
|
|
1816
|
+
Server-side plugin storage directory. Admin sessions only; omitted
|
|
1817
|
+
for access-link (AI token) callers.
|
|
1810
1818
|
defaultLinkTtlSeconds:
|
|
1811
1819
|
type: integer
|
|
1812
1820
|
maxActiveLinks:
|
|
@@ -1859,7 +1867,7 @@ components:
|
|
|
1859
1867
|
proposals:create, proposals:read-own)
|
|
1860
1868
|
baseUrls:
|
|
1861
1869
|
type: object
|
|
1862
|
-
required: [api, rpc, openapi, discovery]
|
|
1870
|
+
required: [api, rpc, openapi, openapiJson, discovery]
|
|
1863
1871
|
properties:
|
|
1864
1872
|
api:
|
|
1865
1873
|
type: string
|
|
@@ -1867,6 +1875,8 @@ components:
|
|
|
1867
1875
|
type: string
|
|
1868
1876
|
openapi:
|
|
1869
1877
|
type: string
|
|
1878
|
+
openapiJson:
|
|
1879
|
+
type: string
|
|
1870
1880
|
discovery:
|
|
1871
1881
|
type: string
|
|
1872
1882
|
|
package/docs/errors.md
CHANGED
|
@@ -25,7 +25,7 @@ GET-link `401` responses include a `WWW-Authenticate: Bearer …` header.
|
|
|
25
25
|
| `invalid_ttl` | 400 | `ttlSeconds` is zero, negative, not a number, or over the cap for the kind | ttlSeconds must be a positive number of seconds within the cap for the token kind: get_link ≤ 86400 (24h); rest and mcp ≤ 2592000 (30 days). | admin |
|
|
26
26
|
| `access_link_limit` | 409 | Too many active links | Revoke an existing link first | admin |
|
|
27
27
|
| `access_link_not_found` | 404 | Unknown link id on revoke | List links and use an existing id | admin |
|
|
28
|
-
| `link_create_not_supported` |
|
|
28
|
+
| `link_create_not_supported` | 403 | Attempted mint under a GET link | Admin mints via `POST /mcp/api/v1/links` only | GET |
|
|
29
29
|
| `rate_limited` | 429 | Per-IP or per-token limit | Wait `retryAfter` / `Retry-After` | GET, REST, MCP |
|
|
30
30
|
| `payload_too_large` | 413 | Body / proposal over ~1.5MB | Shrink content | GET, REST, MCP |
|
|
31
31
|
| `invalid_json` | 400 | Malformed JSON body | Fix Content-Type / body | REST, MCP |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
Releases are published by the `Release` workflow
|
|
4
|
+
(`.github/workflows/release.yml`). Pushing a `v*` tag runs quality checks, the
|
|
5
|
+
production build and tests. It then publishes the package to npm and creates or
|
|
6
|
+
updates the GitHub release for that tag, with the CHANGELOG section as notes and
|
|
7
|
+
the `npm pack` tarball attached.
|
|
8
|
+
|
|
9
|
+
## Cut a release
|
|
10
|
+
|
|
11
|
+
1. Bump the version (no tag yet):
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm version 0.1.1 --no-git-tag-version
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
2. In `CHANGELOG.md`, rename `## [Unreleased]` to `## [0.1.1] - YYYY-MM-DD` (or
|
|
18
|
+
add that section) and summarise the changes. The workflow uses this section
|
|
19
|
+
as the release notes and fails if it is missing.
|
|
20
|
+
3. Commit, open a PR, and merge it to `main` once CI passes.
|
|
21
|
+
4. Tag the merge commit and push the tag:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
git checkout main && git pull
|
|
25
|
+
git tag -a v0.1.1 -m "v0.1.1"
|
|
26
|
+
git push origin v0.1.1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The workflow fails early if the tag does not equal `v` + the `package.json`
|
|
30
|
+
version. If that version is already on npm, the publish step is skipped and only
|
|
31
|
+
the GitHub release is updated. Re-running the workflow is safe.
|
|
32
|
+
|
|
33
|
+
### Re-run for an existing tag
|
|
34
|
+
|
|
35
|
+
Use **Actions → Release → Run workflow** and enter the tag (for example
|
|
36
|
+
`v0.1.0`). The workflow checks out that tag and runs the same steps. Use this to
|
|
37
|
+
publish a version that was tagged before this workflow existed.
|
|
38
|
+
|
|
39
|
+
## npm authentication
|
|
40
|
+
|
|
41
|
+
The publish step supports two modes:
|
|
42
|
+
|
|
43
|
+
- **Trusted publishing (OIDC, preferred).** No secret is needed. The job has
|
|
44
|
+
`permissions: id-token: write` and uses Node 24 with the latest npm (trusted
|
|
45
|
+
publishing needs npm >= 11.5.1 and Node >= 22.14.0). Provenance is generated
|
|
46
|
+
automatically for a public package published from a public repository;
|
|
47
|
+
`--provenance` is also passed.
|
|
48
|
+
- **Token fallback.** If the repository secret `NPM_TOKEN` is set, it is used as
|
|
49
|
+
`NODE_AUTH_TOKEN` instead. Use this for the first publish, because a trusted
|
|
50
|
+
publisher can only be configured on a package that already exists on npm.
|
|
51
|
+
|
|
52
|
+
### First publish
|
|
53
|
+
|
|
54
|
+
1. On npmjs.com, create a granular access token with read and write access to
|
|
55
|
+
publish packages for the `@com55` scope. It needs "bypass 2FA" if your
|
|
56
|
+
account requires 2FA for writes, and a short expiry.
|
|
57
|
+
2. Add it to the GitHub repository as the Actions secret `NPM_TOKEN` (**Settings
|
|
58
|
+
→ Secrets and variables → Actions**).
|
|
59
|
+
3. Push the tag, or run the workflow manually with the existing tag.
|
|
60
|
+
|
|
61
|
+
### Switch to trusted publishing
|
|
62
|
+
|
|
63
|
+
After the package exists on npm:
|
|
64
|
+
|
|
65
|
+
1. Open npmjs.com → the package → **Settings → Trusted publishing**, and choose
|
|
66
|
+
**GitHub Actions**.
|
|
67
|
+
2. Enter:
|
|
68
|
+
- Organization or user: `com55`
|
|
69
|
+
- Repository: `node-red-ai-access`
|
|
70
|
+
- Workflow filename: `release.yml` (the filename only, with the extension)
|
|
71
|
+
- Environment: leave empty
|
|
72
|
+
- Allowed actions: enable direct `npm publish`. The workflow runs
|
|
73
|
+
`npm publish`, not `npm stage publish`.
|
|
74
|
+
3. Complete a publish through the workflow within 2 days, or the new
|
|
75
|
+
configuration expires and has to be recreated.
|
|
76
|
+
4. Delete the `NPM_TOKEN` secret and revoke the token on npmjs.com.
|
|
77
|
+
5. Optional: under the package's **Settings → Publishing access**, choose
|
|
78
|
+
"Require two-factor authentication and disallow tokens". Trusted publishing
|
|
79
|
+
keeps working.
|
|
80
|
+
|
|
81
|
+
`repository.url` in `package.json` must match this GitHub repository exactly, or
|
|
82
|
+
OIDC publishing is rejected.
|
package/package.json
CHANGED