@moostjs/event-wf 0.6.16 → 0.6.18

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.
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  let _wooksjs_event_wf = require("@wooksjs/event-wf");
3
3
  let moost = require("moost");
4
4
  let _prostojs_wf = require("@prostojs/wf");
5
- let node_crypto = require("node:crypto");
5
+ let _prostojs_wf_outlets = require("@prostojs/wf/outlets");
6
6
 
7
7
  //#region packages/event-wf/src/meta-types.ts
8
8
  function getWfMate() {
@@ -127,7 +127,7 @@ const CONTEXT_TYPE = "WF";
127
127
  * ```ts
128
128
  * const wf = new MoostWf()
129
129
  * app.adapter(wf).controllers(MyWorkflows).init()
130
- * const result = await wf.start('my-flow', {}, input)
130
+ * const result = await wf.start('my-flow', {}, { input })
131
131
  * ```
132
132
  */ var MoostWf = class {
133
133
  async onNotFound() {
@@ -169,8 +169,8 @@ const CONTEXT_TYPE = "WF";
169
169
  * @returns The outlet result (form payload + token), finished response, or error.
170
170
  */ handleOutlet(config) {
171
171
  return (0, _wooksjs_event_wf.handleWfOutletRequest)(config, {
172
- start: (schemaId, context, opts) => this.start(schemaId, context, opts?.input),
173
- resume: (state, opts) => this.resume(state, opts?.input)
172
+ start: (schemaId, context, opts) => this.start(schemaId, context, opts),
173
+ resume: (state, opts) => this.resume(state, opts)
174
174
  });
175
175
  }
176
176
  /**
@@ -178,10 +178,14 @@ const CONTEXT_TYPE = "WF";
178
178
  *
179
179
  * @param schemaId - Identifier of the registered workflow schema.
180
180
  * @param initialContext - Initial context data for the workflow.
181
- * @param input - Optional input passed to the first step.
182
- */ start(schemaId, initialContext, input) {
181
+ * @param opts - Optional run options: `input` for the first step, `eventContext`
182
+ * to link this run to a parent event scope (e.g. an HTTP request), and
183
+ * `strategy.name` to pick the initial state strategy. Passing a bare
184
+ * `input` value (legacy positional form) is no longer supported — wrap it
185
+ * in `{ input }`.
186
+ */ start(schemaId, initialContext, opts) {
183
187
  return this.wfApp.start(schemaId, initialContext, {
184
- input,
188
+ ...opts,
185
189
  cleanup: () => {
186
190
  (0, moost.getMoostInfact)().unregisterScope((0, moost.useScopeId)());
187
191
  }
@@ -191,10 +195,12 @@ const CONTEXT_TYPE = "WF";
191
195
  * Resumes a previously paused workflow from a saved state.
192
196
  *
193
197
  * @param state - Saved workflow state containing schema, context, and step indexes.
194
- * @param input - Optional input for the resumed step.
195
- */ resume(state, input) {
198
+ * @param opts - Optional run options: `input` for the resumed step, `eventContext`
199
+ * for parent-chain composable access, and `strategy.name` for the strategy
200
+ * that loaded this state. Legacy positional `input` is no longer supported.
201
+ */ resume(state, opts) {
196
202
  return this.wfApp.resume(state, {
197
- input,
203
+ ...opts,
198
204
  cleanup: () => {
199
205
  (0, moost.getMoostInfact)().unregisterScope((0, moost.useScopeId)());
200
206
  }
@@ -269,185 +275,18 @@ const CONTEXT_TYPE = "WF";
269
275
  };
270
276
 
271
277
  //#endregion
272
- //#region node_modules/.pnpm/@prostojs+wf@0.1.1/node_modules/@prostojs/wf/dist/outlets/index.mjs
273
- /**
274
- * Generic outlet request. Use for custom outlets.
275
- *
276
- * @example
277
- * return outlet('pending-task', {
278
- * payload: ApprovalForm,
279
- * target: managerId,
280
- * context: { orderId, amount },
281
- * })
282
- */
283
- function outlet(name, data) {
284
- return { inputRequired: {
285
- outlet: name,
286
- ...data
287
- } };
288
- }
289
- /**
290
- * Pause for HTTP form input. The outlet returns the payload (form definition)
291
- * and state token in the HTTP response.
292
- *
293
- * @example
294
- * return outletHttp(LoginForm)
295
- * return outletHttp(LoginForm, { error: 'Invalid credentials' })
296
- */
297
- function outletHttp(payload, context) {
298
- return outlet("http", {
299
- payload,
300
- context
301
- });
302
- }
303
- /**
304
- * Pause and send email with a magic link containing the state token.
305
- *
306
- * @example
307
- * return outletEmail('user@test.com', 'invite', { name: 'Alice' })
308
- */
309
- function outletEmail(target, template, context) {
310
- return outlet("email", {
311
- target,
312
- template,
313
- context
314
- });
315
- }
316
- /**
317
- * Self-contained AES-256-GCM encrypted state strategy.
318
- *
319
- * Workflow state is encrypted into a base64url token that travels with the
320
- * transport (cookie, URL param, hidden field). No server-side storage needed.
321
- *
322
- * Token format: `base64url(iv[12] + authTag[16] + ciphertext)`
323
- *
324
- * @example
325
- * const strategy = new EncapsulatedStateStrategy({
326
- * secret: crypto.randomBytes(32),
327
- * defaultTtl: 3600_000, // 1 hour
328
- * });
329
- * const token = await strategy.persist(state);
330
- * const recovered = await strategy.retrieve(token);
331
- */
332
- var EncapsulatedStateStrategy = class {
333
- /** @throws if secret is not exactly 32 bytes */
334
- constructor(config) {
335
- this.config = config;
336
- this.key = typeof config.secret === "string" ? Buffer.from(config.secret, "hex") : config.secret;
337
- if (this.key.length !== 32) throw new Error("EncapsulatedStateStrategy: secret must be exactly 32 bytes");
338
- }
339
- /**
340
- * Encrypt workflow state into a self-contained token.
341
- * @param state — workflow state to persist
342
- * @param options.ttl — time-to-live in ms (overrides defaultTtl)
343
- * @returns base64url-encoded encrypted token
344
- */
345
- async persist(state, options) {
346
- const ttl = options?.ttl ?? this.config.defaultTtl ?? 0;
347
- const exp = ttl > 0 ? Date.now() + ttl : 0;
348
- const payload = JSON.stringify({
349
- s: state,
350
- e: exp
351
- });
352
- const iv = (0, node_crypto.randomBytes)(12);
353
- const cipher = (0, node_crypto.createCipheriv)("aes-256-gcm", this.key, iv);
354
- const encrypted = Buffer.concat([cipher.update(payload, "utf8"), cipher.final()]);
355
- const tag = cipher.getAuthTag();
356
- return Buffer.concat([
357
- iv,
358
- tag,
359
- encrypted
360
- ]).toString("base64url");
361
- }
362
- /** Decrypt and return workflow state. Returns null if token is invalid, expired, or tampered. */
363
- async retrieve(token) {
364
- return this.decrypt(token);
365
- }
366
- /** Same as retrieve (stateless — cannot truly invalidate a token). */
367
- async consume(token) {
368
- return this.decrypt(token);
369
- }
370
- decrypt(token) {
371
- try {
372
- const buf = Buffer.from(token, "base64url");
373
- if (buf.length < 28) return null;
374
- const iv = buf.subarray(0, 12);
375
- const tag = buf.subarray(12, 28);
376
- const ciphertext = buf.subarray(28);
377
- const decipher = (0, node_crypto.createDecipheriv)("aes-256-gcm", this.key, iv);
378
- decipher.setAuthTag(tag);
379
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
380
- const { s: state, e: exp } = JSON.parse(decrypted.toString("utf8"));
381
- if (exp > 0 && Date.now() > exp) return null;
382
- return state;
383
- } catch {
384
- return null;
385
- }
386
- }
387
- };
388
- var HandleStateStrategy = class {
389
- constructor(config) {
390
- this.config = config;
391
- }
392
- async persist(state, options) {
393
- const handle = (this.config.generateHandle ?? node_crypto.randomUUID)();
394
- const ttl = options?.ttl ?? this.config.defaultTtl ?? 0;
395
- const expiresAt = ttl > 0 ? Date.now() + ttl : void 0;
396
- await this.config.store.set(handle, state, expiresAt);
397
- return handle;
398
- }
399
- async retrieve(token) {
400
- return (await this.config.store.get(token))?.state ?? null;
401
- }
402
- async consume(token) {
403
- return (await this.config.store.getAndDelete(token))?.state ?? null;
404
- }
405
- };
406
- /**
407
- * In-memory state store for development and testing.
408
- * State is lost on process restart.
409
- */
410
- var WfStateStoreMemory = class {
411
- constructor() {
412
- this.store = /* @__PURE__ */ new Map();
413
- }
414
- async set(handle, state, expiresAt) {
415
- this.store.set(handle, {
416
- state,
417
- expiresAt
418
- });
419
- }
420
- async get(handle) {
421
- const entry = this.store.get(handle);
422
- if (!entry) return null;
423
- if (entry.expiresAt && Date.now() > entry.expiresAt) {
424
- this.store.delete(handle);
425
- return null;
426
- }
427
- return entry;
428
- }
429
- async delete(handle) {
430
- this.store.delete(handle);
431
- }
432
- async getAndDelete(handle) {
433
- const entry = await this.get(handle);
434
- if (entry) this.store.delete(handle);
435
- return entry;
436
- }
437
- async cleanup() {
438
- const now = Date.now();
439
- let count = 0;
440
- for (const [handle, entry] of this.store) if (entry.expiresAt && now > entry.expiresAt) {
441
- this.store.delete(handle);
442
- count++;
443
- }
444
- return count;
445
- }
446
- };
447
-
448
- //#endregion
449
- exports.EncapsulatedStateStrategy = EncapsulatedStateStrategy;
450
- exports.HandleStateStrategy = HandleStateStrategy;
278
+ Object.defineProperty(exports, 'EncapsulatedStateStrategy', {
279
+ enumerable: true,
280
+ get: function () {
281
+ return _prostojs_wf_outlets.EncapsulatedStateStrategy;
282
+ }
283
+ });
284
+ Object.defineProperty(exports, 'HandleStateStrategy', {
285
+ enumerable: true,
286
+ get: function () {
287
+ return _prostojs_wf_outlets.HandleStateStrategy;
288
+ }
289
+ });
451
290
  exports.MoostWf = MoostWf;
452
291
  exports.Step = Step;
453
292
  Object.defineProperty(exports, 'StepRetriableError', {
@@ -457,7 +296,12 @@ Object.defineProperty(exports, 'StepRetriableError', {
457
296
  }
458
297
  });
459
298
  exports.StepTTL = StepTTL;
460
- exports.WfStateStoreMemory = WfStateStoreMemory;
299
+ Object.defineProperty(exports, 'WfStateStoreMemory', {
300
+ enumerable: true,
301
+ get: function () {
302
+ return _prostojs_wf_outlets.WfStateStoreMemory;
303
+ }
304
+ });
461
305
  exports.Workflow = Workflow;
462
306
  exports.WorkflowParam = WorkflowParam;
463
307
  exports.WorkflowSchema = WorkflowSchema;
@@ -485,9 +329,30 @@ Object.defineProperty(exports, 'handleWfOutletRequest', {
485
329
  return _wooksjs_event_wf.handleWfOutletRequest;
486
330
  }
487
331
  });
488
- exports.outlet = outlet;
489
- exports.outletEmail = outletEmail;
490
- exports.outletHttp = outletHttp;
332
+ Object.defineProperty(exports, 'outlet', {
333
+ enumerable: true,
334
+ get: function () {
335
+ return _prostojs_wf_outlets.outlet;
336
+ }
337
+ });
338
+ Object.defineProperty(exports, 'outletEmail', {
339
+ enumerable: true,
340
+ get: function () {
341
+ return _prostojs_wf_outlets.outletEmail;
342
+ }
343
+ });
344
+ Object.defineProperty(exports, 'outletHttp', {
345
+ enumerable: true,
346
+ get: function () {
347
+ return _prostojs_wf_outlets.outletHttp;
348
+ }
349
+ });
350
+ Object.defineProperty(exports, 'swapStrategy', {
351
+ enumerable: true,
352
+ get: function () {
353
+ return _wooksjs_event_wf.swapStrategy;
354
+ }
355
+ });
491
356
  Object.defineProperty(exports, 'useWfFinished', {
492
357
  enumerable: true,
493
358
  get: function () {
@@ -506,6 +371,12 @@ Object.defineProperty(exports, 'useWfState', {
506
371
  return _wooksjs_event_wf.useWfState;
507
372
  }
508
373
  });
374
+ Object.defineProperty(exports, 'useWfStrategy', {
375
+ enumerable: true,
376
+ get: function () {
377
+ return _wooksjs_event_wf.useWfStrategy;
378
+ }
379
+ });
509
380
  Object.defineProperty(exports, 'wfKind', {
510
381
  enumerable: true,
511
382
  get: function () {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { TWorkflowSchema, TWorkflowSpy, TFlowOutput } from '@prostojs/wf';
2
2
  export { StepRetriableError, TFlowOutput, TWorkflowSchema } from '@prostojs/wf';
3
- import { WooksWf, TWooksWfOptions, WfOutletTriggerConfig } from '@wooksjs/event-wf';
4
- export { WfFinishedResponse, WfOutletTokenConfig, WfOutletTriggerConfig, WfOutletTriggerDeps, createEmailOutlet, createHttpOutlet, createOutletHandler, handleWfOutletRequest, useWfFinished, useWfOutlet, useWfState, wfKind } from '@wooksjs/event-wf';
3
+ import { WooksWf, TWooksWfOptions, WfOutletTriggerConfig, TWfRunOptions } from '@wooksjs/event-wf';
4
+ export { WfFinishedResponse, WfOutletTokenConfig, WfOutletTriggerConfig, WfOutletTriggerDeps, WfPauseRequest, createEmailOutlet, createHttpOutlet, createOutletHandler, handleWfOutletRequest, swapStrategy, useWfFinished, useWfOutlet, useWfState, useWfStrategy, wfKind } from '@wooksjs/event-wf';
5
5
  import { TMoostAdapter, Moost, TMoostAdapterOptions } from 'moost';
6
6
  export { EncapsulatedStateStrategy, HandleStateStrategy, WfOutlet, WfOutletRequest, WfOutletResult, WfState, WfStateStore, WfStateStoreMemory, WfStateStrategy, outlet, outletEmail, outletHttp } from '@prostojs/wf/outlets';
7
7
 
@@ -91,7 +91,7 @@ interface TWfHandlerMeta {
91
91
  * ```ts
92
92
  * const wf = new MoostWf()
93
93
  * app.adapter(wf).controllers(MyWorkflows).init()
94
- * const result = await wf.start('my-flow', {}, input)
94
+ * const result = await wf.start('my-flow', {}, { input })
95
95
  * ```
96
96
  */
97
97
  declare class MoostWf<T = any, IR = any> implements TMoostAdapter<TWfHandlerMeta> {
@@ -128,20 +128,26 @@ declare class MoostWf<T = any, IR = any> implements TMoostAdapter<TWfHandlerMeta
128
128
  *
129
129
  * @param schemaId - Identifier of the registered workflow schema.
130
130
  * @param initialContext - Initial context data for the workflow.
131
- * @param input - Optional input passed to the first step.
131
+ * @param opts - Optional run options: `input` for the first step, `eventContext`
132
+ * to link this run to a parent event scope (e.g. an HTTP request), and
133
+ * `strategy.name` to pick the initial state strategy. Passing a bare
134
+ * `input` value (legacy positional form) is no longer supported — wrap it
135
+ * in `{ input }`.
132
136
  */
133
- start<I>(schemaId: string, initialContext: T, input?: I): Promise<TFlowOutput<T, I, IR>>;
137
+ start<I>(schemaId: string, initialContext: T, opts?: TWfRunOptions<I, T, IR>): Promise<TFlowOutput<T, I, IR>>;
134
138
  /**
135
139
  * Resumes a previously paused workflow from a saved state.
136
140
  *
137
141
  * @param state - Saved workflow state containing schema, context, and step indexes.
138
- * @param input - Optional input for the resumed step.
142
+ * @param opts - Optional run options: `input` for the resumed step, `eventContext`
143
+ * for parent-chain composable access, and `strategy.name` for the strategy
144
+ * that loaded this state. Legacy positional `input` is no longer supported.
139
145
  */
140
146
  resume<I>(state: {
141
147
  schemaId: string;
142
148
  context: T;
143
149
  indexes: number[];
144
- }, input?: I): Promise<TFlowOutput<T, I, IR>>;
150
+ }, opts?: TWfRunOptions<I, T, IR>): Promise<TFlowOutput<T, I, IR>>;
145
151
  bindHandler<T extends object = object>(opts: TMoostAdapterOptions<TWfHandlerMeta, T>): void;
146
152
  }
147
153
 
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { WooksWf, createEmailOutlet, createHttpOutlet, createOutletHandler, createWfApp, handleWfOutletRequest, handleWfOutletRequest as handleWfOutletRequest$1, useWfFinished, useWfOutlet, useWfState, useWfState as useWfState$1, wfKind } from "@wooksjs/event-wf";
1
+ import { WooksWf, createEmailOutlet, createHttpOutlet, createOutletHandler, createWfApp, handleWfOutletRequest, handleWfOutletRequest as handleWfOutletRequest$1, swapStrategy, useWfFinished, useWfOutlet, useWfState, useWfState as useWfState$1, useWfStrategy, wfKind } from "@wooksjs/event-wf";
2
2
  import { Resolve, defineMoostEventHandler, getMoostInfact, getMoostMate, setControllerContext, useScopeId } from "moost";
3
3
  import { StepRetriableError } from "@prostojs/wf";
4
- import { createCipheriv, createDecipheriv, randomBytes, randomUUID } from "node:crypto";
4
+ import { EncapsulatedStateStrategy, HandleStateStrategy, WfStateStoreMemory, outlet, outletEmail, outletHttp } from "@prostojs/wf/outlets";
5
5
 
6
6
  //#region packages/event-wf/src/meta-types.ts
7
7
  function getWfMate() {
@@ -126,7 +126,7 @@ const CONTEXT_TYPE = "WF";
126
126
  * ```ts
127
127
  * const wf = new MoostWf()
128
128
  * app.adapter(wf).controllers(MyWorkflows).init()
129
- * const result = await wf.start('my-flow', {}, input)
129
+ * const result = await wf.start('my-flow', {}, { input })
130
130
  * ```
131
131
  */ var MoostWf = class {
132
132
  async onNotFound() {
@@ -168,8 +168,8 @@ const CONTEXT_TYPE = "WF";
168
168
  * @returns The outlet result (form payload + token), finished response, or error.
169
169
  */ handleOutlet(config) {
170
170
  return handleWfOutletRequest$1(config, {
171
- start: (schemaId, context, opts) => this.start(schemaId, context, opts?.input),
172
- resume: (state, opts) => this.resume(state, opts?.input)
171
+ start: (schemaId, context, opts) => this.start(schemaId, context, opts),
172
+ resume: (state, opts) => this.resume(state, opts)
173
173
  });
174
174
  }
175
175
  /**
@@ -177,10 +177,14 @@ const CONTEXT_TYPE = "WF";
177
177
  *
178
178
  * @param schemaId - Identifier of the registered workflow schema.
179
179
  * @param initialContext - Initial context data for the workflow.
180
- * @param input - Optional input passed to the first step.
181
- */ start(schemaId, initialContext, input) {
180
+ * @param opts - Optional run options: `input` for the first step, `eventContext`
181
+ * to link this run to a parent event scope (e.g. an HTTP request), and
182
+ * `strategy.name` to pick the initial state strategy. Passing a bare
183
+ * `input` value (legacy positional form) is no longer supported — wrap it
184
+ * in `{ input }`.
185
+ */ start(schemaId, initialContext, opts) {
182
186
  return this.wfApp.start(schemaId, initialContext, {
183
- input,
187
+ ...opts,
184
188
  cleanup: () => {
185
189
  getMoostInfact().unregisterScope(useScopeId());
186
190
  }
@@ -190,10 +194,12 @@ const CONTEXT_TYPE = "WF";
190
194
  * Resumes a previously paused workflow from a saved state.
191
195
  *
192
196
  * @param state - Saved workflow state containing schema, context, and step indexes.
193
- * @param input - Optional input for the resumed step.
194
- */ resume(state, input) {
197
+ * @param opts - Optional run options: `input` for the resumed step, `eventContext`
198
+ * for parent-chain composable access, and `strategy.name` for the strategy
199
+ * that loaded this state. Legacy positional `input` is no longer supported.
200
+ */ resume(state, opts) {
195
201
  return this.wfApp.resume(state, {
196
- input,
202
+ ...opts,
197
203
  cleanup: () => {
198
204
  getMoostInfact().unregisterScope(useScopeId());
199
205
  }
@@ -268,181 +274,4 @@ const CONTEXT_TYPE = "WF";
268
274
  };
269
275
 
270
276
  //#endregion
271
- //#region node_modules/.pnpm/@prostojs+wf@0.1.1/node_modules/@prostojs/wf/dist/outlets/index.mjs
272
- /**
273
- * Generic outlet request. Use for custom outlets.
274
- *
275
- * @example
276
- * return outlet('pending-task', {
277
- * payload: ApprovalForm,
278
- * target: managerId,
279
- * context: { orderId, amount },
280
- * })
281
- */
282
- function outlet(name, data) {
283
- return { inputRequired: {
284
- outlet: name,
285
- ...data
286
- } };
287
- }
288
- /**
289
- * Pause for HTTP form input. The outlet returns the payload (form definition)
290
- * and state token in the HTTP response.
291
- *
292
- * @example
293
- * return outletHttp(LoginForm)
294
- * return outletHttp(LoginForm, { error: 'Invalid credentials' })
295
- */
296
- function outletHttp(payload, context) {
297
- return outlet("http", {
298
- payload,
299
- context
300
- });
301
- }
302
- /**
303
- * Pause and send email with a magic link containing the state token.
304
- *
305
- * @example
306
- * return outletEmail('user@test.com', 'invite', { name: 'Alice' })
307
- */
308
- function outletEmail(target, template, context) {
309
- return outlet("email", {
310
- target,
311
- template,
312
- context
313
- });
314
- }
315
- /**
316
- * Self-contained AES-256-GCM encrypted state strategy.
317
- *
318
- * Workflow state is encrypted into a base64url token that travels with the
319
- * transport (cookie, URL param, hidden field). No server-side storage needed.
320
- *
321
- * Token format: `base64url(iv[12] + authTag[16] + ciphertext)`
322
- *
323
- * @example
324
- * const strategy = new EncapsulatedStateStrategy({
325
- * secret: crypto.randomBytes(32),
326
- * defaultTtl: 3600_000, // 1 hour
327
- * });
328
- * const token = await strategy.persist(state);
329
- * const recovered = await strategy.retrieve(token);
330
- */
331
- var EncapsulatedStateStrategy = class {
332
- /** @throws if secret is not exactly 32 bytes */
333
- constructor(config) {
334
- this.config = config;
335
- this.key = typeof config.secret === "string" ? Buffer.from(config.secret, "hex") : config.secret;
336
- if (this.key.length !== 32) throw new Error("EncapsulatedStateStrategy: secret must be exactly 32 bytes");
337
- }
338
- /**
339
- * Encrypt workflow state into a self-contained token.
340
- * @param state — workflow state to persist
341
- * @param options.ttl — time-to-live in ms (overrides defaultTtl)
342
- * @returns base64url-encoded encrypted token
343
- */
344
- async persist(state, options) {
345
- const ttl = options?.ttl ?? this.config.defaultTtl ?? 0;
346
- const exp = ttl > 0 ? Date.now() + ttl : 0;
347
- const payload = JSON.stringify({
348
- s: state,
349
- e: exp
350
- });
351
- const iv = randomBytes(12);
352
- const cipher = createCipheriv("aes-256-gcm", this.key, iv);
353
- const encrypted = Buffer.concat([cipher.update(payload, "utf8"), cipher.final()]);
354
- const tag = cipher.getAuthTag();
355
- return Buffer.concat([
356
- iv,
357
- tag,
358
- encrypted
359
- ]).toString("base64url");
360
- }
361
- /** Decrypt and return workflow state. Returns null if token is invalid, expired, or tampered. */
362
- async retrieve(token) {
363
- return this.decrypt(token);
364
- }
365
- /** Same as retrieve (stateless — cannot truly invalidate a token). */
366
- async consume(token) {
367
- return this.decrypt(token);
368
- }
369
- decrypt(token) {
370
- try {
371
- const buf = Buffer.from(token, "base64url");
372
- if (buf.length < 28) return null;
373
- const iv = buf.subarray(0, 12);
374
- const tag = buf.subarray(12, 28);
375
- const ciphertext = buf.subarray(28);
376
- const decipher = createDecipheriv("aes-256-gcm", this.key, iv);
377
- decipher.setAuthTag(tag);
378
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
379
- const { s: state, e: exp } = JSON.parse(decrypted.toString("utf8"));
380
- if (exp > 0 && Date.now() > exp) return null;
381
- return state;
382
- } catch {
383
- return null;
384
- }
385
- }
386
- };
387
- var HandleStateStrategy = class {
388
- constructor(config) {
389
- this.config = config;
390
- }
391
- async persist(state, options) {
392
- const handle = (this.config.generateHandle ?? randomUUID)();
393
- const ttl = options?.ttl ?? this.config.defaultTtl ?? 0;
394
- const expiresAt = ttl > 0 ? Date.now() + ttl : void 0;
395
- await this.config.store.set(handle, state, expiresAt);
396
- return handle;
397
- }
398
- async retrieve(token) {
399
- return (await this.config.store.get(token))?.state ?? null;
400
- }
401
- async consume(token) {
402
- return (await this.config.store.getAndDelete(token))?.state ?? null;
403
- }
404
- };
405
- /**
406
- * In-memory state store for development and testing.
407
- * State is lost on process restart.
408
- */
409
- var WfStateStoreMemory = class {
410
- constructor() {
411
- this.store = /* @__PURE__ */ new Map();
412
- }
413
- async set(handle, state, expiresAt) {
414
- this.store.set(handle, {
415
- state,
416
- expiresAt
417
- });
418
- }
419
- async get(handle) {
420
- const entry = this.store.get(handle);
421
- if (!entry) return null;
422
- if (entry.expiresAt && Date.now() > entry.expiresAt) {
423
- this.store.delete(handle);
424
- return null;
425
- }
426
- return entry;
427
- }
428
- async delete(handle) {
429
- this.store.delete(handle);
430
- }
431
- async getAndDelete(handle) {
432
- const entry = await this.get(handle);
433
- if (entry) this.store.delete(handle);
434
- return entry;
435
- }
436
- async cleanup() {
437
- const now = Date.now();
438
- let count = 0;
439
- for (const [handle, entry] of this.store) if (entry.expiresAt && now > entry.expiresAt) {
440
- this.store.delete(handle);
441
- count++;
442
- }
443
- return count;
444
- }
445
- };
446
-
447
- //#endregion
448
- export { EncapsulatedStateStrategy, HandleStateStrategy, MoostWf, Step, StepRetriableError, StepTTL, WfStateStoreMemory, Workflow, WorkflowParam, WorkflowSchema, createEmailOutlet, createHttpOutlet, createOutletHandler, handleWfOutletRequest, outlet, outletEmail, outletHttp, useWfFinished, useWfOutlet, useWfState, wfKind };
277
+ export { EncapsulatedStateStrategy, HandleStateStrategy, MoostWf, Step, StepRetriableError, StepTTL, WfStateStoreMemory, Workflow, WorkflowParam, WorkflowSchema, createEmailOutlet, createHttpOutlet, createOutletHandler, handleWfOutletRequest, outlet, outletEmail, outletHttp, swapStrategy, useWfFinished, useWfOutlet, useWfState, useWfStrategy, wfKind };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moostjs/event-wf",
3
- "version": "0.6.16",
3
+ "version": "0.6.18",
4
4
  "description": "@moostjs/event-wf",
5
5
  "keywords": [
6
6
  "composables",
@@ -38,8 +38,8 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@prostojs/wf": "^0.1.1",
42
- "@wooksjs/event-wf": "^0.7.14"
41
+ "@prostojs/wf": "^0.2.1",
42
+ "@wooksjs/event-wf": "^0.7.16"
43
43
  },
44
44
  "devDependencies": {
45
45
  "vitest": "3.2.4"
@@ -47,9 +47,9 @@
47
47
  "peerDependencies": {
48
48
  "@prostojs/infact": "^0.4.1",
49
49
  "@prostojs/mate": "^0.4.0",
50
- "@wooksjs/event-core": "^0.7.14",
51
- "wooks": "^0.7.14",
52
- "moost": "^0.6.16"
50
+ "@wooksjs/event-core": "^0.7.16",
51
+ "wooks": "^0.7.16",
52
+ "moost": "^0.6.18"
53
53
  },
54
54
  "scripts": {
55
55
  "pub": "pnpm publish --access public",