@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/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: string;
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)
@@ -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.0
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 **405** `link_create_not_supported`. Only admins with `*`
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` (405): Attempted mint under a GET link
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` | 405 | Attempted mint under a GET link | Admin mints via `POST /mcp/api/v1/links` only | GET |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@com55/node-red-ai-access",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Node-RED plugin that gives AI agents temporary, owner-approved access via REST and MCP",
5
5
  "main": "dist/plugin.cjs",
6
6
  "types": "dist/plugin.d.cts",