@lafken/state-machine 0.10.1

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 (33) hide show
  1. package/LICENCE +21 -0
  2. package/README.md +383 -0
  3. package/lib/index.d.ts +2 -0
  4. package/lib/index.js +18 -0
  5. package/lib/main/index.d.ts +2 -0
  6. package/lib/main/index.js +18 -0
  7. package/lib/main/param/index.d.ts +2 -0
  8. package/lib/main/param/index.js +18 -0
  9. package/lib/main/param/param.d.ts +105 -0
  10. package/lib/main/param/param.js +115 -0
  11. package/lib/main/param/param.types.d.ts +77 -0
  12. package/lib/main/param/param.types.js +2 -0
  13. package/lib/main/state-machine/index.d.ts +2 -0
  14. package/lib/main/state-machine/index.js +18 -0
  15. package/lib/main/state-machine/state-machine.d.ts +113 -0
  16. package/lib/main/state-machine/state-machine.js +133 -0
  17. package/lib/main/state-machine/state-machine.types.d.ts +977 -0
  18. package/lib/main/state-machine/state-machine.types.js +7 -0
  19. package/lib/resolver/index.d.ts +1 -0
  20. package/lib/resolver/index.js +17 -0
  21. package/lib/resolver/resolver.d.ts +6 -0
  22. package/lib/resolver/resolver.js +28 -0
  23. package/lib/resolver/state-machine/schema/schema.d.ts +34 -0
  24. package/lib/resolver/state-machine/schema/schema.js +431 -0
  25. package/lib/resolver/state-machine/schema/schema.types.d.ts +149 -0
  26. package/lib/resolver/state-machine/schema/schema.types.js +2 -0
  27. package/lib/resolver/state-machine/schema/schema.utils.d.ts +15 -0
  28. package/lib/resolver/state-machine/schema/schema.utils.js +53 -0
  29. package/lib/resolver/state-machine/state-machine.d.ts +19 -0
  30. package/lib/resolver/state-machine/state-machine.js +96 -0
  31. package/lib/resolver/state-machine/state-machine.types.d.ts +7 -0
  32. package/lib/resolver/state-machine/state-machine.types.js +2 -0
  33. package/package.json +87 -0
package/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aníbal Emilio Jorquera Cornejo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # @lafken/state-machine
2
+
3
+ Define AWS Step Functions state machines using TypeScript decorators. `@lafken/state-machine` lets you declare states, transitions, service integrations, and nested workflows directly within your classes — no raw JSON or ASL required.
4
+
5
+ > [!NOTE]
6
+ > This library exclusively supports **JSONata** for data transformation and querying. **JSONPath is not supported**.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @lafken/state-machine
12
+ ```
13
+
14
+ ## Getting Started
15
+
16
+ Register the `StateMachineResolver` in your application and define your first workflow:
17
+
18
+ ```typescript
19
+ import { createApp, createModule } from '@lafken/main';
20
+ import { StateMachineResolver } from '@lafken/state-machine/resolver';
21
+ import { StateMachine, State, Event } from '@lafken/state-machine/main';
22
+
23
+ // 1. Define the state machine
24
+ @StateMachine({
25
+ startAt: 'processOrder',
26
+ })
27
+ class OrderWorkflow {
28
+ @State({ next: 'notifyCustomer' })
29
+ processOrder(@Event('{% $states.input %}') order: any) {
30
+ return { orderId: order.id, status: 'processed' };
31
+ }
32
+
33
+ @State({ end: true })
34
+ notifyCustomer(@Event('{% $states.input %}') data: any) {
35
+ console.log(`Order ${data.orderId} completed`);
36
+ }
37
+ }
38
+
39
+ // 2. Register it in a module
40
+ const orderModule = createModule({
41
+ name: 'orders',
42
+ resources: [OrderWorkflow],
43
+ });
44
+
45
+ // 3. Add the resolver to your app
46
+ createApp({
47
+ name: 'my-app',
48
+ resolvers: [new StateMachineResolver()],
49
+ modules: [orderModule],
50
+ });
51
+ ```
52
+
53
+ ## Features
54
+
55
+ ### Defining a State Machine
56
+
57
+ Use the `@StateMachine` decorator to mark a class as a state machine resource. The `startAt` property defines the entry point of the workflow and must reference either a method name or an inline state definition.
58
+
59
+ ```typescript
60
+ import { StateMachine, State } from '@lafken/state-machine/main';
61
+
62
+ @StateMachine({
63
+ startAt: 'validate',
64
+ })
65
+ export class PaymentWorkflow {
66
+ @State({ next: 'charge' })
67
+ validate(@Event('{% $states.input %}') input: any) {
68
+ return { amount: input.amount, valid: true };
69
+ }
70
+
71
+ @State({ end: true })
72
+ charge(@Event('{% $states.input %}') input: any) {
73
+ return { charged: input.amount };
74
+ }
75
+ }
76
+ ```
77
+
78
+ You can also start with a declarative state instead of a Lambda task:
79
+
80
+ ```typescript
81
+ @StateMachine({
82
+ startAt: {
83
+ type: 'wait',
84
+ seconds: 5,
85
+ next: { type: 'succeed' },
86
+ },
87
+ })
88
+ export class DelayedWorkflow {}
89
+ ```
90
+
91
+ ### Lambda Tasks
92
+
93
+ The `@State` decorator turns a method into a Lambda-backed task within the state machine. Step Functions will invoke the Lambda automatically during execution.
94
+
95
+ Use `next` to chain to the following state, or `end: true` to mark it as a terminal state:
96
+
97
+ ```typescript
98
+ @StateMachine({ startAt: 'enrich' })
99
+ export class DataPipeline {
100
+ @State({ next: 'store' })
101
+ enrich(@Event('{% $states.input %}') record: any) {
102
+ return { ...record, enrichedAt: new Date().toISOString() };
103
+ }
104
+
105
+ @State({ end: true })
106
+ store(@Event('{% $states.input %}') record: any) {
107
+ console.log('Storing record:', record);
108
+ }
109
+ }
110
+ ```
111
+
112
+ #### Output Transformation
113
+
114
+ Use the `output` option to transform a state's result before passing it to the next state. It accepts a JSONata expression or a plain object:
115
+
116
+ ```typescript
117
+ @State({
118
+ next: 'process',
119
+ output: '{% $states.result.data %}',
120
+ })
121
+ fetchData() {
122
+ return { data: { items: [1, 2, 3] }, metadata: {} };
123
+ }
124
+ ```
125
+
126
+ #### State Assignment
127
+
128
+ Use `assign` to add or update values in the state machine context. Assigned values persist across subsequent states:
129
+
130
+ ```typescript
131
+ @State({
132
+ next: 'sendEmail',
133
+ assign: { attemptCount: '{% $states.input.attemptCount + 1 %}' },
134
+ })
135
+ retry(@Event('{% $states.input %}') input: any) {
136
+ return input;
137
+ }
138
+ ```
139
+
140
+ ### AWS Service Integrations
141
+
142
+ Instead of invoking a Lambda function, a state can directly call an AWS service API. Use the `integrationResource` property to specify the service ARN, and the `@IntegrationOptions` decorator to access resource references.
143
+
144
+ This pattern eliminates the need for intermediate Lambda functions when you just need to call an AWS service (DynamoDB, SQS, SNS, etc.).
145
+
146
+ ```typescript
147
+ import {
148
+ StateMachine,
149
+ State,
150
+ Event,
151
+ type IntegrationOptionsParams,
152
+ } from '@lafken/state-machine/main';
153
+ import { IntegrationOptions } from '@lafken/api/main';
154
+
155
+ @StateMachine({
156
+ startAt: 'saveItem',
157
+ services: ['dynamodb'],
158
+ })
159
+ export class InventoryWorkflow {
160
+ @State({
161
+ integrationResource: 'arn:aws:states:::dynamodb:putItem',
162
+ next: 'confirm',
163
+ })
164
+ saveItem(@IntegrationOptions() { getResourceValue }: IntegrationOptionsParams) {
165
+ return {
166
+ TableName: getResourceValue('dynamo::inventory', 'id'),
167
+ Item: {
168
+ sku: { S: '{% $states.input.sku %}' },
169
+ quantity: { N: '{% $string($states.input.quantity) %}' },
170
+ },
171
+ };
172
+ }
173
+
174
+ @State({ end: true })
175
+ confirm(@Event('{% $states.input %}') e: any) {
176
+ console.log('Item saved successfully');
177
+ }
178
+ }
179
+ ```
180
+
181
+ A read example using `getItem`:
182
+
183
+ ```typescript
184
+ @State({
185
+ integrationResource: 'arn:aws:states:::dynamodb:getItem',
186
+ next: 'processResult',
187
+ output: '{% $states.result.Item %}',
188
+ })
189
+ lookupUser(@IntegrationOptions() { getResourceValue }: IntegrationOptionsParams) {
190
+ return {
191
+ TableName: getResourceValue('dynamo::users', 'id'),
192
+ Key: {
193
+ email: { S: '{% $states.input.email %}' },
194
+ },
195
+ };
196
+ }
197
+ ```
198
+
199
+ ### Nested State Machines
200
+
201
+ Complex workflows often require sub-workflows for parallel execution or iteration over collections. Use `@NestedStateMachine` to define these embedded workflows.
202
+
203
+ #### Map State
204
+
205
+ A Map state iterates over a collection and executes a set of states for each item:
206
+
207
+ ```typescript
208
+ import { StateMachine, NestedStateMachine, State, Event } from '@lafken/state-machine/main';
209
+
210
+ @NestedStateMachine({
211
+ startAt: 'processItem',
212
+ })
213
+ class ItemProcessor {
214
+ @State({ end: true })
215
+ processItem(@Event('{% $states.input %}') item: any) {
216
+ return { id: item.id, processed: true };
217
+ }
218
+ }
219
+
220
+ @StateMachine({
221
+ startAt: {
222
+ type: 'map',
223
+ mode: 'inline',
224
+ items: '{% $states.input.items %}',
225
+ states: ItemProcessor,
226
+ end: true,
227
+ },
228
+ })
229
+ export class BatchWorkflow {}
230
+ ```
231
+
232
+ #### Parallel State
233
+
234
+ A Parallel state runs multiple branches concurrently. Each branch is a class decorated with `@NestedStateMachine`:
235
+
236
+ ```typescript
237
+ @NestedStateMachine({ startAt: 'sendEmail' })
238
+ class EmailBranch {
239
+ @State({ end: true })
240
+ sendEmail(@Event('{% $states.input %}') e: any) {
241
+ console.log('Sending email...');
242
+ }
243
+ }
244
+
245
+ @NestedStateMachine({ startAt: 'sendSms' })
246
+ class SmsBranch {
247
+ @State({ end: true })
248
+ sendSms(@Event('{% $states.input %}') e: any) {
249
+ console.log('Sending SMS...');
250
+ }
251
+ }
252
+
253
+ @StateMachine({
254
+ startAt: {
255
+ type: 'parallel',
256
+ branches: [EmailBranch, SmsBranch],
257
+ end: true,
258
+ },
259
+ })
260
+ export class NotificationWorkflow {}
261
+ ```
262
+
263
+ ### Choice State
264
+
265
+ Use the `choice` type in `startAt` or `next` to define conditional branching based on JSONata expressions:
266
+
267
+ ```typescript
268
+ @StateMachine({
269
+ startAt: {
270
+ type: 'choice',
271
+ choices: [
272
+ {
273
+ condition: '{% $states.input.priority = "high" %}',
274
+ next: 'expedite',
275
+ },
276
+ {
277
+ condition: '{% $states.input.priority = "low" %}',
278
+ next: 'enqueue',
279
+ },
280
+ ],
281
+ default: { type: 'fail', error: 'UnknownPriority', cause: 'Priority not recognized' },
282
+ },
283
+ })
284
+ export class RoutingWorkflow {
285
+ @State({ end: true })
286
+ expedite(@Event('{% $states.input %}') e: any) {
287
+ return { routed: 'express' };
288
+ }
289
+
290
+ @State({ end: true })
291
+ enqueue(@Event('{% $states.input %}') e: any) {
292
+ return { routed: 'standard' };
293
+ }
294
+ }
295
+ ```
296
+
297
+ ### Error Handling
298
+
299
+ States support `retry` and `catch` configurations for resilient workflows:
300
+
301
+ ```typescript
302
+ @State({
303
+ next: 'done',
304
+ retry: [
305
+ {
306
+ errorEquals: ['States.TaskFailed'],
307
+ intervalSeconds: 2,
308
+ maxAttempt: 3,
309
+ backoffRate: 2,
310
+ },
311
+ ],
312
+ catch: [
313
+ {
314
+ errorEquals: ['States.ALL'],
315
+ next: { type: 'fail', error: 'ProcessingError', cause: 'Task failed after retries' },
316
+ },
317
+ ],
318
+ })
319
+ riskyOperation(@Event('{% $states.input %}') input: any) {
320
+ // This operation will be retried up to 3 times on failure
321
+ return { result: 'done' };
322
+ }
323
+ ```
324
+
325
+ ### State Events & Payloads
326
+
327
+ Each `@State` method can receive input data through the `@Event` decorator. You can pass either a JSONata expression or a typed `@Payload` class.
328
+
329
+ #### JSONata Expression
330
+
331
+ Extract or transform the incoming event inline:
332
+
333
+ ```typescript
334
+ @State({ end: true })
335
+ handle(@Event('{% $states.input.user %}') user: { name: string; role: string }) {
336
+ console.log(`User: ${user.name}, Role: ${user.role}`);
337
+ }
338
+ ```
339
+
340
+ #### Typed Payload
341
+
342
+ Define a structured payload class with `@Payload` and `@Param` decorators for clear, declarative input mapping:
343
+
344
+ ```typescript
345
+ import { Payload, Param } from '@lafken/state-machine/main';
346
+
347
+ @Payload()
348
+ export class InvoiceInput {
349
+ @Param({ context: 'input', source: 'invoiceId' })
350
+ invoiceId: string;
351
+
352
+ @Param({ context: 'input', source: 'lineItems', type: [Number] })
353
+ lineItems: number[];
354
+
355
+ @Param({ context: 'execution', source: 'id' })
356
+ executionId: string;
357
+ }
358
+
359
+ @StateMachine({ startAt: 'generateInvoice' })
360
+ export class InvoiceWorkflow {
361
+ @State({ next: 'send' })
362
+ generateInvoice(@Event(InvoiceInput) input: InvoiceInput) {
363
+ return { id: input.invoiceId, total: input.lineItems.reduce((a, b) => a + b, 0) };
364
+ }
365
+
366
+ @State({ end: true })
367
+ send(@Event('{% $states.input %}') invoice: any) {
368
+ console.log('Sending invoice:', invoice.id);
369
+ }
370
+ }
371
+ ```
372
+
373
+ Available `@Param` contexts:
374
+
375
+ | Context | Description | Example sources |
376
+ | ---------------- | ------------------------------------------- | -------------------------------------- |
377
+ | `input` | Values from the state input | Any field name (e.g. `'orderId'`) |
378
+ | `execution` | Execution metadata | `'id'`, `'name'`, `'start_time'` |
379
+ | `state` | Current state metadata | `'entered_time'`, `'name'` |
380
+ | `state_machine` | State machine metadata | `'id'`, `'name'` |
381
+ | `task` | Task metadata | `'token'` |
382
+ | `custom` | A hardcoded value | Use `value` instead of `source` |
383
+ | `jsonata` | A dynamic JSONata expression | Use `value` with a JSONata string |
package/lib/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './main';
2
+ export * from './resolver';
package/lib/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./main"), exports);
18
+ __exportStar(require("./resolver"), exports);
@@ -0,0 +1,2 @@
1
+ export * from './param';
2
+ export * from './state-machine';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./param"), exports);
18
+ __exportStar(require("./state-machine"), exports);
@@ -0,0 +1,2 @@
1
+ export * from './param';
2
+ export * from './param.types';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./param"), exports);
18
+ __exportStar(require("./param.types"), exports);
@@ -0,0 +1,105 @@
1
+ import { type ClassResource } from '@lafken/common';
2
+ import type { JsonAtaString, ParamProps } from './param.types';
3
+ export declare const stateMachineFieldKey: string;
4
+ export declare const stateMachinePayloadKey: string;
5
+ /**
6
+ * Parameter decorator that binds the incoming Step Functions state
7
+ * input to a handler method argument.
8
+ *
9
+ * The event data can come from either:
10
+ * - A class decorated with `@Payload`, which maps the incoming data
11
+ * to a typed class structure.
12
+ * - A JSONata expression string (`{%...%}`), allowing dynamic
13
+ * extraction or transformation of the event data.
14
+ *
15
+ * @typeParam E - A `@Payload` class or a JSONata string.
16
+ * @param FieldClass - The payload class or JSONata expression that
17
+ * describes how to extract the event data.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * @StateMachine()
22
+ * export class OrderFlow {
23
+ * @Task()
24
+ * validate(@Event(OrderInput) input: OrderInput) { }
25
+ *
26
+ * @Task()
27
+ * transform(@Event('{%$states.input.orderId%}') id: string) { }
28
+ * }
29
+ * ```
30
+ */
31
+ export declare const Event: <E extends ClassResource | JsonAtaString>(FieldClass: E) => (target: any, methodName: string, _number: number) => void;
32
+ /**
33
+ * Class decorator that declares a class as a Step Functions state
34
+ * input/output payload.
35
+ *
36
+ * The decorated class defines the shape of the data passed between
37
+ * states. Use `@Param` on its properties to describe where each value
38
+ * is extracted from (execution context, state input, custom value, etc.).
39
+ *
40
+ * @param props - Optional payload configuration (e.g. a custom `name`).
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * @Payload()
45
+ * export class OrderInput {
46
+ * @Param({ context: 'input', source: 'orderId' })
47
+ * orderId: string;
48
+ *
49
+ * @Param({ context: 'execution', source: 'id' })
50
+ * executionId: string;
51
+ * }
52
+ * ```
53
+ */
54
+ export declare const Payload: (props?: import("@lafken/common").PayloadProps | undefined) => (target: Function) => void;
55
+ /**
56
+ * Parameter decorator that injects the integration options
57
+ *
58
+ * Use it to receive a `GetResourceProps` object (or custom integration
59
+ * parameters) that provides access to `getResourceValue`, allowing you
60
+ * to reference other infrastructure resources (queues, buckets, tables,
61
+ * etc.) when building the integration payload returned by the handler.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * @StateMachine({ startAt: 'send' })
66
+ * export class OrderFlow {
67
+ * @State({ integrationService: 'sqs', action: 'sendMessage', mode: 'token' })
68
+ * send(@IntegrationOptions() { getResourceValue }: GetResourceProps) {
69
+ * return {
70
+ * QueueUrl: getResourceValue('queue::orders', 'id'),
71
+ * MessageBody: { message: 'new order' },
72
+ * };
73
+ * }
74
+ * }
75
+ * ```
76
+ */
77
+ export declare const IntegrationOptions: () => (target: any, methodName: string, _number: number) => void;
78
+ /**
79
+ * Property decorator that maps a class field to a value extracted from
80
+ * the Step Functions execution context.
81
+ *
82
+ * Use it inside a `@Payload` class to specify which context or source
83
+ * provides the value for the field. Supported contexts include:
84
+ * `input`, `execution`, `state`, `state_machine`, `task`, `custom`,
85
+ * and `jsonata`.
86
+ *
87
+ * @param props - Extraction configuration (context, source/value, optional
88
+ * name and type overrides).
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * @Payload()
93
+ * export class TaskInput {
94
+ * @Param({ context: 'input', source: 'userId' })
95
+ * userId: string;
96
+ *
97
+ * @Param({ context: 'execution', source: 'start_time' })
98
+ * startedAt: string;
99
+ *
100
+ * @Param({ context: 'custom', value: 'pending' })
101
+ * status: string;
102
+ * }
103
+ * ```
104
+ */
105
+ export declare const Param: (props?: ParamProps | undefined) => (target: any, destinationName: string) => void;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Param = exports.IntegrationOptions = exports.Payload = exports.Event = exports.stateMachinePayloadKey = exports.stateMachineFieldKey = void 0;
4
+ const common_1 = require("@lafken/common");
5
+ const state_machine_1 = require("../state-machine");
6
+ exports.stateMachineFieldKey = (0, common_1.createFieldName)(state_machine_1.RESOURCE_TYPE, common_1.FieldProperties.field);
7
+ exports.stateMachinePayloadKey = (0, common_1.createFieldName)(state_machine_1.RESOURCE_TYPE, common_1.FieldProperties.payload);
8
+ /**
9
+ * Parameter decorator that binds the incoming Step Functions state
10
+ * input to a handler method argument.
11
+ *
12
+ * The event data can come from either:
13
+ * - A class decorated with `@Payload`, which maps the incoming data
14
+ * to a typed class structure.
15
+ * - A JSONata expression string (`{%...%}`), allowing dynamic
16
+ * extraction or transformation of the event data.
17
+ *
18
+ * @typeParam E - A `@Payload` class or a JSONata string.
19
+ * @param FieldClass - The payload class or JSONata expression that
20
+ * describes how to extract the event data.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * @StateMachine()
25
+ * export class OrderFlow {
26
+ * @Task()
27
+ * validate(@Event(OrderInput) input: OrderInput) { }
28
+ *
29
+ * @Task()
30
+ * transform(@Event('{%$states.input.orderId%}') id: string) { }
31
+ * }
32
+ * ```
33
+ */
34
+ const Event = (FieldClass) => (0, common_1.createEventDecorator)({ prefix: state_machine_1.RESOURCE_TYPE })(FieldClass);
35
+ exports.Event = Event;
36
+ /**
37
+ * Class decorator that declares a class as a Step Functions state
38
+ * input/output payload.
39
+ *
40
+ * The decorated class defines the shape of the data passed between
41
+ * states. Use `@Param` on its properties to describe where each value
42
+ * is extracted from (execution context, state input, custom value, etc.).
43
+ *
44
+ * @param props - Optional payload configuration (e.g. a custom `name`).
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * @Payload()
49
+ * export class OrderInput {
50
+ * @Param({ context: 'input', source: 'orderId' })
51
+ * orderId: string;
52
+ *
53
+ * @Param({ context: 'execution', source: 'id' })
54
+ * executionId: string;
55
+ * }
56
+ * ```
57
+ */
58
+ exports.Payload = (0, common_1.createPayloadDecorator)({
59
+ prefix: state_machine_1.RESOURCE_TYPE,
60
+ createUniqueId: false,
61
+ });
62
+ /**
63
+ * Parameter decorator that injects the integration options
64
+ *
65
+ * Use it to receive a `GetResourceProps` object (or custom integration
66
+ * parameters) that provides access to `getResourceValue`, allowing you
67
+ * to reference other infrastructure resources (queues, buckets, tables,
68
+ * etc.) when building the integration payload returned by the handler.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * @StateMachine({ startAt: 'send' })
73
+ * export class OrderFlow {
74
+ * @State({ integrationService: 'sqs', action: 'sendMessage', mode: 'token' })
75
+ * send(@IntegrationOptions() { getResourceValue }: GetResourceProps) {
76
+ * return {
77
+ * QueueUrl: getResourceValue('queue::orders', 'id'),
78
+ * MessageBody: { message: 'new order' },
79
+ * };
80
+ * }
81
+ * }
82
+ * ```
83
+ */
84
+ exports.IntegrationOptions = common_1.Context;
85
+ /**
86
+ * Property decorator that maps a class field to a value extracted from
87
+ * the Step Functions execution context.
88
+ *
89
+ * Use it inside a `@Payload` class to specify which context or source
90
+ * provides the value for the field. Supported contexts include:
91
+ * `input`, `execution`, `state`, `state_machine`, `task`, `custom`,
92
+ * and `jsonata`.
93
+ *
94
+ * @param props - Extraction configuration (context, source/value, optional
95
+ * name and type overrides).
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * @Payload()
100
+ * export class TaskInput {
101
+ * @Param({ context: 'input', source: 'userId' })
102
+ * userId: string;
103
+ *
104
+ * @Param({ context: 'execution', source: 'start_time' })
105
+ * startedAt: string;
106
+ *
107
+ * @Param({ context: 'custom', value: 'pending' })
108
+ * status: string;
109
+ * }
110
+ * ```
111
+ */
112
+ exports.Param = (0, common_1.createFieldDecorator)({
113
+ prefix: state_machine_1.RESOURCE_TYPE,
114
+ getMetadata: (props) => props,
115
+ });