@tailor-platform/sdk 1.74.1 → 1.76.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 (64) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/{application-BsH6tkZC.mjs → application-BUfYmf0O.mjs} +291 -15
  3. package/dist/application-BUfYmf0O.mjs.map +1 -0
  4. package/dist/application-DbvD5UUz.mjs +3 -0
  5. package/dist/brand-Eo4pLXPJ.mjs.map +1 -1
  6. package/dist/cli/commands/deploy/workflow-execution-policy.d.mts +1 -0
  7. package/dist/cli/index.mjs +218 -66
  8. package/dist/cli/index.mjs.map +1 -1
  9. package/dist/cli/lib.mjs +2 -2
  10. package/dist/cli/query/index.d.mts +4 -0
  11. package/dist/completion/zsh-worker.zsh +10 -10
  12. package/dist/configure/config/types.d.mts +3 -1
  13. package/dist/configure/index.d.mts +3 -1
  14. package/dist/configure/index.mjs +112 -4
  15. package/dist/configure/index.mjs.map +1 -1
  16. package/dist/configure/services/index.d.mts +3 -1
  17. package/dist/configure/services/tailordb/schema.d.mts +28 -15
  18. package/dist/configure/services/workflow/execution-policy.d.mts +71 -0
  19. package/dist/configure/services/workflow/execution-policy.types.d.mts +104 -0
  20. package/dist/configure/services/workflow/index.d.mts +3 -1
  21. package/dist/configure/services/workflow/job.d.mts +7 -3
  22. package/dist/{globals-B8XX5TRB.mjs → globals-CcU1ONiK.mjs} +2 -2
  23. package/dist/globals-CcU1ONiK.mjs.map +1 -0
  24. package/dist/{job-CtU73PGa.mjs → job-D-PbD1P3.mjs} +5 -3
  25. package/dist/job-D-PbD1P3.mjs.map +1 -0
  26. package/dist/{registry-BozuxbPp.mjs → registry-NfSW0BRo.mjs} +4 -3
  27. package/dist/registry-NfSW0BRo.mjs.map +1 -0
  28. package/dist/resource_pb-BRv7AMXK.mjs +49 -0
  29. package/dist/resource_pb-BRv7AMXK.mjs.map +1 -0
  30. package/dist/runtime/globals.d.mts +1 -1
  31. package/dist/runtime/index.d.mts +1 -1
  32. package/dist/runtime/workflow.d.mts +22 -3
  33. package/dist/{runtime-DV1EnfMs.mjs → runtime-_vUgjiqT.mjs} +253 -254
  34. package/dist/runtime-_vUgjiqT.mjs.map +1 -0
  35. package/dist/{schema-Dl_y0m9e.mjs → schema-DrVyN-LP.mjs} +60 -36
  36. package/dist/schema-DrVyN-LP.mjs.map +1 -0
  37. package/dist/{service_pb-DjwIn4jO.mjs → service_pb-B2FF59sP.mjs} +1 -1
  38. package/dist/{service_pb-CIrhGwHk.mjs → service_pb-B5w9rjPY.mjs} +17 -50
  39. package/dist/service_pb-B5w9rjPY.mjs.map +1 -0
  40. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +1 -1
  41. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +29 -9
  42. package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +35 -1
  43. package/dist/utils/test/index.mjs +1 -1
  44. package/dist/utils/test/index.mjs.map +1 -1
  45. package/dist/vitest/environment.mjs +1 -1
  46. package/dist/vitest/index.mjs +15 -12
  47. package/dist/vitest/index.mjs.map +1 -1
  48. package/dist/vitest/mocks/workflow.d.mts +5 -3
  49. package/dist/vitest/setup.mjs +1 -1
  50. package/dist/workflow-DSwnYPPP.mjs.map +1 -1
  51. package/docs/cli/auth.md +3 -3
  52. package/docs/cli/setup.md +8 -8
  53. package/docs/configuration.md +24 -0
  54. package/docs/services/tailordb.md +20 -0
  55. package/docs/services/workflow.md +78 -0
  56. package/package.json +1 -1
  57. package/dist/application-BsH6tkZC.mjs.map +0 -1
  58. package/dist/application-CSUhZMb5.mjs +0 -3
  59. package/dist/globals-B8XX5TRB.mjs.map +0 -1
  60. package/dist/job-CtU73PGa.mjs.map +0 -1
  61. package/dist/registry-BozuxbPp.mjs.map +0 -1
  62. package/dist/runtime-DV1EnfMs.mjs.map +0 -1
  63. package/dist/schema-Dl_y0m9e.mjs.map +0 -1
  64. package/dist/service_pb-CIrhGwHk.mjs.map +0 -1
@@ -26,7 +26,7 @@ type TailorAnyDBField = Omit<TailorDBField$1<AnyBuilderMethod, AnyBuilderMethod>
26
26
  serial: AnyBuilderMethod;
27
27
  clone: AnyBuilderMethod;
28
28
  };
29
- type TailorAnyDBType = TailorDBType<any, any>;
29
+ type TailorAnyDBType = TailorDBType<any, any, any>;
30
30
  type IsAny<T> = 0 extends 1 & T ? true : false;
31
31
  type DBFieldTypeNameMethod<Defined extends DefinedDBFieldMetadata> = IsAny<Defined> extends true ? TypeLevelError<string> : TypeLevelError<"typeName cannot be used on TailorDB fields">;
32
32
  type WithDBFieldDescription<Defined> = Defined & {
@@ -82,6 +82,19 @@ type WithDBFieldCloneOptions<Defined extends DefinedDBFieldMetadata, NewOpt exte
82
82
  array: true;
83
83
  } ? true : Defined["array"];
84
84
  };
85
+ type DefinedDBTypeMetadata = {
86
+ hooks?: true;
87
+ validate?: true;
88
+ features?: true;
89
+ indexes?: true;
90
+ files?: true;
91
+ permission?: true;
92
+ gqlPermission?: true;
93
+ description?: true;
94
+ };
95
+ type WithDBTypeMetadata<Defined extends DefinedDBTypeMetadata, Key extends keyof DefinedDBTypeMetadata> = Defined & Record<Key, true>;
96
+ type DBTypeDuplicateInputGuard<Defined extends DefinedDBTypeMetadata, Key extends keyof DefinedDBTypeMetadata, Input, Message extends string> = IsAny<Defined> extends true ? Input : Defined extends Record<Key, unknown> ? TypeLevelError<Message> : Input;
97
+ type DBTypeDuplicateRestGuard<Defined extends DefinedDBTypeMetadata, Key extends keyof DefinedDBTypeMetadata, Input extends unknown[], Message extends string> = IsAny<Defined> extends true ? Input : Defined extends Record<Key, unknown> ? [TypeLevelError<Message>, ...TypeLevelError<Message>[]] : Input;
85
98
  type FileKeyConflictError<Fields extends Record<string, TailorAnyDBField>, User extends object> = Partial<Record<keyof output<TailorDBType<Fields, User>> & string, TypeLevelError<"file keys cannot use existing field names">>>;
86
99
  type DBFieldDescriptionFn<Defined extends DefinedDBFieldMetadata, Output> = (description: string) => TailorDBField<WithDBFieldDescription<Defined>, Output>;
87
100
  type DBFieldRelationFn<Defined extends DefinedDBFieldMetadata, Output> = {
@@ -203,22 +216,22 @@ interface TailorDBField<Defined extends DefinedDBFieldMetadata = DefinedDBFieldM
203
216
  * Full TailorDBType interface with builder methods.
204
217
  * Extends the minimal structural interface from types/ with fluent API methods.
205
218
  */
206
- interface TailorDBType<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributeMap> extends TailorDBType$1<Fields, User> {
219
+ interface TailorDBType<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributeMap, Defined extends DefinedDBTypeMetadata = any> extends TailorDBType$1<Fields, User> {
207
220
  _description?: string;
208
- hooks(hooks: Hooks<Fields>): TailorDBType<Fields, User>;
209
- validate(validators: Validators<Fields>): TailorDBType<Fields, User>;
210
- features(features: Omit<TypeFeatures, "pluralForm">): TailorDBType<Fields, User>;
211
- indexes(...indexes: IndexDef<TailorDBType<Fields, User>>[]): TailorDBType<Fields, User>;
212
- files<const F extends string>(files: Record<F, string> & FileKeyConflictError<Fields, User>): TailorDBType<Fields, User>;
213
- permission<U extends object = User, P extends TailorTypePermission<U, output<TailorDBType<Fields, User>>> = TailorTypePermission<U, output<TailorDBType<Fields, User>>>>(permission: P): TailorDBType<Fields, U>;
214
- gqlPermission<U extends object = User, P extends TailorTypeGqlPermission<U> = TailorTypeGqlPermission<U>>(permission: P): TailorDBType<Fields, U>;
215
- description(description: string): TailorDBType<Fields, User>;
221
+ hooks(hooks: DBTypeDuplicateInputGuard<Defined, "hooks", Hooks<Fields>, ".hooks() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "hooks">>;
222
+ validate(validators: DBTypeDuplicateInputGuard<Defined, "validate", Validators<Fields>, ".validate() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "validate">>;
223
+ features(features: DBTypeDuplicateInputGuard<Defined, "features", Omit<TypeFeatures, "pluralForm">, ".features() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "features">>;
224
+ indexes(...indexes: DBTypeDuplicateRestGuard<Defined, "indexes", IndexDef<TailorDBType<Fields, User, Defined>>[], ".indexes() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "indexes">>;
225
+ files<const F extends string>(files: DBTypeDuplicateInputGuard<Defined, "files", Record<F, string> & FileKeyConflictError<Fields, User>, ".files() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "files">>;
226
+ permission<U extends object = User, P extends TailorTypePermission<U, output<TailorDBType<Fields, User, Defined>>> = TailorTypePermission<U, output<TailorDBType<Fields, User, Defined>>>>(permission: DBTypeDuplicateInputGuard<Defined, "permission", P, ".permission() has already been set">): TailorDBType<Fields, U, WithDBTypeMetadata<Defined, "permission">>;
227
+ gqlPermission<U extends object = User, P extends TailorTypeGqlPermission<U> = TailorTypeGqlPermission<U>>(permission: DBTypeDuplicateInputGuard<Defined, "gqlPermission", P, ".gqlPermission() has already been set">): TailorDBType<Fields, U, WithDBTypeMetadata<Defined, "gqlPermission">>;
228
+ description(description: DBTypeDuplicateInputGuard<Defined, "description", string, ".description() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "description">>;
216
229
  pickFields<K extends keyof Fields>(keys: K[]): Pick<Fields, K>;
217
230
  pickFields<K extends keyof Fields, const Opt extends FieldOptions>(keys: K[], options: Opt): { [P in K]: Fields[P] extends TailorDBField<infer D, infer _O> ? TailorDBField<WithDBFieldCloneOptions<D, Opt>, FieldOutput<TailorToTs[D["type"]], Opt>> : never };
218
231
  omitFields<K extends keyof Fields>(keys: K[]): Omit<Fields, K>;
219
- plugin<P extends keyof PluginConfigs<keyof Fields & string>>(config: { [K in P]: PluginConfigs<keyof Fields & string>[K] }): TailorDBType<Fields, User>;
232
+ plugin<P extends keyof PluginConfigs<keyof Fields & string>>(config: { [K in P]: PluginConfigs<keyof Fields & string>[K] }): TailorDBType<Fields, User, Defined>;
220
233
  }
221
- type TailorDBInstance<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributeMap> = TailorDBType<Fields, User>;
234
+ type TailorDBInstance<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributeMap, Defined extends DefinedDBTypeMetadata = any> = TailorDBType<Fields, User, Defined>;
222
235
  interface RelationConfig<S extends RelationType, T extends TailorDBType> {
223
236
  type: S;
224
237
  toward: {
@@ -354,9 +367,9 @@ declare const idField: TailorDBFieldInstance<"uuid", FieldOptions, string>;
354
367
  type idField = typeof idField;
355
368
  type DBType<F extends {
356
369
  id?: never;
357
- } & Record<string, TailorAnyDBField>> = TailorDBInstance<{
370
+ } & Record<string, TailorAnyDBField>, Defined extends DefinedDBTypeMetadata = DefinedDBTypeMetadata> = TailorDBInstance<{
358
371
  id: idField;
359
- } & F>;
372
+ } & F, InferredAttributeMap, Defined>;
360
373
  /**
361
374
  * Creates a new database type with the specified fields.
362
375
  * An `id` field (UUID) is automatically added to every type.
@@ -387,7 +400,7 @@ declare function dbType<const F extends {
387
400
  */
388
401
  declare function dbType<const F extends {
389
402
  id?: never;
390
- } & Record<string, TailorAnyDBField>>(name: string | [string, string], description: string, fields: F): DBType<F>;
403
+ } & Record<string, TailorAnyDBField>>(name: string | [string, string], description: string, fields: F): DBType<F, WithDBTypeMetadata<DefinedDBTypeMetadata, "description">>;
391
404
  /** TailorDB schema builder utilities for defining types and fields. */
392
405
  declare const db: {
393
406
  type: typeof dbType;
@@ -0,0 +1,71 @@
1
+ import { ExecutionPolicyConcurrency, ExecutionPolicyDefInput, ExecutionPolicyExactInstance, ExecutionPolicyGroupOptions, ExecutionPolicyInstance, ExecutionPolicyWildcardInstance, ResolvedExecutionPolicyInstance } from "./execution-policy.types.mjs";
2
+
3
+ //#region src/configure/services/workflow/execution-policy.d.ts
4
+ type ResolveKey<Def, Fallback extends string> = Def extends {
5
+ key: infer K extends string;
6
+ } ? K : Fallback;
7
+ type ResolveMatchType<Def> = Def extends {
8
+ matchType: infer M extends "exact" | "prefix";
9
+ } ? M : "exact";
10
+ /**
11
+ * Define a single workflow job function execution policy.
12
+ *
13
+ * Use this when declaring a policy outside the
14
+ * {@link defineWorkflowExecutionPolicies} builder — for example, when the
15
+ * runtime key prefix needs to differ from the corresponding workspace-unique
16
+ * name.
17
+ *
18
+ * When `matchType: "prefix"` is set, the returned instance has `keyFor(suffix)`
19
+ * instead of a directly-usable `key` (see {@link ExecutionPolicyWildcardInstance}).
20
+ * @param name - Workspace-unique name. Must match `^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$`.
21
+ * @param def - Optional overrides for `key` (defaults to `name`), `matchType`, `separator` (the `keyFor` join character, defaults to `.`), and concurrency
22
+ * @returns An execution policy instance
23
+ * @example
24
+ * export const perTenant = defineWorkflowExecutionPolicy("tenant-api", {
25
+ * matchType: "prefix",
26
+ * concurrencyPolicy: { maxConcurrentExecutions: 3 },
27
+ * });
28
+ *
29
+ * perTenant.keyFor(tenantId); // "tenant-api.<tenantId>"
30
+ */
31
+ declare function defineWorkflowExecutionPolicy<const N extends string, const D extends (Omit<ExecutionPolicyDefInput, "name"> & {
32
+ separator?: string;
33
+ }) | undefined = undefined>(name: N, def?: D): ResolvedExecutionPolicyInstance<ResolveKey<D, N>, ResolveMatchType<D>>;
34
+ /**
35
+ * Define a group of workflow job function execution policies. Property names
36
+ * become the workspace-unique `name` and default `key` verbatim, matching the
37
+ * mental model of {@link defineWaitPoints}. Provide `name` / `key` explicitly
38
+ * to override the property-name default (for example, when the property name
39
+ * is not valid for the execution policy grammar or when the runtime key
40
+ * prefix needs to differ).
41
+ *
42
+ * When `matchType: "prefix"` is set, the returned instance has `keyFor(suffix)`
43
+ * instead of a directly-usable `key` (see {@link ExecutionPolicyWildcardInstance}).
44
+ * `matchType` can be combined with an explicit `key`, or left to apply to
45
+ * the property-name-derived prefix.
46
+ *
47
+ * The return type mirrors the builder's return type so JSDoc on each property
48
+ * is preserved in IDE autocompletion.
49
+ * @param builder - Callback that receives a `define` factory and returns a record of policies
50
+ * @param options - Group-wide options; `separator` overrides the `.` `keyFor` uses to join the prefix and suffix for every prefix policy in the group
51
+ * @returns The same object returned by the builder (with `name` / `key` resolved on each instance)
52
+ * @example
53
+ * export const executionPolicies = defineWorkflowExecutionPolicies((define) => ({
54
+ * premium: define({ concurrencyPolicy: { maxConcurrentExecutions: 5 } }),
55
+ * "tenant-api": define({
56
+ * matchType: "prefix",
57
+ * concurrencyPolicy: { maxConcurrentExecutions: 3 },
58
+ * }),
59
+ * }));
60
+ *
61
+ * // In a workflow job function:
62
+ * await tailor.workflow.triggerJobFunction("worker", args, {
63
+ * executionPolicyKey: executionPolicies.premium.key,
64
+ * });
65
+ * await tailor.workflow.triggerJobFunction("worker", args, {
66
+ * executionPolicyKey: executionPolicies["tenant-api"].keyFor(input.tenantId),
67
+ * });
68
+ */
69
+ declare function defineWorkflowExecutionPolicies<T extends Record<string, ExecutionPolicyInstance>>(builder: (define: <const D extends ExecutionPolicyDefInput | undefined = undefined>(def?: D) => ResolvedExecutionPolicyInstance<ResolveKey<D, string>, ResolveMatchType<D>>) => T, options?: ExecutionPolicyGroupOptions): T;
70
+ //#endregion
71
+ export { type ExecutionPolicyConcurrency, type ExecutionPolicyDefInput, type ExecutionPolicyExactInstance, type ExecutionPolicyGroupOptions, type ExecutionPolicyInstance, type ExecutionPolicyWildcardInstance, type ResolvedExecutionPolicyInstance, defineWorkflowExecutionPolicies, defineWorkflowExecutionPolicy };
@@ -0,0 +1,104 @@
1
+ import { ExecutionPolicyKey } from "../../../runtime/workflow.mjs";
2
+
3
+ //#region src/configure/services/workflow/execution-policy.types.d.ts
4
+ /**
5
+ * Optional per-key concurrency cap applied to job function dispatches that
6
+ * resolve to a policy's `executionPolicyKey`.
7
+ */
8
+ interface ExecutionPolicyConcurrency {
9
+ /** Maximum number of concurrent executions allowed per resolved key. */
10
+ maxConcurrentExecutions: number;
11
+ }
12
+ /** Fields shared by both {@link ExecutionPolicyExactInstance} and {@link ExecutionPolicyWildcardInstance}. */
13
+ interface ExecutionPolicyBase {
14
+ /** Workspace-unique name for this policy. */
15
+ readonly name: string;
16
+ /** Optional per-key concurrency cap. */
17
+ readonly concurrencyPolicy?: ExecutionPolicyConcurrency;
18
+ }
19
+ /**
20
+ * An execution policy declared with `matchType: "exact"` (the default).
21
+ * `key` is branded as {@link ExecutionPolicyKey}, so it can be passed
22
+ * directly as the `executionPolicyKey` option.
23
+ */
24
+ interface ExecutionPolicyExactInstance<Key extends string = string> extends ExecutionPolicyBase {
25
+ /** Declared key; the platform registers it verbatim. */
26
+ readonly key: Key & ExecutionPolicyKey;
27
+ readonly matchType: "exact";
28
+ }
29
+ /**
30
+ * An execution policy declared with `matchType: "prefix"`. The platform
31
+ * registers the declared key prefix with a trailing `*`, and matches every
32
+ * dispatch whose runtime key begins with that prefix. There is no
33
+ * directly-usable `key` — use `keyFor` to build a concrete, branded runtime
34
+ * key at the call site instead of hand-concatenating the prefix and a
35
+ * suffix.
36
+ */
37
+ interface ExecutionPolicyWildcardInstance extends ExecutionPolicyBase {
38
+ readonly matchType: "prefix";
39
+ /**
40
+ * Build a concrete runtime key by appending `suffix` after this policy's
41
+ * declared key prefix, separated by `.` unless a different separator was
42
+ * configured where this policy was declared.
43
+ * @param suffix - Value appended after the wildcard prefix
44
+ * @returns The concrete key to pass as `executionPolicyKey`
45
+ * @throws If the resulting key does not match the execution policy key
46
+ * grammar (for example, an empty `suffix`)
47
+ * @example
48
+ * // key: "tenant-api", matchType: "prefix"
49
+ * tenantApi.keyFor(tenantId); // "tenant-api.<tenantId>"
50
+ */
51
+ keyFor(suffix: string): ExecutionPolicyKey;
52
+ }
53
+ /**
54
+ * A declared workflow job function execution policy — either
55
+ * {@link ExecutionPolicyExactInstance} or {@link ExecutionPolicyWildcardInstance}.
56
+ */
57
+ type ExecutionPolicyInstance<Key extends string = string> = ExecutionPolicyExactInstance<Key> | ExecutionPolicyWildcardInstance;
58
+ /**
59
+ * Resolves to {@link ExecutionPolicyWildcardInstance} when `MatchType` is
60
+ * known at the type level to be `"prefix"`, to {@link ExecutionPolicyExactInstance}
61
+ * when it's known to be `"exact"`, or to their union when `MatchType` is the
62
+ * unnarrowed `"exact" | "prefix"` (e.g. a caller passed a non-literal
63
+ * `matchType`) — narrowing to one branch in that case would claim a `key` or
64
+ * `keyFor` that may not exist on the actual runtime instance.
65
+ */
66
+ type ResolvedExecutionPolicyInstance<Key extends string, MatchType extends "exact" | "prefix"> = "exact" | "prefix" extends MatchType ? ExecutionPolicyExactInstance<Key> | ExecutionPolicyWildcardInstance : MatchType extends "prefix" ? ExecutionPolicyWildcardInstance : ExecutionPolicyExactInstance<Key>;
67
+ /**
68
+ * Body of an execution policy declaration.
69
+ *
70
+ * When both `name` and `key` are omitted in the `defineWorkflowExecutionPolicies`
71
+ * builder, the property name is used verbatim for both (like
72
+ * `defineWaitPoints`). Provide `name` when the property identifier is not
73
+ * valid execution policy grammar, and provide `key` when the runtime key
74
+ * prefix needs to differ from `name` (e.g. it needs `:` or `.`).
75
+ */
76
+ interface ExecutionPolicyDefInput {
77
+ /** Overrides the property-name-derived `name`. 3-63 characters from `[a-z0-9-]`; must start and end with `[a-z0-9]`. */
78
+ name?: string;
79
+ /** Overrides the property-name-derived `key` prefix. Independent of `matchType` — both may be set together. */
80
+ key?: string;
81
+ /**
82
+ * `"exact"` (the default) matches a dispatch whose runtime key equals
83
+ * `key` (or the resolved `name`, if `key` is omitted). `"prefix"`
84
+ * registers `key` as a wildcard prefix — the platform appends a trailing
85
+ * `*`, and the resulting instance exposes `keyFor(suffix)` to build
86
+ * concrete dispatch keys instead of a directly-usable `key`.
87
+ */
88
+ matchType?: "exact" | "prefix";
89
+ /** Optional per-key concurrency cap. */
90
+ concurrencyPolicy?: ExecutionPolicyConcurrency;
91
+ }
92
+ /**
93
+ * Options for {@link defineWorkflowExecutionPolicies}, applying to every
94
+ * policy declared by the builder (not settable per policy).
95
+ */
96
+ interface ExecutionPolicyGroupOptions {
97
+ /**
98
+ * Separator `keyFor(suffix)` inserts between a wildcard policy's declared
99
+ * `key` prefix and `suffix`. Defaults to `.`.
100
+ */
101
+ separator?: string;
102
+ }
103
+ //#endregion
104
+ export { ExecutionPolicyConcurrency, ExecutionPolicyDefInput, ExecutionPolicyExactInstance, ExecutionPolicyGroupOptions, ExecutionPolicyInstance, ExecutionPolicyWildcardInstance, ResolvedExecutionPolicyInstance };
@@ -1,7 +1,9 @@
1
+ import { ExecutionPolicyConcurrency, ExecutionPolicyDefInput, ExecutionPolicyExactInstance, ExecutionPolicyGroupOptions, ExecutionPolicyInstance, ExecutionPolicyWildcardInstance, ResolvedExecutionPolicyInstance } from "./execution-policy.types.mjs";
1
2
  import { WorkflowServiceConfig, WorkflowServiceInput } from "../../config/types.mjs";
2
3
  import { ConcurrencyPolicy, RetryPolicy } from "../../../types/workflow.generated.mjs";
3
4
  import { WORKFLOW_TEST_ENV_KEY } from "./test-env-key.mjs";
4
5
  import { WorkflowJob, WorkflowJobContext, createWorkflowJob } from "./job.mjs";
5
6
  import { Workflow, WorkflowConfig, createWorkflow } from "./workflow.mjs";
7
+ import { defineWorkflowExecutionPolicies, defineWorkflowExecutionPolicy } from "./execution-policy.mjs";
6
8
  import { WaitPointInstance, defineWaitPoint, defineWaitPoints } from "./wait-point.mjs";
7
- export { type ConcurrencyPolicy, type RetryPolicy, WORKFLOW_TEST_ENV_KEY, WaitPointInstance, Workflow, WorkflowConfig, WorkflowJob, WorkflowJobContext, type WorkflowServiceConfig, type WorkflowServiceInput, createWorkflow, createWorkflowJob, defineWaitPoint, defineWaitPoints };
9
+ export { type ConcurrencyPolicy, type ExecutionPolicyConcurrency, type ExecutionPolicyDefInput, type ExecutionPolicyExactInstance, type ExecutionPolicyGroupOptions, type ExecutionPolicyInstance, type ExecutionPolicyWildcardInstance, type ResolvedExecutionPolicyInstance, type RetryPolicy, WORKFLOW_TEST_ENV_KEY, WaitPointInstance, Workflow, WorkflowConfig, WorkflowJob, WorkflowJobContext, type WorkflowServiceConfig, type WorkflowServiceInput, createWorkflow, createWorkflowJob, defineWaitPoint, defineWaitPoints, defineWorkflowExecutionPolicies, defineWorkflowExecutionPolicy };
@@ -1,5 +1,6 @@
1
1
  import { TailorEnv, TailorInvoker } from "../../../runtime/types.mjs";
2
2
  import { JsonCompatible, TypeLevelError } from "../../../types/helpers.mjs";
3
+ import { TriggerJobFunctionOptions } from "../../../runtime/workflow.mjs";
3
4
  import { WORKFLOW_TEST_ENV_KEY } from "./test-env-key.mjs";
4
5
 
5
6
  //#region src/configure/services/workflow/job.d.ts
@@ -28,15 +29,18 @@ interface WorkflowJob<Name extends string = string, Input = undefined, Output =
28
29
  name: Name;
29
30
  /**
30
31
  * Trigger this job with the given input. Returns a Promise that resolves
31
- * to the job's output value.
32
+ * to the job's output value. Accepts an optional second argument to pass
33
+ * `executionPolicyKey` for platform-side concurrency enforcement.
32
34
  * @example
33
35
  * body: async (input) => {
34
36
  * const a = await jobA.trigger({ id: input.id });
35
- * const b = await jobB.trigger({ id: input.id });
37
+ * const b = await jobB.trigger({ id: input.id }, {
38
+ * executionPolicyKey: `tenant-api.${input.tenantId}`,
39
+ * });
36
40
  * return { a, b };
37
41
  * }
38
42
  */
39
- trigger: [Input] extends [undefined] ? () => Promise<Awaited<Output>> : (input: Input) => Promise<Awaited<Output>>;
43
+ trigger: [Input] extends [undefined] ? (input?: undefined, options?: TriggerJobFunctionOptions) => Promise<Awaited<Output>> : (input: Input, options?: TriggerJobFunctionOptions) => Promise<Awaited<Output>>;
40
44
  body: (input: Input, context: WorkflowJobContext) => Output | Promise<Output>;
41
45
  }
42
46
  interface CreateWorkflowJobConfig<Name extends string, I, O> {
@@ -1,4 +1,4 @@
1
- import { c as runRegisteredJob, l as runRegisteredWorkflow } from "./registry-BozuxbPp.mjs";
1
+ import { c as runRegisteredJob, l as runRegisteredWorkflow } from "./registry-NfSW0BRo.mjs";
2
2
 
3
3
  //#region src/vitest/workflow-runtime.ts
4
4
  function createDefaultWorkflowRuntime() {
@@ -106,4 +106,4 @@ function cleanupPlatformGlobals(global) {
106
106
 
107
107
  //#endregion
108
108
  export { cleanupPlatformGlobals as n, installPlatformGlobals as r, RUNTIME_FLAG_KEY as t };
109
- //# sourceMappingURL=globals-B8XX5TRB.mjs.map
109
+ //# sourceMappingURL=globals-CcU1ONiK.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globals-CcU1ONiK.mjs","names":[],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { runRegisteredJob, runRegisteredWorkflow } from \"../configure/services/workflow/registry\";\nimport type { TriggerJobFunctionOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n triggerJobFunction: (\n name: string,\n args?: unknown,\n options?: TriggerJobFunctionOptions,\n ) => unknown;\n triggerWorkflow: (name: string, args?: unknown, options?: unknown) => Promise<string>;\n resumeWorkflow: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n return {\n triggerJobFunction: (name, args) => runRegisteredJob(name, args),\n triggerWorkflow: (name, args) => runRegisteredWorkflow(name, args),\n resumeWorkflow: async (executionId: string): Promise<string> => executionId,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`, `TailorErrorMessage`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorErrorMessageMock extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TailorErrorMessage\";\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n * @param global - The global object to install into (typically `globalThis`)\n */\nexport function installPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default runner\n // so `.trigger()` runs the real job chain locally without `mockWorkflow()`;\n // `mockWorkflow()` overlays and restores it.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorErrorMessage = TailorErrorMessageMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorErrorMessage;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":";;;AAsBA,SAAgB,+BAAuD;CACrE,OAAO;EACL,qBAAqB,MAAM,SAAS,iBAAiB,MAAM,IAAI;EAC/D,kBAAkB,MAAM,SAAS,sBAAsB,MAAM,IAAI;EACjE,gBAAgB,OAAO,gBAAyC;EAChE,OAAO,QAAyB;GAC9B,MAAM,IAAI,MACR,wBAAwB,IAAI,wDAC9B;EACF;EACA,SAAS,YAA2B;GAClC,MAAM,IAAI,MACR,6EACF;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;ACbA,MAAa,mBAAmB;AAWhC,IAAM,mBAAN,cAA+B,MAAM;CACnC;CAEA,YAAY,QAA2B;EACrC,IAAI,CAAC,MAAM,QAAQ,MAAM,GACvB,MAAM,IAAI,UAAU,uCAAuC;EAE7D,MAAM,YAAY,OAAO,KAAK,GAAG,MAAM;GACrC,IAAI,OAAO,EAAE,YAAY,UACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,2BAA2B;GAE3E,IAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,GACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,wBAAwB;GAExE,OAAO;IAAE,SAAS,EAAE;IAAS,MAAM,EAAE;GAAK;EAC5C,CAAC;EAID,MAAM,iBAAiB,KAAK,UAAU,EAAE,QAAQ,UAAU,CAAC,GAAG;EAC9D,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,IAAM,yBAAN,cAAqC,MAAM;CACzC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAEA,IAAM,wBAAN,cAAoC,MAAM;CACxC;CACA,AAAS;CAET,YAAY,SAAiB,MAA8B,OAAiB;EAC1E,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;AASA,SAAS,oBAA2C;CAClD,OAAO;AACT;;;;;;;AAQA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,IAAI;CAEV,EAAE,oBAAoB;CAMtB,EAAE,SAAS;EACT,SAAS,EAAE,YAAY,kBAAkB;EACzC,UAAU,6BAA6B;CACzC;CACA,EAAE,WAAW,CAAC;CAEd,EAAE,eAAe;CACjB,EAAE,qBAAqB;CACvB,EAAE,oBAAoB;AACxB;;;;;;AAOA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,IAAI;CACV,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;AACX"}
@@ -1,5 +1,5 @@
1
1
  import { t as brandValue } from "./brand-Eo4pLXPJ.mjs";
2
- import { n as dispatchTriggerJob, o as registerJob } from "./registry-BozuxbPp.mjs";
2
+ import { n as dispatchTriggerJob, o as registerJob } from "./registry-NfSW0BRo.mjs";
3
3
 
4
4
  //#region src/configure/services/workflow/job.ts
5
5
  /**
@@ -40,7 +40,9 @@ function createWorkflowJob(config) {
40
40
  if (!process.env.TAILOR_PLATFORM_BUNDLE) registerJob(config.name, body);
41
41
  const trigger = process.env.TAILOR_PLATFORM_BUNDLE ? async () => {
42
42
  throw new Error("This workflow job's .trigger() is rewritten at build time and is unavailable in the bundle");
43
- } : async (args) => await dispatchTriggerJob(config.name, args);
43
+ } : async function trigger(args, options) {
44
+ return arguments.length >= 2 ? await dispatchTriggerJob(config.name, args, options) : await dispatchTriggerJob(config.name, args);
45
+ };
44
46
  return brandValue({
45
47
  name: config.name,
46
48
  trigger,
@@ -50,4 +52,4 @@ function createWorkflowJob(config) {
50
52
 
51
53
  //#endregion
52
54
  export { createWorkflowJob as t };
53
- //# sourceMappingURL=job-CtU73PGa.mjs.map
55
+ //# sourceMappingURL=job-D-PbD1P3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-D-PbD1P3.mjs","names":[],"sources":["../src/configure/services/workflow/job.ts"],"sourcesContent":["import { brandValue } from \"#/utils/brand\";\nimport { dispatchTriggerJob, registerJob, type RegisteredJobBody } from \"./registry\";\nimport type { TailorEnv, TailorInvoker } from \"#/runtime/types\";\nimport type { TriggerJobFunctionOptions } from \"#/runtime/workflow\";\nimport type { JsonCompatible, TypeLevelError } from \"#/types/helpers\";\n\n/**\n * Context object passed as the second argument to workflow job body functions.\n */\nexport type WorkflowJobContext = {\n env: TailorEnv;\n invoker?: TailorInvoker;\n};\n\n/**\n * The body function type for a workflow job.\n * Resolves to the callable signature when `I` / `O` are JsonValue-compatible,\n * or to a type-level error that surfaces at the `body:` property.\n */\ntype JobBody<I, O> = [null] extends [I]\n ? TypeLevelError<\"Input cannot be null at the top level\">\n : [I] extends [undefined]\n ? [O] extends [JsonCompatible<O> | undefined | void]\n ? (input: I, context: WorkflowJobContext) => O | Promise<O>\n : TypeLevelError<\"Output must be JsonValue-compatible (plain objects/arrays; no class instances or functions)\">\n : [undefined] extends [I]\n ? TypeLevelError<\"Input cannot include undefined at the top level\">\n : [I] extends [JsonCompatible<I>]\n ? [O] extends [JsonCompatible<O> | undefined | void]\n ? (input: I, context: WorkflowJobContext) => O | Promise<O>\n : TypeLevelError<\"Output must be JsonValue-compatible (plain objects/arrays; no class instances or functions)\">\n : TypeLevelError<\"Input must be JsonValue-compatible (plain objects/arrays; no class instances or functions)\">;\n\n/**\n * WorkflowJob represents a job that can be triggered in a workflow.\n *\n * Type constraints:\n * - Input: Must be JsonValue-compatible (plain objects/arrays; no class instances or functions) or undefined.\n * - Output: Must be JsonValue-compatible (plain objects/arrays; no class instances or functions), undefined, or void.\n * - Trigger returns `Awaited<Output>` as-is (no Jsonify transformation).\n */\nexport interface WorkflowJob<Name extends string = string, Input = undefined, Output = undefined> {\n name: Name;\n /**\n * Trigger this job with the given input. Returns a Promise that resolves\n * to the job's output value. Accepts an optional second argument to pass\n * `executionPolicyKey` for platform-side concurrency enforcement.\n * @example\n * body: async (input) => {\n * const a = await jobA.trigger({ id: input.id });\n * const b = await jobB.trigger({ id: input.id }, {\n * executionPolicyKey: `tenant-api.${input.tenantId}`,\n * });\n * return { a, b };\n * }\n */\n trigger: [Input] extends [undefined]\n ? (input?: undefined, options?: TriggerJobFunctionOptions) => Promise<Awaited<Output>>\n : (input: Input, options?: TriggerJobFunctionOptions) => Promise<Awaited<Output>>;\n body: (input: Input, context: WorkflowJobContext) => Output | Promise<Output>;\n}\n\nexport { WORKFLOW_TEST_ENV_KEY } from \"./test-env-key\";\n\ninterface CreateWorkflowJobConfig<Name extends string, I, O> {\n readonly name: Name;\n readonly body: JobBody<I, O>;\n}\n\n/**\n * Create a workflow job definition.\n *\n * All jobs must be named exports from the workflow file.\n * Job names must be unique across the entire project.\n *\n * Input and output must be JsonValue-compatible (primitives, plain objects, arrays).\n * Functions and objects with a `toJSON` method are rejected at the type level;\n * class instances exposing methods are rejected via the property walk.\n * @param config - Job configuration with name and body function.\n * @param config.name - Unique job name across the project.\n * @param config.body - Async function that processes the job input.\n * @returns A WorkflowJob that can be triggered from other jobs.\n * @example\n * // Simple job with async body:\n * export const fetchData = createWorkflowJob({\n * name: \"fetch-data\",\n * body: async (input: { id: string }) => {\n * const db = getDB(\"tailordb\");\n * return await db.selectFrom(\"Table\").selectAll().where(\"id\", \"=\", input.id).executeTakeFirst();\n * },\n * });\n * @example\n * // Orchestrator job that fans out to other jobs.\n * export const orchestrate = createWorkflowJob({\n * name: \"orchestrate\",\n * body: async (input: { orderId: string }) => {\n * const inventory = await checkInventory.trigger({ orderId: input.orderId });\n * const payment = await processPayment.trigger({ orderId: input.orderId });\n * return { inventory, payment };\n * },\n * });\n */\nexport function createWorkflowJob<const Name extends string, I = undefined, O = undefined>(\n config: CreateWorkflowJobConfig<Name, I, O>,\n): WorkflowJob<Name, I, Awaited<O>> {\n const body = config.body as (input: I, context: WorkflowJobContext) => O | Promise<O>;\n\n // Test-only registry/trigger shim; the platform bundle sets the flag so it is DCE'd.\n if (!process.env.TAILOR_PLATFORM_BUNDLE) {\n registerJob(config.name, body as RegisteredJobBody);\n }\n\n const trigger = process.env.TAILOR_PLATFORM_BUNDLE\n ? async () => {\n throw new Error(\n \"This workflow job's .trigger() is rewritten at build time and is unavailable in the bundle\",\n );\n }\n : // Preserve arity: use `arguments.length` (regular function, not arrow) so\n // `.trigger(args, undefined)` is treated as \"options passed\" — matching\n // the bundler rewrite, which forwards the literal `undefined` from the\n // AST as a third argument. Without this, local execution and bundled\n // workflows would hand mocks different call shapes.\n async function trigger(args?: unknown, options?: TriggerJobFunctionOptions) {\n // oxlint-disable-next-line prefer-rest-params\n return (\n arguments.length >= 2\n ? await dispatchTriggerJob(config.name, args, options)\n : await dispatchTriggerJob(config.name, args)\n ) as Awaited<O>;\n };\n\n return brandValue(\n { name: config.name, trigger, body } as WorkflowJob<Name, I, Awaited<O>>,\n \"workflow-job\",\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsGA,SAAgB,kBACd,QACkC;CAClC,MAAM,OAAO,OAAO;CAGpB,IAAI,CAAC,QAAQ,IAAI,wBACf,YAAY,OAAO,MAAM,IAAyB;CAGpD,MAAM,UAAU,QAAQ,IAAI,yBACxB,YAAY;EACV,MAAM,IAAI,MACR,4FACF;CACF,IAMA,eAAe,QAAQ,MAAgB,SAAqC;EAE1E,OACE,UAAU,UAAU,IAChB,MAAM,mBAAmB,OAAO,MAAM,MAAM,OAAO,IACnD,MAAM,mBAAmB,OAAO,MAAM,IAAI;CAElD;CAEJ,OAAO,WACL;EAAE,MAAM,OAAO;EAAM;EAAS;CAAK,GACnC,cACF;AACF"}
@@ -163,9 +163,10 @@ async function runRegisteredWorkflow(name, args) {
163
163
  if (workflow) await runRegisteredJob(workflow.mainJobName, args);
164
164
  return TRIGGER_DEFAULT;
165
165
  }
166
- function dispatchTriggerJob(name, args) {
166
+ function dispatchTriggerJob(name, args, options) {
167
167
  const workflow = currentPlatformWorkflow();
168
- return workflow ? workflow.triggerJobFunction(name, args) : runRegisteredJob(name, args);
168
+ if (!workflow) return runRegisteredJob(name, args);
169
+ return arguments.length >= 3 ? workflow.triggerJobFunction(name, args, options) : workflow.triggerJobFunction(name, args);
169
170
  }
170
171
  function dispatchTriggerWorkflow(name, args, options) {
171
172
  const workflow = currentPlatformWorkflow();
@@ -174,4 +175,4 @@ function dispatchTriggerWorkflow(name, args, options) {
174
175
 
175
176
  //#endregion
176
177
  export { getRegisteredWorkflow as a, runRegisteredJob as c, buildJobContext as d, clearWorkflowTestEnv as f, getRegisteredJob as i, runRegisteredWorkflow as l, platformSerialize as m, dispatchTriggerJob as n, registerJob as o, writeWorkflowTestEnv as p, dispatchTriggerWorkflow as r, registerWorkflow as s, TRIGGER_DEFAULT as t, WORKFLOW_TEST_ENV_KEY as u };
177
- //# sourceMappingURL=registry-BozuxbPp.mjs.map
178
+ //# sourceMappingURL=registry-NfSW0BRo.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-NfSW0BRo.mjs","names":[],"sources":["../src/utils/test/platform-serialize.ts","../src/configure/services/workflow/test-env-key.ts","../src/configure/services/workflow/registry.ts"],"sourcesContent":["/**\n * Validate and serialize a value as it would cross the Platform JSON boundary.\n *\n * Mirrors the runtime checks the platform performs on workflow arguments,\n * wait payloads, and trigger inputs so that local tests fail in the same\n * places production fails.\n *\n * Throws on:\n * - `NaN` / `Infinity` / `-Infinity` (`JSON.stringify` would silently emit `null`)\n * - `BigInt` (TypeError is thrown by `JSON.stringify`; we emit a clearer message)\n * - Non-plain objects (class instances, including `Date`, `Map`, `Set`, `Error`,\n * and user-defined DTOs whose prototype is not `Object.prototype`)\n *\n * The replacer reads `this[key]` so the check sees the original value before\n * any `toJSON` conversion (e.g. `Date.prototype.toJSON`).\n * @param value - Value to validate and round-trip\n * @returns The JSON-normalized value (undefined/function properties stripped, etc.)\n */\nexport function platformSerialize<T>(value: T): T {\n // Top-level undefined is allowed (jobs may take no input).\n if (value === undefined) return undefined as T;\n\n // Root function/symbol stringify to `undefined`; throw a specific message here.\n if (typeof value === \"function\") {\n throw new TypeError(\"platformSerialize: function is not JSON-serializable at <root>\");\n }\n if (typeof value === \"symbol\") {\n throw new TypeError(\"platformSerialize: Symbol is not JSON-serializable at <root>\");\n }\n\n const serialized = JSON.stringify(value, function (key, val) {\n if (typeof val === \"number\" && !Number.isFinite(val)) {\n throw new TypeError(\n `platformSerialize: non-finite number at ${formatPath(key)}: ${String(val)}`,\n );\n }\n if (typeof val === \"bigint\") {\n throw new TypeError(\n `platformSerialize: BigInt is not JSON-serializable at ${formatPath(key)}`,\n );\n }\n // Look at the pre-toJSON value so Date/Map/Set/etc. can be detected.\n const raw = (this as Record<string, unknown>)[key];\n if (raw !== null && typeof raw === \"object\" && !Array.isArray(raw)) {\n const proto = Object.getPrototypeOf(raw);\n if (proto !== Object.prototype && proto !== null) {\n const ctor = (raw as { constructor?: { name?: string } }).constructor?.name ?? \"anonymous\";\n throw new TypeError(\n `platformSerialize: non-plain object at ${formatPath(key)} (${ctor} instance)`,\n );\n }\n }\n return val;\n });\n\n // `JSON.stringify` returns `undefined` when the root collapses (e.g. a `toJSON`\n // returning `undefined`); parsing that would throw opaquely.\n // JSON.stringify returns undefined for non-serializable values\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (serialized === undefined) {\n throw new TypeError(\"platformSerialize: value is not JSON-serializable at <root>\");\n }\n\n return JSON.parse(serialized) as T;\n}\n\nfunction formatPath(key: string): string {\n return key === \"\" ? \"<root>\" : `\"${key}\"`;\n}\n","/**\n * Typed accessors for the test-time globalThis slot used to pass `env` from\n * `mockWorkflow().setEnv()` (in `@tailor-platform/sdk/vitest`) to\n * `createWorkflowJob().trigger()` bodies. The slot key is private to this\n * module; callers go through the get/set/clear functions below so both sides\n * share the same access path.\n *\n * Lives in its own file (with no `@/` imports) so `vitest/mock.ts` can load\n * it from nested Vitest configs that do not resolve `@/` aliases.\n * @internal\n */\nimport type { TailorEnv, TailorInvoker } from \"../../../runtime/types\";\n\nconst SLOT_KEY = \"__tailorWorkflowTestEnv\";\n\n/**\n * Read the test-time env slot.\n * @returns Current env, or `undefined` when unset.\n * @internal\n */\nexport function readWorkflowTestEnv(): TailorEnv | undefined {\n return (globalThis as unknown as Record<string, TailorEnv | undefined>)[SLOT_KEY];\n}\n\n/**\n * Write the test-time env slot.\n * @param env - Env value to expose to `.trigger()` bodies.\n * @internal\n */\nexport function writeWorkflowTestEnv(env: TailorEnv): void {\n (globalThis as unknown as Record<string, TailorEnv>)[SLOT_KEY] = env;\n}\n\n/**\n * Clear the test-time env slot.\n * @internal\n */\nexport function clearWorkflowTestEnv(): void {\n delete (globalThis as unknown as Record<string, unknown>)[SLOT_KEY];\n}\n\n/**\n * Env-var fallback read by `.trigger()` when `mockWorkflow().setEnv()` is unset.\n * @deprecated Use `mockWorkflow().setEnv()` from `@tailor-platform/sdk/vitest`.\n * @internal\n */\nexport const WORKFLOW_TEST_ENV_KEY = \"TAILOR_TEST_WORKFLOW_ENV\";\n\n// env from `mockWorkflow().setEnv()`, else the deprecated env-var. Shallow-copied\n// to isolate against cross-trigger mutation.\nexport function buildJobContext(): { env: TailorEnv; invoker?: TailorInvoker } {\n const fromGlobal = readWorkflowTestEnv();\n if (fromGlobal !== undefined) return { env: { ...fromGlobal } };\n const raw = process.env[WORKFLOW_TEST_ENV_KEY];\n if (!raw) return { env: {} as TailorEnv };\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (cause) {\n throw new Error(\n `Invalid JSON in ${WORKFLOW_TEST_ENV_KEY}; provide valid JSON or use mockWorkflow().setEnv().`,\n { cause },\n );\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\n `${WORKFLOW_TEST_ENV_KEY} must be a JSON object; provide a record or use mockWorkflow().setEnv().`,\n );\n }\n return { env: { ...(parsed as TailorEnv) } };\n}\n","import { platformSerialize } from \"#/utils/test/platform-serialize\";\nimport { buildJobContext } from \"./test-env-key\";\nimport type { TailorEnv, TailorInvoker } from \"#/runtime/types\";\nimport type { TriggerJobFunctionOptions } from \"#/runtime/workflow\";\n\n/**\n * Body signature shared by workflow jobs at registry-write time.\n * The user's `createWorkflowJob`/`createWorkflow` body uses concrete types,\n * but the registry erases them for storage.\n */\nexport type RegisteredJobBody = (\n args: unknown,\n context: { env: TailorEnv; invoker?: TailorInvoker },\n) => unknown | Promise<unknown>;\n\nexport interface RegisteredWorkflow {\n mainJobName: string;\n}\n\nconst JOB_REGISTRY_KEY: unique symbol = Symbol.for(\"tailor-platform/sdk:job-registry\");\nconst WORKFLOW_REGISTRY_KEY: unique symbol = Symbol.for(\"tailor-platform/sdk:workflow-registry\");\n\ntype PlatformWorkflow = {\n triggerWorkflow: (name: string, args?: unknown, options?: unknown) => Promise<string>;\n triggerJobFunction: (\n name: string,\n args?: unknown,\n options?: TriggerJobFunctionOptions,\n ) => unknown;\n};\n\ntype GlobalWithRegistry = typeof globalThis & {\n [JOB_REGISTRY_KEY]?: Map<string, RegisteredJobBody>;\n [WORKFLOW_REGISTRY_KEY]?: Map<string, RegisteredWorkflow>;\n tailor?: { workflow?: PlatformWorkflow };\n};\n\nfunction jobs(): Map<string, RegisteredJobBody> {\n const g = globalThis as GlobalWithRegistry;\n let map = g[JOB_REGISTRY_KEY];\n if (!map) {\n map = new Map();\n g[JOB_REGISTRY_KEY] = map;\n }\n return map;\n}\n\nfunction workflows(): Map<string, RegisteredWorkflow> {\n const g = globalThis as GlobalWithRegistry;\n let map = g[WORKFLOW_REGISTRY_KEY];\n if (!map) {\n map = new Map();\n g[WORKFLOW_REGISTRY_KEY] = map;\n }\n return map;\n}\n\n/**\n * Register a job body keyed by job name. Called as a side effect by\n * `createWorkflowJob` so the vitest mock can execute the body when\n * `globalThis.tailor.workflow.triggerJobFunction(name, args)` is invoked.\n *\n * In production builds the bundler rewrites `.trigger()` calls so this registry\n * is never read; the gated write is dropped as dead code.\n * @param name - Job name\n * @param body - Job body function\n */\nexport function registerJob(name: string, body: RegisteredJobBody): void {\n jobs().set(name, body);\n}\n\n/**\n * Look up a registered job body by name.\n * @param name - Job name\n * @returns The registered body, or undefined when no job is registered\n */\nexport function getRegisteredJob(name: string): RegisteredJobBody | undefined {\n return jobs().get(name);\n}\n\n/**\n * Register a workflow's main job name so the mock can run the workflow locally.\n * @param name - Workflow name\n * @param mainJobName - Name of the workflow's main job\n */\nexport function registerWorkflow(name: string, mainJobName: string): void {\n workflows().set(name, { mainJobName });\n}\n\n/**\n * Look up a registered workflow by name.\n * @param name - Workflow name\n * @returns The registered workflow, or undefined\n */\nexport function getRegisteredWorkflow(name: string): RegisteredWorkflow | undefined {\n return workflows().get(name);\n}\n\nfunction currentPlatformWorkflow(): PlatformWorkflow | undefined {\n // globalThis may not have the tailor property at runtime\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n return (globalThis as GlobalWithRegistry).tailor?.workflow;\n}\n\n// A valid placeholder UUID, so callers that validate the execution id behave the\n// same locally as against the platform.\nexport const TRIGGER_DEFAULT = \"00000000-0000-4000-8000-000000000000\";\n\nfunction serializeReturn(out: unknown): unknown {\n return out instanceof Promise ? out.then((v) => platformSerialize(v)) : platformSerialize(out);\n}\n\n// Runs the registered body across the platform JSON boundary. Shared by the\n// `tailor-runtime` default runner and the no-shim `.trigger()` fallback below.\nexport function runRegisteredJob(name: string, args?: unknown): unknown {\n const body = getRegisteredJob(name);\n const out = body ? body(platformSerialize(args), buildJobContext()) : null;\n return serializeReturn(out);\n}\n\nexport async function runRegisteredWorkflow(name: string, args?: unknown): Promise<string> {\n const workflow = getRegisteredWorkflow(name);\n if (workflow) await runRegisteredJob(workflow.mainJobName, args);\n return TRIGGER_DEFAULT;\n}\n\n// `.trigger()` routes through the installed `tailor.workflow` shim, falling back\n// to running the registered body/workflow locally when none is installed.\n// Preserve arity: the shim sees a 2-argument call when the caller supplied no\n// options, and a 3-argument call otherwise, mirroring the bundler rewrite so\n// mocks observe the same shape in local execution and in bundled workflows.\nexport function dispatchTriggerJob(\n name: string,\n args?: unknown,\n options?: TriggerJobFunctionOptions,\n): unknown {\n const workflow = currentPlatformWorkflow();\n if (!workflow) return runRegisteredJob(name, args);\n // oxlint-disable-next-line prefer-rest-params\n return arguments.length >= 3\n ? workflow.triggerJobFunction(name, args, options)\n : workflow.triggerJobFunction(name, args);\n}\n\nexport function dispatchTriggerWorkflow(\n name: string,\n args?: unknown,\n options?: unknown,\n): Promise<string> {\n const workflow = currentPlatformWorkflow();\n return workflow\n ? workflow.triggerWorkflow(name, args, options)\n : runRegisteredWorkflow(name, args);\n}\n"],"mappings":"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"}