@wooksjs/event-wf 0.7.9 → 0.7.11
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 +64 -34
- package/dist/index.d.ts +21 -11
- package/dist/index.mjs +64 -34
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -120,7 +120,6 @@ const useWfFinished = (0, __wooksjs_event_core.defineWook)((ctx) => ({
|
|
|
120
120
|
|
|
121
121
|
//#endregion
|
|
122
122
|
//#region packages/event-wf/src/outlets/trigger.ts
|
|
123
|
-
const DEFAULT_CONSUME_TOKEN = { email: true };
|
|
124
123
|
/**
|
|
125
124
|
* Handle an HTTP request that starts or resumes a workflow.
|
|
126
125
|
*
|
|
@@ -168,38 +167,32 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
168
167
|
const wfid = body?.[wfidName] ?? queryParams.get(wfidName) ?? void 0;
|
|
169
168
|
const input = body?.input;
|
|
170
169
|
const resolveStrategy = (id) => typeof config.state === "function" ? config.state(id) : config.state;
|
|
171
|
-
const shouldConsume = (outletName) => {
|
|
172
|
-
if (typeof tok.consume === "boolean") return tok.consume;
|
|
173
|
-
return (tok.consume ?? DEFAULT_CONSUME_TOKEN)[outletName] ?? false;
|
|
174
|
-
};
|
|
175
170
|
let output;
|
|
176
171
|
if (token) {
|
|
177
172
|
const strategy = resolveStrategy(wfid ?? "");
|
|
178
173
|
ctx.set(stateStrategyKey, strategy);
|
|
179
|
-
const state = await strategy.
|
|
180
|
-
if (!state)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
174
|
+
const state = await strategy.consume(token);
|
|
175
|
+
if (!state) {
|
|
176
|
+
response.setStatus(410);
|
|
177
|
+
return { error: "Invalid or expired workflow state" };
|
|
178
|
+
}
|
|
184
179
|
if (state.schemaId !== (wfid ?? "")) {
|
|
185
180
|
const realStrategy = resolveStrategy(state.schemaId);
|
|
186
181
|
ctx.set(stateStrategyKey, realStrategy);
|
|
187
182
|
}
|
|
188
|
-
const outletName = state.meta?.outlet;
|
|
189
|
-
if (outletName && shouldConsume(outletName)) await strategy.consume(token);
|
|
190
183
|
output = await deps.resume(state, {
|
|
191
184
|
input,
|
|
192
185
|
eventContext: ctx
|
|
193
186
|
});
|
|
194
187
|
} else if (wfid) {
|
|
195
|
-
if (config.allow?.length && !config.allow.includes(wfid))
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
if (config.block?.includes(wfid))
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
188
|
+
if (config.allow?.length && !config.allow.includes(wfid)) {
|
|
189
|
+
response.setStatus(403);
|
|
190
|
+
return { error: `Workflow '${wfid}' is not allowed` };
|
|
191
|
+
}
|
|
192
|
+
if (config.block?.includes(wfid)) {
|
|
193
|
+
response.setStatus(403);
|
|
194
|
+
return { error: `Workflow '${wfid}' is blocked` };
|
|
195
|
+
}
|
|
203
196
|
const strategy = resolveStrategy(wfid);
|
|
204
197
|
ctx.set(stateStrategyKey, strategy);
|
|
205
198
|
const initialContext = config.initialContext ? config.initialContext(body, wfid) : {};
|
|
@@ -207,10 +200,10 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
207
200
|
input,
|
|
208
201
|
eventContext: ctx
|
|
209
202
|
});
|
|
210
|
-
} else
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
203
|
+
} else {
|
|
204
|
+
response.setStatus(400);
|
|
205
|
+
return { error: "Missing wfs (state token) or wfid (workflow ID)" };
|
|
206
|
+
}
|
|
214
207
|
if (output.finished) {
|
|
215
208
|
if (config.onFinished) return config.onFinished({
|
|
216
209
|
context: output.state.context,
|
|
@@ -219,32 +212,37 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
219
212
|
const finished = ctx.get(wfFinishedKey);
|
|
220
213
|
if (finished?.cookies) for (const [name, cookie] of Object.entries(finished.cookies)) response.setCookie(name, cookie.value, cookie.options);
|
|
221
214
|
if (finished?.type === "redirect") {
|
|
215
|
+
response.setStatus(finished.status ?? 302);
|
|
222
216
|
response.setHeader("location", finished.value);
|
|
223
|
-
return
|
|
217
|
+
return "";
|
|
218
|
+
}
|
|
219
|
+
if (finished) {
|
|
220
|
+
if (finished.status) response.setStatus(finished.status);
|
|
221
|
+
return finished.value;
|
|
224
222
|
}
|
|
225
|
-
if (finished) return finished.value;
|
|
226
223
|
return { finished: true };
|
|
227
224
|
}
|
|
228
225
|
if (output.inputRequired) {
|
|
229
226
|
const outletReq = output.inputRequired;
|
|
230
227
|
const outletHandler = registry.get(outletReq.outlet);
|
|
231
|
-
if (!outletHandler)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
228
|
+
if (!outletHandler) {
|
|
229
|
+
response.setStatus(500);
|
|
230
|
+
return { error: `Unknown outlet: '${outletReq.outlet}'` };
|
|
231
|
+
}
|
|
235
232
|
const strategy = ctx.get(stateStrategyKey);
|
|
236
233
|
const stateWithMeta = {
|
|
237
234
|
...output.state,
|
|
238
235
|
meta: { outlet: outletReq.outlet }
|
|
239
236
|
};
|
|
240
237
|
const newToken = await strategy.persist(stateWithMeta, output.expires ? { ttl: output.expires - Date.now() } : void 0);
|
|
241
|
-
|
|
238
|
+
const outOfBand = outletHandler.tokenDelivery === "out-of-band";
|
|
239
|
+
if (tokenWrite === "cookie" && !outOfBand) response.setCookie(tokenName, newToken, {
|
|
242
240
|
httpOnly: true,
|
|
243
241
|
sameSite: "Strict",
|
|
244
242
|
path: "/"
|
|
245
243
|
});
|
|
246
244
|
const result = await outletHandler.deliver(outletReq, newToken);
|
|
247
|
-
if (tokenWrite === "body" && result?.response && typeof result.response === "object") return {
|
|
245
|
+
if (tokenWrite === "body" && !outOfBand && result?.response && typeof result.response === "object") return {
|
|
248
246
|
...result.response,
|
|
249
247
|
[tokenName]: newToken
|
|
250
248
|
};
|
|
@@ -274,6 +272,7 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
274
272
|
function createHttpOutlet(opts) {
|
|
275
273
|
return {
|
|
276
274
|
name: "http",
|
|
275
|
+
tokenDelivery: "caller",
|
|
277
276
|
async deliver(request, _token) {
|
|
278
277
|
const body = opts?.transform ? opts.transform(request.payload, request.context) : typeof request.payload === "object" && request.payload !== null ? {
|
|
279
278
|
...request.payload,
|
|
@@ -302,6 +301,7 @@ function createHttpOutlet(opts) {
|
|
|
302
301
|
function createEmailOutlet(send) {
|
|
303
302
|
return {
|
|
304
303
|
name: "email",
|
|
304
|
+
tokenDelivery: "out-of-band",
|
|
305
305
|
async deliver(request, token) {
|
|
306
306
|
await send({
|
|
307
307
|
target: request.target ?? "",
|
|
@@ -339,7 +339,7 @@ function createOutletHandler(wfApp) {
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
//#endregion
|
|
342
|
-
//#region node_modules/.pnpm/@prostojs+wf@0.
|
|
342
|
+
//#region node_modules/.pnpm/@prostojs+wf@0.2.0/node_modules/@prostojs/wf/dist/outlets/index.mjs
|
|
343
343
|
/**
|
|
344
344
|
* Generic outlet request. Use for custom outlets.
|
|
345
345
|
*
|
|
@@ -391,6 +391,29 @@ function outletEmail(target, template, context) {
|
|
|
391
391
|
*
|
|
392
392
|
* Token format: `base64url(iv[12] + authTag[16] + ciphertext)`
|
|
393
393
|
*
|
|
394
|
+
* ## Security warning — replay
|
|
395
|
+
*
|
|
396
|
+
* This strategy is STATELESS. It cannot enforce single-use semantics:
|
|
397
|
+
* `consume()` is a no-op alias for `retrieve()` because there is no
|
|
398
|
+
* server-side record to delete. Anyone who obtains a copy of the token
|
|
399
|
+
* (browser history, server logs, shoulder-surfing, intermediate proxy,
|
|
400
|
+
* shared device) can replay it until the TTL expires.
|
|
401
|
+
*
|
|
402
|
+
* Use `EncapsulatedStateStrategy` ONLY when BOTH of the following hold:
|
|
403
|
+
*
|
|
404
|
+
* 1. Every workflow step is idempotent — re-executing a step with the same
|
|
405
|
+
* input produces no harmful side effects (pure data collection,
|
|
406
|
+
* validation-only steps).
|
|
407
|
+
* 2. The flow is not security-sensitive — no credential changes, financial
|
|
408
|
+
* operations, account provisioning, permission grants, or any other
|
|
409
|
+
* privileged action.
|
|
410
|
+
*
|
|
411
|
+
* For auth flows (login, password reset, invite accept), financial
|
|
412
|
+
* operations, or anything with meaningful side effects, use
|
|
413
|
+
* `HandleStateStrategy` with a durable `WfStateStore`. `HandleStateStrategy`
|
|
414
|
+
* supports true single-use tokens via atomic `getAndDelete` at the store
|
|
415
|
+
* layer.
|
|
416
|
+
*
|
|
394
417
|
* @example
|
|
395
418
|
* const strategy = new EncapsulatedStateStrategy({
|
|
396
419
|
* secret: crypto.randomBytes(32),
|
|
@@ -433,7 +456,14 @@ var EncapsulatedStateStrategy = class {
|
|
|
433
456
|
async retrieve(token) {
|
|
434
457
|
return this.decrypt(token);
|
|
435
458
|
}
|
|
436
|
-
/**
|
|
459
|
+
/**
|
|
460
|
+
* Stateless — CANNOT invalidate the token. Returns identical result to
|
|
461
|
+
* `retrieve()`. See the class-level security warning.
|
|
462
|
+
*
|
|
463
|
+
* This method exists only to satisfy the `WfStateStrategy` contract.
|
|
464
|
+
* Callers that need true single-use semantics must use
|
|
465
|
+
* `HandleStateStrategy`.
|
|
466
|
+
*/
|
|
437
467
|
async consume(token) {
|
|
438
468
|
return this.decrypt(token);
|
|
439
469
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -92,26 +92,36 @@ interface WfOutletTokenConfig {
|
|
|
92
92
|
write?: 'body' | 'cookie';
|
|
93
93
|
/** Parameter name for state token (default: `'wfs'`) */
|
|
94
94
|
name?: string;
|
|
95
|
-
/**
|
|
96
|
-
* Token consumption mode per outlet. When `true`, the trigger calls
|
|
97
|
-
* `strategy.consume()` (single-use token) instead of `strategy.retrieve()`
|
|
98
|
-
* on resume. Defaults to `{ email: true }` — email magic links are consumed
|
|
99
|
-
* on first use, HTTP tokens are reusable.
|
|
100
|
-
*
|
|
101
|
-
* Can be a boolean (applies to all outlets) or a per-outlet-name map.
|
|
102
|
-
*/
|
|
103
|
-
consume?: boolean | Record<string, boolean>;
|
|
104
95
|
}
|
|
105
96
|
interface WfOutletTriggerConfig {
|
|
106
97
|
/** Whitelist of allowed workflow IDs. If empty, all are allowed. */
|
|
107
98
|
allow?: string[];
|
|
108
99
|
/** Blacklist of workflow IDs. Checked after allow. */
|
|
109
100
|
block?: string[];
|
|
110
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* State persistence strategy. Either a single strategy shared by all
|
|
103
|
+
* workflows, or a function that returns a strategy per workflow ID.
|
|
104
|
+
*
|
|
105
|
+
* **Constraint when using the function form.** The trigger resolves the
|
|
106
|
+
* strategy at resume time using the `wfid` from the request. If the resume
|
|
107
|
+
* request does not include `wfid` (e.g. cookie-only transport, token-only
|
|
108
|
+
* body), the trigger calls `config.state('')` — meaning:
|
|
109
|
+
*
|
|
110
|
+
* - EITHER all strategies returned by the function must share the same
|
|
111
|
+
* underlying storage (same Redis instance, same `WfStateStore`, same
|
|
112
|
+
* encryption key), so `consume`/`retrieve` operations work regardless of
|
|
113
|
+
* which strategy instance is picked;
|
|
114
|
+
* - OR every resume request must carry `wfid` so the correct strategy is
|
|
115
|
+
* always resolved.
|
|
116
|
+
*
|
|
117
|
+
* Violating this contract silently breaks single-use token invalidation:
|
|
118
|
+
* the `consume` call runs against the wrong strategy's storage, and the
|
|
119
|
+
* token remains live in the real strategy.
|
|
120
|
+
*/
|
|
111
121
|
state: WfStateStrategy | ((wfid: string) => WfStateStrategy);
|
|
112
122
|
/** Registered outlets */
|
|
113
123
|
outlets: WfOutlet[];
|
|
114
|
-
/** Token configuration (reading, writing, naming
|
|
124
|
+
/** Token configuration (reading, writing, naming) */
|
|
115
125
|
token?: WfOutletTokenConfig;
|
|
116
126
|
/** Parameter name for workflow ID (default: `'wfid'`) */
|
|
117
127
|
wfidName?: string;
|
package/dist/index.mjs
CHANGED
|
@@ -97,7 +97,6 @@ const useWfFinished = defineWook((ctx) => ({
|
|
|
97
97
|
|
|
98
98
|
//#endregion
|
|
99
99
|
//#region packages/event-wf/src/outlets/trigger.ts
|
|
100
|
-
const DEFAULT_CONSUME_TOKEN = { email: true };
|
|
101
100
|
/**
|
|
102
101
|
* Handle an HTTP request that starts or resumes a workflow.
|
|
103
102
|
*
|
|
@@ -145,38 +144,32 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
145
144
|
const wfid = body?.[wfidName] ?? queryParams.get(wfidName) ?? void 0;
|
|
146
145
|
const input = body?.input;
|
|
147
146
|
const resolveStrategy = (id) => typeof config.state === "function" ? config.state(id) : config.state;
|
|
148
|
-
const shouldConsume = (outletName) => {
|
|
149
|
-
if (typeof tok.consume === "boolean") return tok.consume;
|
|
150
|
-
return (tok.consume ?? DEFAULT_CONSUME_TOKEN)[outletName] ?? false;
|
|
151
|
-
};
|
|
152
147
|
let output;
|
|
153
148
|
if (token) {
|
|
154
149
|
const strategy = resolveStrategy(wfid ?? "");
|
|
155
150
|
ctx.set(stateStrategyKey, strategy);
|
|
156
|
-
const state = await strategy.
|
|
157
|
-
if (!state)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
151
|
+
const state = await strategy.consume(token);
|
|
152
|
+
if (!state) {
|
|
153
|
+
response.setStatus(410);
|
|
154
|
+
return { error: "Invalid or expired workflow state" };
|
|
155
|
+
}
|
|
161
156
|
if (state.schemaId !== (wfid ?? "")) {
|
|
162
157
|
const realStrategy = resolveStrategy(state.schemaId);
|
|
163
158
|
ctx.set(stateStrategyKey, realStrategy);
|
|
164
159
|
}
|
|
165
|
-
const outletName = state.meta?.outlet;
|
|
166
|
-
if (outletName && shouldConsume(outletName)) await strategy.consume(token);
|
|
167
160
|
output = await deps.resume(state, {
|
|
168
161
|
input,
|
|
169
162
|
eventContext: ctx
|
|
170
163
|
});
|
|
171
164
|
} else if (wfid) {
|
|
172
|
-
if (config.allow?.length && !config.allow.includes(wfid))
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
if (config.block?.includes(wfid))
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
165
|
+
if (config.allow?.length && !config.allow.includes(wfid)) {
|
|
166
|
+
response.setStatus(403);
|
|
167
|
+
return { error: `Workflow '${wfid}' is not allowed` };
|
|
168
|
+
}
|
|
169
|
+
if (config.block?.includes(wfid)) {
|
|
170
|
+
response.setStatus(403);
|
|
171
|
+
return { error: `Workflow '${wfid}' is blocked` };
|
|
172
|
+
}
|
|
180
173
|
const strategy = resolveStrategy(wfid);
|
|
181
174
|
ctx.set(stateStrategyKey, strategy);
|
|
182
175
|
const initialContext = config.initialContext ? config.initialContext(body, wfid) : {};
|
|
@@ -184,10 +177,10 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
184
177
|
input,
|
|
185
178
|
eventContext: ctx
|
|
186
179
|
});
|
|
187
|
-
} else
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
180
|
+
} else {
|
|
181
|
+
response.setStatus(400);
|
|
182
|
+
return { error: "Missing wfs (state token) or wfid (workflow ID)" };
|
|
183
|
+
}
|
|
191
184
|
if (output.finished) {
|
|
192
185
|
if (config.onFinished) return config.onFinished({
|
|
193
186
|
context: output.state.context,
|
|
@@ -196,32 +189,37 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
196
189
|
const finished = ctx.get(wfFinishedKey);
|
|
197
190
|
if (finished?.cookies) for (const [name, cookie] of Object.entries(finished.cookies)) response.setCookie(name, cookie.value, cookie.options);
|
|
198
191
|
if (finished?.type === "redirect") {
|
|
192
|
+
response.setStatus(finished.status ?? 302);
|
|
199
193
|
response.setHeader("location", finished.value);
|
|
200
|
-
return
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
if (finished) {
|
|
197
|
+
if (finished.status) response.setStatus(finished.status);
|
|
198
|
+
return finished.value;
|
|
201
199
|
}
|
|
202
|
-
if (finished) return finished.value;
|
|
203
200
|
return { finished: true };
|
|
204
201
|
}
|
|
205
202
|
if (output.inputRequired) {
|
|
206
203
|
const outletReq = output.inputRequired;
|
|
207
204
|
const outletHandler = registry.get(outletReq.outlet);
|
|
208
|
-
if (!outletHandler)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
205
|
+
if (!outletHandler) {
|
|
206
|
+
response.setStatus(500);
|
|
207
|
+
return { error: `Unknown outlet: '${outletReq.outlet}'` };
|
|
208
|
+
}
|
|
212
209
|
const strategy = ctx.get(stateStrategyKey);
|
|
213
210
|
const stateWithMeta = {
|
|
214
211
|
...output.state,
|
|
215
212
|
meta: { outlet: outletReq.outlet }
|
|
216
213
|
};
|
|
217
214
|
const newToken = await strategy.persist(stateWithMeta, output.expires ? { ttl: output.expires - Date.now() } : void 0);
|
|
218
|
-
|
|
215
|
+
const outOfBand = outletHandler.tokenDelivery === "out-of-band";
|
|
216
|
+
if (tokenWrite === "cookie" && !outOfBand) response.setCookie(tokenName, newToken, {
|
|
219
217
|
httpOnly: true,
|
|
220
218
|
sameSite: "Strict",
|
|
221
219
|
path: "/"
|
|
222
220
|
});
|
|
223
221
|
const result = await outletHandler.deliver(outletReq, newToken);
|
|
224
|
-
if (tokenWrite === "body" && result?.response && typeof result.response === "object") return {
|
|
222
|
+
if (tokenWrite === "body" && !outOfBand && result?.response && typeof result.response === "object") return {
|
|
225
223
|
...result.response,
|
|
226
224
|
[tokenName]: newToken
|
|
227
225
|
};
|
|
@@ -251,6 +249,7 @@ async function handleWfOutletRequest(config, deps) {
|
|
|
251
249
|
function createHttpOutlet(opts) {
|
|
252
250
|
return {
|
|
253
251
|
name: "http",
|
|
252
|
+
tokenDelivery: "caller",
|
|
254
253
|
async deliver(request, _token) {
|
|
255
254
|
const body = opts?.transform ? opts.transform(request.payload, request.context) : typeof request.payload === "object" && request.payload !== null ? {
|
|
256
255
|
...request.payload,
|
|
@@ -279,6 +278,7 @@ function createHttpOutlet(opts) {
|
|
|
279
278
|
function createEmailOutlet(send) {
|
|
280
279
|
return {
|
|
281
280
|
name: "email",
|
|
281
|
+
tokenDelivery: "out-of-band",
|
|
282
282
|
async deliver(request, token) {
|
|
283
283
|
await send({
|
|
284
284
|
target: request.target ?? "",
|
|
@@ -316,7 +316,7 @@ function createOutletHandler(wfApp) {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
//#endregion
|
|
319
|
-
//#region node_modules/.pnpm/@prostojs+wf@0.
|
|
319
|
+
//#region node_modules/.pnpm/@prostojs+wf@0.2.0/node_modules/@prostojs/wf/dist/outlets/index.mjs
|
|
320
320
|
/**
|
|
321
321
|
* Generic outlet request. Use for custom outlets.
|
|
322
322
|
*
|
|
@@ -368,6 +368,29 @@ function outletEmail(target, template, context) {
|
|
|
368
368
|
*
|
|
369
369
|
* Token format: `base64url(iv[12] + authTag[16] + ciphertext)`
|
|
370
370
|
*
|
|
371
|
+
* ## Security warning — replay
|
|
372
|
+
*
|
|
373
|
+
* This strategy is STATELESS. It cannot enforce single-use semantics:
|
|
374
|
+
* `consume()` is a no-op alias for `retrieve()` because there is no
|
|
375
|
+
* server-side record to delete. Anyone who obtains a copy of the token
|
|
376
|
+
* (browser history, server logs, shoulder-surfing, intermediate proxy,
|
|
377
|
+
* shared device) can replay it until the TTL expires.
|
|
378
|
+
*
|
|
379
|
+
* Use `EncapsulatedStateStrategy` ONLY when BOTH of the following hold:
|
|
380
|
+
*
|
|
381
|
+
* 1. Every workflow step is idempotent — re-executing a step with the same
|
|
382
|
+
* input produces no harmful side effects (pure data collection,
|
|
383
|
+
* validation-only steps).
|
|
384
|
+
* 2. The flow is not security-sensitive — no credential changes, financial
|
|
385
|
+
* operations, account provisioning, permission grants, or any other
|
|
386
|
+
* privileged action.
|
|
387
|
+
*
|
|
388
|
+
* For auth flows (login, password reset, invite accept), financial
|
|
389
|
+
* operations, or anything with meaningful side effects, use
|
|
390
|
+
* `HandleStateStrategy` with a durable `WfStateStore`. `HandleStateStrategy`
|
|
391
|
+
* supports true single-use tokens via atomic `getAndDelete` at the store
|
|
392
|
+
* layer.
|
|
393
|
+
*
|
|
371
394
|
* @example
|
|
372
395
|
* const strategy = new EncapsulatedStateStrategy({
|
|
373
396
|
* secret: crypto.randomBytes(32),
|
|
@@ -410,7 +433,14 @@ var EncapsulatedStateStrategy = class {
|
|
|
410
433
|
async retrieve(token) {
|
|
411
434
|
return this.decrypt(token);
|
|
412
435
|
}
|
|
413
|
-
/**
|
|
436
|
+
/**
|
|
437
|
+
* Stateless — CANNOT invalidate the token. Returns identical result to
|
|
438
|
+
* `retrieve()`. See the class-level security warning.
|
|
439
|
+
*
|
|
440
|
+
* This method exists only to satisfy the `WfStateStrategy` contract.
|
|
441
|
+
* Callers that need true single-use semantics must use
|
|
442
|
+
* `HandleStateStrategy`.
|
|
443
|
+
*/
|
|
414
444
|
async consume(token) {
|
|
415
445
|
return this.decrypt(token);
|
|
416
446
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wooksjs/event-wf",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.11",
|
|
4
4
|
"description": "@wooksjs/event-wf",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -37,22 +37,22 @@
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@prostojs/wf": "^0.
|
|
40
|
+
"@prostojs/wf": "^0.2.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"typescript": "^5.9.3",
|
|
44
44
|
"vitest": "^3.2.4",
|
|
45
|
-
"@wooksjs/event-core": "^0.7.
|
|
46
|
-
"@wooksjs/event-http": "^0.7.
|
|
47
|
-
"@wooksjs/http-body": "^0.7.
|
|
48
|
-
"wooks": "^0.7.
|
|
45
|
+
"@wooksjs/event-core": "^0.7.11",
|
|
46
|
+
"@wooksjs/event-http": "^0.7.11",
|
|
47
|
+
"@wooksjs/http-body": "^0.7.11",
|
|
48
|
+
"wooks": "^0.7.11"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@prostojs/logger": "^0.4.3",
|
|
52
|
-
"@wooksjs/event-core": "^0.7.
|
|
53
|
-
"@wooksjs/event-http": "^0.7.
|
|
54
|
-
"@wooksjs/http-body": "^0.7.
|
|
55
|
-
"wooks": "^0.7.
|
|
52
|
+
"@wooksjs/event-core": "^0.7.11",
|
|
53
|
+
"@wooksjs/event-http": "^0.7.11",
|
|
54
|
+
"@wooksjs/http-body": "^0.7.11",
|
|
55
|
+
"wooks": "^0.7.11"
|
|
56
56
|
},
|
|
57
57
|
"peerDependenciesMeta": {
|
|
58
58
|
"@wooksjs/event-http": {
|