@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,42 @@
1
+ /**
2
+ * Generic cell-data base schema.
3
+ *
4
+ * The wire-side shape every cell consumer can read without per-kind
5
+ * knowledge: a permissive bag with three universally-relevant typed
6
+ * fields. Per-kind schemas extend this and narrow `kind` to a literal.
7
+ *
8
+ * Loose object: arbitrary additional fields pass through unvalidated,
9
+ * preserving the "unknown kinds ship without RPC churn" property. Per-kind
10
+ * shape enforcement is opt-in via the `validate_data` deps slot — see
11
+ * `cell_actions.ts`.
12
+ *
13
+ * **Discipline**: a field joins `CellData` only when at least two
14
+ * consumers in different domains read it generically. `kind` (editor
15
+ * dispatch + sub-API registry), `label` (list/index rendering), and
16
+ * `summary` (card subtitle + share-target description) meet this bar.
17
+ * Future candidates require evidence of generic usage — otherwise they
18
+ * stay per-kind.
19
+ *
20
+ * **Visibility is not in here.** Access control is a peer of `cell_grant`,
21
+ * not content metadata — `cell.visibility` lives as a top-level column on
22
+ * `CellJson` and `CellRow` (the `CellVisibility` enum is defined in
23
+ * `cell_action_specs.ts` next to the wire fields that use it), and is
24
+ * enforced by `can_view_cell` reading the column directly (no JSON dive).
25
+ *
26
+ * @module
27
+ */
28
+ import { z } from 'zod';
29
+ /**
30
+ * Base cell-data shape. All fields optional; loose mode admits arbitrary
31
+ * additional keys so apps can attach metadata or stage new kinds without
32
+ * touching the wire schema.
33
+ *
34
+ * `kind` is optional because cells without a registered kind are valid —
35
+ * admin-curated content, in-development types, or unknown shapes pass
36
+ * through. Known kinds get richer validation via the per-kind sub-API.
37
+ */
38
+ export const CellData = z.looseObject({
39
+ kind: z.string().optional(),
40
+ label: z.string().optional(),
41
+ summary: z.string().optional(),
42
+ });
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Cell-field RPC specs — declarative contract for the three named-relation
3
+ * verbs (`set` / `delete` / `list`).
4
+ *
5
+ * `(source_id, name) → target_id` edges modeled after JSON object
6
+ * key/value pairs. One target per `(source_id, name)` pair: re-setting a
7
+ * name overwrites the prior target. `cell_field_list` is bidirectional:
8
+ * pass `source_id` for forward fields, `target_id` for reverse upfields
9
+ * (the latter has 2-layer authz — see handler).
10
+ *
11
+ * @module
12
+ */
13
+ import { z } from 'zod';
14
+ /** Error reason — `cell_field_list` got neither `source_id` nor `target_id`. */
15
+ export declare const ERROR_CELL_FIELD_LIST_REQUIRES_SOURCE_OR_TARGET: "cell_field_list_requires_source_or_target";
16
+ /**
17
+ * Field name grammar — fuz snake_case identifier convention. Anchored
18
+ * `^[a-z][a-z0-9_]{0,63}$`: leading letter, alphanumeric + underscore
19
+ * trailing, 64-char cap. No reserved names yet.
20
+ */
21
+ export declare const CELL_FIELD_NAME_REGEX: RegExp;
22
+ export declare const CellFieldName: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
23
+ export type CellFieldName = z.infer<typeof CellFieldName>;
24
+ /** Wire-format for a `cell_field` row. ISO `created_at`, branded UUIDs. */
25
+ export declare const FieldJson: z.ZodObject<{
26
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
27
+ name: z.ZodString;
28
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
29
+ created_at: z.ZodString;
30
+ }, z.core.$strict>;
31
+ export type FieldJson = z.infer<typeof FieldJson>;
32
+ /**
33
+ * Input for `cell_field_set`. UPSERT on `(source_id, name)` — re-issuing
34
+ * the same input updates `target_id` and bumps `created_at`.
35
+ */
36
+ export declare const CellFieldSetInput: z.ZodObject<{
37
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
38
+ name: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
39
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
40
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
41
+ }, z.core.$strict>;
42
+ export type CellFieldSetInput = z.infer<typeof CellFieldSetInput>;
43
+ export declare const CellFieldSetOutput: z.ZodObject<{
44
+ field: z.ZodObject<{
45
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
46
+ name: z.ZodString;
47
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
48
+ created_at: z.ZodString;
49
+ }, z.core.$strict>;
50
+ }, z.core.$strict>;
51
+ export type CellFieldSetOutput = z.infer<typeof CellFieldSetOutput>;
52
+ /**
53
+ * Input for `cell_field_delete`. Idempotent: a successful response is
54
+ * returned even when no row matched.
55
+ */
56
+ export declare const CellFieldDeleteInput: z.ZodObject<{
57
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
58
+ name: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
59
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
60
+ }, z.core.$strict>;
61
+ export type CellFieldDeleteInput = z.infer<typeof CellFieldDeleteInput>;
62
+ export declare const CellFieldDeleteOutput: z.ZodObject<{
63
+ ok: z.ZodLiteral<true>;
64
+ deleted: z.ZodBoolean;
65
+ }, z.core.$strict>;
66
+ export type CellFieldDeleteOutput = z.infer<typeof CellFieldDeleteOutput>;
67
+ /**
68
+ * Input for `cell_field_list`. Pass `source_id` for forward fields or
69
+ * `target_id` for reverse upfields — exactly one (the schema rejects
70
+ * both / neither). Reverse listing has 2-layer authz (target view-check
71
+ * gates the call; per-source view-check filters the rows).
72
+ *
73
+ * Forward listing supports cursor pagination via `name_after` (return
74
+ * rows whose `name > name_after` lex). The reverse listing doesn't
75
+ * paginate (the result set is small in practice — number of sources
76
+ * pointing at a given target).
77
+ */
78
+ export declare const CellFieldListInput: z.ZodObject<{
79
+ source_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
80
+ target_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
81
+ name_after: z.ZodOptional<z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">>;
82
+ limit: z.ZodOptional<z.ZodNumber>;
83
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
84
+ }, z.core.$strict>;
85
+ export type CellFieldListInput = z.infer<typeof CellFieldListInput>;
86
+ export declare const CellFieldListOutput: z.ZodObject<{
87
+ fields: z.ZodArray<z.ZodObject<{
88
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
89
+ name: z.ZodString;
90
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
91
+ created_at: z.ZodString;
92
+ }, z.core.$strict>>;
93
+ }, z.core.$strict>;
94
+ export type CellFieldListOutput = z.infer<typeof CellFieldListOutput>;
95
+ export declare const cell_field_set_action_spec: {
96
+ method: string;
97
+ kind: "request_response";
98
+ initiator: "frontend";
99
+ auth: {
100
+ account: "required";
101
+ actor: "required";
102
+ };
103
+ side_effects: true;
104
+ input: z.ZodObject<{
105
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
106
+ name: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
107
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
108
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
109
+ }, z.core.$strict>;
110
+ output: z.ZodObject<{
111
+ field: z.ZodObject<{
112
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
113
+ name: z.ZodString;
114
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
115
+ created_at: z.ZodString;
116
+ }, z.core.$strict>;
117
+ }, z.core.$strict>;
118
+ async: true;
119
+ description: string;
120
+ };
121
+ export declare const cell_field_delete_action_spec: {
122
+ method: string;
123
+ kind: "request_response";
124
+ initiator: "frontend";
125
+ auth: {
126
+ account: "required";
127
+ actor: "required";
128
+ };
129
+ side_effects: true;
130
+ input: z.ZodObject<{
131
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
132
+ name: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
133
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
134
+ }, z.core.$strict>;
135
+ output: z.ZodObject<{
136
+ ok: z.ZodLiteral<true>;
137
+ deleted: z.ZodBoolean;
138
+ }, z.core.$strict>;
139
+ async: true;
140
+ description: string;
141
+ };
142
+ export declare const cell_field_list_action_spec: {
143
+ method: string;
144
+ kind: "request_response";
145
+ initiator: "frontend";
146
+ auth: {
147
+ account: "optional";
148
+ actor: "optional";
149
+ };
150
+ side_effects: false;
151
+ input: z.ZodObject<{
152
+ source_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
153
+ target_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
154
+ name_after: z.ZodOptional<z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">>;
155
+ limit: z.ZodOptional<z.ZodNumber>;
156
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
157
+ }, z.core.$strict>;
158
+ output: z.ZodObject<{
159
+ fields: z.ZodArray<z.ZodObject<{
160
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
161
+ name: z.ZodString;
162
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
163
+ created_at: z.ZodString;
164
+ }, z.core.$strict>>;
165
+ }, z.core.$strict>;
166
+ async: true;
167
+ rate_limit: "ip";
168
+ description: string;
169
+ };
170
+ /** All cell_field action specs — composed into `all_cell_action_specs`. */
171
+ export declare const all_cell_field_action_specs: readonly [{
172
+ method: string;
173
+ kind: "request_response";
174
+ initiator: "frontend";
175
+ auth: {
176
+ account: "required";
177
+ actor: "required";
178
+ };
179
+ side_effects: true;
180
+ input: z.ZodObject<{
181
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
182
+ name: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
183
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
184
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
185
+ }, z.core.$strict>;
186
+ output: z.ZodObject<{
187
+ field: z.ZodObject<{
188
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
189
+ name: z.ZodString;
190
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
191
+ created_at: z.ZodString;
192
+ }, z.core.$strict>;
193
+ }, z.core.$strict>;
194
+ async: true;
195
+ description: string;
196
+ }, {
197
+ method: string;
198
+ kind: "request_response";
199
+ initiator: "frontend";
200
+ auth: {
201
+ account: "required";
202
+ actor: "required";
203
+ };
204
+ side_effects: true;
205
+ input: z.ZodObject<{
206
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
207
+ name: z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">;
208
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
209
+ }, z.core.$strict>;
210
+ output: z.ZodObject<{
211
+ ok: z.ZodLiteral<true>;
212
+ deleted: z.ZodBoolean;
213
+ }, z.core.$strict>;
214
+ async: true;
215
+ description: string;
216
+ }, {
217
+ method: string;
218
+ kind: "request_response";
219
+ initiator: "frontend";
220
+ auth: {
221
+ account: "optional";
222
+ actor: "optional";
223
+ };
224
+ side_effects: false;
225
+ input: z.ZodObject<{
226
+ source_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
227
+ target_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
228
+ name_after: z.ZodOptional<z.core.$ZodBranded<z.ZodString, "CellFieldName", "out">>;
229
+ limit: z.ZodOptional<z.ZodNumber>;
230
+ acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
231
+ }, z.core.$strict>;
232
+ output: z.ZodObject<{
233
+ fields: z.ZodArray<z.ZodObject<{
234
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
235
+ name: z.ZodString;
236
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
237
+ created_at: z.ZodString;
238
+ }, z.core.$strict>>;
239
+ }, z.core.$strict>;
240
+ async: true;
241
+ rate_limit: "ip";
242
+ description: string;
243
+ }];
244
+ //# sourceMappingURL=cell_field_action_specs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_field_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_field_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAQtB,gFAAgF;AAChF,eAAO,MAAM,+CAA+C,EAC3D,2CAAoD,CAAC;AAItD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAA2B,CAAC;AAC9D,eAAO,MAAM,aAAa,yDAAiE,CAAC;AAC5F,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,2EAA2E;AAC3E,eAAO,MAAM,SAAS;;;;;kBAKpB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAIlD;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;;;;kBAO5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,kBAAkB;;;;;;;kBAAqC,CAAC;AACrE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAIpE;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;kBAI/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,eAAO,MAAM,qBAAqB;;;kBAGhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI1E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB;;;;;;kBAoB5B,CAAC;AACJ,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,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAEtC,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;CAWL,CAAC;AAEtC,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYH,CAAC;AAEtC,2EAA2E;AAC3E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI9B,CAAC"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Cell-field RPC specs — declarative contract for the three named-relation
3
+ * verbs (`set` / `delete` / `list`).
4
+ *
5
+ * `(source_id, name) → target_id` edges modeled after JSON object
6
+ * key/value pairs. One target per `(source_id, name)` pair: re-setting a
7
+ * name overwrites the prior target. `cell_field_list` is bidirectional:
8
+ * pass `source_id` for forward fields, `target_id` for reverse upfields
9
+ * (the latter has 2-layer authz — see handler).
10
+ *
11
+ * @module
12
+ */
13
+ import { z } from 'zod';
14
+ import { Uuid } from '@fuzdev/fuz_util/id.js';
15
+ import { ActingActor } from '../http/auth_shape.js';
16
+ // -- Error reasons ----------------------------------------------------------
17
+ /** Error reason — `cell_field_list` got neither `source_id` nor `target_id`. */
18
+ export const ERROR_CELL_FIELD_LIST_REQUIRES_SOURCE_OR_TARGET = 'cell_field_list_requires_source_or_target';
19
+ // -- Shared schemas ---------------------------------------------------------
20
+ /**
21
+ * Field name grammar — fuz snake_case identifier convention. Anchored
22
+ * `^[a-z][a-z0-9_]{0,63}$`: leading letter, alphanumeric + underscore
23
+ * trailing, 64-char cap. No reserved names yet.
24
+ */
25
+ export const CELL_FIELD_NAME_REGEX = /^[a-z][a-z0-9_]{0,63}$/;
26
+ export const CellFieldName = z.string().regex(CELL_FIELD_NAME_REGEX).brand('CellFieldName');
27
+ /** Wire-format for a `cell_field` row. ISO `created_at`, branded UUIDs. */
28
+ export const FieldJson = z.strictObject({
29
+ source_id: Uuid,
30
+ name: z.string(),
31
+ target_id: Uuid,
32
+ created_at: z.string(),
33
+ });
34
+ // -- cell_field_set ---------------------------------------------------------
35
+ /**
36
+ * Input for `cell_field_set`. UPSERT on `(source_id, name)` — re-issuing
37
+ * the same input updates `target_id` and bumps `created_at`.
38
+ */
39
+ export const CellFieldSetInput = z.strictObject({
40
+ source_id: Uuid.meta({ description: 'Cell whose field to set.' }),
41
+ name: CellFieldName.meta({
42
+ description: 'Field name. snake_case identifier; max 64 chars.',
43
+ }),
44
+ target_id: Uuid.meta({ description: 'Cell the field points at.' }),
45
+ acting: ActingActor,
46
+ });
47
+ export const CellFieldSetOutput = z.strictObject({ field: FieldJson });
48
+ // -- cell_field_delete ------------------------------------------------------
49
+ /**
50
+ * Input for `cell_field_delete`. Idempotent: a successful response is
51
+ * returned even when no row matched.
52
+ */
53
+ export const CellFieldDeleteInput = z.strictObject({
54
+ source_id: Uuid.meta({ description: 'Cell whose field to delete.' }),
55
+ name: CellFieldName.meta({ description: 'Field name to delete.' }),
56
+ acting: ActingActor,
57
+ });
58
+ export const CellFieldDeleteOutput = z.strictObject({
59
+ ok: z.literal(true),
60
+ deleted: z.boolean(),
61
+ });
62
+ // -- cell_field_list --------------------------------------------------------
63
+ /**
64
+ * Input for `cell_field_list`. Pass `source_id` for forward fields or
65
+ * `target_id` for reverse upfields — exactly one (the schema rejects
66
+ * both / neither). Reverse listing has 2-layer authz (target view-check
67
+ * gates the call; per-source view-check filters the rows).
68
+ *
69
+ * Forward listing supports cursor pagination via `name_after` (return
70
+ * rows whose `name > name_after` lex). The reverse listing doesn't
71
+ * paginate (the result set is small in practice — number of sources
72
+ * pointing at a given target).
73
+ */
74
+ export const CellFieldListInput = z
75
+ .strictObject({
76
+ source_id: Uuid.optional().meta({
77
+ description: 'List forward fields whose source is this cell.',
78
+ }),
79
+ target_id: Uuid.optional().meta({
80
+ description: 'List reverse upfields whose target is this cell.',
81
+ }),
82
+ name_after: CellFieldName.optional().meta({
83
+ description: 'Cursor for forward pagination — return rows whose name > this lex. Forward only.',
84
+ }),
85
+ limit: z.number().int().positive().max(500).optional().meta({
86
+ description: 'Page size cap (max 500). Forward only. Omit for unbounded — explicit list calls escape the bundled `cell_get` cap.',
87
+ }),
88
+ acting: ActingActor,
89
+ })
90
+ .refine((v) => Boolean(v.source_id) !== Boolean(v.target_id), {
91
+ message: ERROR_CELL_FIELD_LIST_REQUIRES_SOURCE_OR_TARGET,
92
+ });
93
+ export const CellFieldListOutput = z.strictObject({
94
+ fields: z.array(FieldJson),
95
+ });
96
+ // -- Action specs -----------------------------------------------------------
97
+ export const cell_field_set_action_spec = {
98
+ method: 'cell_field_set',
99
+ kind: 'request_response',
100
+ initiator: 'frontend',
101
+ auth: { account: 'required', actor: 'required' },
102
+ side_effects: true,
103
+ input: CellFieldSetInput,
104
+ output: CellFieldSetOutput,
105
+ async: true,
106
+ description: 'Set a named relation `(source.name) → target`. UPSERT on `(source_id, name)`: re-pointing replaces in place. Caller must be able to edit `source` and view `target`; both gate via `can_edit_cell` / `can_view_cell`.',
107
+ };
108
+ export const cell_field_delete_action_spec = {
109
+ method: 'cell_field_delete',
110
+ kind: 'request_response',
111
+ initiator: 'frontend',
112
+ auth: { account: 'required', actor: 'required' },
113
+ side_effects: true,
114
+ input: CellFieldDeleteInput,
115
+ output: CellFieldDeleteOutput,
116
+ async: true,
117
+ description: 'Delete a named relation. Idempotent — `deleted: false` when no row matched. Caller must be able to edit `source`.',
118
+ };
119
+ export const cell_field_list_action_spec = {
120
+ method: 'cell_field_list',
121
+ kind: 'request_response',
122
+ initiator: 'frontend',
123
+ auth: { account: 'optional', actor: 'optional' },
124
+ side_effects: false,
125
+ input: CellFieldListInput,
126
+ output: CellFieldListOutput,
127
+ async: true,
128
+ rate_limit: 'ip',
129
+ description: 'List forward fields (pass `source_id`) or reverse upfields (pass `target_id`). Forward listing filters targets to those the caller may view (strict target-visibility). Reverse listing has 2-layer authz: gate on `can_view_cell(target)` first (404 otherwise), then filter rows by per-source `can_view_cell`. Per-IP rate-limited — symmetric with `cell_get` to bound public-surface id-walking.',
130
+ };
131
+ /** All cell_field action specs — composed into `all_cell_action_specs`. */
132
+ export const all_cell_field_action_specs = [
133
+ cell_field_set_action_spec,
134
+ cell_field_delete_action_spec,
135
+ cell_field_list_action_spec,
136
+ ];
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Cell-field RPC handlers.
3
+ *
4
+ * Three `request_response` actions bound to the specs in
5
+ * `./cell_field_action_specs.ts`:
6
+ *
7
+ * - `cell_field_set` — admin / owner / editor-grant on `source` may set;
8
+ * `target` must be view-admitted (so a caller can't link to a cell they
9
+ * couldn't otherwise see). Idempotent UPSERT on `(source_id, name)`.
10
+ * - `cell_field_delete` — admin / owner / editor-grant on `source`.
11
+ * Idempotent: `deleted: false` when no row matched.
12
+ * - `cell_field_list` — bidirectional. Forward (pass `source_id`) is
13
+ * gated on `can_view_cell(source)` and filters targets to those the
14
+ * caller may view (strict target-visibility, batched). Reverse (pass
15
+ * `target_id`) has 2-layer authz: gate on `can_view_cell(target)`
16
+ * first, then filter rows by `can_view_cell(source)`.
17
+ *
18
+ * IDOR-mask 404s on cell-miss / cell-unviewable, mirroring the existence-
19
+ * leak guards in `cell_actions.ts` / `cell_grant_actions.ts`.
20
+ *
21
+ * Audit events `cell_field_set` / `cell_field_delete` carry IDs only —
22
+ * see `./cell_field_audit_metadata.ts`.
23
+ *
24
+ * @module
25
+ */
26
+ import { type RpcAction } from '../actions/action_rpc.js';
27
+ import type { RouteFactoryDeps } from './deps.js';
28
+ import { type FieldJson } from './cell_field_action_specs.js';
29
+ import { type CellFieldRow } from '../db/cell_field_queries.js';
30
+ export type CellFieldActionDeps = Pick<RouteFactoryDeps, 'log' | 'audit'>;
31
+ export declare const to_field_json: (row: CellFieldRow) => FieldJson;
32
+ /** Create the three `cell_field_*` RPC actions. */
33
+ export declare const create_cell_field_actions: (deps: CellFieldActionDeps) => Array<RpcAction>;
34
+ //# sourceMappingURL=cell_field_actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_field_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_field_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAEhD,OAAO,EAUN,KAAK,SAAS,EACd,MAAM,8BAA8B,CAAC;AAMtC,OAAO,EAKN,KAAK,YAAY,EACjB,MAAM,6BAA6B,CAAC;AAMrC,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC;AAE1E,eAAO,MAAM,aAAa,GAAI,KAAK,YAAY,KAAG,SAKhD,CAAC;AAEH,mDAAmD;AACnD,eAAO,MAAM,yBAAyB,GAAI,MAAM,mBAAmB,KAAG,KAAK,CAAC,SAAS,CAmIpF,CAAC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Cell-field RPC handlers.
3
+ *
4
+ * Three `request_response` actions bound to the specs in
5
+ * `./cell_field_action_specs.ts`:
6
+ *
7
+ * - `cell_field_set` — admin / owner / editor-grant on `source` may set;
8
+ * `target` must be view-admitted (so a caller can't link to a cell they
9
+ * couldn't otherwise see). Idempotent UPSERT on `(source_id, name)`.
10
+ * - `cell_field_delete` — admin / owner / editor-grant on `source`.
11
+ * Idempotent: `deleted: false` when no row matched.
12
+ * - `cell_field_list` — bidirectional. Forward (pass `source_id`) is
13
+ * gated on `can_view_cell(source)` and filters targets to those the
14
+ * caller may view (strict target-visibility, batched). Reverse (pass
15
+ * `target_id`) has 2-layer authz: gate on `can_view_cell(target)`
16
+ * first, then filter rows by `can_view_cell(source)`.
17
+ *
18
+ * IDOR-mask 404s on cell-miss / cell-unviewable, mirroring the existence-
19
+ * leak guards in `cell_actions.ts` / `cell_grant_actions.ts`.
20
+ *
21
+ * Audit events `cell_field_set` / `cell_field_delete` carry IDs only —
22
+ * see `./cell_field_audit_metadata.ts`.
23
+ *
24
+ * @module
25
+ */
26
+ import { rpc_action, } from '../actions/action_rpc.js';
27
+ import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
28
+ import { cell_field_set_action_spec, cell_field_delete_action_spec, cell_field_list_action_spec, } from './cell_field_action_specs.js';
29
+ import { ERROR_CELL_NOT_FOUND } from './cell_action_specs.js';
30
+ import { can_view_cell, can_edit_cell } from './cell_authorize.js';
31
+ import { filter_visible_target_ids } from './cell_relation_visibility.js';
32
+ import { query_cell_get } from '../db/cell_queries.js';
33
+ import { query_cell_grant_list_for_cell } from '../db/cell_grant_queries.js';
34
+ import { query_cell_field_set, query_cell_field_delete, query_cell_field_list_for_source, query_cell_field_list_for_target, } from '../db/cell_field_queries.js';
35
+ export const to_field_json = (row) => ({
36
+ source_id: row.source_id,
37
+ name: row.name,
38
+ target_id: row.target_id,
39
+ created_at: typeof row.created_at === 'string' ? row.created_at : row.created_at.toISOString(),
40
+ });
41
+ /** Create the three `cell_field_*` RPC actions. */
42
+ export const create_cell_field_actions = (deps) => {
43
+ const set_handler = async (input, ctx) => {
44
+ const auth = ctx.auth;
45
+ const source = await query_cell_get(ctx, input.source_id);
46
+ if (!source) {
47
+ // IDOR mask: same code as cell_get's miss/unviewable.
48
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
49
+ }
50
+ const source_grants = await query_cell_grant_list_for_cell(ctx, source.id);
51
+ if (!can_edit_cell(auth, source, source_grants)) {
52
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
53
+ }
54
+ const target = await query_cell_get(ctx, input.target_id);
55
+ if (!target) {
56
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
57
+ }
58
+ // Target must be view-admitted — otherwise a caller could probe for
59
+ // the existence of private cells by trying to point a field at them
60
+ // (and observe whether the call 404s vs. succeeds).
61
+ const target_grants = await query_cell_grant_list_for_cell(ctx, target.id);
62
+ if (!can_view_cell(auth, target, target_grants)) {
63
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
64
+ }
65
+ const row = await query_cell_field_set(ctx, {
66
+ source_id: input.source_id,
67
+ name: input.name,
68
+ target_id: input.target_id,
69
+ });
70
+ deps.audit.emit(ctx, {
71
+ event_type: 'cell_field_set',
72
+ actor_id: auth.actor.id,
73
+ account_id: auth.account.id,
74
+ ip: ctx.client_ip,
75
+ metadata: {
76
+ source_id: row.source_id,
77
+ name: row.name,
78
+ target_id: row.target_id,
79
+ },
80
+ });
81
+ return { field: to_field_json(row) };
82
+ };
83
+ const delete_handler = async (input, ctx) => {
84
+ const auth = ctx.auth;
85
+ const source = await query_cell_get(ctx, input.source_id);
86
+ if (!source) {
87
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
88
+ }
89
+ const source_grants = await query_cell_grant_list_for_cell(ctx, source.id);
90
+ if (!can_edit_cell(auth, source, source_grants)) {
91
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
92
+ }
93
+ const deleted = await query_cell_field_delete(ctx, input.source_id, input.name);
94
+ if (deleted) {
95
+ deps.audit.emit(ctx, {
96
+ event_type: 'cell_field_delete',
97
+ actor_id: auth.actor.id,
98
+ account_id: auth.account.id,
99
+ ip: ctx.client_ip,
100
+ metadata: {
101
+ source_id: deleted.source_id,
102
+ name: deleted.name,
103
+ target_id: deleted.target_id,
104
+ },
105
+ });
106
+ }
107
+ return { ok: true, deleted: deleted !== null };
108
+ };
109
+ const list_handler = async (input, ctx) => {
110
+ const auth = ctx.auth;
111
+ // Forward listing: gate on can_view_cell(source), then filter the
112
+ // targets to those the caller may view (strict target-visibility).
113
+ if (input.source_id !== undefined) {
114
+ const source = await query_cell_get(ctx, input.source_id);
115
+ if (!source) {
116
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
117
+ }
118
+ const source_grants = auth ? await query_cell_grant_list_for_cell(ctx, source.id) : null;
119
+ if (!can_view_cell(auth, source, source_grants)) {
120
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
121
+ }
122
+ const rows = await query_cell_field_list_for_source(ctx, source.id, {
123
+ limit: input.limit,
124
+ name_after: input.name_after,
125
+ });
126
+ const visible_targets = await filter_visible_target_ids(ctx, auth, rows.map((r) => r.target_id));
127
+ return { fields: rows.filter((r) => visible_targets.has(r.target_id)).map(to_field_json) };
128
+ }
129
+ // Reverse listing: 2-layer authz. First, can_view_cell(target).
130
+ // Without this, the count of returned rows leaks "at least N
131
+ // viewable cells link to this private target."
132
+ const target = await query_cell_get(ctx, input.target_id);
133
+ if (!target) {
134
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
135
+ }
136
+ const target_grants = auth ? await query_cell_grant_list_for_cell(ctx, target.id) : null;
137
+ if (!can_view_cell(auth, target, target_grants)) {
138
+ throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
139
+ }
140
+ // Then filter rows by per-source can_view_cell. Batched (not N+1):
141
+ // one bulk visibility filter over all source ids, same as the forward
142
+ // branch. Bounded by `limit` at the query so a heavily inbound-linked
143
+ // target can't force an unbounded fetch on this public endpoint.
144
+ const rows = await query_cell_field_list_for_target(ctx, target.id, { limit: input.limit });
145
+ const visible_sources = await filter_visible_target_ids(ctx, auth, rows.map((r) => r.source_id));
146
+ return { fields: rows.filter((r) => visible_sources.has(r.source_id)).map(to_field_json) };
147
+ };
148
+ return [
149
+ rpc_action(cell_field_set_action_spec, set_handler),
150
+ rpc_action(cell_field_delete_action_spec, delete_handler),
151
+ rpc_action(cell_field_list_action_spec, list_handler),
152
+ ];
153
+ };
@@ -0,0 +1,30 @@
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
+ /**
12
+ * Metadata envelope for `cell_field_set`. Emitted on every successful
13
+ * create OR update path (UPSERT on `(source_id, name)`); the audit
14
+ * reader correlates create-vs-update via repeated `(source_id, name)`
15
+ * if needed.
16
+ */
17
+ export declare const CellFieldSetAuditMetadata: z.ZodObject<{
18
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
19
+ name: z.ZodString;
20
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
21
+ }, z.core.$loose>;
22
+ export type CellFieldSetAuditMetadata = z.infer<typeof CellFieldSetAuditMetadata>;
23
+ /** Metadata envelope for `cell_field_delete`. */
24
+ export declare const CellFieldDeleteAuditMetadata: z.ZodObject<{
25
+ source_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
26
+ name: z.ZodString;
27
+ target_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
28
+ }, z.core.$loose>;
29
+ export type CellFieldDeleteAuditMetadata = z.infer<typeof CellFieldDeleteAuditMetadata>;
30
+ //# sourceMappingURL=cell_field_audit_metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_field_audit_metadata.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_field_audit_metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;iBAIpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,iDAAiD;AACjD,eAAO,MAAM,4BAA4B;;;;iBAIvC,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC"}