@tailor-platform/sdk 1.35.2 → 1.37.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 (79) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/application-ILhZq_oW.mjs +4 -0
  3. package/dist/{application-BnJRroGX.mjs → application-qRGMV8Tr.mjs} +150 -35
  4. package/dist/application-qRGMV8Tr.mjs.map +1 -0
  5. package/dist/{brand-0SscafcY.mjs → brand-D-d15jx3.mjs} +1 -1
  6. package/dist/{brand-0SscafcY.mjs.map → brand-D-d15jx3.mjs.map} +1 -1
  7. package/dist/cli/index.mjs +247 -12
  8. package/dist/cli/index.mjs.map +1 -1
  9. package/dist/cli/lib.d.mts +190 -6
  10. package/dist/cli/lib.mjs +7 -7
  11. package/dist/{client-BmQP4kKS.mjs → client-424n_3T9.mjs} +1 -1
  12. package/dist/{client-CA2NM_4R.mjs → client-DllDLYmZ.mjs} +28 -11
  13. package/dist/client-DllDLYmZ.mjs.map +1 -0
  14. package/dist/configure/index.d.mts +5 -4
  15. package/dist/configure/index.mjs +42 -23
  16. package/dist/configure/index.mjs.map +1 -1
  17. package/dist/{crash-report-CPkI2-cp.mjs → crash-report-CDQ2JvgR.mjs} +4 -4
  18. package/dist/{crash-report-CPkI2-cp.mjs.map → crash-report-CDQ2JvgR.mjs.map} +1 -1
  19. package/dist/{crash-report-Bd2T8BhU.mjs → crash-report-aHnky_xH.mjs} +1 -1
  20. package/dist/{enum-constants-DI85-fPE.mjs → enum-constants-Dx82rSjf.mjs} +1 -1
  21. package/dist/{enum-constants-DI85-fPE.mjs.map → enum-constants-Dx82rSjf.mjs.map} +1 -1
  22. package/dist/env-04IQXqsl.d.mts +30 -0
  23. package/dist/{file-utils-C4rXlOVt.mjs → file-utils-DeWpvq3T.mjs} +1 -1
  24. package/dist/{file-utils-C4rXlOVt.mjs.map → file-utils-DeWpvq3T.mjs.map} +1 -1
  25. package/dist/{index-DTJkkO-t.d.mts → index-BUT18Kak.d.mts} +2 -2
  26. package/dist/{index--9iVDOXn.d.mts → index-BVJQLjyN.d.mts} +98 -12
  27. package/dist/{index-D4pBPp65.d.mts → index-C3kcXHXJ.d.mts} +2 -2
  28. package/dist/{index-niQ9Qblw.d.mts → index-CeS4FA9o.d.mts} +2 -2
  29. package/dist/{index-qVqjEYnr.d.mts → index-DnIg_LfT.d.mts} +2 -2
  30. package/dist/{interceptor-f7slMkCC.mjs → interceptor-dSNiQq71.mjs} +1 -1
  31. package/dist/{interceptor-f7slMkCC.mjs.map → interceptor-dSNiQq71.mjs.map} +1 -1
  32. package/dist/{job-CPKYCk_e.mjs → job-DkAklmE4.mjs} +2 -2
  33. package/dist/{job-CPKYCk_e.mjs.map → job-DkAklmE4.mjs.map} +1 -1
  34. package/dist/{kysely-type-DtnNdHn3.mjs → kysely-type-CwtvQuxh.mjs} +1 -1
  35. package/dist/{kysely-type-DtnNdHn3.mjs.map → kysely-type-CwtvQuxh.mjs.map} +1 -1
  36. package/dist/{logger-qz-Y4sBV.mjs → logger-C8qBDCKO.mjs} +1 -1
  37. package/dist/{logger-qz-Y4sBV.mjs.map → logger-C8qBDCKO.mjs.map} +1 -1
  38. package/dist/package-json--6dmp6-h.mjs +4 -0
  39. package/dist/{package-json-CfUqjJaQ.mjs → package-json-BHViVisJ.mjs} +1 -1
  40. package/dist/{package-json-CfUqjJaQ.mjs.map → package-json-BHViVisJ.mjs.map} +1 -1
  41. package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
  42. package/dist/plugin/builtin/enum-constants/index.mjs +1 -1
  43. package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
  44. package/dist/plugin/builtin/file-utils/index.mjs +1 -1
  45. package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
  46. package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
  47. package/dist/plugin/builtin/seed/index.d.mts +1 -1
  48. package/dist/plugin/builtin/seed/index.mjs +1 -1
  49. package/dist/plugin/index.d.mts +2 -1
  50. package/dist/{plugin-D8hKE6rZ.d.mts → plugin-D6P4g_2L.d.mts} +17 -36
  51. package/dist/{runtime-D4O-RfcH.mjs → runtime-D9ejnCm6.mjs} +788 -109
  52. package/dist/runtime-D9ejnCm6.mjs.map +1 -0
  53. package/dist/{schema-D27cW0Ca.mjs → schema-CnwUqPyM.mjs} +4 -361
  54. package/dist/schema-CnwUqPyM.mjs.map +1 -0
  55. package/dist/{seed-BZIFDG27.mjs → seed-DrbB1VXd.mjs} +1 -1
  56. package/dist/{seed-BZIFDG27.mjs.map → seed-DrbB1VXd.mjs.map} +1 -1
  57. package/dist/telemetry-4IOPW6wE.mjs +4 -0
  58. package/dist/{telemetry-CREcGK8y.mjs → telemetry-DwHuiNiR.mjs} +2 -2
  59. package/dist/{telemetry-CREcGK8y.mjs.map → telemetry-DwHuiNiR.mjs.map} +1 -1
  60. package/dist/types-B9ZMosul.mjs +372 -0
  61. package/dist/types-B9ZMosul.mjs.map +1 -0
  62. package/dist/types-C45jRrCM.mjs +4 -0
  63. package/dist/utils/test/index.d.mts +2 -2
  64. package/dist/utils/test/index.mjs +1 -1
  65. package/dist/{workflow.generated-DMt8PNVd.d.mts → workflow.generated-Bj_DVqGh.d.mts} +212 -4
  66. package/docs/services/auth.md +6 -5
  67. package/docs/services/executor.md +5 -12
  68. package/docs/services/idp.md +50 -0
  69. package/docs/services/resolver.md +6 -13
  70. package/docs/services/secret.md +25 -0
  71. package/docs/services/workflow.md +4 -3
  72. package/package.json +7 -6
  73. package/dist/application-BnJRroGX.mjs.map +0 -1
  74. package/dist/application-mGasp_EX.mjs +0 -4
  75. package/dist/client-CA2NM_4R.mjs.map +0 -1
  76. package/dist/package-json-D5Km1jjt.mjs +0 -4
  77. package/dist/runtime-D4O-RfcH.mjs.map +0 -1
  78. package/dist/schema-D27cW0Ca.mjs.map +0 -1
  79. package/dist/telemetry-C508zIi1.mjs +0 -4
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@tailor-platform/function-types" />
2
- import { Pt as BuiltinIdP, S as TailorDBServiceInput, T as AuthConfig } from "./plugin-D8hKE6rZ.mjs";
2
+ import { Nt as BuiltinIdP, S as TailorDBServiceInput, T as AuthConfig } from "./plugin-D6P4g_2L.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-DMt8PNVd.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-Bj_DVqGh.d.mts.map
@@ -256,9 +256,9 @@ Get a machine user token using the CLI:
256
256
  tailor-sdk machineuser token <name>
257
257
  ```
258
258
 
259
- ### Using auth.invoker()
259
+ ### Specifying a machine user invoker
260
260
 
261
- The `auth.invoker()` method creates a type-safe reference to a machine user for use in workflow triggers. This specifies which machine user's permissions should be used when executing the workflow.
261
+ Resolvers, executors, and `workflow.trigger()` accept an `authInvoker` option that chooses which machine user runs the operation. Pass the machine user name as a plain string it is type-narrowed to the names you registered in `machineUsers`.
262
262
 
263
263
  ```typescript
264
264
  // tailor.config.ts
@@ -275,7 +275,6 @@ export const auth = defineAuth("my-auth", {
275
275
  ```typescript
276
276
  // resolvers/trigger-workflow.ts
277
277
  import { createResolver, t } from "@tailor-platform/sdk";
278
- import { auth } from "../tailor.config";
279
278
  import myWorkflow from "../workflows/my-workflow";
280
279
 
281
280
  export default createResolver({
@@ -288,7 +287,7 @@ export default createResolver({
288
287
  // Trigger workflow with machine user permissions
289
288
  const workflowRunId = await myWorkflow.trigger(
290
289
  { id: input.id },
291
- { authInvoker: auth.invoker("admin-machine-user") },
290
+ { authInvoker: "admin-machine-user" },
292
291
  );
293
292
  return { workflowRunId };
294
293
  },
@@ -298,7 +297,9 @@ export default createResolver({
298
297
  });
299
298
  ```
300
299
 
301
- The `invoker()` method is type-safe and only accepts machine user names defined in the auth configuration.
300
+ Type narrowing is provided by the generated `tailor.d.ts` (the `MachineUserNameRegistry` interface). Run `tailor-sdk generate` (or `apply`) after defining new machine users to refresh it.
301
+
302
+ > **Deprecated:** The `auth.invoker("<name>")` helper is still available for backward compatibility. Prefer the string form — it does not require importing `auth` from `tailor.config.ts` into runtime files, avoiding bundling config-layer (Node-only) dependencies.
302
303
 
303
304
  ## OAuth 2.0 Clients
304
305
 
@@ -294,19 +294,10 @@ createExecutor({
294
294
 
295
295
  ### Authentication for Operations
296
296
 
297
- GraphQL and Workflow operations can specify an `authInvoker` to execute with machine user credentials:
297
+ GraphQL and Workflow operations can specify an `authInvoker` to execute with machine user credentials. Pass the machine user name as a plain string — it is type-narrowed to the names defined in your auth config:
298
298
 
299
299
  ```typescript
300
- import { defineAuth, createExecutor, scheduleTrigger } from "@tailor-platform/sdk";
301
-
302
- const auth = defineAuth("my-auth", {
303
- // ... auth configuration
304
- machineUsers: {
305
- "batch-processor": {
306
- attributes: { role: "ADMIN" },
307
- },
308
- },
309
- });
300
+ import { createExecutor, scheduleTrigger } from "@tailor-platform/sdk";
310
301
 
311
302
  export default createExecutor({
312
303
  name: "scheduled-cleanup",
@@ -314,11 +305,13 @@ export default createExecutor({
314
305
  operation: {
315
306
  kind: "graphql",
316
307
  query: `mutation { cleanupOldRecords { count } }`,
317
- authInvoker: auth.invoker("batch-processor"),
308
+ authInvoker: "batch-processor",
318
309
  },
319
310
  });
320
311
  ```
321
312
 
313
+ > **Deprecated:** `auth.invoker("batch-processor")` still works, but is deprecated. Prefer the string form to avoid importing config-layer modules into runtime files.
314
+
322
315
  ## Event Payloads
323
316
 
324
317
  Each trigger type provides specific context data in the callback functions.
@@ -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.
@@ -350,19 +350,10 @@ createResolver({
350
350
 
351
351
  ## Authentication
352
352
 
353
- Specify an `authInvoker` to execute the resolver with machine user credentials:
353
+ Specify an `authInvoker` 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:
354
354
 
355
355
  ```typescript
356
- import { defineAuth, createResolver, t } from "@tailor-platform/sdk";
357
-
358
- const auth = defineAuth("my-auth", {
359
- // ... auth configuration
360
- machineUsers: {
361
- "batch-processor": {
362
- attributes: { role: "ADMIN" },
363
- },
364
- },
365
- });
356
+ import { createResolver, t } from "@tailor-platform/sdk";
366
357
 
367
358
  export default createResolver({
368
359
  name: "adminQuery",
@@ -372,10 +363,12 @@ export default createResolver({
372
363
  // Executes as "batch-processor" machine user
373
364
  return { result: "ok" };
374
365
  },
375
- authInvoker: auth.invoker("batch-processor"),
366
+ authInvoker: "batch-processor",
376
367
  });
377
368
  ```
378
369
 
379
- The `authInvoker` option accepts the return value of `auth.invoker()`, which specifies the auth namespace and machine user name.
370
+ The machine user name is looked up in the auth service configured on your app (`machineUsers` in `defineAuth`). The namespace is resolved automatically — no need to import `auth` from `tailor.config.ts` in resolver files.
371
+
372
+ > **Deprecated:** `auth.invoker("batch-processor")` still works, but is deprecated. Importing `auth` into runtime files pulls config-layer (Node-only) dependencies into the bundle.
380
373
 
381
374
  **Note:** `authInvoker` controls the permissions for database operations and other platform actions, but the `user` object passed to the `body` function still reflects the original caller who invoked the resolver.
@@ -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()`
@@ -227,11 +227,10 @@ export default createWorkflow({
227
227
  You can start a workflow execution from a resolver using `workflow.trigger()`.
228
228
 
229
229
  - `workflow.trigger(args, options?)` returns a workflow run ID (`Promise<string>`).
230
- - To run with machine-user permissions, pass `{ authInvoker: auth.invoker("<machine-user>") }`.
230
+ - To run with machine-user permissions, pass `{ authInvoker: "<machine-user>" }`. The name is type-narrowed to the machine users defined in your auth config.
231
231
 
232
232
  ```typescript
233
233
  import { createResolver, t } from "@tailor-platform/sdk";
234
- import { auth } from "../tailor.config";
235
234
  import orderProcessingWorkflow from "../workflows/order-processing";
236
235
 
237
236
  export default createResolver({
@@ -244,7 +243,7 @@ export default createResolver({
244
243
  body: async ({ input }) => {
245
244
  const workflowRunId = await orderProcessingWorkflow.trigger(
246
245
  { orderId: input.orderId, customerId: input.customerId },
247
- { authInvoker: auth.invoker("manager-machine-user") },
246
+ { authInvoker: "manager-machine-user" },
248
247
  );
249
248
 
250
249
  return { workflowRunId };
@@ -255,6 +254,8 @@ export default createResolver({
255
254
  });
256
255
  ```
257
256
 
257
+ > **Deprecated:** `auth.invoker("manager-machine-user")` still works but is deprecated. Using the string form avoids importing `auth` into runtime code.
258
+
258
259
  See the full working example in the repository: [example/resolvers/triggerWorkflow.ts](../../../../example/resolvers/triggerWorkflow.ts).
259
260
 
260
261
  ## File Organization
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "1.35.2",
3
+ "version": "1.37.0",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -82,7 +82,8 @@
82
82
  "@connectrpc/connect": "2.1.1",
83
83
  "@connectrpc/connect-node": "2.1.1",
84
84
  "@inquirer/core": "11.1.8",
85
- "@inquirer/prompts": "8.4.0",
85
+ "@inquirer/prompts": "8.4.1",
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",
@@ -116,7 +117,7 @@
116
117
  "pgsql-ast-parser": "12.0.2",
117
118
  "pkg-types": "2.3.0",
118
119
  "politty": "0.4.13",
119
- "rolldown": "1.0.0-rc.13",
120
+ "rolldown": "1.0.0-rc.15",
120
121
  "semver": "7.7.4",
121
122
  "serve": "14.2.6",
122
123
  "std-env": "4.0.0",
@@ -138,14 +139,14 @@
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
+ "eslint-plugin-oxlint": "1.59.0",
142
143
  "oxfmt": "0.44.0",
143
- "oxlint": "1.58.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",
147
148
  "typescript": "5.9.3",
148
- "typescript-eslint": "8.58.0",
149
+ "typescript-eslint": "8.58.1",
149
150
  "vitest": "4.1.2",
150
151
  "zinfer": "0.1.7"
151
152
  },