@haverstack/core 0.41.0 → 0.43.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 (317) hide show
  1. package/README.md +124 -64
  2. package/dist/access.d.ts +43 -47
  3. package/dist/access.d.ts.map +1 -1
  4. package/dist/access.js +66 -101
  5. package/dist/access.js.map +1 -1
  6. package/dist/{combine.d.ts → adapter/combine.d.ts} +8 -1
  7. package/dist/adapter/combine.d.ts.map +1 -0
  8. package/dist/{combine.js → adapter/combine.js} +18 -3
  9. package/dist/adapter/combine.js.map +1 -0
  10. package/dist/adapter/index.d.ts +19 -0
  11. package/dist/adapter/index.d.ts.map +1 -0
  12. package/dist/adapter/index.js +16 -0
  13. package/dist/adapter/index.js.map +1 -0
  14. package/dist/adapter/reach.d.ts +14 -0
  15. package/dist/adapter/reach.d.ts.map +1 -0
  16. package/dist/adapter/reach.js +31 -0
  17. package/dist/adapter/reach.js.map +1 -0
  18. package/dist/{sort.d.ts → adapter/sort.d.ts} +20 -20
  19. package/dist/adapter/sort.d.ts.map +1 -0
  20. package/dist/{sort.js → adapter/sort.js} +37 -27
  21. package/dist/adapter/sort.js.map +1 -0
  22. package/dist/associations/identity.d.ts +69 -0
  23. package/dist/associations/identity.d.ts.map +1 -0
  24. package/dist/associations/identity.js +174 -0
  25. package/dist/associations/identity.js.map +1 -0
  26. package/dist/associations/validation.d.ts +83 -0
  27. package/dist/associations/validation.d.ts.map +1 -0
  28. package/dist/associations/validation.js +312 -0
  29. package/dist/associations/validation.js.map +1 -0
  30. package/dist/attachment-records.d.ts +48 -0
  31. package/dist/attachment-records.d.ts.map +1 -0
  32. package/dist/attachment-records.js +52 -0
  33. package/dist/attachment-records.js.map +1 -0
  34. package/dist/collection.d.ts +178 -0
  35. package/dist/collection.d.ts.map +1 -0
  36. package/dist/collection.js +397 -0
  37. package/dist/collection.js.map +1 -0
  38. package/dist/content-match.d.ts +25 -0
  39. package/dist/content-match.d.ts.map +1 -0
  40. package/dist/content-match.js +51 -0
  41. package/dist/content-match.js.map +1 -0
  42. package/dist/content-translation.d.ts +42 -0
  43. package/dist/content-translation.d.ts.map +1 -0
  44. package/dist/content-translation.js +108 -0
  45. package/dist/content-translation.js.map +1 -0
  46. package/dist/did/did.d.ts.map +1 -0
  47. package/dist/{did.js → did/did.js} +3 -4
  48. package/dist/did/did.js.map +1 -0
  49. package/dist/{did-entry.d.ts → did/index.d.ts} +1 -1
  50. package/dist/did/index.d.ts.map +1 -0
  51. package/dist/{did-entry.js → did/index.js} +3 -3
  52. package/dist/did/index.js.map +1 -0
  53. package/dist/errors.d.ts +54 -66
  54. package/dist/errors.d.ts.map +1 -1
  55. package/dist/errors.js +58 -62
  56. package/dist/errors.js.map +1 -1
  57. package/dist/grants.d.ts +20 -44
  58. package/dist/grants.d.ts.map +1 -1
  59. package/dist/grants.js +69 -151
  60. package/dist/grants.js.map +1 -1
  61. package/dist/id.d.ts +13 -31
  62. package/dist/id.d.ts.map +1 -1
  63. package/dist/id.js +13 -31
  64. package/dist/id.js.map +1 -1
  65. package/dist/index.d.ts +13 -9
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +9 -6
  68. package/dist/index.js.map +1 -1
  69. package/dist/install.d.ts +3 -6
  70. package/dist/install.d.ts.map +1 -1
  71. package/dist/install.js +6 -10
  72. package/dist/install.js.map +1 -1
  73. package/dist/lazy.d.ts +13 -0
  74. package/dist/lazy.d.ts.map +1 -0
  75. package/dist/lazy.js +27 -0
  76. package/dist/lazy.js.map +1 -0
  77. package/dist/merge.d.ts +1 -1
  78. package/dist/merge.d.ts.map +1 -1
  79. package/dist/merge.js +6 -12
  80. package/dist/merge.js.map +1 -1
  81. package/dist/migration-steps.d.ts +102 -0
  82. package/dist/migration-steps.d.ts.map +1 -0
  83. package/dist/migration-steps.js +293 -0
  84. package/dist/migration-steps.js.map +1 -0
  85. package/dist/query-validation.d.ts +68 -121
  86. package/dist/query-validation.d.ts.map +1 -1
  87. package/dist/query-validation.js +214 -380
  88. package/dist/query-validation.js.map +1 -1
  89. package/dist/record-changes.d.ts +11 -150
  90. package/dist/record-changes.d.ts.map +1 -1
  91. package/dist/record-changes.js +14 -305
  92. package/dist/record-changes.js.map +1 -1
  93. package/dist/schema.d.ts +18 -7
  94. package/dist/schema.d.ts.map +1 -1
  95. package/dist/schema.js +59 -30
  96. package/dist/schema.js.map +1 -1
  97. package/dist/scoped-stack/authority-snapshot.d.ts +37 -0
  98. package/dist/scoped-stack/authority-snapshot.d.ts.map +1 -0
  99. package/dist/scoped-stack/authority-snapshot.js +49 -0
  100. package/dist/scoped-stack/authority-snapshot.js.map +1 -0
  101. package/dist/scoped-stack/authority.d.ts +169 -0
  102. package/dist/scoped-stack/authority.d.ts.map +1 -0
  103. package/dist/scoped-stack/authority.js +408 -0
  104. package/dist/scoped-stack/authority.js.map +1 -0
  105. package/dist/scoped-stack/family-policy.d.ts +59 -0
  106. package/dist/scoped-stack/family-policy.d.ts.map +1 -0
  107. package/dist/scoped-stack/family-policy.js +68 -0
  108. package/dist/scoped-stack/family-policy.js.map +1 -0
  109. package/dist/scoped-stack/scoped-stack.d.ts +318 -0
  110. package/dist/scoped-stack/scoped-stack.d.ts.map +1 -0
  111. package/dist/scoped-stack/scoped-stack.js +695 -0
  112. package/dist/scoped-stack/scoped-stack.js.map +1 -0
  113. package/dist/scoped-stack/subscription.d.ts +36 -0
  114. package/dist/scoped-stack/subscription.d.ts.map +1 -0
  115. package/dist/scoped-stack/subscription.js +69 -0
  116. package/dist/scoped-stack/subscription.js.map +1 -0
  117. package/dist/stack/arguments.d.ts +27 -0
  118. package/dist/stack/arguments.d.ts.map +1 -0
  119. package/dist/stack/arguments.js +53 -0
  120. package/dist/stack/arguments.js.map +1 -0
  121. package/dist/stack/attachments.d.ts +24 -0
  122. package/dist/stack/attachments.d.ts.map +1 -0
  123. package/dist/stack/attachments.js +113 -0
  124. package/dist/stack/attachments.js.map +1 -0
  125. package/dist/{changes.d.ts → stack/changes.d.ts} +30 -72
  126. package/dist/stack/changes.d.ts.map +1 -0
  127. package/dist/{changes.js → stack/changes.js} +40 -74
  128. package/dist/stack/changes.js.map +1 -0
  129. package/dist/stack/client.d.ts +247 -0
  130. package/dist/stack/client.d.ts.map +1 -0
  131. package/dist/stack/client.js +9 -0
  132. package/dist/stack/client.js.map +1 -0
  133. package/dist/stack/identity-bindings.d.ts.map +1 -0
  134. package/dist/{identity-bindings.js → stack/identity-bindings.js} +5 -14
  135. package/dist/stack/identity-bindings.js.map +1 -0
  136. package/dist/stack/install-app.d.ts +22 -0
  137. package/dist/stack/install-app.d.ts.map +1 -0
  138. package/dist/stack/install-app.js +262 -0
  139. package/dist/stack/install-app.js.map +1 -0
  140. package/dist/stack/integrity.d.ts +94 -0
  141. package/dist/stack/integrity.d.ts.map +1 -0
  142. package/dist/stack/integrity.js +268 -0
  143. package/dist/stack/integrity.js.map +1 -0
  144. package/dist/{limits.d.ts → stack/limits.d.ts} +2 -5
  145. package/dist/stack/limits.d.ts.map +1 -0
  146. package/dist/{limits.js → stack/limits.js} +3 -6
  147. package/dist/stack/limits.js.map +1 -0
  148. package/dist/stack/migrations.d.ts +59 -0
  149. package/dist/stack/migrations.d.ts.map +1 -0
  150. package/dist/stack/migrations.js +141 -0
  151. package/dist/stack/migrations.js.map +1 -0
  152. package/dist/stack/reads.d.ts +69 -0
  153. package/dist/stack/reads.d.ts.map +1 -0
  154. package/dist/stack/reads.js +141 -0
  155. package/dist/stack/reads.js.map +1 -0
  156. package/dist/stack/record-id.d.ts +35 -0
  157. package/dist/stack/record-id.d.ts.map +1 -0
  158. package/dist/stack/record-id.js +82 -0
  159. package/dist/stack/record-id.js.map +1 -0
  160. package/dist/stack/stack.d.ts +444 -0
  161. package/dist/stack/stack.d.ts.map +1 -0
  162. package/dist/stack/stack.js +1339 -0
  163. package/dist/stack/stack.js.map +1 -0
  164. package/dist/stack/system-types.d.ts +16 -0
  165. package/dist/stack/system-types.d.ts.map +1 -0
  166. package/dist/stack/system-types.js +111 -0
  167. package/dist/stack/system-types.js.map +1 -0
  168. package/dist/stack/type-grants.d.ts +20 -0
  169. package/dist/stack/type-grants.d.ts.map +1 -0
  170. package/dist/stack/type-grants.js +69 -0
  171. package/dist/stack/type-grants.js.map +1 -0
  172. package/dist/stack/write-expectation.d.ts +79 -0
  173. package/dist/stack/write-expectation.d.ts.map +1 -0
  174. package/dist/stack/write-expectation.js +71 -0
  175. package/dist/stack/write-expectation.js.map +1 -0
  176. package/dist/stack/write-gate.d.ts +23 -0
  177. package/dist/stack/write-gate.d.ts.map +1 -0
  178. package/dist/stack/write-gate.js +17 -0
  179. package/dist/stack/write-gate.js.map +1 -0
  180. package/dist/testing.d.ts +44 -33
  181. package/dist/testing.d.ts.map +1 -1
  182. package/dist/testing.js +180 -176
  183. package/dist/testing.js.map +1 -1
  184. package/dist/type-handle.d.ts +67 -78
  185. package/dist/type-handle.d.ts.map +1 -1
  186. package/dist/type-handle.js +44 -111
  187. package/dist/type-handle.js.map +1 -1
  188. package/dist/types/adapter.d.ts +282 -0
  189. package/dist/types/adapter.d.ts.map +1 -0
  190. package/dist/types/adapter.js +5 -0
  191. package/dist/types/adapter.js.map +1 -0
  192. package/dist/types/associations.d.ts +140 -0
  193. package/dist/types/associations.d.ts.map +1 -0
  194. package/dist/types/associations.js +6 -0
  195. package/dist/types/associations.js.map +1 -0
  196. package/dist/types/capabilities.d.ts +89 -0
  197. package/dist/types/capabilities.d.ts.map +1 -0
  198. package/dist/types/capabilities.js +5 -0
  199. package/dist/types/capabilities.js.map +1 -0
  200. package/dist/types/events.d.ts +150 -0
  201. package/dist/types/events.d.ts.map +1 -0
  202. package/dist/types/events.js +5 -0
  203. package/dist/types/events.js.map +1 -0
  204. package/dist/types/ids.d.ts +43 -0
  205. package/dist/types/ids.d.ts.map +1 -0
  206. package/dist/types/ids.js +5 -0
  207. package/dist/types/ids.js.map +1 -0
  208. package/dist/types/index.d.ts +19 -0
  209. package/dist/types/index.d.ts.map +1 -0
  210. package/dist/types/index.js +19 -0
  211. package/dist/types/index.js.map +1 -0
  212. package/dist/types/journal.d.ts +47 -0
  213. package/dist/types/journal.d.ts.map +1 -0
  214. package/dist/types/journal.js +5 -0
  215. package/dist/types/journal.js.map +1 -0
  216. package/dist/types/query.d.ts +185 -0
  217. package/dist/types/query.d.ts.map +1 -0
  218. package/dist/types/query.js +10 -0
  219. package/dist/types/query.js.map +1 -0
  220. package/dist/types/records.d.ts +76 -0
  221. package/dist/types/records.d.ts.map +1 -0
  222. package/dist/types/records.js +5 -0
  223. package/dist/types/records.js.map +1 -0
  224. package/dist/types/schema.d.ts +74 -0
  225. package/dist/types/schema.d.ts.map +1 -0
  226. package/dist/types/schema.js +5 -0
  227. package/dist/types/schema.js.map +1 -0
  228. package/dist/types/system.d.ts +161 -0
  229. package/dist/types/system.d.ts.map +1 -0
  230. package/dist/types/system.js +32 -0
  231. package/dist/types/system.js.map +1 -0
  232. package/dist/types/tokens.d.ts +39 -0
  233. package/dist/types/tokens.d.ts.map +1 -0
  234. package/dist/types/tokens.js +5 -0
  235. package/dist/types/tokens.js.map +1 -0
  236. package/dist/validate.d.ts +31 -70
  237. package/dist/validate.d.ts.map +1 -1
  238. package/dist/validate.js +52 -92
  239. package/dist/validate.js.map +1 -1
  240. package/dist/{attachment-download.d.ts → wire/attachment-download.d.ts} +0 -57
  241. package/dist/wire/attachment-download.d.ts.map +1 -0
  242. package/dist/{attachment-download.js → wire/attachment-download.js} +0 -61
  243. package/dist/wire/attachment-download.js.map +1 -0
  244. package/dist/{auth.d.ts → wire/auth.d.ts} +5 -8
  245. package/dist/wire/auth.d.ts.map +1 -0
  246. package/dist/{auth.js → wire/auth.js} +5 -8
  247. package/dist/wire/auth.js.map +1 -0
  248. package/dist/{wire-body.d.ts → wire/body.d.ts} +35 -12
  249. package/dist/wire/body.d.ts.map +1 -0
  250. package/dist/{wire-body.js → wire/body.js} +74 -13
  251. package/dist/wire/body.js.map +1 -0
  252. package/dist/{wire-entry.d.ts → wire/index.d.ts} +12 -12
  253. package/dist/wire/index.d.ts.map +1 -0
  254. package/dist/{wire-entry.js → wire/index.js} +13 -17
  255. package/dist/wire/index.js.map +1 -0
  256. package/dist/wire/record.d.ts +31 -0
  257. package/dist/wire/record.d.ts.map +1 -0
  258. package/dist/{wire-record.js → wire/record.js} +7 -67
  259. package/dist/wire/record.js.map +1 -0
  260. package/dist/{wire-request.d.ts → wire/request.d.ts} +32 -49
  261. package/dist/wire/request.d.ts.map +1 -0
  262. package/dist/{wire-request.js → wire/request.js} +113 -83
  263. package/dist/wire/request.js.map +1 -0
  264. package/package.json +7 -7
  265. package/dist/adapter-entry.d.ts +0 -16
  266. package/dist/adapter-entry.d.ts.map +0 -1
  267. package/dist/adapter-entry.js +0 -14
  268. package/dist/adapter-entry.js.map +0 -1
  269. package/dist/attachment-download.d.ts.map +0 -1
  270. package/dist/attachment-download.js.map +0 -1
  271. package/dist/auth.d.ts.map +0 -1
  272. package/dist/auth.js.map +0 -1
  273. package/dist/changes.d.ts.map +0 -1
  274. package/dist/changes.js.map +0 -1
  275. package/dist/combine.d.ts.map +0 -1
  276. package/dist/combine.js.map +0 -1
  277. package/dist/did-entry.d.ts.map +0 -1
  278. package/dist/did-entry.js.map +0 -1
  279. package/dist/did.d.ts.map +0 -1
  280. package/dist/did.js.map +0 -1
  281. package/dist/identity-bindings.d.ts.map +0 -1
  282. package/dist/identity-bindings.js.map +0 -1
  283. package/dist/limits.d.ts.map +0 -1
  284. package/dist/limits.js.map +0 -1
  285. package/dist/record-id.d.ts +0 -70
  286. package/dist/record-id.d.ts.map +0 -1
  287. package/dist/record-id.js +0 -127
  288. package/dist/record-id.js.map +0 -1
  289. package/dist/scoped-stack.d.ts +0 -549
  290. package/dist/scoped-stack.d.ts.map +0 -1
  291. package/dist/scoped-stack.js +0 -1301
  292. package/dist/scoped-stack.js.map +0 -1
  293. package/dist/sort.d.ts.map +0 -1
  294. package/dist/sort.js.map +0 -1
  295. package/dist/stack-reads.d.ts +0 -38
  296. package/dist/stack-reads.d.ts.map +0 -1
  297. package/dist/stack-reads.js +0 -79
  298. package/dist/stack-reads.js.map +0 -1
  299. package/dist/stack.d.ts +0 -1032
  300. package/dist/stack.d.ts.map +0 -1
  301. package/dist/stack.js +0 -2337
  302. package/dist/stack.js.map +0 -1
  303. package/dist/types.d.ts +0 -1278
  304. package/dist/types.d.ts.map +0 -1
  305. package/dist/types.js +0 -51
  306. package/dist/types.js.map +0 -1
  307. package/dist/wire-body.d.ts.map +0 -1
  308. package/dist/wire-body.js.map +0 -1
  309. package/dist/wire-entry.d.ts.map +0 -1
  310. package/dist/wire-entry.js.map +0 -1
  311. package/dist/wire-record.d.ts +0 -50
  312. package/dist/wire-record.d.ts.map +0 -1
  313. package/dist/wire-record.js.map +0 -1
  314. package/dist/wire-request.d.ts.map +0 -1
  315. package/dist/wire-request.js.map +0 -1
  316. /package/dist/{did.d.ts → did/did.d.ts} +0 -0
  317. /package/dist/{identity-bindings.d.ts → stack/identity-bindings.d.ts} +0 -0
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Association validation
3
+ * -------------------------------------------------------
4
+ * The rules an association is held to before it is stored: a known kind,
5
+ * only the keys that kind defines, a well-formed target or grantee, the
6
+ * right half of the authority/data partition, and each identity named
7
+ * once. A discriminated union is a compile-time promise, and a server
8
+ * mapping a request body onto one supplies raw JSON no compiler has seen,
9
+ * so the rules live in the invariant layer where no adapter can forget
10
+ * one. See docs/spec/data-model.md § Associations.
11
+ */
12
+ import type { ValidationError } from '../validate.js';
13
+ import type { Association, AssociationEdit, AuthorityAssociation, DataAssociation, GrantGrantee, RelationshipTarget, RelationshipTargetPattern } from '../types/index.js';
14
+ /** Every key each relationship target arm defines. */
15
+ export declare const TARGET_KEYS: Record<RelationshipTarget['kind'], readonly string[]>;
16
+ /** Every key each grantee arm defines, the default tier included. */
17
+ export declare const GRANTEE_KEYS: Record<GrantGrantee['kind'], readonly string[]>;
18
+ /**
19
+ * The keys of `value` its arm does not define. An element carrying one is
20
+ * refused rather than stored: an adapter keeps only the keys it has
21
+ * columns for, so the rest would answer 200 and then vanish.
22
+ * See docs/spec/data-model.md § Associations.
23
+ */
24
+ export declare function unknownKeys(value: object, keys: readonly string[]): string[];
25
+ /** unknownKeys() as a refusal. 400, not 422: the key addresses nothing. */
26
+ export declare function assertKnownKeys(value: object, keys: readonly string[], path: string): void;
27
+ /**
28
+ * Collect what makes a relationship target malformed. Absence is
29
+ * meaningful on `stackUrl` and an external `id` — this stack, and the
30
+ * whole namespace — so every part that names something must be non-empty:
31
+ * an empty string stores and matches as though it were absent.
32
+ * See docs/spec/data-model.md § Relationship targets.
33
+ */
34
+ export declare function targetErrors(target: RelationshipTarget | RelationshipTargetPattern, path: string, opts?: {
35
+ externalIdOptional?: boolean;
36
+ }): ValidationError[];
37
+ /**
38
+ * Reject an association outside the closed set the types promise: a request
39
+ * body is raw JSON, and an unknown target kind would otherwise be stored as
40
+ * a Record in this stack. A key its kind does not define is a 400 at every
41
+ * depth, as on a request body. See docs/spec/data-model.md § Associations.
42
+ */
43
+ export declare function validateAssociation(association: Association, path?: string): ValidationError[];
44
+ /**
45
+ * What makes a grantee malformed, under `path`: first a key its tier does not
46
+ * define — a 400 under `throw`, as on a request body, or collected on a
47
+ * stored `_grant` — then its tier's own fields. `role` has no default to fall
48
+ * back on. `authenticated` is a `_grant` tier alone; `anyRole` admits `'any'`.
49
+ */
50
+ export declare function granteeErrors(grantee: unknown, path: string, opts: {
51
+ unknownKeys: 'throw' | 'collect';
52
+ authenticated?: boolean;
53
+ anyRole?: boolean;
54
+ }): ValidationError[];
55
+ /**
56
+ * Refuse an authority element on the data surface. The two halves share
57
+ * storage but never a call, or an app editing tags could replace an ACL it
58
+ * was never shown. Thrown, not collected: the caller named the wrong
59
+ * surface, and wanted editAccess()/setAccess().
60
+ * See docs/spec/access-control.md § Record-level permissions.
61
+ */
62
+ export declare function assertDataAssociations(associations: readonly Association[], surface: string): asserts associations is DataAssociation[];
63
+ /**
64
+ * The mirror of assertDataAssociations(): the `permissions` surface takes
65
+ * authority kinds alone, so a tag routed through it is refused rather than
66
+ * quietly becoming an ACL entry the `associations` projection never shows.
67
+ */
68
+ export declare function assertAuthorityAssociations(permissions: readonly Association[], surface: string): asserts permissions is AuthorityAssociation[];
69
+ /**
70
+ * Every association in a list, plus the list's own rule: identities are
71
+ * distinct. An adapter keys associations by identity, so a repeat would
72
+ * displace the first and leave which one stands to chance — a caller bug,
73
+ * refused rather than collapsed. See docs/spec/data-model.md § Associations.
74
+ */
75
+ export declare function validateAssociations(associations: Association[] | undefined, path?: string): ValidationError[];
76
+ /**
77
+ * Hold an edit list to the rules every verb shares: non-empty, known `op`s
78
+ * over well-formed associations, one surface, each identity once — removing
79
+ * and adding one identity is as ambiguous as naming it twice. `repoint` is
80
+ * the journal's word, never a request. See docs/spec/data-model.md § Mutations.
81
+ */
82
+ export declare function assertAssociationEdits(changes: unknown, surface: string, half: 'data' | 'authority'): asserts changes is AssociationEdit[];
83
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/associations/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAEV,WAAW,EACX,eAAe,EAEf,oBAAoB,EACpB,eAAe,EAGf,YAAY,EAKZ,kBAAkB,EAClB,yBAAyB,EAE1B,MAAM,mBAAmB,CAAC;AAY3B,sDAAsD;AACtD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAI7E,CAAC;AAgBF,qEAAqE;AACrE,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAIxE,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAE5E;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM1F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,kBAAkB,GAAG,yBAAyB,EACtD,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,eAAe,EAAE,CAyBnB;AAmBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,EACxB,IAAI,SAAgB,GACnB,eAAe,EAAE,CAoBnB;AAmCD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,WAAW,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACrF,eAAe,EAAE,CA+CnB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,SAAS,WAAW,EAAE,EACpC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,IAAI,eAAe,EAAE,CAO3C;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,SAAS,WAAW,EAAE,EACnC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,IAAI,oBAAoB,EAAE,CAO/C;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,WAAW,EAAE,GAAG,SAAS,EACvC,IAAI,SAAiB,GACpB,eAAe,EAAE,CAMnB;AAgBD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GAAG,WAAW,GACzB,OAAO,CAAC,OAAO,IAAI,eAAe,EAAE,CAoCtC"}
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Association validation
3
+ * -------------------------------------------------------
4
+ * The rules an association is held to before it is stored: a known kind,
5
+ * only the keys that kind defines, a well-formed target or grantee, the
6
+ * right half of the authority/data partition, and each identity named
7
+ * once. A discriminated union is a compile-time promise, and a server
8
+ * mapping a request body onto one supplies raw JSON no compiler has seen,
9
+ * so the rules live in the invariant layer where no adapter can forget
10
+ * one. See docs/spec/data-model.md § Associations.
11
+ */
12
+ import { ARGUMENTS_INVALID, StackBadRequestError, StackValidationError } from '../errors.js';
13
+ import { associationEqual, isAuthorityAssociation } from './identity.js';
14
+ /** The identifier spaces a relationship target may name. */
15
+ const TARGET_KINDS = new Set(['record', 'entity', 'external']);
16
+ /**
17
+ * The keys of one arm of a union, listed as an object so the compiler
18
+ * holds the list to the type: a field added to the arm fails to compile
19
+ * here until it is listed.
20
+ */
21
+ const keysOf = (keys) => Object.keys(keys);
22
+ /** Every key each relationship target arm defines. */
23
+ export const TARGET_KEYS = {
24
+ record: keysOf({ kind: true, recordId: true, stackUrl: true }),
25
+ entity: keysOf({ kind: true, entityId: true }),
26
+ external: keysOf({ kind: true, ns: true, id: true }),
27
+ };
28
+ /** Every key each association kind defines. */
29
+ const ASSOCIATION_KEYS = {
30
+ tag: keysOf({ kind: true, label: true }),
31
+ attachment: keysOf({
32
+ kind: true,
33
+ label: true,
34
+ fileId: true,
35
+ attachmentRecordId: true,
36
+ }),
37
+ relationship: keysOf({ kind: true, label: true, target: true }),
38
+ permission: keysOf({ kind: true, label: true, grantee: true }),
39
+ anyone: keysOf({ kind: true, label: true }),
40
+ };
41
+ /** Every key each grantee arm defines, the default tier included. */
42
+ export const GRANTEE_KEYS = {
43
+ entity: keysOf({ kind: true, entityId: true }),
44
+ group: keysOf({ kind: true, groupId: true, role: true }),
45
+ authenticated: keysOf({ kind: true }),
46
+ };
47
+ /**
48
+ * The keys of `value` its arm does not define. An element carrying one is
49
+ * refused rather than stored: an adapter keeps only the keys it has
50
+ * columns for, so the rest would answer 200 and then vanish.
51
+ * See docs/spec/data-model.md § Associations.
52
+ */
53
+ export function unknownKeys(value, keys) {
54
+ return Object.keys(value).filter((key) => !keys.includes(key));
55
+ }
56
+ /** unknownKeys() as a refusal. 400, not 422: the key addresses nothing. */
57
+ export function assertKnownKeys(value, keys, path) {
58
+ const unknown = unknownKeys(value, keys);
59
+ if (unknown.length > 0)
60
+ throw new StackBadRequestError(`Unknown key${unknown.length > 1 ? 's' : ''} in ${path}: ${unknown.join(', ')}`);
61
+ }
62
+ /**
63
+ * Collect what makes a relationship target malformed. Absence is
64
+ * meaningful on `stackUrl` and an external `id` — this stack, and the
65
+ * whole namespace — so every part that names something must be non-empty:
66
+ * an empty string stores and matches as though it were absent.
67
+ * See docs/spec/data-model.md § Relationship targets.
68
+ */
69
+ export function targetErrors(target, path, opts = {}) {
70
+ const fail = (message) => [{ path, message }];
71
+ if (!target || typeof target !== 'object')
72
+ return fail('A relationship target must be an object.');
73
+ if (!TARGET_KINDS.has(target.kind)) {
74
+ return fail(`Unknown relationship target kind "${target.kind}": expected "record", "entity" or "external".`);
75
+ }
76
+ assertKnownKeys(target, TARGET_KEYS[target.kind], path);
77
+ if (target.kind === 'record') {
78
+ if (!target.recordId)
79
+ return fail('A record target requires a non-empty recordId.');
80
+ if (target.stackUrl !== undefined && !target.stackUrl) {
81
+ return fail("A record target's stackUrl must be non-empty; omit it to name this stack.");
82
+ }
83
+ return [];
84
+ }
85
+ if (target.kind === 'entity') {
86
+ return target.entityId ? [] : fail('An entity target requires a non-empty entityId.');
87
+ }
88
+ if (!target.ns)
89
+ return fail('An external target requires a non-empty ns.');
90
+ if (target.id === undefined) {
91
+ return opts.externalIdOptional ? [] : fail('An external target requires an id.');
92
+ }
93
+ return target.id ? [] : fail("An external target's id must be non-empty when present.");
94
+ }
95
+ /** The kinds an association may name — the closed set every surface reads. */
96
+ const ASSOCIATION_KINDS = new Set(['tag', 'attachment', 'relationship', 'permission', 'anyone']);
97
+ /**
98
+ * Whether a value is an association at all. Asked ahead of the partition
99
+ * checks, so a malformed element is named as one rather than reported as
100
+ * the wrong surface for a kind it never had — a request body supplies raw
101
+ * JSON, and `null` or `{}` is neither half of the partition.
102
+ */
103
+ function namesKind(association) {
104
+ return (!!association &&
105
+ typeof association === 'object' &&
106
+ ASSOCIATION_KINDS.has(association.kind));
107
+ }
108
+ /**
109
+ * Reject an association outside the closed set the types promise: a request
110
+ * body is raw JSON, and an unknown target kind would otherwise be stored as
111
+ * a Record in this stack. A key its kind does not define is a 400 at every
112
+ * depth, as on a request body. See docs/spec/data-model.md § Associations.
113
+ */
114
+ export function validateAssociation(association, path = 'association') {
115
+ if (!namesKind(association)) {
116
+ return [
117
+ {
118
+ path: `${path}.kind`,
119
+ message: `Unknown association kind "${String(association?.kind)}": expected ${[...ASSOCIATION_KINDS].map((k) => `"${k}"`).join(', ')}.`,
120
+ },
121
+ ];
122
+ }
123
+ assertKnownKeys(association, ASSOCIATION_KEYS[association.kind], path);
124
+ if (association.kind === 'permission') {
125
+ return permissionErrors(association, path);
126
+ }
127
+ if (association.kind === 'anyone') {
128
+ return association.label === 'read'
129
+ ? []
130
+ : [{ path: `${path}.label`, message: 'An `anyone` association carries only `read`.' }];
131
+ }
132
+ if (association.kind !== 'relationship')
133
+ return [];
134
+ return targetErrors(association.target, `${path}.target`);
135
+ }
136
+ /**
137
+ * Who a duplicated permission names, since kind and label alone don't
138
+ * distinguish two grants of the same bit to different grantees.
139
+ */
140
+ function granteeSuffix(association) {
141
+ if (association.kind !== 'permission')
142
+ return '';
143
+ const g = association.grantee;
144
+ return g.kind === 'entity' ? ` for "${g.entityId}"` : ` for ${g.role}s of "${g.groupId}"`;
145
+ }
146
+ /** The bits a permission element may name — the whole of its meaning. */
147
+ const PERMISSION_LABELS = new Set(['read', 'write']);
148
+ /** A permission element's label and grantee — see granteeErrors(). */
149
+ function permissionErrors(association, path) {
150
+ if (!PERMISSION_LABELS.has(association.label)) {
151
+ return [
152
+ {
153
+ path: `${path}.label`,
154
+ message: `Unknown permission label "${association.label}": expected "read" or "write".`,
155
+ },
156
+ ];
157
+ }
158
+ const grantee = association.grantee;
159
+ if (!grantee || typeof grantee !== 'object') {
160
+ return [{ path: `${path}.grantee`, message: 'A permission requires a grantee.' }];
161
+ }
162
+ return granteeErrors(grantee, `${path}.grantee`, { unknownKeys: 'throw' });
163
+ }
164
+ /**
165
+ * What makes a grantee malformed, under `path`: first a key its tier does not
166
+ * define — a 400 under `throw`, as on a request body, or collected on a
167
+ * stored `_grant` — then its tier's own fields. `role` has no default to fall
168
+ * back on. `authenticated` is a `_grant` tier alone; `anyRole` admits `'any'`.
169
+ */
170
+ export function granteeErrors(grantee, path, opts) {
171
+ const g = (grantee ?? {});
172
+ const tier = g.kind === 'entity' || g.kind === 'group' || (opts.authenticated && g.kind === 'authenticated')
173
+ ? g.kind
174
+ : null;
175
+ if (tier === null) {
176
+ return [
177
+ {
178
+ path: `${path}.kind`,
179
+ message: opts.authenticated
180
+ ? "A grantee must name its tier: 'entity', 'group' or 'authenticated'."
181
+ : "A grantee must name its tier: 'entity' or 'group'.",
182
+ },
183
+ ];
184
+ }
185
+ if (opts.unknownKeys === 'throw')
186
+ assertKnownKeys(g, GRANTEE_KEYS[tier], path);
187
+ const unknown = unknownKeys(g, GRANTEE_KEYS[tier]);
188
+ if (unknown.length > 0) {
189
+ const article = tier === 'group' ? 'A' : 'An';
190
+ return unknown.map((key) => ({
191
+ path: `${path}.${key}`,
192
+ message: `${article} ${tier} grantee does not carry ${key}.`,
193
+ }));
194
+ }
195
+ if (tier === 'authenticated')
196
+ return [];
197
+ if (tier === 'entity') {
198
+ return typeof g.entityId === 'string' && g.entityId.length > 0
199
+ ? []
200
+ : [{ path: `${path}.entityId`, message: 'An entity grantee requires a non-empty entityId.' }];
201
+ }
202
+ const errors = [];
203
+ if (typeof g.groupId !== 'string' || g.groupId.length === 0) {
204
+ errors.push({
205
+ path: `${path}.groupId`,
206
+ message: 'A group grantee requires a non-empty groupId.',
207
+ });
208
+ }
209
+ if (g.role !== 'member' && g.role !== 'admin' && !(opts.anyRole && g.role === 'any')) {
210
+ errors.push({
211
+ path: `${path}.role`,
212
+ message: opts.anyRole
213
+ ? "A group grantee requires role 'member', 'admin' or 'any'."
214
+ : "A group grantee requires role 'member' or 'admin'.",
215
+ });
216
+ }
217
+ return errors;
218
+ }
219
+ /**
220
+ * Refuse an authority element on the data surface. The two halves share
221
+ * storage but never a call, or an app editing tags could replace an ACL it
222
+ * was never shown. Thrown, not collected: the caller named the wrong
223
+ * surface, and wanted editAccess()/setAccess().
224
+ * See docs/spec/access-control.md § Record-level permissions.
225
+ */
226
+ export function assertDataAssociations(associations, surface) {
227
+ const authority = associations.find((a) => namesKind(a) && isAuthorityAssociation(a));
228
+ if (!authority)
229
+ return;
230
+ throw new StackBadRequestError(`${surface} does not carry authority: a "${authority.kind}" association belongs to the ` +
231
+ '`permissions` surface — use editAccess() or setAccess().');
232
+ }
233
+ /**
234
+ * The mirror of assertDataAssociations(): the `permissions` surface takes
235
+ * authority kinds alone, so a tag routed through it is refused rather than
236
+ * quietly becoming an ACL entry the `associations` projection never shows.
237
+ */
238
+ export function assertAuthorityAssociations(permissions, surface) {
239
+ const data = permissions.find((a) => namesKind(a) && !isAuthorityAssociation(a));
240
+ if (!data)
241
+ return;
242
+ throw new StackBadRequestError(`${surface} carries authority alone: a "${data.kind}" association belongs to the ` +
243
+ '`associations` surface — use editAssociations() or setAssociations().');
244
+ }
245
+ /**
246
+ * Every association in a list, plus the list's own rule: identities are
247
+ * distinct. An adapter keys associations by identity, so a repeat would
248
+ * displace the first and leave which one stands to chance — a caller bug,
249
+ * refused rather than collapsed. See docs/spec/data-model.md § Associations.
250
+ */
251
+ export function validateAssociations(associations, path = 'associations') {
252
+ const list = associations ?? [];
253
+ return [
254
+ ...list.flatMap((a, i) => validateAssociation(a, `${path}[${i}]`)),
255
+ ...duplicateIdentityErrors(list, path),
256
+ ];
257
+ }
258
+ /** Each element naming an identity an earlier element already named. */
259
+ function duplicateIdentityErrors(list, path) {
260
+ return list.flatMap((a, i) => list.slice(0, i).some((b) => associationEqual(a, b))
261
+ ? [
262
+ {
263
+ path: `${path}[${i}]`,
264
+ message: `Duplicate association identity: ${a.kind} "${a.label}"${granteeSuffix(a)} is named more than once.`,
265
+ },
266
+ ]
267
+ : []);
268
+ }
269
+ /**
270
+ * Hold an edit list to the rules every verb shares: non-empty, known `op`s
271
+ * over well-formed associations, one surface, each identity once — removing
272
+ * and adding one identity is as ambiguous as naming it twice. `repoint` is
273
+ * the journal's word, never a request. See docs/spec/data-model.md § Mutations.
274
+ */
275
+ export function assertAssociationEdits(changes, surface, half) {
276
+ if (!Array.isArray(changes) || changes.length === 0) {
277
+ throw new StackValidationError([{ path: 'changes', message: `${surface} names at least one change.` }], ARGUMENTS_INVALID);
278
+ }
279
+ const errors = [];
280
+ changes.forEach((raw, i) => {
281
+ const path = `changes[${i}]`;
282
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
283
+ errors.push({ path, message: `${path} must be an object.` });
284
+ return;
285
+ }
286
+ const edit = raw;
287
+ if (edit.op !== 'repoint')
288
+ assertKnownKeys(edit, ['op', 'association'], path);
289
+ if (edit.op === 'repoint') {
290
+ errors.push({
291
+ path: `${path}.op`,
292
+ message: 'op: "repoint" is recorded by the journal, not requested. ' +
293
+ "Send { op: 'add', association }: an add naming an attachment the record already holds re-points it in place.",
294
+ });
295
+ }
296
+ else if (edit.op !== 'add' && edit.op !== 'remove') {
297
+ errors.push({ path: `${path}.op`, message: 'op must be "add" or "remove".' });
298
+ }
299
+ errors.push(...validateAssociation(edit.association, `${path}.association`));
300
+ });
301
+ if (errors.length > 0)
302
+ throw new StackValidationError(errors, ARGUMENTS_INVALID);
303
+ const associations = changes.map((c) => c.association);
304
+ if (half === 'data')
305
+ assertDataAssociations(associations, surface);
306
+ else
307
+ assertAuthorityAssociations(associations, surface);
308
+ const duplicates = duplicateIdentityErrors(associations, 'changes');
309
+ if (duplicates.length > 0)
310
+ throw new StackValidationError(duplicates, ARGUMENTS_INVALID);
311
+ }
312
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/associations/validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Attachment metadata records
3
+ * -------------------------------------------------------
4
+ * Which of a fileId's `_attachment` records answers for it: the one that
5
+ * establishes its mimeType, and the one a given reference names. Pure and
6
+ * generic over the record shape, so `Stack` and a server's own rows reach
7
+ * the same answer — `@haverstack/core/wire` exports the selections, and
8
+ * this module imports nothing so that entry point stays light.
9
+ */
10
+ /**
11
+ * Which `_attachment@1` record establishes a fileId's mimeType: earliest
12
+ * `createdAt`, ties to the lower `id`. Two racing first uploads can both
13
+ * land, so determinism rests on core's conflict check and every server
14
+ * ordering through here. The caller filters to one fileId.
15
+ * See docs/spec/attachments.md § Finding a `fileId`'s metadata records.
16
+ */
17
+ export declare function firstRecordedAttachment<T extends {
18
+ id: string;
19
+ createdAt: Date;
20
+ }>(records: readonly T[]): T | undefined;
21
+ /**
22
+ * The same total order as a comparator, for a caller handing back the whole
23
+ * candidate set rather than the winner — sorted this way, the winner is
24
+ * element zero. Package-internal: `core/wire` exports the selection,
25
+ * since the ordering is only useful to something that already has every
26
+ * record.
27
+ */
28
+ export declare function compareRecordedAttachments<T extends {
29
+ id: string;
30
+ createdAt: Date;
31
+ }>(a: T, b: T): number;
32
+ /**
33
+ * Which `_attachment` record a *reference* to a fileId names: its
34
+ * `attachmentRecordId`, else the requester's own upload, else the
35
+ * first-recorded — each step falling back rather than failing.
36
+ * See docs/spec/attachments.md § Naming the upload a reference came from.
37
+ */
38
+ export declare function resolveReferencedAttachment<T extends {
39
+ id: string;
40
+ createdAt: Date;
41
+ createdBy?: {
42
+ subjectId: string;
43
+ };
44
+ }>(records: readonly T[], opts?: {
45
+ attachmentRecordId?: string;
46
+ requesterEntityId?: string;
47
+ }): T | undefined;
48
+ //# sourceMappingURL=attachment-records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-records.d.ts","sourceRoot":"","sources":["../src/attachment-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAE,EAC/E,OAAO,EAAE,SAAS,CAAC,EAAE,GACpB,CAAC,GAAG,SAAS,CAKf;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAE,EAClF,CAAC,EAAE,CAAC,EACJ,CAAC,EAAE,CAAC,GACH,MAAM,CAIR;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAE5E,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,IAAI,GAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAO,GACrE,CAAC,GAAG,SAAS,CAUf"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Attachment metadata records
3
+ * -------------------------------------------------------
4
+ * Which of a fileId's `_attachment` records answers for it: the one that
5
+ * establishes its mimeType, and the one a given reference names. Pure and
6
+ * generic over the record shape, so `Stack` and a server's own rows reach
7
+ * the same answer — `@haverstack/core/wire` exports the selections, and
8
+ * this module imports nothing so that entry point stays light.
9
+ */
10
+ /**
11
+ * Which `_attachment@1` record establishes a fileId's mimeType: earliest
12
+ * `createdAt`, ties to the lower `id`. Two racing first uploads can both
13
+ * land, so determinism rests on core's conflict check and every server
14
+ * ordering through here. The caller filters to one fileId.
15
+ * See docs/spec/attachments.md § Finding a `fileId`'s metadata records.
16
+ */
17
+ export function firstRecordedAttachment(records) {
18
+ return records.reduce((first, record) => (!first || compareRecordedAttachments(record, first) < 0 ? record : first), undefined);
19
+ }
20
+ /**
21
+ * The same total order as a comparator, for a caller handing back the whole
22
+ * candidate set rather than the winner — sorted this way, the winner is
23
+ * element zero. Package-internal: `core/wire` exports the selection,
24
+ * since the ordering is only useful to something that already has every
25
+ * record.
26
+ */
27
+ export function compareRecordedAttachments(a, b) {
28
+ const delta = a.createdAt.getTime() - b.createdAt.getTime();
29
+ if (delta !== 0)
30
+ return delta;
31
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
32
+ }
33
+ /**
34
+ * Which `_attachment` record a *reference* to a fileId names: its
35
+ * `attachmentRecordId`, else the requester's own upload, else the
36
+ * first-recorded — each step falling back rather than failing.
37
+ * See docs/spec/attachments.md § Naming the upload a reference came from.
38
+ */
39
+ export function resolveReferencedAttachment(records, opts = {}) {
40
+ if (opts.attachmentRecordId) {
41
+ const named = records.find((record) => record.id === opts.attachmentRecordId);
42
+ if (named)
43
+ return named;
44
+ }
45
+ if (opts.requesterEntityId) {
46
+ const own = records.filter((record) => record.createdBy?.subjectId === opts.requesterEntityId);
47
+ if (own.length > 0)
48
+ return firstRecordedAttachment(own);
49
+ }
50
+ return firstRecordedAttachment(records);
51
+ }
52
+ //# sourceMappingURL=attachment-records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-records.js","sourceRoot":"","sources":["../src/attachment-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAqB;IAErB,OAAO,OAAO,CAAC,MAAM,CACnB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,0BAA0B,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAC7F,SAAS,CACV,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,CAAI,EACJ,CAAI;IAEJ,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IAC5D,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAGzC,OAAqB,EACrB,OAAoE,EAAE;IAEtE,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC9E,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC/F,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC"}