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.
Files changed (260) 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/createZeroDirectServer.cjs +269 -0
  5. package/dist/cjs/createZeroDirectServer.native.js +287 -0
  6. package/dist/cjs/createZeroDirectServer.native.js.map +1 -0
  7. package/dist/cjs/createZeroSQLiteServer.cjs +50 -0
  8. package/dist/cjs/createZeroSQLiteServer.native.js +58 -0
  9. package/dist/cjs/createZeroSQLiteServer.native.js.map +1 -0
  10. package/dist/cjs/createZeroSQLiteServer.test.cjs +595 -0
  11. package/dist/cjs/createZeroSQLiteServer.test.native.js +647 -0
  12. package/dist/cjs/createZeroSQLiteServer.test.native.js.map +1 -0
  13. package/dist/cjs/createZeroServer.cjs +82 -0
  14. package/dist/cjs/createZeroServer.native.js +93 -0
  15. package/dist/cjs/createZeroServer.native.js.map +1 -0
  16. package/dist/cjs/createZeroServer.test.cjs +378 -0
  17. package/dist/cjs/createZeroServer.test.native.js +448 -0
  18. package/dist/cjs/createZeroServer.test.native.js.map +1 -0
  19. package/dist/cjs/createZeroServerCore.cjs +211 -0
  20. package/dist/cjs/createZeroServerCore.native.js +355 -0
  21. package/dist/cjs/createZeroServerCore.native.js.map +1 -0
  22. package/dist/cjs/helpers/createMutators.cjs +3 -4
  23. package/dist/cjs/helpers/createMutators.native.js +3 -6
  24. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  25. package/dist/cjs/httpPull/auth.test.cjs +197 -0
  26. package/dist/cjs/httpPull/auth.test.native.js +279 -0
  27. package/dist/cjs/httpPull/auth.test.native.js.map +1 -0
  28. package/dist/cjs/httpPull/churn.test.cjs +132 -0
  29. package/dist/cjs/httpPull/churn.test.native.js +155 -0
  30. package/dist/cjs/httpPull/churn.test.native.js.map +1 -0
  31. package/dist/cjs/httpPull/completeAck.test.cjs +69 -0
  32. package/dist/cjs/httpPull/completeAck.test.native.js +76 -0
  33. package/dist/cjs/httpPull/completeAck.test.native.js.map +1 -0
  34. package/dist/cjs/httpPull/fixtureServer.cjs +340 -0
  35. package/dist/cjs/httpPull/fixtureServer.native.js +534 -0
  36. package/dist/cjs/httpPull/fixtureServer.native.js.map +1 -0
  37. package/dist/cjs/httpPull/integration.test.cjs +53 -0
  38. package/dist/cjs/httpPull/integration.test.native.js +60 -0
  39. package/dist/cjs/httpPull/integration.test.native.js.map +1 -0
  40. package/dist/cjs/httpPull/rebase.test.cjs +360 -0
  41. package/dist/cjs/httpPull/rebase.test.native.js +420 -0
  42. package/dist/cjs/httpPull/rebase.test.native.js.map +1 -0
  43. package/dist/cjs/httpPull/relations.test.cjs +107 -0
  44. package/dist/cjs/httpPull/relations.test.native.js +119 -0
  45. package/dist/cjs/httpPull/relations.test.native.js.map +1 -0
  46. package/dist/cjs/httpPull/testHarness.cjs +100 -0
  47. package/dist/cjs/httpPull/testHarness.native.js +112 -0
  48. package/dist/cjs/httpPull/testHarness.native.js.map +1 -0
  49. package/dist/cjs/index.cjs +1 -0
  50. package/dist/cjs/index.native.js +1 -0
  51. package/dist/cjs/index.native.js.map +1 -1
  52. package/dist/cjs/run.cjs +1 -1
  53. package/dist/cjs/run.native.js +1 -1
  54. package/dist/cjs/server.cjs +22 -0
  55. package/dist/cjs/server.native.js +4 -0
  56. package/dist/cjs/server.native.js.map +1 -0
  57. package/dist/cjs/sqliteRuntime.cjs +318 -0
  58. package/dist/cjs/sqliteRuntime.native.js +438 -0
  59. package/dist/cjs/sqliteRuntime.native.js.map +1 -0
  60. package/dist/cjs/state.cjs +1 -1
  61. package/dist/cjs/state.native.js +1 -1
  62. package/dist/cjs/syncHost.cjs +179 -0
  63. package/dist/cjs/syncHost.native.js +388 -0
  64. package/dist/cjs/syncHost.native.js.map +1 -0
  65. package/dist/cjs/syncHost.test.cjs +240 -0
  66. package/dist/cjs/syncHost.test.native.js +290 -0
  67. package/dist/cjs/syncHost.test.native.js.map +1 -0
  68. package/dist/cjs/zeroRunner.cjs +1 -1
  69. package/dist/cjs/zeroRunner.native.js +1 -1
  70. package/dist/esm/asyncTasks.mjs +26 -0
  71. package/dist/esm/asyncTasks.mjs.map +1 -0
  72. package/dist/esm/asyncTasks.native.js +56 -0
  73. package/dist/esm/asyncTasks.native.js.map +1 -0
  74. package/dist/esm/createZeroDirectServer.mjs +241 -0
  75. package/dist/esm/createZeroDirectServer.mjs.map +1 -0
  76. package/dist/esm/createZeroDirectServer.native.js +256 -0
  77. package/dist/esm/createZeroDirectServer.native.js.map +1 -0
  78. package/dist/esm/createZeroSQLiteServer.mjs +24 -0
  79. package/dist/esm/createZeroSQLiteServer.mjs.map +1 -0
  80. package/dist/esm/createZeroSQLiteServer.native.js +29 -0
  81. package/dist/esm/createZeroSQLiteServer.native.js.map +1 -0
  82. package/dist/esm/createZeroSQLiteServer.test.mjs +596 -0
  83. package/dist/esm/createZeroSQLiteServer.test.mjs.map +1 -0
  84. package/dist/esm/createZeroSQLiteServer.test.native.js +645 -0
  85. package/dist/esm/createZeroSQLiteServer.test.native.js.map +1 -0
  86. package/dist/esm/createZeroServer.mjs +57 -0
  87. package/dist/esm/createZeroServer.mjs.map +1 -0
  88. package/dist/esm/createZeroServer.native.js +65 -0
  89. package/dist/esm/createZeroServer.native.js.map +1 -0
  90. package/dist/esm/createZeroServer.test.mjs +379 -0
  91. package/dist/esm/createZeroServer.test.mjs.map +1 -0
  92. package/dist/esm/createZeroServer.test.native.js +446 -0
  93. package/dist/esm/createZeroServer.test.native.js.map +1 -0
  94. package/dist/esm/createZeroServerCore.mjs +186 -0
  95. package/dist/esm/createZeroServerCore.mjs.map +1 -0
  96. package/dist/esm/createZeroServerCore.native.js +327 -0
  97. package/dist/esm/createZeroServerCore.native.js.map +1 -0
  98. package/dist/esm/helpers/createMutators.mjs +3 -4
  99. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  100. package/dist/esm/helpers/createMutators.native.js +3 -6
  101. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  102. package/dist/esm/httpPull/auth.test.mjs +198 -0
  103. package/dist/esm/httpPull/auth.test.mjs.map +1 -0
  104. package/dist/esm/httpPull/auth.test.native.js +277 -0
  105. package/dist/esm/httpPull/auth.test.native.js.map +1 -0
  106. package/dist/esm/httpPull/churn.test.mjs +133 -0
  107. package/dist/esm/httpPull/churn.test.mjs.map +1 -0
  108. package/dist/esm/httpPull/churn.test.native.js +153 -0
  109. package/dist/esm/httpPull/churn.test.native.js.map +1 -0
  110. package/dist/esm/httpPull/completeAck.test.mjs +70 -0
  111. package/dist/esm/httpPull/completeAck.test.mjs.map +1 -0
  112. package/dist/esm/httpPull/completeAck.test.native.js +74 -0
  113. package/dist/esm/httpPull/completeAck.test.native.js.map +1 -0
  114. package/dist/esm/httpPull/fixtureServer.mjs +315 -0
  115. package/dist/esm/httpPull/fixtureServer.mjs.map +1 -0
  116. package/dist/esm/httpPull/fixtureServer.native.js +506 -0
  117. package/dist/esm/httpPull/fixtureServer.native.js.map +1 -0
  118. package/dist/esm/httpPull/integration.test.mjs +54 -0
  119. package/dist/esm/httpPull/integration.test.mjs.map +1 -0
  120. package/dist/esm/httpPull/integration.test.native.js +58 -0
  121. package/dist/esm/httpPull/integration.test.native.js.map +1 -0
  122. package/dist/esm/httpPull/rebase.test.mjs +361 -0
  123. package/dist/esm/httpPull/rebase.test.mjs.map +1 -0
  124. package/dist/esm/httpPull/rebase.test.native.js +418 -0
  125. package/dist/esm/httpPull/rebase.test.native.js.map +1 -0
  126. package/dist/esm/httpPull/relations.test.mjs +108 -0
  127. package/dist/esm/httpPull/relations.test.mjs.map +1 -0
  128. package/dist/esm/httpPull/relations.test.native.js +117 -0
  129. package/dist/esm/httpPull/relations.test.native.js.map +1 -0
  130. package/dist/esm/httpPull/testHarness.mjs +72 -0
  131. package/dist/esm/httpPull/testHarness.mjs.map +1 -0
  132. package/dist/esm/httpPull/testHarness.native.js +81 -0
  133. package/dist/esm/httpPull/testHarness.native.js.map +1 -0
  134. package/dist/esm/index.js +1 -0
  135. package/dist/esm/index.js.map +1 -1
  136. package/dist/esm/index.mjs +1 -0
  137. package/dist/esm/index.mjs.map +1 -1
  138. package/dist/esm/index.native.js +1 -0
  139. package/dist/esm/index.native.js.map +1 -1
  140. package/dist/esm/run.mjs +1 -1
  141. package/dist/esm/run.mjs.map +1 -1
  142. package/dist/esm/run.native.js +1 -1
  143. package/dist/esm/server.mjs +4 -0
  144. package/dist/esm/server.mjs.map +1 -0
  145. package/dist/esm/server.native.js +2 -0
  146. package/dist/esm/server.native.js.map +1 -0
  147. package/dist/esm/sqliteRuntime.mjs +289 -0
  148. package/dist/esm/sqliteRuntime.mjs.map +1 -0
  149. package/dist/esm/sqliteRuntime.native.js +406 -0
  150. package/dist/esm/sqliteRuntime.native.js.map +1 -0
  151. package/dist/esm/state.mjs +1 -1
  152. package/dist/esm/state.native.js +1 -1
  153. package/dist/esm/syncHost.mjs +153 -0
  154. package/dist/esm/syncHost.mjs.map +1 -0
  155. package/dist/esm/syncHost.native.js +359 -0
  156. package/dist/esm/syncHost.native.js.map +1 -0
  157. package/dist/esm/syncHost.test.mjs +217 -0
  158. package/dist/esm/syncHost.test.mjs.map +1 -0
  159. package/dist/esm/syncHost.test.native.js +264 -0
  160. package/dist/esm/syncHost.test.native.js.map +1 -0
  161. package/dist/esm/zeroRunner.mjs +1 -1
  162. package/dist/esm/zeroRunner.mjs.map +1 -1
  163. package/dist/esm/zeroRunner.native.js +1 -1
  164. package/package.json +23 -8
  165. package/readme.md +65 -40
  166. package/src/asyncTasks.ts +36 -0
  167. package/src/createZeroClient.tsx +1 -1
  168. package/src/createZeroDirectServer.ts +411 -0
  169. package/src/createZeroSQLiteServer.test.ts +614 -0
  170. package/src/createZeroSQLiteServer.ts +56 -0
  171. package/src/createZeroServer.test.ts +421 -0
  172. package/src/createZeroServer.ts +105 -0
  173. package/src/createZeroServerCore.ts +296 -0
  174. package/src/helpers/createMutators.ts +2 -6
  175. package/src/httpPull/auth.test.ts +208 -0
  176. package/src/httpPull/churn.test.ts +147 -0
  177. package/src/httpPull/completeAck.test.ts +80 -0
  178. package/src/httpPull/fixtureServer.ts +391 -0
  179. package/src/httpPull/integration.test.ts +57 -0
  180. package/src/httpPull/rebase.test.ts +368 -0
  181. package/src/httpPull/relations.test.ts +135 -0
  182. package/src/httpPull/testHarness.ts +95 -0
  183. package/src/index.ts +1 -0
  184. package/src/run.ts +1 -1
  185. package/src/server.native.ts +3 -0
  186. package/src/server.ts +4 -0
  187. package/src/sqliteRuntime.ts +512 -0
  188. package/src/state.ts +1 -1
  189. package/src/syncHost.test.ts +223 -0
  190. package/src/syncHost.ts +294 -0
  191. package/src/types.ts +5 -0
  192. package/src/zeroRunner.ts +1 -1
  193. package/test-fixtures/server-return-types.ts +58 -21
  194. package/types/asyncTasks.d.ts +11 -0
  195. package/types/asyncTasks.d.ts.map +1 -0
  196. package/types/createZeroDirectServer.d.ts +80 -0
  197. package/types/createZeroDirectServer.d.ts.map +1 -0
  198. package/types/createZeroSQLiteServer.d.ts +12 -0
  199. package/types/createZeroSQLiteServer.d.ts.map +1 -0
  200. package/types/createZeroSQLiteServer.test.d.ts +2 -0
  201. package/types/createZeroSQLiteServer.test.d.ts.map +1 -0
  202. package/types/createZeroServer.d.ts +18 -0
  203. package/types/createZeroServer.d.ts.map +1 -0
  204. package/types/createZeroServer.test.d.ts +2 -0
  205. package/types/createZeroServer.test.d.ts.map +1 -0
  206. package/types/createZeroServerCore.d.ts +256 -0
  207. package/types/createZeroServerCore.d.ts.map +1 -0
  208. package/types/helpers/createMutators.d.ts +1 -2
  209. package/types/helpers/createMutators.d.ts.map +1 -1
  210. package/types/httpPull/auth.test.d.ts +2 -0
  211. package/types/httpPull/auth.test.d.ts.map +1 -0
  212. package/types/httpPull/churn.test.d.ts +2 -0
  213. package/types/httpPull/churn.test.d.ts.map +1 -0
  214. package/types/httpPull/completeAck.test.d.ts +2 -0
  215. package/types/httpPull/completeAck.test.d.ts.map +1 -0
  216. package/types/httpPull/fixtureSchema.d.ts +1 -1
  217. package/types/httpPull/fixtureServer.d.ts +14 -0
  218. package/types/httpPull/fixtureServer.d.ts.map +1 -0
  219. package/types/httpPull/integration.test.d.ts +2 -0
  220. package/types/httpPull/integration.test.d.ts.map +1 -0
  221. package/types/httpPull/rebase.test.d.ts +2 -0
  222. package/types/httpPull/rebase.test.d.ts.map +1 -0
  223. package/types/httpPull/relations.test.d.ts +2 -0
  224. package/types/httpPull/relations.test.d.ts.map +1 -0
  225. package/types/httpPull/testHarness.d.ts +32 -0
  226. package/types/httpPull/testHarness.d.ts.map +1 -0
  227. package/types/index.d.ts +1 -0
  228. package/types/index.d.ts.map +1 -1
  229. package/types/server.d.ts +5 -0
  230. package/types/server.d.ts.map +1 -0
  231. package/types/server.native.d.ts +1 -0
  232. package/types/server.native.d.ts.map +1 -0
  233. package/types/sqliteRuntime.d.ts +71 -0
  234. package/types/sqliteRuntime.d.ts.map +1 -0
  235. package/types/syncHost.d.ts +42 -0
  236. package/types/syncHost.d.ts.map +1 -0
  237. package/types/syncHost.test.d.ts +2 -0
  238. package/types/syncHost.test.d.ts.map +1 -0
  239. package/types/types.d.ts +4 -0
  240. package/types/types.d.ts.map +1 -1
  241. package/dist/cjs/orez.cjs +0 -227
  242. package/dist/cjs/orez.native.js +0 -314
  243. package/dist/cjs/orez.native.js.map +0 -1
  244. package/dist/cjs/orez.test.cjs +0 -211
  245. package/dist/cjs/orez.test.native.js +0 -226
  246. package/dist/cjs/orez.test.native.js.map +0 -1
  247. package/dist/esm/orez.mjs +0 -202
  248. package/dist/esm/orez.mjs.map +0 -1
  249. package/dist/esm/orez.native.js +0 -286
  250. package/dist/esm/orez.native.js.map +0 -1
  251. package/dist/esm/orez.test.mjs +0 -188
  252. package/dist/esm/orez.test.mjs.map +0 -1
  253. package/dist/esm/orez.test.native.js +0 -200
  254. package/dist/esm/orez.test.native.js.map +0 -1
  255. package/src/orez.test.ts +0 -195
  256. package/src/orez.ts +0 -331
  257. package/types/orez.d.ts +0 -53
  258. package/types/orez.d.ts.map +0 -1
  259. package/types/orez.test.d.ts +0 -2
  260. package/types/orez.test.d.ts.map +0 -1
@@ -0,0 +1,411 @@
1
+ import { createBuilder, mustGetQuery } from '@rocicorp/zero'
2
+
3
+ import { runAsyncTaskEntries } from './asyncTasks'
4
+ import { createPermissions } from './createPermissions'
5
+ import { createMutators } from './helpers/createMutators'
6
+ import {
7
+ getScopedAuthData,
8
+ isInZeroMutation,
9
+ mutatorContext,
10
+ runWithAuthScope,
11
+ } from './helpers/mutatorContext'
12
+ import { runWithQueryContext } from './helpers/queryContext'
13
+ import { getMutationsPermissions } from './modelRegistry'
14
+ import { setCustomQueries } from './run'
15
+ import { getZQL, setEnvironment, setSchema } from './state'
16
+ import { setEvaluatingPermission } from './where'
17
+ import { setRunner } from './zeroRunner'
18
+
19
+ import type {
20
+ AdminRoleMode,
21
+ AsyncTask,
22
+ AsyncTaskEntry,
23
+ AsyncTaskOptions,
24
+ AuthData,
25
+ GenericModels,
26
+ MutatorContext,
27
+ QueryBuilder,
28
+ Transaction,
29
+ } from './types'
30
+ import type {
31
+ AnyQueryRegistry,
32
+ HumanReadable,
33
+ Query,
34
+ Schema as ZeroSchema,
35
+ } from '@rocicorp/zero'
36
+ import type { Database, TransactionProviderInput } from '@rocicorp/zero/server'
37
+
38
+ type MutateAuthData = Pick<AuthData, 'email' | 'id'> & Partial<AuthData>
39
+
40
+ export type MutateOptions = {
41
+ authData?: MutateAuthData
42
+ awaitEffects?: boolean
43
+ }
44
+
45
+ export type ServerMutate<Models extends GenericModels> = {
46
+ [Key in keyof Models]: {
47
+ [K in keyof Models[Key]['mutate']]: Models[Key]['mutate'][K] extends (
48
+ ctx: MutatorContext,
49
+ arg: infer Arg,
50
+ ) => any
51
+ ? (arg: Arg, options?: MutateOptions) => Promise<void>
52
+ : (options?: MutateOptions) => Promise<void>
53
+ }
54
+ }
55
+
56
+ export type ValidateQueryArgs = {
57
+ authData: AuthData | null
58
+ queryName: string
59
+ params: unknown
60
+ }
61
+
62
+ export type ValidateMutationArgs = {
63
+ authData: AuthData | null
64
+ mutatorName: string
65
+ tableName: string
66
+ args: unknown
67
+ }
68
+
69
+ export type ValidateQueryFn = (args: ValidateQueryArgs) => void
70
+ export type ValidateMutationFn = (args: ValidateMutationArgs) => void | Promise<void>
71
+
72
+ export type ServerQueryResolverOptions = {
73
+ authData: AuthData | null
74
+ name: string
75
+ args: unknown
76
+ queries: AnyQueryRegistry
77
+ permissions: ReturnType<typeof createPermissions>
78
+ validateQuery?: ValidateQueryFn
79
+ }
80
+
81
+ export function resolveServerQuery({
82
+ authData,
83
+ name,
84
+ args,
85
+ queries,
86
+ permissions,
87
+ validateQuery,
88
+ }: ServerQueryResolverOptions) {
89
+ if (name.startsWith('permission.')) {
90
+ const table = name.slice('permission.'.length)
91
+ const { objOrId } = args as {
92
+ objOrId: string | Record<string, any>
93
+ }
94
+ const permission = getMutationsPermissions(table)
95
+ if (!permission) {
96
+ throw new Error(`[permission] no permission defined for table: ${table}`)
97
+ }
98
+ setEvaluatingPermission(true)
99
+ try {
100
+ return (getZQL() as any)[table]
101
+ .where((eb: any) => {
102
+ return permissions.buildPermissionQuery(
103
+ authData,
104
+ eb,
105
+ permission,
106
+ objOrId,
107
+ table,
108
+ )
109
+ })
110
+ .one()
111
+ } finally {
112
+ setEvaluatingPermission(false)
113
+ }
114
+ }
115
+
116
+ if (validateQuery) {
117
+ validateQuery({ authData, queryName: name, params: args })
118
+ }
119
+
120
+ const query = (mustGetQuery as any)(queries, name)
121
+ return query.fn({ args, ctx: authData })
122
+ }
123
+
124
+ export type TransactionAttemptLifecycle = {
125
+ beginAttempt(): void
126
+ completeAttempt(): void
127
+ rollbackAttempt(): void
128
+ commitTransaction(): void
129
+ rollbackTransaction(): void
130
+ }
131
+
132
+ export type ZeroServerDatabase = Database<Transaction>
133
+
134
+ export type ZeroServerCommonOptions<
135
+ Schema extends ZeroSchema,
136
+ Models extends GenericModels,
137
+ ServerActions extends Record<string, unknown>,
138
+ > = {
139
+ schema: Schema
140
+ models: Models
141
+ createServerActions: () => ServerActions
142
+ queries?: AnyQueryRegistry
143
+ /** generated validators keyed by model and mutation name */
144
+ mutations?: Record<string, Record<string, any>>
145
+ /** synchronous query authorization hook; throw to reject */
146
+ validateQuery?: ValidateQueryFn
147
+ /** mutation authorization hook; throw to reject */
148
+ validateMutation?: ValidateMutationFn
149
+ /** controls which operations the admin role bypasses */
150
+ defaultAllowAdminRole?: AdminRoleMode
151
+ /** auth data used by direct server mutations when no scope provides it */
152
+ defaultMutateAuthData?: MutateAuthData
153
+ }
154
+
155
+ export type ZeroDirectServerOptions<
156
+ Schema extends ZeroSchema,
157
+ Models extends GenericModels,
158
+ ServerActions extends Record<string, unknown>,
159
+ > = ZeroServerCommonOptions<Schema, Models, ServerActions> & {
160
+ createDatabase: () => ZeroServerDatabase
161
+ }
162
+
163
+ export type ZeroDirectServer<Schema extends ZeroSchema, Models extends GenericModels> = {
164
+ transaction: <
165
+ CB extends (tx: Transaction) => Promise<any>,
166
+ Returns extends CB extends (tx: Transaction) => Promise<infer X> ? X : never,
167
+ >(
168
+ query: CB,
169
+ ) => Promise<Returns>
170
+ mutate: ServerMutate<Models>
171
+ query: <R>(
172
+ cb: (q: QueryBuilder) => Query<any, Schema, R>,
173
+ authData?: AuthData | null,
174
+ ) => Promise<HumanReadable<R>>
175
+ }
176
+
177
+ export function createAsyncTaskCollector() {
178
+ const committed: AsyncTaskEntry[] = []
179
+ let attempt: AsyncTaskEntry[] | undefined
180
+ let completedAttempt: AsyncTaskEntry[] | undefined
181
+
182
+ const enqueueTask = (task: AsyncTask, opts?: AsyncTaskOptions) => {
183
+ const entries = attempt ?? committed
184
+ entries.push({ task, barrier: opts?.barrier === true })
185
+ }
186
+
187
+ const lifecycle: TransactionAttemptLifecycle = {
188
+ beginAttempt() {
189
+ attempt = []
190
+ completedAttempt = undefined
191
+ },
192
+ completeAttempt() {
193
+ completedAttempt = attempt
194
+ attempt = undefined
195
+ },
196
+ rollbackAttempt() {
197
+ attempt = undefined
198
+ completedAttempt = undefined
199
+ },
200
+ commitTransaction() {
201
+ if (completedAttempt) committed.push(...completedAttempt)
202
+ completedAttempt = undefined
203
+ },
204
+ rollbackTransaction() {
205
+ attempt = undefined
206
+ completedAttempt = undefined
207
+ },
208
+ }
209
+
210
+ return { committed, enqueueTask, lifecycle }
211
+ }
212
+
213
+ export function createZeroDirectServerRuntime<
214
+ Schema extends ZeroSchema,
215
+ Models extends GenericModels,
216
+ ServerActions extends Record<string, unknown>,
217
+ >({
218
+ createDatabase,
219
+ createServerActions,
220
+ defaultAllowAdminRole = 'all',
221
+ defaultMutateAuthData = {} as MutateAuthData,
222
+ models,
223
+ mutations: mutationValidators,
224
+ queries,
225
+ schema,
226
+ validateMutation,
227
+ validateQuery,
228
+ }: ZeroDirectServerOptions<Schema, Models, ServerActions>): {
229
+ permissions: ReturnType<typeof createPermissions<Schema>>
230
+ server: ZeroDirectServer<Schema, Models>
231
+ } {
232
+ setSchema(schema, createBuilder(schema))
233
+ setEnvironment('server')
234
+
235
+ const permissions = createPermissions<Schema>({
236
+ environment: 'server',
237
+ schema,
238
+ adminRoleMode: defaultAllowAdminRole,
239
+ })
240
+
241
+ async function runTransaction<
242
+ CB extends (tx: Transaction) => Promise<any>,
243
+ Returns extends CB extends (tx: Transaction) => Promise<infer X> ? X : never,
244
+ >(database: ZeroServerDatabase, query: CB): Promise<Returns> {
245
+ try {
246
+ if (isInZeroMutation()) {
247
+ const { tx } = mutatorContext()
248
+ return await query(tx)
249
+ }
250
+ return (await database.transaction(query, dummyTransactionInput)) as Returns
251
+ } catch (err) {
252
+ if ((err as any)?.name !== 'PermissionError') {
253
+ console.error(`Error running transaction(): ${err}`)
254
+ }
255
+ throw err
256
+ }
257
+ }
258
+
259
+ async function transaction<
260
+ CB extends (tx: Transaction) => Promise<any>,
261
+ Returns extends CB extends (tx: Transaction) => Promise<infer X> ? X : never,
262
+ >(query: CB): Promise<Returns> {
263
+ return runTransaction(createDatabase(), query)
264
+ }
265
+
266
+ async function runMutate(
267
+ modelName: string,
268
+ mutatorName: string,
269
+ mutatorArg: unknown,
270
+ options?: MutateOptions,
271
+ ) {
272
+ let authData = options?.authData
273
+ if (!authData) {
274
+ const scoped = getScopedAuthData()
275
+ if (scoped) authData = scoped as MutateAuthData
276
+ }
277
+
278
+ const tasks = createAsyncTaskCollector()
279
+ const mutators = createMutators({
280
+ models,
281
+ environment: 'server',
282
+ enqueueTask: tasks.enqueueTask,
283
+ authData: {
284
+ ...defaultMutateAuthData,
285
+ ...authData,
286
+ },
287
+ createServerActions,
288
+ can: permissions.can,
289
+ validateMutation,
290
+ mutationValidators,
291
+ })
292
+ const modelMutators = mutators[modelName as keyof typeof mutators] as Record<
293
+ string,
294
+ (tx: Transaction, arg?: unknown) => Promise<void>
295
+ >
296
+ const mutator = modelMutators[mutatorName]
297
+
298
+ await runTransaction(
299
+ createDatabaseWithLifecycle(createDatabase(), tasks.lifecycle),
300
+ async (tx) => {
301
+ await mutator(tx, mutatorArg)
302
+ },
303
+ )
304
+
305
+ if (tasks.committed.length) {
306
+ const resolvedAuth = authData ?? null
307
+ const entries = tasks.committed.map((entry) => ({
308
+ ...entry,
309
+ task: () => runWithAuthScope(resolvedAuth, entry.task),
310
+ }))
311
+ if (options?.awaitEffects) {
312
+ await Promise.all(entries.map(({ task }) => task()))
313
+ } else {
314
+ await runAsyncTaskEntries(entries, { background: () => undefined })
315
+ }
316
+ }
317
+ }
318
+
319
+ const mutate = new Proxy({} as ServerMutate<Models>, {
320
+ get(_, modelName: string) {
321
+ return new Proxy(
322
+ {},
323
+ {
324
+ get(_, mutatorName: string) {
325
+ return (arg: unknown, options?: MutateOptions) =>
326
+ runMutate(modelName, mutatorName, arg, options)
327
+ },
328
+ },
329
+ )
330
+ },
331
+ })
332
+
333
+ function query<R>(
334
+ cb: (q: QueryBuilder) => Query<any, Schema, R>,
335
+ authData?: AuthData | null,
336
+ ): Promise<HumanReadable<R>> {
337
+ const run = () =>
338
+ transaction(async (tx) => {
339
+ return tx.run(cb(getZQL()))
340
+ }) as any
341
+
342
+ if (authData !== undefined) {
343
+ return runWithQueryContext({ authData }, run)
344
+ }
345
+ return run()
346
+ }
347
+
348
+ if (queries) {
349
+ setCustomQueries(queries)
350
+ }
351
+
352
+ setRunner((queryObj) => {
353
+ return transaction(async (tx) => {
354
+ return tx.run(queryObj)
355
+ })
356
+ })
357
+
358
+ return {
359
+ permissions,
360
+ server: {
361
+ transaction,
362
+ mutate,
363
+ query,
364
+ },
365
+ }
366
+ }
367
+
368
+ export function createZeroDirectServer<
369
+ Schema extends ZeroSchema,
370
+ Models extends GenericModels,
371
+ ServerActions extends Record<string, unknown>,
372
+ >(
373
+ options: ZeroDirectServerOptions<Schema, Models, ServerActions>,
374
+ ): ZeroDirectServer<Schema, Models> {
375
+ return createZeroDirectServerRuntime(options).server
376
+ }
377
+
378
+ function createDatabaseWithLifecycle(
379
+ database: ZeroServerDatabase,
380
+ lifecycle: TransactionAttemptLifecycle,
381
+ ): ZeroServerDatabase {
382
+ return {
383
+ async transaction(callback, input) {
384
+ try {
385
+ const value = await database.transaction(async (tx, hooks) => {
386
+ lifecycle.beginAttempt()
387
+ try {
388
+ const result = await callback(tx, hooks)
389
+ lifecycle.completeAttempt()
390
+ return result
391
+ } catch (error) {
392
+ lifecycle.rollbackAttempt()
393
+ throw error
394
+ }
395
+ }, input)
396
+ lifecycle.commitTransaction()
397
+ return value
398
+ } catch (error) {
399
+ lifecycle.rollbackTransaction()
400
+ throw error
401
+ }
402
+ },
403
+ }
404
+ }
405
+
406
+ const dummyTransactionInput: TransactionProviderInput = {
407
+ clientGroupID: 'unused',
408
+ clientID: 'unused',
409
+ mutationID: 42,
410
+ upstreamSchema: 'unused',
411
+ }