orez-sync-cf-host 0.4.63 → 0.4.64

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orez-sync-cf-host",
3
- "version": "0.4.63",
3
+ "version": "0.4.64",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/src/host.ts CHANGED
@@ -690,7 +690,8 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
690
690
  async #fetchDelegatedPush(
691
691
  endpoint: URL,
692
692
  headers: Headers,
693
- body: ArrayBuffer
693
+ body: ArrayBuffer,
694
+ provisioning = false
694
695
  ): Promise<Response> {
695
696
  const binding = this.#serviceBinding(
696
697
  config.mutateBinding ?? config.upstream?.binding
@@ -703,7 +704,9 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
703
704
  method: 'POST',
704
705
  headers,
705
706
  body,
706
- signal: AbortSignal.timeout(delegateTimeoutMs),
707
+ signal: AbortSignal.timeout(
708
+ provisioning ? Math.max(delegateTimeoutMs, 25_000) : delegateTimeoutMs
709
+ ),
707
710
  })
708
711
  } catch (error) {
709
712
  lastError = error
@@ -1048,7 +1051,8 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
1048
1051
  const upstreamResponse = await this.#fetchDelegatedPush(
1049
1052
  endpoint,
1050
1053
  headers,
1051
- bytes
1054
+ bytes,
1055
+ this.#engineState()?.upstreamWatermark === '0'
1052
1056
  )
1053
1057
  if (!upstreamResponse.ok) {
1054
1058
  return new Response(upstreamResponse.body, upstreamResponse)
@@ -1477,6 +1481,17 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
1477
1481
  return this.#pull(request, claims, namespace)
1478
1482
  }
1479
1483
  if (route === '/push' && request.method === 'POST') {
1484
+ // A push may be the first request for a fresh namespace. DATA's
1485
+ // /changes call is also its schema-provisioning barrier, so complete it
1486
+ // before delegating the mutation to APP. Pull already enforces this
1487
+ // ordering above; skipping it here let APP race half-created tables and
1488
+ // surface a terminal, bodyless 500 to Zero.
1489
+ try {
1490
+ await this.#ingest(upstreamPath)
1491
+ } catch (error) {
1492
+ await request.arrayBuffer()
1493
+ return json(errorBody(error), statusOf(error))
1494
+ }
1480
1495
  return this.#push(request, claims, namespace, upstreamPath)
1481
1496
  }
1482
1497
  return json({ error: 'not found' }, 404)
@@ -29,6 +29,7 @@ interface Env extends SyncHostEnv {
29
29
 
30
30
  const runawayNamespaces = new Set<string>()
31
31
  const numericTextNamespaces = new Set<string>()
32
+ const hydratedNamespaces = new Set<string>()
32
33
  let delegatedFailuresRemaining = 0
33
34
  let delegatedAttempts = 0
34
35
 
@@ -96,7 +97,7 @@ async function upstreamFetch(request: Request, env: Env): Promise<Response> {
96
97
 
97
98
  /** Self service-binding target backed by the real ZeroSqlDO. */
98
99
  export class DataService extends WorkerEntrypoint<Env> {
99
- fetch(request: Request): Promise<Response> {
100
+ async fetch(request: Request): Promise<Response> {
100
101
  const url = new URL(request.url)
101
102
  const pathname = url.pathname
102
103
  if (
@@ -170,7 +171,9 @@ export class DataService extends WorkerEntrypoint<Env> {
170
171
  })
171
172
  )
172
173
  }
173
- return upstreamFetch(request, this.env)
174
+ const response = await upstreamFetch(request, this.env)
175
+ if (pathname.endsWith('/changes') && response.ok) hydratedNamespaces.add(namespace)
176
+ return response
174
177
  }
175
178
  }
176
179
 
@@ -181,6 +184,12 @@ export class AppService extends WorkerEntrypoint<Env> {
181
184
  new Response('APP route rejected non-push request', { status: 418 })
182
185
  )
183
186
  }
187
+ const namespace = new URL(request.url).pathname.split('/')[1] ?? ''
188
+ if (!hydratedNamespaces.has(namespace)) {
189
+ return Promise.resolve(
190
+ Response.json({ error: 'schema provisioning has not completed' }, { status: 500 })
191
+ )
192
+ }
184
193
  delegatedAttempts++
185
194
  if (delegatedFailuresRemaining > 0) {
186
195
  delegatedFailuresRemaining--