@haverstack/core 0.40.0 → 0.42.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 (287) hide show
  1. package/README.md +121 -59
  2. package/dist/access.d.ts +34 -36
  3. package/dist/access.d.ts.map +1 -1
  4. package/dist/access.js +65 -42
  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} +7 -0
  9. package/dist/adapter/combine.js.map +1 -0
  10. package/dist/{adapter-entry.d.ts → adapter/index.d.ts} +6 -5
  11. package/dist/adapter/index.d.ts.map +1 -0
  12. package/dist/{adapter-entry.js → adapter/index.js} +5 -4
  13. package/dist/adapter/index.js.map +1 -0
  14. package/dist/{sort.d.ts → adapter/sort.d.ts} +20 -20
  15. package/dist/adapter/sort.d.ts.map +1 -0
  16. package/dist/{sort.js → adapter/sort.js} +37 -27
  17. package/dist/adapter/sort.js.map +1 -0
  18. package/dist/associations/identity.d.ts +93 -0
  19. package/dist/associations/identity.d.ts.map +1 -0
  20. package/dist/associations/identity.js +198 -0
  21. package/dist/associations/identity.js.map +1 -0
  22. package/dist/associations/validation.d.ts +90 -0
  23. package/dist/associations/validation.d.ts.map +1 -0
  24. package/dist/associations/validation.js +339 -0
  25. package/dist/associations/validation.js.map +1 -0
  26. package/dist/attachment-records.d.ts +48 -0
  27. package/dist/attachment-records.d.ts.map +1 -0
  28. package/dist/attachment-records.js +52 -0
  29. package/dist/attachment-records.js.map +1 -0
  30. package/dist/collection.d.ts +182 -0
  31. package/dist/collection.d.ts.map +1 -0
  32. package/dist/collection.js +407 -0
  33. package/dist/collection.js.map +1 -0
  34. package/dist/content-match.d.ts +25 -0
  35. package/dist/content-match.d.ts.map +1 -0
  36. package/dist/content-match.js +51 -0
  37. package/dist/content-match.js.map +1 -0
  38. package/dist/content-translation.d.ts +42 -0
  39. package/dist/content-translation.d.ts.map +1 -0
  40. package/dist/content-translation.js +108 -0
  41. package/dist/content-translation.js.map +1 -0
  42. package/dist/did/did.d.ts.map +1 -0
  43. package/dist/{did.js → did/did.js} +3 -4
  44. package/dist/did/did.js.map +1 -0
  45. package/dist/{did-entry.d.ts → did/index.d.ts} +1 -1
  46. package/dist/did/index.d.ts.map +1 -0
  47. package/dist/{did-entry.js → did/index.js} +3 -3
  48. package/dist/did/index.js.map +1 -0
  49. package/dist/errors.d.ts +36 -63
  50. package/dist/errors.d.ts.map +1 -1
  51. package/dist/errors.js +35 -58
  52. package/dist/errors.js.map +1 -1
  53. package/dist/grants.d.ts +20 -43
  54. package/dist/grants.d.ts.map +1 -1
  55. package/dist/grants.js +71 -134
  56. package/dist/grants.js.map +1 -1
  57. package/dist/id.d.ts +13 -31
  58. package/dist/id.d.ts.map +1 -1
  59. package/dist/id.js +13 -31
  60. package/dist/id.js.map +1 -1
  61. package/dist/index.d.ts +14 -8
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +9 -5
  64. package/dist/index.js.map +1 -1
  65. package/dist/install.d.ts +141 -0
  66. package/dist/install.d.ts.map +1 -0
  67. package/dist/install.js +219 -0
  68. package/dist/install.js.map +1 -0
  69. package/dist/merge.d.ts.map +1 -1
  70. package/dist/merge.js +5 -11
  71. package/dist/merge.js.map +1 -1
  72. package/dist/migration-steps.d.ts +102 -0
  73. package/dist/migration-steps.d.ts.map +1 -0
  74. package/dist/migration-steps.js +293 -0
  75. package/dist/migration-steps.js.map +1 -0
  76. package/dist/query-validation.d.ts +28 -94
  77. package/dist/query-validation.d.ts.map +1 -1
  78. package/dist/query-validation.js +156 -336
  79. package/dist/query-validation.js.map +1 -1
  80. package/dist/record-changes.d.ts +2 -117
  81. package/dist/record-changes.d.ts.map +1 -1
  82. package/dist/record-changes.js +10 -212
  83. package/dist/record-changes.js.map +1 -1
  84. package/dist/schema.d.ts +18 -7
  85. package/dist/schema.d.ts.map +1 -1
  86. package/dist/schema.js +59 -30
  87. package/dist/schema.js.map +1 -1
  88. package/dist/scoped-stack/authority.d.ts +156 -0
  89. package/dist/scoped-stack/authority.d.ts.map +1 -0
  90. package/dist/scoped-stack/authority.js +384 -0
  91. package/dist/scoped-stack/authority.js.map +1 -0
  92. package/dist/scoped-stack/scoped-stack.d.ts +338 -0
  93. package/dist/scoped-stack/scoped-stack.d.ts.map +1 -0
  94. package/dist/scoped-stack/scoped-stack.js +776 -0
  95. package/dist/scoped-stack/scoped-stack.js.map +1 -0
  96. package/dist/scoped-stack/subscription.d.ts +55 -0
  97. package/dist/scoped-stack/subscription.d.ts.map +1 -0
  98. package/dist/scoped-stack/subscription.js +110 -0
  99. package/dist/scoped-stack/subscription.js.map +1 -0
  100. package/dist/stack/attachments.d.ts +24 -0
  101. package/dist/stack/attachments.d.ts.map +1 -0
  102. package/dist/stack/attachments.js +113 -0
  103. package/dist/stack/attachments.js.map +1 -0
  104. package/dist/{changes.d.ts → stack/changes.d.ts} +29 -65
  105. package/dist/stack/changes.d.ts.map +1 -0
  106. package/dist/{changes.js → stack/changes.js} +32 -66
  107. package/dist/stack/changes.js.map +1 -0
  108. package/dist/stack/client.d.ts +271 -0
  109. package/dist/stack/client.d.ts.map +1 -0
  110. package/dist/stack/client.js +9 -0
  111. package/dist/stack/client.js.map +1 -0
  112. package/dist/stack/identity-bindings.d.ts.map +1 -0
  113. package/dist/{identity-bindings.js → stack/identity-bindings.js} +8 -14
  114. package/dist/stack/identity-bindings.js.map +1 -0
  115. package/dist/stack/install-app.d.ts +22 -0
  116. package/dist/stack/install-app.d.ts.map +1 -0
  117. package/dist/stack/install-app.js +260 -0
  118. package/dist/stack/install-app.js.map +1 -0
  119. package/dist/stack/integrity.d.ts +94 -0
  120. package/dist/stack/integrity.d.ts.map +1 -0
  121. package/dist/stack/integrity.js +268 -0
  122. package/dist/stack/integrity.js.map +1 -0
  123. package/dist/{limits.d.ts → stack/limits.d.ts} +2 -5
  124. package/dist/stack/limits.d.ts.map +1 -0
  125. package/dist/{limits.js → stack/limits.js} +3 -6
  126. package/dist/stack/limits.js.map +1 -0
  127. package/dist/stack/migrations.d.ts +59 -0
  128. package/dist/stack/migrations.d.ts.map +1 -0
  129. package/dist/stack/migrations.js +141 -0
  130. package/dist/stack/migrations.js.map +1 -0
  131. package/dist/{stack-reads.d.ts → stack/reads.d.ts} +33 -6
  132. package/dist/stack/reads.d.ts.map +1 -0
  133. package/dist/{stack-reads.js → stack/reads.js} +49 -7
  134. package/dist/stack/reads.js.map +1 -0
  135. package/dist/stack/record-id.d.ts +35 -0
  136. package/dist/stack/record-id.d.ts.map +1 -0
  137. package/dist/stack/record-id.js +82 -0
  138. package/dist/stack/record-id.js.map +1 -0
  139. package/dist/stack/stack.d.ts +438 -0
  140. package/dist/stack/stack.d.ts.map +1 -0
  141. package/dist/stack/stack.js +1366 -0
  142. package/dist/stack/stack.js.map +1 -0
  143. package/dist/stack/system-types.d.ts +16 -0
  144. package/dist/stack/system-types.d.ts.map +1 -0
  145. package/dist/stack/system-types.js +111 -0
  146. package/dist/stack/system-types.js.map +1 -0
  147. package/dist/stack/type-grants.d.ts +20 -0
  148. package/dist/stack/type-grants.d.ts.map +1 -0
  149. package/dist/stack/type-grants.js +69 -0
  150. package/dist/stack/type-grants.js.map +1 -0
  151. package/dist/stack/write-expectation.d.ts +78 -0
  152. package/dist/stack/write-expectation.d.ts.map +1 -0
  153. package/dist/stack/write-expectation.js +71 -0
  154. package/dist/stack/write-expectation.js.map +1 -0
  155. package/dist/testing.d.ts +21 -26
  156. package/dist/testing.d.ts.map +1 -1
  157. package/dist/testing.js +50 -70
  158. package/dist/testing.js.map +1 -1
  159. package/dist/type-handle.d.ts +67 -78
  160. package/dist/type-handle.d.ts.map +1 -1
  161. package/dist/type-handle.js +44 -111
  162. package/dist/type-handle.js.map +1 -1
  163. package/dist/types/adapter.d.ts +223 -0
  164. package/dist/types/adapter.d.ts.map +1 -0
  165. package/dist/types/adapter.js +5 -0
  166. package/dist/types/adapter.js.map +1 -0
  167. package/dist/types/associations.d.ts +156 -0
  168. package/dist/types/associations.d.ts.map +1 -0
  169. package/dist/types/associations.js +13 -0
  170. package/dist/types/associations.js.map +1 -0
  171. package/dist/types/capabilities.d.ts +89 -0
  172. package/dist/types/capabilities.d.ts.map +1 -0
  173. package/dist/types/capabilities.js +5 -0
  174. package/dist/types/capabilities.js.map +1 -0
  175. package/dist/types/events.d.ts +155 -0
  176. package/dist/types/events.d.ts.map +1 -0
  177. package/dist/types/events.js +5 -0
  178. package/dist/types/events.js.map +1 -0
  179. package/dist/types/ids.d.ts +43 -0
  180. package/dist/types/ids.d.ts.map +1 -0
  181. package/dist/types/ids.js +5 -0
  182. package/dist/types/ids.js.map +1 -0
  183. package/dist/types/index.d.ts +19 -0
  184. package/dist/types/index.d.ts.map +1 -0
  185. package/dist/types/index.js +19 -0
  186. package/dist/types/index.js.map +1 -0
  187. package/dist/types/journal.d.ts +47 -0
  188. package/dist/types/journal.d.ts.map +1 -0
  189. package/dist/types/journal.js +5 -0
  190. package/dist/types/journal.js.map +1 -0
  191. package/dist/types/query.d.ts +185 -0
  192. package/dist/types/query.d.ts.map +1 -0
  193. package/dist/types/query.js +10 -0
  194. package/dist/types/query.js.map +1 -0
  195. package/dist/types/records.d.ts +76 -0
  196. package/dist/types/records.d.ts.map +1 -0
  197. package/dist/types/records.js +5 -0
  198. package/dist/types/records.js.map +1 -0
  199. package/dist/types/schema.d.ts +74 -0
  200. package/dist/types/schema.d.ts.map +1 -0
  201. package/dist/types/schema.js +5 -0
  202. package/dist/types/schema.js.map +1 -0
  203. package/dist/types/system.d.ts +161 -0
  204. package/dist/types/system.d.ts.map +1 -0
  205. package/dist/types/system.js +32 -0
  206. package/dist/types/system.js.map +1 -0
  207. package/dist/types/tokens.d.ts +39 -0
  208. package/dist/types/tokens.d.ts.map +1 -0
  209. package/dist/types/tokens.js +5 -0
  210. package/dist/types/tokens.js.map +1 -0
  211. package/dist/validate.d.ts +29 -70
  212. package/dist/validate.d.ts.map +1 -1
  213. package/dist/validate.js +65 -97
  214. package/dist/validate.js.map +1 -1
  215. package/dist/{attachment-download.d.ts → wire/attachment-download.d.ts} +0 -57
  216. package/dist/wire/attachment-download.d.ts.map +1 -0
  217. package/dist/{attachment-download.js → wire/attachment-download.js} +0 -61
  218. package/dist/wire/attachment-download.js.map +1 -0
  219. package/dist/{auth.d.ts → wire/auth.d.ts} +5 -8
  220. package/dist/wire/auth.d.ts.map +1 -0
  221. package/dist/{auth.js → wire/auth.js} +5 -8
  222. package/dist/wire/auth.js.map +1 -0
  223. package/dist/{wire-body.d.ts → wire/body.d.ts} +13 -5
  224. package/dist/wire/body.d.ts.map +1 -0
  225. package/dist/{wire-body.js → wire/body.js} +65 -7
  226. package/dist/wire/body.js.map +1 -0
  227. package/dist/{wire-entry.d.ts → wire/index.d.ts} +12 -12
  228. package/dist/wire/index.d.ts.map +1 -0
  229. package/dist/{wire-entry.js → wire/index.js} +13 -17
  230. package/dist/wire/index.js.map +1 -0
  231. package/dist/{wire-record.d.ts → wire/record.d.ts} +10 -22
  232. package/dist/wire/record.d.ts.map +1 -0
  233. package/dist/{wire-record.js → wire/record.js} +12 -24
  234. package/dist/wire/record.js.map +1 -0
  235. package/dist/{wire-request.d.ts → wire/request.d.ts} +20 -37
  236. package/dist/wire/request.d.ts.map +1 -0
  237. package/dist/{wire-request.js → wire/request.js} +79 -54
  238. package/dist/wire/request.js.map +1 -0
  239. package/package.json +7 -7
  240. package/dist/adapter-entry.d.ts.map +0 -1
  241. package/dist/adapter-entry.js.map +0 -1
  242. package/dist/attachment-download.d.ts.map +0 -1
  243. package/dist/attachment-download.js.map +0 -1
  244. package/dist/auth.d.ts.map +0 -1
  245. package/dist/auth.js.map +0 -1
  246. package/dist/changes.d.ts.map +0 -1
  247. package/dist/changes.js.map +0 -1
  248. package/dist/combine.d.ts.map +0 -1
  249. package/dist/combine.js.map +0 -1
  250. package/dist/did-entry.d.ts.map +0 -1
  251. package/dist/did-entry.js.map +0 -1
  252. package/dist/did.d.ts.map +0 -1
  253. package/dist/did.js.map +0 -1
  254. package/dist/identity-bindings.d.ts.map +0 -1
  255. package/dist/identity-bindings.js.map +0 -1
  256. package/dist/limits.d.ts.map +0 -1
  257. package/dist/limits.js.map +0 -1
  258. package/dist/record-id.d.ts +0 -70
  259. package/dist/record-id.d.ts.map +0 -1
  260. package/dist/record-id.js +0 -127
  261. package/dist/record-id.js.map +0 -1
  262. package/dist/scoped-stack.d.ts +0 -532
  263. package/dist/scoped-stack.d.ts.map +0 -1
  264. package/dist/scoped-stack.js +0 -1219
  265. package/dist/scoped-stack.js.map +0 -1
  266. package/dist/sort.d.ts.map +0 -1
  267. package/dist/sort.js.map +0 -1
  268. package/dist/stack-reads.d.ts.map +0 -1
  269. package/dist/stack-reads.js.map +0 -1
  270. package/dist/stack.d.ts +0 -971
  271. package/dist/stack.d.ts.map +0 -1
  272. package/dist/stack.js +0 -2012
  273. package/dist/stack.js.map +0 -1
  274. package/dist/types.d.ts +0 -1250
  275. package/dist/types.d.ts.map +0 -1
  276. package/dist/types.js +0 -49
  277. package/dist/types.js.map +0 -1
  278. package/dist/wire-body.d.ts.map +0 -1
  279. package/dist/wire-body.js.map +0 -1
  280. package/dist/wire-entry.d.ts.map +0 -1
  281. package/dist/wire-entry.js.map +0 -1
  282. package/dist/wire-record.d.ts.map +0 -1
  283. package/dist/wire-record.js.map +0 -1
  284. package/dist/wire-request.d.ts.map +0 -1
  285. package/dist/wire-request.js.map +0 -1
  286. /package/dist/{did.d.ts → did/did.d.ts} +0 -0
  287. /package/dist/{identity-bindings.d.ts → stack/identity-bindings.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC"}
@@ -7,8 +7,9 @@
7
7
  * adapters). Types an app reads too, such as StackCapabilities, live in
8
8
  * the root entry point instead: every export has exactly one home.
9
9
  */
10
- export { OwnerMismatchError } from './errors.js';
10
+ export { OwnerMismatchError } from '../errors.js';
11
11
  export { combineAdapters } from './combine.js';
12
- export { assertQueryCapabilities, assertSortCapability, assertValidSort, assertValidAssociationFilters, assertValidJournalQuery, assertValidVersionsQuery, filtersContent, parseContentFilterKey, } from './query-validation.js';
13
- export { contentSortEntry, contentSortKey, compareSortEntries } from './sort.js';
14
- //# sourceMappingURL=adapter-entry.js.map
12
+ export { assertQueryCapabilities, assertSortCapability, assertValidSort, assertValidAssociationFilters, assertValidJournalQuery, assertValidVersionsQuery, filtersContent, parseContentFilterKey, } from '../query-validation.js';
13
+ export { contentSortEntry, contentSortKey, compareSortEntries, constantSortEntry, sortConstant, } from './sort.js';
14
+ export { AUTHORITY_ASSOCIATION_KINDS, partitionAssociations } from '../associations/identity.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC"}
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * See docs/spec/data-model.md § Sorting by a content field.
12
12
  */
13
- import type { ScalarFieldKind } from './types.js';
13
+ import type { ScalarFieldKind } from '../types/index.js';
14
14
  /**
15
15
  * A field's value reduced to something ordered: a number, or text plus
16
16
  * the key its ordering actually uses (see contentSortKey).
@@ -24,30 +24,30 @@ export type SortEntry = {
24
24
  key: string;
25
25
  };
26
26
  /**
27
- * Fold text into the key it sorts by: compatibility-decompose, drop
28
- * combining marks, lowercase. `Émile` files with `emile` and `Zebra` with
29
- * `zebra`, which is what a person reading a list expects and what raw
30
- * code-point order gets wrong.
31
- *
32
- * `toLowerCase()`, never `toLocaleLowerCase()` — a locale-sensitive fold
33
- * would order Turkish `İstanbul` differently from every other runtime's,
34
- * and the key is stored, so the divergence would be baked into an index.
35
- * What this deliberately does not promise is in
36
- * docs/spec/data-model.md § Text ordering.
27
+ * Fold text into the key it sorts by — decompose, drop combining marks,
28
+ * lowercase — so `Émile` files with `emile`. `toLowerCase()`, never the
29
+ * locale form: the key is stored, so a locale-sensitive fold would bake one
30
+ * runtime's order into the index. See docs/spec/data-model.md § Text ordering.
37
31
  */
38
32
  export declare const contentSortKey: (value: string) => string;
39
33
  /**
40
- * The ordered form of `value` held in a field of the declared `kind`, or
41
- * null when there is nothing to order by. The kind comes from the schema
42
- * rather than from the value's runtime type: a field that is numeric on
43
- * the records that carry it must not order as text on the ones that
44
- * spell it differently.
45
- *
46
- * `date` normalizes to epoch milliseconds so a date field orders the way
47
- * `createdAt` does instead of by ISO string collation, and `boolean` to
48
- * 0/1 so false precedes true.
34
+ * The ordered form of `value` in a field of the declared `kind`, or null
35
+ * when there is nothing to order by. The kind comes from the schema, not
36
+ * the value, so a field orders one way on every record. `date` orders as
37
+ * epoch ms like `createdAt`, `boolean` as 0/1, and an enum as text, since
38
+ * its declaration order is not part of the schema.
49
39
  */
50
40
  export declare function contentSortEntry(kind: ScalarFieldKind, value: unknown): SortEntry | null;
41
+ /**
42
+ * A constant a `contentFieldByType` key orders by, reduced from a value of
43
+ * `kind` to what it orders as: a number, text, or null for no value. The
44
+ * reduction happens before the query is sent, so an adapter orders it
45
+ * without knowing the kind. See docs/spec/data-model.md § Sorting by a
46
+ * content field.
47
+ */
48
+ export declare function sortConstant(kind: ScalarFieldKind, value: unknown): string | number | null;
49
+ /** The entry a reduced constant orders as; see sortConstant(). */
50
+ export declare function constantSortEntry(value: string | number | null): SortEntry | null;
51
51
  /**
52
52
  * Order two records by one sort field, absent values last. `direction`
53
53
  * reverses the order between values but never moves absence: a record
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/adapter/sort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MACe,CAAC;AAU/D;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAsBxF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAG1F;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAIjF;AA+BD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,SAAS,GAAG,IAAI,EACnB,CAAC,EAAE,SAAS,GAAG,IAAI,EACnB,SAAS,EAAE,KAAK,GAAG,MAAM,GACxB,MAAM,CAGR"}
@@ -11,38 +11,25 @@
11
11
  * See docs/spec/data-model.md § Sorting by a content field.
12
12
  */
13
13
  /**
14
- * Fold text into the key it sorts by: compatibility-decompose, drop
15
- * combining marks, lowercase. `Émile` files with `emile` and `Zebra` with
16
- * `zebra`, which is what a person reading a list expects and what raw
17
- * code-point order gets wrong.
18
- *
19
- * `toLowerCase()`, never `toLocaleLowerCase()` — a locale-sensitive fold
20
- * would order Turkish `İstanbul` differently from every other runtime's,
21
- * and the key is stored, so the divergence would be baked into an index.
22
- * What this deliberately does not promise is in
23
- * docs/spec/data-model.md § Text ordering.
14
+ * Fold text into the key it sorts by — decompose, drop combining marks,
15
+ * lowercase — so `Émile` files with `emile`. `toLowerCase()`, never the
16
+ * locale form: the key is stored, so a locale-sensitive fold would bake one
17
+ * runtime's order into the index. See docs/spec/data-model.md § Text ordering.
24
18
  */
25
19
  export const contentSortKey = (value) => value.normalize('NFKD').replace(/\p{M}/gu, '').toLowerCase();
26
20
  /**
27
- * A `date` field may hold an offset-less date-time — the offset is
28
- * optional in the shape validate.ts pins — and bare `Date.parse` resolves
29
- * one of those in the *host's* zone. The stored index value and a cursor
30
- * value re-derived elsewhere would then disagree, skipping or repeating a
31
- * record at a page boundary, and two adapters in two zones would answer
32
- * one query in two orders. A zone-less date-time is read as UTC, which is
33
- * what `Date.parse` already does for a date-only string.
21
+ * A zone-less date-time, read as UTC as `Date.parse` already reads a
22
+ * date-only string. Read in the host's zone, a stored index value and a
23
+ * cursor re-derived elsewhere would disagree at a page boundary, and two
24
+ * adapters in two zones would order one query two ways.
34
25
  */
35
26
  const ZONELESS_DATE_TIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$/;
36
27
  /**
37
- * The ordered form of `value` held in a field of the declared `kind`, or
38
- * null when there is nothing to order by. The kind comes from the schema
39
- * rather than from the value's runtime type: a field that is numeric on
40
- * the records that carry it must not order as text on the ones that
41
- * spell it differently.
42
- *
43
- * `date` normalizes to epoch milliseconds so a date field orders the way
44
- * `createdAt` does instead of by ISO string collation, and `boolean` to
45
- * 0/1 so false precedes true.
28
+ * The ordered form of `value` in a field of the declared `kind`, or null
29
+ * when there is nothing to order by. The kind comes from the schema, not
30
+ * the value, so a field orders one way on every record. `date` orders as
31
+ * epoch ms like `createdAt`, `boolean` as 0/1, and an enum as text, since
32
+ * its declaration order is not part of the schema.
46
33
  */
47
34
  export function contentSortEntry(kind, value) {
48
35
  switch (kind) {
@@ -58,12 +45,35 @@ export function contentSortEntry(kind, value) {
58
45
  const ms = Date.parse(ZONELESS_DATE_TIME_RE.test(value) ? `${value}Z` : value);
59
46
  return Number.isNaN(ms) ? null : { kind: 'num', num: ms };
60
47
  }
61
- default:
48
+ case 'string':
49
+ case 'text':
50
+ case 'record-ref':
51
+ case 'file-ref':
52
+ case 'enum':
62
53
  return typeof value === 'string'
63
54
  ? { kind: 'text', text: value, key: contentSortKey(value) }
64
55
  : null;
65
56
  }
66
57
  }
58
+ /**
59
+ * A constant a `contentFieldByType` key orders by, reduced from a value of
60
+ * `kind` to what it orders as: a number, text, or null for no value. The
61
+ * reduction happens before the query is sent, so an adapter orders it
62
+ * without knowing the kind. See docs/spec/data-model.md § Sorting by a
63
+ * content field.
64
+ */
65
+ export function sortConstant(kind, value) {
66
+ const entry = contentSortEntry(kind, value);
67
+ return entry === null ? null : entry.kind === 'num' ? entry.num : entry.text;
68
+ }
69
+ /** The entry a reduced constant orders as; see sortConstant(). */
70
+ export function constantSortEntry(value) {
71
+ if (typeof value === 'number')
72
+ return Number.isFinite(value) ? { kind: 'num', num: value } : null;
73
+ if (typeof value === 'string')
74
+ return { kind: 'text', text: value, key: contentSortKey(value) };
75
+ return null;
76
+ }
67
77
  /**
68
78
  * Order two strings by code point. JS `<` compares UTF-16 code units,
69
79
  * which files every supplementary character (U+10000 and above, stored as
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort.js","sourceRoot":"","sources":["../../src/adapter/sort.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Association identity and edits
3
+ * -------------------------------------------------------
4
+ * When two associations are the same one, what a list of edits leaves
5
+ * behind, and what it moved. Identity is asked by every layer that touches
6
+ * an association — the no-op decision, the journal's delta, an adapter
7
+ * applying edits, the feed — so they answer it with one comparison and
8
+ * can never disagree. See docs/spec/data-model.md § Associations.
9
+ */
10
+ import type { Association, AssociationChange, AssociationEdit, AuthorityAssociation, DataAssociation, Grantee, RelationshipTarget } from '../types/index.js';
11
+ /**
12
+ * Association identity — what dissociate() matches and a repeat associate()
13
+ * collides with; the SQLite adapter's primary key. An attachment's
14
+ * `attachmentRecordId` annotates a reference rather than naming one, so it
15
+ * is outside; a group grantee's `role` names a different set of people, so
16
+ * it is inside. See docs/spec/data-model.md § Associations.
17
+ */
18
+ export declare function associationEqual(a: Association, b: Association): boolean;
19
+ /**
20
+ * Structural equality per grantee arm. `role` is required, so there is no
21
+ * absent-means-any spelling to normalize.
22
+ */
23
+ export declare function granteeEqual(a: Grantee, b: Grantee): boolean;
24
+ /** Structural equality per target arm — what dissociate() matches on. */
25
+ export declare function targetEqual(a: RelationshipTarget, b: RelationshipTarget): boolean;
26
+ /**
27
+ * Identity plus every annotation outside it, so a write that only re-points
28
+ * an attachment association's `attachmentRecordId` still counts as a
29
+ * change. Identity alone decides which stored association a write lands on;
30
+ * this decides whether it says anything new.
31
+ */
32
+ export declare function associationIdentical(a: Association, b: Association): boolean;
33
+ /**
34
+ * The association kinds that carry authority. Every other kind is data.
35
+ * Storage that partitions by kind in a query reads this list rather than
36
+ * restating it, so a new authority kind can't fall into the data half.
37
+ */
38
+ export declare const AUTHORITY_ASSOCIATION_KINDS: readonly AuthorityAssociation['kind'][];
39
+ /**
40
+ * Whether an association carries authority rather than data — the partition
41
+ * `StackRecord.permissions` and `StackRecord.associations` project, and the
42
+ * line `associate()`/`dissociate()` refuse to cross.
43
+ * See docs/spec/access-control.md § Record-level permissions.
44
+ */
45
+ export declare function isAuthorityAssociation(a: Association): a is AuthorityAssociation;
46
+ /**
47
+ * One stored association set split into the two the record presents. An app
48
+ * editing tags never sees the authority half, so it cannot drop it.
49
+ */
50
+ export declare function partitionAssociations(associations: Association[]): {
51
+ associations: DataAssociation[];
52
+ permissions: AuthorityAssociation[];
53
+ };
54
+ /**
55
+ * What a `changes.associations` list moves against a record's current set,
56
+ * one tagged edit each. An entry matching an existing identity displaced it:
57
+ * a `repoint`, carrying the prior association in full as `previous` — the
58
+ * only place an overwritten `attachmentRecordId` survives.
59
+ * See docs/spec/journal.md § The entry.
60
+ */
61
+ export declare function associationDelta(before: Association[], after: Association[]): AssociationChange[];
62
+ /**
63
+ * The two flat lists a change frame carries, derived from the tagged list.
64
+ * The feed reports what is true now, so a `repoint` appears only under its
65
+ * new value and a `remove` by identity alone — the prior state the journal
66
+ * keeps has no place on a notification. The data half alone: `reshare` is
67
+ * what announces an ACL move. See docs/spec/events.md § The event shape.
68
+ */
69
+ export declare function feedAssociationDelta(changes: AssociationChange[]): {
70
+ added: DataAssociation[];
71
+ removed: DataAssociation[];
72
+ };
73
+ /**
74
+ * An association edit list travels one surface: authority and data share
75
+ * storage and a delta, and never share a call. Refused here so every
76
+ * adapter inherits the same rule.
77
+ * See docs/spec/access-control.md § Storage unifies; the API does not.
78
+ */
79
+ export declare function assertOneSurface(changes: readonly AssociationEdit[]): void;
80
+ /**
81
+ * The set a list of edits leaves behind: removes first, then adds, an add
82
+ * landing on an identity already held in place. Adds naming one identity
83
+ * collapse, last wins; an add outlives a remove of the same identity.
84
+ * See docs/spec/adapters.md § Amending associations.
85
+ */
86
+ export declare function applyAssociationEdits(current: Association[], changes: readonly AssociationEdit[]): Association[];
87
+ /**
88
+ * The same op over every element of a list — what associate(),
89
+ * dissociate(), grantAccess() and revokeAccess() hand to the amend verb
90
+ * each is one half of.
91
+ */
92
+ export declare function editsOf(op: 'add' | 'remove', associations: Association[]): AssociationEdit[];
93
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/associations/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,OAAO,EACP,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAaxE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAQ5D;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAQjF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAM5E;AAcD;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,EAAE,SAAS,oBAAoB,CAAC,MAAM,CAAC,EAG9E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,IAAI,oBAAoB,CAEhF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG;IAClE,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACrC,CAKA;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,iBAAiB,EAAE,CAcjG;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG;IAClE,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAYA;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAO1E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,WAAW,EAAE,CAWf;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,KAAK,GAAG,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,eAAe,EAAE,CAE5F"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Association identity and edits
3
+ * -------------------------------------------------------
4
+ * When two associations are the same one, what a list of edits leaves
5
+ * behind, and what it moved. Identity is asked by every layer that touches
6
+ * an association — the no-op decision, the journal's delta, an adapter
7
+ * applying edits, the feed — so they answer it with one comparison and
8
+ * can never disagree. See docs/spec/data-model.md § Associations.
9
+ */
10
+ import { StackBadRequestError } from '../errors.js';
11
+ /**
12
+ * Association identity — what dissociate() matches and a repeat associate()
13
+ * collides with; the SQLite adapter's primary key. An attachment's
14
+ * `attachmentRecordId` annotates a reference rather than naming one, so it
15
+ * is outside; a group grantee's `role` names a different set of people, so
16
+ * it is inside. See docs/spec/data-model.md § Associations.
17
+ */
18
+ export function associationEqual(a, b) {
19
+ // Never "the same one": naming a malformed association is
20
+ // validateAssociation()'s job, which this must reach without throwing.
21
+ if (!a || !b)
22
+ return false;
23
+ if (a.kind !== b.kind || a.label !== b.label)
24
+ return false;
25
+ if (a.kind === 'attachment' && b.kind === 'attachment')
26
+ return a.fileId === b.fileId;
27
+ if (a.kind === 'relationship' && b.kind === 'relationship') {
28
+ return targetEqual(a.target, b.target);
29
+ }
30
+ if (a.kind === 'permission' && b.kind === 'permission') {
31
+ return granteeEqual(a.grantee, b.grantee);
32
+ }
33
+ return true;
34
+ }
35
+ /**
36
+ * Structural equality per grantee arm. `role` is required, so there is no
37
+ * absent-means-any spelling to normalize.
38
+ */
39
+ export function granteeEqual(a, b) {
40
+ if (!a || !b)
41
+ return false;
42
+ if (a.kind !== b.kind)
43
+ return false;
44
+ if (a.kind === 'entity' && b.kind === 'entity')
45
+ return a.entityId === b.entityId;
46
+ if (a.kind === 'group' && b.kind === 'group') {
47
+ return a.groupId === b.groupId && a.role === b.role;
48
+ }
49
+ return false;
50
+ }
51
+ /** Structural equality per target arm — what dissociate() matches on. */
52
+ export function targetEqual(a, b) {
53
+ if (a.kind !== b.kind)
54
+ return false;
55
+ if (a.kind === 'record' && b.kind === 'record') {
56
+ return a.recordId === b.recordId && (a.stackUrl ?? '') === (b.stackUrl ?? '');
57
+ }
58
+ if (a.kind === 'entity' && b.kind === 'entity')
59
+ return a.entityId === b.entityId;
60
+ if (a.kind === 'external' && b.kind === 'external')
61
+ return a.ns === b.ns && a.id === b.id;
62
+ return false;
63
+ }
64
+ /**
65
+ * Identity plus every annotation outside it, so a write that only re-points
66
+ * an attachment association's `attachmentRecordId` still counts as a
67
+ * change. Identity alone decides which stored association a write lands on;
68
+ * this decides whether it says anything new.
69
+ */
70
+ export function associationIdentical(a, b) {
71
+ if (!associationEqual(a, b))
72
+ return false;
73
+ if (a.kind === 'attachment' && b.kind === 'attachment') {
74
+ return (a.attachmentRecordId ?? '') === (b.attachmentRecordId ?? '');
75
+ }
76
+ return true;
77
+ }
78
+ /**
79
+ * An association's identity alone, its annotation dropped — what a change
80
+ * event reports for an association that's gone, as a `purged` frame names
81
+ * a destroyed record without repeating its content.
82
+ * See docs/spec/events.md § The event shape.
83
+ */
84
+ function stripAssociationAnnotation(association) {
85
+ if (association.kind !== 'attachment')
86
+ return association;
87
+ const { attachmentRecordId: _attachmentRecordId, ...identity } = association;
88
+ return identity;
89
+ }
90
+ /**
91
+ * The association kinds that carry authority. Every other kind is data.
92
+ * Storage that partitions by kind in a query reads this list rather than
93
+ * restating it, so a new authority kind can't fall into the data half.
94
+ */
95
+ export const AUTHORITY_ASSOCIATION_KINDS = [
96
+ 'permission',
97
+ 'anyone',
98
+ ];
99
+ /**
100
+ * Whether an association carries authority rather than data — the partition
101
+ * `StackRecord.permissions` and `StackRecord.associations` project, and the
102
+ * line `associate()`/`dissociate()` refuse to cross.
103
+ * See docs/spec/access-control.md § Record-level permissions.
104
+ */
105
+ export function isAuthorityAssociation(a) {
106
+ return AUTHORITY_ASSOCIATION_KINDS.includes(a.kind);
107
+ }
108
+ /**
109
+ * One stored association set split into the two the record presents. An app
110
+ * editing tags never sees the authority half, so it cannot drop it.
111
+ */
112
+ export function partitionAssociations(associations) {
113
+ return {
114
+ associations: associations.filter((a) => !isAuthorityAssociation(a)),
115
+ permissions: associations.filter(isAuthorityAssociation),
116
+ };
117
+ }
118
+ /**
119
+ * What a `changes.associations` list moves against a record's current set,
120
+ * one tagged edit each. An entry matching an existing identity displaced it:
121
+ * a `repoint`, carrying the prior association in full as `previous` — the
122
+ * only place an overwritten `attachmentRecordId` survives.
123
+ * See docs/spec/journal.md § The entry.
124
+ */
125
+ export function associationDelta(before, after) {
126
+ const changes = after
127
+ .filter((a) => !before.some((b) => associationIdentical(a, b)))
128
+ .map((association) => {
129
+ const previous = before.find((b) => associationEqual(b, association));
130
+ return previous
131
+ ? { op: 'repoint', association, previous }
132
+ : { op: 'add', association };
133
+ });
134
+ return changes.concat(before
135
+ .filter((b) => !after.some((a) => associationEqual(a, b)))
136
+ .map((association) => ({ op: 'remove', association })));
137
+ }
138
+ /**
139
+ * The two flat lists a change frame carries, derived from the tagged list.
140
+ * The feed reports what is true now, so a `repoint` appears only under its
141
+ * new value and a `remove` by identity alone — the prior state the journal
142
+ * keeps has no place on a notification. The data half alone: `reshare` is
143
+ * what announces an ACL move. See docs/spec/events.md § The event shape.
144
+ */
145
+ export function feedAssociationDelta(changes) {
146
+ const added = [];
147
+ const removed = [];
148
+ for (const c of changes) {
149
+ if (c.op === 'remove') {
150
+ const identity = stripAssociationAnnotation(c.association);
151
+ if (!isAuthorityAssociation(identity))
152
+ removed.push(identity);
153
+ }
154
+ else if (!isAuthorityAssociation(c.association)) {
155
+ added.push(c.association);
156
+ }
157
+ }
158
+ return { added, removed };
159
+ }
160
+ /**
161
+ * An association edit list travels one surface: authority and data share
162
+ * storage and a delta, and never share a call. Refused here so every
163
+ * adapter inherits the same rule.
164
+ * See docs/spec/access-control.md § Storage unifies; the API does not.
165
+ */
166
+ export function assertOneSurface(changes) {
167
+ const authority = changes.filter((c) => isAuthorityAssociation(c.association)).length;
168
+ if (authority === 0 || authority === changes.length)
169
+ return;
170
+ throw new StackBadRequestError('An association edit list carries authority or data, never both: permission and anyone ' +
171
+ 'elements travel on the permissions surface.');
172
+ }
173
+ /**
174
+ * The set a list of edits leaves behind: removes first, then adds, an add
175
+ * landing on an identity already held in place. Adds naming one identity
176
+ * collapse, last wins; an add outlives a remove of the same identity.
177
+ * See docs/spec/adapters.md § Amending associations.
178
+ */
179
+ export function applyAssociationEdits(current, changes) {
180
+ let next = current.filter((a) => !changes.some((c) => c.op === 'remove' && associationEqual(c.association, a)));
181
+ for (const c of changes) {
182
+ if (c.op !== 'add')
183
+ continue;
184
+ next = next.some((a) => associationEqual(a, c.association))
185
+ ? next.map((a) => (associationEqual(a, c.association) ? c.association : a))
186
+ : [...next, c.association];
187
+ }
188
+ return next;
189
+ }
190
+ /**
191
+ * The same op over every element of a list — what associate(),
192
+ * dissociate(), grantAccess() and revokeAccess() hand to the amend verb
193
+ * each is one half of.
194
+ */
195
+ export function editsOf(op, associations) {
196
+ return associations.map((association) => ({ op, association }));
197
+ }
198
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/associations/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
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 grantAccess()/revokeAccess().
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
+ /**
84
+ * assertAssociationEdits() for the verbs taking a bare list — associate(),
85
+ * grantAccess() and their inverses — asked before wrapping, so problems are
86
+ * reported under `param`, the name the caller used. Same order of checks,
87
+ * so a wrong-surface element is refused as such before duplicates count.
88
+ */
89
+ export declare function assertAssociationList(associations: unknown, surface: string, param: string, half: 'data' | 'authority'): asserts associations is Association[];
90
+ //# 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;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,OAAO,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GAAG,WAAW,GACzB,OAAO,CAAC,YAAY,IAAI,WAAW,EAAE,CAoBvC"}