on-zero 0.1.45 → 0.1.47

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 (54) hide show
  1. package/dist/cjs/constants.cjs +2 -1
  2. package/dist/cjs/constants.js +2 -1
  3. package/dist/cjs/constants.js.map +1 -1
  4. package/dist/cjs/constants.native.js +1 -1
  5. package/dist/cjs/generate.cjs +26 -11
  6. package/dist/cjs/generate.js +32 -10
  7. package/dist/cjs/generate.js.map +1 -1
  8. package/dist/cjs/generate.native.js +36 -19
  9. package/dist/cjs/generate.native.js.map +1 -1
  10. package/dist/cjs/generate.test.cjs +24 -1
  11. package/dist/cjs/generate.test.js +27 -1
  12. package/dist/cjs/generate.test.js.map +1 -1
  13. package/dist/cjs/generate.test.native.js +24 -1
  14. package/dist/cjs/generate.test.native.js.map +1 -1
  15. package/dist/cjs/mutations.cjs +3 -2
  16. package/dist/cjs/mutations.js +2 -2
  17. package/dist/cjs/mutations.js.map +1 -1
  18. package/dist/cjs/mutations.native.js +3 -2
  19. package/dist/cjs/mutations.native.js.map +1 -1
  20. package/dist/esm/constants.js +2 -1
  21. package/dist/esm/constants.js.map +1 -1
  22. package/dist/esm/constants.mjs +2 -1
  23. package/dist/esm/constants.mjs.map +1 -1
  24. package/dist/esm/constants.native.js +1 -1
  25. package/dist/esm/generate.js +32 -10
  26. package/dist/esm/generate.js.map +1 -1
  27. package/dist/esm/generate.mjs +26 -11
  28. package/dist/esm/generate.mjs.map +1 -1
  29. package/dist/esm/generate.native.js +36 -19
  30. package/dist/esm/generate.native.js.map +1 -1
  31. package/dist/esm/generate.test.js +27 -1
  32. package/dist/esm/generate.test.js.map +1 -1
  33. package/dist/esm/generate.test.mjs +24 -1
  34. package/dist/esm/generate.test.mjs.map +1 -1
  35. package/dist/esm/generate.test.native.js +24 -1
  36. package/dist/esm/generate.test.native.js.map +1 -1
  37. package/dist/esm/mutations.js +2 -1
  38. package/dist/esm/mutations.js.map +1 -1
  39. package/dist/esm/mutations.mjs +2 -1
  40. package/dist/esm/mutations.mjs.map +1 -1
  41. package/dist/esm/mutations.native.js +2 -1
  42. package/dist/esm/mutations.native.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/constants.native.ts +1 -1
  45. package/src/constants.ts +8 -1
  46. package/src/generate.test.ts +37 -1
  47. package/src/generate.ts +39 -10
  48. package/src/mutations.ts +2 -1
  49. package/types/constants.d.ts.map +1 -1
  50. package/types/constants.native.d.ts +1 -1
  51. package/types/constants.native.d.ts.map +1 -1
  52. package/types/generate.d.ts.map +1 -1
  53. package/types/mutations.d.ts.map +1 -1
  54. package/types/state.d.ts +1 -1
@@ -270,7 +270,7 @@ export const mutate = mutations(schema, perm)
270
270
  expect(content).toContain('delete:')
271
271
  })
272
272
 
273
- test('skips models without export const mutate', async () => {
273
+ test('treats models without export const mutate as empty mutations', async () => {
274
274
  writeFileSync(
275
275
  join(testDir, 'models/readonly.ts'),
276
276
  `
@@ -285,6 +285,9 @@ export const schema = table('readonly').columns({
285
285
 
286
286
  const result = await generate({ dir: testDir, silent: true })
287
287
  expect(result.mutationCount).toBe(0)
288
+
289
+ const content = readFileSync(join(testDir, 'generated/syncedMutations.ts'), 'utf-8')
290
+ expect(content).toContain('readonly: {')
288
291
  })
289
292
 
290
293
  test('extracts custom mutations from bare mutations({})', async () => {
@@ -505,6 +508,39 @@ export const mutate = mutations(schema, perm, {
505
508
  expect(content).not.toMatch(/rename:[\s\S]*count/)
506
509
  })
507
510
 
511
+ test('skips symbol-keyed properties when resolving imported mutation param types', async () => {
512
+ writeFileSync(
513
+ join(testDir, 'models/types.ts'),
514
+ `
515
+ export type WeirdParams = {
516
+ id: string
517
+ [Symbol.iterator]?: () => Iterator<string>
518
+ }
519
+ `
520
+ )
521
+
522
+ writeFileSync(
523
+ join(testDir, 'models/item.ts'),
524
+ `
525
+ import { mutations } from 'on-zero'
526
+ import type { WeirdParams } from './types'
527
+
528
+ export const mutate = mutations({
529
+ run: async ({ tx }, params: WeirdParams) => {
530
+ await tx.mutate.item.delete({ id: params.id })
531
+ },
532
+ })
533
+ `
534
+ )
535
+
536
+ await generate({ dir: testDir, silent: true })
537
+
538
+ const content = readFileSync(join(testDir, 'generated/syncedMutations.ts'), 'utf-8')
539
+ expect(content).toContain('run')
540
+ expect(content).toContain('id: v.string()')
541
+ expect(content).not.toContain('__@iterator')
542
+ })
543
+
508
544
  test('resolves imported types in query params', async () => {
509
545
  writeFileSync(
510
546
  join(testDir, 'models/post.ts'),
package/src/generate.ts CHANGED
@@ -430,7 +430,7 @@ function extractMutationsFromModel(
430
430
  ts: typeof import('typescript'),
431
431
  sourceFile: ReturnType<typeof ts.createSourceFile>,
432
432
  content: string,
433
- _fileName: string,
433
+ fileName: string,
434
434
  silent: boolean,
435
435
  typeToValibot: (typeString: string) => string | null,
436
436
  resolvedTypes?: Map<string, import('typescript').Type>,
@@ -450,7 +450,15 @@ function extractMutationsFromModel(
450
450
  }
451
451
  })
452
452
 
453
- if (!mutateNode) return null
453
+ if (!mutateNode) {
454
+ return {
455
+ modelName: basename(fileName, '.ts'),
456
+ hasCRUD: false,
457
+ columns: {},
458
+ primaryKeys: [],
459
+ custom: [],
460
+ }
461
+ }
454
462
 
455
463
  const call = mutateNode as import('typescript').CallExpression
456
464
  const args = call.arguments
@@ -621,6 +629,16 @@ function columnTypeToValibot(col: SchemaColumn): string {
621
629
  return col.optional ? `v.optional(v.nullable(${base}))` : base
622
630
  }
623
631
 
632
+ function shouldSkipObjectKey(name: string): boolean {
633
+ // TypeScript exposes symbol keys as synthetic names like "__@iterator@851".
634
+ // These cannot come from JSON mutation payloads and break codegen if emitted.
635
+ return name.startsWith('__@')
636
+ }
637
+
638
+ function formatObjectKey(name: string): string {
639
+ return /^[$A-Z_a-z][$\w]*$/.test(name) ? name : JSON.stringify(name)
640
+ }
641
+
624
642
  function schemaColumnsToValibot(
625
643
  columns: Record<string, SchemaColumn>,
626
644
  primaryKeys: string[],
@@ -632,22 +650,29 @@ function schemaColumnsToValibot(
632
650
  // only PKs
633
651
  for (const pk of primaryKeys) {
634
652
  const col = columns[pk]
635
- if (col) entries.push(`${pk}: ${columnTypeToValibot({ ...col, optional: false })}`)
653
+ if (col)
654
+ entries.push(
655
+ `${formatObjectKey(pk)}: ${columnTypeToValibot({ ...col, optional: false })}`
656
+ )
636
657
  }
637
658
  } else if (mode === 'update') {
638
659
  // PKs required, rest optional
639
660
  for (const [name, col] of Object.entries(columns)) {
640
661
  const isPK = primaryKeys.includes(name)
641
662
  if (isPK) {
642
- entries.push(`${name}: ${columnTypeToValibot({ ...col, optional: false })}`)
663
+ entries.push(
664
+ `${formatObjectKey(name)}: ${columnTypeToValibot({ ...col, optional: false })}`
665
+ )
643
666
  } else {
644
- entries.push(`${name}: ${columnTypeToValibot({ ...col, optional: true })}`)
667
+ entries.push(
668
+ `${formatObjectKey(name)}: ${columnTypeToValibot({ ...col, optional: true })}`
669
+ )
645
670
  }
646
671
  }
647
672
  } else {
648
673
  // insert: all columns as-is
649
674
  for (const [name, col] of Object.entries(columns)) {
650
- entries.push(`${name}: ${columnTypeToValibot(col)}`)
675
+ entries.push(`${formatObjectKey(name)}: ${columnTypeToValibot(col)}`)
651
676
  }
652
677
  }
653
678
 
@@ -750,7 +775,7 @@ function parseTypeString(type: string): string | null {
750
775
  if (!parsed) return null // can't resolve inner type
751
776
  let val = parsed
752
777
  if (opt) val = `v.optional(${val})`
753
- entries.push(`${name}: ${val}`)
778
+ entries.push(`${formatObjectKey(name)}: ${val}`)
754
779
  }
755
780
  if (entries.length === 0) return 'v.object({})'
756
781
  return `v.object({\n ${entries.join(',\n ')},\n })`
@@ -853,14 +878,17 @@ function tsTypeToValibot(
853
878
  if (props.length === 0) return 'v.object({})'
854
879
  const entries: string[] = []
855
880
  for (const prop of props) {
881
+ const name = prop.getName()
882
+ if (shouldSkipObjectKey(name)) continue
856
883
  const propType = resolveSymbolType(prop)
857
884
  const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional)
858
885
  let val = recurse(propType)
859
886
  if (isOptional && !val.startsWith('v.optional(')) {
860
887
  val = `v.optional(${val})`
861
888
  }
862
- entries.push(`${prop.getName()}: ${val}`)
889
+ entries.push(`${formatObjectKey(name)}: ${val}`)
863
890
  }
891
+ if (entries.length === 0) return 'v.object({})'
864
892
  return `v.object({\n ${entries.join(',\n ')},\n })`
865
893
  }
866
894
 
@@ -895,13 +923,15 @@ function tsTypeToValibot(
895
923
  // regular object
896
924
  const entries: string[] = []
897
925
  for (const prop of props) {
926
+ const name = prop.getName()
927
+ if (shouldSkipObjectKey(name)) continue
898
928
  const propType = resolveSymbolType(prop)
899
929
  const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional)
900
930
  let val = recurse(propType)
901
931
  if (isOptional && !val.startsWith('v.optional(')) {
902
932
  val = `v.optional(${val})`
903
933
  }
904
- entries.push(`${prop.getName()}: ${val}`)
934
+ entries.push(`${formatObjectKey(name)}: ${val}`)
905
935
  }
906
936
  if (entries.length === 0) return 'v.object({})'
907
937
  return `v.object({\n ${entries.join(',\n ')},\n })`
@@ -1124,7 +1154,6 @@ export async function generate(options: GenerateOptions): Promise<GenerateResult
1124
1154
 
1125
1155
  try {
1126
1156
  const content = readFileSync(filePath, 'utf-8')
1127
- if (!content.includes('export const mutate')) continue
1128
1157
 
1129
1158
  mutationFiles.push({ path: filePath, content, baseName: fileBaseName })
1130
1159
 
package/src/mutations.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { isServer } from './constants'
1
2
  import { getDidRunPermissionCheck } from './helpers/didRunPermissionCheck'
2
3
  import { setMutationsPermissions } from './modelRegistry'
3
4
 
@@ -143,7 +144,7 @@ export function mutations<
143
144
  }
144
145
 
145
146
  // only validate on the server
146
- if (process.env.VITE_ENVIRONMENT === 'ssr') {
147
+ if (isServer) {
147
148
  await ctx.can(permissions, obj)
148
149
  }
149
150
  }
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,SAAgC,CAAA;AACrD,eAAO,MAAM,SAAS,SAAY,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,QAAQ,SAE6C,CAAA;AAElE,eAAO,MAAM,SAAS,SAAY,CAAA"}
@@ -1,3 +1,3 @@
1
1
  export declare const isServer = false;
2
- export declare const isBrowser = false;
2
+ export declare const isBrowser = true;
3
3
  //# sourceMappingURL=constants.native.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.native.d.ts","sourceRoot":"","sources":["../src/constants.native.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,QAAQ,CAAA;AAC7B,eAAO,MAAM,SAAS,QAAQ,CAAA"}
1
+ {"version":3,"file":"constants.native.d.ts","sourceRoot":"","sources":["../src/constants.native.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,QAAQ,CAAA;AAC7B,eAAO,MAAM,SAAS,OAAO,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AA05BA,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAoUhF;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,yCAkChD"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAw7BA,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAmUhF;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,yCAkChD"}
@@ -1 +1 @@
1
- {"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../src/mutations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEd,cAAc,EACd,KAAK,EACN,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AA2D7D,KAAK,eAAe,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AACnF,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;AAevD,KAAK,YAAY,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAA;AAEhD,KAAK,aAAa,CAAC,KAAK,SAAS,YAAY,IAAI;IAC/C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;CAC/C,CAAA;AAED,KAAK,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE1D,KAAK,iBAAiB,CAAC,KAAK,SAAS,YAAY,EAAE,SAAS,SAAS,gBAAgB,IAAI;KACtF,GAAG,IAAI,SAAS,GAAG,MAAM,SAAS,GAAG,GAAG,SAAS,MAAM,SAAS,GAC7D,SAAS,CAAC,GAAG,CAAC,GACd,GAAG,SAAS,MAAM,aAAa,CAAC,GAAG,CAAC,GAClC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GACzB,KAAK;CACZ,CAAA;AAED,wBAAgB,SAAS,CAAC,SAAS,SAAS,gBAAgB,EAC1D,SAAS,EAAE,SAAS,GACnB,SAAS,CAAA;AACZ,wBAAgB,SAAS,CAAC,KAAK,SAAS,YAAY,EAAE,WAAW,SAAS,KAAK,EAC7E,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,GACvB,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAC/B,wBAAgB,SAAS,CACvB,KAAK,SAAS,YAAY,EAC1B,WAAW,SAAS,KAAK,EACzB,SAAS,SAAS,gBAAgB,EAElC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,GACnB,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA"}
1
+ {"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../src/mutations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEd,cAAc,EACd,KAAK,EACN,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AA2D7D,KAAK,eAAe,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AACnF,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;AAevD,KAAK,YAAY,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAA;AAEhD,KAAK,aAAa,CAAC,KAAK,SAAS,YAAY,IAAI;IAC/C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9C,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;CAC/C,CAAA;AAED,KAAK,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE1D,KAAK,iBAAiB,CAAC,KAAK,SAAS,YAAY,EAAE,SAAS,SAAS,gBAAgB,IAAI;KACtF,GAAG,IAAI,SAAS,GAAG,MAAM,SAAS,GAAG,GAAG,SAAS,MAAM,SAAS,GAC7D,SAAS,CAAC,GAAG,CAAC,GACd,GAAG,SAAS,MAAM,aAAa,CAAC,GAAG,CAAC,GAClC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GACzB,KAAK;CACZ,CAAA;AAED,wBAAgB,SAAS,CAAC,SAAS,SAAS,gBAAgB,EAC1D,SAAS,EAAE,SAAS,GACnB,SAAS,CAAA;AACZ,wBAAgB,SAAS,CAAC,KAAK,SAAS,YAAY,EAAE,WAAW,SAAS,KAAK,EAC7E,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,GACvB,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAC/B,wBAAgB,SAAS,CACvB,KAAK,SAAS,YAAY,EAC1B,WAAW,SAAS,KAAK,EACzB,SAAS,SAAS,gBAAgB,EAElC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,GACnB,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA"}
package/types/state.d.ts CHANGED
@@ -5,6 +5,6 @@ export declare const getSchema: () => Schema;
5
5
  export declare const setSchema: (_: Schema) => void;
6
6
  export declare const getAuthData: () => {} | null;
7
7
  export declare const setAuthData: (_: AuthData) => void;
8
- export declare const getEnvironment: () => "server" | "client" | null;
8
+ export declare const getEnvironment: () => "client" | "server" | null;
9
9
  export declare const setEnvironment: (env: "client" | "server") => void;
10
10
  //# sourceMappingURL=state.d.ts.map