on-zero 0.6.15 → 0.6.17

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 (140) hide show
  1. package/dist/cjs/asyncTasks.cjs +51 -0
  2. package/dist/cjs/asyncTasks.native.js +84 -0
  3. package/dist/cjs/asyncTasks.native.js.map +1 -0
  4. package/dist/cjs/cli.cjs +8 -1
  5. package/dist/cjs/cli.native.js +8 -1
  6. package/dist/cjs/cli.native.js.map +1 -1
  7. package/dist/cjs/createZeroDirectServer.cjs +20 -30
  8. package/dist/cjs/createZeroDirectServer.native.js +28 -33
  9. package/dist/cjs/createZeroDirectServer.native.js.map +1 -1
  10. package/dist/cjs/createZeroSQLiteServer.test.cjs +6 -6
  11. package/dist/cjs/createZeroSQLiteServer.test.native.js +6 -6
  12. package/dist/cjs/createZeroSQLiteServer.test.native.js.map +1 -1
  13. package/dist/cjs/createZeroServer.native.js.map +1 -1
  14. package/dist/cjs/createZeroServer.test.cjs +177 -1
  15. package/dist/cjs/createZeroServer.test.native.js +189 -1
  16. package/dist/cjs/createZeroServer.test.native.js.map +1 -1
  17. package/dist/cjs/createZeroServerCore.cjs +9 -3
  18. package/dist/cjs/createZeroServerCore.native.js +13 -5
  19. package/dist/cjs/createZeroServerCore.native.js.map +1 -1
  20. package/dist/cjs/generate.cjs +5 -2
  21. package/dist/cjs/generate.native.js +5 -2
  22. package/dist/cjs/generate.native.js.map +1 -1
  23. package/dist/cjs/generate.test.cjs +16 -0
  24. package/dist/cjs/generate.test.native.js +16 -0
  25. package/dist/cjs/generate.test.native.js.map +1 -1
  26. package/dist/cjs/helpers/createMutators.cjs +2 -2
  27. package/dist/cjs/helpers/createMutators.native.js +2 -2
  28. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  29. package/dist/cjs/index.cjs +1 -0
  30. package/dist/cjs/index.native.js +1 -0
  31. package/dist/cjs/index.native.js.map +1 -1
  32. package/dist/cjs/server.cjs +2 -1
  33. package/dist/cjs/syncHost.cjs +10 -3
  34. package/dist/cjs/syncHost.native.js +11 -4
  35. package/dist/cjs/syncHost.native.js.map +1 -1
  36. package/dist/cjs/syncHost.test.cjs +2 -2
  37. package/dist/cjs/syncHost.test.native.js +2 -2
  38. package/dist/cjs/syncHost.test.native.js.map +1 -1
  39. package/dist/cjs/vite-plugin.cjs +2 -1
  40. package/dist/cjs/vite-plugin.native.js +2 -1
  41. package/dist/cjs/vite-plugin.native.js.map +1 -1
  42. package/dist/esm/asyncTasks.mjs +26 -0
  43. package/dist/esm/asyncTasks.mjs.map +1 -0
  44. package/dist/esm/asyncTasks.native.js +56 -0
  45. package/dist/esm/asyncTasks.native.js.map +1 -0
  46. package/dist/esm/cli.mjs +8 -1
  47. package/dist/esm/cli.mjs.map +1 -1
  48. package/dist/esm/cli.native.js +8 -1
  49. package/dist/esm/cli.native.js.map +1 -1
  50. package/dist/esm/createZeroDirectServer.mjs +20 -30
  51. package/dist/esm/createZeroDirectServer.mjs.map +1 -1
  52. package/dist/esm/createZeroDirectServer.native.js +28 -33
  53. package/dist/esm/createZeroDirectServer.native.js.map +1 -1
  54. package/dist/esm/createZeroSQLiteServer.test.mjs +6 -6
  55. package/dist/esm/createZeroSQLiteServer.test.mjs.map +1 -1
  56. package/dist/esm/createZeroSQLiteServer.test.native.js +6 -6
  57. package/dist/esm/createZeroSQLiteServer.test.native.js.map +1 -1
  58. package/dist/esm/createZeroServer.mjs.map +1 -1
  59. package/dist/esm/createZeroServer.native.js.map +1 -1
  60. package/dist/esm/createZeroServer.test.mjs +178 -2
  61. package/dist/esm/createZeroServer.test.mjs.map +1 -1
  62. package/dist/esm/createZeroServer.test.native.js +190 -2
  63. package/dist/esm/createZeroServer.test.native.js.map +1 -1
  64. package/dist/esm/createZeroServerCore.mjs +9 -3
  65. package/dist/esm/createZeroServerCore.mjs.map +1 -1
  66. package/dist/esm/createZeroServerCore.native.js +13 -5
  67. package/dist/esm/createZeroServerCore.native.js.map +1 -1
  68. package/dist/esm/generate.mjs +5 -2
  69. package/dist/esm/generate.mjs.map +1 -1
  70. package/dist/esm/generate.native.js +5 -2
  71. package/dist/esm/generate.native.js.map +1 -1
  72. package/dist/esm/generate.test.mjs +16 -0
  73. package/dist/esm/generate.test.mjs.map +1 -1
  74. package/dist/esm/generate.test.native.js +16 -0
  75. package/dist/esm/generate.test.native.js.map +1 -1
  76. package/dist/esm/helpers/createMutators.mjs +2 -2
  77. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  78. package/dist/esm/helpers/createMutators.native.js +2 -2
  79. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  80. package/dist/esm/index.js +1 -0
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/esm/index.mjs +1 -0
  83. package/dist/esm/index.mjs.map +1 -1
  84. package/dist/esm/index.native.js +1 -0
  85. package/dist/esm/index.native.js.map +1 -1
  86. package/dist/esm/server.mjs +1 -0
  87. package/dist/esm/server.mjs.map +1 -1
  88. package/dist/esm/syncHost.mjs +10 -3
  89. package/dist/esm/syncHost.mjs.map +1 -1
  90. package/dist/esm/syncHost.native.js +11 -4
  91. package/dist/esm/syncHost.native.js.map +1 -1
  92. package/dist/esm/syncHost.test.mjs +2 -2
  93. package/dist/esm/syncHost.test.mjs.map +1 -1
  94. package/dist/esm/syncHost.test.native.js +2 -2
  95. package/dist/esm/syncHost.test.native.js.map +1 -1
  96. package/dist/esm/vite-plugin.mjs +2 -1
  97. package/dist/esm/vite-plugin.mjs.map +1 -1
  98. package/dist/esm/vite-plugin.native.js +2 -1
  99. package/dist/esm/vite-plugin.native.js.map +1 -1
  100. package/lint/ssr-guards.js +8 -7
  101. package/package.json +2 -2
  102. package/readme.md +21 -5
  103. package/src/asyncTasks.ts +33 -0
  104. package/src/cli.ts +7 -1
  105. package/src/createZeroDirectServer.ts +20 -36
  106. package/src/createZeroSQLiteServer.test.ts +8 -7
  107. package/src/createZeroServer.test.ts +192 -2
  108. package/src/createZeroServer.ts +2 -0
  109. package/src/createZeroServerCore.ts +18 -11
  110. package/src/generate.test.ts +18 -0
  111. package/src/generate.ts +7 -1
  112. package/src/helpers/createMutators.ts +3 -3
  113. package/src/helpers/mutatorContext.ts +1 -1
  114. package/src/index.ts +1 -0
  115. package/src/server.ts +2 -0
  116. package/src/syncHost.test.ts +2 -2
  117. package/src/syncHost.ts +6 -4
  118. package/src/types.ts +21 -3
  119. package/src/vite-plugin.ts +1 -0
  120. package/test-fixtures/server-return-types.ts +24 -1
  121. package/types/asyncTasks.d.ts +7 -0
  122. package/types/asyncTasks.d.ts.map +1 -0
  123. package/types/createZeroDirectServer.d.ts +3 -3
  124. package/types/createZeroDirectServer.d.ts.map +1 -1
  125. package/types/createZeroServer.d.ts +1 -1
  126. package/types/createZeroServer.d.ts.map +1 -1
  127. package/types/createZeroServerCore.d.ts +9 -6
  128. package/types/createZeroServerCore.d.ts.map +1 -1
  129. package/types/generate.d.ts +2 -0
  130. package/types/generate.d.ts.map +1 -1
  131. package/types/helpers/createMutators.d.ts +3 -3
  132. package/types/helpers/createMutators.d.ts.map +1 -1
  133. package/types/index.d.ts +1 -0
  134. package/types/index.d.ts.map +1 -1
  135. package/types/server.d.ts +2 -0
  136. package/types/server.d.ts.map +1 -1
  137. package/types/syncHost.d.ts.map +1 -1
  138. package/types/types.d.ts +18 -2
  139. package/types/types.d.ts.map +1 -1
  140. package/types/vite-plugin.d.ts.map +1 -1
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from 'vitest'
1
+ import { describe, expect, test, vi } from 'vitest'
2
2
 
3
3
  import { createZeroServer } from './createZeroServer'
4
4
  import { zeroHttpFixtureSchema } from './httpPull/fixtureSchema'
@@ -103,7 +103,7 @@ describe('createZeroServer mutation recovery', () => {
103
103
  project: {
104
104
  mutate: {
105
105
  touch: async ({ server }) => {
106
- server?.asyncTasks.push(async () => {
106
+ server?.enqueueTask(async () => {
107
107
  effectRuns++
108
108
  })
109
109
  throw new Error('rejected')
@@ -129,6 +129,196 @@ describe('createZeroServer mutation recovery', () => {
129
129
  expect(effectRuns).toBe(0)
130
130
  })
131
131
 
132
+ test('awaits barrier tasks before resolving the push response', async () => {
133
+ const pg = new FakePgClient()
134
+ let releaseBarrier!: () => void
135
+ let markBarrierStarted!: () => void
136
+ const barrierStarted = new Promise<void>((resolve) => {
137
+ markBarrierStarted = resolve
138
+ })
139
+ const barrier = new Promise<void>((resolve) => {
140
+ releaseBarrier = resolve
141
+ })
142
+ const zeroServer = createZeroServer({
143
+ schema: zeroHttpFixtureSchema,
144
+ models: {
145
+ project: {
146
+ mutate: {
147
+ touch: async ({ server }) => {
148
+ server?.enqueueTask(
149
+ async () => {
150
+ markBarrierStarted()
151
+ await barrier
152
+ },
153
+ { barrier: true },
154
+ )
155
+ },
156
+ },
157
+ },
158
+ },
159
+ createServerActions: () => ({}),
160
+ pool: pg as any,
161
+ })
162
+
163
+ let responseResolved = false
164
+ const resultPromise = zeroServer
165
+ .handleMutationRequest({
166
+ authData: null,
167
+ request: pushRequest(1),
168
+ })
169
+ .then((result) => {
170
+ responseResolved = true
171
+ return result
172
+ })
173
+
174
+ await barrierStarted
175
+ await Promise.resolve()
176
+ expect(responseResolved).toBe(false)
177
+
178
+ releaseBarrier()
179
+ const result = await resultPromise
180
+ expect((result.response as any).mutations[0].result).toEqual({})
181
+ })
182
+
183
+ test('does not fail the push when a background task rejects', async () => {
184
+ const pg = new FakePgClient()
185
+ const error = new Error('background failed')
186
+ const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
187
+ const zeroServer = createZeroServer({
188
+ schema: zeroHttpFixtureSchema,
189
+ models: {
190
+ project: {
191
+ mutate: {
192
+ touch: async ({ server }) => {
193
+ server?.enqueueTask(async () => {
194
+ throw error
195
+ })
196
+ },
197
+ },
198
+ },
199
+ },
200
+ createServerActions: () => ({}),
201
+ pool: pg as any,
202
+ })
203
+
204
+ const result = await zeroServer.handleMutationRequest({
205
+ authData: null,
206
+ request: pushRequest(1),
207
+ })
208
+
209
+ expect((result.response as any).mutations[0].result).toEqual({})
210
+ await vi.waitFor(() => {
211
+ expect(consoleError).toHaveBeenCalledWith('[on-zero] async task failed', error)
212
+ })
213
+ consoleError.mockRestore()
214
+ })
215
+
216
+ test('registers a promise that settles every background task with the request scheduler', async () => {
217
+ const pg = new FakePgClient()
218
+ const error = new Error('background failed')
219
+ const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
220
+ let releaseSibling!: () => void
221
+ const siblingGate = new Promise<void>((resolve) => {
222
+ releaseSibling = resolve
223
+ })
224
+ let siblingFinished = false
225
+ let scheduled: Promise<void> | undefined
226
+ const zeroServer = createZeroServer({
227
+ schema: zeroHttpFixtureSchema,
228
+ models: {
229
+ project: {
230
+ mutate: {
231
+ touch: async ({ server }) => {
232
+ server?.enqueueTask(async () => {
233
+ throw error
234
+ })
235
+ server?.enqueueTask(async () => {
236
+ await siblingGate
237
+ siblingFinished = true
238
+ })
239
+ },
240
+ },
241
+ },
242
+ },
243
+ createServerActions: () => ({}),
244
+ pool: pg as any,
245
+ })
246
+
247
+ const result = await zeroServer.handleMutationRequest({
248
+ authData: null,
249
+ request: pushRequest(1),
250
+ scheduleBackgroundTask: (promise) => {
251
+ scheduled = promise
252
+ },
253
+ })
254
+
255
+ expect((result.response as any).mutations[0].result).toEqual({})
256
+ expect(scheduled).toBeInstanceOf(Promise)
257
+ expect(siblingFinished).toBe(false)
258
+
259
+ let scheduledSettled = false
260
+ void scheduled!.then(() => {
261
+ scheduledSettled = true
262
+ })
263
+ await Promise.resolve()
264
+ expect(scheduledSettled).toBe(false)
265
+
266
+ releaseSibling()
267
+ await scheduled
268
+
269
+ expect(siblingFinished).toBe(true)
270
+ expect(consoleError).toHaveBeenCalledWith('[on-zero] async task failed', error)
271
+ consoleError.mockRestore()
272
+ })
273
+
274
+ test('awaits background tasks when the request has no scheduler', async () => {
275
+ const pg = new FakePgClient()
276
+ let markTaskStarted!: () => void
277
+ const taskStarted = new Promise<void>((resolve) => {
278
+ markTaskStarted = resolve
279
+ })
280
+ let releaseTask!: () => void
281
+ const taskGate = new Promise<void>((resolve) => {
282
+ releaseTask = resolve
283
+ })
284
+ const zeroServer = createZeroServer({
285
+ schema: zeroHttpFixtureSchema,
286
+ models: {
287
+ project: {
288
+ mutate: {
289
+ touch: async ({ server }) => {
290
+ server?.enqueueTask(async () => {
291
+ markTaskStarted()
292
+ await taskGate
293
+ })
294
+ },
295
+ },
296
+ },
297
+ },
298
+ createServerActions: () => ({}),
299
+ pool: pg as any,
300
+ })
301
+
302
+ let responseResolved = false
303
+ const resultPromise = zeroServer
304
+ .handleMutationRequest({
305
+ authData: null,
306
+ request: pushRequest(1),
307
+ })
308
+ .then((result) => {
309
+ responseResolved = true
310
+ return result
311
+ })
312
+
313
+ await taskStarted
314
+ await Promise.resolve()
315
+ expect(responseResolved).toBe(false)
316
+
317
+ releaseTask()
318
+ const result = await resultPromise
319
+ expect((result.response as any).mutations[0].result).toEqual({})
320
+ })
321
+
132
322
  test('persists alreadyProcessed duplicate results for zero-cache recovery rows', async () => {
133
323
  const pg = new FakePgClient()
134
324
  const zeroServer = createZeroServer({
@@ -15,6 +15,8 @@ import type { Schema as ZeroSchema } from '@rocicorp/zero'
15
15
  import type { NodePgTransaction } from '@rocicorp/zero/server/adapters/pg'
16
16
 
17
17
  export type {
18
+ BackgroundTaskScheduler,
19
+ HandleMutationRequestOptions,
18
20
  ValidateMutationArgs,
19
21
  ValidateMutationFn,
20
22
  ValidateQueryArgs,
@@ -3,6 +3,7 @@ import {
3
3
  handleQueryRequest as zeroHandleQueryRequest,
4
4
  } from '@rocicorp/zero/server'
5
5
 
6
+ import { runAsyncTaskEntries } from './asyncTasks'
6
7
  import {
7
8
  createAsyncTaskCollector,
8
9
  createZeroDirectServerRuntime,
@@ -33,6 +34,15 @@ type PushRequestBody = {
33
34
  clientGroupID?: unknown
34
35
  }
35
36
 
37
+ export type BackgroundTaskScheduler = (promise: Promise<void>) => void
38
+
39
+ export type HandleMutationRequestOptions = {
40
+ authData: AuthData | null
41
+ request: Request
42
+ scheduleBackgroundTask?: BackgroundTaskScheduler
43
+ skipAsyncTasks?: boolean
44
+ }
45
+
36
46
  export type PersistAlreadyProcessedArgs = {
37
47
  clientGroupID: string
38
48
  mutations: AlreadyProcessedMutation[]
@@ -81,16 +91,13 @@ export function createZeroServerCore<
81
91
  const handleMutationRequest = async ({
82
92
  authData,
83
93
  request,
94
+ scheduleBackgroundTask,
84
95
  skipAsyncTasks,
85
- }: {
86
- authData: AuthData | null
87
- request: Request
88
- skipAsyncTasks?: boolean
89
- }) => {
96
+ }: HandleMutationRequestOptions) => {
90
97
  const tasks = createAsyncTaskCollector()
91
98
  const recoveryRequest = request.clone()
92
99
  const mutators = createMutators({
93
- asyncTasks: tasks.queue,
100
+ enqueueTask: tasks.enqueueTask,
94
101
  can: permissions.can,
95
102
  createServerActions,
96
103
  environment: 'server',
@@ -110,11 +117,11 @@ export function createZeroServerCore<
110
117
  }
111
118
 
112
119
  if (!skipAsyncTasks && tasks.committed.length) {
113
- Promise.all(tasks.committed.map((task) => runWithAuthScope(authData, task))).catch(
114
- (err: unknown) => {
115
- console.error('[push] async tasks failed', err)
116
- },
117
- )
120
+ const entries = tasks.committed.map((entry) => ({
121
+ ...entry,
122
+ task: () => runWithAuthScope(authData, entry.task),
123
+ }))
124
+ await runAsyncTaskEntries(entries, { background: scheduleBackgroundTask })
118
125
  }
119
126
 
120
127
  return {
@@ -218,6 +218,24 @@ export const allPosts = () => zero.query.post
218
218
  const second = await generate({ dir: testDir, silent: true })
219
219
  expect(second.filesChanged).toBe(0)
220
220
  })
221
+
222
+ test('force regenerates without source changes', async () => {
223
+ writeFileSync(
224
+ join(testDir, 'models/post.ts'),
225
+ `export const schema = table('post', { id: string() })`,
226
+ )
227
+ writeFileSync(
228
+ join(testDir, 'queries/post.ts'),
229
+ `export const allPosts = () => zero.query.post`,
230
+ )
231
+ await generate({ dir: testDir, silent: true })
232
+ const syncedQueriesPath = join(testDir, 'generated/syncedQueries.ts')
233
+ rmSync(syncedQueriesPath)
234
+
235
+ await generate({ dir: testDir, silent: true, force: true })
236
+
237
+ expect(existsSync(syncedQueriesPath)).toBe(true)
238
+ })
221
239
  })
222
240
 
223
241
  describe('mutations', () => {
package/src/generate.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  import type { ExtractedMutation, ModelMutations, SchemaColumn } from './generate-helpers'
18
18
 
19
19
  const hash = (s: string) => createHash('sha256').update(s).digest('hex')
20
+ const GENERATOR_CACHE_VERSION = '1'
20
21
 
21
22
  const isGeneratorSourceFile = (name: string) =>
22
23
  name.endsWith('.ts') &&
@@ -793,6 +794,8 @@ export interface GenerateOptions {
793
794
  after?: string
794
795
  /** suppress output */
795
796
  silent?: boolean
797
+ /** ignore the generation cache */
798
+ force?: boolean
796
799
  }
797
800
 
798
801
  export interface WatchOptions extends GenerateOptions {
@@ -809,7 +812,7 @@ export interface GenerateResult {
809
812
  }
810
813
 
811
814
  export async function generate(options: GenerateOptions): Promise<GenerateResult> {
812
- const { dir, after, silent } = options
815
+ const { dir, after, silent, force } = options
813
816
  const baseDir = resolve(dir)
814
817
  // support both mutations/ (new) and models/ (legacy) directories
815
818
  const mutationsDir = resolve(baseDir, 'mutations')
@@ -832,6 +835,8 @@ export async function generate(options: GenerateOptions): Promise<GenerateResult
832
835
  // still re-runs generate on real model/query edits.
833
836
  const inputHash = hashInputTree(baseDir, generatedDir)
834
837
  if (
838
+ !force &&
839
+ generateCache.__generatorVersion === GENERATOR_CACHE_VERSION &&
835
840
  generateCache.__inputHash === inputHash &&
836
841
  existsSync(resolve(generatedDir, 'models.ts'))
837
842
  ) {
@@ -1154,6 +1159,7 @@ export async function generate(options: GenerateOptions): Promise<GenerateResult
1154
1159
  }
1155
1160
 
1156
1161
  // record the input hash + counts so the next boot can skip a no-op regen.
1162
+ generateCache.__generatorVersion = GENERATOR_CACHE_VERSION
1157
1163
  generateCache.__inputHash = inputHash
1158
1164
  generateCache.__counts = JSON.stringify({
1159
1165
  modelCount: allModelFiles.length,
@@ -25,7 +25,7 @@ export function createMutators<Models extends GenericModels>({
25
25
  environment,
26
26
  authData,
27
27
  createServerActions,
28
- asyncTasks = [],
28
+ enqueueTask = () => {},
29
29
  can,
30
30
  models,
31
31
  validateMutation,
@@ -35,7 +35,7 @@ export function createMutators<Models extends GenericModels>({
35
35
  authData: AuthData | null
36
36
  can: Can
37
37
  models: Models
38
- asyncTasks?: Array<() => Promise<void>>
38
+ enqueueTask?: NonNullable<MutatorContext['server']>['enqueueTask']
39
39
  createServerActions?: () => Record<string, any>
40
40
  validateMutation?: ValidateMutationFn
41
41
  /** valibot schemas keyed by model.mutationName, auto-validates args before running */
@@ -61,7 +61,7 @@ export function createMutators<Models extends GenericModels>({
61
61
  environment === 'server'
62
62
  ? ({
63
63
  actions: serverActions || {},
64
- asyncTasks: asyncTasks || {},
64
+ enqueueTask,
65
65
  } as MutatorContext['server'])
66
66
  : undefined,
67
67
  }
@@ -13,7 +13,7 @@ const asyncContext =
13
13
  contextStore.__onZeroMutatorContext__ ??
14
14
  (contextStore.__onZeroMutatorContext__ = createAsyncContext<MutatorContext>())
15
15
 
16
- // lightweight auth-only scope for asyncTasks (where mutation context is gone but authData is needed)
16
+ // lightweight auth-only scope for async tasks (where mutation context is gone but authData is needed)
17
17
  const authScopeContext =
18
18
  contextStore.__onZeroAuthScopeContext__ ??
19
19
  (contextStore.__onZeroAuthScopeContext__ = createAsyncContext<AuthData | null>())
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './createPermissions'
2
+ export * from './asyncTasks'
2
3
  export * from './queryRegistry'
3
4
  export * from './helpers/batchQuery'
4
5
  export * from './helpers/createMutators'
package/src/server.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './createZeroServer'
2
2
  export * from './createZeroSQLiteServer'
3
+ export * from './asyncTasks'
4
+ export type { AsyncTask, AsyncTaskEntry, AsyncTaskOptions } from './types'
@@ -86,7 +86,7 @@ describe('createZeroSyncHostAdapter', () => {
86
86
  create: async ({ authData, server, tx }, value: Record<string, unknown>) => {
87
87
  expect(authData?.id).toBe('u1')
88
88
  await tx.mutate.project.insert(value as never)
89
- server?.asyncTasks.push(async () => {
89
+ server?.enqueueTask(async () => {
90
90
  effectAuthID = getScopedAuthData()?.id as string
91
91
  })
92
92
  },
@@ -132,7 +132,7 @@ describe('createZeroSyncHostAdapter', () => {
132
132
  mutate: {
133
133
  reject: async ({ server, tx }, value: Record<string, unknown>) => {
134
134
  await tx.mutate.project.insert(value as never)
135
- server?.asyncTasks.push(async () => {
135
+ server?.enqueueTask(async () => {
136
136
  effectRuns++
137
137
  })
138
138
  throw new Error('denied')
package/src/syncHost.ts CHANGED
@@ -23,7 +23,7 @@ import { runWithAuthScope } from './helpers/mutatorContext'
23
23
  import { runWithQueryContext } from './helpers/queryContext'
24
24
  import { setEnvironment, setSchema } from './state'
25
25
 
26
- import type { AuthData, GenericModels } from './types'
26
+ import type { AsyncTaskEntry, AuthData, GenericModels } from './types'
27
27
  import type { Schema as ZeroSchema } from '@rocicorp/zero'
28
28
 
29
29
  export type SyncHostJsonValue =
@@ -147,9 +147,11 @@ export function createZeroSyncHostAdapter<
147
147
  for (const mutatorName of Object.keys(model.mutate ?? {})) {
148
148
  mutators[`${modelName}|${mutatorName}`] = async (executor, args, context) => {
149
149
  const authData = mapAuthData(context.claims)
150
- const asyncTasks: Array<() => Promise<void>> = []
150
+ const asyncTaskEntries: AsyncTaskEntry[] = []
151
151
  const modelMutators = createMutators({
152
- asyncTasks,
152
+ enqueueTask(task, opts) {
153
+ asyncTaskEntries.push({ task, barrier: opts?.barrier === true })
154
+ },
153
155
  authData,
154
156
  can: permissions.can,
155
157
  createServerActions: options.createServerActions,
@@ -181,7 +183,7 @@ export function createZeroSyncHostAdapter<
181
183
  } catch (error) {
182
184
  throw asMutationApplicationError(error)
183
185
  }
184
- for (const task of asyncTasks) {
186
+ for (const { task } of asyncTaskEntries) {
185
187
  context.defer(() => runWithAuthScope(authData, task))
186
188
  }
187
189
  }
package/src/types.ts CHANGED
@@ -60,6 +60,17 @@ export type ServerActions =
60
60
 
61
61
  export type QueryBuilder = SchemaQuery<Schema>
62
62
 
63
+ export type AsyncTask = () => Promise<void>
64
+
65
+ export type AsyncTaskOptions = {
66
+ barrier?: boolean
67
+ }
68
+
69
+ export type AsyncTaskEntry = {
70
+ task: AsyncTask
71
+ barrier: boolean
72
+ }
73
+
63
74
  /**
64
75
  * ➗0️⃣ END OVERRIDDEN TYPES
65
76
  */
@@ -71,7 +82,16 @@ export type MutatorContext = {
71
82
  environment: 'server' | 'client'
72
83
  server?: {
73
84
  actions: ServerActions
74
- asyncTasks: Array<() => Promise<void>>
85
+ /**
86
+ * Schedules work after the mutation transaction commits. Tasks run in the
87
+ * background by default, following Zero's async task model, so they do not
88
+ * block the push response.
89
+ *
90
+ * Set `barrier: true` only when the client's next writes depend on the
91
+ * effect, such as provisioning a namespace before the client writes
92
+ * through a new instance. Barrier tasks finish before the push response.
93
+ */
94
+ enqueueTask(task: AsyncTask, opts?: AsyncTaskOptions): void
75
95
  }
76
96
  can: Can
77
97
  }
@@ -112,8 +132,6 @@ export type Can = <PWhere extends Where>(
112
132
  obj: string | Record<string, unknown>,
113
133
  ) => Promise<void>
114
134
 
115
- export type AsyncAction = () => Promise<void>
116
-
117
135
  type GenericTable = TableBuilderWithColumns<any>
118
136
 
119
137
  type GetTableSchema<TS extends GenericTable> =
@@ -62,6 +62,7 @@ export function onZeroPlugin(options: OnZeroPluginOptions = {}): Plugin[] {
62
62
  dir: dataDir,
63
63
  after: options.after,
64
64
  silent,
65
+ force: options.force,
65
66
  })
66
67
 
67
68
  return [
@@ -1,4 +1,10 @@
1
- import { createZeroServer } from 'on-zero/server'
1
+ import {
2
+ createZeroServer,
3
+ runAsyncTaskEntries,
4
+ type AsyncTaskEntry,
5
+ type BackgroundTaskScheduler,
6
+ type HandleMutationRequestOptions,
7
+ } from 'on-zero/server'
2
8
  import { createZeroSQLiteServer, type SqlStatementMetadata } from 'on-zero/sqlite'
3
9
 
4
10
  import type { Config, MutatorContext } from 'on-zero'
@@ -30,6 +36,7 @@ type SQLiteServer = ReturnType<typeof createZeroSQLiteServer<ZeroSchema, Models,
30
36
 
31
37
  declare const postgresServer: PostgresServer
32
38
  declare const sqliteServer: SQLiteServer
39
+ declare const taskEntries: AsyncTaskEntry[]
33
40
 
34
41
  const authData: Config['authData'] = {
35
42
  email: 'admin@example.com',
@@ -44,6 +51,22 @@ const sqliteWrite: SqlStatementMetadata = {
44
51
  }
45
52
  void sqliteWrite
46
53
 
54
+ void runAsyncTaskEntries(taskEntries, {
55
+ background(promise) {
56
+ void promise
57
+ },
58
+ })
59
+
60
+ const scheduleBackgroundTask: BackgroundTaskScheduler = (promise) => {
61
+ void promise
62
+ }
63
+ const mutationRequest: HandleMutationRequestOptions = {
64
+ authData,
65
+ request: new Request('https://example.com/api/zero/push'),
66
+ scheduleBackgroundTask,
67
+ }
68
+ void postgresServer.handleMutationRequest(mutationRequest)
69
+
47
70
  postgresServer.mutate.project.create(
48
71
  { id: 'pg' },
49
72
  { authData: { email: authData.email, id: authData.id, role: authData.role } },
@@ -0,0 +1,7 @@
1
+ import type { AsyncTaskEntry } from './types';
2
+ export type RunAsyncTaskEntriesOptions = {
3
+ /** Receives the background-task promise. Omit this to await all entries. */
4
+ background?: (promise: Promise<void>) => void;
5
+ };
6
+ export declare function runAsyncTaskEntries(entries: readonly AsyncTaskEntry[], { background }?: RunAsyncTaskEntriesOptions): Promise<void>;
7
+ //# sourceMappingURL=asyncTasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncTasks.d.ts","sourceRoot":"","sources":["../src/asyncTasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,MAAM,0BAA0B,GAAG;IACvC,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;CAC9C,CAAA;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,EAAE,UAAU,EAAE,GAAE,0BAA+B,GAC9C,OAAO,CAAC,IAAI,CAAC,CAsBf"}
@@ -1,5 +1,5 @@
1
1
  import { createPermissions } from './createPermissions';
2
- import type { AdminRoleMode, AsyncAction, AuthData, GenericModels, MutatorContext, QueryBuilder, Transaction } from './types';
2
+ import type { AdminRoleMode, AsyncTask, AsyncTaskEntry, AsyncTaskOptions, AuthData, GenericModels, MutatorContext, QueryBuilder, Transaction } from './types';
3
3
  import type { AnyQueryRegistry, HumanReadable, Query, Schema as ZeroSchema } from '@rocicorp/zero';
4
4
  import type { Database } from '@rocicorp/zero/server';
5
5
  type MutateAuthData = Pick<AuthData, 'email' | 'id'> & Partial<AuthData>;
@@ -67,9 +67,9 @@ export type ZeroDirectServer<Schema extends ZeroSchema, Models extends GenericMo
67
67
  query: <R>(cb: (q: QueryBuilder) => Query<any, Schema, R>, authData?: AuthData | null) => Promise<HumanReadable<R>>;
68
68
  };
69
69
  export declare function createAsyncTaskCollector(): {
70
- committed: AsyncAction[];
70
+ committed: AsyncTaskEntry[];
71
+ enqueueTask: (task: AsyncTask, opts?: AsyncTaskOptions) => void;
71
72
  lifecycle: TransactionAttemptLifecycle;
72
- queue: AsyncAction[];
73
73
  };
74
74
  export declare function createZeroDirectServerRuntime<Schema extends ZeroSchema, Models extends GenericModels, ServerActions extends Record<string, unknown>>({ createDatabase, createServerActions, defaultAllowAdminRole, defaultMutateAuthData, models, mutations: mutationValidators, queries, schema, validateMutation, validateQuery, }: ZeroDirectServerOptions<Schema, Models, ServerActions>): {
75
75
  permissions: ReturnType<typeof createPermissions<Schema>>;
@@ -1 +1 @@
1
- {"version":3,"file":"createZeroDirectServer.d.ts","sourceRoot":"","sources":["../src/createZeroDirectServer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"createZeroDirectServer.d.ts","sourceRoot":"","sources":["../src/createZeroDirectServer.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import type { ZeroServer, ZeroServerCommonOptions } from './createZeroServerCore
2
2
  import type { GenericModels } from './types';
3
3
  import type { Schema as ZeroSchema } from '@rocicorp/zero';
4
4
  import type { NodePgTransaction } from '@rocicorp/zero/server/adapters/pg';
5
- export type { ValidateMutationArgs, ValidateMutationFn, ValidateQueryArgs, ValidateQueryFn, } from './createZeroServerCore';
5
+ export type { BackgroundTaskScheduler, HandleMutationRequestOptions, ValidateMutationArgs, ValidateMutationFn, ValidateQueryArgs, ValidateQueryFn, } from './createZeroServerCore';
6
6
  export declare function createZeroServer<Schema extends ZeroSchema, Models extends GenericModels, ServerActions extends Record<string, unknown>>({ database, pool: externalPool, ...options }: ZeroServerCommonOptions<Schema, Models, ServerActions> & {
7
7
  /**
8
8
  * Optional pre-built Pool-like object, such as a PGlite wrapper.
@@ -1 +1 @@
1
- {"version":3,"file":"createZeroServer.d.ts","sourceRoot":"","sources":["../src/createZeroServer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,UAAU,EACV,uBAAuB,EAExB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AAE1E,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,GAChB,MAAM,wBAAwB,CAAA;AAE/B,wBAAgB,gBAAgB,CAC9B,MAAM,SAAS,UAAU,EACzB,MAAM,SAAS,aAAa,EAC5B,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,EACA,QAAQ,EACR,IAAI,EAAE,YAAY,EAClB,GAAG,OAAO,EACX,EAAE,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG;IAC1D;;;OAGG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CA8B5C"}
1
+ {"version":3,"file":"createZeroServer.d.ts","sourceRoot":"","sources":["../src/createZeroServer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,UAAU,EACV,uBAAuB,EAExB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AAE1E,YAAY,EACV,uBAAuB,EACvB,4BAA4B,EAC5B,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,GAChB,MAAM,wBAAwB,CAAA;AAE/B,wBAAgB,gBAAgB,CAC9B,MAAM,SAAS,UAAU,EACzB,MAAM,SAAS,aAAa,EAC5B,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,EACA,QAAQ,EACR,IAAI,EAAE,YAAY,EAClB,GAAG,OAAO,EACX,EAAE,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG;IAC1D;;;OAGG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CA8B5C"}
@@ -11,6 +11,13 @@ type AlreadyProcessedMutation = {
11
11
  details?: unknown;
12
12
  };
13
13
  };
14
+ export type BackgroundTaskScheduler = (promise: Promise<void>) => void;
15
+ export type HandleMutationRequestOptions = {
16
+ authData: AuthData | null;
17
+ request: Request;
18
+ scheduleBackgroundTask?: BackgroundTaskScheduler;
19
+ skipAsyncTasks?: boolean;
20
+ };
14
21
  export type PersistAlreadyProcessedArgs = {
15
22
  clientGroupID: string;
16
23
  mutations: AlreadyProcessedMutation[];
@@ -24,11 +31,7 @@ export declare function createZeroServerCore<Schema extends ZeroSchema, Models e
24
31
  transaction: <CB extends (tx: import("./types").Transaction) => Promise<any>, Returns extends CB extends (tx: import("./types").Transaction) => Promise<infer X> ? X : never>(query: CB) => Promise<Returns>;
25
32
  mutate: import("./createZeroDirectServer").ServerMutate<Models>;
26
33
  query: <R>(cb: (q: import("./types").QueryBuilder) => import("@rocicorp/zero").Query<any, Schema, R>, authData?: {} | null | undefined) => Promise<import("@rocicorp/zero").HumanReadable<R>>;
27
- handleMutationRequest: ({ authData, request, skipAsyncTasks, }: {
28
- authData: AuthData | null;
29
- request: Request;
30
- skipAsyncTasks?: boolean;
31
- }) => Promise<{
34
+ handleMutationRequest: ({ authData, request, scheduleBackgroundTask, skipAsyncTasks, }: HandleMutationRequestOptions) => Promise<{
32
35
  response: {
33
36
  userID?: string | null | undefined;
34
37
  kind: "MutateResponse";
@@ -157,7 +160,7 @@ export declare function createZeroServerCore<Schema extends ZeroSchema, Models e
157
160
  origin: "zeroCache";
158
161
  reason: "parse" | "timeout" | "internal";
159
162
  };
160
- asyncTasks: import("./types").AsyncAction[];
163
+ asyncTasks: import("./types").AsyncTaskEntry[];
161
164
  }>;
162
165
  handleQueryRequest: ({ authData, request, }: {
163
166
  authData: AuthData | null;