@tailor-platform/sdk 1.35.1 → 1.36.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 (43) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/application-BB5TqXWY.mjs +4 -0
  3. package/dist/{application-BnJRroGX.mjs → application-BwboBFcU.mjs} +102 -17
  4. package/dist/application-BwboBFcU.mjs.map +1 -0
  5. package/dist/cli/index.mjs +303 -17
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/cli/lib.d.mts +190 -6
  8. package/dist/cli/lib.mjs +3 -3
  9. package/dist/{client-BmQP4kKS.mjs → client-B6icVEv4.mjs} +1 -1
  10. package/dist/{client-CA2NM_4R.mjs → client-CN15WgW2.mjs} +25 -8
  11. package/dist/client-CN15WgW2.mjs.map +1 -0
  12. package/dist/configure/index.d.mts +5 -5
  13. package/dist/configure/index.mjs +38 -9
  14. package/dist/configure/index.mjs.map +1 -1
  15. package/dist/{crash-report-Bd2T8BhU.mjs → crash-report-CB1UtT3O.mjs} +1 -1
  16. package/dist/{crash-report-CPkI2-cp.mjs → crash-report-CdxPj_SW.mjs} +2 -2
  17. package/dist/{crash-report-CPkI2-cp.mjs.map → crash-report-CdxPj_SW.mjs.map} +1 -1
  18. package/dist/{env-MSlwZt8l.d.mts → env-_ce3IYbl.d.mts} +2 -2
  19. package/dist/{index-B1Fgxi8D.d.mts → index-C7vIBAg8.d.mts} +2 -2
  20. package/dist/{index-wCoQup4y.d.mts → index-CYaunQeL.d.mts} +76 -6
  21. package/dist/{index-D-tMAFVp.d.mts → index-CxSLivW7.d.mts} +2 -2
  22. package/dist/{index-BG7YCyXF.d.mts → index-DDCyefuU.d.mts} +2 -2
  23. package/dist/{index-BBlE_vQF.d.mts → index-DZN1QFLM.d.mts} +2 -2
  24. package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
  25. package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
  26. package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
  27. package/dist/plugin/builtin/seed/index.d.mts +1 -1
  28. package/dist/plugin/index.d.mts +2 -2
  29. package/dist/{plugin-CZaJ3_QR.d.mts → plugin-CiPUxkyN.d.mts} +3 -2
  30. package/dist/{runtime-D4O-RfcH.mjs → runtime-C7RRDaB3.mjs} +230 -22
  31. package/dist/runtime-C7RRDaB3.mjs.map +1 -0
  32. package/dist/utils/test/index.d.mts +2 -2
  33. package/dist/{workflow.generated-IZ3kLjC_.d.mts → workflow.generated-8BeGQsVU.d.mts} +212 -4
  34. package/docs/cli/function.md +2 -2
  35. package/docs/services/idp.md +50 -0
  36. package/docs/services/resolver.md +1 -1
  37. package/docs/services/secret.md +25 -0
  38. package/docs/services/workflow.md +48 -0
  39. package/package.json +9 -8
  40. package/dist/application-BnJRroGX.mjs.map +0 -1
  41. package/dist/application-mGasp_EX.mjs +0 -4
  42. package/dist/client-CA2NM_4R.mjs.map +0 -1
  43. package/dist/runtime-D4O-RfcH.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@tailor-platform/function-types" />
2
- import { U as TailorDBType, rt as TailorField } from "../../plugin-CZaJ3_QR.mjs";
3
- import { et as WORKFLOW_TEST_ENV_KEY, n as output } from "../../index-wCoQup4y.mjs";
2
+ import { U as TailorDBType, rt as TailorField } from "../../plugin-CiPUxkyN.mjs";
3
+ import { n as output, rt as WORKFLOW_TEST_ENV_KEY } from "../../index-CYaunQeL.mjs";
4
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
5
5
 
6
6
  //#region src/utils/test/mock.d.ts
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@tailor-platform/function-types" />
2
- import { Nt as BuiltinIdP, S as TailorDBServiceInput, T as AuthConfig } from "./plugin-CZaJ3_QR.mjs";
2
+ import { Nt as BuiltinIdP, S as TailorDBServiceInput, T as AuthConfig } from "./plugin-CiPUxkyN.mjs";
3
3
 
4
4
  //#region src/types/idp.generated.d.ts
5
5
  /**
@@ -59,6 +59,193 @@ type IdPInput = {
59
59
  emailConfig?: {
60
60
  fromName?: string | undefined;
61
61
  passwordResetSubject?: string | undefined;
62
+ } | undefined; /** Per-operation permission policies for IdP users */
63
+ permission?: {
64
+ create: readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
65
+ user: string;
66
+ } | {
67
+ idpUser: "name" | "id" | "disabled";
68
+ } | {
69
+ oldIdpUser: "name" | "id" | "disabled";
70
+ } | {
71
+ newIdpUser: "name" | "id" | "disabled";
72
+ })[] | readonly (boolean | readonly (string | boolean | readonly string[] | readonly boolean[] | {
73
+ user: string;
74
+ } | {
75
+ idpUser: "name" | "id" | "disabled";
76
+ } | {
77
+ oldIdpUser: "name" | "id" | "disabled";
78
+ } | {
79
+ newIdpUser: "name" | "id" | "disabled";
80
+ })[])[] | {
81
+ conditions: readonly (string | boolean | readonly string[] | readonly boolean[] | {
82
+ user: string;
83
+ } | {
84
+ idpUser: "name" | "id" | "disabled";
85
+ } | {
86
+ oldIdpUser: "name" | "id" | "disabled";
87
+ } | {
88
+ newIdpUser: "name" | "id" | "disabled";
89
+ })[] | readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
90
+ user: string;
91
+ } | {
92
+ idpUser: "name" | "id" | "disabled";
93
+ } | {
94
+ oldIdpUser: "name" | "id" | "disabled";
95
+ } | {
96
+ newIdpUser: "name" | "id" | "disabled";
97
+ })[])[];
98
+ description?: string | undefined;
99
+ permit?: boolean | undefined;
100
+ })[];
101
+ read: readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
102
+ user: string;
103
+ } | {
104
+ idpUser: "name" | "id" | "disabled";
105
+ } | {
106
+ oldIdpUser: "name" | "id" | "disabled";
107
+ } | {
108
+ newIdpUser: "name" | "id" | "disabled";
109
+ })[] | readonly (boolean | readonly (string | boolean | readonly string[] | readonly boolean[] | {
110
+ user: string;
111
+ } | {
112
+ idpUser: "name" | "id" | "disabled";
113
+ } | {
114
+ oldIdpUser: "name" | "id" | "disabled";
115
+ } | {
116
+ newIdpUser: "name" | "id" | "disabled";
117
+ })[])[] | {
118
+ conditions: readonly (string | boolean | readonly string[] | readonly boolean[] | {
119
+ user: string;
120
+ } | {
121
+ idpUser: "name" | "id" | "disabled";
122
+ } | {
123
+ oldIdpUser: "name" | "id" | "disabled";
124
+ } | {
125
+ newIdpUser: "name" | "id" | "disabled";
126
+ })[] | readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
127
+ user: string;
128
+ } | {
129
+ idpUser: "name" | "id" | "disabled";
130
+ } | {
131
+ oldIdpUser: "name" | "id" | "disabled";
132
+ } | {
133
+ newIdpUser: "name" | "id" | "disabled";
134
+ })[])[];
135
+ description?: string | undefined;
136
+ permit?: boolean | undefined;
137
+ })[];
138
+ update: readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
139
+ user: string;
140
+ } | {
141
+ idpUser: "name" | "id" | "disabled";
142
+ } | {
143
+ oldIdpUser: "name" | "id" | "disabled";
144
+ } | {
145
+ newIdpUser: "name" | "id" | "disabled";
146
+ })[] | readonly (boolean | readonly (string | boolean | readonly string[] | readonly boolean[] | {
147
+ user: string;
148
+ } | {
149
+ idpUser: "name" | "id" | "disabled";
150
+ } | {
151
+ oldIdpUser: "name" | "id" | "disabled";
152
+ } | {
153
+ newIdpUser: "name" | "id" | "disabled";
154
+ })[])[] | {
155
+ conditions: readonly (string | boolean | readonly string[] | readonly boolean[] | {
156
+ user: string;
157
+ } | {
158
+ idpUser: "name" | "id" | "disabled";
159
+ } | {
160
+ oldIdpUser: "name" | "id" | "disabled";
161
+ } | {
162
+ newIdpUser: "name" | "id" | "disabled";
163
+ })[] | readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
164
+ user: string;
165
+ } | {
166
+ idpUser: "name" | "id" | "disabled";
167
+ } | {
168
+ oldIdpUser: "name" | "id" | "disabled";
169
+ } | {
170
+ newIdpUser: "name" | "id" | "disabled";
171
+ })[])[];
172
+ description?: string | undefined;
173
+ permit?: boolean | undefined;
174
+ })[];
175
+ delete: readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
176
+ user: string;
177
+ } | {
178
+ idpUser: "name" | "id" | "disabled";
179
+ } | {
180
+ oldIdpUser: "name" | "id" | "disabled";
181
+ } | {
182
+ newIdpUser: "name" | "id" | "disabled";
183
+ })[] | readonly (boolean | readonly (string | boolean | readonly string[] | readonly boolean[] | {
184
+ user: string;
185
+ } | {
186
+ idpUser: "name" | "id" | "disabled";
187
+ } | {
188
+ oldIdpUser: "name" | "id" | "disabled";
189
+ } | {
190
+ newIdpUser: "name" | "id" | "disabled";
191
+ })[])[] | {
192
+ conditions: readonly (string | boolean | readonly string[] | readonly boolean[] | {
193
+ user: string;
194
+ } | {
195
+ idpUser: "name" | "id" | "disabled";
196
+ } | {
197
+ oldIdpUser: "name" | "id" | "disabled";
198
+ } | {
199
+ newIdpUser: "name" | "id" | "disabled";
200
+ })[] | readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
201
+ user: string;
202
+ } | {
203
+ idpUser: "name" | "id" | "disabled";
204
+ } | {
205
+ oldIdpUser: "name" | "id" | "disabled";
206
+ } | {
207
+ newIdpUser: "name" | "id" | "disabled";
208
+ })[])[];
209
+ description?: string | undefined;
210
+ permit?: boolean | undefined;
211
+ })[];
212
+ sendPasswordResetEmail: readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
213
+ user: string;
214
+ } | {
215
+ idpUser: "name" | "id" | "disabled";
216
+ } | {
217
+ oldIdpUser: "name" | "id" | "disabled";
218
+ } | {
219
+ newIdpUser: "name" | "id" | "disabled";
220
+ })[] | readonly (boolean | readonly (string | boolean | readonly string[] | readonly boolean[] | {
221
+ user: string;
222
+ } | {
223
+ idpUser: "name" | "id" | "disabled";
224
+ } | {
225
+ oldIdpUser: "name" | "id" | "disabled";
226
+ } | {
227
+ newIdpUser: "name" | "id" | "disabled";
228
+ })[])[] | {
229
+ conditions: readonly (string | boolean | readonly string[] | readonly boolean[] | {
230
+ user: string;
231
+ } | {
232
+ idpUser: "name" | "id" | "disabled";
233
+ } | {
234
+ oldIdpUser: "name" | "id" | "disabled";
235
+ } | {
236
+ newIdpUser: "name" | "id" | "disabled";
237
+ })[] | readonly (readonly (string | boolean | readonly string[] | readonly boolean[] | {
238
+ user: string;
239
+ } | {
240
+ idpUser: "name" | "id" | "disabled";
241
+ } | {
242
+ oldIdpUser: "name" | "id" | "disabled";
243
+ } | {
244
+ newIdpUser: "name" | "id" | "disabled";
245
+ })[])[];
246
+ description?: string | undefined;
247
+ permit?: boolean | undefined;
248
+ })[];
62
249
  } | undefined;
63
250
  };
64
251
  //#endregion
@@ -77,6 +264,7 @@ type IdPExternalConfig = {
77
264
  };
78
265
  type IdPOwnConfig = Omit<DefinedIdp<string, IdPInput, string>, "provider">;
79
266
  type IdPConfig = IdPOwnConfig | IdPExternalConfig;
267
+ type IdPUserField = "id" | "name" | "disabled";
80
268
  //#endregion
81
269
  //#region src/configure/services/secrets/index.d.ts
82
270
  declare const secretsDefinitionBrand: unique symbol;
@@ -84,8 +272,15 @@ type SecretsDefinitionBrand = {
84
272
  readonly [secretsDefinitionBrand]: true;
85
273
  };
86
274
  type SecretsVaultInput = Record<string, string>;
275
+ type SecretsVaultInputNullish = Record<string, string | undefined | null>;
87
276
  type SecretsInput = Record<string, SecretsVaultInput>;
88
- type DefinedSecrets<T extends SecretsInput> = {
277
+ type SecretsInputNullish = Record<string, SecretsVaultInputNullish>;
278
+ type SecretsOptions = {
279
+ readonly ignoreNullishValues: boolean;
280
+ };
281
+ type DefinedSecrets<T extends SecretsInputNullish> = {
282
+ readonly vaults: T;
283
+ readonly options: SecretsOptions;
89
284
  get<V extends Extract<keyof T, string>, S extends Extract<keyof T[V], string>>(vault: V, secret: S): Promise<string | undefined>;
90
285
  getAll<V extends Extract<keyof T, string>, S extends Extract<keyof T[V], string>>(vault: V, secrets: readonly S[]): Promise<(string | undefined)[]>;
91
286
  } & SecretsDefinitionBrand;
@@ -98,6 +293,19 @@ type SecretsConfig = Omit<ReturnType<typeof defineSecretManager>, "get" | "getAl
98
293
  * @returns Defined secrets with typed runtime access methods
99
294
  */
100
295
  declare function defineSecretManager<const T extends SecretsInput>(config: T): DefinedSecrets<T>;
296
+ /**
297
+ * Define secrets configuration for the Tailor SDK with ignoreNullishValues option.
298
+ * When `ignoreNullishValues` is true, secrets with nullish values are skipped during deploy
299
+ * instead of causing an error. This is useful for CI environments where not all
300
+ * secret values are available.
301
+ * @param config - Secrets configuration mapping vault names to their secrets
302
+ * @param options - Options for secret management behavior
303
+ * @param options.ignoreNullishValues - When true, secrets with nullish values are skipped during deploy
304
+ * @returns Defined secrets with typed runtime access methods
305
+ */
306
+ declare function defineSecretManager<const T extends SecretsInputNullish>(config: T, options: {
307
+ ignoreNullishValues: true;
308
+ }): DefinedSecrets<T>;
101
309
  //#endregion
102
310
  //#region src/types/staticwebsite.generated.d.ts
103
311
  type StaticWebsite = {
@@ -202,5 +410,5 @@ type RetryPolicy = {
202
410
  backoffMultiplier: number;
203
411
  };
204
412
  //#endregion
205
- export { IdPEmailConfig as _, ResolverExternalConfig as a, IdPInput as b, WorkflowServiceConfig as c, defineStaticWebSite as d, SecretsConfig as f, IdpDefinitionBrand as g, IdPExternalConfig as h, ExecutorServiceInput as i, WorkflowServiceInput as l, IdPConfig as m, AppConfig as n, ResolverServiceConfig as o, defineSecretManager as p, ExecutorServiceConfig as r, ResolverServiceInput as s, RetryPolicy as t, StaticWebsiteConfig as u, IdPGqlOperations as v, IdPGqlOperationsInput as y };
206
- //# sourceMappingURL=workflow.generated-IZ3kLjC_.d.mts.map
413
+ export { IdpDefinitionBrand as _, ResolverExternalConfig as a, IdPGqlOperationsInput as b, WorkflowServiceConfig as c, defineStaticWebSite as d, SecretsConfig as f, IdPUserField as g, IdPExternalConfig as h, ExecutorServiceInput as i, WorkflowServiceInput as l, IdPConfig as m, AppConfig as n, ResolverServiceConfig as o, defineSecretManager as p, ExecutorServiceConfig as r, ResolverServiceInput as s, RetryPolicy as t, StaticWebsiteConfig as u, IdPEmailConfig as v, IdPInput as x, IdPGqlOperations as y };
414
+ //# sourceMappingURL=workflow.generated-8BeGQsVU.d.mts.map
@@ -152,7 +152,7 @@ tailor-sdk function test-run [options] <file>
152
152
  **Run a resolver with input arguments**
153
153
 
154
154
  ```bash
155
- $ tailor-sdk function test-run resolvers/add.ts --arg '{"input":{"a":1,"b":2}}'
155
+ $ tailor-sdk function test-run resolvers/add.ts --arg '{"a":1,"b":2}'
156
156
  ```
157
157
 
158
158
  **Run a specific workflow job by name**
@@ -164,7 +164,7 @@ $ tailor-sdk function test-run workflows/sample.ts --name validate-order
164
164
  **Run a pre-bundled .js file directly**
165
165
 
166
166
  ```bash
167
- $ tailor-sdk function test-run build/resolvers/add.js --arg '{"input":{"a":1,"b":2}}'
167
+ $ tailor-sdk function test-run build/resolvers/add.js --arg '{"a":1,"b":2}'
168
168
  ```
169
169
 
170
170
  <!-- politty:command:function test-run:examples:end -->
@@ -99,6 +99,56 @@ defineIdp("my-idp", {
99
99
 
100
100
  **Validation:** Each field must be 200 characters or less and must not contain newline characters.
101
101
 
102
+ ### permission
103
+
104
+ Per-operation permission policies for IdP user management. Controls who can create, read, update, delete users, and send password reset emails.
105
+
106
+ ```typescript
107
+ defineIdp("my-idp", {
108
+ authorization: "loggedIn",
109
+ clients: ["my-client"],
110
+ permission: {
111
+ create: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
112
+ read: [{ conditions: [[{ user: "_loggedIn" }, "=", true]], permit: true }],
113
+ update: [
114
+ { conditions: [[{ newIdpUser: "name" }, "!=", { oldIdpUser: "name" }]], permit: true },
115
+ ],
116
+ delete: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
117
+ sendPasswordResetEmail: [{ conditions: [], permit: true }],
118
+ },
119
+ });
120
+ ```
121
+
122
+ **Operations:**
123
+
124
+ - `create` - Controls who can create IdP users
125
+ - `read` - Controls who can read IdP users
126
+ - `update` - Controls who can update IdP users
127
+ - `delete` - Controls who can delete IdP users
128
+ - `sendPasswordResetEmail` - Controls who can send password reset emails
129
+
130
+ **Operands:**
131
+
132
+ - `{ user: "field" }` - Authenticated user's attribute
133
+ - `{ idpUser: "field" }` - IdP user field (for create/read/delete). Allowed values: `"id"`, `"name"`, `"disabled"`
134
+ - `{ oldIdpUser: "field" }` - Previous IdP user field value (for update only). Allowed values: `"id"`, `"name"`, `"disabled"`
135
+ - `{ newIdpUser: "field" }` - New IdP user field value (for update only). Allowed values: `"id"`, `"name"`, `"disabled"`
136
+ - Literal values: `string`, `boolean`, `string[]`, `boolean[]`
137
+
138
+ **Operators:** `"="`, `"!="`, `"in"`, `"not in"`
139
+
140
+ **Helper:** `unsafeAllowAllIdPPermission` grants full access without conditions. Intended only for development and testing.
141
+
142
+ ```typescript
143
+ import { unsafeAllowAllIdPPermission } from "@tailor-platform/sdk";
144
+
145
+ defineIdp("my-idp", {
146
+ authorization: "loggedIn",
147
+ clients: ["my-client"],
148
+ permission: unsafeAllowAllIdPPermission,
149
+ });
150
+ ```
151
+
102
152
  ## Using idp.provider()
103
153
 
104
154
  The `idp.provider()` method creates a type-safe reference to the IdP for use in Auth configuration. The client name is validated at compile time against the clients defined in the IdP.
@@ -13,7 +13,7 @@ Resolvers provide:
13
13
 
14
14
  ## Comparison with Tailor Platform Pipeline Resolver
15
15
 
16
- The SDK's Resolver is a simplified version of Tailor Platform's [Pipeline Resolver](https://docs.tailor.tech/guides/pipeline).
16
+ The SDK's Resolver is a simplified version of Tailor Platform's [Pipeline Resolver](https://docs.tailor.tech/guides/resolver).
17
17
 
18
18
  | Pipeline Resolver | SDK Resolver |
19
19
  | ---------------------------------------- | --------------------------------- |
@@ -64,6 +64,31 @@ export default defineConfig({
64
64
 
65
65
  The exported `secrets` object provides type-safe `get()` and `getAll()` methods for runtime access from resolvers, executors, and workflows.
66
66
 
67
+ ### Skipping Secrets with Missing Values
68
+
69
+ In CI environments, you may not have all secret values available (e.g., secrets are already set on the platform and you don't want to duplicate them in CI environment variables). Use the `ignoreNullishValues` option to skip secrets whose values are `undefined` or `null`:
70
+
71
+ ```typescript
72
+ export const secrets = defineSecretManager(
73
+ {
74
+ "api-keys": {
75
+ "stripe-secret-key": process.env.STRIPE_SECRET_KEY,
76
+ "sendgrid-api-key": process.env.SENDGRID_API_KEY,
77
+ },
78
+ },
79
+ { ignoreNullishValues: true },
80
+ );
81
+ ```
82
+
83
+ When `ignoreNullishValues: true`:
84
+
85
+ - Secrets with a string value are created or updated as normal
86
+ - Secrets with `undefined` or `null` values are **skipped** — they are not created, updated, or deleted
87
+ - Skipped secrets are shown in the deploy output for visibility
88
+ - Secrets removed from the config entirely are still deleted (orphan cleanup)
89
+
90
+ This allows you to set secret values once (e.g., via local `tailor-sdk apply` or the CLI) and then deploy from CI without needing the actual values in CI environment variables.
91
+
67
92
  ## Using Secrets
68
93
 
69
94
  ### Runtime Access with `get()` / `getAll()`
@@ -115,6 +115,54 @@ export const mainJob = createWorkflowJob({
115
115
 
116
116
  **Important:** On the Tailor runtime, job triggers are executed synchronously. This means `Promise.all([jobA.trigger(), jobB.trigger()])` will not run jobs in parallel.
117
117
 
118
+ ### Deterministic Execution Requirement
119
+
120
+ Workflow jobs use a **suspend/resume execution model**. When a job calls `.trigger()`, the runtime suspends the current job, executes the triggered job, and then **re-executes the calling job from the beginning** with cached results from previous triggers.
121
+
122
+ This means that **job code must be deterministic** — every re-execution must produce the same sequence of `.trigger()` calls with the same arguments in the same order.
123
+
124
+ Using `.trigger()` inside a loop works correctly, as long as the loop is deterministic:
125
+
126
+ ```typescript
127
+ // ✅ OK: deterministic loop — same calls in the same order on every execution
128
+ const regions = ["us", "eu", "ap"];
129
+ for (const region of regions) {
130
+ const result = await fetchData.trigger({ region });
131
+ results.push(result);
132
+ }
133
+ ```
134
+
135
+ ```typescript
136
+ // ❌ Bad: non-deterministic — argument changes between executions
137
+ await processJob.trigger({ timestamp: Date.now() });
138
+
139
+ // ✅ OK: call Date.now() in separated job
140
+ const timestamp = await timestampJob.trigger();
141
+ await processJob.trigger({ timestamp });
142
+ ```
143
+
144
+ ```typescript
145
+ // ❌ Bad: non-deterministic — external data may change between executions
146
+ const items = await fetch("https://api.example.com/items").then((r) => r.json());
147
+ for (const item of items) {
148
+ await processItem.trigger({ id: item.id });
149
+ }
150
+
151
+ // ✅ OK: call fetch("https://api.example.com/items").then((r) => r.json()); in separated job
152
+ const items = await fetchItemsJob.trigger();
153
+ for (const item of items) {
154
+ await processItem.trigger({ id: item.id });
155
+ }
156
+ ```
157
+
158
+ If the runtime detects that a `.trigger()` call at the same position has different arguments than the previous execution, it will throw an **argument hash mismatch error**.
159
+
160
+ **Guidelines:**
161
+
162
+ - Do not use non-deterministic values (random numbers, timestamps, external API responses) as `.trigger()` arguments.
163
+ - Do not use conditions that may change between executions to decide whether to call `.trigger()`.
164
+ - Any data that varies between executions should be fetched **inside the triggered job**, not passed as an argument from the calling job.
165
+
118
166
  ## Workflow Definition
119
167
 
120
168
  Define a workflow using `createWorkflow` and export it as default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "1.35.1",
3
+ "version": "1.36.0",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -81,8 +81,9 @@
81
81
  "@bufbuild/protobuf": "2.11.0",
82
82
  "@connectrpc/connect": "2.1.1",
83
83
  "@connectrpc/connect-node": "2.1.1",
84
- "@inquirer/core": "11.1.7",
85
- "@inquirer/prompts": "8.3.2",
84
+ "@inquirer/core": "11.1.8",
85
+ "@inquirer/prompts": "8.4.0",
86
+ "@jridgewell/trace-mapping": "0.3.31",
86
87
  "@liam-hq/cli": "0.7.24",
87
88
  "@napi-rs/keyring": "1.2.0",
88
89
  "@opentelemetry/api": "1.9.1",
@@ -110,7 +111,7 @@
110
111
  "multiline-ts": "4.0.1",
111
112
  "open": "11.0.0",
112
113
  "ora": "9.3.0",
113
- "oxc-parser": "0.121.0",
114
+ "oxc-parser": "0.124.0",
114
115
  "p-limit": "7.3.0",
115
116
  "pathe": "2.0.3",
116
117
  "pgsql-ast-parser": "12.0.2",
@@ -134,13 +135,13 @@
134
135
  "@types/mime-types": "3.0.1",
135
136
  "@types/node": "24.12.2",
136
137
  "@types/semver": "7.7.1",
137
- "@typescript/native-preview": "7.0.0-dev.20260404.1",
138
+ "@typescript/native-preview": "7.0.0-dev.20260406.1",
138
139
  "@vitest/coverage-v8": "4.1.2",
139
140
  "eslint": "10.2.0",
140
141
  "eslint-plugin-jsdoc": "62.9.0",
141
- "eslint-plugin-oxlint": "1.58.0",
142
- "oxfmt": "0.42.0",
143
- "oxlint": "1.58.0",
142
+ "eslint-plugin-oxlint": "1.59.0",
143
+ "oxfmt": "0.44.0",
144
+ "oxlint": "1.59.0",
144
145
  "oxlint-tsgolint": "0.20.0",
145
146
  "sonda": "0.11.1",
146
147
  "tsdown": "0.21.7",