@prestack/thread 0.1.2 → 0.1.4

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 (265) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/dist/core/actor.d.ts +1 -1
  3. package/dist/core/actor.js +5 -4
  4. package/dist/core/actor.ts +5 -4
  5. package/dist/core/attach.d.ts +0 -7
  6. package/dist/core/attach.js +67 -58
  7. package/dist/core/attach.ts +61 -68
  8. package/dist/core/chain.js +13 -17
  9. package/dist/core/chain.ts +11 -15
  10. package/dist/core/condition.d.ts +4 -4
  11. package/dist/core/condition.js +2 -2
  12. package/dist/core/descend.d.ts +4 -2
  13. package/dist/core/descend.js +89 -21
  14. package/dist/core/descend.ts +86 -17
  15. package/dist/core/errors/catalogue.d.ts +52 -0
  16. package/dist/{operations/errors/errors.js → core/errors/catalogue.js} +1 -1
  17. package/dist/{operations/errors/errors.ts → core/errors/catalogue.ts} +1 -1
  18. package/dist/{operations/errors/catalog.d.ts → core/errors/error.d.ts} +2 -3
  19. package/dist/{operations/errors/catalog.js → core/errors/error.js} +1 -16
  20. package/dist/{operations/errors/catalog.ts → core/errors/error.ts} +3 -19
  21. package/dist/core/errors/namespaces.d.ts +3 -0
  22. package/dist/core/errors/namespaces.js +15 -0
  23. package/dist/core/errors/namespaces.ts +19 -0
  24. package/dist/core/finding.js +2 -2
  25. package/dist/core/finding.ts +1 -2
  26. package/dist/core/init.d.ts +0 -2
  27. package/dist/core/init.js +51 -15
  28. package/dist/core/init.ts +58 -15
  29. package/dist/core/invoked.d.ts +1 -1
  30. package/dist/core/invoked.js +3 -1
  31. package/dist/core/invoked.ts +5 -2
  32. package/dist/core/round.js +36 -22
  33. package/dist/core/round.ts +26 -9
  34. package/dist/core/rows.d.ts +4 -0
  35. package/dist/core/rows.js +31 -2
  36. package/dist/core/rows.ts +33 -1
  37. package/dist/core/thread.d.ts +3 -3
  38. package/dist/core/tree.d.ts +4 -1
  39. package/dist/core/tree.js +26 -6
  40. package/dist/core/tree.ts +29 -6
  41. package/dist/core/types.d.ts +3 -3
  42. package/dist/core/types.js +3 -1
  43. package/dist/core/types.ts +2 -1
  44. package/dist/derivation/attach.js +1 -1
  45. package/dist/derivation/generators/build.js +6 -6
  46. package/dist/derivation/generators/build.ts +1 -1
  47. package/dist/derivation/generators/check.js +1 -1
  48. package/dist/derivation/generators/determinism.js +1 -1
  49. package/dist/derivation/generators/release.js +60 -47
  50. package/dist/derivation/generators/release.ts +66 -43
  51. package/dist/derivation/release.d.ts +7 -3
  52. package/dist/derivation/release.js +14 -1
  53. package/dist/derivation/release.ts +22 -2
  54. package/dist/integrations/attach.d.ts +4 -0
  55. package/dist/integrations/attach.js +33 -54
  56. package/dist/integrations/attach.ts +50 -57
  57. package/dist/integrations/cli.d.ts +37 -0
  58. package/dist/integrations/cli.js +440 -0
  59. package/dist/integrations/cli.ts +543 -0
  60. package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -20
  61. package/dist/integrations/disk.js +435 -0
  62. package/dist/integrations/disk.ts +465 -0
  63. package/dist/integrations/generators/read.js +6 -6
  64. package/dist/integrations/generators/read.ts +4 -4
  65. package/dist/integrations/generators/vault.js +10 -11
  66. package/dist/integrations/generators/vault.ts +4 -5
  67. package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
  68. package/dist/integrations/https.js +170 -0
  69. package/dist/integrations/https.ts +216 -0
  70. package/dist/integrations/pglite.d.ts +26 -0
  71. package/dist/integrations/pglite.js +143 -0
  72. package/dist/integrations/pglite.ts +206 -0
  73. package/dist/integrations/secret.d.ts +8 -2
  74. package/dist/integrations/secret.js +3 -5
  75. package/dist/integrations/secret.ts +10 -6
  76. package/dist/integrations/target.d.ts +155 -14
  77. package/dist/integrations/target.js +171 -50
  78. package/dist/integrations/target.ts +377 -61
  79. package/dist/integrations/vault.d.ts +1 -0
  80. package/dist/integrations/vault.js +20 -5
  81. package/dist/integrations/vault.ts +17 -5
  82. package/dist/integrity/attach.js +3 -73
  83. package/dist/integrity/attach.ts +1 -71
  84. package/dist/integrity/check-threads.js +5 -5
  85. package/dist/integrity/check-threads.ts +2 -2
  86. package/dist/integrity/constraint.d.ts +0 -1
  87. package/dist/integrity/constraint.js +267 -366
  88. package/dist/integrity/constraint.ts +267 -375
  89. package/dist/integrity/generators/compiler.js +14 -17
  90. package/dist/integrity/generators/compiler.ts +10 -15
  91. package/dist/integrity/generators/gate.js +15 -15
  92. package/dist/integrity/generators/gate.ts +10 -10
  93. package/dist/integrity/generators/issues.js +7 -7
  94. package/dist/integrity/generators/publish.js +39 -57
  95. package/dist/integrity/generators/publish.ts +44 -55
  96. package/dist/integrity/generators/trial.d.ts +3 -3
  97. package/dist/integrity/generators/trial.js +133 -161
  98. package/dist/integrity/generators/trial.ts +145 -165
  99. package/dist/integrity/lint.js +9 -13
  100. package/dist/integrity/lint.ts +7 -10
  101. package/dist/integrity/lsp/bin.js +5 -4
  102. package/dist/integrity/lsp/bin.ts +3 -1
  103. package/dist/integrity/lsp/diagnostics.js +3 -3
  104. package/dist/integrity/lsp/diagnostics.ts +1 -1
  105. package/dist/integrity/lsp/lint.js +19 -30
  106. package/dist/integrity/lsp/lint.ts +16 -32
  107. package/dist/integrity/lsp/server.js +3 -3
  108. package/dist/integrity/slopnator.d.ts +3 -13
  109. package/dist/integrity/slopnator.js +58 -37
  110. package/dist/integrity/slopnator.ts +53 -37
  111. package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
  112. package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
  113. package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
  114. package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
  115. package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
  116. package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
  117. package/dist/integrity/slopnators/sl_inert_island.js +10 -8
  118. package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
  119. package/dist/integrity/slopnators/sl_missing_row.js +6 -51
  120. package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
  121. package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
  122. package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
  123. package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
  124. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
  125. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
  126. package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
  127. package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
  128. package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
  129. package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
  130. package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
  131. package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
  132. package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
  133. package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
  134. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
  135. package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
  136. package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
  137. package/dist/integrity/slopnators/sl_stale_path.js +5 -22
  138. package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
  139. package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
  140. package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
  141. package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
  142. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
  143. package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
  144. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
  145. package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
  146. package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
  147. package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
  148. package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
  149. package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
  150. package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
  151. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
  152. package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
  153. package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
  154. package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
  155. package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
  156. package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
  157. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
  158. package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
  159. package/dist/integrity/slopnators/sl_underived_route.js +61 -0
  160. package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
  161. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
  162. package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
  163. package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
  164. package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
  165. package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
  166. package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
  167. package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
  168. package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
  169. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
  170. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
  171. package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
  172. package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
  173. package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
  174. package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
  175. package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
  176. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
  177. package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
  178. package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
  179. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
  180. package/dist/integrity/slopnators/sl_unversioned.js +6 -4
  181. package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
  182. package/dist/integrity/sweep.d.ts +1 -0
  183. package/dist/integrity/sweep.js +105 -42
  184. package/dist/integrity/sweep.ts +115 -42
  185. package/dist/knowledge/attach.js +1 -1
  186. package/dist/knowledge/generators/docsgen.js +8 -6
  187. package/dist/knowledge/generators/docsgen.ts +4 -2
  188. package/dist/knowledge/generators/glossary.js +4 -4
  189. package/dist/knowledge/generators/glossary.ts +1 -1
  190. package/dist/operations/access.d.ts +23 -0
  191. package/dist/operations/access.js +28 -1
  192. package/dist/operations/access.ts +43 -0
  193. package/dist/operations/attach.js +28 -109
  194. package/dist/operations/attach.ts +46 -113
  195. package/dist/operations/capabilities.d.ts +14 -5
  196. package/dist/operations/capabilities.js +13 -4
  197. package/dist/operations/capabilities.ts +27 -8
  198. package/dist/operations/dispatch.d.ts +8 -2
  199. package/dist/operations/dispatch.js +128 -185
  200. package/dist/operations/dispatch.ts +138 -191
  201. package/dist/operations/error-results.d.ts +1 -1
  202. package/dist/operations/error-results.js +2 -2
  203. package/dist/operations/error-results.ts +2 -2
  204. package/dist/operations/generators/capability.d.ts +11 -1
  205. package/dist/operations/generators/capability.js +481 -224
  206. package/dist/operations/generators/capability.ts +562 -233
  207. package/dist/operations/generators/compile.js +66 -39
  208. package/dist/operations/generators/compile.ts +78 -39
  209. package/dist/operations/generators/permits.js +11 -12
  210. package/dist/operations/generators/permits.ts +3 -4
  211. package/dist/operations/generators/seed.d.ts +1 -0
  212. package/dist/operations/generators/seed.js +19 -17
  213. package/dist/operations/generators/seed.ts +22 -14
  214. package/dist/operations/generators/trial.d.ts +6 -8
  215. package/dist/operations/generators/trial.js +200 -70
  216. package/dist/operations/generators/trial.ts +230 -93
  217. package/dist/operations/nodes.d.ts +15 -16
  218. package/dist/operations/nodes.ts +16 -17
  219. package/dist/operations/operations.d.ts +40 -4
  220. package/dist/operations/operations.js +1 -0
  221. package/dist/operations/operations.ts +61 -4
  222. package/dist/operations/result.d.ts +2 -2
  223. package/dist/operations/result.ts +2 -2
  224. package/package.json +1 -4
  225. package/dist/core/answers.d.ts +0 -171
  226. package/dist/core/answers.js +0 -789
  227. package/dist/core/answers.ts +0 -999
  228. package/dist/core/client.d.ts +0 -57
  229. package/dist/core/client.js +0 -247
  230. package/dist/core/client.ts +0 -286
  231. package/dist/core/files.js +0 -145
  232. package/dist/core/files.ts +0 -193
  233. package/dist/integrations/module.d.ts +0 -6
  234. package/dist/integrations/module.js +0 -153
  235. package/dist/integrations/module.ts +0 -191
  236. package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
  237. package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
  238. package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
  239. package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
  240. package/dist/operations/cost.d.ts +0 -14
  241. package/dist/operations/cost.js +0 -37
  242. package/dist/operations/cost.ts +0 -58
  243. package/dist/operations/errors/errors.d.ts +0 -52
  244. package/dist/operations/http.js +0 -124
  245. package/dist/operations/http.ts +0 -169
  246. package/dist/operations/memory.d.ts +0 -104
  247. package/dist/operations/memory.js +0 -365
  248. package/dist/operations/memory.ts +0 -470
  249. package/dist/operations/metering.d.ts +0 -55
  250. package/dist/operations/metering.js +0 -247
  251. package/dist/operations/metering.ts +0 -328
  252. package/dist/operations/queue-policy.d.ts +0 -3
  253. package/dist/operations/queue-policy.js +0 -8
  254. package/dist/operations/queue-policy.ts +0 -10
  255. package/dist/operations/seams.d.ts +0 -239
  256. package/dist/operations/seams.js +0 -45
  257. package/dist/operations/seams.ts +0 -364
  258. package/dist/operations/store.d.ts +0 -14
  259. package/dist/operations/store.js +0 -1
  260. package/dist/operations/store.ts +0 -29
  261. /package/dist/{operations → core}/errors/classes.d.ts +0 -0
  262. /package/dist/{operations → core}/errors/classes.js +0 -0
  263. /package/dist/{operations → core}/errors/classes.ts +0 -0
  264. /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
  265. /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
@@ -1,169 +0,0 @@
1
- import { payloadBytes } from './metering.ts'
2
- import { ValidationError } from './result.ts'
3
- import type { Http, HttpRequest, HttpResponse } from './seams.ts'
4
-
5
- export const HTTP_CALL_ACTION = 'http.call'
6
-
7
- export class HttpNotConfiguredError extends Error {
8
- constructor() {
9
- super(
10
- 'no outward seam is configured. `http.call` needs `seams.http`, which is the transport an app ' +
11
- 'wires — which hosts it may reach is declared in its tree and is not this seam\'s business.',
12
- )
13
- this.name = 'HttpNotConfiguredError'
14
- }
15
- }
16
-
17
- export class OutwardTransportError extends Error {
18
- constructor(
19
- readonly target: string,
20
- cause: unknown,
21
- ) {
22
- super(`outward call to "${target}" never reached it: ${cause instanceof Error ? cause.message : String(cause)}`)
23
- this.name = 'OutwardTransportError'
24
- }
25
- }
26
-
27
- export function outwardUrl(target: string, address: string, path: string): URL {
28
- let base: URL
29
- try {
30
- base = new URL(address)
31
- } catch {
32
- throw new ValidationError(`the address resolved for "${target}" is not an absolute URL: ${JSON.stringify(address)}`)
33
- }
34
- if (base.protocol !== 'https:') {
35
- throw new ValidationError(`outward calls go over https only, and "${target}" resolved to ${base.protocol.replace(':', '')}`)
36
- }
37
- if (base.search !== '' || base.hash !== '') {
38
- throw new ValidationError(`the address for "${target}" carries a query or a fragment — those belong to the call`)
39
- }
40
- if (!path.startsWith('/')) {
41
- throw new ValidationError(`an outward path starts with "/", and "${path}" does not`)
42
- }
43
- if (path.startsWith('//')) {
44
- throw new ValidationError(`the path "${path}" is protocol-relative, which points at another host`)
45
- }
46
- const url = new URL(`${base.origin}${base.pathname.replace(/\/$/, '')}${path}`)
47
- if (url.origin !== base.origin) {
48
- throw new ValidationError(`the path "${path}" resolves to ${url.origin}, which is not where "${target}" is`)
49
- }
50
- return url
51
- }
52
-
53
- function requestBytes(headers: Readonly<Record<string, string>>, body: Uint8Array | undefined): number {
54
- return payloadBytes(headers) + (body === undefined ? 0 : body.byteLength)
55
- }
56
-
57
- function wireBody(body: Uint8Array): ArrayBuffer {
58
- const copy = new ArrayBuffer(body.byteLength)
59
- new Uint8Array(copy).set(body)
60
- return copy
61
- }
62
-
63
- export interface HttpSeamOptions {
64
- readonly transport?: typeof fetch
65
-
66
- readonly timeoutMs?: number
67
- }
68
-
69
- const DEFAULT_TIMEOUT_MS = 10_000
70
-
71
- export function httpSeam(options: HttpSeamOptions = {}): Http {
72
- const send = options.transport ?? fetch
73
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS
74
-
75
- return {
76
- async call(request: HttpRequest): Promise<HttpResponse> {
77
- const url = outwardUrl(request.target, request.address, request.path)
78
-
79
- const headers: Record<string, string> = { ...request.headers }
80
- if (request.contentType !== undefined) headers['content-type'] = request.contentType
81
- if (request.idempotencyKey !== undefined) headers['idempotency-key'] = request.idempotencyKey
82
-
83
- const bytesSent = requestBytes(headers, request.body)
84
- const startedAt = Date.now()
85
-
86
- let response: Response
87
- try {
88
- response = await send(url.toString(), {
89
- method: request.method,
90
- headers,
91
- ...(request.body === undefined ? {} : { body: wireBody(request.body) }),
92
- signal: AbortSignal.timeout(timeoutMs),
93
- })
94
- } catch (error) {
95
-
96
- throw new OutwardTransportError(request.target, error)
97
- }
98
-
99
- const body = new Uint8Array(await response.arrayBuffer())
100
- const responseHeaders = Object.fromEntries(response.headers.entries())
101
-
102
- return {
103
- status: response.status,
104
- headers: responseHeaders,
105
- body,
106
- bytesSent,
107
- bytesReceived: payloadBytes(responseHeaders) + body.byteLength,
108
- durationMs: Date.now() - startedAt,
109
- }
110
- },
111
- }
112
- }
113
-
114
- export interface RecordedCall {
115
- readonly target: string
116
- readonly method: string
117
- readonly path: string
118
- readonly headers: Readonly<Record<string, string>>
119
- readonly body: string
120
- }
121
-
122
- export interface ScriptedAnswer {
123
- readonly status: number
124
- readonly headers?: Readonly<Record<string, string>>
125
- readonly body?: string
126
- }
127
-
128
- const REDACTED = '(sent)'
129
-
130
- export function recordingHttp(
131
- script: Readonly<Record<string, ScriptedAnswer>> = {},
132
- ): Http & { readonly calls: readonly RecordedCall[] } {
133
- const calls: RecordedCall[] = []
134
- const decoder = new TextDecoder()
135
-
136
- return {
137
- calls,
138
- async call(request) {
139
- outwardUrl(request.target, request.address, request.path)
140
-
141
- const body = request.body === undefined ? '' : decoder.decode(request.body)
142
- calls.push({
143
- target: request.target,
144
- method: request.method,
145
- path: request.path,
146
- headers: Object.fromEntries(Object.keys(request.headers ?? {}).map((one) => [one, REDACTED])),
147
- body,
148
- })
149
-
150
- const answer = script[`${request.method} ${request.path}`]
151
- if (answer === undefined) {
152
- throw new Error(
153
- `this scenario scripts no answer for "${request.method} ${request.path}", so nothing here knows what ${request.target} would say. Add that key to the scenario's answers — a call answered by something nobody scripted proves it was made and nothing about what came back.`,
154
- )
155
- }
156
- const answered = new TextEncoder().encode(answer.body ?? '')
157
- const headers = answer.headers ?? {}
158
- return {
159
- status: answer.status,
160
- headers,
161
- body: answered,
162
- bytesSent: requestBytes({ ...request.headers }, request.body),
163
- bytesReceived: payloadBytes(headers) + answered.byteLength,
164
-
165
- durationMs: 0,
166
- }
167
- },
168
- }
169
- }
@@ -1,104 +0,0 @@
1
- import type { Actor } from '../core/actor.ts';
2
- import type { Store, Row, Seams, Idempotency, PlatformEvent, LogLevel, Queue, Job, EnqueueOpts, Transactional, AuditRecord, ErrorRecord, Vault, FieldList } from './seams.ts';
3
- export declare class UnknownColumnError extends Error {
4
- constructor(entity: string, key: string);
5
- }
6
- export declare class VersionConflictError extends Error {
7
- constructor(entity: string, id: string, expectedVersion: number);
8
- }
9
- export declare class MemoryStore implements Store, Transactional {
10
- private data;
11
- private readonly declared;
12
- private readonly keys;
13
- constructor(declared?: ReadonlyMap<string, ReadonlySet<string>>, keys?: ReadonlyMap<string, string>);
14
- private keyOf;
15
- private static readonly SYSTEM;
16
- private assertDeclared;
17
- private depth;
18
- transaction<T>(_actor: Actor, fn: () => Promise<T>): Promise<T>;
19
- insert(_actor: Actor, entity: string, row: Row): Promise<Row>;
20
- get(_actor: Actor, entity: string, key: string | number, fields: FieldList): Promise<Row | null>;
21
- list(_actor: Actor, entity: string, opts?: {
22
- limit?: number;
23
- where?: Readonly<Record<string, string | number | boolean | null>>;
24
- }): Promise<Row[]>;
25
- update(_actor: Actor, entity: string, key: string | number, patch: Record<string, unknown>, expectedVersion?: number): Promise<Row>;
26
- remove(_actor: Actor, entity: string, key: string | number): Promise<void>;
27
- }
28
- export declare class MemoryQueue implements Queue {
29
- private jobs;
30
- private dead;
31
- private seq;
32
- enqueue<T>(actor: Actor, kind: string, payload: T, opts?: EnqueueOpts): Promise<string>;
33
- poll(kinds: string[], limit: number, now: number): Promise<Job[]>;
34
- ack(id: string): Promise<void>;
35
- fail(id: string, error: string, now: number): Promise<void>;
36
- deadLetter(id: string, error: string): Promise<void>;
37
- deadLetters(): Promise<Job[]>;
38
- }
39
- export interface Sink {
40
- logs: {
41
- level: LogLevel;
42
- action: string;
43
- data: Record<string, unknown>;
44
- }[];
45
- events: PlatformEvent[];
46
- audits: AuditRecord[];
47
- errors: ErrorRecord[];
48
- costs: string[];
49
- indexed: {
50
- entity: string;
51
- row: Row;
52
- }[];
53
- spans: {
54
- action: string;
55
- status: 'ok' | 'error';
56
- }[];
57
- outbox: PlatformEvent[];
58
- gateOrder: string[];
59
- quota: {
60
- reserved: number[];
61
- committed: number[];
62
- released: number;
63
- };
64
- files: {
65
- action: 'put' | 'get' | 'signed' | 'remove';
66
- key: string;
67
- bytes: number | null;
68
- }[];
69
- queries: {
70
- sql: string;
71
- params: readonly unknown[];
72
- rows: number;
73
- }[];
74
- }
75
- export declare class MemoryIdempotency implements Idempotency {
76
- private readonly records;
77
- private readonly onCheck?;
78
- constructor(opts: {
79
- readonly onCheck?: () => void;
80
- readonly records?: Map<string, unknown>;
81
- });
82
- private keyFor;
83
- check(key: string | undefined, action: string): Promise<unknown | null>;
84
- store(key: string | undefined, action: string, output: unknown): Promise<void>;
85
- }
86
- export interface MemorySeamOptions {
87
- readonly allowRate?: boolean;
88
- readonly features?: readonly string[];
89
- readonly quota?: Readonly<Record<string, number>>;
90
- readonly onExceed?: string;
91
- readonly entities?: ReadonlyMap<string, ReadonlySet<string>>;
92
- readonly keys?: ReadonlyMap<string, string>;
93
- readonly secrets?: Readonly<Record<string, string>>;
94
- readonly views?: Readonly<Record<string, readonly unknown[]>>;
95
- }
96
- export declare function memoryVault(seed?: Readonly<Record<string, string>>): Vault;
97
- export declare const arrived: () => number;
98
- export declare const fresh: () => string;
99
- export declare function inMemorySeams(opts?: MemorySeamOptions): {
100
- seams: Seams;
101
- sink: Sink;
102
- store: MemoryStore;
103
- queue: MemoryQueue;
104
- };
@@ -1,365 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { backoffMs, isExhausted } from "./queue-policy.js";
3
- function projectRow(row, fields, key) {
4
- const keep = new Set([key, 'version', ...fields]);
5
- const projected = {};
6
- for (const [name, value] of Object.entries(row)) {
7
- if (keep.has(name))
8
- projected[name] = value;
9
- }
10
- return projected;
11
- }
12
- export class UnknownColumnError extends Error {
13
- constructor(entity, key) {
14
- super(`${entity} does not declare "${key}", so writing it would be silently discarded. ` +
15
- 'Declare the field or relation on the entity, or stop writing the key.');
16
- this.name = 'UnknownColumnError';
17
- }
18
- }
19
- export class VersionConflictError extends Error {
20
- constructor(entity, id, expectedVersion) {
21
- super(`${entity} ${id} was not at version ${expectedVersion} — someone else changed it first. ` +
22
- 're-read the row and retry with its current ETag.');
23
- this.name = 'VersionConflictError';
24
- }
25
- }
26
- export class MemoryStore {
27
- data = new Map();
28
- declared;
29
- keys;
30
- constructor(declared, keys) {
31
- this.declared = declared ?? new Map();
32
- this.keys = keys ?? new Map();
33
- }
34
- keyOf(entity) {
35
- const held = this.keys.get(entity);
36
- if (held === undefined) {
37
- throw new Error(`nothing told this store which value identifies a ${entity}, so it cannot find one row rather than all of ` +
38
- 'them. An entity states that with a `unique` invariant over one of its values, and whatever builds this ' +
39
- 'store passes those along with the columns each entity declares.');
40
- }
41
- return held;
42
- }
43
- static SYSTEM = new Set(['version']);
44
- assertDeclared(entity, row) {
45
- const allowed = this.declared.get(entity);
46
- if (allowed === undefined)
47
- return;
48
- for (const key of Object.keys(row)) {
49
- if (allowed.has(key) || MemoryStore.SYSTEM.has(key))
50
- continue;
51
- throw new UnknownColumnError(entity, key);
52
- }
53
- }
54
- depth = 0;
55
- async transaction(_actor, fn) {
56
- if (this.depth > 0)
57
- return fn();
58
- const snapshot = new Map();
59
- for (const [key, rows] of this.data)
60
- snapshot.set(key, rows.map((r) => ({ ...r })));
61
- this.depth += 1;
62
- try {
63
- return await fn();
64
- }
65
- catch (err) {
66
- this.data = snapshot;
67
- throw err;
68
- }
69
- finally {
70
- this.depth -= 1;
71
- }
72
- }
73
- async insert(_actor, entity, row) {
74
- this.assertDeclared(entity, row);
75
- const rows = this.data.get(entity) ?? [];
76
- const rec = { ...row, version: 1 };
77
- rows.push(rec);
78
- this.data.set(entity, rows);
79
- return { ...rec };
80
- }
81
- async get(_actor, entity, key, fields) {
82
- const named = this.keyOf(entity);
83
- const row = this.data.get(entity)?.find((r) => r[named] === key) ?? null;
84
- return row === null ? null : projectRow(row, fields, named);
85
- }
86
- async list(_actor, entity, opts) {
87
- const all = this.data.get(entity) ?? [];
88
- const where = Object.entries(opts?.where ?? {});
89
- for (const [field] of where)
90
- this.assertDeclared(entity, { [field]: null });
91
- const matched = where.length === 0 ? all : all.filter((row) => where.every(([f, v]) => (row[f] ?? null) === v));
92
- return opts?.limit ? matched.slice(0, opts.limit).map((r) => ({ ...r })) : matched.map((r) => ({ ...r }));
93
- }
94
- async update(_actor, entity, key, patch, expectedVersion) {
95
- this.assertDeclared(entity, patch);
96
- const named = this.keyOf(entity);
97
- const rows = this.data.get(entity) ?? [];
98
- const i = rows.findIndex((r) => r[named] === key);
99
- const cur = rows[i];
100
- if (i < 0 || !cur)
101
- throw new Error(`record ${String(key)} not found`);
102
- const currentVersion = typeof cur['version'] === 'number' ? cur['version'] : 1;
103
- if (expectedVersion !== undefined && expectedVersion !== currentVersion) {
104
- throw new VersionConflictError(entity, String(key), expectedVersion);
105
- }
106
- const next = { ...cur, ...patch, [named]: key, version: currentVersion + 1 };
107
- rows[i] = next;
108
- return { ...next };
109
- }
110
- async remove(_actor, entity, key) {
111
- const named = this.keyOf(entity);
112
- this.data.set(entity, (this.data.get(entity) ?? []).filter((r) => r[named] !== key));
113
- }
114
- }
115
- export class MemoryQueue {
116
- jobs = new Map();
117
- dead = [];
118
- seq = 0;
119
- async enqueue(actor, kind, payload, opts) {
120
- if (opts?.dedupeKey) {
121
- for (const [id, job] of this.jobs) {
122
- if (job.dedupeKey === opts.dedupeKey)
123
- return id;
124
- }
125
- }
126
- const id = `job_${++this.seq}`;
127
- this.jobs.set(id, {
128
- id,
129
- kind,
130
- payload,
131
- attempts: 0,
132
- runAt: opts?.runAt ?? 0,
133
- claimed: false,
134
- dedupeKey: opts?.dedupeKey,
135
- actor,
136
- });
137
- return id;
138
- }
139
- async poll(kinds, limit, now) {
140
- const due = [];
141
- for (const job of this.jobs.values()) {
142
- if (due.length >= limit)
143
- break;
144
- if (job.claimed || !kinds.includes(job.kind) || job.runAt > now)
145
- continue;
146
- job.claimed = true;
147
- due.push({ ...job });
148
- }
149
- return due;
150
- }
151
- async ack(id) {
152
- this.jobs.delete(id);
153
- }
154
- async fail(id, error, now) {
155
- const job = this.jobs.get(id);
156
- if (!job)
157
- return;
158
- job.attempts += 1;
159
- job.claimed = false;
160
- if (isExhausted(job.attempts)) {
161
- this.dead.push({ ...job });
162
- this.jobs.delete(id);
163
- return;
164
- }
165
- job.runAt = now + backoffMs(job.attempts);
166
- void error;
167
- }
168
- async deadLetter(id, error) {
169
- const job = this.jobs.get(id);
170
- if (!job)
171
- return;
172
- this.dead.push({ ...job });
173
- this.jobs.delete(id);
174
- void error;
175
- }
176
- async deadLetters() {
177
- return this.dead.map((j) => ({ ...j }));
178
- }
179
- }
180
- export class MemoryIdempotency {
181
- records;
182
- onCheck;
183
- constructor(opts) {
184
- this.records = opts.records ?? new Map();
185
- this.onCheck = opts.onCheck;
186
- }
187
- keyFor(key, action) {
188
- return `${key}:${action}`;
189
- }
190
- async check(key, action) {
191
- this.onCheck?.();
192
- if (!key)
193
- return null;
194
- const k = this.keyFor(key, action);
195
- return this.records.has(k) ? (this.records.get(k) ?? null) : null;
196
- }
197
- async store(key, action, output) {
198
- if (!key)
199
- return;
200
- const k = this.keyFor(key, action);
201
- if (!this.records.has(k))
202
- this.records.set(k, output);
203
- }
204
- }
205
- export function memoryVault(seed = {}) {
206
- return {
207
- async resolve(refs) {
208
- const found = {};
209
- for (const ref of refs) {
210
- const value = seed[ref];
211
- if (value === undefined)
212
- throw new Error(`vault has no value for "${ref}"`);
213
- found[ref] = value;
214
- }
215
- return found;
216
- },
217
- };
218
- }
219
- export const arrived = () => Date.now();
220
- export const fresh = () => randomUUID();
221
- export function inMemorySeams(opts) {
222
- const sink = {
223
- logs: [], events: [], audits: [], errors: [], costs: [], indexed: [], spans: [],
224
- outbox: [], gateOrder: [], quota: { reserved: [], committed: [], released: 0 },
225
- files: [], queries: [],
226
- };
227
- const store = new MemoryStore(opts?.entities, opts?.keys);
228
- const queue = new MemoryQueue();
229
- const searchIdx = new Map();
230
- const telemetry = {
231
- start(action) {
232
- let status = 'ok';
233
- return {
234
- ok() { status = 'ok'; },
235
- error() { status = 'error'; },
236
- end() { sink.spans.push({ action, status }); },
237
- };
238
- },
239
- };
240
- const log = { write(level, action, _actor, data) { sink.logs.push({ level, action, data }); } };
241
- const audit = { async append(_actor, record) { sink.audits.push(record); } };
242
- const errors = { async record(_actor, record) { sink.errors.push(record); } };
243
- const cost = { meter(action) { sink.costs.push(action); } };
244
- const events = { async publish(e) { sink.events.push(e); } };
245
- const rateLimiter = {
246
- async check() {
247
- sink.gateOrder.push('rate');
248
- return opts?.allowRate ?? true;
249
- },
250
- async checkPolicy() {
251
- sink.gateOrder.push('rate');
252
- return opts?.allowRate ?? true;
253
- },
254
- };
255
- const featureGate = opts?.features === undefined
256
- ? undefined
257
- : {
258
- async check(_actor, feature) {
259
- sink.gateOrder.push('feature');
260
- return (opts.features ?? []).includes(feature);
261
- },
262
- };
263
- const used = new Map();
264
- const quotas = opts?.quota === undefined
265
- ? undefined
266
- : {
267
- async reserve(_actor, meter, estimate) {
268
- sink.gateOrder.push('quota');
269
- sink.quota.reserved.push(estimate);
270
- const allowance = opts.quota?.[meter] ?? Number.POSITIVE_INFINITY;
271
- const before = used.get(meter) ?? 0;
272
- if (before + estimate > allowance) {
273
- return {
274
- ok: false,
275
- behavior: opts.onExceed ?? 'block',
276
- retryAfterSeconds: 60,
277
- async commit() { },
278
- async release() { },
279
- };
280
- }
281
- used.set(meter, before + estimate);
282
- let settled = false;
283
- return {
284
- ok: true,
285
- behavior: null,
286
- retryAfterSeconds: 0,
287
- async commit(actual) {
288
- if (settled)
289
- return;
290
- settled = true;
291
- sink.quota.committed.push(actual);
292
- used.set(meter, (used.get(meter) ?? 0) - estimate + actual);
293
- },
294
- async release() {
295
- if (settled)
296
- return;
297
- settled = true;
298
- sink.quota.released += 1;
299
- used.set(meter, (used.get(meter) ?? 0) - estimate);
300
- },
301
- };
302
- },
303
- };
304
- const outbox = {
305
- async emit(_actor, event) {
306
- sink.outbox.push(event);
307
- },
308
- };
309
- const idempotency = new MemoryIdempotency({
310
- onCheck: () => sink.gateOrder.push('idempotency'),
311
- });
312
- const search = {
313
- async index(_actor, entity, row) {
314
- sink.indexed.push({ entity, row });
315
- searchIdx.set(entity, [...(searchIdx.get(entity) ?? []), row]);
316
- },
317
- async query(_actor, entity, q) {
318
- const needle = q.toLowerCase();
319
- return (searchIdx.get(entity) ?? []).filter((r) => JSON.stringify(r).toLowerCase().includes(needle));
320
- },
321
- };
322
- const vault = opts?.secrets === undefined ? undefined : memoryVault(opts.secrets);
323
- const stored = new Map();
324
- const files = {
325
- async put(_actor, key, body, contentType) {
326
- stored.set(key, { body, contentType });
327
- sink.files.push({ action: 'put', key, bytes: body.byteLength });
328
- return { size: body.byteLength };
329
- },
330
- async get(_actor, key) {
331
- const found = stored.get(key);
332
- sink.files.push({ action: 'get', key, bytes: found === undefined ? null : found.body.byteLength });
333
- return found === undefined ? null : { body: found.body, contentType: found.contentType };
334
- },
335
- async signedUrl(_actor, key, expiresInSeconds) {
336
- sink.files.push({ action: 'signed', key, bytes: null });
337
- return `https://files.invalid/unsigned-in-memory/${encodeURIComponent(key)}?expires_in=${String(expiresInSeconds)}`;
338
- },
339
- async remove(_actor, key) {
340
- stored.delete(key);
341
- sink.files.push({ action: 'remove', key, bytes: null });
342
- },
343
- };
344
- const answers = opts?.views;
345
- const views = answers === undefined
346
- ? undefined
347
- : {
348
- async query(_actor, sql, params) {
349
- const found = (answers[sql] ?? []);
350
- sink.queries.push({ sql, params, rows: found.length });
351
- return found;
352
- },
353
- };
354
- return {
355
- seams: {
356
- store, telemetry, log, audit, errors, search, cost, idempotency, events, rateLimiter, queue,
357
- outbox, files, clock: { now: arrived }, random: { next: Math.random, uuid: fresh },
358
- ...(featureGate ? { featureGate } : {}),
359
- ...(quotas ? { quotas } : {}),
360
- ...(vault ? { vault } : {}),
361
- ...(views ? { views } : {}),
362
- },
363
- sink, store, queue,
364
- };
365
- }