on-zero 0.7.2-1784530701923 → 0.7.2
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/dist/cjs/asyncTasks.cjs +51 -0
- package/dist/cjs/asyncTasks.native.js +84 -0
- package/dist/cjs/asyncTasks.native.js.map +1 -0
- package/dist/cjs/createZeroDirectServer.cjs +269 -0
- package/dist/cjs/createZeroDirectServer.native.js +287 -0
- package/dist/cjs/createZeroDirectServer.native.js.map +1 -0
- package/dist/cjs/createZeroSQLiteServer.cjs +50 -0
- package/dist/cjs/createZeroSQLiteServer.native.js +58 -0
- package/dist/cjs/createZeroSQLiteServer.native.js.map +1 -0
- package/dist/cjs/createZeroSQLiteServer.test.cjs +595 -0
- package/dist/cjs/createZeroSQLiteServer.test.native.js +647 -0
- package/dist/cjs/createZeroSQLiteServer.test.native.js.map +1 -0
- package/dist/cjs/createZeroServer.cjs +82 -0
- package/dist/cjs/createZeroServer.native.js +93 -0
- package/dist/cjs/createZeroServer.native.js.map +1 -0
- package/dist/cjs/createZeroServer.test.cjs +378 -0
- package/dist/cjs/createZeroServer.test.native.js +448 -0
- package/dist/cjs/createZeroServer.test.native.js.map +1 -0
- package/dist/cjs/createZeroServerCore.cjs +211 -0
- package/dist/cjs/createZeroServerCore.native.js +355 -0
- package/dist/cjs/createZeroServerCore.native.js.map +1 -0
- package/dist/cjs/helpers/createMutators.cjs +3 -4
- package/dist/cjs/helpers/createMutators.native.js +3 -6
- package/dist/cjs/helpers/createMutators.native.js.map +1 -1
- package/dist/cjs/httpPull/auth.test.cjs +197 -0
- package/dist/cjs/httpPull/auth.test.native.js +279 -0
- package/dist/cjs/httpPull/auth.test.native.js.map +1 -0
- package/dist/cjs/httpPull/churn.test.cjs +132 -0
- package/dist/cjs/httpPull/churn.test.native.js +155 -0
- package/dist/cjs/httpPull/churn.test.native.js.map +1 -0
- package/dist/cjs/httpPull/completeAck.test.cjs +69 -0
- package/dist/cjs/httpPull/completeAck.test.native.js +76 -0
- package/dist/cjs/httpPull/completeAck.test.native.js.map +1 -0
- package/dist/cjs/httpPull/fixtureServer.cjs +340 -0
- package/dist/cjs/httpPull/fixtureServer.native.js +534 -0
- package/dist/cjs/httpPull/fixtureServer.native.js.map +1 -0
- package/dist/cjs/httpPull/integration.test.cjs +53 -0
- package/dist/cjs/httpPull/integration.test.native.js +60 -0
- package/dist/cjs/httpPull/integration.test.native.js.map +1 -0
- package/dist/cjs/httpPull/rebase.test.cjs +360 -0
- package/dist/cjs/httpPull/rebase.test.native.js +420 -0
- package/dist/cjs/httpPull/rebase.test.native.js.map +1 -0
- package/dist/cjs/httpPull/relations.test.cjs +107 -0
- package/dist/cjs/httpPull/relations.test.native.js +119 -0
- package/dist/cjs/httpPull/relations.test.native.js.map +1 -0
- package/dist/cjs/httpPull/testHarness.cjs +100 -0
- package/dist/cjs/httpPull/testHarness.native.js +112 -0
- package/dist/cjs/httpPull/testHarness.native.js.map +1 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.native.js +1 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/run.cjs +1 -1
- package/dist/cjs/run.native.js +1 -1
- package/dist/cjs/server.cjs +22 -0
- package/dist/cjs/server.native.js +4 -0
- package/dist/cjs/server.native.js.map +1 -0
- package/dist/cjs/sqliteRuntime.cjs +318 -0
- package/dist/cjs/sqliteRuntime.native.js +438 -0
- package/dist/cjs/sqliteRuntime.native.js.map +1 -0
- package/dist/cjs/state.cjs +1 -1
- package/dist/cjs/state.native.js +1 -1
- package/dist/cjs/syncHost.cjs +179 -0
- package/dist/cjs/syncHost.native.js +388 -0
- package/dist/cjs/syncHost.native.js.map +1 -0
- package/dist/cjs/syncHost.test.cjs +240 -0
- package/dist/cjs/syncHost.test.native.js +290 -0
- package/dist/cjs/syncHost.test.native.js.map +1 -0
- package/dist/cjs/zeroRunner.cjs +1 -1
- package/dist/cjs/zeroRunner.native.js +1 -1
- package/dist/esm/asyncTasks.mjs +26 -0
- package/dist/esm/asyncTasks.mjs.map +1 -0
- package/dist/esm/asyncTasks.native.js +56 -0
- package/dist/esm/asyncTasks.native.js.map +1 -0
- package/dist/esm/createZeroDirectServer.mjs +241 -0
- package/dist/esm/createZeroDirectServer.mjs.map +1 -0
- package/dist/esm/createZeroDirectServer.native.js +256 -0
- package/dist/esm/createZeroDirectServer.native.js.map +1 -0
- package/dist/esm/createZeroSQLiteServer.mjs +24 -0
- package/dist/esm/createZeroSQLiteServer.mjs.map +1 -0
- package/dist/esm/createZeroSQLiteServer.native.js +29 -0
- package/dist/esm/createZeroSQLiteServer.native.js.map +1 -0
- package/dist/esm/createZeroSQLiteServer.test.mjs +596 -0
- package/dist/esm/createZeroSQLiteServer.test.mjs.map +1 -0
- package/dist/esm/createZeroSQLiteServer.test.native.js +645 -0
- package/dist/esm/createZeroSQLiteServer.test.native.js.map +1 -0
- package/dist/esm/createZeroServer.mjs +57 -0
- package/dist/esm/createZeroServer.mjs.map +1 -0
- package/dist/esm/createZeroServer.native.js +65 -0
- package/dist/esm/createZeroServer.native.js.map +1 -0
- package/dist/esm/createZeroServer.test.mjs +379 -0
- package/dist/esm/createZeroServer.test.mjs.map +1 -0
- package/dist/esm/createZeroServer.test.native.js +446 -0
- package/dist/esm/createZeroServer.test.native.js.map +1 -0
- package/dist/esm/createZeroServerCore.mjs +186 -0
- package/dist/esm/createZeroServerCore.mjs.map +1 -0
- package/dist/esm/createZeroServerCore.native.js +327 -0
- package/dist/esm/createZeroServerCore.native.js.map +1 -0
- package/dist/esm/helpers/createMutators.mjs +3 -4
- package/dist/esm/helpers/createMutators.mjs.map +1 -1
- package/dist/esm/helpers/createMutators.native.js +3 -6
- package/dist/esm/helpers/createMutators.native.js.map +1 -1
- package/dist/esm/httpPull/auth.test.mjs +198 -0
- package/dist/esm/httpPull/auth.test.mjs.map +1 -0
- package/dist/esm/httpPull/auth.test.native.js +277 -0
- package/dist/esm/httpPull/auth.test.native.js.map +1 -0
- package/dist/esm/httpPull/churn.test.mjs +133 -0
- package/dist/esm/httpPull/churn.test.mjs.map +1 -0
- package/dist/esm/httpPull/churn.test.native.js +153 -0
- package/dist/esm/httpPull/churn.test.native.js.map +1 -0
- package/dist/esm/httpPull/completeAck.test.mjs +70 -0
- package/dist/esm/httpPull/completeAck.test.mjs.map +1 -0
- package/dist/esm/httpPull/completeAck.test.native.js +74 -0
- package/dist/esm/httpPull/completeAck.test.native.js.map +1 -0
- package/dist/esm/httpPull/fixtureServer.mjs +315 -0
- package/dist/esm/httpPull/fixtureServer.mjs.map +1 -0
- package/dist/esm/httpPull/fixtureServer.native.js +506 -0
- package/dist/esm/httpPull/fixtureServer.native.js.map +1 -0
- package/dist/esm/httpPull/integration.test.mjs +54 -0
- package/dist/esm/httpPull/integration.test.mjs.map +1 -0
- package/dist/esm/httpPull/integration.test.native.js +58 -0
- package/dist/esm/httpPull/integration.test.native.js.map +1 -0
- package/dist/esm/httpPull/rebase.test.mjs +361 -0
- package/dist/esm/httpPull/rebase.test.mjs.map +1 -0
- package/dist/esm/httpPull/rebase.test.native.js +418 -0
- package/dist/esm/httpPull/rebase.test.native.js.map +1 -0
- package/dist/esm/httpPull/relations.test.mjs +108 -0
- package/dist/esm/httpPull/relations.test.mjs.map +1 -0
- package/dist/esm/httpPull/relations.test.native.js +117 -0
- package/dist/esm/httpPull/relations.test.native.js.map +1 -0
- package/dist/esm/httpPull/testHarness.mjs +72 -0
- package/dist/esm/httpPull/testHarness.mjs.map +1 -0
- package/dist/esm/httpPull/testHarness.native.js +81 -0
- package/dist/esm/httpPull/testHarness.native.js.map +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +1 -0
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/run.mjs +1 -1
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/run.native.js +1 -1
- package/dist/esm/server.mjs +4 -0
- package/dist/esm/server.mjs.map +1 -0
- package/dist/esm/server.native.js +2 -0
- package/dist/esm/server.native.js.map +1 -0
- package/dist/esm/sqliteRuntime.mjs +289 -0
- package/dist/esm/sqliteRuntime.mjs.map +1 -0
- package/dist/esm/sqliteRuntime.native.js +406 -0
- package/dist/esm/sqliteRuntime.native.js.map +1 -0
- package/dist/esm/state.mjs +1 -1
- package/dist/esm/state.native.js +1 -1
- package/dist/esm/syncHost.mjs +153 -0
- package/dist/esm/syncHost.mjs.map +1 -0
- package/dist/esm/syncHost.native.js +359 -0
- package/dist/esm/syncHost.native.js.map +1 -0
- package/dist/esm/syncHost.test.mjs +217 -0
- package/dist/esm/syncHost.test.mjs.map +1 -0
- package/dist/esm/syncHost.test.native.js +264 -0
- package/dist/esm/syncHost.test.native.js.map +1 -0
- package/dist/esm/zeroRunner.mjs +1 -1
- package/dist/esm/zeroRunner.mjs.map +1 -1
- package/dist/esm/zeroRunner.native.js +1 -1
- package/package.json +23 -8
- package/readme.md +65 -40
- package/src/asyncTasks.ts +36 -0
- package/src/createZeroClient.tsx +1 -1
- package/src/createZeroDirectServer.ts +411 -0
- package/src/createZeroSQLiteServer.test.ts +614 -0
- package/src/createZeroSQLiteServer.ts +56 -0
- package/src/createZeroServer.test.ts +421 -0
- package/src/createZeroServer.ts +105 -0
- package/src/createZeroServerCore.ts +296 -0
- package/src/helpers/createMutators.ts +2 -6
- package/src/httpPull/auth.test.ts +208 -0
- package/src/httpPull/churn.test.ts +147 -0
- package/src/httpPull/completeAck.test.ts +80 -0
- package/src/httpPull/fixtureServer.ts +391 -0
- package/src/httpPull/integration.test.ts +57 -0
- package/src/httpPull/rebase.test.ts +368 -0
- package/src/httpPull/relations.test.ts +135 -0
- package/src/httpPull/testHarness.ts +95 -0
- package/src/index.ts +1 -0
- package/src/run.ts +1 -1
- package/src/server.native.ts +3 -0
- package/src/server.ts +4 -0
- package/src/sqliteRuntime.ts +512 -0
- package/src/state.ts +1 -1
- package/src/syncHost.test.ts +223 -0
- package/src/syncHost.ts +294 -0
- package/src/types.ts +5 -0
- package/src/zeroRunner.ts +1 -1
- package/test-fixtures/server-return-types.ts +58 -21
- package/types/asyncTasks.d.ts +11 -0
- package/types/asyncTasks.d.ts.map +1 -0
- package/types/createZeroDirectServer.d.ts +80 -0
- package/types/createZeroDirectServer.d.ts.map +1 -0
- package/types/createZeroSQLiteServer.d.ts +12 -0
- package/types/createZeroSQLiteServer.d.ts.map +1 -0
- package/types/createZeroSQLiteServer.test.d.ts +2 -0
- package/types/createZeroSQLiteServer.test.d.ts.map +1 -0
- package/types/createZeroServer.d.ts +18 -0
- package/types/createZeroServer.d.ts.map +1 -0
- package/types/createZeroServer.test.d.ts +2 -0
- package/types/createZeroServer.test.d.ts.map +1 -0
- package/types/createZeroServerCore.d.ts +256 -0
- package/types/createZeroServerCore.d.ts.map +1 -0
- package/types/helpers/createMutators.d.ts +1 -2
- package/types/helpers/createMutators.d.ts.map +1 -1
- package/types/httpPull/auth.test.d.ts +2 -0
- package/types/httpPull/auth.test.d.ts.map +1 -0
- package/types/httpPull/churn.test.d.ts +2 -0
- package/types/httpPull/churn.test.d.ts.map +1 -0
- package/types/httpPull/completeAck.test.d.ts +2 -0
- package/types/httpPull/completeAck.test.d.ts.map +1 -0
- package/types/httpPull/fixtureSchema.d.ts +1 -1
- package/types/httpPull/fixtureServer.d.ts +14 -0
- package/types/httpPull/fixtureServer.d.ts.map +1 -0
- package/types/httpPull/integration.test.d.ts +2 -0
- package/types/httpPull/integration.test.d.ts.map +1 -0
- package/types/httpPull/rebase.test.d.ts +2 -0
- package/types/httpPull/rebase.test.d.ts.map +1 -0
- package/types/httpPull/relations.test.d.ts +2 -0
- package/types/httpPull/relations.test.d.ts.map +1 -0
- package/types/httpPull/testHarness.d.ts +32 -0
- package/types/httpPull/testHarness.d.ts.map +1 -0
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/server.d.ts +5 -0
- package/types/server.d.ts.map +1 -0
- package/types/server.native.d.ts +1 -0
- package/types/server.native.d.ts.map +1 -0
- package/types/sqliteRuntime.d.ts +71 -0
- package/types/sqliteRuntime.d.ts.map +1 -0
- package/types/syncHost.d.ts +42 -0
- package/types/syncHost.d.ts.map +1 -0
- package/types/syncHost.test.d.ts +2 -0
- package/types/syncHost.test.d.ts.map +1 -0
- package/types/types.d.ts +4 -0
- package/types/types.d.ts.map +1 -1
- package/dist/cjs/orez.cjs +0 -227
- package/dist/cjs/orez.native.js +0 -314
- package/dist/cjs/orez.native.js.map +0 -1
- package/dist/cjs/orez.test.cjs +0 -211
- package/dist/cjs/orez.test.native.js +0 -226
- package/dist/cjs/orez.test.native.js.map +0 -1
- package/dist/esm/orez.mjs +0 -202
- package/dist/esm/orez.mjs.map +0 -1
- package/dist/esm/orez.native.js +0 -286
- package/dist/esm/orez.native.js.map +0 -1
- package/dist/esm/orez.test.mjs +0 -188
- package/dist/esm/orez.test.mjs.map +0 -1
- package/dist/esm/orez.test.native.js +0 -200
- package/dist/esm/orez.test.native.js.map +0 -1
- package/src/orez.test.ts +0 -195
- package/src/orez.ts +0 -331
- package/types/orez.d.ts +0 -53
- package/types/orez.d.ts.map +0 -1
- package/types/orez.test.d.ts +0 -2
- package/types/orez.test.d.ts.map +0 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { DatabaseSync, type SQLInputValue } from 'node:sqlite'
|
|
2
|
+
|
|
3
|
+
import { defineQueries, defineQuery } from '@rocicorp/zero'
|
|
4
|
+
import * as v from 'valibot'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { getScopedAuthData } from './helpers/mutatorContext'
|
|
8
|
+
import { zeroHttpFixtureSchema } from './httpPull/fixtureSchema'
|
|
9
|
+
import { createZeroSyncHostAdapter } from './syncHost'
|
|
10
|
+
import { zql } from './zql'
|
|
11
|
+
|
|
12
|
+
import type { SqlStatementMetadata, SQLiteQueryFormat } from './createZeroSQLiteServer'
|
|
13
|
+
import type {
|
|
14
|
+
SyncHostApplicationTransaction,
|
|
15
|
+
SyncHostMutatorContext,
|
|
16
|
+
SyncHostTransactionExecutor,
|
|
17
|
+
} from './syncHost'
|
|
18
|
+
|
|
19
|
+
const queries = defineQueries({
|
|
20
|
+
project: {
|
|
21
|
+
byOwner: defineQuery(v.object({ ownerId: v.string() }), ({ args }) =>
|
|
22
|
+
zql.project.where('ownerId', args.ownerId),
|
|
23
|
+
),
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('createZeroSyncHostAdapter', () => {
|
|
28
|
+
let db: DatabaseSync
|
|
29
|
+
let executor: SyncHostTransactionExecutor
|
|
30
|
+
let transaction: SyncHostApplicationTransaction
|
|
31
|
+
let lastQueryFormat: SQLiteQueryFormat | undefined
|
|
32
|
+
let statements: SqlStatementMetadata[]
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
db = new DatabaseSync(':memory:')
|
|
36
|
+
db.exec(
|
|
37
|
+
'CREATE TABLE project (id TEXT PRIMARY KEY, ownerId TEXT NOT NULL, name TEXT NOT NULL)',
|
|
38
|
+
)
|
|
39
|
+
statements = []
|
|
40
|
+
executor = {
|
|
41
|
+
exec(sql, params = [], metadata) {
|
|
42
|
+
if (metadata) statements.push(metadata)
|
|
43
|
+
const result = db.prepare(sql).run(...(params as SQLInputValue[]))
|
|
44
|
+
return { changes: Number(result.changes) }
|
|
45
|
+
},
|
|
46
|
+
query<Row extends Record<string, unknown>>(sql, params = []) {
|
|
47
|
+
return db.prepare(sql).all(...(params as SQLInputValue[])) as Row[]
|
|
48
|
+
},
|
|
49
|
+
queryAst<Result>(_ast, format) {
|
|
50
|
+
lastQueryFormat = format
|
|
51
|
+
const rows = db.prepare('SELECT * FROM project ORDER BY id').all()
|
|
52
|
+
return (format.singular ? rows[0] : rows) as Result
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
transaction = async (work) => {
|
|
56
|
+
const effects: Array<() => void | Promise<void>> = []
|
|
57
|
+
db.exec('BEGIN')
|
|
58
|
+
try {
|
|
59
|
+
const value = await work(executor, {
|
|
60
|
+
defer(effect) {
|
|
61
|
+
effects.push(effect)
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
db.exec('COMMIT')
|
|
65
|
+
for (const effect of effects) await effect()
|
|
66
|
+
return value
|
|
67
|
+
} catch (error) {
|
|
68
|
+
db.exec('ROLLBACK')
|
|
69
|
+
throw error
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
db.close()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('adapts pipe-named mutators, auth, validation, and deferred effects', async () => {
|
|
79
|
+
let effectAuthID: string | undefined
|
|
80
|
+
let validatedAuthID: string | undefined
|
|
81
|
+
const adapter = createZeroSyncHostAdapter({
|
|
82
|
+
schema: zeroHttpFixtureSchema,
|
|
83
|
+
models: {
|
|
84
|
+
project: {
|
|
85
|
+
mutate: {
|
|
86
|
+
create: async ({ authData, server, tx }, value: Record<string, unknown>) => {
|
|
87
|
+
expect(authData?.id).toBe('u1')
|
|
88
|
+
await tx.mutate.project.insert(value as never)
|
|
89
|
+
server?.enqueueTask(async () => {
|
|
90
|
+
effectAuthID = getScopedAuthData()?.id as string
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
createServerActions: () => ({}),
|
|
97
|
+
queries,
|
|
98
|
+
transaction,
|
|
99
|
+
validateMutation({ authData }) {
|
|
100
|
+
validatedAuthID = authData?.id as string
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
expect(Object.keys(adapter.mutators)).toEqual([
|
|
105
|
+
'project|create',
|
|
106
|
+
'_zero_cleanupResults',
|
|
107
|
+
])
|
|
108
|
+
await transaction((tx, context) =>
|
|
109
|
+
adapter.mutators['project|create']!(
|
|
110
|
+
tx,
|
|
111
|
+
{ id: 'p1', ownerId: 'u1', name: 'first' },
|
|
112
|
+
mutationContext(context),
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
expect(db.prepare('SELECT * FROM project').all()).toEqual([
|
|
117
|
+
{ id: 'p1', ownerId: 'u1', name: 'first' },
|
|
118
|
+
])
|
|
119
|
+
expect(validatedAuthID).toBe('u1')
|
|
120
|
+
expect(effectAuthID).toBe('u1')
|
|
121
|
+
expect(statements).toEqual([
|
|
122
|
+
{ table: 'project', publicTable: 'project', kind: 'insert' },
|
|
123
|
+
])
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
test('returns a structural application error and drops rolled-back effects', async () => {
|
|
127
|
+
let effectRuns = 0
|
|
128
|
+
const adapter = createZeroSyncHostAdapter({
|
|
129
|
+
schema: zeroHttpFixtureSchema,
|
|
130
|
+
models: {
|
|
131
|
+
project: {
|
|
132
|
+
mutate: {
|
|
133
|
+
reject: async ({ server, tx }, value: Record<string, unknown>) => {
|
|
134
|
+
await tx.mutate.project.insert(value as never)
|
|
135
|
+
server?.enqueueTask(async () => {
|
|
136
|
+
effectRuns++
|
|
137
|
+
})
|
|
138
|
+
throw new Error('denied')
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
createServerActions: () => ({}),
|
|
144
|
+
transaction,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const error = await transaction((tx, context) =>
|
|
148
|
+
adapter.mutators['project|reject']!(
|
|
149
|
+
tx,
|
|
150
|
+
{ id: 'p1', ownerId: 'u1', name: 'must roll back' },
|
|
151
|
+
mutationContext(context),
|
|
152
|
+
),
|
|
153
|
+
).catch((caught) => caught)
|
|
154
|
+
|
|
155
|
+
expect(error).toMatchObject({
|
|
156
|
+
name: 'MutationApplicationError',
|
|
157
|
+
message: 'denied',
|
|
158
|
+
details: 'denied',
|
|
159
|
+
})
|
|
160
|
+
expect(db.prepare('SELECT * FROM project').all()).toEqual([])
|
|
161
|
+
expect(effectRuns).toBe(0)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
test('uses the host queryAst compiler surface for direct server queries', async () => {
|
|
165
|
+
db.prepare('INSERT INTO project (id, ownerId, name) VALUES (?, ?, ?)').run(
|
|
166
|
+
'p1',
|
|
167
|
+
'u1',
|
|
168
|
+
'first',
|
|
169
|
+
)
|
|
170
|
+
const adapter = createZeroSyncHostAdapter({
|
|
171
|
+
schema: zeroHttpFixtureSchema,
|
|
172
|
+
models: {},
|
|
173
|
+
createServerActions: () => ({}),
|
|
174
|
+
transaction,
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
await expect(adapter.server.query((q) => q.project.one())).resolves.toEqual({
|
|
178
|
+
id: 'p1',
|
|
179
|
+
ownerId: 'u1',
|
|
180
|
+
name: 'first',
|
|
181
|
+
})
|
|
182
|
+
expect(lastQueryFormat).toEqual({ relationships: {}, singular: true })
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
test('resolves auth-sensitive named queries and runs query validation', async () => {
|
|
186
|
+
let validation: unknown
|
|
187
|
+
const adapter = createZeroSyncHostAdapter({
|
|
188
|
+
schema: zeroHttpFixtureSchema,
|
|
189
|
+
models: {},
|
|
190
|
+
createServerActions: () => ({}),
|
|
191
|
+
queries,
|
|
192
|
+
transaction,
|
|
193
|
+
validateQuery(args) {
|
|
194
|
+
validation = args
|
|
195
|
+
},
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
const ast = await adapter.resolveQuery('project|byOwner', [{ ownerId: 'u1' }], {
|
|
199
|
+
userID: 'u1',
|
|
200
|
+
role: 'member',
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
expect(ast).toMatchObject({ table: 'project' })
|
|
204
|
+
expect(JSON.stringify(ast)).toContain('ownerId')
|
|
205
|
+
expect(JSON.stringify(ast)).toContain('u1')
|
|
206
|
+
expect(validation).toEqual({
|
|
207
|
+
authData: { id: 'u1', role: 'member', userID: 'u1' },
|
|
208
|
+
queryName: 'project|byOwner',
|
|
209
|
+
params: { ownerId: 'u1' },
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
function mutationContext(context: {
|
|
215
|
+
defer(effect: () => void | Promise<void>): void
|
|
216
|
+
}): SyncHostMutatorContext {
|
|
217
|
+
return {
|
|
218
|
+
...context,
|
|
219
|
+
claims: { userID: 'u1', role: 'member' },
|
|
220
|
+
clientID: 'client-a',
|
|
221
|
+
mutationID: '1',
|
|
222
|
+
}
|
|
223
|
+
}
|
package/src/syncHost.ts
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { asQueryInternals } from '@rocicorp/zero/bindings'
|
|
2
|
+
import { createBuilder, type Schema as ZeroSchema } from '@rocicorp/zero'
|
|
3
|
+
|
|
4
|
+
import { createPermissions } from './createPermissions'
|
|
5
|
+
import {
|
|
6
|
+
createZeroDirectServer,
|
|
7
|
+
resolveServerQuery,
|
|
8
|
+
type ZeroDirectServer,
|
|
9
|
+
type ZeroServerCommonOptions,
|
|
10
|
+
} from './createZeroDirectServer'
|
|
11
|
+
import {
|
|
12
|
+
createSQLiteDatabase,
|
|
13
|
+
createZeroSQLiteTransaction,
|
|
14
|
+
defaultLedgerTables,
|
|
15
|
+
encodeSQLiteValue,
|
|
16
|
+
type SqlStatementMetadata,
|
|
17
|
+
type SQLiteExecResult,
|
|
18
|
+
type SQLiteTransactionExecutor,
|
|
19
|
+
type SQLiteTransactionProvider,
|
|
20
|
+
type ZeroSQLiteTransactionOptions,
|
|
21
|
+
} from './sqliteRuntime'
|
|
22
|
+
import { createMutators } from './helpers/createMutators'
|
|
23
|
+
import { runWithAuthScope } from './helpers/mutatorContext'
|
|
24
|
+
import { runWithQueryContext } from './helpers/queryContext'
|
|
25
|
+
import { setEnvironment, setSchema } from './state'
|
|
26
|
+
|
|
27
|
+
import type { AsyncTaskEntry, AuthData, GenericModels } from './types'
|
|
28
|
+
|
|
29
|
+
export type SyncHostJsonValue =
|
|
30
|
+
| string
|
|
31
|
+
| number
|
|
32
|
+
| boolean
|
|
33
|
+
| null
|
|
34
|
+
| SyncHostJsonValue[]
|
|
35
|
+
| { [key: string]: SyncHostJsonValue }
|
|
36
|
+
|
|
37
|
+
export type SyncHostClaims = {
|
|
38
|
+
userID: string
|
|
39
|
+
[claim: string]: SyncHostJsonValue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type SyncHostTransactionContext = {
|
|
43
|
+
defer(effect: () => void | Promise<void>): void
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type SyncHostTransactionExecutor = {
|
|
47
|
+
exec(
|
|
48
|
+
sql: string,
|
|
49
|
+
params?: readonly unknown[],
|
|
50
|
+
metadata?: SqlStatementMetadata,
|
|
51
|
+
): SQLiteExecResult | Promise<SQLiteExecResult>
|
|
52
|
+
query<Row extends Record<string, unknown> = Record<string, unknown>>(
|
|
53
|
+
sql: string,
|
|
54
|
+
params?: readonly unknown[],
|
|
55
|
+
): Row[] | Promise<Row[]>
|
|
56
|
+
queryAst<Result = unknown>(
|
|
57
|
+
ast: SyncHostJsonValue,
|
|
58
|
+
format: import('./sqliteRuntime').SQLiteQueryFormat,
|
|
59
|
+
queryName?: string,
|
|
60
|
+
): Result | Promise<Result>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type SyncHostMutatorContext = SyncHostTransactionContext & {
|
|
64
|
+
claims: SyncHostClaims
|
|
65
|
+
clientID?: string
|
|
66
|
+
mutationID?: string | number
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type SyncHostRegisteredMutator = (
|
|
70
|
+
tx: SyncHostTransactionExecutor,
|
|
71
|
+
args: SyncHostJsonValue,
|
|
72
|
+
context: SyncHostMutatorContext,
|
|
73
|
+
) => void | Promise<void>
|
|
74
|
+
|
|
75
|
+
export type SyncHostApplicationTransaction = <Value>(
|
|
76
|
+
work: (
|
|
77
|
+
tx: SyncHostTransactionExecutor,
|
|
78
|
+
context: SyncHostTransactionContext,
|
|
79
|
+
) => Value | Promise<Value>,
|
|
80
|
+
) => Promise<Value>
|
|
81
|
+
|
|
82
|
+
export type CreateZeroSyncHostAdapterOptions<
|
|
83
|
+
Schema extends ZeroSchema,
|
|
84
|
+
Models extends GenericModels,
|
|
85
|
+
ServerActions extends Record<string, unknown>,
|
|
86
|
+
> = Omit<
|
|
87
|
+
ZeroServerCommonOptions<Schema, Models, ServerActions>,
|
|
88
|
+
'defaultMutateAuthData'
|
|
89
|
+
> &
|
|
90
|
+
ZeroSQLiteTransactionOptions<Schema> & {
|
|
91
|
+
transaction: SyncHostApplicationTransaction
|
|
92
|
+
mapAuthData?: (claims: SyncHostClaims) => AuthData
|
|
93
|
+
defaultMutateAuthData?: Pick<AuthData, 'email' | 'id'> & Partial<AuthData>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type ZeroSyncHostAdapter<
|
|
97
|
+
Schema extends ZeroSchema,
|
|
98
|
+
Models extends GenericModels,
|
|
99
|
+
> = {
|
|
100
|
+
mutators: Readonly<Record<string, SyncHostRegisteredMutator>>
|
|
101
|
+
resolveQuery(
|
|
102
|
+
name: string,
|
|
103
|
+
args: readonly SyncHostJsonValue[],
|
|
104
|
+
claims: SyncHostClaims,
|
|
105
|
+
): Promise<SyncHostJsonValue>
|
|
106
|
+
server: ZeroDirectServer<Schema, Models>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export class MutationApplicationError extends Error {
|
|
110
|
+
constructor(
|
|
111
|
+
readonly details: string,
|
|
112
|
+
message = details,
|
|
113
|
+
) {
|
|
114
|
+
super(message)
|
|
115
|
+
this.name = 'MutationApplicationError'
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function createZeroSyncHostAdapter<
|
|
120
|
+
Schema extends ZeroSchema,
|
|
121
|
+
Models extends GenericModels,
|
|
122
|
+
ServerActions extends Record<string, unknown>,
|
|
123
|
+
>({
|
|
124
|
+
encodeValue,
|
|
125
|
+
mapAuthData = defaultMapAuthData,
|
|
126
|
+
transaction,
|
|
127
|
+
...options
|
|
128
|
+
}: CreateZeroSyncHostAdapterOptions<Schema, Models, ServerActions>): ZeroSyncHostAdapter<
|
|
129
|
+
Schema,
|
|
130
|
+
Models
|
|
131
|
+
> {
|
|
132
|
+
setSchema(options.schema, createBuilder(options.schema))
|
|
133
|
+
setEnvironment('server')
|
|
134
|
+
|
|
135
|
+
const permissions = createPermissions({
|
|
136
|
+
environment: 'server',
|
|
137
|
+
schema: options.schema,
|
|
138
|
+
adminRoleMode: options.defaultAllowAdminRole ?? 'all',
|
|
139
|
+
})
|
|
140
|
+
const transactionOptions = {
|
|
141
|
+
encodeValue,
|
|
142
|
+
schema: options.schema,
|
|
143
|
+
}
|
|
144
|
+
const mutators: Record<string, SyncHostRegisteredMutator> = {}
|
|
145
|
+
|
|
146
|
+
for (const [modelName, model] of Object.entries(options.models)) {
|
|
147
|
+
for (const mutatorName of Object.keys(model.mutate ?? {})) {
|
|
148
|
+
mutators[`${modelName}|${mutatorName}`] = async (executor, args, context) => {
|
|
149
|
+
const authData = mapAuthData(context.claims)
|
|
150
|
+
const asyncTaskEntries: AsyncTaskEntry[] = []
|
|
151
|
+
const modelMutators = createMutators({
|
|
152
|
+
enqueueTask(task, opts) {
|
|
153
|
+
asyncTaskEntries.push({ task, barrier: opts?.barrier === true })
|
|
154
|
+
},
|
|
155
|
+
authData,
|
|
156
|
+
can: permissions.can,
|
|
157
|
+
createServerActions: options.createServerActions,
|
|
158
|
+
environment: 'server',
|
|
159
|
+
models: options.models,
|
|
160
|
+
mutationValidators: options.mutations,
|
|
161
|
+
validateMutation: options.validateMutation,
|
|
162
|
+
}) as Record<
|
|
163
|
+
string,
|
|
164
|
+
Record<string, (tx: unknown, args: unknown) => Promise<void>>
|
|
165
|
+
>
|
|
166
|
+
const mutation = modelMutators[modelName]?.[mutatorName]
|
|
167
|
+
if (!mutation)
|
|
168
|
+
throw new Error(`unknown on-zero mutator: ${modelName}|${mutatorName}`)
|
|
169
|
+
|
|
170
|
+
const mutationID = numericMutationID(context.mutationID)
|
|
171
|
+
const onZeroTransaction = createZeroSQLiteTransaction(
|
|
172
|
+
transactionOptions,
|
|
173
|
+
toSQLiteExecutor(executor),
|
|
174
|
+
{
|
|
175
|
+
clientGroupID: 'orez-sync-host',
|
|
176
|
+
clientID: context.clientID ?? '',
|
|
177
|
+
mutationID,
|
|
178
|
+
upstreamSchema: 'orez-sync-host',
|
|
179
|
+
},
|
|
180
|
+
)
|
|
181
|
+
try {
|
|
182
|
+
await mutation(onZeroTransaction, args)
|
|
183
|
+
} catch (error) {
|
|
184
|
+
throw asMutationApplicationError(error)
|
|
185
|
+
}
|
|
186
|
+
for (const { task } of asyncTaskEntries) {
|
|
187
|
+
context.defer(() => runWithAuthScope(authData, task))
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// orez owns result retention and lmids. zero clients may still emit this
|
|
194
|
+
// protocol mutation, so accepting it advances the host ledger without
|
|
195
|
+
// creating a second on-zero cleanup ledger.
|
|
196
|
+
mutators._zero_cleanupResults = async () => {}
|
|
197
|
+
|
|
198
|
+
const transactionProvider: SQLiteTransactionProvider = (work) =>
|
|
199
|
+
transaction((executor) => work(toSQLiteExecutor(executor)))
|
|
200
|
+
const directDatabaseOptions = {
|
|
201
|
+
encodeValue: encodeValue ?? encodeSQLiteValue,
|
|
202
|
+
initializedLedgers: new Set<string>(),
|
|
203
|
+
ledgerTables: defaultLedgerTables,
|
|
204
|
+
schema: options.schema,
|
|
205
|
+
transactionProvider,
|
|
206
|
+
}
|
|
207
|
+
const direct = createZeroDirectServer({
|
|
208
|
+
...options,
|
|
209
|
+
createDatabase: () => createSQLiteDatabase(directDatabaseOptions),
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
mutators: Object.freeze(mutators),
|
|
214
|
+
async resolveQuery(
|
|
215
|
+
name: string,
|
|
216
|
+
args: readonly SyncHostJsonValue[],
|
|
217
|
+
claims: SyncHostClaims,
|
|
218
|
+
): Promise<SyncHostJsonValue> {
|
|
219
|
+
if (!options.queries) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
'No queries registered with createZeroSyncHostAdapter. Pass the syncedQueries registry via the queries option.',
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
const authData = mapAuthData(claims)
|
|
225
|
+
const query = await runWithQueryContext({ authData }, () =>
|
|
226
|
+
resolveServerQuery({
|
|
227
|
+
authData,
|
|
228
|
+
args: args[0],
|
|
229
|
+
name,
|
|
230
|
+
permissions,
|
|
231
|
+
queries: options.queries!,
|
|
232
|
+
validateQuery: options.validateQuery,
|
|
233
|
+
}),
|
|
234
|
+
)
|
|
235
|
+
return asQueryInternals(query as never).ast as unknown as SyncHostJsonValue
|
|
236
|
+
},
|
|
237
|
+
server: {
|
|
238
|
+
mutate: direct.mutate,
|
|
239
|
+
query: direct.query,
|
|
240
|
+
transaction: direct.transaction,
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function defaultMapAuthData(claims: SyncHostClaims): AuthData {
|
|
246
|
+
return {
|
|
247
|
+
...claims,
|
|
248
|
+
id: typeof claims.id === 'string' ? claims.id : claims.userID,
|
|
249
|
+
} as AuthData
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function toSQLiteExecutor(
|
|
253
|
+
executor: SyncHostTransactionExecutor,
|
|
254
|
+
): SQLiteTransactionExecutor {
|
|
255
|
+
return {
|
|
256
|
+
exec(sql, params, metadata) {
|
|
257
|
+
return executor.exec(sql, params, metadata)
|
|
258
|
+
},
|
|
259
|
+
query<Row extends Record<string, unknown>>(sql: string, params?: readonly unknown[]) {
|
|
260
|
+
return executor.query<Row>(sql, params)
|
|
261
|
+
},
|
|
262
|
+
queryAst<Result>(ast, format, queryName) {
|
|
263
|
+
return executor.queryAst<Result>(
|
|
264
|
+
ast as unknown as SyncHostJsonValue,
|
|
265
|
+
format,
|
|
266
|
+
queryName,
|
|
267
|
+
)
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function numericMutationID(value: string | number | undefined): number {
|
|
273
|
+
if (value === undefined) return 0
|
|
274
|
+
const numeric = typeof value === 'number' ? value : Number(value)
|
|
275
|
+
if (!Number.isSafeInteger(numeric) || numeric < 0) {
|
|
276
|
+
throw new TypeError(`invalid Zero mutation ID: ${value}`)
|
|
277
|
+
}
|
|
278
|
+
return numeric
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function asMutationApplicationError(error: unknown): MutationApplicationError {
|
|
282
|
+
if (
|
|
283
|
+
typeof error === 'object' &&
|
|
284
|
+
error !== null &&
|
|
285
|
+
(error as { name?: unknown }).name === 'MutationApplicationError' &&
|
|
286
|
+
typeof (error as { details?: unknown }).details === 'string'
|
|
287
|
+
) {
|
|
288
|
+
return error as MutationApplicationError
|
|
289
|
+
}
|
|
290
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
291
|
+
const applicationError = new MutationApplicationError(message)
|
|
292
|
+
if (error instanceof Error && error.stack) applicationError.stack = error.stack
|
|
293
|
+
return applicationError
|
|
294
|
+
}
|
package/src/types.ts
CHANGED
package/src/zeroRunner.ts
CHANGED
|
@@ -37,7 +37,7 @@ export function getAmbientRunner(instance?: { runner: ZeroRunner | null }): Zero
|
|
|
37
37
|
|
|
38
38
|
if (!runner) {
|
|
39
39
|
throw new Error(
|
|
40
|
-
'Zero runner not initialized. Ensure ProvideZero is mounted or
|
|
40
|
+
'Zero runner not initialized. Ensure ProvideZero is mounted (client) or createZeroServer is called (server).',
|
|
41
41
|
)
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createZeroServer,
|
|
3
|
+
runAsyncTaskEntries,
|
|
4
|
+
type AsyncTaskEntry,
|
|
5
|
+
type BackgroundTaskScheduler,
|
|
6
|
+
type HandleMutationRequestOptions,
|
|
7
|
+
} from 'on-zero/server'
|
|
8
|
+
import { createZeroSQLiteServer, type SqlStatementMetadata } from 'on-zero/sqlite'
|
|
2
9
|
|
|
10
|
+
import {
|
|
11
|
+
runAsyncTaskEntries as runAsyncTaskEntriesFromRoot,
|
|
12
|
+
type Config,
|
|
13
|
+
type MutatorContext,
|
|
14
|
+
type RunAsyncTaskEntriesOptions,
|
|
15
|
+
} from 'on-zero'
|
|
3
16
|
import type { Schema as ZeroSchema } from '@rocicorp/zero'
|
|
4
|
-
import type { NormalizedClaims, SyncExecutor } from 'orez/sync-executor'
|
|
5
|
-
import type { Config, MutatorContext } from 'on-zero'
|
|
6
17
|
|
|
7
18
|
type AppAuthData = {
|
|
8
19
|
email: string
|
|
@@ -25,31 +36,57 @@ type Models = {
|
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
type Actions = Record<string, never>
|
|
39
|
+
type PostgresServer = ReturnType<typeof createZeroServer<ZeroSchema, Models, Actions>>
|
|
40
|
+
type SQLiteServer = ReturnType<typeof createZeroSQLiteServer<ZeroSchema, Models, Actions>>
|
|
28
41
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
createServerActions: () => ({}),
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
declare const executor: SyncExecutor<ZeroSchema>
|
|
36
|
-
const server = bindings.server(executor)
|
|
42
|
+
declare const postgresServer: PostgresServer
|
|
43
|
+
declare const sqliteServer: SQLiteServer
|
|
44
|
+
declare const taskEntries: AsyncTaskEntry[]
|
|
37
45
|
|
|
38
46
|
const authData: Config['authData'] = {
|
|
39
47
|
email: 'admin@example.com',
|
|
40
48
|
id: 'admin',
|
|
41
49
|
role: 'admin',
|
|
42
50
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
|
|
52
|
+
const sqliteWrite: SqlStatementMetadata = {
|
|
53
|
+
table: 'project_records',
|
|
54
|
+
publicTable: 'project',
|
|
55
|
+
kind: 'upsert',
|
|
56
|
+
}
|
|
57
|
+
void sqliteWrite
|
|
58
|
+
|
|
59
|
+
void runAsyncTaskEntries(taskEntries, {
|
|
60
|
+
background(promise) {
|
|
61
|
+
void promise
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const rootTaskOptions: RunAsyncTaskEntriesOptions = {
|
|
66
|
+
background(promise) {
|
|
67
|
+
void promise
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
void runAsyncTaskEntriesFromRoot(taskEntries, rootTaskOptions)
|
|
71
|
+
|
|
72
|
+
const scheduleBackgroundTask: BackgroundTaskScheduler = (promise) => {
|
|
73
|
+
void promise
|
|
74
|
+
}
|
|
75
|
+
const mutationRequest: HandleMutationRequestOptions = {
|
|
76
|
+
authData,
|
|
77
|
+
request: new Request('https://example.com/api/zero/push'),
|
|
78
|
+
scheduleBackgroundTask,
|
|
47
79
|
}
|
|
80
|
+
void postgresServer.handleMutationRequest(mutationRequest)
|
|
48
81
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
82
|
+
postgresServer.mutate.project.create(
|
|
83
|
+
{ id: 'pg' },
|
|
84
|
+
{ authData: { email: authData.email, id: authData.id, role: authData.role } },
|
|
85
|
+
)
|
|
86
|
+
sqliteServer.mutate.project.create(
|
|
87
|
+
{ id: 'sqlite' },
|
|
88
|
+
{ authData: { email: authData.email, id: authData.id, role: authData.role } },
|
|
89
|
+
)
|
|
53
90
|
|
|
54
|
-
// @ts-expect-error
|
|
55
|
-
|
|
91
|
+
// @ts-expect-error consumer auth augmentation must remain enforced
|
|
92
|
+
postgresServer.mutate.project.create({ id: 'invalid' }, { authData: { id: 'admin' } })
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type AsyncTaskEntry = {
|
|
2
|
+
task: () => Promise<void>;
|
|
3
|
+
barrier: boolean;
|
|
4
|
+
};
|
|
5
|
+
export type RunAsyncTaskEntriesOptions = {
|
|
6
|
+
/** Receives the background-task promise. Omit this to await all entries. */
|
|
7
|
+
background?: (promise: Promise<void>) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function runAsyncTaskEntries(entries: readonly AsyncTaskEntry[], { background }?: RunAsyncTaskEntriesOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=asyncTasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncTasks.d.ts","sourceRoot":"","sources":["../src/asyncTasks.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,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"}
|