@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/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;
@@ -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.8
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. Late settlement no longer updates this proposal; approval always re-reads live flows.
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.8",
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",