orez-sync-cf-host 0.5.18 → 0.5.20

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 (46) hide show
  1. package/README.md +117 -7
  2. package/dist/bun-wasm-loader.d.ts +1 -0
  3. package/dist/bun-wasm-loader.js +20 -0
  4. package/dist/config.d.ts +3 -0
  5. package/dist/config.js +93 -0
  6. package/{src → dist}/generated/sync_wasm.d.ts +2 -2
  7. package/{src → dist}/generated/sync_wasm.js +3 -2
  8. package/dist/generated/sync_wasm_bg.wasm +0 -0
  9. package/dist/host.d.ts +12 -0
  10. package/dist/host.js +1512 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.js +4 -0
  13. package/dist/mutation-error.d.ts +9 -0
  14. package/dist/mutation-error.js +23 -0
  15. package/dist/node-wasm-loader.d.ts +1 -0
  16. package/dist/node-wasm-loader.js +22 -0
  17. package/dist/post-commit.d.ts +13 -0
  18. package/dist/post-commit.js +31 -0
  19. package/dist/query-compiler.d.ts +4 -0
  20. package/dist/query-compiler.js +4 -0
  21. package/dist/sql-storage-adapter.d.ts +69 -0
  22. package/dist/sql-storage-adapter.js +192 -0
  23. package/dist/transaction-query.d.ts +72 -0
  24. package/dist/transaction-query.js +379 -0
  25. package/dist/types.d.ts +144 -0
  26. package/dist/types.js +5 -0
  27. package/dist/vite-wasm-loader.d.ts +3 -0
  28. package/dist/vite-wasm-loader.js +24 -0
  29. package/dist/wasm.d.ts +1 -0
  30. package/dist/wasm.js +7 -0
  31. package/dist/write-safeguards.d.ts +53 -0
  32. package/dist/write-safeguards.js +186 -0
  33. package/package.json +63 -12
  34. package/src/config.ts +0 -93
  35. package/src/generated/sync_wasm_bg.wasm +0 -0
  36. package/src/harness-config.ts +0 -487
  37. package/src/harness-worker.ts +0 -33
  38. package/src/host.ts +0 -1948
  39. package/src/index.ts +0 -22
  40. package/src/ingest-harness-worker.ts +0 -440
  41. package/src/platform-probe-worker.ts +0 -305
  42. package/src/sql-storage-adapter.ts +0 -185
  43. package/src/types.ts +0 -181
  44. package/src/write-safeguards.ts +0 -248
  45. /package/{src → dist}/generated/package.json +0 -0
  46. /package/{src → dist}/generated/sync_wasm_bg.wasm.d.ts +0 -0
package/src/index.ts DELETED
@@ -1,22 +0,0 @@
1
- export { createSyncDurableObject, createSyncWorker } from './host.js'
2
- export { MutationApplicationError, registerMutators } from './types.js'
3
- export type {
4
- DeferredEffect,
5
- JsonPrimitive,
6
- JsonValue,
7
- MutatorContext,
8
- MutatorRegistry,
9
- MutatorSql,
10
- NormalizedClaims,
11
- PullCaps,
12
- QueryResolver,
13
- RegisteredMutator,
14
- SyncHostConfig,
15
- SyncHostEnv,
16
- ServiceBinding,
17
- SyncSql,
18
- UpstreamConfig,
19
- VisibilityConfig,
20
- VisibilityFilter,
21
- ZeroSchemaConfig,
22
- } from './types.js'
@@ -1,440 +0,0 @@
1
- import { WorkerEntrypoint } from 'cloudflare:workers'
2
-
3
- import { ZeroDO } from '../../../src/cf-do/worker.js'
4
- import { createSyncDurableObject, createSyncWorker } from './index.js'
5
-
6
- import type { SyncHostConfig, SyncHostEnv, ZeroSchemaConfig } from './index.js'
7
-
8
- const schema = {
9
- tables: {
10
- item: {
11
- columns: {
12
- id: { type: 'string' },
13
- label: { type: 'string' },
14
- rank: { type: 'number' },
15
- done: { type: 'boolean' },
16
- meta: { type: 'json' },
17
- },
18
- primaryKey: ['id'],
19
- },
20
- },
21
- } as const satisfies ZeroSchemaConfig
22
-
23
- type Fetcher = { fetch(input: string | Request, init?: RequestInit): Promise<Response> }
24
- interface Env extends SyncHostEnv {
25
- DATA: Fetcher
26
- APP: Fetcher
27
- UPSTREAM_DO: DurableObjectNamespace
28
- }
29
-
30
- const runawayNamespaces = new Set<string>()
31
- const numericTextNamespaces = new Set<string>()
32
- const jsonValueNamespaces = new Set<string>()
33
- const hydratedNamespaces = new Set<string>()
34
- const heldSnapshots = new Set<string>()
35
- const holdSnapshotsAfterCursor = new Set<string>()
36
- const activeSnapshots = new Set<string>()
37
- const snapshotLimits = new Map<string, number[]>()
38
- let delegatedFailuresRemaining = 0
39
- let delegatedAttempts = 0
40
- let delegatedPushFailedRemaining = 0
41
- let delegatedUrl = ''
42
-
43
- const config: SyncHostConfig<Env> = {
44
- hostVersion: 'upstream-ingest-harness',
45
- schema,
46
- mutateUrl: '/api/zero/push?schema=feed_0&appID=feed',
47
- mutateOrigin: 'https://app.internal',
48
- mutateBinding: 'APP',
49
- delegatedPushRetry: {
50
- maxAttempts: 3,
51
- initialBackoffMs: 10,
52
- maxBackoffMs: 20,
53
- timeoutMs: 1_000,
54
- },
55
- upstream: {
56
- binding: 'DATA',
57
- namespacePath: (namespace) =>
58
- namespace.startsWith('root-mount-') ? '/' : `/${namespace}`,
59
- changeLimit: 2,
60
- intervalMs: 1_000,
61
- ingestBudgetRows: 600,
62
- },
63
- initialize(sql) {
64
- sql.exec(
65
- 'CREATE TABLE IF NOT EXISTS item (id TEXT PRIMARY KEY, label TEXT NOT NULL, rank REAL NOT NULL, done INTEGER NOT NULL, meta TEXT)'
66
- )
67
- },
68
- authenticate(request) {
69
- const userID = request.headers.get('authorization')?.match(/^Bearer token-(.+)$/)?.[1]
70
- return userID ? { userID } : null
71
- },
72
- authorizeWake(request) {
73
- return new URL(request.url).searchParams.get('wakeToken') === 'ingest-harness-wake'
74
- },
75
- authorizeNotify(request, env) {
76
- return Boolean(env.ADMIN_KEY) && request.headers.get('x-admin-key') === env.ADMIN_KEY
77
- },
78
- namespace(request) {
79
- return new URL(request.url).pathname.split('/')[1] || null
80
- },
81
- }
82
-
83
- export const SyncDurableObject = createSyncDurableObject(config)
84
- export { ZeroDO }
85
-
86
- async function upstreamFetch(request: Request, env: Env): Promise<Response> {
87
- const url = new URL(request.url)
88
- const [, namespace, ...rest] = url.pathname.split('/')
89
- if (!namespace) return new Response('namespace required', { status: 400 })
90
- const stub = env.UPSTREAM_DO.get(env.UPSTREAM_DO.idFromName(namespace))
91
- url.pathname = `/${rest.join('/')}`
92
- if (url.pathname === '/_orez/write-budget') return stub.fetch(new Request(url, request))
93
- const exec = async (sql: string, params: unknown[] = []) => {
94
- const response = await stub.fetch('https://upstream.invalid/exec', {
95
- method: 'POST',
96
- headers: { 'content-type': 'application/json' },
97
- body: JSON.stringify({ sql, params }),
98
- })
99
- if (!response.ok) throw new Error(`upstream init failed: ${await response.text()}`)
100
- }
101
- await exec(
102
- 'CREATE TABLE IF NOT EXISTS item (id TEXT PRIMARY KEY, label TEXT NOT NULL, rank REAL NOT NULL, done INTEGER NOT NULL, meta TEXT)'
103
- )
104
- await exec(
105
- 'CREATE TABLE IF NOT EXISTS _zero_schema_tables (name TEXT PRIMARY KEY, schema_json TEXT NOT NULL)'
106
- )
107
- await exec(
108
- 'INSERT OR IGNORE INTO _zero_schema_tables (name, schema_json) VALUES (?, ?)',
109
- ['item', JSON.stringify(schema.tables.item)]
110
- )
111
- return stub.fetch(new Request(url, request))
112
- }
113
-
114
- /** Self service-binding target backed by the real ZeroSqlDO. */
115
- export class DataService extends WorkerEntrypoint<Env> {
116
- async fetch(request: Request): Promise<Response> {
117
- const url = new URL(request.url)
118
- const pathname = url.pathname
119
- if (
120
- !pathname.endsWith('/changes') &&
121
- !pathname.endsWith('/snapshot') &&
122
- !pathname.endsWith('/_orez/write-budget')
123
- ) {
124
- return Promise.resolve(
125
- new Response('DATA route rejected non-feed request', { status: 418 })
126
- )
127
- }
128
- if (pathname === '/changes') {
129
- const cursor = Number(url.searchParams.get('watermark') ?? 0)
130
- return Promise.resolve(
131
- Response.json({
132
- watermark: 1,
133
- changes:
134
- cursor >= 1
135
- ? []
136
- : [
137
- {
138
- watermark: 1,
139
- tableName: 'item',
140
- op: 'INSERT',
141
- rowData: {
142
- id: 'root-feed-row',
143
- label: 'root-mounted upstream feed',
144
- rank: 1,
145
- done: false,
146
- meta: null,
147
- },
148
- oldData: null,
149
- },
150
- ],
151
- })
152
- )
153
- }
154
- if (pathname === '/_orez/write-budget') {
155
- return Promise.resolve(Response.json({ enabled: true, rootMount: true }))
156
- }
157
- const namespace = pathname.split('/')[1] ?? ''
158
- if (pathname.endsWith('/changes') && jsonValueNamespaces.has(namespace)) {
159
- const cursor = Number(new URL(request.url).searchParams.get('watermark') ?? 0)
160
- const values = [
161
- { nested: { tags: ['a', 2, true] } },
162
- [1, 'two', null],
163
- '42',
164
- 'true',
165
- 'null',
166
- '{"looks":"encoded"}',
167
- 42.5,
168
- true,
169
- ]
170
- return Promise.resolve(
171
- Response.json({
172
- watermark: values.length,
173
- changes: values
174
- .map((meta, index) => ({
175
- watermark: index + 1,
176
- tableName: 'item',
177
- op: 'INSERT',
178
- rowData: {
179
- id: `json-${index}`,
180
- label: 'json round trip',
181
- rank: index,
182
- done: false,
183
- meta,
184
- },
185
- oldData: null,
186
- }))
187
- .filter((change) => change.watermark > cursor)
188
- .slice(0, 2),
189
- })
190
- )
191
- }
192
- if (pathname.endsWith('/changes') && numericTextNamespaces.has(namespace)) {
193
- const watermark = Number(new URL(request.url).searchParams.get('watermark') ?? 0)
194
- return Promise.resolve(
195
- Response.json({
196
- watermark: 2,
197
- changes:
198
- watermark >= 2
199
- ? []
200
- : [
201
- {
202
- watermark: 1,
203
- tableName: 'item',
204
- op: 'INSERT',
205
- rowData: {
206
- id: 'numeric-text',
207
- label: 'SQL timestamp text',
208
- rank: '2026-07-11 13:34:46',
209
- done: false,
210
- meta: null,
211
- },
212
- oldData: null,
213
- },
214
- {
215
- watermark: 2,
216
- tableName: 'item',
217
- op: 'INSERT',
218
- rowData: {
219
- id: 'numeric-native',
220
- label: 'native JSON number',
221
- rank: 1783776886000,
222
- done: false,
223
- meta: null,
224
- },
225
- oldData: null,
226
- },
227
- ],
228
- })
229
- )
230
- }
231
- if (pathname.endsWith('/changes') && runawayNamespaces.has(namespace)) {
232
- return Promise.resolve(
233
- Response.json({
234
- watermark: 100,
235
- changes: [
236
- {
237
- watermark: 1,
238
- tableName: 'item',
239
- op: 'INSERT',
240
- rowData: {
241
- id: 'runaway-replay',
242
- label: 'replayed without cursor progress',
243
- rank: 1,
244
- done: false,
245
- meta: null,
246
- },
247
- oldData: null,
248
- },
249
- ],
250
- })
251
- )
252
- }
253
- const response = await upstreamFetch(request, this.env)
254
- if (pathname.endsWith('/snapshot')) {
255
- const limit = Number(url.searchParams.get('limit'))
256
- if (Number.isSafeInteger(limit)) {
257
- const limits = snapshotLimits.get(namespace) ?? []
258
- limits.push(limit)
259
- snapshotLimits.set(namespace, limits)
260
- }
261
- const shouldHold =
262
- heldSnapshots.has(namespace) &&
263
- (!holdSnapshotsAfterCursor.has(namespace) || url.searchParams.has('cursor'))
264
- if (shouldHold) {
265
- activeSnapshots.add(namespace)
266
- try {
267
- while (
268
- heldSnapshots.has(namespace) &&
269
- (!holdSnapshotsAfterCursor.has(namespace) || url.searchParams.has('cursor'))
270
- ) {
271
- await scheduler.wait(10)
272
- }
273
- } finally {
274
- activeSnapshots.delete(namespace)
275
- }
276
- }
277
- }
278
- if (pathname.endsWith('/changes') && response.ok) hydratedNamespaces.add(namespace)
279
- return response
280
- }
281
- }
282
-
283
- export class AppService extends WorkerEntrypoint<Env> {
284
- fetch(request: Request): Promise<Response> {
285
- delegatedUrl = request.url
286
- if (!new URL(request.url).pathname.endsWith('/api/zero/push')) {
287
- return Promise.resolve(
288
- new Response('APP route rejected non-push request', { status: 418 })
289
- )
290
- }
291
- const namespace = new URL(request.url).pathname.split('/')[1] ?? ''
292
- if (!hydratedNamespaces.has(namespace)) {
293
- return Promise.resolve(
294
- Response.json({ error: 'schema provisioning has not completed' }, { status: 500 })
295
- )
296
- }
297
- delegatedAttempts++
298
- if (delegatedPushFailedRemaining > 0) {
299
- delegatedPushFailedRemaining--
300
- return Promise.resolve(
301
- Response.json({
302
- kind: 'PushFailed',
303
- origin: 'server',
304
- reason: 'database',
305
- mutationIDs: [{ clientID: 'writer', id: 2 }],
306
- message: 'synthetic mutation result persistence failure',
307
- })
308
- )
309
- }
310
- if (delegatedFailuresRemaining > 0) {
311
- delegatedFailuresRemaining--
312
- return Promise.resolve(
313
- Response.json({ error: 'synthetic delegated push failure' }, { status: 503 })
314
- )
315
- }
316
- return upstreamFetch(request, this.env)
317
- }
318
- }
319
-
320
- const syncWorker = createSyncWorker(config)
321
- export default {
322
- fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
323
- const url = new URL(request.url)
324
- if (url.pathname.startsWith('/snapshot-control/')) {
325
- const namespace = url.pathname.slice('/snapshot-control/'.length)
326
- if (request.method === 'GET') {
327
- return Promise.resolve(
328
- Response.json({
329
- active: activeSnapshots.has(namespace),
330
- held: heldSnapshots.has(namespace),
331
- afterCursor: holdSnapshotsAfterCursor.has(namespace),
332
- limits: snapshotLimits.get(namespace) ?? [],
333
- })
334
- )
335
- }
336
- return request
337
- .json()
338
- .catch(() => ({}))
339
- .then((body) => {
340
- if ((body as { hold?: unknown }).hold === true) {
341
- heldSnapshots.add(namespace)
342
- if ((body as { afterCursor?: unknown }).afterCursor === true) {
343
- holdSnapshotsAfterCursor.add(namespace)
344
- } else {
345
- holdSnapshotsAfterCursor.delete(namespace)
346
- }
347
- } else {
348
- heldSnapshots.delete(namespace)
349
- holdSnapshotsAfterCursor.delete(namespace)
350
- }
351
- if ((body as { reset?: unknown }).reset === true)
352
- snapshotLimits.set(namespace, [])
353
- return Response.json({
354
- active: activeSnapshots.has(namespace),
355
- held: heldSnapshots.has(namespace),
356
- afterCursor: holdSnapshotsAfterCursor.has(namespace),
357
- limits: snapshotLimits.get(namespace) ?? [],
358
- })
359
- })
360
- }
361
- if (url.pathname.startsWith('/json-values-control/')) {
362
- const namespace = url.pathname.slice('/json-values-control/'.length)
363
- return request
364
- .json()
365
- .catch(() => ({}))
366
- .then((body) => {
367
- if ((body as { enabled?: unknown }).enabled === true)
368
- jsonValueNamespaces.add(namespace)
369
- else jsonValueNamespaces.delete(namespace)
370
- return Response.json({ ok: true, namespace })
371
- })
372
- }
373
- if (url.pathname.startsWith('/numeric-text-control/')) {
374
- const namespace = url.pathname.slice('/numeric-text-control/'.length)
375
- return request
376
- .json()
377
- .catch(() => ({}))
378
- .then((body) => {
379
- if ((body as { enabled?: unknown }).enabled === true)
380
- numericTextNamespaces.add(namespace)
381
- else numericTextNamespaces.delete(namespace)
382
- return Response.json({ ok: true, namespace })
383
- })
384
- }
385
- if (url.pathname.startsWith('/runaway-control/')) {
386
- const namespace = url.pathname.slice('/runaway-control/'.length)
387
- return request
388
- .json()
389
- .catch(() => ({}))
390
- .then((body) => {
391
- if ((body as { enabled?: unknown }).enabled === true)
392
- runawayNamespaces.add(namespace)
393
- else runawayNamespaces.delete(namespace)
394
- return Response.json({
395
- ok: true,
396
- namespace,
397
- enabled: runawayNamespaces.has(namespace),
398
- })
399
- })
400
- }
401
- if (url.pathname === '/delegation-control') {
402
- if (request.method === 'GET') {
403
- return Promise.resolve(
404
- Response.json({
405
- delegatedFailuresRemaining,
406
- delegatedPushFailedRemaining,
407
- delegatedAttempts,
408
- delegatedUrl,
409
- })
410
- )
411
- }
412
- return request
413
- .json()
414
- .catch(() => ({}))
415
- .then((body) => {
416
- delegatedFailuresRemaining = Math.max(
417
- 0,
418
- Number((body as { failures?: unknown }).failures) || 0
419
- )
420
- delegatedPushFailedRemaining = Math.max(
421
- 0,
422
- Number((body as { pushFailed?: unknown }).pushFailed) || 0
423
- )
424
- delegatedAttempts = 0
425
- delegatedUrl = ''
426
- return Response.json({
427
- delegatedFailuresRemaining,
428
- delegatedPushFailedRemaining,
429
- delegatedAttempts,
430
- delegatedUrl,
431
- })
432
- })
433
- }
434
- if (url.pathname.startsWith('/upstream/')) {
435
- url.pathname = url.pathname.slice('/upstream'.length)
436
- return upstreamFetch(new Request(url, request), env)
437
- }
438
- return syncWorker.fetch!(request as never, env, ctx) as Promise<Response>
439
- },
440
- }