@tailor-platform/sdk 2.0.1 → 2.2.0

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 (92) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/{dist/cli/index.mjs → bin/tailor.mjs} +1 -1
  3. package/dist/{application-CM6hKnSK.mjs → application-BpLeawBg.mjs} +126 -28
  4. package/dist/application-BpLeawBg.mjs.map +1 -0
  5. package/dist/application-BxLLiLsr.mjs +3 -0
  6. package/dist/cli/commands/deploy/tailordb/index.d.mts +2 -1
  7. package/dist/cli/commands/deploy/types.d.mts +2 -1
  8. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -4
  9. package/dist/cli/commands/tailordb/migrate/file-state.d.mts +1 -0
  10. package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +2 -2
  11. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +8 -1
  12. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -3
  13. package/dist/cli/lib.d.mts +4 -4
  14. package/dist/cli/lib.mjs +3 -482
  15. package/dist/cli/lib.mjs.map +1 -1
  16. package/dist/cli/main.mjs +997 -202
  17. package/dist/cli/main.mjs.map +1 -1
  18. package/dist/completion/zsh-worker.zsh +145 -2
  19. package/dist/configure/config/types.d.mts +12 -1
  20. package/dist/configure/index.d.mts +3 -3
  21. package/dist/configure/services/index.d.mts +3 -2
  22. package/dist/configure/services/resolver/index.d.mts +1 -1
  23. package/dist/configure/services/resolver/resolver.d.mts +1 -1
  24. package/dist/configure/services/tailordb/index.d.mts +2 -1
  25. package/dist/configure/services/tailordb/schema.d.mts +46 -46
  26. package/dist/configure/services/tailordb/types.d.mts +30 -4
  27. package/dist/{crashreport-B5LqCTfF.mjs → crashreport-CIIfLnoO.mjs} +2 -2
  28. package/dist/{crashreport-B5LqCTfF.mjs.map → crashreport-CIIfLnoO.mjs.map} +1 -1
  29. package/dist/{crashreport-eI7ty7ok.mjs → crashreport-CINZ5dVN.mjs} +1 -1
  30. package/dist/errors-CWj21238.mjs +75 -0
  31. package/dist/errors-CWj21238.mjs.map +1 -0
  32. package/dist/{globals-TfAVItuK.mjs → globals-B2nlxBrz.mjs} +2 -10
  33. package/dist/globals-B2nlxBrz.mjs.map +1 -0
  34. package/dist/kysely/index.d.mts +52 -5
  35. package/dist/kysely/index.mjs +7 -2
  36. package/dist/kysely/index.mjs.map +1 -1
  37. package/dist/{logger-CXQq9YIp.mjs → logger-DSdExfor.mjs} +83 -42
  38. package/dist/logger-DSdExfor.mjs.map +1 -0
  39. package/dist/plugin/builtin/seed/index.mjs +1 -1
  40. package/dist/{register-ts-hook-LYV7zH-e.mjs → register-ts-hook-CTth1eqj.mjs} +1587 -272
  41. package/dist/register-ts-hook-CTth1eqj.mjs.map +1 -0
  42. package/dist/runtime/globals.d.mts +0 -7
  43. package/dist/runtime/workflow.d.mts +2 -7
  44. package/dist/schema--xYWRGfe.mjs.map +1 -1
  45. package/dist/seed/index.d.mts +52 -3
  46. package/dist/seed/index.mjs +200 -44
  47. package/dist/seed/index.mjs.map +1 -1
  48. package/dist/{seed-B-yckgQY.mjs → seed-xqM9WIHP.mjs} +8 -8
  49. package/dist/seed-xqM9WIHP.mjs.map +1 -0
  50. package/dist/{service-B5WynBHQ.mjs → service-CCwl3Avt.mjs} +3 -3
  51. package/dist/{service-B5WynBHQ.mjs.map → service-CCwl3Avt.mjs.map} +1 -1
  52. package/dist/service-_XmjSEGr.mjs +3 -0
  53. package/dist/{service-k1xy_A5G.mjs → service-goqlJJgA.mjs} +2 -2
  54. package/dist/{service-k1xy_A5G.mjs.map → service-goqlJJgA.mjs.map} +1 -1
  55. package/dist/{service_pb-D5--My_M.mjs → service_pb-BEWj1pOV.mjs} +2 -2
  56. package/dist/{service_pb-D5--My_M.mjs.map → service_pb-BEWj1pOV.mjs.map} +1 -1
  57. package/dist/{service_pb-i8CmnQP4.mjs → service_pb-BjlhvK9E.mjs} +1 -1
  58. package/dist/utils/test/index.d.mts +9 -3
  59. package/dist/utils/test/index.mjs +49 -25
  60. package/dist/utils/test/index.mjs.map +1 -1
  61. package/dist/vitest/environment.mjs +1 -1
  62. package/dist/vitest/index.d.mts +2 -1
  63. package/dist/vitest/index.mjs +84 -2
  64. package/dist/vitest/index.mjs.map +1 -1
  65. package/dist/vitest/mocks/file.d.mts +1 -1
  66. package/dist/vitest/pglite-kysely.d.mts +43 -0
  67. package/dist/vitest/setup.mjs +1 -1
  68. package/dist/workflow-Bamae_Yc.mjs.map +1 -1
  69. package/dist/{workspace_resource_pb-DXnO2AT-.mjs → workspace_resource_pb-HNIL_Vfj.mjs} +10 -2
  70. package/dist/{workspace_resource_pb-DXnO2AT-.mjs.map → workspace_resource_pb-HNIL_Vfj.mjs.map} +1 -1
  71. package/docs/cli/tailordb.md +87 -22
  72. package/docs/cli-reference.md +13 -11
  73. package/docs/configuration.md +4 -1
  74. package/docs/migration/v2.md +1 -1
  75. package/docs/plugin/custom.md +48 -48
  76. package/docs/plugin/index.md +24 -24
  77. package/docs/services/auth.md +10 -10
  78. package/docs/services/executor.md +1 -1
  79. package/docs/services/resolver.md +34 -2
  80. package/docs/services/tailordb-migration.md +375 -76
  81. package/docs/services/tailordb.md +28 -28
  82. package/docs/testing.md +3 -1
  83. package/package.json +13 -8
  84. package/dist/application-CM6hKnSK.mjs.map +0 -1
  85. package/dist/application-CXNaUNhv.mjs +0 -3
  86. package/dist/errors-D7583Zz7.mjs +0 -58
  87. package/dist/errors-D7583Zz7.mjs.map +0 -1
  88. package/dist/globals-TfAVItuK.mjs.map +0 -1
  89. package/dist/logger-CXQq9YIp.mjs.map +0 -1
  90. package/dist/register-ts-hook-LYV7zH-e.mjs.map +0 -1
  91. package/dist/seed-B-yckgQY.mjs.map +0 -1
  92. package/dist/service-M7OYziQP.mjs +0 -3
@@ -1,3 +1,3 @@
1
- import { i as file_tailor_v1_service, n as PingRequestSchema, r as PingResponseSchema, t as OperatorService } from "./service_pb-D5--My_M.mjs";
1
+ import { i as file_tailor_v1_service, n as PingRequestSchema, r as PingResponseSchema, t as OperatorService } from "./service_pb-BEWj1pOV.mjs";
2
2
 
3
3
  export { OperatorService, PingRequestSchema, PingResponseSchema, file_tailor_v1_service };
@@ -8,20 +8,26 @@ import { StandardSchemaV1 } from "@standard-schema/spec";
8
8
  * - Uses existing id from data if provided, otherwise generates UUID for id fields
9
9
  * - Recursively processes nested types
10
10
  * - Executes hooks.create for fields with create hooks
11
+ * - Takes each field from the data's own properties, so a field named after a
12
+ * member of `Object` such as `toString` is read from the record rather than
13
+ * from the prototype
11
14
  * @template T - The output type of the hook function
12
15
  * @param type - TailorDB type definition
13
16
  * @returns A function that transforms input data according to field hooks
14
17
  */
15
18
  declare function createTailorDBHook<T extends TailorDBType<any, any>>(type: T): (data: unknown, now?: Date) => Partial<output<T>>;
16
19
  /**
17
- * Creates the standard schema definition for lines-db
18
- * This returns the first argument for defineSchema with the ~standard section
20
+ * Creates the standard schema definition used to validate seed rows.
21
+ * Runs the hook, then the type's own `validate`, and the field schema only when
22
+ * that reported nothing, so both levels of validation report as issues rather
23
+ * than by throwing.
19
24
  * @template T - The output type after validation
20
25
  * @param schemaType - TailorDB field schema for validation
21
26
  * @param hook - Hook function to transform data before validation
27
+ * @param type - TailorDB type definition, when it carries a type-level `validate`
22
28
  * @returns Schema object with ~standard section for defineSchema
23
29
  */
24
- declare function createStandardSchema<T = Record<string, unknown>>(schemaType: TailorField<any, T>, hook: (data: unknown) => Partial<T>): {
30
+ declare function createStandardSchema<T = Record<string, unknown>>(schemaType: TailorField<any, T>, hook: (data: unknown) => Partial<T>, type?: TailorDBType<any, any>): {
25
31
  readonly "~standard": {
26
32
  readonly version: 1;
27
33
  readonly vendor: "@tailor-platform/sdk";
@@ -1,9 +1,20 @@
1
1
  //#region src/utils/test/index.ts
2
+ function setField(record, key, value) {
3
+ Object.defineProperty(record, key, {
4
+ value,
5
+ enumerable: true,
6
+ writable: true,
7
+ configurable: true
8
+ });
9
+ }
2
10
  /**
3
11
  * Creates a hook function that processes TailorDB type fields
4
12
  * - Uses existing id from data if provided, otherwise generates UUID for id fields
5
13
  * - Recursively processes nested types
6
14
  * - Executes hooks.create for fields with create hooks
15
+ * - Takes each field from the data's own properties, so a field named after a
16
+ * member of `Object` such as `toString` is read from the record rather than
17
+ * from the prototype
7
18
  * @template T - The output type of the hook function
8
19
  * @param type - TailorDB type definition
9
20
  * @returns A function that transforms input data according to field hooks
@@ -13,25 +24,26 @@ function createTailorDBHook(type) {
13
24
  const obj = data && typeof data === "object" ? data : void 0;
14
25
  const hooked = Object.entries(type.fields).reduce((hooked, [key, value]) => {
15
26
  const field = value;
16
- if (key === "id") hooked[key] = obj?.[key] ?? crypto.randomUUID();
27
+ const input = obj && Object.hasOwn(obj, key) ? obj[key] : void 0;
28
+ let hookedValue;
29
+ if (key === "id") hookedValue = input ?? crypto.randomUUID();
17
30
  else if (field.type === "nested") {
18
31
  const nestedHook = createTailorDBHook({ fields: field.fields });
19
- if (field.metadata.array) {
20
- const nestedValue = obj?.[key];
21
- hooked[key] = Array.isArray(nestedValue) ? nestedValue.map((item) => nestedHook(item, now)) : nestedValue;
22
- } else hooked[key] = nestedHook(obj?.[key], now);
32
+ if (field.metadata.array) hookedValue = Array.isArray(input) ? input.map((item) => nestedHook(item, now)) : input;
33
+ else hookedValue = nestedHook(input, now);
23
34
  } else if (field.metadata.hooks?.create) {
24
- hooked[key] = field.metadata.hooks.create({
25
- input: obj?.[key],
35
+ hookedValue = field.metadata.hooks.create({
36
+ input,
26
37
  invoker: null,
27
38
  now
28
39
  });
29
- if (hooked[key] instanceof Date) hooked[key] = hooked[key].toISOString();
30
- } else if (obj) hooked[key] = obj[key];
31
- if (hooked[key] == null && field.metadata.default !== void 0) {
40
+ if (hookedValue instanceof Date) hookedValue = hookedValue.toISOString();
41
+ } else hookedValue = input;
42
+ if (hookedValue == null && field.metadata.default !== void 0) {
32
43
  const isTimeType = field.type === "datetime" || field.type === "date" || field.type === "time";
33
- hooked[key] = field.metadata.default === "now" && isTimeType ? now.toISOString() : field.metadata.default;
44
+ hookedValue = field.metadata.default === "now" && isTimeType ? now.toISOString() : field.metadata.default;
34
45
  }
46
+ setField(hooked, key, hookedValue);
35
47
  return hooked;
36
48
  }, {});
37
49
  if (type.metadata?.typeHook?.create) {
@@ -41,35 +53,47 @@ function createTailorDBHook(type) {
41
53
  invoker: null,
42
54
  now
43
55
  });
44
- if (overrides && typeof overrides === "object") for (const [key, value] of Object.entries(overrides)) hooked[key] = value instanceof Date ? value.toISOString() : value;
45
- }
46
- if (type.metadata?.typeValidate) {
47
- const { id: _id, ...newRecord } = hooked;
48
- type.metadata.typeValidate({
49
- newRecord,
50
- oldRecord: null,
51
- invoker: null
52
- }, (field, message) => {
53
- throw new Error(`Validation failed on field '${field}': ${message}`);
54
- });
56
+ if (overrides && typeof overrides === "object") for (const [key, value] of Object.entries(overrides)) setField(hooked, key, value instanceof Date ? value.toISOString() : value);
55
57
  }
56
58
  return hooked;
57
59
  };
58
60
  }
61
+ function typeLevelIssues(type, hooked) {
62
+ const typeValidate = type?.metadata?.typeValidate;
63
+ if (!typeValidate) return [];
64
+ const { id: _id, ...newRecord } = hooked;
65
+ const issues = [];
66
+ typeValidate({
67
+ newRecord,
68
+ oldRecord: null,
69
+ invoker: null
70
+ }, (field, message) => {
71
+ issues.push({
72
+ message,
73
+ path: [field]
74
+ });
75
+ });
76
+ return issues;
77
+ }
59
78
  /**
60
- * Creates the standard schema definition for lines-db
61
- * This returns the first argument for defineSchema with the ~standard section
79
+ * Creates the standard schema definition used to validate seed rows.
80
+ * Runs the hook, then the type's own `validate`, and the field schema only when
81
+ * that reported nothing, so both levels of validation report as issues rather
82
+ * than by throwing.
62
83
  * @template T - The output type after validation
63
84
  * @param schemaType - TailorDB field schema for validation
64
85
  * @param hook - Hook function to transform data before validation
86
+ * @param type - TailorDB type definition, when it carries a type-level `validate`
65
87
  * @returns Schema object with ~standard section for defineSchema
66
88
  */
67
- function createStandardSchema(schemaType, hook) {
89
+ function createStandardSchema(schemaType, hook, type) {
68
90
  return { "~standard": {
69
91
  version: 1,
70
92
  vendor: "@tailor-platform/sdk",
71
93
  validate: (value) => {
72
94
  const hooked = hook(value);
95
+ const issues = typeLevelIssues(type, hooked);
96
+ if (issues.length > 0) return { issues };
73
97
  const result = schemaType.parse({
74
98
  value: hooked,
75
99
  data: hooked,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/utils/test/index.ts"],"sourcesContent":["import type { output } from \"#/configure/index\";\nimport type { TailorDBType } from \"#/configure/services/tailordb/schema\";\nimport type { TailorField } from \"#/configure/types/type\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Creates a hook function that processes TailorDB type fields\n * - Uses existing id from data if provided, otherwise generates UUID for id fields\n * - Recursively processes nested types\n * - Executes hooks.create for fields with create hooks\n * @template T - The output type of the hook function\n * @param type - TailorDB type definition\n * @returns A function that transforms input data according to field hooks\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function createTailorDBHook<T extends TailorDBType<any, any>>(type: T) {\n return (data: unknown, now: Date = new Date()) => {\n const obj = data && typeof data === \"object\" ? (data as Record<string, unknown>) : undefined;\n const hooked = Object.entries(type.fields).reduce(\n (hooked, [key, value]) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const field = value as TailorField<any, any, any>;\n if (key === \"id\") {\n hooked[key] = obj?.[key] ?? crypto.randomUUID();\n } else if (field.type === \"nested\") {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const nestedHook = createTailorDBHook({ fields: field.fields } as any);\n if (field.metadata.array) {\n const nestedValue = obj?.[key];\n hooked[key] = Array.isArray(nestedValue)\n ? nestedValue.map((item) => nestedHook(item, now))\n : nestedValue;\n } else {\n hooked[key] = nestedHook(obj?.[key], now);\n }\n } else if (field.metadata.hooks?.create) {\n hooked[key] = field.metadata.hooks.create({\n input: obj?.[key],\n invoker: null,\n now,\n });\n if (hooked[key] instanceof Date) {\n hooked[key] = hooked[key].toISOString();\n }\n } else if (obj) {\n hooked[key] = obj[key];\n }\n if (hooked[key] == null && field.metadata.default !== undefined) {\n const isTimeType =\n field.type === \"datetime\" || field.type === \"date\" || field.type === \"time\";\n hooked[key] =\n field.metadata.default === \"now\" && isTimeType\n ? now.toISOString()\n : field.metadata.default;\n }\n return hooked;\n },\n {} as Record<string, unknown>,\n );\n\n // oxlint-disable-next-line typescript/no-unnecessary-condition -- metadata absent in recursive nested calls\n if (type.metadata?.typeHook?.create) {\n const { id: _id, ...typeHookInput } = hooked;\n // oxlint-disable-next-line typescript/no-unsafe-function-type\n const overrides = (type.metadata.typeHook.create as Function)({\n input: typeHookInput,\n invoker: null,\n now,\n });\n if (overrides && typeof overrides === \"object\") {\n for (const [key, value] of Object.entries(overrides as Record<string, unknown>)) {\n hooked[key] = value instanceof Date ? value.toISOString() : value;\n }\n }\n }\n\n // oxlint-disable-next-line typescript/no-unnecessary-condition -- metadata absent in recursive nested calls\n if (type.metadata?.typeValidate) {\n const { id: _id, ...newRecord } = hooked;\n // oxlint-disable-next-line typescript/no-unsafe-function-type\n (type.metadata.typeValidate as Function)(\n { newRecord, oldRecord: null, invoker: null },\n (field: string, message: string) => {\n throw new Error(`Validation failed on field '${field}': ${message}`);\n },\n );\n }\n\n return hooked as Partial<output<T>>;\n };\n}\n\n/**\n * Creates the standard schema definition for lines-db\n * This returns the first argument for defineSchema with the ~standard section\n * @template T - The output type after validation\n * @param schemaType - TailorDB field schema for validation\n * @param hook - Hook function to transform data before validation\n * @returns Schema object with ~standard section for defineSchema\n */\nexport function createStandardSchema<T = Record<string, unknown>>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schemaType: TailorField<any, T>,\n hook: (data: unknown) => Partial<T>,\n) {\n return {\n \"~standard\": {\n version: 1,\n vendor: \"@tailor-platform/sdk\",\n validate: (value: unknown) => {\n const hooked = hook(value);\n const result = schemaType.parse({\n value: hooked,\n data: hooked,\n invoker: null,\n });\n if (result.issues) {\n return result;\n }\n return { value: hooked as T };\n },\n },\n } as const satisfies StandardSchemaV1<T>;\n}\n"],"mappings":";;;;;;;;;;AAeA,SAAgB,mBAAqD,MAAS;CAC5E,QAAQ,MAAe,sBAAY,IAAI,KAAK,MAAM;EAChD,MAAM,MAAM,QAAQ,OAAO,SAAS,WAAY,OAAmC;EACnF,MAAM,SAAS,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,QACxC,QAAQ,CAAC,KAAK,WAAW;GAExB,MAAM,QAAQ;GACd,IAAI,QAAQ,MACV,OAAO,OAAO,MAAM,QAAQ,OAAO,WAAW;QACzC,IAAI,MAAM,SAAS,UAAU;IAElC,MAAM,aAAa,mBAAmB,EAAE,QAAQ,MAAM,OAAO,CAAQ;IACrE,IAAI,MAAM,SAAS,OAAO;KACxB,MAAM,cAAc,MAAM;KAC1B,OAAO,OAAO,MAAM,QAAQ,WAAW,IACnC,YAAY,KAAK,SAAS,WAAW,MAAM,GAAG,CAAC,IAC/C;IACN,OACE,OAAO,OAAO,WAAW,MAAM,MAAM,GAAG;GAE5C,OAAO,IAAI,MAAM,SAAS,OAAO,QAAQ;IACvC,OAAO,OAAO,MAAM,SAAS,MAAM,OAAO;KACxC,OAAO,MAAM;KACb,SAAS;KACT;IACF,CAAC;IACD,IAAI,OAAO,gBAAgB,MACzB,OAAO,OAAO,OAAO,IAAI,CAAC,YAAY;GAE1C,OAAO,IAAI,KACT,OAAO,OAAO,IAAI;GAEpB,IAAI,OAAO,QAAQ,QAAQ,MAAM,SAAS,YAAY,QAAW;IAC/D,MAAM,aACJ,MAAM,SAAS,cAAc,MAAM,SAAS,UAAU,MAAM,SAAS;IACvE,OAAO,OACL,MAAM,SAAS,YAAY,SAAS,aAChC,IAAI,YAAY,IAChB,MAAM,SAAS;GACvB;GACA,OAAO;EACT,GACA,CAAC,CACH;EAGA,IAAI,KAAK,UAAU,UAAU,QAAQ;GACnC,MAAM,EAAE,IAAI,KAAK,GAAG,kBAAkB;GAEtC,MAAM,YAAa,KAAK,SAAS,SAAS,OAAoB;IAC5D,OAAO;IACP,SAAS;IACT;GACF,CAAC;GACD,IAAI,aAAa,OAAO,cAAc,UACpC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAoC,GAC5E,OAAO,OAAO,iBAAiB,OAAO,MAAM,YAAY,IAAI;EAGlE;EAGA,IAAI,KAAK,UAAU,cAAc;GAC/B,MAAM,EAAE,IAAI,KAAK,GAAG,cAAc;GAElC,AAAC,KAAK,SAAS,aACb;IAAE;IAAW,WAAW;IAAM,SAAS;GAAK,IAC3C,OAAe,YAAoB;IAClC,MAAM,IAAI,MAAM,+BAA+B,MAAM,KAAK,SAAS;GACrE,CACF;EACF;EAEA,OAAO;CACT;AACF;;;;;;;;;AAUA,SAAgB,qBAEd,YACA,MACA;CACA,OAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,WAAW,UAAmB;GAC5B,MAAM,SAAS,KAAK,KAAK;GACzB,MAAM,SAAS,WAAW,MAAM;IAC9B,OAAO;IACP,MAAM;IACN,SAAS;GACX,CAAC;GACD,IAAI,OAAO,QACT,OAAO;GAET,OAAO,EAAE,OAAO,OAAY;EAC9B;CACF,EACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/utils/test/index.ts"],"sourcesContent":["import type { output } from \"#/configure/index\";\nimport type { TailorDBType } from \"#/configure/services/tailordb/schema\";\nimport type { TailorField } from \"#/configure/types/type\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n// Not `record[key] = value`: assigning to `__proto__` goes through the inherited\n// setter, which mutates the prototype instead of recording the field and leaves\n// no own property behind for the value to be read from.\nfunction setField(record: Record<string, unknown>, key: string, value: unknown): void {\n Object.defineProperty(record, key, {\n value,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n}\n\n/**\n * Creates a hook function that processes TailorDB type fields\n * - Uses existing id from data if provided, otherwise generates UUID for id fields\n * - Recursively processes nested types\n * - Executes hooks.create for fields with create hooks\n * - Takes each field from the data's own properties, so a field named after a\n * member of `Object` such as `toString` is read from the record rather than\n * from the prototype\n * @template T - The output type of the hook function\n * @param type - TailorDB type definition\n * @returns A function that transforms input data according to field hooks\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function createTailorDBHook<T extends TailorDBType<any, any>>(type: T) {\n return (data: unknown, now: Date = new Date()) => {\n const obj = data && typeof data === \"object\" ? (data as Record<string, unknown>) : undefined;\n const hooked = Object.entries(type.fields).reduce(\n (hooked, [key, value]) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const field = value as TailorField<any, any, any>;\n // `Object.hasOwn`, not `obj?.[key]`: a field named after an Object member\n // such as `toString` would otherwise read the inherited value.\n const input = obj && Object.hasOwn(obj, key) ? obj[key] : undefined;\n let hookedValue: unknown;\n if (key === \"id\") {\n hookedValue = input ?? crypto.randomUUID();\n } else if (field.type === \"nested\") {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const nestedHook = createTailorDBHook({ fields: field.fields } as any);\n if (field.metadata.array) {\n hookedValue = Array.isArray(input) ? input.map((item) => nestedHook(item, now)) : input;\n } else {\n hookedValue = nestedHook(input, now);\n }\n } else if (field.metadata.hooks?.create) {\n hookedValue = field.metadata.hooks.create({ input, invoker: null, now });\n if (hookedValue instanceof Date) {\n hookedValue = hookedValue.toISOString();\n }\n } else {\n hookedValue = input;\n }\n if (hookedValue == null && field.metadata.default !== undefined) {\n const isTimeType =\n field.type === \"datetime\" || field.type === \"date\" || field.type === \"time\";\n hookedValue =\n field.metadata.default === \"now\" && isTimeType\n ? now.toISOString()\n : field.metadata.default;\n }\n // Set even when there is no value: the key carrying `undefined` is what\n // tells a schema inferred from the record that the column is nullable,\n // and it shadows a same-named member of `Object.prototype`.\n setField(hooked, key, hookedValue);\n return hooked;\n },\n {} as Record<string, unknown>,\n );\n\n // oxlint-disable-next-line typescript/no-unnecessary-condition -- metadata absent in recursive nested calls\n if (type.metadata?.typeHook?.create) {\n const { id: _id, ...typeHookInput } = hooked;\n // oxlint-disable-next-line typescript/no-unsafe-function-type\n const overrides = (type.metadata.typeHook.create as Function)({\n input: typeHookInput,\n invoker: null,\n now,\n });\n if (overrides && typeof overrides === \"object\") {\n for (const [key, value] of Object.entries(overrides as Record<string, unknown>)) {\n setField(hooked, key, value instanceof Date ? value.toISOString() : value);\n }\n }\n }\n\n return hooked as Partial<output<T>>;\n };\n}\n\n// Collect the issues the type's own `validate` reports for a record, so they\n// surface the same way a field's do instead of ending the run.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction typeLevelIssues(type: TailorDBType<any, any> | undefined, hooked: unknown) {\n // oxlint-disable-next-line typescript/no-unnecessary-condition -- absent on a nested type\n const typeValidate = type?.metadata?.typeValidate;\n if (!typeValidate) {\n return [];\n }\n const { id: _id, ...newRecord } = hooked as Record<string, unknown>;\n const issues: StandardSchemaV1.Issue[] = [];\n // oxlint-disable-next-line typescript/no-unsafe-function-type\n (typeValidate as Function)(\n { newRecord, oldRecord: null, invoker: null },\n (field: string, message: string) => {\n issues.push({ message, path: [field] });\n },\n );\n return issues;\n}\n\n/**\n * Creates the standard schema definition used to validate seed rows.\n * Runs the hook, then the type's own `validate`, and the field schema only when\n * that reported nothing, so both levels of validation report as issues rather\n * than by throwing.\n * @template T - The output type after validation\n * @param schemaType - TailorDB field schema for validation\n * @param hook - Hook function to transform data before validation\n * @param type - TailorDB type definition, when it carries a type-level `validate`\n * @returns Schema object with ~standard section for defineSchema\n */\nexport function createStandardSchema<T = Record<string, unknown>>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schemaType: TailorField<any, T>,\n hook: (data: unknown) => Partial<T>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n type?: TailorDBType<any, any>,\n) {\n return {\n \"~standard\": {\n version: 1,\n vendor: \"@tailor-platform/sdk\",\n validate: (value: unknown) => {\n const hooked = hook(value);\n const issues = typeLevelIssues(type, hooked);\n if (issues.length > 0) {\n return { issues };\n }\n const result = schemaType.parse({\n value: hooked,\n data: hooked,\n invoker: null,\n });\n if (result.issues) {\n return result;\n }\n return { value: hooked as T };\n },\n },\n } as const satisfies StandardSchemaV1<T>;\n}\n"],"mappings":";AAQA,SAAS,SAAS,QAAiC,KAAa,OAAsB;CACpF,OAAO,eAAe,QAAQ,KAAK;EACjC;EACA,YAAY;EACZ,UAAU;EACV,cAAc;CAChB,CAAC;AACH;;;;;;;;;;;;;AAeA,SAAgB,mBAAqD,MAAS;CAC5E,QAAQ,MAAe,sBAAY,IAAI,KAAK,MAAM;EAChD,MAAM,MAAM,QAAQ,OAAO,SAAS,WAAY,OAAmC;EACnF,MAAM,SAAS,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,QACxC,QAAQ,CAAC,KAAK,WAAW;GAExB,MAAM,QAAQ;GAGd,MAAM,QAAQ,OAAO,OAAO,OAAO,KAAK,GAAG,IAAI,IAAI,OAAO;GAC1D,IAAI;GACJ,IAAI,QAAQ,MACV,cAAc,SAAS,OAAO,WAAW;QACpC,IAAI,MAAM,SAAS,UAAU;IAElC,MAAM,aAAa,mBAAmB,EAAE,QAAQ,MAAM,OAAO,CAAQ;IACrE,IAAI,MAAM,SAAS,OACjB,cAAc,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,SAAS,WAAW,MAAM,GAAG,CAAC,IAAI;SAElF,cAAc,WAAW,OAAO,GAAG;GAEvC,OAAO,IAAI,MAAM,SAAS,OAAO,QAAQ;IACvC,cAAc,MAAM,SAAS,MAAM,OAAO;KAAE;KAAO,SAAS;KAAM;IAAI,CAAC;IACvE,IAAI,uBAAuB,MACzB,cAAc,YAAY,YAAY;GAE1C,OACE,cAAc;GAEhB,IAAI,eAAe,QAAQ,MAAM,SAAS,YAAY,QAAW;IAC/D,MAAM,aACJ,MAAM,SAAS,cAAc,MAAM,SAAS,UAAU,MAAM,SAAS;IACvE,cACE,MAAM,SAAS,YAAY,SAAS,aAChC,IAAI,YAAY,IAChB,MAAM,SAAS;GACvB;GAIA,SAAS,QAAQ,KAAK,WAAW;GACjC,OAAO;EACT,GACA,CAAC,CACH;EAGA,IAAI,KAAK,UAAU,UAAU,QAAQ;GACnC,MAAM,EAAE,IAAI,KAAK,GAAG,kBAAkB;GAEtC,MAAM,YAAa,KAAK,SAAS,SAAS,OAAoB;IAC5D,OAAO;IACP,SAAS;IACT;GACF,CAAC;GACD,IAAI,aAAa,OAAO,cAAc,UACpC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAoC,GAC5E,SAAS,QAAQ,KAAK,iBAAiB,OAAO,MAAM,YAAY,IAAI,KAAK;EAG/E;EAEA,OAAO;CACT;AACF;AAKA,SAAS,gBAAgB,MAA0C,QAAiB;CAElF,MAAM,eAAe,MAAM,UAAU;CACrC,IAAI,CAAC,cACH,OAAO,CAAC;CAEV,MAAM,EAAE,IAAI,KAAK,GAAG,cAAc;CAClC,MAAM,SAAmC,CAAC;CAE1C,AAAC,aACC;EAAE;EAAW,WAAW;EAAM,SAAS;CAAK,IAC3C,OAAe,YAAoB;EAClC,OAAO,KAAK;GAAE;GAAS,MAAM,CAAC,KAAK;EAAE,CAAC;CACxC,CACF;CACA,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,qBAEd,YACA,MAEA,MACA;CACA,OAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,WAAW,UAAmB;GAC5B,MAAM,SAAS,KAAK,KAAK;GACzB,MAAM,SAAS,gBAAgB,MAAM,MAAM;GAC3C,IAAI,OAAO,SAAS,GAClB,OAAO,EAAE,OAAO;GAElB,MAAM,SAAS,WAAW,MAAM;IAC9B,OAAO;IACP,MAAM;IACN,SAAS;GACX,CAAC;GACD,IAAI,OAAO,QACT,OAAO;GAET,OAAO,EAAE,OAAO,OAAY;EAC9B;CACF,EACF;AACF"}
@@ -1,4 +1,4 @@
1
- import { n as cleanupPlatformGlobals, r as installPlatformGlobals, t as RUNTIME_FLAG_KEY } from "../globals-TfAVItuK.mjs";
1
+ import { n as cleanupPlatformGlobals, r as installPlatformGlobals, t as RUNTIME_FLAG_KEY } from "../globals-B2nlxBrz.mjs";
2
2
  import * as globals from "globals";
3
3
 
4
4
  //#region src/vitest/environment.ts
@@ -10,6 +10,7 @@ import { mockWorkflow } from "./mocks/workflow.mjs";
10
10
  import "./mock.mjs";
11
11
  import { RunWorkflowLocallyOptions, runWorkflowLocally } from "./workflow-local.mjs";
12
12
  import { ExecutedQuery, KyselyMock, createKyselyMock } from "./mock-kysely.mjs";
13
+ import { PGliteClient, createKyselyPGlite } from "./pglite-kysely.mjs";
13
14
  import { Plugin } from "vitest/config";
14
15
  //#region src/vitest/index.d.ts
15
16
  /**
@@ -71,4 +72,4 @@ declare function tailorRuntime(options?: {
71
72
  config?: string;
72
73
  }): Plugin[];
73
74
  //#endregion
74
- export { type ExecutedQuery, type KyselyMock, type MockAigatewayOptions, type MockAuthconnectionOptions, type MockFileOptions, type MockIconvOptions, type MockIdpOptions, type MockLoggerOptions, type MockSecretmanagerOptions, type MockTailordbOptions, type QueryBehavior, type QueryMatch, type QueryMatcher, type RunWorkflowLocallyOptions, createKyselyMock, mockAigateway, mockAuthconnection, mockFile, mockIconv, mockIdp, mockLogger, mockSecretmanager, mockTailordb, mockWorkflow, runWorkflowLocally, tailorRuntime };
75
+ export { type ExecutedQuery, type KyselyMock, type MockAigatewayOptions, type MockAuthconnectionOptions, type MockFileOptions, type MockIconvOptions, type MockIdpOptions, type MockLoggerOptions, type MockSecretmanagerOptions, type MockTailordbOptions, type PGliteClient, type QueryBehavior, type QueryMatch, type QueryMatcher, type RunWorkflowLocallyOptions, createKyselyMock, createKyselyPGlite, mockAigateway, mockAuthconnection, mockFile, mockIconv, mockIdp, mockLogger, mockSecretmanager, mockTailordb, mockWorkflow, runWorkflowLocally, tailorRuntime };
@@ -6,7 +6,7 @@ import { t as platformSerialize } from "../platform-serialize-RoRtBS0v.mjs";
6
6
  import { i as withDispose, n as tailorRoot, r as tailordbRoot, t as mockSecretmanager } from "../secretmanager-IY4UvinW.mjs";
7
7
  import { isEqual } from "es-toolkit";
8
8
  import { fileURLToPath } from "node:url";
9
- import { ColumnNode, InsertQueryNode, Kysely, PostgresAdapter, PostgresIntrospector, PostgresQueryCompiler, PrimitiveValueListNode, ReferenceNode, UpdateQueryNode, ValueListNode, ValueNode, ValuesNode } from "kysely";
9
+ import { ColumnNode, CompiledQuery, InsertQueryNode, Kysely, PostgresAdapter, PostgresIntrospector, PostgresQueryCompiler, PrimitiveValueListNode, ReferenceNode, UpdateQueryNode, ValueListNode, ValueNode, ValuesNode } from "kysely";
10
10
  import { dirname, isAbsolute, matchesGlob, relative, resolve } from "node:path";
11
11
  import { vi } from "vitest";
12
12
 
@@ -1751,6 +1751,88 @@ function createKyselyMock() {
1751
1751
  };
1752
1752
  }
1753
1753
 
1754
+ //#endregion
1755
+ //#region src/vitest/pglite-kysely.ts
1756
+ /**
1757
+ * Kysely adapter for running migration scripts against PGlite.
1758
+ *
1759
+ * Accepts the PGlite client structurally so the SDK does not depend on
1760
+ * `@electric-sql/pglite`; users install it themselves as a devDependency.
1761
+ */
1762
+ var PGliteConnection = class {
1763
+ #client;
1764
+ constructor(client) {
1765
+ this.#client = client;
1766
+ }
1767
+ async executeQuery(compiledQuery) {
1768
+ const result = await this.#client.query(compiledQuery.sql, [...compiledQuery.parameters]);
1769
+ return {
1770
+ rows: result.rows,
1771
+ numAffectedRows: BigInt(result.affectedRows ?? 0)
1772
+ };
1773
+ }
1774
+ streamQuery() {
1775
+ throw new Error("createKyselyPGlite: streaming is not supported");
1776
+ }
1777
+ };
1778
+ var PGliteDriver = class {
1779
+ #client;
1780
+ constructor(client) {
1781
+ this.#client = client;
1782
+ }
1783
+ async init() {}
1784
+ async acquireConnection() {
1785
+ return new PGliteConnection(this.#client);
1786
+ }
1787
+ async beginTransaction(connection, settings) {
1788
+ const parts = settings.isolationLevel ? ["start transaction", `isolation level ${settings.isolationLevel}`] : ["begin"];
1789
+ if (settings.accessMode) parts.push(settings.accessMode);
1790
+ await connection.executeQuery(CompiledQuery.raw(parts.join(" ")));
1791
+ }
1792
+ async commitTransaction(connection) {
1793
+ await connection.executeQuery(CompiledQuery.raw("commit"));
1794
+ }
1795
+ async rollbackTransaction(connection) {
1796
+ await connection.executeQuery(CompiledQuery.raw("rollback"));
1797
+ }
1798
+ async releaseConnection() {}
1799
+ async destroy() {
1800
+ await this.#client.close();
1801
+ }
1802
+ };
1803
+ /**
1804
+ * Create a Kysely instance backed by a PGlite in-memory Postgres, for
1805
+ * executing a migration script's queries against real data in tests.
1806
+ * Pass the migration's schema as the type argument, e.g.
1807
+ * `createKyselyPGlite<Database>(new PGlite())`.
1808
+ *
1809
+ * PGlite runs full PostgreSQL while TailorDB supports a subset of it, so a
1810
+ * statement passing here can still be rejected by the platform; keep a
1811
+ * statement-level test (see `createKyselyMock`) alongside.
1812
+ * @param client - A `PGlite` instance from `@electric-sql/pglite`
1813
+ * @returns A Kysely instance that executes queries on the client and closes it on `destroy()`
1814
+ * @example
1815
+ * ```typescript
1816
+ * // migrations/0005/migrate.test.ts
1817
+ * import { PGlite } from "@electric-sql/pglite";
1818
+ * import { createKyselyPGlite } from "@tailor-platform/sdk/vitest";
1819
+ * import type { Database } from "./db";
1820
+ * import { main } from "./migrate";
1821
+ *
1822
+ * const db = createKyselyPGlite<Database>(new PGlite());
1823
+ * // create tables matching db.ts, insert rows, then:
1824
+ * await db.transaction().execute((trx) => main(trx));
1825
+ * ```
1826
+ */
1827
+ function createKyselyPGlite(client) {
1828
+ return new Kysely({ dialect: {
1829
+ createAdapter: () => new PostgresAdapter(),
1830
+ createDriver: () => new PGliteDriver(client),
1831
+ createIntrospector: (db) => new PostgresIntrospector(db),
1832
+ createQueryCompiler: () => new PostgresQueryCompiler()
1833
+ } });
1834
+ }
1835
+
1754
1836
  //#endregion
1755
1837
  //#region src/vitest/index.ts
1756
1838
  /**
@@ -1813,5 +1895,5 @@ function tailorRuntime(options) {
1813
1895
  }
1814
1896
 
1815
1897
  //#endregion
1816
- export { createKyselyMock, mockAigateway, mockAuthconnection, mockFile, mockIconv, mockIdp, mockLogger, mockSecretmanager, mockTailordb, mockWorkflow, runWorkflowLocally, tailorRuntime };
1898
+ export { createKyselyMock, createKyselyPGlite, mockAigateway, mockAuthconnection, mockFile, mockIconv, mockIdp, mockLogger, mockSecretmanager, mockTailordb, mockWorkflow, runWorkflowLocally, tailorRuntime };
1817
1899
  //# sourceMappingURL=index.mjs.map