@anchrd/intel-contract 0.19.0 → 0.20.0

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/README.md CHANGED
@@ -95,10 +95,15 @@ edge and the tool ends up in the chain. The graph is then refused with
95
95
  `Node <id> is a link and must be attached to a step` — in `title`, per the first item above. A step
96
96
  may hold several links; one link belongs to exactly one step.
97
97
 
98
- ### A flow is not a node, and carries no grants of its own
98
+ ### A flow is not a node, and has its own grant calls
99
99
 
100
- `node_grant_create` addresses nodes. A flow has no grants; it inherits those of the folder it lives
101
- in. To change who reaches a flow, share its folder or move the flow.
100
+ `node_grant_create` addresses nodes; `flow_grant_create` addresses flows. A flow is reached by both:
101
+ the folder it is filed in passes its grants down, and a grant may sit on the flow itself. The two
102
+ add up — the flow grant never replaces what the folder passes down.
103
+
104
+ ⚠️ A grant on one flow reaches **that flow** and nothing else — not the folder, and not the flows it
105
+ calls. `ShareResult` says so: `unrunnable` names the sub-flows the new principal could not start,
106
+ by title where you may see them and by count where you may not.
102
107
 
103
108
  ### Import takes its idempotency key as a header
104
109
 
@@ -438,9 +438,9 @@ export const FlowPublishPreview = z.strictObject({
438
438
  calls: z.array(FlowPublishCall),
439
439
  tools: z.array(FlowPublishTool),
440
440
  });
441
- // A flow has no share schema of its own. A grant sits on the folder a flow is filed in and inherits
442
- // down from there (ADR-0004 §2); a narrower grant beside it would destroy the subtree guarantee
443
- // section 3 rests on, so per-flow grants were removed rather than deprecated.
441
+ // A flow's own sharing schemas live in `share.ts` beside the node's (#530): `ShareFlowInput`,
442
+ // `RevokeFlowGrantInput`, `ListFlowGrantsInput`. They are there rather than here because a grant is
443
+ // one subject with two kinds of target, not two features and `ShareResult` answers for both.
444
444
  // What accesses what, for one level of the shared tree (#19). A folder answers it for its contents,
445
445
  // a single flow for itself. Documents and flows are two kinds of thing that share one tree
446
446
  // (ADR-0004 §1), so the graph carries both and says which of them it is.
@@ -20,6 +20,10 @@ export declare const ListGrantsInput: z.ZodObject<{
20
20
  resourceId: z.ZodString;
21
21
  }, z.core.$strict>;
22
22
  export type ListGrantsInput = z.infer<typeof ListGrantsInput>;
23
+ export declare const ListFlowGrantsInput: z.ZodObject<{
24
+ flowId: z.ZodString;
25
+ }, z.core.$strict>;
26
+ export type ListFlowGrantsInput = z.infer<typeof ListFlowGrantsInput>;
23
27
  export declare const ResourceGrant: z.ZodObject<{
24
28
  id: z.ZodString;
25
29
  resourceId: z.ZodString;
@@ -70,6 +74,33 @@ export declare const RevokeGrantInput: z.ZodObject<{
70
74
  idempotencyKey: z.ZodString;
71
75
  }, z.core.$strict>;
72
76
  export type RevokeGrantInput = z.infer<typeof RevokeGrantInput>;
77
+ export declare const ShareFlowInput: z.ZodObject<{
78
+ flowId: z.ZodString;
79
+ principal: z.ZodDiscriminatedUnion<[z.ZodObject<{
80
+ type: z.ZodLiteral<"user">;
81
+ id: z.ZodString;
82
+ }, z.core.$strict>, z.ZodObject<{
83
+ type: z.ZodLiteral<"email">;
84
+ email: z.ZodEmail;
85
+ }, z.core.$strict>, z.ZodObject<{
86
+ type: z.ZodLiteral<"organization">;
87
+ }, z.core.$strict>], "type">;
88
+ verb: z.ZodEnum<{
89
+ read: "read";
90
+ write: "write";
91
+ execute: "execute";
92
+ share: "share";
93
+ }>;
94
+ expiresAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
95
+ idempotencyKey: z.ZodString;
96
+ }, z.core.$strict>;
97
+ export type ShareFlowInput = z.infer<typeof ShareFlowInput>;
98
+ export declare const RevokeFlowGrantInput: z.ZodObject<{
99
+ flowId: z.ZodString;
100
+ grantId: z.ZodString;
101
+ idempotencyKey: z.ZodString;
102
+ }, z.core.$strict>;
103
+ export type RevokeFlowGrantInput = z.infer<typeof RevokeFlowGrantInput>;
73
104
  export declare const UnreadableNodes: z.ZodObject<{
74
105
  titles: z.ZodArray<z.ZodString>;
75
106
  hidden: z.ZodNumber;
@@ -102,6 +133,10 @@ export declare const ShareResult: z.ZodObject<{
102
133
  titles: z.ZodArray<z.ZodString>;
103
134
  hidden: z.ZodNumber;
104
135
  }, z.core.$strict>;
136
+ unrunnable: z.ZodDefault<z.ZodObject<{
137
+ titles: z.ZodArray<z.ZodString>;
138
+ hidden: z.ZodNumber;
139
+ }, z.core.$strict>>;
105
140
  }, z.core.$strict>;
106
141
  export type ShareResult = z.infer<typeof ShareResult>;
107
142
  export declare const ResourceGrantList: z.ZodObject<{
@@ -17,6 +17,12 @@ export const SharePrincipal = z.discriminatedUnion("type", [
17
17
  export const ListGrantsInput = z.strictObject({
18
18
  resourceId: IntelId.describe("Node whose direct grants to list. Access inherited from a folder above is not a grant on this node and is not listed here."),
19
19
  });
20
+ // The same three shapes for a flow (#530). Separate inputs rather than a widened `resourceId`,
21
+ // because the id names a different table and a caller that passes the wrong kind should be told so
22
+ // by the route it called rather than by a lookup that finds nothing.
23
+ export const ListFlowGrantsInput = z.strictObject({
24
+ flowId: IntelId.describe("Flow whose direct grants to list. Access inherited from the folder it is filed in is not a grant on this flow and is not listed here."),
25
+ });
20
26
  export const ResourceGrant = z.strictObject({
21
27
  id: IntelId,
22
28
  resourceId: IntelId,
@@ -40,6 +46,20 @@ export const RevokeGrantInput = z.strictObject({
40
46
  grantId: IntelId.describe("The grant to withdraw, from node_grant_list."),
41
47
  idempotencyKey: IdempotencyKey,
42
48
  });
49
+ export const ShareFlowInput = z.strictObject({
50
+ flowId: IntelId.describe("Flow to grant access to. A grant here reaches this flow and nothing else — not the folder it is filed in, and not the flows it calls."),
51
+ principal: SharePrincipal.describe("Who gets the access: a Gate user by id, someone by verified email address, or the whole organization."),
52
+ verb: ResourceVerb.describe("What they may do. Each verb is granted on its own and none implies another: `read` opens the flow, `write` edits it, `execute` runs it, `share` passes access on."),
53
+ expiresAt: IsoDateTime.nullable()
54
+ .default(null)
55
+ .describe("When the grant stops working, or `null` for one that does not expire on its own."),
56
+ idempotencyKey: IdempotencyKey,
57
+ });
58
+ export const RevokeFlowGrantInput = z.strictObject({
59
+ flowId: IntelId.describe("Flow the grant sits on. Named alongside the grant id so access is decided on the flow."),
60
+ grantId: IntelId.describe("The grant to withdraw, from flow_grant_list."),
61
+ idempotencyKey: IdempotencyKey,
62
+ });
43
63
  // What a grant does not cover, reported to whoever just made it. A flow in the shared folder may
44
64
  // read a document outside it, and the run is re-authorized against the person running it — so the
45
65
  // grant can be complete and the flow still stop for them (ADR-0004 §4).
@@ -53,9 +73,17 @@ export const UnreadableNodes = z.strictObject({
53
73
  // The grant is in the answer, so the warning cannot be mistaken for a refusal: it is written first
54
74
  // and described afterwards. Blocking would force everyone who uses a central policy document to
55
75
  // duplicate it, which is the opposite of what one tree is for (ADR-0004 §4).
76
+ //
77
+ // ⚠️ `unrunnable` is the second half of the same sentence and belongs to the flow grant (#530). A
78
+ // grant on a folder covered every flow beneath it, so there was nothing to say; a grant on one flow
79
+ // reaches that flow and stops, and the sub-flows it calls are then somebody else's to grant. It
80
+ // carries the shape of `UnreadableNodes` because it answers the same question — what this grant
81
+ // does NOT reach, named where the sharer may see it and counted where they may not — and it is
82
+ // empty for every node grant.
56
83
  export const ShareResult = z.strictObject({
57
84
  grant: ResourceGrant,
58
85
  unreadable: UnreadableNodes,
86
+ unrunnable: UnreadableNodes.default({ titles: [], hidden: 0 }),
59
87
  });
60
88
  // `applicableVerbs` travels with the list because the answer is the business layer's, not the
61
89
  // screen's: a document has nothing to execute, so `execute` is not offered on one (ADR-0004 §2).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anchrd/intel-contract",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {