@com55/node-red-ai-access 0.2.0-beta.8 → 0.2.0-beta.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/CHANGELOG.md +22 -0
- package/README.md +22 -16
- package/ai-access.html +1 -1
- package/dist/plugin.cjs +313 -215
- package/dist/plugin.d.cts +13 -0
- package/docs/api/openapi.yaml +73 -2
- package/docs/errors.md +1 -0
- package/package.json +2 -1
package/dist/plugin.d.cts
CHANGED
|
@@ -300,11 +300,16 @@ interface Proposal {
|
|
|
300
300
|
nodeId: string;
|
|
301
301
|
property: string;
|
|
302
302
|
}[];
|
|
303
|
+
deploymentAlert?: string;
|
|
304
|
+
landedAfterWithdraw?: boolean;
|
|
305
|
+
rejectedWhileDeployUnknown?: boolean;
|
|
303
306
|
/** Persisted while a timed-out runtime deployment has an unknown outcome. */
|
|
304
307
|
deployPending?: {
|
|
305
308
|
mergedHash: string;
|
|
309
|
+
bootId?: string;
|
|
306
310
|
reason: string;
|
|
307
311
|
queueReleased?: boolean;
|
|
312
|
+
attemptId?: string;
|
|
308
313
|
};
|
|
309
314
|
/** Last auto-rebase result (pending / conflict proposals). */
|
|
310
315
|
rebase?: ProposalRebaseInfo;
|
|
@@ -366,6 +371,7 @@ declare class ProposalStore {
|
|
|
366
371
|
private toDiskRecord;
|
|
367
372
|
private writeAtomic;
|
|
368
373
|
create(input: CreateProposalInput): Proposal;
|
|
374
|
+
private currentProcessProposal;
|
|
369
375
|
get(id: string): Proposal;
|
|
370
376
|
list(filter?: {
|
|
371
377
|
linkId?: string;
|
|
@@ -379,6 +385,9 @@ declare class ProposalStore {
|
|
|
379
385
|
beginApprove(id: string): Proposal;
|
|
380
386
|
releaseLock(id: string): void;
|
|
381
387
|
recordDeployPending(id: string, pending: Proposal['deployPending']): Proposal;
|
|
388
|
+
flagRejectedWhileDeployUnknown(id: string): Proposal;
|
|
389
|
+
flagLandedAfterWithdraw(id: string): void;
|
|
390
|
+
flagDeployment(id: string, message: string): void;
|
|
382
391
|
markApproved(id: string, decidedBy: ProposalDecisionBy, resultRev: string): Proposal;
|
|
383
392
|
markRejected(id: string, decidedBy: ProposalDecisionBy | undefined, reason: string): Proposal;
|
|
384
393
|
markFailed(id: string, decidedBy: ProposalDecisionBy | undefined, reason: string): Proposal;
|
|
@@ -548,6 +557,7 @@ interface ProposalServiceOptions {
|
|
|
548
557
|
deployHardCapMs?: number;
|
|
549
558
|
}
|
|
550
559
|
interface ApproveOptions {
|
|
560
|
+
overrideDeployOutcomeUnknown?: boolean;
|
|
551
561
|
deploymentType?: DeploymentType;
|
|
552
562
|
/**
|
|
553
563
|
* `mergedHash` the reviewer last saw. Required when the rebase merged live
|
|
@@ -562,6 +572,9 @@ declare class ProposalService {
|
|
|
562
572
|
private readonly getDeploymentType;
|
|
563
573
|
private readonly serviceOptions;
|
|
564
574
|
constructor(proposals: ProposalStore, audit: AuditLog, adapter: FlowAdapter, getDeploymentType: () => DeploymentType, serviceOptions?: ProposalServiceOptions);
|
|
575
|
+
unknownDeployBlocks(): Proposal[];
|
|
576
|
+
confirmLiveChecked(id: string, actor: ProposalDecisionBy, expectedAttemptId: unknown): Proposal;
|
|
577
|
+
private guardUnknown;
|
|
565
578
|
approve(id: string, decidedBy: ProposalDecisionBy, options?: ApproveOptions): Promise<Proposal>;
|
|
566
579
|
private approveLocked;
|
|
567
580
|
private withDeployDeadline;
|
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.2.0-beta.
|
|
5
|
+
version: 0.2.0-beta.9
|
|
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
|
|
@@ -950,6 +950,21 @@ paths:
|
|
|
950
950
|
type: array
|
|
951
951
|
items:
|
|
952
952
|
$ref: '#/components/schemas/Proposal'
|
|
953
|
+
deployUnknownBlocks:
|
|
954
|
+
type: array
|
|
955
|
+
description: Admin-only active process blocks, independent of status filters and pagination. Each deployment submits a full flow snapshot, so these blocks apply to all approvals, including after proposal closure.
|
|
956
|
+
items:
|
|
957
|
+
type: object
|
|
958
|
+
required: [proposalId, flowIds]
|
|
959
|
+
properties:
|
|
960
|
+
proposalId:
|
|
961
|
+
type: string
|
|
962
|
+
attemptId:
|
|
963
|
+
type: string
|
|
964
|
+
flowIds:
|
|
965
|
+
type: array
|
|
966
|
+
items:
|
|
967
|
+
type: string
|
|
953
968
|
total:
|
|
954
969
|
type: integer
|
|
955
970
|
description: Count after filters, before limit/offset
|
|
@@ -1244,6 +1259,42 @@ paths:
|
|
|
1244
1259
|
'415':
|
|
1245
1260
|
$ref: '#/components/responses/UnsupportedMediaType'
|
|
1246
1261
|
|
|
1262
|
+
/proposals/{id}/confirm-live-checked:
|
|
1263
|
+
post:
|
|
1264
|
+
tags: [Proposals]
|
|
1265
|
+
summary: Confirm live flows checked and clear the unknown deployment block
|
|
1266
|
+
description: Requires full admin permission (*). Records the actor and attempt in proposal.live_checked audit. Requires a post-cap deployPending.queueReleased flag and its matching attemptId. Does not cancel a detached deploy; a later landing is still monitored on every changed tab.
|
|
1267
|
+
operationId: confirmProposalLiveChecked
|
|
1268
|
+
security:
|
|
1269
|
+
- AdminSession: []
|
|
1270
|
+
parameters:
|
|
1271
|
+
- $ref: '#/components/parameters/ProposalId'
|
|
1272
|
+
requestBody:
|
|
1273
|
+
required: true
|
|
1274
|
+
content:
|
|
1275
|
+
application/json:
|
|
1276
|
+
schema:
|
|
1277
|
+
type: object
|
|
1278
|
+
required: [attemptId]
|
|
1279
|
+
properties:
|
|
1280
|
+
attemptId:
|
|
1281
|
+
type: string
|
|
1282
|
+
responses:
|
|
1283
|
+
'200':
|
|
1284
|
+
description: Block cleared
|
|
1285
|
+
content:
|
|
1286
|
+
application/json:
|
|
1287
|
+
schema:
|
|
1288
|
+
$ref: '#/components/schemas/Proposal'
|
|
1289
|
+
'401':
|
|
1290
|
+
$ref: '#/components/responses/Unauthorized'
|
|
1291
|
+
'403':
|
|
1292
|
+
$ref: '#/components/responses/Forbidden'
|
|
1293
|
+
'409':
|
|
1294
|
+
description: deploy_outcome_unknown — no post-cap deployment or attemptId does not match
|
|
1295
|
+
'404':
|
|
1296
|
+
$ref: '#/components/responses/NotFound'
|
|
1297
|
+
|
|
1247
1298
|
/proposals/{id}/reject:
|
|
1248
1299
|
post:
|
|
1249
1300
|
tags: [Proposals]
|
|
@@ -1569,6 +1620,7 @@ components:
|
|
|
1569
1620
|
Machine-readable `code` on JSON error bodies. See docs/errors.md.
|
|
1570
1621
|
|
|
1571
1622
|
- `approve_queue_timeout` (504): Approval exceeded its queue-wait deadline (default 60 seconds); no deployment was started for this request
|
|
1623
|
+
- `deploy_outcome_unknown` (409): A past-cap deployment can still change live flows
|
|
1572
1624
|
- `deploy_timeout` (504): Deployment exceeded its deadline (default 60 seconds); approvals wait for settlement or the hard cap (default 5 minutes)
|
|
1573
1625
|
- `proposal_conflict` (409): Editor and proposal changes conflict (conflicts contains field names only)
|
|
1574
1626
|
- `rebase_ack_required` (409): The merged result needs review (mergedHash included)
|
|
@@ -1630,6 +1682,7 @@ components:
|
|
|
1630
1682
|
- `internal_error` (500): Unexpected server error
|
|
1631
1683
|
enum:
|
|
1632
1684
|
- approve_queue_timeout
|
|
1685
|
+
- deploy_outcome_unknown
|
|
1633
1686
|
- deploy_timeout
|
|
1634
1687
|
- proposal_conflict
|
|
1635
1688
|
- rebase_ack_required
|
|
@@ -2385,18 +2438,32 @@ components:
|
|
|
2385
2438
|
choice:
|
|
2386
2439
|
type: string
|
|
2387
2440
|
enum: [live, proposed]
|
|
2441
|
+
rejectedWhileDeployUnknown:
|
|
2442
|
+
type: boolean
|
|
2443
|
+
description: Rejected while a full-snapshot deploy could still land. Check live flows; late landing triggers an alert and audit entry.
|
|
2444
|
+
landedAfterWithdraw:
|
|
2445
|
+
type: boolean
|
|
2446
|
+
description: The withdrawn proposal’s outstanding deployment landed later; shown as a dashboard badge.
|
|
2447
|
+
deploymentAlert:
|
|
2448
|
+
type: string
|
|
2449
|
+
description: Warning that a late deployment may have overwritten an intervening decision.
|
|
2388
2450
|
deployPending:
|
|
2389
2451
|
type: object
|
|
2390
2452
|
description: Timed-out deployment has an unknown outcome; approvals wait until settlement or the hard cap. Check live flows before approving again.
|
|
2391
2453
|
required: [mergedHash, reason]
|
|
2392
2454
|
properties:
|
|
2455
|
+
attemptId:
|
|
2456
|
+
type: string
|
|
2457
|
+
bootId:
|
|
2458
|
+
type: string
|
|
2459
|
+
description: Process identity; flags from previous processes are ignored.
|
|
2393
2460
|
mergedHash:
|
|
2394
2461
|
type: string
|
|
2395
2462
|
reason:
|
|
2396
2463
|
type: string
|
|
2397
2464
|
queueReleased:
|
|
2398
2465
|
type: boolean
|
|
2399
|
-
description: True when the deploy hard cap released the queue.
|
|
2466
|
+
description: True when the deploy hard cap released the queue. All approvals are blocked until settlement, restart, or confirm-live-checked with a matching attemptId; closing the proposal does not clear the block; approval may proceed with an audited override. Rejection is allowed with rejectedWhileDeployUnknown warning. Late settlement updates the proposal or flags intervening decisions.
|
|
2400
2467
|
rebase:
|
|
2401
2468
|
$ref: '#/components/schemas/ProposalRebase'
|
|
2402
2469
|
id:
|
|
@@ -2674,6 +2741,10 @@ components:
|
|
|
2674
2741
|
ApproveProposalRequest:
|
|
2675
2742
|
type: object
|
|
2676
2743
|
properties:
|
|
2744
|
+
overrideDeployOutcomeUnknown:
|
|
2745
|
+
type: boolean
|
|
2746
|
+
default: false
|
|
2747
|
+
description: Explicitly allow approval while a past-cap deploy can still overwrite live flows.
|
|
2677
2748
|
mergedHash:
|
|
2678
2749
|
type: string
|
|
2679
2750
|
description: Hash of the reviewed merged result; required when editor changes are merged.
|
package/docs/errors.md
CHANGED
|
@@ -14,6 +14,7 @@ GET-link `401` responses include a `WWW-Authenticate: Bearer …` header.
|
|
|
14
14
|
| Code | HTTP | Meaning | Hint / next step | Channels |
|
|
15
15
|
| --- | --- | --- | --- | --- |
|
|
16
16
|
| `approve_queue_timeout` | 504 | Approval exceeded its queue-wait deadline (default 60 seconds); no deployment was started for this request | Check the live flow and retry approval | admin |
|
|
17
|
+
| `deploy_outcome_unknown` | 409 | A past-cap deployment can still change live flows | All approvals require settlement, confirm live checked with the matching attempt, restart, or an audited override; rejection is allowed with a warning | admin |
|
|
17
18
|
| `deploy_timeout` | 504 | Deployment exceeded its deadline (default 60 seconds); approvals wait for settlement or the hard cap (default 5 minutes) | Before the cap, late settlement updates the proposal; after the cap, deployPending.queueReleased is true and the outcome stays unknown. Check the live flow before approving again; approval always re-reads live | admin |
|
|
18
19
|
| `proposal_conflict` | 409 | Editor and proposal changes conflict (conflicts contains field names only) | Read the current flow and resolve the proposal before approval | GET, REST, MCP, admin |
|
|
19
20
|
| `rebase_ack_required` | 409 | The merged result needs review (mergedHash included) | Review the diff and approve with its mergedHash | admin |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@com55/node-red-ai-access",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.9",
|
|
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",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
26
|
"!dist/**/*.map",
|
|
27
|
+
"!dist/.production-build-hash",
|
|
27
28
|
"docs",
|
|
28
29
|
"ai-access.cjs",
|
|
29
30
|
"ai-access.html",
|