on-zero 0.1.19 → 0.1.21

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 (47) hide show
  1. package/dist/cjs/createPermissions.cjs +4 -2
  2. package/dist/cjs/createPermissions.js +5 -2
  3. package/dist/cjs/createPermissions.js.map +1 -1
  4. package/dist/cjs/createPermissions.native.js +6 -2
  5. package/dist/cjs/createPermissions.native.js.map +1 -1
  6. package/dist/cjs/createZeroServer.cjs +15 -5
  7. package/dist/cjs/createZeroServer.js +11 -5
  8. package/dist/cjs/createZeroServer.js.map +1 -1
  9. package/dist/cjs/createZeroServer.native.js +15 -4
  10. package/dist/cjs/createZeroServer.native.js.map +1 -1
  11. package/dist/cjs/helpers/createMutators.cjs +16 -5
  12. package/dist/cjs/helpers/createMutators.js +20 -5
  13. package/dist/cjs/helpers/createMutators.js.map +1 -1
  14. package/dist/cjs/helpers/createMutators.native.js +19 -5
  15. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  16. package/dist/esm/createPermissions.js +5 -2
  17. package/dist/esm/createPermissions.js.map +1 -1
  18. package/dist/esm/createPermissions.mjs +4 -2
  19. package/dist/esm/createPermissions.mjs.map +1 -1
  20. package/dist/esm/createPermissions.native.js +6 -2
  21. package/dist/esm/createPermissions.native.js.map +1 -1
  22. package/dist/esm/createZeroServer.js +11 -5
  23. package/dist/esm/createZeroServer.js.map +1 -1
  24. package/dist/esm/createZeroServer.mjs +15 -5
  25. package/dist/esm/createZeroServer.mjs.map +1 -1
  26. package/dist/esm/createZeroServer.native.js +15 -4
  27. package/dist/esm/createZeroServer.native.js.map +1 -1
  28. package/dist/esm/helpers/createMutators.js +20 -5
  29. package/dist/esm/helpers/createMutators.js.map +1 -1
  30. package/dist/esm/helpers/createMutators.mjs +16 -5
  31. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  32. package/dist/esm/helpers/createMutators.native.js +19 -5
  33. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  34. package/package.json +2 -2
  35. package/readme.md +35 -0
  36. package/src/createPermissions.ts +12 -3
  37. package/src/createZeroServer.ts +45 -0
  38. package/src/helpers/createMutators.ts +50 -11
  39. package/src/types.ts +9 -0
  40. package/types/createPermissions.d.ts +3 -2
  41. package/types/createPermissions.d.ts.map +1 -1
  42. package/types/createZeroServer.d.ts +32 -2
  43. package/types/createZeroServer.d.ts.map +1 -1
  44. package/types/helpers/createMutators.d.ts +9 -1
  45. package/types/helpers/createMutators.d.ts.map +1 -1
  46. package/types/types.d.ts +8 -0
  47. package/types/types.d.ts.map +1 -1
package/readme.md CHANGED
@@ -475,6 +475,41 @@ app.post('/api/zero/pull', async (req) => {
475
475
  })
476
476
  ```
477
477
 
478
+ ### server validation hooks
479
+
480
+ add custom validation for all queries and mutations:
481
+
482
+ ```ts
483
+ export const zeroServer = createZeroServer({
484
+ schema,
485
+ models,
486
+ database: process.env.DATABASE_URL,
487
+ queries: syncedQueries,
488
+ createServerActions: () => ({ ... }),
489
+
490
+ // validate all queries before execution (must be sync, throw to reject)
491
+ validateQuery({ authData, queryName, params }) {
492
+ if (queryName === 'adminOnlyQuery' && authData?.role !== 'admin') {
493
+ throw new Error('admin only')
494
+ }
495
+ },
496
+
497
+ // validate all mutations before execution (can be async)
498
+ async validateMutation({ authData, tableName, mutatorName, args }) {
499
+ if (tableName === 'user' && mutatorName === 'delete') {
500
+ await auditLog('user.delete', authData, args)
501
+ }
502
+ },
503
+
504
+ // admin role bypass for permissions (default: 'all')
505
+ // - 'all': admin bypasses both query and mutation permissions
506
+ // - 'queries': admin bypasses only query permissions
507
+ // - 'mutations': admin bypasses only mutation permissions
508
+ // - 'off': no admin bypass, normal permission checks apply
509
+ defaultAllowAdminRole: 'all',
510
+ })
511
+ ```
512
+
478
513
  type augmentation:
479
514
 
480
515
  ```ts
@@ -6,7 +6,7 @@ import { prettyFormatZeroQuery } from './helpers/prettyFormatZeroQuery'
6
6
  import { getZQL } from './state'
7
7
  import { getWhereTableName } from './where'
8
8
 
9
- import type { AuthData, Can, TableName, Transaction, Where } from './types'
9
+ import type { AdminRoleMode, AuthData, Can, TableName, Transaction, Where } from './types'
10
10
  import type {
11
11
  Condition,
12
12
  ExpressionBuilder,
@@ -17,9 +17,11 @@ import type {
17
17
  export function createPermissions<Schema extends ZeroSchema>({
18
18
  environment,
19
19
  schema,
20
+ adminRoleMode = 'all',
20
21
  }: {
21
22
  environment: 'client' | 'server'
22
23
  schema: Schema
24
+ adminRoleMode?: AdminRoleMode
23
25
  }) {
24
26
  type PermissionReturn = Condition | boolean
25
27
 
@@ -36,6 +38,12 @@ export function createPermissions<Schema extends ZeroSchema>({
36
38
  objOrId: Record<string, any> | string,
37
39
  tableNameOverride?: TableName
38
40
  ) {
41
+ // check admin bypass for queries
42
+ const adminBypassQueries = adminRoleMode === 'all' || adminRoleMode === 'queries'
43
+ if (adminBypassQueries && authData?.role === 'admin') {
44
+ return eb.cmpLit(true, '=', true)
45
+ }
46
+
39
47
  const tableName = tableNameOverride || getWhereTableName(permissionWhere)
40
48
 
41
49
  if (!tableName) {
@@ -93,8 +101,9 @@ export function createPermissions<Schema extends ZeroSchema>({
93
101
  where: Where,
94
102
  obj: any // TODO until i can get a working PickPrimaryKeys<'message'>
95
103
  ): Promise<void> {
96
- if (authData?.role === 'admin') {
97
- // admin role can do any mutation
104
+ // check admin bypass for mutations
105
+ const adminBypassMutations = adminRoleMode === 'all' || adminRoleMode === 'mutations'
106
+ if (adminBypassMutations && authData?.role === 'admin') {
98
107
  return
99
108
  }
100
109
 
@@ -14,6 +14,7 @@ import { getZQL, setAuthData, setSchema } from './state'
14
14
  import { setRunner } from './zeroRunner'
15
15
 
16
16
  import type {
17
+ AdminRoleMode,
17
18
  AsyncAction,
18
19
  AuthData,
19
20
  GenericModels,
@@ -29,6 +30,22 @@ import type {
29
30
  } from '@rocicorp/zero'
30
31
  import type { TransactionProviderInput } from '@rocicorp/zero/pg'
31
32
 
33
+ export type ValidateQueryArgs = {
34
+ authData: AuthData | null
35
+ queryName: string
36
+ params: unknown
37
+ }
38
+
39
+ export type ValidateMutationArgs = {
40
+ authData: AuthData | null
41
+ mutatorName: string
42
+ tableName: string
43
+ args: unknown
44
+ }
45
+
46
+ export type ValidateQueryFn = (args: ValidateQueryArgs) => void
47
+ export type ValidateMutationFn = (args: ValidateMutationArgs) => void | Promise<void>
48
+
32
49
  export function createZeroServer<
33
50
  Schema extends ZeroSchema,
34
51
  Models extends GenericModels,
@@ -39,6 +56,9 @@ export function createZeroServer<
39
56
  schema,
40
57
  models,
41
58
  queries,
59
+ validateQuery,
60
+ validateMutation,
61
+ defaultAllowAdminRole = 'all',
42
62
  }: {
43
63
  /**
44
64
  * The DB connection string, same as ZERO_UPSTREAM_DB
@@ -48,6 +68,23 @@ export function createZeroServer<
48
68
  models: Models
49
69
  createServerActions: () => ServerActions
50
70
  queries?: AnyQueryRegistry
71
+ /**
72
+ * Hook to validate queries before execution. Throw to reject.
73
+ * Must be synchronous.
74
+ */
75
+ validateQuery?: ValidateQueryFn
76
+ /**
77
+ * Hook to validate mutations before execution. Throw to reject.
78
+ */
79
+ validateMutation?: ValidateMutationFn
80
+ /**
81
+ * Admin role bypass for permissions:
82
+ * - 'all': admin bypasses both query and mutation permissions (default)
83
+ * - 'queries': admin bypasses only query permissions
84
+ * - 'mutations': admin bypasses only mutation permissions
85
+ * - 'off': admin has no special bypass
86
+ */
87
+ defaultAllowAdminRole?: AdminRoleMode
51
88
  }) {
52
89
  setSchema(schema)
53
90
 
@@ -67,6 +104,7 @@ export function createZeroServer<
67
104
  const permissions = createPermissions<Schema>({
68
105
  environment: 'server',
69
106
  schema,
107
+ adminRoleMode: defaultAllowAdminRole,
70
108
  })
71
109
 
72
110
  const processor = new PushProcessor(zeroDb)
@@ -90,6 +128,7 @@ export function createZeroServer<
90
128
  environment: 'server',
91
129
  models,
92
130
  authData,
131
+ validateMutation,
93
132
  })
94
133
 
95
134
  // @ts-expect-error type is ok but config in monorepo
@@ -150,6 +189,11 @@ export function createZeroServer<
150
189
  .one()
151
190
  }
152
191
 
192
+ // run validation hook if provided (must be sync - throw to reject)
193
+ if (validateQuery) {
194
+ validateQuery({ authData, queryName: name, params: args })
195
+ }
196
+
153
197
  const query = (mustGetQuery as any)(queries, name)
154
198
  return query.fn({ args, ctx: authData })
155
199
  },
@@ -180,6 +224,7 @@ export function createZeroServer<
180
224
  },
181
225
  createServerActions,
182
226
  can: permissions.can,
227
+ validateMutation,
183
228
  })
184
229
 
185
230
  await transaction(async (tx) => {
@@ -13,6 +13,15 @@ import type {
13
13
  Transaction,
14
14
  } from '../types'
15
15
 
16
+ export type ValidateMutationFn = (args: {
17
+ authData: AuthData | null
18
+ mutatorName: string
19
+ tableName: string
20
+ args: unknown
21
+ }) => void | Promise<void>
22
+
23
+ export type { ValidateMutationFn as CreateMutatorsValidateFn }
24
+
16
25
  export function createMutators<Models extends GenericModels>({
17
26
  environment,
18
27
  authData,
@@ -20,6 +29,7 @@ export function createMutators<Models extends GenericModels>({
20
29
  asyncTasks = [],
21
30
  can,
22
31
  models,
32
+ validateMutation,
23
33
  }: {
24
34
  environment: 'server' | 'client'
25
35
  authData: AuthData | null
@@ -27,6 +37,7 @@ export function createMutators<Models extends GenericModels>({
27
37
  models: Models
28
38
  asyncTasks?: Array<() => Promise<void>>
29
39
  createServerActions?: () => Record<string, any>
40
+ validateMutation?: ValidateMutationFn
30
41
  }): GetZeroMutators<Models> {
31
42
  const serverActions = createServerActions?.()
32
43
 
@@ -68,27 +79,31 @@ export function createMutators<Models extends GenericModels>({
68
79
  return fn
69
80
  }
70
81
 
82
+ const debug = process.env.DEBUG
83
+
71
84
  return async (...args: Args): Promise<void> => {
72
85
  const startTime = performance.now()
73
86
 
74
87
  try {
75
- if (isServer) {
88
+ if (debug && isServer) {
76
89
  console.info(`[mutator] ${name} start`)
77
90
  }
78
91
  const result = await fn(...args)
79
92
  const duration = (performance.now() - startTime).toFixed(2)
80
- if (isBrowser) {
81
- console.groupCollapsed(`[mutator] ${name} completed in ${duration}ms`)
82
- console.info('→', args[1])
83
- console.info('', result)
84
- console.trace()
85
- console.groupEnd()
86
- } else {
87
- // TODO in prod just track
88
- console.info(`[mutator] ${name} completed in ${duration}ms`)
93
+ if (debug) {
94
+ if (isBrowser) {
95
+ console.groupCollapsed(`[mutator] ${name} completed in ${duration}ms`)
96
+ console.info('', args[1])
97
+ console.info('←', result)
98
+ console.trace()
99
+ console.groupEnd()
100
+ } else {
101
+ console.info(`[mutator] ${name} completed in ${duration}ms`)
102
+ }
89
103
  }
90
104
  return result
91
105
  } catch (error) {
106
+ // always log errors
92
107
  const duration = (performance.now() - startTime).toFixed(2)
93
108
  console.groupCollapsed(`[mutator] ${name} failed after ${duration}ms`)
94
109
  console.error('error:', error)
@@ -118,6 +133,27 @@ export function createMutators<Models extends GenericModels>({
118
133
  }
119
134
  }
120
135
 
136
+ function withValidation<Args extends any[]>(
137
+ tableName: string,
138
+ mutatorName: string,
139
+ fn: (...args: Args) => Promise<void>
140
+ ) {
141
+ if (!validateMutation) {
142
+ return fn
143
+ }
144
+
145
+ return async (...args: Args): Promise<void> => {
146
+ // args[0] is tx, args[1] is the mutation args
147
+ await validateMutation({
148
+ authData: isBrowser ? getAuthData() : authData,
149
+ tableName,
150
+ mutatorName,
151
+ args: args[1],
152
+ })
153
+ return fn(...args)
154
+ }
155
+ }
156
+
121
157
  function decorateMutators<T extends Record<string, Record<string, any>>>(modules: T) {
122
158
  const result: any = {}
123
159
 
@@ -128,7 +164,10 @@ export function createMutators<Models extends GenericModels>({
128
164
  const fullName = `${moduleName}.${name}`
129
165
  result[moduleName][name] = withDevelopmentLogging(
130
166
  fullName,
131
- withTimeoutGuard(fullName, withContext(exportValue))
167
+ withTimeoutGuard(
168
+ fullName,
169
+ withValidation(moduleName, name, withContext(exportValue))
170
+ )
132
171
  )
133
172
  }
134
173
  }
package/src/types.ts CHANGED
@@ -134,3 +134,12 @@ export type TablePrimaryKeys<TS extends GenericTable> = TupleToUnion<
134
134
  >
135
135
 
136
136
  export type ZeroEvent = { type: 'error'; message: string }
137
+
138
+ /**
139
+ * Admin role bypass for permissions:
140
+ * - 'all': admin bypasses both query and mutation permissions (default)
141
+ * - 'queries': admin bypasses only query permissions
142
+ * - 'mutations': admin bypasses only mutation permissions
143
+ * - 'off': admin has no special bypass
144
+ */
145
+ export type AdminRoleMode = 'all' | 'queries' | 'mutations' | 'off'
@@ -1,8 +1,9 @@
1
- import type { AuthData, Can, TableName, Where } from './types';
1
+ import type { AdminRoleMode, AuthData, Can, TableName, Where } from './types';
2
2
  import type { Condition, ExpressionBuilder, Schema as ZeroSchema } from '@rocicorp/zero';
3
- export declare function createPermissions<Schema extends ZeroSchema>({ environment, schema, }: {
3
+ export declare function createPermissions<Schema extends ZeroSchema>({ environment, schema, adminRoleMode, }: {
4
4
  environment: 'client' | 'server';
5
5
  schema: Schema;
6
+ adminRoleMode?: AdminRoleMode;
6
7
  }): {
7
8
  can: Can;
8
9
  buildPermissionQuery: <PermissionWhere extends Where<string, boolean | Condition>>(authData: AuthData | null, eb: ExpressionBuilder<any, any>, permissionWhere: PermissionWhere, objOrId: Record<string, any> | string, tableNameOverride?: TableName) => Condition;
@@ -1 +1 @@
1
- {"version":3,"file":"createPermissions.d.ts","sourceRoot":"","sources":["../src/createPermissions.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAe,KAAK,EAAE,MAAM,SAAS,CAAA;AAC3E,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EAEjB,MAAM,IAAI,UAAU,EACrB,MAAM,gBAAgB,CAAA;AAEvB,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,UAAU,EAAE,EAC3D,WAAW,EACX,MAAM,GACP,EAAE;IACD,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;CACf;;2BAQ+B,eAAe,uDACjC,QAAQ,GAAG,IAAI,MACrB,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,mBACd,eAAe,WAEvB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,sBACjB,SAAS;EA+FhC"}
1
+ {"version":3,"file":"createPermissions.d.ts","sourceRoot":"","sources":["../src/createPermissions.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAe,KAAK,EAAE,MAAM,SAAS,CAAA;AAC1F,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EAEjB,MAAM,IAAI,UAAU,EACrB,MAAM,gBAAgB,CAAA;AAEvB,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,UAAU,EAAE,EAC3D,WAAW,EACX,MAAM,EACN,aAAqB,GACtB,EAAE;IACD,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,aAAa,CAAA;CAC9B;;2BAQ+B,eAAe,uDACjC,QAAQ,GAAG,IAAI,MACrB,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,mBACd,eAAe,WAEvB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,sBACjB,SAAS;EAsGhC"}
@@ -1,6 +1,19 @@
1
- import type { AsyncAction, AuthData, GenericModels, GetZeroMutators, QueryBuilder, Transaction } from './types';
1
+ import type { AdminRoleMode, AsyncAction, AuthData, GenericModels, GetZeroMutators, QueryBuilder, Transaction } from './types';
2
2
  import type { AnyQueryRegistry, HumanReadable, Query, Schema as ZeroSchema } from '@rocicorp/zero';
3
- export declare function createZeroServer<Schema extends ZeroSchema, Models extends GenericModels, ServerActions extends Record<string, unknown>>({ createServerActions, database, schema, models, queries, }: {
3
+ export type ValidateQueryArgs = {
4
+ authData: AuthData | null;
5
+ queryName: string;
6
+ params: unknown;
7
+ };
8
+ export type ValidateMutationArgs = {
9
+ authData: AuthData | null;
10
+ mutatorName: string;
11
+ tableName: string;
12
+ args: unknown;
13
+ };
14
+ export type ValidateQueryFn = (args: ValidateQueryArgs) => void;
15
+ export type ValidateMutationFn = (args: ValidateMutationArgs) => void | Promise<void>;
16
+ export declare function createZeroServer<Schema extends ZeroSchema, Models extends GenericModels, ServerActions extends Record<string, unknown>>({ createServerActions, database, schema, models, queries, validateQuery, validateMutation, defaultAllowAdminRole, }: {
4
17
  /**
5
18
  * The DB connection string, same as ZERO_UPSTREAM_DB
6
19
  */
@@ -9,6 +22,23 @@ export declare function createZeroServer<Schema extends ZeroSchema, Models exten
9
22
  models: Models;
10
23
  createServerActions: () => ServerActions;
11
24
  queries?: AnyQueryRegistry;
25
+ /**
26
+ * Hook to validate queries before execution. Throw to reject.
27
+ * Must be synchronous.
28
+ */
29
+ validateQuery?: ValidateQueryFn;
30
+ /**
31
+ * Hook to validate mutations before execution. Throw to reject.
32
+ */
33
+ validateMutation?: ValidateMutationFn;
34
+ /**
35
+ * Admin role bypass for permissions:
36
+ * - 'all': admin bypasses both query and mutation permissions (default)
37
+ * - 'queries': admin bypasses only query permissions
38
+ * - 'mutations': admin bypasses only mutation permissions
39
+ * - 'off': admin has no special bypass
40
+ */
41
+ defaultAllowAdminRole?: AdminRoleMode;
12
42
  }): {
13
43
  handleMutationRequest: ({ authData, request, skipAsyncTasks, }: {
14
44
  authData: AuthData | null;
@@ -1 +1 @@
1
- {"version":3,"file":"createZeroServer.d.ts","sourceRoot":"","sources":["../src/createZeroServer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,aAAa,EACb,eAAe,EACf,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,KAAK,EACL,MAAM,IAAI,UAAU,EACrB,MAAM,gBAAgB,CAAA;AAGvB,wBAAgB,gBAAgB,CAC9B,MAAM,SAAS,UAAU,EACzB,MAAM,SAAS,aAAa,EAC5B,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,EACA,mBAAmB,EACnB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,GACR,EAAE;IACD;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB,EAAE,MAAM,aAAa,CAAA;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAC3B;oEA2BI;QACD,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;QACzB,OAAO,EAAE,OAAO,CAAA;QAChB,cAAc,CAAC,EAAE,OAAO,CAAA;KACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAsCE;QACD,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;QACzB,OAAO,EAAE,OAAO,CAAA;KACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsEC,EAAE,SAAS,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,EAC5C,OAAO,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,SACrE,EAAE,KAAG,OAAO,CAAC,OAAO,CAAC;kBA7BvB,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,aAC/D,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;YA2ChD,CAAC,MACV,CAAC,CAAC,EAAE,YAAY,KAAK,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAC7C,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;EAiC7B"}
1
+ {"version":3,"file":"createZeroServer.d.ts","sourceRoot":"","sources":["../src/createZeroServer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,QAAQ,EACR,aAAa,EACb,eAAe,EACf,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,KAAK,EACL,MAAM,IAAI,UAAU,EACrB,MAAM,gBAAgB,CAAA;AAGvB,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAA;AAC/D,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAErF,wBAAgB,gBAAgB,CAC9B,MAAM,SAAS,UAAU,EACzB,MAAM,SAAS,aAAa,EAC5B,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,EACA,mBAAmB,EACnB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,qBAA6B,GAC9B,EAAE;IACD;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB,EAAE,MAAM,aAAa,CAAA;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,eAAe,CAAA;IAC/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,kBAAkB,CAAA;IACrC;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,aAAa,CAAA;CACtC;oEA4BI;QACD,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;QACzB,OAAO,EAAE,OAAO,CAAA;QAChB,cAAc,CAAC,EAAE,OAAO,CAAA;KACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAuCE;QACD,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;QACzB,OAAO,EAAE,OAAO,CAAA;KACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4EC,EAAE,SAAS,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,EAC5C,OAAO,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,SACrE,EAAE,KAAG,OAAO,CAAC,OAAO,CAAC;kBA9BvB,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,aAC/D,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;YA4ChD,CAAC,MACV,CAAC,CAAC,EAAE,YAAY,KAAK,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAC7C,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;EAiC7B"}
@@ -1,10 +1,18 @@
1
1
  import type { AuthData, Can, GenericModels, GetZeroMutators } from '../types';
2
- export declare function createMutators<Models extends GenericModels>({ environment, authData, createServerActions, asyncTasks, can, models, }: {
2
+ export type ValidateMutationFn = (args: {
3
+ authData: AuthData | null;
4
+ mutatorName: string;
5
+ tableName: string;
6
+ args: unknown;
7
+ }) => void | Promise<void>;
8
+ export type { ValidateMutationFn as CreateMutatorsValidateFn };
9
+ export declare function createMutators<Models extends GenericModels>({ environment, authData, createServerActions, asyncTasks, can, models, validateMutation, }: {
3
10
  environment: 'server' | 'client';
4
11
  authData: AuthData | null;
5
12
  can: Can;
6
13
  models: Models;
7
14
  asyncTasks?: Array<() => Promise<void>>;
8
15
  createServerActions?: () => Record<string, any>;
16
+ validateMutation?: ValidateMutationFn;
9
17
  }): GetZeroMutators<Models>;
10
18
  //# sourceMappingURL=createMutators.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createMutators.d.ts","sourceRoot":"","sources":["../../src/helpers/createMutators.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,QAAQ,EACR,GAAG,EACH,aAAa,EACb,eAAe,EAGhB,MAAM,UAAU,CAAA;AAEjB,wBAAgB,cAAc,CAAC,MAAM,SAAS,aAAa,EAAE,EAC3D,WAAW,EACX,QAAQ,EACR,mBAAmB,EACnB,UAAe,EACf,GAAG,EACH,MAAM,GACP,EAAE;IACD,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACvC,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAChD,GAAG,eAAe,CAAC,MAAM,CAAC,CA+G1B"}
1
+ {"version":3,"file":"createMutators.d.ts","sourceRoot":"","sources":["../../src/helpers/createMutators.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,QAAQ,EACR,GAAG,EACH,aAAa,EACb,eAAe,EAGhB,MAAM,UAAU,CAAA;AAEjB,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;CACd,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1B,YAAY,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,CAAA;AAE9D,wBAAgB,cAAc,CAAC,MAAM,SAAS,aAAa,EAAE,EAC3D,WAAW,EACX,QAAQ,EACR,mBAAmB,EACnB,UAAe,EACf,GAAG,EACH,MAAM,EACN,gBAAgB,GACjB,EAAE;IACD,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACvC,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/C,gBAAgB,CAAC,EAAE,kBAAkB,CAAA;CACtC,GAAG,eAAe,CAAC,MAAM,CAAC,CA2I1B"}
package/types/types.d.ts CHANGED
@@ -74,5 +74,13 @@ export type ZeroEvent = {
74
74
  type: 'error';
75
75
  message: string;
76
76
  };
77
+ /**
78
+ * Admin role bypass for permissions:
79
+ * - 'all': admin bypasses both query and mutation permissions (default)
80
+ * - 'queries': admin bypasses only query permissions
81
+ * - 'mutations': admin bypasses only mutation permissions
82
+ * - 'off': admin has no special bypass
83
+ */
84
+ export type AdminRoleMode = 'all' | 'queries' | 'mutations' | 'off';
77
85
  export {};
78
86
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}