@tailor-platform/sdk 2.0.0 → 2.1.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 (36) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +2 -2
  3. package/dist/application-Af1zIqSI.mjs +3 -0
  4. package/dist/{application-CM6hKnSK.mjs → application-D77KJFKD.mjs} +121 -23
  5. package/dist/application-D77KJFKD.mjs.map +1 -0
  6. package/dist/cli/lib.mjs +2 -2
  7. package/dist/cli/main.mjs +33 -20
  8. package/dist/cli/main.mjs.map +1 -1
  9. package/dist/completion/zsh-worker.zsh +1 -1
  10. package/dist/configure/config/types.d.mts +12 -1
  11. package/dist/configure/index.d.mts +1 -1
  12. package/dist/configure/services/index.d.mts +1 -1
  13. package/dist/configure/services/resolver/index.d.mts +1 -1
  14. package/dist/configure/services/resolver/resolver.d.mts +1 -1
  15. package/dist/{globals-TfAVItuK.mjs → globals-B2nlxBrz.mjs} +2 -10
  16. package/dist/globals-B2nlxBrz.mjs.map +1 -0
  17. package/dist/{register-ts-hook-LYV7zH-e.mjs → register-ts-hook-BU18uU44.mjs} +3 -3
  18. package/dist/{register-ts-hook-LYV7zH-e.mjs.map → register-ts-hook-BU18uU44.mjs.map} +1 -1
  19. package/dist/runtime/globals.d.mts +0 -7
  20. package/dist/runtime/workflow.d.mts +2 -7
  21. package/dist/utils/test/index.d.mts +3 -0
  22. package/dist/utils/test/index.mjs +24 -12
  23. package/dist/utils/test/index.mjs.map +1 -1
  24. package/dist/vitest/environment.mjs +1 -1
  25. package/dist/vitest/mocks/file.d.mts +1 -1
  26. package/dist/vitest/setup.mjs +1 -1
  27. package/dist/workflow-Bamae_Yc.mjs.map +1 -1
  28. package/docs/configuration.md +3 -0
  29. package/docs/migration/v2.md +6 -3
  30. package/docs/quickstart.md +5 -5
  31. package/docs/services/resolver.md +32 -0
  32. package/docs/testing.md +1 -1
  33. package/package.json +5 -5
  34. package/dist/application-CM6hKnSK.mjs.map +0 -1
  35. package/dist/application-CXNaUNhv.mjs +0 -3
  36. package/dist/globals-TfAVItuK.mjs.map +0 -1
@@ -78,11 +78,4 @@ declare global {
78
78
  name: "TailorErrors";
79
79
  errors: TailorErrorItem[];
80
80
  }
81
- /**
82
- * Single-message error raised by the Tailor Platform Function runtime.
83
- */
84
- class TailorErrorMessage extends Error {
85
- constructor(message: string);
86
- name: "TailorErrorMessage";
87
- }
88
81
  }
@@ -6,10 +6,8 @@
6
6
  * At runtime this delegates to `globalThis.tailor.workflow`. Use `mockWorkflow`
7
7
  * from `@tailor-platform/sdk/vitest` to mock these calls in unit tests.
8
8
  *
9
- * The canonical names (`startWorkflow`, `execJobFunction`,
10
- * `resumeWorkflowExecution`) mirror the public `tailor.v1` RPC vocabulary:
11
- * `Exec*` is a blocking call that returns the job's result, while `Start*`
12
- * returns only an execution ID.
9
+ * `execJobFunction` blocks until the job finishes and returns its result, while
10
+ * `startWorkflow` returns only an execution ID.
13
11
  * @example
14
12
  * import { workflow } from "@tailor-platform/sdk/runtime";
15
13
  *
@@ -69,9 +67,6 @@ interface PlatformWorkflowAPI {
69
67
  resumeWorkflowExecution(executionId: string): Promise<string>;
70
68
  /**
71
69
  * Executes a job function and returns its result via durable suspend/replay.
72
- *
73
- * Canonical name under the platform verb convention: `Exec*` blocks and
74
- * returns the job's result, while `Start*` returns only an execution ID.
75
70
  * @param jobName - Job name as defined in the workflow
76
71
  * @param args - Arguments forwarded to the job
77
72
  * @param options - Optional execution options (e.g. `executionPolicyKey`)
@@ -8,6 +8,9 @@ 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
@@ -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,7 +53,7 @@ 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;
56
+ if (overrides && typeof overrides === "object") for (const [key, value] of Object.entries(overrides)) setField(hooked, key, value instanceof Date ? value.toISOString() : value);
45
57
  }
46
58
  if (type.metadata?.typeValidate) {
47
59
  const { id: _id, ...newRecord } = 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 // 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":";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;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,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
@@ -46,10 +46,10 @@ declare function mockFile(options?: MockFileOptions): {
46
46
  calls: FileCall[];
47
47
  clear(): void;
48
48
  reset(): void;
49
- delete: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<void>>;
50
49
  upload: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string, data: string | ArrayBuffer | Uint8Array | number[], options?: FileUploadOptions) => Promise<FileUploadResponse>>;
51
50
  download: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileDownloadResponse>>;
52
51
  downloadAsBase64: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileDownloadAsBase64Response>>;
52
+ delete: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<void>>;
53
53
  getMetadata: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileMetadata>>;
54
54
  downloadStream: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileDownloadStreamResponse>>;
55
55
  uploadStream: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string, readableStream: ReadableStream<Uint8Array | ArrayBuffer>, options?: FileUploadStreamOptions) => Promise<FileUploadResponse>>;
@@ -1,4 +1,4 @@
1
- import { t as RUNTIME_FLAG_KEY } from "../globals-TfAVItuK.mjs";
1
+ import { t as RUNTIME_FLAG_KEY } from "../globals-B2nlxBrz.mjs";
2
2
  import { t as mockSecretmanager } from "../secretmanager-IY4UvinW.mjs";
3
3
  import { pathToFileURL } from "node:url";
4
4
  import { afterEach, beforeAll, beforeEach } from "vitest";
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-Bamae_Yc.mjs","names":[],"sources":["../src/runtime/workflow.ts"],"sourcesContent":["/**\n * Workflow utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.workflow` runtime API.\n * At runtime this delegates to `globalThis.tailor.workflow`. Use `mockWorkflow`\n * from `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n *\n * The canonical names (`startWorkflow`, `execJobFunction`,\n * `resumeWorkflowExecution`) mirror the public `tailor.v1` RPC vocabulary:\n * `Exec*` is a blocking call that returns the job's result, while `Start*`\n * returns only an execution ID.\n * @example\n * import { workflow } from \"@tailor-platform/sdk/runtime\";\n *\n * const executionId = await workflow.startWorkflow(\"myWorkflow\", { data: \"value\" });\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Specifies the machine user that should be used to execute the workflow.\n * This allows workflows to run with specific authentication context.\n */\nexport interface Invoker {\n /** The namespace where the machine user is defined */\n namespace: string;\n /** The name of the machine user to use for workflow execution */\n machineUserName: string;\n}\n\n/** Options for {@link startWorkflow}. */\nexport interface StartWorkflowOptions {\n /** Optional authentication invoker to specify which machine user should execute the workflow */\n authInvoker?: Invoker;\n}\n\ndeclare const executionPolicyKeyBrand: unique symbol;\n\n/**\n * A concrete runtime key produced by an execution policy instance — either an\n * exact-match policy's `.key`, or a wildcard policy's `.keyFor(suffix)` (see\n * `defineWorkflowExecutionPolicies`). Branded so an arbitrary string that\n * wasn't derived from a declared policy can't be passed as `executionPolicyKey`.\n */\nexport type ExecutionPolicyKey = string & { readonly [executionPolicyKeyBrand]: never };\n\n/** Options for {@link execJobFunction}. */\nexport interface ExecJobFunctionOptions {\n /**\n * Execution policy key matched by the platform against the policies\n * declared with `defineWorkflowExecutionPolicies` in `tailor.config.ts`.\n */\n executionPolicyKey?: ExecutionPolicyKey;\n}\n\n/**\n * Platform API surface for `tailor.workflow`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.workflow`.\n */\nexport interface PlatformWorkflowAPI {\n /**\n * Starts a workflow and returns its execution ID.\n * @param workflowName - Workflow name as defined in tailor.config\n * @param args - Arguments forwarded to the workflow's main job\n * @param options - Optional start options (e.g. `authInvoker`)\n * @returns The execution ID of the started workflow\n */\n startWorkflow(workflowName: string, args?: any, options?: StartWorkflowOptions): Promise<string>;\n\n /**\n * Resumes a failed or pending-retry workflow execution and returns its execution ID.\n * @param executionId - The execution to resume\n * @returns The execution ID of the resumed workflow\n */\n resumeWorkflowExecution(executionId: string): Promise<string>;\n\n /**\n * Executes a job function and returns its result via durable suspend/replay.\n *\n * Canonical name under the platform verb convention: `Exec*` blocks and\n * returns the job's result, while `Start*` returns only an execution ID.\n * @param jobName - Job name as defined in the workflow\n * @param args - Arguments forwarded to the job\n * @param options - Optional execution options (e.g. `executionPolicyKey`)\n * @returns The job's return value\n */\n execJobFunction(jobName: string, args?: any, options?: ExecJobFunctionOptions): any;\n\n /**\n * Suspends the current workflow execution and waits for an external signal to resume.\n * @param key - Wait point key\n * @param payload - Optional payload to record with the wait point\n * @returns The payload supplied by the corresponding `resolve` call\n */\n wait(key: string, payload?: any): any;\n\n /**\n * Resolves a waiting workflow execution, causing it to resume.\n * @param executionId - The execution to resume\n * @param key - Wait point key to resolve\n * @param callback - Callback receiving the wait payload; its return value is forwarded to `wait`\n * @returns A promise that resolves once the resolve has been recorded\n */\n resolve(executionId: string, key: string, callback: (waitPayload: any) => any): Promise<void>;\n}\n\nconst api = (): PlatformWorkflowAPI =>\n (globalThis as unknown as { tailor: { workflow: PlatformWorkflowAPI } }).tailor.workflow;\n\n/**\n * See {@link PlatformWorkflowAPI.startWorkflow}.\n * @param args - Forwarded to {@link PlatformWorkflowAPI.startWorkflow}\n * @returns The execution ID of the started workflow\n */\nconst startWorkflow: PlatformWorkflowAPI[\"startWorkflow\"] = (...args) =>\n api().startWorkflow(...args);\n\n/**\n * See {@link PlatformWorkflowAPI.resumeWorkflowExecution}.\n * @param args - Forwarded to {@link PlatformWorkflowAPI.resumeWorkflowExecution}\n * @returns The execution ID of the resumed workflow\n */\nconst resumeWorkflowExecution: PlatformWorkflowAPI[\"resumeWorkflowExecution\"] = (...args) =>\n api().resumeWorkflowExecution(...args);\n\n/**\n * See {@link PlatformWorkflowAPI.execJobFunction}.\n * @param args - Forwarded to {@link PlatformWorkflowAPI.execJobFunction}\n * @returns The job's return value\n */\nconst execJobFunction: PlatformWorkflowAPI[\"execJobFunction\"] = (...args) =>\n api().execJobFunction(...args);\n\nconst wait: PlatformWorkflowAPI[\"wait\"] = (...args) => api().wait(...args);\n\nconst resolve: PlatformWorkflowAPI[\"resolve\"] = (...args) => api().resolve(...args);\n\n/** Runtime wrapper namespace for `tailor.workflow`. */\nexport const workflow = {\n startWorkflow,\n resumeWorkflowExecution,\n execJobFunction,\n wait,\n resolve,\n} as const satisfies PlatformWorkflowAPI;\n"],"mappings":";AA0GA,MAAM,YACH,WAAwE,OAAO;;;;;;AAOlF,MAAM,iBAAuD,GAAG,SAC9D,IAAI,CAAC,CAAC,cAAc,GAAG,IAAI;;;;;;AAO7B,MAAM,2BAA2E,GAAG,SAClF,IAAI,CAAC,CAAC,wBAAwB,GAAG,IAAI;;;;;;AAOvC,MAAM,mBAA2D,GAAG,SAClE,IAAI,CAAC,CAAC,gBAAgB,GAAG,IAAI;AAE/B,MAAM,QAAqC,GAAG,SAAS,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI;AAEzE,MAAM,WAA2C,GAAG,SAAS,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI;;AAGlF,MAAa,WAAW;CACtB;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"workflow-Bamae_Yc.mjs","names":[],"sources":["../src/runtime/workflow.ts"],"sourcesContent":["/**\n * Workflow utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.workflow` runtime API.\n * At runtime this delegates to `globalThis.tailor.workflow`. Use `mockWorkflow`\n * from `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n *\n * `execJobFunction` blocks until the job finishes and returns its result, while\n * `startWorkflow` returns only an execution ID.\n * @example\n * import { workflow } from \"@tailor-platform/sdk/runtime\";\n *\n * const executionId = await workflow.startWorkflow(\"myWorkflow\", { data: \"value\" });\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Specifies the machine user that should be used to execute the workflow.\n * This allows workflows to run with specific authentication context.\n */\nexport interface Invoker {\n /** The namespace where the machine user is defined */\n namespace: string;\n /** The name of the machine user to use for workflow execution */\n machineUserName: string;\n}\n\n/** Options for {@link startWorkflow}. */\nexport interface StartWorkflowOptions {\n /** Optional authentication invoker to specify which machine user should execute the workflow */\n authInvoker?: Invoker;\n}\n\ndeclare const executionPolicyKeyBrand: unique symbol;\n\n/**\n * A concrete runtime key produced by an execution policy instance — either an\n * exact-match policy's `.key`, or a wildcard policy's `.keyFor(suffix)` (see\n * `defineWorkflowExecutionPolicies`). Branded so an arbitrary string that\n * wasn't derived from a declared policy can't be passed as `executionPolicyKey`.\n */\nexport type ExecutionPolicyKey = string & { readonly [executionPolicyKeyBrand]: never };\n\n/** Options for {@link execJobFunction}. */\nexport interface ExecJobFunctionOptions {\n /**\n * Execution policy key matched by the platform against the policies\n * declared with `defineWorkflowExecutionPolicies` in `tailor.config.ts`.\n */\n executionPolicyKey?: ExecutionPolicyKey;\n}\n\n/**\n * Platform API surface for `tailor.workflow`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.workflow`.\n */\nexport interface PlatformWorkflowAPI {\n /**\n * Starts a workflow and returns its execution ID.\n * @param workflowName - Workflow name as defined in tailor.config\n * @param args - Arguments forwarded to the workflow's main job\n * @param options - Optional start options (e.g. `authInvoker`)\n * @returns The execution ID of the started workflow\n */\n startWorkflow(workflowName: string, args?: any, options?: StartWorkflowOptions): Promise<string>;\n\n /**\n * Resumes a failed or pending-retry workflow execution and returns its execution ID.\n * @param executionId - The execution to resume\n * @returns The execution ID of the resumed workflow\n */\n resumeWorkflowExecution(executionId: string): Promise<string>;\n\n /**\n * Executes a job function and returns its result via durable suspend/replay.\n * @param jobName - Job name as defined in the workflow\n * @param args - Arguments forwarded to the job\n * @param options - Optional execution options (e.g. `executionPolicyKey`)\n * @returns The job's return value\n */\n execJobFunction(jobName: string, args?: any, options?: ExecJobFunctionOptions): any;\n\n /**\n * Suspends the current workflow execution and waits for an external signal to resume.\n * @param key - Wait point key\n * @param payload - Optional payload to record with the wait point\n * @returns The payload supplied by the corresponding `resolve` call\n */\n wait(key: string, payload?: any): any;\n\n /**\n * Resolves a waiting workflow execution, causing it to resume.\n * @param executionId - The execution to resume\n * @param key - Wait point key to resolve\n * @param callback - Callback receiving the wait payload; its return value is forwarded to `wait`\n * @returns A promise that resolves once the resolve has been recorded\n */\n resolve(executionId: string, key: string, callback: (waitPayload: any) => any): Promise<void>;\n}\n\nconst api = (): PlatformWorkflowAPI =>\n (globalThis as unknown as { tailor: { workflow: PlatformWorkflowAPI } }).tailor.workflow;\n\n/**\n * See {@link PlatformWorkflowAPI.startWorkflow}.\n * @param args - Forwarded to {@link PlatformWorkflowAPI.startWorkflow}\n * @returns The execution ID of the started workflow\n */\nconst startWorkflow: PlatformWorkflowAPI[\"startWorkflow\"] = (...args) =>\n api().startWorkflow(...args);\n\n/**\n * See {@link PlatformWorkflowAPI.resumeWorkflowExecution}.\n * @param args - Forwarded to {@link PlatformWorkflowAPI.resumeWorkflowExecution}\n * @returns The execution ID of the resumed workflow\n */\nconst resumeWorkflowExecution: PlatformWorkflowAPI[\"resumeWorkflowExecution\"] = (...args) =>\n api().resumeWorkflowExecution(...args);\n\n/**\n * See {@link PlatformWorkflowAPI.execJobFunction}.\n * @param args - Forwarded to {@link PlatformWorkflowAPI.execJobFunction}\n * @returns The job's return value\n */\nconst execJobFunction: PlatformWorkflowAPI[\"execJobFunction\"] = (...args) =>\n api().execJobFunction(...args);\n\nconst wait: PlatformWorkflowAPI[\"wait\"] = (...args) => api().wait(...args);\n\nconst resolve: PlatformWorkflowAPI[\"resolve\"] = (...args) => api().resolve(...args);\n\n/** Runtime wrapper namespace for `tailor.workflow`. */\nexport const workflow = {\n startWorkflow,\n resumeWorkflowExecution,\n execJobFunction,\n wait,\n resolve,\n} as const satisfies PlatformWorkflowAPI;\n"],"mappings":";AAqGA,MAAM,YACH,WAAwE,OAAO;;;;;;AAOlF,MAAM,iBAAuD,GAAG,SAC9D,IAAI,CAAC,CAAC,cAAc,GAAG,IAAI;;;;;;AAO7B,MAAM,2BAA2E,GAAG,SAClF,IAAI,CAAC,CAAC,wBAAwB,GAAG,IAAI;;;;;;AAOvC,MAAM,mBAA2D,GAAG,SAClE,IAAI,CAAC,CAAC,gBAAgB,GAAG,IAAI;AAE/B,MAAM,QAAqC,GAAG,SAAS,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI;AAEzE,MAAM,WAA2C,GAAG,SAAS,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI;;AAGlF,MAAa,WAAW;CACtB;CACA;CACA;CACA;CACA;AACF"}
@@ -69,6 +69,7 @@ export default defineConfig({
69
69
  resolver: {
70
70
  "my-resolver": {
71
71
  files: ["resolver/**/*.ts"],
72
+ defaultPermission: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
72
73
  },
73
74
  },
74
75
  executor: {
@@ -84,6 +85,8 @@ export default defineConfig({
84
85
 
85
86
  **ignores**: Glob patterns to exclude files. Optional. By default, `**/*.test.ts` and `**/*.spec.ts` are automatically ignored. If you explicitly specify `ignores`, the default patterns will not be applied. Use `ignores: []` to include all files including test files.
86
87
 
88
+ **defaultPermission** (resolver namespaces only): Access requirement applied to every resolver in the namespace that declares no `permission` of its own. Optional, and takes the same values as a resolver's own `permission`. See [Namespace-wide default](./services/resolver.md#namespace-wide-default-defaultpermission).
89
+
87
90
  **Pattern resolution**: `files` and `ignores` patterns are resolved relative to the directory of the `tailor.config.ts` file that declares them, not the directory you run the command from. This matters when deploying [multiple configs](./cli/application.md#deploy) together — each config's patterns only match files under its own directory. If a config's _relative_ patterns match nothing under its own directory, the SDK falls back to resolving them from the directory you ran the command from and logs a warning (this fallback doesn't apply to already-absolute patterns, since their resolution can't change). Update such patterns to be relative to the config's own directory — this fallback will be removed in v2.
88
91
 
89
92
  ### Bundling
@@ -97,7 +97,7 @@ npx tailor-sdk-skills
97
97
  After:
98
98
 
99
99
  ```sh
100
- tailor skills add
100
+ npx @tailor-platform/sdk skills add
101
101
  ```
102
102
 
103
103
  <details>
@@ -107,7 +107,10 @@ tailor skills add
107
107
  The standalone tailor-sdk-skills binary is removed in v2; call the skills add
108
108
  subcommand on the main tailor CLI instead. Replace any remaining
109
109
  tailor-sdk-skills invocations the codemod did not rewrite with
110
- `tailor skills add`.
110
+ `tailor skills add`, or `npx @tailor-platform/sdk skills add` when the
111
+ invocation runs through a package runner (npx, bunx, pnpm/yarn dlx, npm exec)
112
+ — those resolve a package name, and `npx tailor` reaches an unrelated
113
+ `tailor` package on npm.
111
114
  ```
112
115
 
113
116
  </details>
@@ -1401,7 +1404,7 @@ CLI plugin (@tailor-platform/sdk-plugin-seed) replaces it:
1401
1404
  typically fork the runner and await a hand-rolled Promise around
1402
1405
  `child.on("close", ...)`). The plugin is a CLI-dispatched binary rather
1403
1406
  than a forkable JS module, so call it synchronously instead —
1404
- `execSync("npx tailor seed apply", { env, stdio: "inherit" })` — keeping
1407
+ `execSync("npx @tailor-platform/sdk seed apply", { env, stdio: "inherit" })` — keeping
1405
1408
  the original `env` and `stdio` forwarding, and unwind the surrounding
1406
1409
  Promise wrapper (drop the now-unused `await`, and the `async` keyword when
1407
1410
  nothing else in the function awaits). Note that `execSync` throws on a
@@ -33,13 +33,13 @@ cd example-app
33
33
  Before deploying your app, you need to create a workspace:
34
34
 
35
35
  ```bash
36
- npx tailor login
37
- npx tailor workspace create --name <workspace-name> --region <workspace-region>
38
- npx tailor workspace list
36
+ npx @tailor-platform/sdk login
37
+ npx @tailor-platform/sdk workspace create --name <workspace-name> --region <workspace-region>
38
+ npx @tailor-platform/sdk workspace list
39
39
 
40
40
  # Or with Bun:
41
- # bunx tailor login
42
- # bunx tailor workspace create --name <workspace-name> --region <workspace-region>
41
+ # bun tailor login
42
+ # bun tailor workspace create --name <workspace-name> --region <workspace-region>
43
43
 
44
44
  # OR
45
45
  # Create a new workspace using Tailor Platform Console
@@ -406,6 +406,38 @@ Besides a policy array, `permission` also accepts:
406
406
 
407
407
  This check is based on `context.user`, the original caller, so it still applies even when `authInvoker` swaps in a machine user for database access.
408
408
 
409
+ ### Namespace-wide default (`defaultPermission`)
410
+
411
+ Declaring `permission` on every resolver is the only way to close a whole namespace, and one file that forgets it is enough to leave an opening. Declare `defaultPermission` on the resolver namespace in your config instead, and it applies to every resolver in that namespace:
412
+
413
+ ```typescript
414
+ export default defineConfig({
415
+ name: "my-app",
416
+ resolver: {
417
+ "main-resolver": {
418
+ files: ["./src/resolver/*.ts"],
419
+ defaultPermission: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
420
+ },
421
+ },
422
+ });
423
+ ```
424
+
425
+ `defaultPermission` takes the same values as a resolver's own `permission`, including `"allowAnonymous"` — use that to record that a namespace is public by design rather than by oversight.
426
+
427
+ A resolver's own `permission` **replaces** the namespace default rather than adding to it, so a single resolver opts out of a namespace-wide requirement explicitly:
428
+
429
+ ```typescript
430
+ export default createResolver({
431
+ name: "healthCheck",
432
+ operation: "query",
433
+ permission: "allowAnonymous", // reachable even though the namespace requires a login
434
+ output: t.string(),
435
+ body: () => "ok",
436
+ });
437
+ ```
438
+
439
+ When a namespace declares no `defaultPermission` and some of its resolvers declare no `permission` either, `generate` and `deploy` warn that those resolvers are reachable by anonymous callers. Declaring either one silences the warning.
440
+
409
441
  ## Authentication
410
442
 
411
443
  Specify an `invoker` to execute the resolver with machine user credentials. Pass the machine user name as a plain string — it is type-narrowed to the names you defined in your auth config:
package/docs/testing.md CHANGED
@@ -59,7 +59,7 @@ export default defineConfig({
59
59
 
60
60
  1. **Node.js module blocking** — `import { randomBytes } from "node:crypto"` in production code throws an error with a suggestion for the Web Standard API alternative (`globalThis.crypto`). Test files (`*.test.ts`, `*.spec.ts`) are exempt.
61
61
  2. **Node.js globals removal** — Only globals available in the platform runtime are kept (whitelist). `Buffer`, `global`, `setImmediate`, `__dirname`, `__filename`, `performance`, and others are removed.
62
- 3. **Platform API mocks** — the platform error classes (`TailorErrors`, `TailorErrorMessage`, `TailorDBFileError`) and `tailor.context` are always available. The other namespaces (`tailordb.Client`, `tailor.workflow`, `tailor.secretmanager`, …) are mocked when you acquire the corresponding `mockX()` — see below.
62
+ 3. **Platform API mocks** — the platform error classes (`TailorErrors`, `TailorDBFileError`) and `tailor.context` are always available. The other namespaces (`tailordb.Client`, `tailor.workflow`, `tailor.secretmanager`, …) are mocked when you acquire the corresponding `mockX()` — see below.
63
63
 
64
64
  ### Acquiring mocks with `using`
65
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -168,17 +168,17 @@
168
168
  "@secretlint/secretlint-rule-preset-recommend": "13.0.4",
169
169
  "@standard-schema/spec": "1.1.0",
170
170
  "@tailor-platform/function-kysely-tailordb": "0.1.3",
171
- "@toiroakr/lines-db": "0.10.1",
171
+ "@toiroakr/lines-db": "0.11.0",
172
172
  "@toiroakr/read-multiline": "0.4.1",
173
173
  "@urql/core": "6.0.3",
174
- "amaro": "1.1.10",
174
+ "amaro": "1.1.11",
175
175
  "chalk": "5.6.2",
176
176
  "confbox": "0.2.4",
177
177
  "date-fns": "4.4.0",
178
178
  "es-toolkit": "1.50.0",
179
179
  "find-up-simple": "1.0.1",
180
180
  "get-east-asian-width": "1.6.0",
181
- "get-tsconfig": "4.14.0",
181
+ "get-tsconfig": "4.14.1",
182
182
  "globals": "17.8.0",
183
183
  "graphql": "17.0.2",
184
184
  "inflection": "3.0.2",
@@ -207,7 +207,7 @@
207
207
  "@types/semver": "7.7.1",
208
208
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
209
209
  "@vitest/coverage-v8": "4.1.10",
210
- "eslint-plugin-zod": "4.7.0",
210
+ "eslint-plugin-zod": "4.9.0",
211
211
  "oxfmt": "0.61.0",
212
212
  "oxlint": "1.76.0",
213
213
  "oxlint-tsgolint": "7.0.2001",