@fuzdev/fuz_app 0.67.0 → 0.68.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.
Files changed (168) hide show
  1. package/dist/auth/CLAUDE.md +99 -5
  2. package/dist/auth/account_queries.d.ts +87 -4
  3. package/dist/auth/account_queries.d.ts.map +1 -1
  4. package/dist/auth/account_queries.js +107 -17
  5. package/dist/auth/account_schema.d.ts +19 -0
  6. package/dist/auth/account_schema.d.ts.map +1 -1
  7. package/dist/auth/account_schema.js +8 -0
  8. package/dist/auth/admin_action_specs.d.ts +168 -0
  9. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  10. package/dist/auth/admin_action_specs.js +146 -1
  11. package/dist/auth/admin_actions.d.ts.map +1 -1
  12. package/dist/auth/admin_actions.js +218 -4
  13. package/dist/auth/audit_log_ddl.d.ts +10 -1
  14. package/dist/auth/audit_log_ddl.d.ts.map +1 -1
  15. package/dist/auth/audit_log_ddl.js +13 -4
  16. package/dist/auth/audit_log_schema.d.ts +34 -1
  17. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  18. package/dist/auth/audit_log_schema.js +73 -0
  19. package/dist/auth/auth_ddl.d.ts +2 -2
  20. package/dist/auth/auth_ddl.d.ts.map +1 -1
  21. package/dist/auth/auth_ddl.js +10 -2
  22. package/dist/auth/cell_action_specs.d.ts +1295 -0
  23. package/dist/auth/cell_action_specs.d.ts.map +1 -0
  24. package/dist/auth/cell_action_specs.js +397 -0
  25. package/dist/auth/cell_actions.d.ts +63 -0
  26. package/dist/auth/cell_actions.d.ts.map +1 -0
  27. package/dist/auth/cell_actions.js +546 -0
  28. package/dist/auth/cell_audit_action_specs.d.ts +131 -0
  29. package/dist/auth/cell_audit_action_specs.d.ts.map +1 -0
  30. package/dist/auth/cell_audit_action_specs.js +70 -0
  31. package/dist/auth/cell_audit_actions.d.ts +18 -0
  32. package/dist/auth/cell_audit_actions.d.ts.map +1 -0
  33. package/dist/auth/cell_audit_actions.js +59 -0
  34. package/dist/auth/cell_audit_events.d.ts +28 -0
  35. package/dist/auth/cell_audit_events.d.ts.map +1 -0
  36. package/dist/auth/cell_audit_events.js +42 -0
  37. package/dist/auth/cell_audit_metadata.d.ts +48 -0
  38. package/dist/auth/cell_audit_metadata.d.ts.map +1 -0
  39. package/dist/auth/cell_audit_metadata.js +46 -0
  40. package/dist/auth/cell_authorize.d.ts +88 -0
  41. package/dist/auth/cell_authorize.d.ts.map +1 -0
  42. package/dist/auth/cell_authorize.js +172 -0
  43. package/dist/auth/cell_data_schema.d.ts +44 -0
  44. package/dist/auth/cell_data_schema.d.ts.map +1 -0
  45. package/dist/auth/cell_data_schema.js +42 -0
  46. package/dist/auth/cell_field_action_specs.d.ts +244 -0
  47. package/dist/auth/cell_field_action_specs.d.ts.map +1 -0
  48. package/dist/auth/cell_field_action_specs.js +136 -0
  49. package/dist/auth/cell_field_actions.d.ts +34 -0
  50. package/dist/auth/cell_field_actions.d.ts.map +1 -0
  51. package/dist/auth/cell_field_actions.js +153 -0
  52. package/dist/auth/cell_field_audit_metadata.d.ts +30 -0
  53. package/dist/auth/cell_field_audit_metadata.d.ts.map +1 -0
  54. package/dist/auth/cell_field_audit_metadata.js +28 -0
  55. package/dist/auth/cell_grant_action_specs.d.ts +333 -0
  56. package/dist/auth/cell_grant_action_specs.d.ts.map +1 -0
  57. package/dist/auth/cell_grant_action_specs.js +148 -0
  58. package/dist/auth/cell_grant_actions.d.ts +50 -0
  59. package/dist/auth/cell_grant_actions.d.ts.map +1 -0
  60. package/dist/auth/cell_grant_actions.js +208 -0
  61. package/dist/auth/cell_grant_audit_metadata.d.ts +75 -0
  62. package/dist/auth/cell_grant_audit_metadata.d.ts.map +1 -0
  63. package/dist/auth/cell_grant_audit_metadata.js +54 -0
  64. package/dist/auth/cell_item_action_specs.d.ts +331 -0
  65. package/dist/auth/cell_item_action_specs.d.ts.map +1 -0
  66. package/dist/auth/cell_item_action_specs.js +182 -0
  67. package/dist/auth/cell_item_actions.d.ts +37 -0
  68. package/dist/auth/cell_item_actions.d.ts.map +1 -0
  69. package/dist/auth/cell_item_actions.js +204 -0
  70. package/dist/auth/cell_item_audit_metadata.d.ts +35 -0
  71. package/dist/auth/cell_item_audit_metadata.d.ts.map +1 -0
  72. package/dist/auth/cell_item_audit_metadata.js +32 -0
  73. package/dist/auth/cell_relation_visibility.d.ts +32 -0
  74. package/dist/auth/cell_relation_visibility.d.ts.map +1 -0
  75. package/dist/auth/cell_relation_visibility.js +57 -0
  76. package/dist/auth/deps.d.ts +9 -0
  77. package/dist/auth/deps.d.ts.map +1 -1
  78. package/dist/auth/role_grant_queries.d.ts +30 -0
  79. package/dist/auth/role_grant_queries.d.ts.map +1 -1
  80. package/dist/auth/role_grant_queries.js +54 -0
  81. package/dist/db/CLAUDE.md +118 -0
  82. package/dist/db/cell_audit_queries.d.ts +26 -0
  83. package/dist/db/cell_audit_queries.d.ts.map +1 -0
  84. package/dist/db/cell_audit_queries.js +53 -0
  85. package/dist/db/cell_ddl.d.ts +151 -0
  86. package/dist/db/cell_ddl.d.ts.map +1 -0
  87. package/dist/db/cell_ddl.js +247 -0
  88. package/dist/db/cell_field_queries.d.ts +105 -0
  89. package/dist/db/cell_field_queries.d.ts.map +1 -0
  90. package/dist/db/cell_field_queries.js +113 -0
  91. package/dist/db/cell_grant_queries.d.ts +132 -0
  92. package/dist/db/cell_grant_queries.d.ts.map +1 -0
  93. package/dist/db/cell_grant_queries.js +145 -0
  94. package/dist/db/cell_history_ddl.d.ts +38 -0
  95. package/dist/db/cell_history_ddl.d.ts.map +1 -0
  96. package/dist/db/cell_history_ddl.js +61 -0
  97. package/dist/db/cell_item_queries.d.ts +107 -0
  98. package/dist/db/cell_item_queries.d.ts.map +1 -0
  99. package/dist/db/cell_item_queries.js +119 -0
  100. package/dist/db/cell_queries.d.ts +327 -0
  101. package/dist/db/cell_queries.d.ts.map +1 -0
  102. package/dist/db/cell_queries.js +431 -0
  103. package/dist/db/fact_ddl.d.ts +38 -0
  104. package/dist/db/fact_ddl.d.ts.map +1 -0
  105. package/dist/db/fact_ddl.js +71 -0
  106. package/dist/db/fact_queries.d.ts +140 -0
  107. package/dist/db/fact_queries.d.ts.map +1 -0
  108. package/dist/db/fact_queries.js +161 -0
  109. package/dist/db/fact_store.d.ts +112 -0
  110. package/dist/db/fact_store.d.ts.map +1 -0
  111. package/dist/db/fact_store.js +225 -0
  112. package/dist/server/env.d.ts +2 -0
  113. package/dist/server/env.d.ts.map +1 -1
  114. package/dist/server/env.js +6 -0
  115. package/dist/server/fact_write.d.ts +32 -0
  116. package/dist/server/fact_write.d.ts.map +1 -0
  117. package/dist/server/fact_write.js +56 -0
  118. package/dist/server/file_fact_fetcher.d.ts +42 -0
  119. package/dist/server/file_fact_fetcher.d.ts.map +1 -0
  120. package/dist/server/file_fact_fetcher.js +60 -0
  121. package/dist/server/file_fact_url.d.ts +53 -0
  122. package/dist/server/file_fact_url.d.ts.map +1 -0
  123. package/dist/server/file_fact_url.js +52 -0
  124. package/dist/server/serve_fact_route.d.ts +78 -0
  125. package/dist/server/serve_fact_route.d.ts.map +1 -0
  126. package/dist/server/serve_fact_route.js +205 -0
  127. package/dist/testing/CLAUDE.md +58 -5
  128. package/dist/testing/app_server.d.ts +12 -0
  129. package/dist/testing/app_server.d.ts.map +1 -1
  130. package/dist/testing/app_server.js +36 -2
  131. package/dist/testing/audit_completeness.d.ts.map +1 -1
  132. package/dist/testing/audit_completeness.js +67 -1
  133. package/dist/testing/cross_backend/account_lifecycle.d.ts +10 -0
  134. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -0
  135. package/dist/testing/cross_backend/account_lifecycle.js +76 -0
  136. package/dist/testing/cross_backend/capabilities.d.ts +31 -0
  137. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  138. package/dist/testing/cross_backend/capabilities.js +3 -0
  139. package/dist/testing/cross_backend/cell_cross_helpers.d.ts +39 -0
  140. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +1 -0
  141. package/dist/testing/cross_backend/cell_cross_helpers.js +45 -0
  142. package/dist/testing/cross_backend/cell_crud.d.ts +4 -0
  143. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -0
  144. package/dist/testing/cross_backend/cell_crud.js +168 -0
  145. package/dist/testing/cross_backend/cell_relations.d.ts +4 -0
  146. package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -0
  147. package/dist/testing/cross_backend/cell_relations.js +229 -0
  148. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  149. package/dist/testing/cross_backend/default_backend_configs.js +6 -0
  150. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  151. package/dist/testing/cross_backend/setup.js +5 -0
  152. package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -1
  153. package/dist/testing/cross_backend/spawn_backend.js +31 -3
  154. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
  155. package/dist/testing/cross_backend/testing_server_bun.js +29 -2
  156. package/dist/testing/entities.d.ts.map +1 -1
  157. package/dist/testing/entities.js +4 -0
  158. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  159. package/dist/testing/ws_round_trip.js +4 -0
  160. package/dist/ui/AdminAccounts.svelte +58 -0
  161. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  162. package/dist/ui/admin_accounts_state.svelte.d.ts +30 -2
  163. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  164. package/dist/ui/admin_accounts_state.svelte.js +45 -1
  165. package/dist/ui/admin_rpc_adapters.d.ts +6 -2
  166. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  167. package/dist/ui/admin_rpc_adapters.js +5 -1
  168. package/package.json +4 -2
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Audit-log metadata schemas for `cell_field_set` / `cell_field_delete`.
3
+ *
4
+ * IDs only — same discipline as the cell + cell_grant envelopes (audit
5
+ * logs store references, not denormalized strings). Apps register these
6
+ * via `extra_events:` on `create_audit_log_config`.
7
+ *
8
+ * @module
9
+ */
10
+ import { z } from 'zod';
11
+ import { Uuid } from '@fuzdev/fuz_util/id.js';
12
+ /**
13
+ * Metadata envelope for `cell_field_set`. Emitted on every successful
14
+ * create OR update path (UPSERT on `(source_id, name)`); the audit
15
+ * reader correlates create-vs-update via repeated `(source_id, name)`
16
+ * if needed.
17
+ */
18
+ export const CellFieldSetAuditMetadata = z.looseObject({
19
+ source_id: Uuid,
20
+ name: z.string(),
21
+ target_id: Uuid,
22
+ });
23
+ /** Metadata envelope for `cell_field_delete`. */
24
+ export const CellFieldDeleteAuditMetadata = z.looseObject({
25
+ source_id: Uuid,
26
+ name: z.string(),
27
+ target_id: Uuid,
28
+ });
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Cell-grant ACL RPC specs — declarative contract for the three
3
+ * `cell_grant_*` verbs (`create`, `revoke`, `list`).
4
+ *
5
+ * The grant primitive is a resource-side ACL: each row admits a
6
+ * principal (actor or role+scope) at a level (viewer / editor) on a
7
+ * single cell. Owner is implicit on `cell.created_by` and never appears
8
+ * in the grant list.
9
+ *
10
+ * Principal is `{actor_id}` or `{role, scope_id?}` — no name resolver on
11
+ * this verb. Callers pick an actor by id via `actor_search` (debounced
12
+ * prefix search) and submit the resolved id directly.
13
+ *
14
+ * @module
15
+ */
16
+ import { z } from 'zod';
17
+ /** Error reason — grant id did not resolve, or caller may not see it. */
18
+ export declare const ERROR_CELL_GRANT_NOT_FOUND: "cell_grant_not_found";
19
+ /**
20
+ * Error reason — `cell_grant_create` principal resolves to the cell's
21
+ * owner. Owner access is implicit (`cell.created_by`); a self-grant
22
+ * row would shadow it without changing access and create a confusing
23
+ * self-leave path.
24
+ */
25
+ export declare const ERROR_CELL_GRANT_PRINCIPAL_IS_OWNER: "cell_grant_principal_is_owner";
26
+ /**
27
+ * Error reason — role-shaped principal references a role string not
28
+ * registered in the role schema. Would produce a dead grant row that
29
+ * no role_grant could match.
30
+ */
31
+ export declare const ERROR_CELL_GRANT_UNKNOWN_ROLE: "cell_grant_unknown_role";
32
+ /** Grant level — view-only or view-plus-edit. */
33
+ export declare const CellGrantLevel: z.ZodEnum<{
34
+ viewer: "viewer";
35
+ editor: "editor";
36
+ }>;
37
+ export type CellGrantLevel = z.infer<typeof CellGrantLevel>;
38
+ /**
39
+ * Wire-input principal. Discriminated by `kind`. Actor-shaped principals
40
+ * carry a resolved `actor_id` — the picker UI runs `actor_search` to
41
+ * convert a typed name to an id before this verb is called.
42
+ */
43
+ export declare const CellGrantPrincipalInput: z.ZodDiscriminatedUnion<[z.ZodObject<{
44
+ kind: z.ZodLiteral<"actor">;
45
+ actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
46
+ }, z.core.$strict>, z.ZodObject<{
47
+ kind: z.ZodLiteral<"role">;
48
+ role: z.ZodString;
49
+ scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
50
+ }, z.core.$strict>], "kind">;
51
+ export type CellGrantPrincipalInput = z.infer<typeof CellGrantPrincipalInput>;
52
+ /**
53
+ * Wire-format for a cell_grant row. Mirrors `CellJson`'s shape — ISO-string
54
+ * `created_at`, branded UUIDs, principal columns surfaced as-is. Caller
55
+ * inspects `actor_id` xor `role` to render the right principal label.
56
+ */
57
+ export declare const GrantJson: z.ZodObject<{
58
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
59
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
60
+ level: z.ZodEnum<{
61
+ viewer: "viewer";
62
+ editor: "editor";
63
+ }>;
64
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
65
+ role: z.ZodNullable<z.ZodString>;
66
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
67
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
68
+ created_at: z.ZodString;
69
+ }, z.core.$strict>;
70
+ export type GrantJson = z.infer<typeof GrantJson>;
71
+ /**
72
+ * Input for `cell_grant_create`. Idempotent on the unique index —
73
+ * re-granting the same `(cell_id, principal)` pair updates `level` +
74
+ * `granted_by` rather than producing a duplicate row.
75
+ */
76
+ export declare const CellGrantCreateInput: z.ZodObject<{
77
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
78
+ level: z.ZodEnum<{
79
+ viewer: "viewer";
80
+ editor: "editor";
81
+ }>;
82
+ principal: z.ZodDiscriminatedUnion<[z.ZodObject<{
83
+ kind: z.ZodLiteral<"actor">;
84
+ actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
85
+ }, z.core.$strict>, z.ZodObject<{
86
+ kind: z.ZodLiteral<"role">;
87
+ role: z.ZodString;
88
+ scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
89
+ }, z.core.$strict>], "kind">;
90
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
91
+ }, z.core.$strict>;
92
+ export type CellGrantCreateInput = z.infer<typeof CellGrantCreateInput>;
93
+ export declare const CellGrantCreateOutput: z.ZodObject<{
94
+ grant: z.ZodObject<{
95
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
96
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
97
+ level: z.ZodEnum<{
98
+ viewer: "viewer";
99
+ editor: "editor";
100
+ }>;
101
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
102
+ role: z.ZodNullable<z.ZodString>;
103
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
104
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
105
+ created_at: z.ZodString;
106
+ }, z.core.$strict>;
107
+ }, z.core.$strict>;
108
+ export type CellGrantCreateOutput = z.infer<typeof CellGrantCreateOutput>;
109
+ export declare const CellGrantRevokeInput: z.ZodObject<{
110
+ grant_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
111
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
112
+ }, z.core.$strict>;
113
+ export type CellGrantRevokeInput = z.infer<typeof CellGrantRevokeInput>;
114
+ /**
115
+ * Output for `cell_grant_revoke`. `still_admitted` is `true` when the
116
+ * caller retains some admit path on the cell after the revoke (other
117
+ * grant, ownership, admin). Always `true` for non-self revokes (the
118
+ * caller didn't admit via this row to begin with).
119
+ */
120
+ export declare const CellGrantRevokeOutput: z.ZodObject<{
121
+ ok: z.ZodLiteral<true>;
122
+ still_admitted: z.ZodBoolean;
123
+ }, z.core.$strict>;
124
+ export type CellGrantRevokeOutput = z.infer<typeof CellGrantRevokeOutput>;
125
+ export declare const CellGrantListInput: z.ZodObject<{
126
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
127
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
128
+ }, z.core.$strict>;
129
+ export type CellGrantListInput = z.infer<typeof CellGrantListInput>;
130
+ export declare const CellGrantListOutput: z.ZodObject<{
131
+ grants: z.ZodArray<z.ZodObject<{
132
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
133
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
134
+ level: z.ZodEnum<{
135
+ viewer: "viewer";
136
+ editor: "editor";
137
+ }>;
138
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
139
+ role: z.ZodNullable<z.ZodString>;
140
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
141
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
142
+ created_at: z.ZodString;
143
+ }, z.core.$strict>>;
144
+ }, z.core.$strict>;
145
+ export type CellGrantListOutput = z.infer<typeof CellGrantListOutput>;
146
+ export declare const cell_grant_create_action_spec: {
147
+ method: string;
148
+ kind: "request_response";
149
+ initiator: "frontend";
150
+ auth: {
151
+ account: "required";
152
+ actor: "required";
153
+ };
154
+ side_effects: true;
155
+ input: z.ZodObject<{
156
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
157
+ level: z.ZodEnum<{
158
+ viewer: "viewer";
159
+ editor: "editor";
160
+ }>;
161
+ principal: z.ZodDiscriminatedUnion<[z.ZodObject<{
162
+ kind: z.ZodLiteral<"actor">;
163
+ actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
164
+ }, z.core.$strict>, z.ZodObject<{
165
+ kind: z.ZodLiteral<"role">;
166
+ role: z.ZodString;
167
+ scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
168
+ }, z.core.$strict>], "kind">;
169
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
170
+ }, z.core.$strict>;
171
+ output: z.ZodObject<{
172
+ grant: z.ZodObject<{
173
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
174
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
175
+ level: z.ZodEnum<{
176
+ viewer: "viewer";
177
+ editor: "editor";
178
+ }>;
179
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
180
+ role: z.ZodNullable<z.ZodString>;
181
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
182
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
183
+ created_at: z.ZodString;
184
+ }, z.core.$strict>;
185
+ }, z.core.$strict>;
186
+ async: true;
187
+ description: string;
188
+ };
189
+ export declare const cell_grant_revoke_action_spec: {
190
+ method: string;
191
+ kind: "request_response";
192
+ initiator: "frontend";
193
+ auth: {
194
+ account: "required";
195
+ actor: "required";
196
+ };
197
+ side_effects: true;
198
+ input: z.ZodObject<{
199
+ grant_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
200
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
201
+ }, z.core.$strict>;
202
+ output: z.ZodObject<{
203
+ ok: z.ZodLiteral<true>;
204
+ still_admitted: z.ZodBoolean;
205
+ }, z.core.$strict>;
206
+ async: true;
207
+ description: string;
208
+ };
209
+ export declare const cell_grant_list_action_spec: {
210
+ method: string;
211
+ kind: "request_response";
212
+ initiator: "frontend";
213
+ auth: {
214
+ account: "required";
215
+ actor: "required";
216
+ };
217
+ side_effects: false;
218
+ input: z.ZodObject<{
219
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
220
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
221
+ }, z.core.$strict>;
222
+ output: z.ZodObject<{
223
+ grants: z.ZodArray<z.ZodObject<{
224
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
225
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
226
+ level: z.ZodEnum<{
227
+ viewer: "viewer";
228
+ editor: "editor";
229
+ }>;
230
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
231
+ role: z.ZodNullable<z.ZodString>;
232
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
233
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
234
+ created_at: z.ZodString;
235
+ }, z.core.$strict>>;
236
+ }, z.core.$strict>;
237
+ async: true;
238
+ description: string;
239
+ };
240
+ /** All cell_grant action specs — composed into `all_cell_action_specs`. */
241
+ export declare const all_cell_grant_action_specs: readonly [{
242
+ method: string;
243
+ kind: "request_response";
244
+ initiator: "frontend";
245
+ auth: {
246
+ account: "required";
247
+ actor: "required";
248
+ };
249
+ side_effects: true;
250
+ input: z.ZodObject<{
251
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
252
+ level: z.ZodEnum<{
253
+ viewer: "viewer";
254
+ editor: "editor";
255
+ }>;
256
+ principal: z.ZodDiscriminatedUnion<[z.ZodObject<{
257
+ kind: z.ZodLiteral<"actor">;
258
+ actor_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
259
+ }, z.core.$strict>, z.ZodObject<{
260
+ kind: z.ZodLiteral<"role">;
261
+ role: z.ZodString;
262
+ scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
263
+ }, z.core.$strict>], "kind">;
264
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
265
+ }, z.core.$strict>;
266
+ output: z.ZodObject<{
267
+ grant: z.ZodObject<{
268
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
269
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
270
+ level: z.ZodEnum<{
271
+ viewer: "viewer";
272
+ editor: "editor";
273
+ }>;
274
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
275
+ role: z.ZodNullable<z.ZodString>;
276
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
277
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
278
+ created_at: z.ZodString;
279
+ }, z.core.$strict>;
280
+ }, z.core.$strict>;
281
+ async: true;
282
+ description: string;
283
+ }, {
284
+ method: string;
285
+ kind: "request_response";
286
+ initiator: "frontend";
287
+ auth: {
288
+ account: "required";
289
+ actor: "required";
290
+ };
291
+ side_effects: true;
292
+ input: z.ZodObject<{
293
+ grant_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
294
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
295
+ }, z.core.$strict>;
296
+ output: z.ZodObject<{
297
+ ok: z.ZodLiteral<true>;
298
+ still_admitted: z.ZodBoolean;
299
+ }, z.core.$strict>;
300
+ async: true;
301
+ description: string;
302
+ }, {
303
+ method: string;
304
+ kind: "request_response";
305
+ initiator: "frontend";
306
+ auth: {
307
+ account: "required";
308
+ actor: "required";
309
+ };
310
+ side_effects: false;
311
+ input: z.ZodObject<{
312
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
313
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
314
+ }, z.core.$strict>;
315
+ output: z.ZodObject<{
316
+ grants: z.ZodArray<z.ZodObject<{
317
+ id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
318
+ cell_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
319
+ level: z.ZodEnum<{
320
+ viewer: "viewer";
321
+ editor: "editor";
322
+ }>;
323
+ actor_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
324
+ role: z.ZodNullable<z.ZodString>;
325
+ scope_id: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
326
+ granted_by: z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
327
+ created_at: z.ZodString;
328
+ }, z.core.$strict>>;
329
+ }, z.core.$strict>;
330
+ async: true;
331
+ description: string;
332
+ }];
333
+ //# sourceMappingURL=cell_grant_action_specs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_grant_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_grant_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAQtB,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,EAAG,sBAA+B,CAAC;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,EAAG,+BAAwC,CAAC;AAE5F;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,EAAG,yBAAkC,CAAC;AAIhF,iDAAiD;AACjD,eAAO,MAAM,cAAc;;;EAA+B,CAAC;AAC3D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;4BAYlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;kBASpB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAIlD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;kBAO/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;kBAAqC,CAAC;AACxE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI1E,eAAO,MAAM,oBAAoB;;;kBAG/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;kBAGhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI1E,eAAO,MAAM,kBAAkB;;;kBAG7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;kBAE9B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAItE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWL,CAAC;AAEtC,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;CAWL,CAAC;AAEtC,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWH,CAAC;AAEtC,2EAA2E;AAC3E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI9B,CAAC"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Cell-grant ACL RPC specs — declarative contract for the three
3
+ * `cell_grant_*` verbs (`create`, `revoke`, `list`).
4
+ *
5
+ * The grant primitive is a resource-side ACL: each row admits a
6
+ * principal (actor or role+scope) at a level (viewer / editor) on a
7
+ * single cell. Owner is implicit on `cell.created_by` and never appears
8
+ * in the grant list.
9
+ *
10
+ * Principal is `{actor_id}` or `{role, scope_id?}` — no name resolver on
11
+ * this verb. Callers pick an actor by id via `actor_search` (debounced
12
+ * prefix search) and submit the resolved id directly.
13
+ *
14
+ * @module
15
+ */
16
+ import { z } from 'zod';
17
+ import { Uuid } from '@fuzdev/fuz_util/id.js';
18
+ import { ActingActor } from '../http/auth_shape.js';
19
+ // -- Error reasons ----------------------------------------------------------
20
+ /** Error reason — grant id did not resolve, or caller may not see it. */
21
+ export const ERROR_CELL_GRANT_NOT_FOUND = 'cell_grant_not_found';
22
+ /**
23
+ * Error reason — `cell_grant_create` principal resolves to the cell's
24
+ * owner. Owner access is implicit (`cell.created_by`); a self-grant
25
+ * row would shadow it without changing access and create a confusing
26
+ * self-leave path.
27
+ */
28
+ export const ERROR_CELL_GRANT_PRINCIPAL_IS_OWNER = 'cell_grant_principal_is_owner';
29
+ /**
30
+ * Error reason — role-shaped principal references a role string not
31
+ * registered in the role schema. Would produce a dead grant row that
32
+ * no role_grant could match.
33
+ */
34
+ export const ERROR_CELL_GRANT_UNKNOWN_ROLE = 'cell_grant_unknown_role';
35
+ // -- Shared schemas ---------------------------------------------------------
36
+ /** Grant level — view-only or view-plus-edit. */
37
+ export const CellGrantLevel = z.enum(['viewer', 'editor']);
38
+ /**
39
+ * Wire-input principal. Discriminated by `kind`. Actor-shaped principals
40
+ * carry a resolved `actor_id` — the picker UI runs `actor_search` to
41
+ * convert a typed name to an id before this verb is called.
42
+ */
43
+ export const CellGrantPrincipalInput = z.discriminatedUnion('kind', [
44
+ z.strictObject({
45
+ kind: z.literal('actor'),
46
+ actor_id: Uuid,
47
+ }),
48
+ z.strictObject({
49
+ kind: z.literal('role'),
50
+ role: z.string().min(1),
51
+ scope_id: Uuid.nullish().meta({
52
+ description: '`null` / omitted = any-scope grant (admits any matching-role role_grant).',
53
+ }),
54
+ }),
55
+ ]);
56
+ /**
57
+ * Wire-format for a cell_grant row. Mirrors `CellJson`'s shape — ISO-string
58
+ * `created_at`, branded UUIDs, principal columns surfaced as-is. Caller
59
+ * inspects `actor_id` xor `role` to render the right principal label.
60
+ */
61
+ export const GrantJson = z.strictObject({
62
+ id: Uuid,
63
+ cell_id: Uuid,
64
+ level: CellGrantLevel,
65
+ actor_id: Uuid.nullable(),
66
+ role: z.string().nullable(),
67
+ scope_id: Uuid.nullable(),
68
+ granted_by: Uuid.nullable(),
69
+ created_at: z.string(),
70
+ });
71
+ // -- cell_grant_create ------------------------------------------------------
72
+ /**
73
+ * Input for `cell_grant_create`. Idempotent on the unique index —
74
+ * re-granting the same `(cell_id, principal)` pair updates `level` +
75
+ * `granted_by` rather than producing a duplicate row.
76
+ */
77
+ export const CellGrantCreateInput = z.strictObject({
78
+ cell_id: Uuid.meta({ description: 'Cell to grant access on.' }),
79
+ level: CellGrantLevel.meta({ description: 'Grant level: `viewer` or `editor`.' }),
80
+ principal: CellGrantPrincipalInput.meta({
81
+ description: 'Subject of the grant. Discriminated by `kind`.',
82
+ }),
83
+ acting: ActingActor,
84
+ });
85
+ export const CellGrantCreateOutput = z.strictObject({ grant: GrantJson });
86
+ // -- cell_grant_revoke ------------------------------------------------------
87
+ export const CellGrantRevokeInput = z.strictObject({
88
+ grant_id: Uuid.meta({ description: 'Grant to revoke.' }),
89
+ acting: ActingActor,
90
+ });
91
+ /**
92
+ * Output for `cell_grant_revoke`. `still_admitted` is `true` when the
93
+ * caller retains some admit path on the cell after the revoke (other
94
+ * grant, ownership, admin). Always `true` for non-self revokes (the
95
+ * caller didn't admit via this row to begin with).
96
+ */
97
+ export const CellGrantRevokeOutput = z.strictObject({
98
+ ok: z.literal(true),
99
+ still_admitted: z.boolean(),
100
+ });
101
+ // -- cell_grant_list --------------------------------------------------------
102
+ export const CellGrantListInput = z.strictObject({
103
+ cell_id: Uuid.meta({ description: 'Cell whose grants to list.' }),
104
+ acting: ActingActor,
105
+ });
106
+ export const CellGrantListOutput = z.strictObject({
107
+ grants: z.array(GrantJson),
108
+ });
109
+ // -- Action specs -----------------------------------------------------------
110
+ export const cell_grant_create_action_spec = {
111
+ method: 'cell_grant_create',
112
+ kind: 'request_response',
113
+ initiator: 'frontend',
114
+ auth: { account: 'required', actor: 'required' },
115
+ side_effects: true,
116
+ input: CellGrantCreateInput,
117
+ output: CellGrantCreateOutput,
118
+ async: true,
119
+ description: 'Grant view or edit access on a cell. Manage-tier only (admin / owner) — editor-grant holders cannot manage grants. Idempotent on `(cell_id, principal)`. Owner-as-principal rejected. Actor-shaped principals carry a pre-resolved `actor_id` (callers pick via `actor_search`); no name resolver on this verb.',
120
+ };
121
+ export const cell_grant_revoke_action_spec = {
122
+ method: 'cell_grant_revoke',
123
+ kind: 'request_response',
124
+ initiator: 'frontend',
125
+ auth: { account: 'required', actor: 'required' },
126
+ side_effects: true,
127
+ input: CellGrantRevokeInput,
128
+ output: CellGrantRevokeOutput,
129
+ async: true,
130
+ description: 'Revoke a grant. Manage-tier only (admin / owner), plus self for actor-shaped grants ("leave shared cell"). Returns `still_admitted` so the UI can tell the recipient whether other admit paths remain.',
131
+ };
132
+ export const cell_grant_list_action_spec = {
133
+ method: 'cell_grant_list',
134
+ kind: 'request_response',
135
+ initiator: 'frontend',
136
+ auth: { account: 'required', actor: 'required' },
137
+ side_effects: false,
138
+ input: CellGrantListInput,
139
+ output: CellGrantListOutput,
140
+ async: true,
141
+ description: "List grants on a cell. Manage-tier only (admin / owner); viewers and editors get IDOR-mask 404 (the share list is the manager's to curate).",
142
+ };
143
+ /** All cell_grant action specs — composed into `all_cell_action_specs`. */
144
+ export const all_cell_grant_action_specs = [
145
+ cell_grant_create_action_spec,
146
+ cell_grant_revoke_action_spec,
147
+ cell_grant_list_action_spec,
148
+ ];
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Cell-grant ACL RPC handlers.
3
+ *
4
+ * Three `request_response` actions bound to specs in
5
+ * `./cell_grant_action_specs.ts`:
6
+ *
7
+ * Grant management is **manage-tier only** (`can_manage_cell` = admin /
8
+ * owner). Editor-grant holders may edit a cell's content + relations but
9
+ * cannot manage its grants — delegating the share list would let an editor
10
+ * widen access or mint peer editors and escape the manager's authority.
11
+ *
12
+ * - `cell_grant_create` — admin / owner only. Validates role-shaped
13
+ * principals against the role schema; rejects owner-as-principal.
14
+ * Actor-shaped principals carry a pre-resolved `actor_id` (callers pick
15
+ * via `actor_search`). Idempotent — re-granting the same principal
16
+ * updates `level` via UPSERT.
17
+ * - `cell_grant_revoke` — admin / owner, plus self for actor-shaped grants
18
+ * ("leave shared cell"). Returns `still_admitted` computed by re-running
19
+ * `can_view_cell` against the remaining grants.
20
+ * - `cell_grant_list` — admin / owner only. Viewers and editors alike get
21
+ * the IDOR-mask 404 (the share list is the manager's to curate).
22
+ *
23
+ * All three 404 with `cell_not_found` on cell-miss / cell-unviewable, and
24
+ * with `cell_grant_not_found` on grant-miss, mirroring the existence-leak
25
+ * guards in `cell_actions.ts`.
26
+ *
27
+ * Audit events `cell_grant_create` / `cell_grant_revoke` carry IDs only
28
+ * (no display-name snapshots); see `./cell_grant_audit_metadata.ts`.
29
+ *
30
+ * @module
31
+ */
32
+ import { type RpcAction } from '../actions/action_rpc.js';
33
+ import type { RoleSchemaResult } from './role_schema.js';
34
+ import type { RouteFactoryDeps } from './deps.js';
35
+ import { type GrantJson } from './cell_grant_action_specs.js';
36
+ import { type CellGrantRow } from '../db/cell_grant_queries.js';
37
+ /**
38
+ * Dependencies for `create_cell_grant_actions`.
39
+ *
40
+ * `roles` is the role schema — read for the role-validity gate on
41
+ * `cell_grant_create`. The other slots match `CellActionDeps` so
42
+ * audit-log emit goes through the same fire-and-forget plumbing.
43
+ */
44
+ export type CellGrantActionDeps = Pick<RouteFactoryDeps, 'log' | 'audit'> & {
45
+ roles: RoleSchemaResult;
46
+ };
47
+ export declare const to_grant_json: (row: CellGrantRow) => GrantJson;
48
+ /** Create the three `cell_grant_*` RPC actions. */
49
+ export declare const create_cell_grant_actions: (deps: CellGrantActionDeps) => Array<RpcAction>;
50
+ //# sourceMappingURL=cell_grant_actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_grant_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_grant_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAsC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAE7F,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAEhD,OAAO,EAaN,KAAK,SAAS,EACd,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAKN,KAAK,YAAY,EAEjB,MAAM,6BAA6B,CAAC;AAOrC;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,OAAO,CAAC,GAAG;IAC3E,KAAK,EAAE,gBAAgB,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,KAAK,YAAY,KAAG,SAShD,CAAC;AAgDH,mDAAmD;AACnD,eAAO,MAAM,yBAAyB,GAAI,MAAM,mBAAmB,KAAG,KAAK,CAAC,SAAS,CAoIpF,CAAC"}