foldkit-remote 0.20.0 → 0.22.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 (198) hide show
  1. package/README.md +987 -198
  2. package/dist/answerGaps.d.ts +16 -0
  3. package/dist/answerGaps.d.ts.map +1 -0
  4. package/dist/answerGaps.js +60 -0
  5. package/dist/answerGaps.js.map +1 -0
  6. package/dist/client-B055kQuP.d.ts +110 -0
  7. package/dist/client-B055kQuP.d.ts.map +1 -0
  8. package/dist/client.d.ts +2 -0
  9. package/dist/client.js +142 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/coalesce-CLAr92Nk.d.ts +34 -0
  12. package/dist/coalesce-CLAr92Nk.d.ts.map +1 -0
  13. package/dist/coalesce.d.ts +2 -0
  14. package/dist/coalesce.js +131 -0
  15. package/dist/coalesce.js.map +1 -0
  16. package/dist/connection-BRyaJy89.d.ts +45 -0
  17. package/dist/connection-BRyaJy89.d.ts.map +1 -0
  18. package/dist/connection.d.ts +2 -0
  19. package/dist/connection.js +170 -0
  20. package/dist/connection.js.map +1 -0
  21. package/dist/data.d.ts +7 -0
  22. package/dist/data.d.ts.map +1 -0
  23. package/dist/data.js +21 -0
  24. package/dist/data.js.map +1 -0
  25. package/dist/diagnostics-DHhVYflV.d.ts +125 -0
  26. package/dist/diagnostics-DHhVYflV.d.ts.map +1 -0
  27. package/dist/diagnostics.d.ts +2 -0
  28. package/dist/diagnostics.js +60 -0
  29. package/dist/diagnostics.js.map +1 -0
  30. package/dist/entity-CgsG5Uel.d.ts +196 -0
  31. package/dist/entity-CgsG5Uel.d.ts.map +1 -0
  32. package/dist/entity-DuDxaa3n.js +279 -0
  33. package/dist/entity-DuDxaa3n.js.map +1 -0
  34. package/dist/entity.d.ts +2 -0
  35. package/dist/entity.js +1 -0
  36. package/dist/held.d.ts +19 -0
  37. package/dist/held.d.ts.map +1 -0
  38. package/dist/held.js +70 -0
  39. package/dist/held.js.map +1 -0
  40. package/dist/impact.d.ts +79 -0
  41. package/dist/impact.d.ts.map +1 -0
  42. package/dist/impact.js +166 -0
  43. package/dist/impact.js.map +1 -0
  44. package/dist/index.d.ts +1542 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +2791 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/inspect-DtRQGCRP.d.ts +134 -0
  49. package/dist/inspect-DtRQGCRP.d.ts.map +1 -0
  50. package/dist/inspect.d.ts +2 -0
  51. package/dist/inspect.js +33 -0
  52. package/dist/inspect.js.map +1 -0
  53. package/dist/json-DowLl1eB.d.ts +52 -0
  54. package/dist/json-DowLl1eB.d.ts.map +1 -0
  55. package/dist/json.d.ts +2 -0
  56. package/dist/json.js +123 -0
  57. package/dist/json.js.map +1 -0
  58. package/dist/law.d.ts +56 -0
  59. package/dist/law.d.ts.map +1 -0
  60. package/dist/law.js +201 -0
  61. package/dist/law.js.map +1 -0
  62. package/dist/live-BpTzlCnY.d.ts +79 -0
  63. package/dist/live-BpTzlCnY.d.ts.map +1 -0
  64. package/dist/live.d.ts +2 -0
  65. package/dist/live.js +126 -0
  66. package/dist/live.js.map +1 -0
  67. package/dist/matching-DF5F9Us8.d.ts +100 -0
  68. package/dist/matching-DF5F9Us8.d.ts.map +1 -0
  69. package/dist/matching.d.ts +2 -0
  70. package/dist/matching.js +172 -0
  71. package/dist/matching.js.map +1 -0
  72. package/dist/model-B6zk1NMB.d.ts +710 -0
  73. package/dist/model-B6zk1NMB.d.ts.map +1 -0
  74. package/dist/model.d.ts +2 -0
  75. package/dist/model.js +1308 -0
  76. package/dist/model.js.map +1 -0
  77. package/dist/mutation.d.ts +2 -0
  78. package/dist/mutation.js +612 -0
  79. package/dist/mutation.js.map +1 -0
  80. package/dist/optimistic-CECsfNGY.d.ts +523 -0
  81. package/dist/optimistic-CECsfNGY.d.ts.map +1 -0
  82. package/dist/optimistic.d.ts +2 -0
  83. package/dist/optimistic.js +336 -0
  84. package/dist/optimistic.js.map +1 -0
  85. package/dist/outbox-DNuc4kZp.d.ts +259 -0
  86. package/dist/outbox-DNuc4kZp.d.ts.map +1 -0
  87. package/dist/outbox.d.ts +2 -0
  88. package/dist/outbox.js +326 -0
  89. package/dist/outbox.js.map +1 -0
  90. package/dist/patchValues.d.ts +10 -0
  91. package/dist/patchValues.d.ts.map +1 -0
  92. package/dist/patchValues.js +57 -0
  93. package/dist/patchValues.js.map +1 -0
  94. package/dist/persistence-CCMnvg7-.d.ts +114 -0
  95. package/dist/persistence-CCMnvg7-.d.ts.map +1 -0
  96. package/dist/persistence.d.ts +2 -0
  97. package/dist/persistence.js +205 -0
  98. package/dist/persistence.js.map +1 -0
  99. package/dist/placement-jZdsIpmj.d.ts +50 -0
  100. package/dist/placement-jZdsIpmj.d.ts.map +1 -0
  101. package/dist/placement.d.ts +2 -0
  102. package/dist/placement.js +116 -0
  103. package/dist/placement.js.map +1 -0
  104. package/dist/plan-D9cftxC_.d.ts +35 -0
  105. package/dist/plan-D9cftxC_.d.ts.map +1 -0
  106. package/dist/plan.d.ts +2 -0
  107. package/dist/plan.js +100 -0
  108. package/dist/plan.js.map +1 -0
  109. package/dist/policy-DsWHmIAq.d.ts +42 -0
  110. package/dist/policy-DsWHmIAq.d.ts.map +1 -0
  111. package/dist/policy.d.ts +2 -0
  112. package/dist/policy.js +32 -0
  113. package/dist/policy.js.map +1 -0
  114. package/dist/{port.d.mts → port.d.ts} +3 -2
  115. package/dist/port.d.ts.map +1 -0
  116. package/dist/{port.mjs → port.js} +3 -2
  117. package/dist/port.js.map +1 -0
  118. package/dist/query-BuIU93xA.d.ts +141 -0
  119. package/dist/query-BuIU93xA.d.ts.map +1 -0
  120. package/dist/query.d.ts +2 -0
  121. package/dist/query.js +0 -0
  122. package/dist/query.js.map +1 -0
  123. package/dist/record.d.ts +11 -0
  124. package/dist/record.d.ts.map +1 -0
  125. package/dist/record.js +21 -0
  126. package/dist/record.js.map +1 -0
  127. package/dist/relation-BLBGOZom.d.ts +59 -0
  128. package/dist/relation-BLBGOZom.d.ts.map +1 -0
  129. package/dist/relation.d.ts +2 -0
  130. package/dist/relation.js +93 -0
  131. package/dist/relation.js.map +1 -0
  132. package/dist/remoteData-mK1suYi1.d.ts +148 -0
  133. package/dist/remoteData-mK1suYi1.d.ts.map +1 -0
  134. package/dist/remoteData.d.ts +2 -0
  135. package/dist/remoteData.js +179 -0
  136. package/dist/remoteData.js.map +1 -0
  137. package/dist/reporting.d.ts +12 -0
  138. package/dist/reporting.d.ts.map +1 -0
  139. package/dist/reporting.js +45 -0
  140. package/dist/reporting.js.map +1 -0
  141. package/dist/requirement-D57S2LpH.d.ts +64 -0
  142. package/dist/requirement-D57S2LpH.d.ts.map +1 -0
  143. package/dist/requirement.d.ts +2 -0
  144. package/dist/requirement.js +114 -0
  145. package/dist/requirement.js.map +1 -0
  146. package/dist/resume-Ct5R6yli.d.ts +92 -0
  147. package/dist/resume-Ct5R6yli.d.ts.map +1 -0
  148. package/dist/resume.d.ts +2 -0
  149. package/dist/resume.js +222 -0
  150. package/dist/resume.js.map +1 -0
  151. package/dist/retain-BfNTvBRb.d.ts +48 -0
  152. package/dist/retain-BfNTvBRb.d.ts.map +1 -0
  153. package/dist/retain.d.ts +2 -0
  154. package/dist/retain.js +107 -0
  155. package/dist/retain.js.map +1 -0
  156. package/dist/selection.d.ts +2 -0
  157. package/dist/selection.js +1 -0
  158. package/dist/shown.d.ts +20 -0
  159. package/dist/shown.d.ts.map +1 -0
  160. package/dist/shown.js +40 -0
  161. package/dist/shown.js.map +1 -0
  162. package/dist/sse-C7LhdbiQ.d.ts +17 -0
  163. package/dist/sse-C7LhdbiQ.d.ts.map +1 -0
  164. package/dist/sse.d.ts +2 -0
  165. package/dist/sse.js +127 -0
  166. package/dist/sse.js.map +1 -0
  167. package/dist/store-ah2qjcJW.d.ts +100 -0
  168. package/dist/store-ah2qjcJW.d.ts.map +1 -0
  169. package/dist/store.d.ts +2 -0
  170. package/dist/store.js +218 -0
  171. package/dist/store.js.map +1 -0
  172. package/dist/testing.d.ts +133 -0
  173. package/dist/testing.d.ts.map +1 -0
  174. package/dist/testing.js +0 -0
  175. package/dist/testing.js.map +1 -0
  176. package/dist/why-kgp_Wr3z.d.ts +483 -0
  177. package/dist/why-kgp_Wr3z.d.ts.map +1 -0
  178. package/dist/why.d.ts +2 -0
  179. package/dist/why.js +293 -0
  180. package/dist/why.js.map +1 -0
  181. package/dist/whyReasons.d.ts +42 -0
  182. package/dist/whyReasons.d.ts.map +1 -0
  183. package/dist/whyReasons.js +211 -0
  184. package/dist/whyReasons.js.map +1 -0
  185. package/dist/wire-DthPcTM6.d.ts +787 -0
  186. package/dist/wire-DthPcTM6.d.ts.map +1 -0
  187. package/dist/wire.d.ts +2 -0
  188. package/dist/wire.js +329 -0
  189. package/dist/wire.js.map +1 -0
  190. package/package.json +19 -14
  191. package/dist/index-BEvVAL76.d.mts +0 -4097
  192. package/dist/index-BEvVAL76.d.mts.map +0 -1
  193. package/dist/index.d.mts +0 -2
  194. package/dist/index.mjs +0 -1
  195. package/dist/port.d.mts.map +0 -1
  196. package/dist/port.mjs.map +0 -1
  197. package/dist/src-BDqn7Ocr.mjs +0 -6344
  198. package/dist/src-BDqn7Ocr.mjs.map +0 -1
@@ -0,0 +1,170 @@
1
+ import { entityKey } from "./store.js";
2
+ // src/connection.ts
3
+ /**
4
+ * The pure connection model: an ordered normalized structure of edges with
5
+ * explicit known boundaries. Pages, live events, and optimistic inserts are all
6
+ * evidence about one connection; `merge` is the single deterministic reducer and
7
+ * performs no I/O.
8
+ *
9
+ * Optimistic overlays and live state arrive in later phases.
10
+ */
11
+ const edge = (ref, key = entityKey(ref.entity, ref.id)) => ({
12
+ key,
13
+ ref
14
+ });
15
+ const terminal = { _tag: "Terminal" };
16
+ const unknown = { _tag: "Unknown" };
17
+ const cursor = (value) => ({
18
+ _tag: "Cursor",
19
+ cursor: value
20
+ });
21
+ const emptyConnection = {
22
+ segments: [],
23
+ stale: false
24
+ };
25
+ const segment = (edges, start, end) => ({
26
+ edges,
27
+ start,
28
+ end
29
+ });
30
+ const dedupeEdges = (edges) => {
31
+ const seen = /* @__PURE__ */ new Set();
32
+ const out = [];
33
+ for (const value of edges) {
34
+ if (seen.has(value.key)) continue;
35
+ seen.add(value.key);
36
+ out.push(value);
37
+ }
38
+ return out;
39
+ };
40
+ const normalize = (segment) => ({
41
+ ...segment,
42
+ edges: dedupeEdges(segment.edges)
43
+ });
44
+ /** Longest suffix of `a` that is a prefix of `b`, matched by edge identity. */
45
+ const overlapLength = (a, b) => {
46
+ const most = Math.min(a.length, b.length);
47
+ for (let length = most; length > 0; length--) {
48
+ let matches = true;
49
+ for (let i = 0; i < length; i++) if (a[a.length - length + i].key !== b[i].key) {
50
+ matches = false;
51
+ break;
52
+ }
53
+ if (matches) return length;
54
+ }
55
+ return 0;
56
+ };
57
+ const cursorJoinable = (a, b) => a._tag === "Cursor" && b._tag === "Cursor" && a.cursor === b.cursor;
58
+ /** Joins `a` immediately before `b`, or returns `undefined` when they are not contiguous. */
59
+ const join = (a, b) => {
60
+ if (cursorJoinable(a.end, b.start)) return {
61
+ edges: dedupeEdges([...a.edges, ...b.edges]),
62
+ start: a.start,
63
+ end: b.end
64
+ };
65
+ if (overlapLength(a.edges, b.edges) > 0) return {
66
+ edges: dedupeEdges([...a.edges, ...b.edges]),
67
+ start: a.start,
68
+ end: b.end
69
+ };
70
+ };
71
+ /**
72
+ * Global by edge identity: an edge appears once per connection. Dropping a
73
+ * shared edge from the middle of a segment would otherwise imply that its
74
+ * surviving neighbours are adjacent, so a segment with holes is split at each
75
+ * hole and the new inner boundaries are `Unknown`.
76
+ */
77
+ const dedupeConnection = (segments) => {
78
+ const seen = /* @__PURE__ */ new Set();
79
+ const out = [];
80
+ for (const segmentValue of segments) {
81
+ const runs = [];
82
+ let run = [];
83
+ for (const edgeValue of segmentValue.edges) {
84
+ if (seen.has(edgeValue.key)) {
85
+ if (run.length > 0) {
86
+ runs.push(run);
87
+ run = [];
88
+ }
89
+ continue;
90
+ }
91
+ seen.add(edgeValue.key);
92
+ run.push(edgeValue);
93
+ }
94
+ if (run.length > 0) runs.push(run);
95
+ if (runs.length === 0) continue;
96
+ if (runs.length === 1) {
97
+ out.push({
98
+ ...segmentValue,
99
+ edges: runs[0]
100
+ });
101
+ continue;
102
+ }
103
+ runs.forEach((edges, index) => {
104
+ out.push({
105
+ edges,
106
+ start: index === 0 ? segmentValue.start : unknown,
107
+ end: index === runs.length - 1 ? segmentValue.end : unknown
108
+ });
109
+ });
110
+ }
111
+ return out;
112
+ };
113
+ /** Adds a page to the connection, joining contiguous or overlapping segments. */
114
+ const merge = (current, page) => {
115
+ const incoming = normalize(page);
116
+ if (incoming.edges.length === 0) return incoming.start._tag === "Terminal" && incoming.end._tag === "Terminal" && current.segments.length === 0 ? {
117
+ ...current,
118
+ segments: [incoming]
119
+ } : current;
120
+ const segments = [...current.segments.map(normalize), incoming];
121
+ let joined = true;
122
+ while (joined) {
123
+ joined = false;
124
+ outer: for (let i = 0; i < segments.length; i++) for (let j = 0; j < segments.length; j++) {
125
+ if (i === j) continue;
126
+ const result = join(segments[i], segments[j]);
127
+ if (result === void 0) continue;
128
+ segments[i] = result;
129
+ segments.splice(j, 1);
130
+ joined = true;
131
+ break outer;
132
+ }
133
+ }
134
+ return {
135
+ ...current,
136
+ segments: orderSegments(dedupeConnection(segments))
137
+ };
138
+ };
139
+ /**
140
+ * Disjoint segments have no cursor linking them, so their relative order is
141
+ * whatever it was; the two exceptions are known: a segment starting at the
142
+ * terminal boundary is first, one ending at it is last.
143
+ */
144
+ const orderSegments = (segments) => {
145
+ const first = segments.filter((value) => value.start._tag === "Terminal");
146
+ const last = segments.filter((value) => value.end._tag === "Terminal" && !first.includes(value));
147
+ const middle = segments.filter((value) => !first.includes(value) && !last.includes(value));
148
+ return [
149
+ ...first,
150
+ ...middle,
151
+ ...last
152
+ ];
153
+ };
154
+ /** Visible edges, segment by segment. */
155
+ const items = (connection) => connection.segments.flatMap((value) => value.edges);
156
+ /** There is more before the known region. Derived from boundaries, never row count. */
157
+ const hasPrevious = (connection) => {
158
+ const first = connection.segments[0];
159
+ return first !== void 0 && first.start._tag !== "Terminal";
160
+ };
161
+ /** There is more after the known region. Derived from boundaries, never row count. */
162
+ const hasNext = (connection) => {
163
+ const last = connection.segments[connection.segments.length - 1];
164
+ return last !== void 0 && last.end._tag !== "Terminal";
165
+ };
166
+ /** A connection with more than one segment has an explicit unknown gap. */
167
+ const isGapped = (connection) => connection.segments.length > 1;
168
+ export { cursor, edge, emptyConnection, hasNext, hasPrevious, isGapped, items, merge, segment, terminal, unknown };
169
+
170
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","names":[],"sources":["../src/connection.ts"],"sourcesContent":["/**\n * The pure connection model: an ordered normalized structure of edges with\n * explicit known boundaries. Pages, live events, and optimistic inserts are all\n * evidence about one connection; `merge` is the single deterministic reducer and\n * performs no I/O.\n *\n * Optimistic overlays and live state arrive in later phases.\n */\nimport { entityKey } from './store.js'\n\nexport interface EdgeRef {\n readonly entity: string\n readonly id: string\n}\n\n/** `key` is the edge identity used for de-duplication. */\nexport interface Edge {\n readonly key: string\n readonly ref: EdgeRef\n}\n\nexport const edge = (ref: EdgeRef, key: string = entityKey(ref.entity, ref.id)): Edge => ({\n key,\n ref,\n})\n\nexport type Cursor = string\n\nexport type Boundary =\n | { readonly _tag: 'Terminal' }\n | { readonly _tag: 'Cursor'; readonly cursor: Cursor }\n | { readonly _tag: 'Unknown' }\n\nexport const terminal: Boundary = { _tag: 'Terminal' }\nexport const unknown: Boundary = { _tag: 'Unknown' }\nexport const cursor = (value: Cursor): Boundary => ({ _tag: 'Cursor', cursor: value })\n\nexport interface Segment {\n readonly edges: readonly Edge[]\n readonly start: Boundary\n readonly end: Boundary\n}\n\nexport interface Connection {\n readonly segments: readonly Segment[]\n readonly stale: boolean\n}\n\nexport const emptyConnection: Connection = { segments: [], stale: false }\n\nexport const segment = (edges: readonly Edge[], start: Boundary, end: Boundary): Segment => ({\n edges,\n start,\n end,\n})\n\nconst dedupeEdges = (edges: readonly Edge[]): Edge[] => {\n const seen = new Set<string>()\n const out: Edge[] = []\n for (const value of edges) {\n if (seen.has(value.key)) continue\n seen.add(value.key)\n out.push(value)\n }\n return out\n}\n\nconst normalize = (segment: Segment): Segment => ({ ...segment, edges: dedupeEdges(segment.edges) })\n\n/** Longest suffix of `a` that is a prefix of `b`, matched by edge identity. */\nconst overlapLength = (a: readonly Edge[], b: readonly Edge[]): number => {\n const most = Math.min(a.length, b.length)\n for (let length = most; length > 0; length--) {\n let matches = true\n for (let i = 0; i < length; i++) {\n if (a[a.length - length + i]!.key !== b[i]!.key) {\n matches = false\n break\n }\n }\n if (matches) return length\n }\n return 0\n}\n\nconst cursorJoinable = (a: Boundary, b: Boundary): boolean =>\n a._tag === 'Cursor' && b._tag === 'Cursor' && a.cursor === b.cursor\n\n/** Joins `a` immediately before `b`, or returns `undefined` when they are not contiguous. */\nconst join = (a: Segment, b: Segment): Segment | undefined => {\n if (cursorJoinable(a.end, b.start)) {\n return { edges: dedupeEdges([...a.edges, ...b.edges]), start: a.start, end: b.end }\n }\n const overlap = overlapLength(a.edges, b.edges)\n if (overlap > 0) {\n return {\n edges: dedupeEdges([...a.edges, ...b.edges]),\n start: a.start,\n end: b.end,\n }\n }\n return undefined\n}\n\n/**\n * Global by edge identity: an edge appears once per connection. Dropping a\n * shared edge from the middle of a segment would otherwise imply that its\n * surviving neighbours are adjacent, so a segment with holes is split at each\n * hole and the new inner boundaries are `Unknown`.\n */\nconst dedupeConnection = (segments: readonly Segment[]): Segment[] => {\n const seen = new Set<string>()\n const out: Segment[] = []\n for (const segmentValue of segments) {\n const runs: Edge[][] = []\n let run: Edge[] = []\n for (const edgeValue of segmentValue.edges) {\n if (seen.has(edgeValue.key)) {\n if (run.length > 0) {\n runs.push(run)\n run = []\n }\n continue\n }\n seen.add(edgeValue.key)\n run.push(edgeValue)\n }\n if (run.length > 0) runs.push(run)\n if (runs.length === 0) continue\n if (runs.length === 1) {\n out.push({ ...segmentValue, edges: runs[0]! })\n continue\n }\n runs.forEach((edges, index) => {\n out.push({\n edges,\n start: index === 0 ? segmentValue.start : unknown,\n end: index === runs.length - 1 ? segmentValue.end : unknown,\n })\n })\n }\n return out\n}\n\n/** Adds a page to the connection, joining contiguous or overlapping segments. */\nexport const merge = (current: Connection, page: Segment): Connection => {\n // A zero-edge page carries no ordering evidence; joining it would let its\n // boundary overwrite a real segment's end. Ignore it, unless it is the whole\n // list and nothing is held: then it is the evidence that the list is empty,\n // which placing a created row by the list's order needs. A later page drops\n // it, as `dedupeConnection` keeps no segment without edges.\n const incoming = normalize(page)\n if (incoming.edges.length === 0) {\n const whole = incoming.start._tag === 'Terminal' && incoming.end._tag === 'Terminal'\n return whole && current.segments.length === 0 ? { ...current, segments: [incoming] } : current\n }\n\n const segments = [...current.segments.map(normalize), incoming]\n let joined = true\n while (joined) {\n joined = false\n outer: for (let i = 0; i < segments.length; i++) {\n for (let j = 0; j < segments.length; j++) {\n if (i === j) continue\n const result = join(segments[i]!, segments[j]!)\n if (result === undefined) continue\n segments[i] = result\n segments.splice(j, 1)\n joined = true\n break outer\n }\n }\n }\n return { ...current, segments: orderSegments(dedupeConnection(segments)) }\n}\n\n/**\n * Disjoint segments have no cursor linking them, so their relative order is\n * whatever it was; the two exceptions are known: a segment starting at the\n * terminal boundary is first, one ending at it is last.\n */\nconst orderSegments = (segments: readonly Segment[]): Segment[] => {\n const first = segments.filter(value => value.start._tag === 'Terminal')\n const last = segments.filter(value => value.end._tag === 'Terminal' && !first.includes(value))\n const middle = segments.filter(value => !first.includes(value) && !last.includes(value))\n return [...first, ...middle, ...last]\n}\n\n/** Visible edges, segment by segment. */\nexport const items = (connection: Connection): ReadonlyArray<Edge> =>\n connection.segments.flatMap(value => value.edges)\n\n/** There is more before the known region. Derived from boundaries, never row count. */\nexport const hasPrevious = (connection: Connection): boolean => {\n const first = connection.segments[0]\n return first !== undefined && first.start._tag !== 'Terminal'\n}\n\n/** There is more after the known region. Derived from boundaries, never row count. */\nexport const hasNext = (connection: Connection): boolean => {\n const last = connection.segments[connection.segments.length - 1]\n return last !== undefined && last.end._tag !== 'Terminal'\n}\n\n/** A connection with more than one segment has an explicit unknown gap. */\nexport const isGapped = (connection: Connection): boolean => connection.segments.length > 1\n"],"mappings":"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"}
package/dist/data.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether two values the server sent are the same data: equal primitives, or
3
+ * arrays and plain objects whose entries are. Anything else is compared by
4
+ * identity.
5
+ */
6
+ export declare const sameData: (left: unknown, right: unknown) => boolean;
7
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","names":[],"sources":["../src/data.ts"],"mappings":";;;;;qBAKa,WAAQ,eAAiB"}
package/dist/data.js ADDED
@@ -0,0 +1,21 @@
1
+ // src/data.ts
2
+ /**
3
+ * Whether two values the server sent are the same data: equal primitives, or
4
+ * arrays and plain objects whose entries are. Anything else is compared by
5
+ * identity.
6
+ */
7
+ const sameData = (left, right) => {
8
+ if (Object.is(left, right)) return true;
9
+ if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
10
+ if (Array.isArray(left)) return Array.isArray(right) && left.length === right.length && left.every((item, index) => sameData(item, right[index]));
11
+ if (!isPlain(left) || !isPlain(right)) return false;
12
+ const keys = Object.keys(left);
13
+ return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && sameData(left[key], right[key]));
14
+ };
15
+ const isPlain = (value) => {
16
+ const prototype = Object.getPrototypeOf(value);
17
+ return prototype === Object.prototype || prototype === null;
18
+ };
19
+ export { sameData };
20
+
21
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","names":[],"sources":["../src/data.ts"],"sourcesContent":["/**\n * Whether two values the server sent are the same data: equal primitives, or\n * arrays and plain objects whose entries are. Anything else is compared by\n * identity.\n */\nexport const sameData = (left: unknown, right: unknown): boolean => {\n if (Object.is(left, right)) return true\n if (typeof left !== 'object' || typeof right !== 'object' || left === null || right === null) {\n return false\n }\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((item, index) => sameData(item, right[index]))\n )\n }\n if (!isPlain(left) || !isPlain(right)) return false\n const keys = Object.keys(left)\n return (\n keys.length === Object.keys(right).length &&\n keys.every(\n key =>\n Object.hasOwn(right, key) &&\n sameData((left as Record<string, unknown>)[key], (right as Record<string, unknown>)[key]),\n )\n )\n}\n\nconst isPlain = (value: object): boolean => {\n const prototype = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n}\n"],"mappings":";;;;;;AAKA,MAAa,YAAY,MAAe,UAA4B;CAClE,IAAI,OAAO,GAAG,MAAM,KAAK,GAAG,OAAO;CACnC,IAAI,OAAO,SAAS,YAAY,OAAO,UAAU,YAAY,SAAS,QAAQ,UAAU,MACtF,OAAO;CAET,IAAI,MAAM,QAAQ,IAAI,GACpB,OACE,MAAM,QAAQ,KAAK,KACnB,KAAK,WAAW,MAAM,UACtB,KAAK,OAAO,MAAM,UAAU,SAAS,MAAM,MAAM,MAAM,CAAC;CAG5D,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,GAAG,OAAO;CAC9C,MAAM,OAAO,OAAO,KAAK,IAAI;CAC7B,OACE,KAAK,WAAW,OAAO,KAAK,KAAK,CAAC,CAAC,UACnC,KAAK,OACH,QACE,OAAO,OAAO,OAAO,GAAG,KACxB,SAAU,KAAiC,MAAO,MAAkC,IAAI,CAC5F;AAEJ;AAEA,MAAM,WAAW,UAA2B;CAC1C,MAAM,YAAY,OAAO,eAAe,KAAK;CAC7C,OAAO,cAAc,OAAO,aAAa,cAAc;AACzD"}
@@ -0,0 +1,125 @@
1
+ import { i as RemoteError } from "./remoteData-mK1suYi1.js";
2
+ import { Data, Option } from "effect";
3
+ import { Diagnostic } from "foldkit-surface";
4
+ /**
5
+ * Which part of a prediction the server's answer disagreed with. `Value`: a
6
+ * field a pending write showed, answered with another value. `Placement`: a
7
+ * list the client placed rows in, which the server's first page lists
8
+ * otherwise. `Gap`: a row whose answer left out fields the client showed,
9
+ * so they are read again and the row reads `Loading` meanwhile.
10
+ */
11
+ type PredictionPart = Data.TaggedEnum<{
12
+ Value: {
13
+ /** The request the answer settled, as `Data.mutate` returned it. */
14
+ readonly requestId: string;
15
+ /** The mutation's name, when the request was started with one (`Data.mutate` always is). */
16
+ readonly mutation: Option.Option<string>;
17
+ readonly entity: string;
18
+ readonly id: string;
19
+ readonly field: string;
20
+ /** What the client showed while the write was pending, encoded. */
21
+ readonly shown: unknown;
22
+ /** What the answer holds, encoded. */
23
+ readonly answered: unknown;
24
+ };
25
+ Placement: {
26
+ readonly connection: string;
27
+ /** The keys as placed, as far as the server's page reached. */
28
+ readonly placed: ReadonlyArray<string>;
29
+ /** The keys of the server's first page. */
30
+ readonly served: ReadonlyArray<string>;
31
+ };
32
+ Gap: {
33
+ readonly requestId: string;
34
+ readonly mutation: Option.Option<string>;
35
+ readonly entity: string;
36
+ readonly id: string;
37
+ /** The fields shown and not answered, which the store does not otherwise hold. */
38
+ readonly fields: ReadonlyArray<string>;
39
+ };
40
+ }>;
41
+ declare const PredictionPart: Data.TaggedEnum.Constructor<{
42
+ readonly _tag: "Gap";
43
+ readonly requestId: string;
44
+ readonly mutation: Option.Option<string>;
45
+ readonly entity: string;
46
+ readonly id: string;
47
+ readonly fields: ReadonlyArray<string>;
48
+ } | {
49
+ readonly _tag: "Placement";
50
+ readonly connection: string;
51
+ readonly placed: ReadonlyArray<string>;
52
+ readonly served: ReadonlyArray<string>;
53
+ } | {
54
+ readonly _tag: "Value";
55
+ readonly requestId: string;
56
+ readonly mutation: Option.Option<string>;
57
+ readonly entity: string;
58
+ readonly id: string;
59
+ readonly field: string;
60
+ readonly shown: unknown;
61
+ readonly answered: unknown;
62
+ }>;
63
+ /**
64
+ * Under `verifyPredictions`, a part the client predicted that the server's
65
+ * answer disagreed with: where the client's evaluation is not unknown, it
66
+ * should equal the server's (operations-phase6-DESIGN §2).
67
+ */
68
+ interface PredictionMismatch extends Diagnostic {
69
+ readonly _tag: 'PredictionMismatch';
70
+ readonly part: PredictionPart;
71
+ }
72
+ /**
73
+ * A write that failed while the application's own `update` does not receive
74
+ * `MutationFailed`: its optimistic change went, and nothing answered it.
75
+ */
76
+ interface WriteUnheard extends Diagnostic {
77
+ readonly _tag: 'WriteUnheard';
78
+ readonly requestId: string;
79
+ readonly mutation: Option.Option<string>;
80
+ readonly error: RemoteError;
81
+ }
82
+ /**
83
+ * A live stream the server refused for what it asks (`RemoteLiveRefused`):
84
+ * more rows of one Entity than its `maxIdsPerEntity`. It is not reopened
85
+ * until what it asks changes, so those rows are not live meanwhile.
86
+ */
87
+ interface LiveRefused extends Diagnostic {
88
+ readonly _tag: 'LiveRefused';
89
+ /** The stream's key, as `Data.liveStatus` and the Model's `streams` name it. */
90
+ readonly stream: string;
91
+ readonly error: RemoteError;
92
+ }
93
+ /**
94
+ * A durable write the outbox read back and cannot send: stored by a version
95
+ * of the application that registered a Mutation this one lacks, or whose
96
+ * input this one's `Input` no longer decodes. It is kept, shown no layer and
97
+ * never sent, and the writes after it are sent.
98
+ */
99
+ interface OutboxUnreadable extends Diagnostic {
100
+ readonly _tag: 'OutboxUnreadable';
101
+ /** Its operation id, which `Data.dismiss` takes. */
102
+ readonly requestId: string;
103
+ readonly reason: string;
104
+ }
105
+ /**
106
+ * The outbox could not write its store (it is full, or the browser refuses
107
+ * storage): its writes are still sent, but a reload before they are answered
108
+ * loses them.
109
+ */
110
+ interface OutboxUnsaved extends Diagnostic {
111
+ readonly _tag: 'OutboxUnsaved';
112
+ readonly key: string;
113
+ readonly reason: string;
114
+ }
115
+ /** Every diagnostic Remote's client records. */
116
+ type RemoteDiagnostic = LiveRefused | OutboxUnreadable | OutboxUnsaved | PredictionMismatch | WriteUnheard;
117
+ declare const predictionMismatch: (part: PredictionPart) => PredictionMismatch;
118
+ declare const writeUnheard: (facts: Pick<WriteUnheard, 'requestId' | 'mutation' | 'error'>) => WriteUnheard;
119
+ declare const liveRefused: (facts: Pick<LiveRefused, 'stream' | 'error'>) => LiveRefused;
120
+ declare const outboxUnreadable: (facts: Pick<OutboxUnreadable, 'requestId' | 'reason'>) => OutboxUnreadable;
121
+ declare const outboxUnsaved: (facts: Pick<OutboxUnsaved, 'key' | 'reason'>) => OutboxUnsaved;
122
+ /** `kept` with `recorded` after it, within the window; `kept` itself when nothing was recorded. */
123
+ declare const withDiagnostics: (kept: ReadonlyArray<RemoteDiagnostic>, recorded: ReadonlyArray<RemoteDiagnostic>) => ReadonlyArray<RemoteDiagnostic>;
124
+ export { PredictionPart as a, liveRefused as c, predictionMismatch as d, withDiagnostics as f, PredictionMismatch as i, outboxUnreadable as l, OutboxUnreadable as n, RemoteDiagnostic as o, writeUnheard as p, OutboxUnsaved as r, WriteUnheard as s, LiveRefused as t, outboxUnsaved as u };
125
+ //# sourceMappingURL=diagnostics-DHhVYflV.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics-DHhVYflV.d.ts","names":[],"sources":["../src/diagnostics.ts"],"mappings":";;;;;;;;;;KAoBY,iBAAiB,KAAK;EAChC;;aAEW;;aAEA,UAAU,OAAO;aACjB;aACA;aACA;;aAEA;;aAEA;;EAEX;aACW;;aAEA,QAAQ;;aAER,QAAQ;;EAEnB;aACW;aACA,UAAU,OAAO;aACjB;aACA;;aAEA,QAAQ;;;cAGR,gBAAc,KAAA,WAAA;;WARH;WACD,UAAA,OAAO;WACT;WACJ;WAEI,QAAA;;;WAZI;WAEJ,QAAA;WAEA,QAAA;;;WAhBG;WAED,UAAA,OAAO;WACT;WACJ;WACG;WAEA;WAEG;;;;;;;UAyBN,2BAA2B;WACjC;WACA,MAAM;;;;;;UAOA,qBAAqB;WAC3B;WACA;WACA,UAAU,OAAO;WACjB,OAAO;;;;;;;UAQD,oBAAoB;WAC1B;;WAEA;WACA,OAAO;;;;;;;;UASD,yBAAyB;WAC/B;;WAEA;WACA;;;;;;;UAQM,sBAAsB;WAC5B;WACA;WACA;;;KAIC,mBACR,cACA,mBACA,gBACA,qBACA;cAUS,qBAAkB,MAAU,mBAAiB;cAe7C,eAAY,OAChB,KAAK,sDACX;cAQU,cAAW,OAAW,KAAK,qCAAmC;cAQ9D,mBAAgB,OACpB,KAAK,8CACX;cAQU,gBAAa,OAAW,KAAK,qCAAmC;;cAehE,kBAAe,MACpB,cAAc,mBAAiB,UAC3B,cAAc,sBACvB,cAAc"}
@@ -0,0 +1,2 @@
1
+ import { a as PredictionPart, c as liveRefused, d as predictionMismatch, f as withDiagnostics, i as PredictionMismatch, l as outboxUnreadable, n as OutboxUnreadable, o as RemoteDiagnostic, p as writeUnheard, r as OutboxUnsaved, s as WriteUnheard, t as LiveRefused, u as outboxUnsaved } from "./diagnostics-DHhVYflV.js";
2
+ export { LiveRefused, OutboxUnreadable, OutboxUnsaved, PredictionMismatch, PredictionPart, RemoteDiagnostic, WriteUnheard, liveRefused, outboxUnreadable, outboxUnsaved, predictionMismatch, withDiagnostics, writeUnheard };
@@ -0,0 +1,60 @@
1
+ import { Data, Option } from "effect";
2
+ // src/diagnostics.ts
3
+ /**
4
+ * What Remote's client meets and keeps going past, as diagnostics: a
5
+ * prediction the server's answer disagreed with (`verifyPredictions`), a
6
+ * failed write the application does not hear, and a live stream refused. The
7
+ * reducer records each in the Model's `diagnostics`; the wiring and
8
+ * `Remote.fold` report what an update recorded.
9
+ */
10
+ const source = "foldkit-remote";
11
+ const PredictionPart = Data.taggedEnum();
12
+ const named = (mutation, requestId) => Option.match(mutation, {
13
+ onNone: () => `Request ${requestId}`,
14
+ onSome: (name) => `${name} (request ${requestId})`
15
+ });
16
+ const shownAs = (value) => JSON.stringify(value) ?? String(value);
17
+ const predictionMismatch = (part) => ({
18
+ _tag: "PredictionMismatch",
19
+ source,
20
+ level: "warning",
21
+ message: PredictionPart.$match(part, {
22
+ Value: (facts) => `${named(facts.mutation, facts.requestId)} showed ${facts.entity}:${facts.id}.${facts.field} as ${shownAs(facts.shown)} while it was pending, and the server answered ${shownAs(facts.answered)}: the client's prediction and the server's write disagree.`,
23
+ Placement: (facts) => `The client placed rows in ${facts.connection} as [${facts.placed.join(", ")}], and the server's first page lists [${facts.served.join(", ")}]: the client's order and the server's disagree.`,
24
+ Gap: (facts) => `${named(facts.mutation, facts.requestId)} answered ${facts.entity}:${facts.id} without ${facts.fields.join(", ")}, which the client showed while it was pending. They are read again, so the row reads Loading meanwhile: answer with them, or select fewer.`
25
+ }),
26
+ part
27
+ });
28
+ const writeUnheard = (facts) => ({
29
+ _tag: "WriteUnheard",
30
+ source,
31
+ level: "warning",
32
+ message: `${named(facts.mutation, facts.requestId)} failed (${facts.error._tag}: ${facts.error.message}) and the application's update does not hear it, so its change went with no word. Share MutationFailed (Data.wiring(actives, { shared: ['MutationFailed'] })) and show Data.failedWrites.`,
33
+ ...facts
34
+ });
35
+ const liveRefused = (facts) => ({
36
+ _tag: "LiveRefused",
37
+ source,
38
+ level: "warning",
39
+ message: `The server refused a live stream (${facts.error.message}), so what it asks is not live and is not asked again until it changes. Watch fewer rows at once, or raise the server's maxIdsPerEntity.`,
40
+ ...facts
41
+ });
42
+ const outboxUnreadable = (facts) => ({
43
+ _tag: "OutboxUnreadable",
44
+ source,
45
+ level: "warning",
46
+ message: `A stored write (${facts.requestId}) cannot be sent: ${facts.reason}. It was made by an earlier version of the application; it is kept until Data.dismiss, and the writes after it are sent.`,
47
+ ...facts
48
+ });
49
+ const outboxUnsaved = (facts) => ({
50
+ _tag: "OutboxUnsaved",
51
+ source,
52
+ level: "warning",
53
+ message: `The outbox could not write ${facts.key} (${facts.reason}). Its writes are sent, but a reload before they are answered loses them.`,
54
+ ...facts
55
+ });
56
+ /** `kept` with `recorded` after it, within the window; `kept` itself when nothing was recorded. */
57
+ const withDiagnostics = (kept, recorded) => recorded.length === 0 ? kept : [...kept, ...recorded].slice(-256);
58
+ export { PredictionPart, liveRefused, outboxUnreadable, outboxUnsaved, predictionMismatch, withDiagnostics, writeUnheard };
59
+
60
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","names":[],"sources":["../src/diagnostics.ts"],"sourcesContent":["/**\n * What Remote's client meets and keeps going past, as diagnostics: a\n * prediction the server's answer disagreed with (`verifyPredictions`), a\n * failed write the application does not hear, and a live stream refused. The\n * reducer records each in the Model's `diagnostics`; the wiring and\n * `Remote.fold` report what an update recorded.\n */\nimport { Data, Option } from 'effect'\nimport type { Diagnostic } from 'foldkit-surface'\nimport type { RemoteError } from './remoteData.js'\n\nconst source = 'foldkit-remote'\n\n/**\n * Which part of a prediction the server's answer disagreed with. `Value`: a\n * field a pending write showed, answered with another value. `Placement`: a\n * list the client placed rows in, which the server's first page lists\n * otherwise. `Gap`: a row whose answer left out fields the client showed,\n * so they are read again and the row reads `Loading` meanwhile.\n */\nexport type PredictionPart = Data.TaggedEnum<{\n Value: {\n /** The request the answer settled, as `Data.mutate` returned it. */\n readonly requestId: string\n /** The mutation's name, when the request was started with one (`Data.mutate` always is). */\n readonly mutation: Option.Option<string>\n readonly entity: string\n readonly id: string\n readonly field: string\n /** What the client showed while the write was pending, encoded. */\n readonly shown: unknown\n /** What the answer holds, encoded. */\n readonly answered: unknown\n }\n Placement: {\n readonly connection: string\n /** The keys as placed, as far as the server's page reached. */\n readonly placed: ReadonlyArray<string>\n /** The keys of the server's first page. */\n readonly served: ReadonlyArray<string>\n }\n Gap: {\n readonly requestId: string\n readonly mutation: Option.Option<string>\n readonly entity: string\n readonly id: string\n /** The fields shown and not answered, which the store does not otherwise hold. */\n readonly fields: ReadonlyArray<string>\n }\n}>\nexport const PredictionPart = Data.taggedEnum<PredictionPart>()\n\n/**\n * Under `verifyPredictions`, a part the client predicted that the server's\n * answer disagreed with: where the client's evaluation is not unknown, it\n * should equal the server's (operations-phase6-DESIGN §2).\n */\nexport interface PredictionMismatch extends Diagnostic {\n readonly _tag: 'PredictionMismatch'\n readonly part: PredictionPart\n}\n\n/**\n * A write that failed while the application's own `update` does not receive\n * `MutationFailed`: its optimistic change went, and nothing answered it.\n */\nexport interface WriteUnheard extends Diagnostic {\n readonly _tag: 'WriteUnheard'\n readonly requestId: string\n readonly mutation: Option.Option<string>\n readonly error: RemoteError\n}\n\n/**\n * A live stream the server refused for what it asks (`RemoteLiveRefused`):\n * more rows of one Entity than its `maxIdsPerEntity`. It is not reopened\n * until what it asks changes, so those rows are not live meanwhile.\n */\nexport interface LiveRefused extends Diagnostic {\n readonly _tag: 'LiveRefused'\n /** The stream's key, as `Data.liveStatus` and the Model's `streams` name it. */\n readonly stream: string\n readonly error: RemoteError\n}\n\n/**\n * A durable write the outbox read back and cannot send: stored by a version\n * of the application that registered a Mutation this one lacks, or whose\n * input this one's `Input` no longer decodes. It is kept, shown no layer and\n * never sent, and the writes after it are sent.\n */\nexport interface OutboxUnreadable extends Diagnostic {\n readonly _tag: 'OutboxUnreadable'\n /** Its operation id, which `Data.dismiss` takes. */\n readonly requestId: string\n readonly reason: string\n}\n\n/**\n * The outbox could not write its store (it is full, or the browser refuses\n * storage): its writes are still sent, but a reload before they are answered\n * loses them.\n */\nexport interface OutboxUnsaved extends Diagnostic {\n readonly _tag: 'OutboxUnsaved'\n readonly key: string\n readonly reason: string\n}\n\n/** Every diagnostic Remote's client records. */\nexport type RemoteDiagnostic =\n | LiveRefused\n | OutboxUnreadable\n | OutboxUnsaved\n | PredictionMismatch\n | WriteUnheard\n\nconst named = (mutation: Option.Option<string>, requestId: string): string =>\n Option.match(mutation, {\n onNone: () => `Request ${requestId}`,\n onSome: name => `${name} (request ${requestId})`,\n })\n\nconst shownAs = (value: unknown): string => JSON.stringify(value) ?? String(value)\n\nexport const predictionMismatch = (part: PredictionPart): PredictionMismatch => ({\n _tag: 'PredictionMismatch',\n source,\n level: 'warning',\n message: PredictionPart.$match(part, {\n Value: facts =>\n `${named(facts.mutation, facts.requestId)} showed ${facts.entity}:${facts.id}.${facts.field} as ${shownAs(facts.shown)} while it was pending, and the server answered ${shownAs(facts.answered)}: the client's prediction and the server's write disagree.`,\n Placement: facts =>\n `The client placed rows in ${facts.connection} as [${facts.placed.join(', ')}], and the server's first page lists [${facts.served.join(', ')}]: the client's order and the server's disagree.`,\n Gap: facts =>\n `${named(facts.mutation, facts.requestId)} answered ${facts.entity}:${facts.id} without ${facts.fields.join(', ')}, which the client showed while it was pending. They are read again, so the row reads Loading meanwhile: answer with them, or select fewer.`,\n }),\n part,\n})\n\nexport const writeUnheard = (\n facts: Pick<WriteUnheard, 'requestId' | 'mutation' | 'error'>,\n): WriteUnheard => ({\n _tag: 'WriteUnheard',\n source,\n level: 'warning',\n message: `${named(facts.mutation, facts.requestId)} failed (${facts.error._tag}: ${facts.error.message}) and the application's update does not hear it, so its change went with no word. Share MutationFailed (Data.wiring(actives, { shared: ['MutationFailed'] })) and show Data.failedWrites.`,\n ...facts,\n})\n\nexport const liveRefused = (facts: Pick<LiveRefused, 'stream' | 'error'>): LiveRefused => ({\n _tag: 'LiveRefused',\n source,\n level: 'warning',\n message: `The server refused a live stream (${facts.error.message}), so what it asks is not live and is not asked again until it changes. Watch fewer rows at once, or raise the server's maxIdsPerEntity.`,\n ...facts,\n})\n\nexport const outboxUnreadable = (\n facts: Pick<OutboxUnreadable, 'requestId' | 'reason'>,\n): OutboxUnreadable => ({\n _tag: 'OutboxUnreadable',\n source,\n level: 'warning',\n message: `A stored write (${facts.requestId}) cannot be sent: ${facts.reason}. It was made by an earlier version of the application; it is kept until Data.dismiss, and the writes after it are sent.`,\n ...facts,\n})\n\nexport const outboxUnsaved = (facts: Pick<OutboxUnsaved, 'key' | 'reason'>): OutboxUnsaved => ({\n _tag: 'OutboxUnsaved',\n source,\n level: 'warning',\n message: `The outbox could not write ${facts.key} (${facts.reason}). Its writes are sent, but a reload before they are answered loses them.`,\n ...facts,\n})\n\n/**\n * How many diagnostics the Model keeps, the newest. Each was reported as it\n * was recorded; the bound keeps a long session's failed writes from growing it.\n */\nconst DIAGNOSTIC_WINDOW = 256\n\n/** `kept` with `recorded` after it, within the window; `kept` itself when nothing was recorded. */\nexport const withDiagnostics = (\n kept: ReadonlyArray<RemoteDiagnostic>,\n recorded: ReadonlyArray<RemoteDiagnostic>,\n): ReadonlyArray<RemoteDiagnostic> =>\n recorded.length === 0 ? kept : [...kept, ...recorded].slice(-DIAGNOSTIC_WINDOW)\n"],"mappings":";;;;;;;;;AAWA,MAAM,SAAS;AAuCf,MAAa,iBAAiB,KAAK,WAA2B;AAmE9D,MAAM,SAAS,UAAiC,cAC9C,OAAO,MAAM,UAAU;CACrB,cAAc,WAAW;CACzB,SAAQ,SAAQ,GAAG,KAAK,YAAY,UAAU;AAChD,CAAC;AAEH,MAAM,WAAW,UAA2B,KAAK,UAAU,KAAK,KAAK,OAAO,KAAK;AAEjF,MAAa,sBAAsB,UAA8C;CAC/E,MAAM;CACN;CACA,OAAO;CACP,SAAS,eAAe,OAAO,MAAM;EACnC,QAAO,UACL,GAAG,MAAM,MAAM,UAAU,MAAM,SAAS,EAAE,UAAU,MAAM,OAAO,GAAG,MAAM,GAAG,GAAG,MAAM,MAAM,MAAM,QAAQ,MAAM,KAAK,EAAE,iDAAiD,QAAQ,MAAM,QAAQ,EAAE;EAClM,YAAW,UACT,6BAA6B,MAAM,WAAW,OAAO,MAAM,OAAO,KAAK,IAAI,EAAE,wCAAwC,MAAM,OAAO,KAAK,IAAI,EAAE;EAC/I,MAAK,UACH,GAAG,MAAM,MAAM,UAAU,MAAM,SAAS,EAAE,YAAY,MAAM,OAAO,GAAG,MAAM,GAAG,WAAW,MAAM,OAAO,KAAK,IAAI,EAAE;CACtH,CAAC;CACD;AACF;AAEA,MAAa,gBACX,WACkB;CAClB,MAAM;CACN;CACA,OAAO;CACP,SAAS,GAAG,MAAM,MAAM,UAAU,MAAM,SAAS,EAAE,WAAW,MAAM,MAAM,KAAK,IAAI,MAAM,MAAM,QAAQ;CACvG,GAAG;AACL;AAEA,MAAa,eAAe,WAA+D;CACzF,MAAM;CACN;CACA,OAAO;CACP,SAAS,qCAAqC,MAAM,MAAM,QAAQ;CAClE,GAAG;AACL;AAEA,MAAa,oBACX,WACsB;CACtB,MAAM;CACN;CACA,OAAO;CACP,SAAS,mBAAmB,MAAM,UAAU,oBAAoB,MAAM,OAAO;CAC7E,GAAG;AACL;AAEA,MAAa,iBAAiB,WAAiE;CAC7F,MAAM;CACN;CACA,OAAO;CACP,SAAS,8BAA8B,MAAM,IAAI,IAAI,MAAM,OAAO;CAClE,GAAG;AACL;;AASA,MAAa,mBACX,MACA,aAEA,SAAS,WAAW,IAAI,OAAO,CAAC,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC,MAAM,IAAkB"}
@@ -0,0 +1,196 @@
1
+ import { r as EntityStore } from "./store-ah2qjcJW.js";
2
+ import { l as QueryWindow } from "./query-BuIU93xA.js";
3
+ import { n as RelationRequirement } from "./requirement-D57S2LpH.js";
4
+ import { u as refParts } from "./relation-BLBGOZom.js";
5
+ import { Schema } from "effect";
6
+ import * as Domain from "foldkit-entity";
7
+ /** One page of a paginated relation with each target assembled through a nested selection. */
8
+ interface Page<Item> {
9
+ readonly items: ReadonlyArray<Item>;
10
+ readonly hasNext: boolean;
11
+ readonly hasPrevious: boolean;
12
+ }
13
+ /**
14
+ * The fields a projection reads of one entity, plus the slice it reads of each
15
+ * relation's target. `Shape` tells a parent selection whether this one is a
16
+ * paginated relation (`connection`) or a plain entity slice (`entity`).
17
+ */
18
+ interface Selection<Value, Name extends string = string, Shape extends 'entity' | 'connection' = 'entity' | 'connection'> {
19
+ readonly entity: Name;
20
+ readonly fields: readonly string[];
21
+ /** A pure codec: entity fields carry no decoding or encoding services. */
22
+ readonly schema: Schema.Codec<Value, unknown, never, never>;
23
+ /** Pagination windows for nested relation fields, keyed by field name. */
24
+ readonly connections?: Readonly<Record<string, QueryWindow>> | undefined;
25
+ /** The slice required of each nested relation's target, keyed by field name. */
26
+ readonly relations?: Readonly<Record<string, RelationRequirement>> | undefined;
27
+ /** Present when this selection is itself a paginated relation. */
28
+ readonly window?: QueryWindow | undefined;
29
+ /** Phantom: see `Shape`. */
30
+ readonly shape?: Shape | undefined;
31
+ }
32
+ /** Flattens a mapped type so hovers show the picked fields, not the machinery. */
33
+ type Simplify<T> = T extends (infer O) ? { readonly [K in keyof O]: O[K]; } : never;
34
+ /** The value a Selection reads: `Selection.Value<typeof ProjectCard>`. */
35
+ type SelectionValueOf<S> = S extends Selection<infer V, any, any> ? V : never;
36
+ /** The nested selections a relation field admits: of its target entity, in the shapes its value takes. */
37
+ type NestedFor<Field> = Exclude<Field, null | undefined> extends ReadonlyArray<EntityRef$1<infer Name, any>> ? Selection<unknown, Name, 'entity' | 'connection'> : Exclude<Field, null | undefined> extends RefPage<infer Name, any> ? Selection<unknown, Name, 'entity' | 'connection'> : Exclude<Field, null | undefined> extends EntityRef$1<infer Name, any> ? Selection<unknown, Name, 'entity'> : never;
38
+ /** What a selection of an entity with fields `F` may pick: `true` per scalar, a nested selection per relation. */
39
+ type SelectionOf<F extends Schema.Struct.Fields> = { readonly [K in keyof F]?: true | NestedFor<Schema.Schema.Type<F[K]>>; };
40
+ /** `T | null` when the field admits `null` or `undefined` (both assemble to `null`). */
41
+ type Nullable<Field, T> = [Extract<Field, null | undefined>] extends [never] ? T : T | null;
42
+ /** A nested selection's value takes the shape of the field it selects through. */
43
+ type NestedValue<Field, Sel> = Sel extends Selection<infer V, string, 'connection'> ? Nullable<Field, V> : Sel extends Selection<infer V, string, 'entity'> ? Nullable<Field, Exclude<Field, null | undefined> extends ReadonlyArray<EntityRef$1<any, any>> ? ReadonlyArray<V> : Exclude<Field, null | undefined> extends RefPage<any, any> ? Page<V> : V> : never;
44
+ /** The value a selection `Sel` of fields `F` reads. */
45
+ type SelectionValue<F extends Schema.Struct.Fields, Sel> = Simplify<{ readonly [K in keyof Sel & keyof F]: Sel[K] extends true ? Schema.Schema.Type<F[K]> : NestedValue<Schema.Schema.Type<F[K]>, Sel[K]>; }>;
46
+ declare const pageSchema: (item: AnySchema) => AnySchema;
47
+ /** The requirement a nested selection contributes for its relation's target. */
48
+ declare const relationOf: (selection: Selection<unknown>) => RelationRequirement;
49
+ declare const Selection: {
50
+ /**
51
+ * The Remote Selection of a `foldkit-entity` Selection: the same members, read
52
+ * from Remote's store. `true` on a relation reads its refs, as it does here.
53
+ */
54
+ from: <Name extends string, S extends Schema.Constraint>(selection: Domain.Selection<Name, unknown, S>) => Selection<S['Type'], Name, 'entity'>;
55
+ /**
56
+ * The fields to read of `entity`. A nested `Selection` on a relation field
57
+ * reads through the ref (or refs, or page of refs) the field holds into the
58
+ * target's fields; a scalar field cannot take one.
59
+ */
60
+ make: <Name extends string, F extends Schema.Struct.Fields, const Sel extends SelectionOf<F>>(entity: EntityDescriptor<Name, F>, selection: Sel) => Selection<SelectionValue<F, Sel>, Name, 'entity'>;
61
+ /**
62
+ * A paginated relation: one page of refs to `entity` with a window, or, with
63
+ * a nested selection, one page of targets assembled through it.
64
+ */
65
+ connection: {
66
+ <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>, window: QueryWindow): Selection<RefPage<Name, F>, Name, 'connection'>;
67
+ <Name extends string, F extends Schema.Struct.Fields, Item>(entity: EntityDescriptor<Name, F>, window: QueryWindow, selection: Selection<Item, NoInfer<Name>, 'entity'>): Selection<Page<Item>, Name, 'connection'>;
68
+ };
69
+ };
70
+ interface Assembled {
71
+ readonly values: unknown;
72
+ readonly refreshing: boolean;
73
+ }
74
+ /**
75
+ * Reads an entity's selected fields out of the store, following each nested
76
+ * relation into its targets. `undefined` means some field, at any depth, is
77
+ * not present yet. A tombstoned target reads as `null` (or is dropped from a
78
+ * list), so the Selection's codec decides whether that is a failure.
79
+ */
80
+ declare const assemble: (store: EntityStore, key: string, requirement: RelationRequirement) => Assembled | undefined;
81
+ /**
82
+ * The first field `requirement` reads, at any depth, that the server settled
83
+ * without a value, as `Entity:id.field`. A read that consults it says why it
84
+ * cannot assemble rather than waiting on a field nothing will fetch.
85
+ */
86
+ declare const unavailableOf: (store: EntityStore, key: string, requirement: RelationRequirement) => string | undefined;
87
+ type AnySchema = Schema.Schema<unknown>;
88
+ declare const entityRefFields: unique symbol;
89
+ /**
90
+ * A normalized reference to an entity. `F` is a phantom carrying the entity's
91
+ * fields so `Entity.patch` can type its patch; it is absent at runtime.
92
+ */
93
+ interface EntityRef$1<Name extends string, F extends Schema.Struct.Fields = Schema.Struct.Fields> {
94
+ readonly entity: Name;
95
+ readonly id: string;
96
+ readonly [entityRefFields]?: F;
97
+ }
98
+ interface EntityDescriptor<Name extends string, F extends Schema.Struct.Fields> {
99
+ readonly name: Name;
100
+ readonly schema: Schema.Struct<F>;
101
+ readonly fields: F;
102
+ ref(id: Schema.Schema.Type<F['id']>): EntityRef$1<Name, F>;
103
+ /** The fields a Surface reads of this entity; `Selection.make(entity, …)` with the entity as receiver. */
104
+ select<const Sel extends SelectionOf<F>>(selection: Sel): Selection<SelectionValue<F, Sel>, Name, 'entity'>;
105
+ /** A patch of this entity's wire-shaped values; `Entity.patch(entity.ref(id), values)`. */
106
+ patch(id: Schema.Schema.Type<F['id']>, values: Partial<Schema.Struct.Encoded<F>>): EntityPatch<Name, F>;
107
+ }
108
+ /**
109
+ * Relations are **references**, never inline target schemas: a ref cannot
110
+ * reconstruct a full entity, and dereferencing is a store concern. Because the
111
+ * target schema is not inlined, recursive relations cannot arise through the
112
+ * schema graph.
113
+ */
114
+ /**
115
+ * A ref as the wire carries it: the target's name, a colon, and its id. Typed
116
+ * with the name, so a relation to `User` takes `'User:u1'` and not a ref to
117
+ * some other entity, which would read as a row that does not exist.
118
+ */
119
+ type RefKey<Name extends string> = `${Name}:${string}`;
120
+ /**
121
+ * A patch in wire shape: the values the store holds, so a relation is its ref
122
+ * key (`Entity.refKey`), not an `EntityRef`.
123
+ */
124
+ interface EntityPatch<Name extends string, F extends Schema.Struct.Fields> {
125
+ readonly entity: Name;
126
+ readonly id: string;
127
+ readonly values: Partial<Schema.Struct.Encoded<F>>;
128
+ }
129
+ /** What a relation field decodes to: a ref, refs, or a page of refs, perhaps null. */
130
+ type IsRelation<T> = [NonNullable<T>] extends [never] ? false : [NonNullable<T>] extends [EntityRef$1<string, any> | ReadonlyArray<EntityRef$1<string, any>> | RefPage<string, any>] ? true : false;
131
+ /**
132
+ * `Remote.patch`'s values: each field's wire shape, except a relation, which
133
+ * takes what it decodes to (`Remote.ref(User, id)`, an array of refs, a page
134
+ * of refs, or `null` where it is optional), never a ref key typed by hand.
135
+ */
136
+ type PatchValues<F extends Schema.Struct.Fields> = { readonly [K in keyof Schema.Struct.Encoded<F>]?: K extends keyof Schema.Struct.Type<F> ? IsRelation<Schema.Struct.Type<F>[K]> extends true ? Schema.Struct.Type<F>[K] : Schema.Struct.Encoded<F>[K] : Schema.Struct.Encoded<F>[K]; };
137
+ /**
138
+ * One authoritative page of a paginated relation: refs (never inline entities)
139
+ * plus whether more exist. The adapter does not hold segmentation state; the
140
+ * client merges pages.
141
+ */
142
+ interface RefPage<Name extends string, F extends Schema.Struct.Fields = Schema.Struct.Fields> {
143
+ readonly refs: ReadonlyArray<EntityRef$1<Name, F>>;
144
+ readonly hasNext: boolean;
145
+ readonly hasPrevious: boolean;
146
+ }
147
+ /** The ref codec a `foldkit-entity` relation becomes: one ref, a nullable ref, or an array of refs. */
148
+ type RelationField<Spec> = Spec extends Domain.RelationSpec<infer Target, infer Cardinality, infer Optional> ? Cardinality extends 'many' ? Schema.$Array<Schema.Codec<EntityRef$1<Target['name']>, RefKey<Target['name']>>> : Optional extends true ? Schema.NullOr<Schema.Codec<EntityRef$1<Target['name']>, RefKey<Target['name']>>> : Schema.Codec<EntityRef$1<Target['name']>, RefKey<Target['name']>> : never;
149
+ /**
150
+ * The fields Remote stores for a `foldkit-entity` Entity: its own fields, its
151
+ * derived members (the server supplies them like any field), and each relation
152
+ * as refs.
153
+ */
154
+ type FieldsFrom<E> = E extends Domain.Entity<any, infer Fields, infer Relations, infer Derived> ? Fields & { readonly [K in keyof Derived]: Derived[K]['schema']; } & { readonly [K in keyof Relations]: RelationField<Relations[K]>; } : never;
155
+ declare const Entity$1: {
156
+ /**
157
+ * The Remote descriptor of a `foldkit-entity` Entity. Relations declared with
158
+ * `Entity.relate` become ref fields, so the store, the planner, and the server
159
+ * treat it as they treat an `Entity.make` descriptor.
160
+ */
161
+ from: <E extends Domain.AnyEntity>(entity: E & {
162
+ readonly fields: {
163
+ readonly id: unknown;
164
+ };
165
+ }) => EntityDescriptor<E['name'], FieldsFrom<E>>;
166
+ make: <const Name extends string, const F extends Schema.Struct.Fields & {
167
+ readonly id: Schema.Schema<unknown>;
168
+ }>(name: Name, schema: Schema.Struct<F>) => EntityDescriptor<Name, F>;
169
+ /** A relation to a known entity, decoded as a reference. */
170
+ ref: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<EntityRef$1<Name, F>, RefKey<Name>>;
171
+ /** A relation by name, for recursive or forward references. */
172
+ refTo: <Name extends string>(name: Name) => Schema.Codec<EntityRef$1<Name>, RefKey<Name>>;
173
+ /**
174
+ * The wire key a relation field carries (`"Entity:id"`). Adapters that read a
175
+ * foreign key emit this so the ref codec can decode it on the client.
176
+ */
177
+ refKey: (ref: {
178
+ readonly entity: string;
179
+ readonly id: string;
180
+ }) => string;
181
+ /** Splits a ref key back into its entity and id. */
182
+ refParts: typeof refParts;
183
+ /** A relation value of one authoritative page of refs. */
184
+ refPage: <Name extends string, F extends Schema.Struct.Fields>(entity: EntityDescriptor<Name, F>) => Schema.Codec<RefPage<Name, F>, {
185
+ readonly refs: ReadonlyArray<string>;
186
+ readonly hasNext: boolean;
187
+ readonly hasPrevious: boolean;
188
+ }>;
189
+ /**
190
+ * A normalized patch for an entity, typed against its fields' wire shape:
191
+ * write a relation as its ref key (`Entity.refKey`), as the server does.
192
+ */
193
+ patch: <Name extends string, F extends Schema.Struct.Fields>(ref: EntityRef$1<Name, F>, patch: Partial<Schema.Struct.Encoded<F>>) => EntityPatch<Name, F>;
194
+ };
195
+ export { relationOf as _, EntityRef$1 as a, RefKey as c, Selection as d, SelectionOf as f, pageSchema as g, assemble as h, EntityPatch as i, RefPage as l, SelectionValueOf as m, Entity$1 as n, FieldsFrom as o, SelectionValue as p, EntityDescriptor as r, PatchValues as s, AnySchema as t, Page as u, unavailableOf as v };
196
+ //# sourceMappingURL=entity-CgsG5Uel.d.ts.map