@brandboostinggmbh/observable-workflows 0.1.0 → 0.2.2
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/README.md +4 -30
- package/dist/index.d.ts +22 -5
- package/dist/index.js +32 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,41 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# observable-workflows [](https://npmjs.com/package/ts-starter)
|
|
2
2
|
|
|
3
3
|
[](https://github.com/sxzz/ts-starter/actions/workflows/unit-test.yml)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<!-- Remove belows -->
|
|
8
|
-
|
|
9
|
-
Forked from [egoist/ts-starter](https://github.com/egoist/ts-starter)
|
|
10
|
-
|
|
11
|
-
## Using this template
|
|
12
|
-
|
|
13
|
-
- Search `ts-starter` and replace it with your custom package name.
|
|
14
|
-
- Search `sxzz` and replace it with your name.
|
|
15
|
-
- Remove sponsors below.
|
|
16
|
-
|
|
17
|
-
Features:
|
|
18
|
-
|
|
19
|
-
- Package manager [pnpm](https://pnpm.js.org/), safe and fast
|
|
20
|
-
- Bundle with blazing fast [tsdown](https://github.com/sxzz/tsdown)
|
|
21
|
-
- Test with [Vitest](https://vitest.dev)
|
|
22
|
-
|
|
23
|
-
<!-- Remove aboves -->
|
|
5
|
+
TODO
|
|
24
6
|
|
|
25
7
|
## Install
|
|
26
8
|
|
|
27
9
|
```bash
|
|
28
|
-
npm i
|
|
10
|
+
npm i @brandboostinggmbh/observable-workflows
|
|
29
11
|
```
|
|
30
12
|
|
|
31
|
-
## Sponsors
|
|
32
|
-
|
|
33
|
-
<p align="center">
|
|
34
|
-
<a href="https://cdn.jsdelivr.net/gh/sxzz/sponsors/sponsors.svg">
|
|
35
|
-
<img src='https://cdn.jsdelivr.net/gh/sxzz/sponsors/sponsors.svg'/>
|
|
36
|
-
</a>
|
|
37
|
-
</p>
|
|
38
|
-
|
|
39
13
|
## License
|
|
40
14
|
|
|
41
|
-
[MIT](./LICENSE) License © 2025 [
|
|
15
|
+
[MIT](./LICENSE) License © 2025 [Tim Stepanov](https://github.com/TimStepanovAtBrandBoosting)
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,8 @@ declare function insertWorkflowRecord(options: InternalWorkflowContextOptions, {
|
|
|
24
24
|
workflowStatus,
|
|
25
25
|
startTime,
|
|
26
26
|
endTime,
|
|
27
|
-
parentInstanceId
|
|
27
|
+
parentInstanceId,
|
|
28
|
+
tenantId
|
|
28
29
|
}: {
|
|
29
30
|
instanceId: string;
|
|
30
31
|
workflowType: string;
|
|
@@ -35,6 +36,7 @@ declare function insertWorkflowRecord(options: InternalWorkflowContextOptions, {
|
|
|
35
36
|
startTime: number;
|
|
36
37
|
endTime?: number | null;
|
|
37
38
|
parentInstanceId?: string | null;
|
|
39
|
+
tenantId: string;
|
|
38
40
|
}): Promise<D1Result<Record<string, unknown>>>;
|
|
39
41
|
declare function insertStepRecordFull(context: StepContextOptions, {
|
|
40
42
|
instanceId,
|
|
@@ -61,7 +63,8 @@ declare function pushLogToDB(options: InternalWorkflowContextOptions, {
|
|
|
61
63
|
message,
|
|
62
64
|
timestamp,
|
|
63
65
|
type,
|
|
64
|
-
logOrder
|
|
66
|
+
logOrder,
|
|
67
|
+
tenantId
|
|
65
68
|
}: {
|
|
66
69
|
instanceId: string;
|
|
67
70
|
stepName: string | null;
|
|
@@ -69,6 +72,7 @@ declare function pushLogToDB(options: InternalWorkflowContextOptions, {
|
|
|
69
72
|
timestamp: number;
|
|
70
73
|
type: string;
|
|
71
74
|
logOrder: number;
|
|
75
|
+
tenantId: string;
|
|
72
76
|
}): Promise<D1Result<Record<string, unknown>>>;
|
|
73
77
|
declare function tryDeserializeObj(obj: string, serializer: Serializer): any;
|
|
74
78
|
/**
|
|
@@ -121,13 +125,15 @@ declare function upsertWorkflowProperty<T extends keyof ValueTypeMap>({
|
|
|
121
125
|
instanceId,
|
|
122
126
|
key,
|
|
123
127
|
valueType,
|
|
124
|
-
value
|
|
128
|
+
value,
|
|
129
|
+
tenantId
|
|
125
130
|
}: {
|
|
126
131
|
context: InternalWorkflowContextOptions;
|
|
127
132
|
instanceId: string;
|
|
128
133
|
key: string;
|
|
129
134
|
valueType: T;
|
|
130
135
|
value: ValueTypeMap[T];
|
|
136
|
+
tenantId: string;
|
|
131
137
|
}): Promise<boolean>;
|
|
132
138
|
|
|
133
139
|
//#endregion
|
|
@@ -203,7 +209,6 @@ type Serializer = {
|
|
|
203
209
|
};
|
|
204
210
|
type WorkflowContextOptions = {
|
|
205
211
|
D1: D1Database;
|
|
206
|
-
tenantId: string;
|
|
207
212
|
idFactory?: () => string;
|
|
208
213
|
serializer?: Serializer;
|
|
209
214
|
};
|
|
@@ -251,7 +256,19 @@ declare function defineWorkflow<I extends {} | null>(workflow: {
|
|
|
251
256
|
//#endregion
|
|
252
257
|
//#region src/observableWorkflows/createWorkflowContext.d.ts
|
|
253
258
|
declare function createWorkflowContext(options: WorkflowContextOptions): Promise<{
|
|
254
|
-
call: <I>(
|
|
259
|
+
call: <I>({
|
|
260
|
+
workflow,
|
|
261
|
+
input,
|
|
262
|
+
workflowName,
|
|
263
|
+
tenantId,
|
|
264
|
+
parentInstanceId
|
|
265
|
+
}: {
|
|
266
|
+
workflow: WorkflowFunction<I>;
|
|
267
|
+
input: I;
|
|
268
|
+
workflowName: string;
|
|
269
|
+
tenantId: string;
|
|
270
|
+
parentInstanceId?: string | undefined;
|
|
271
|
+
}) => Promise<void>;
|
|
255
272
|
retry: <I>(workflow: WorkflowFunction<I>, retryInstanceId: string) => Promise<void>;
|
|
256
273
|
}>;
|
|
257
274
|
|
package/dist/index.js
CHANGED
|
@@ -7,13 +7,13 @@ function finalizeWorkflowRecord(options, { workflowStatus, endTime, instanceId }
|
|
|
7
7
|
WHERE instanceId = ?`
|
|
8
8
|
).bind(workflowStatus, endTime, instanceId).run();
|
|
9
9
|
}
|
|
10
|
-
function insertWorkflowRecord(options, { instanceId, workflowType, workflowName, workflowMetadata, input, workflowStatus, startTime, endTime, parentInstanceId }) {
|
|
10
|
+
function insertWorkflowRecord(options, { instanceId, workflowType, workflowName, workflowMetadata, input, workflowStatus, startTime, endTime, parentInstanceId, tenantId }) {
|
|
11
11
|
return options.D1.prepare(
|
|
12
12
|
/* sql */
|
|
13
13
|
`INSERT INTO WorkflowTable
|
|
14
14
|
(instanceId, workflowType, workflowName, workflowMetadata, input, tenantId, workflowStatus, startTime, endTime, parentInstanceId)
|
|
15
15
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
16
|
-
).bind(instanceId, workflowType, workflowName, options.serializer.serialize(workflowMetadata), options.serializer.serialize(input),
|
|
16
|
+
).bind(instanceId, workflowType, workflowName, options.serializer.serialize(workflowMetadata), options.serializer.serialize(input), tenantId, workflowStatus, startTime, endTime ?? null, parentInstanceId ?? null).run();
|
|
17
17
|
}
|
|
18
18
|
function insertStepRecordFull(context, { instanceId, name, status, metadata, startTime, endTime, result, error }) {
|
|
19
19
|
return context.D1.prepare(
|
|
@@ -23,13 +23,13 @@ function insertStepRecordFull(context, { instanceId, name, status, metadata, sta
|
|
|
23
23
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
24
24
|
).bind(instanceId, name, status, metadata, startTime, endTime, result, error, context.tenantId).run();
|
|
25
25
|
}
|
|
26
|
-
function pushLogToDB(options, { instanceId, stepName, message, timestamp, type, logOrder }) {
|
|
26
|
+
function pushLogToDB(options, { instanceId, stepName, message, timestamp, type, logOrder, tenantId }) {
|
|
27
27
|
return options.D1.prepare(
|
|
28
28
|
/* sql */
|
|
29
29
|
`INSERT INTO LogTable
|
|
30
30
|
(instanceId, stepName, log, timestamp, type, logOrder, tenantId)
|
|
31
31
|
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
32
|
-
).bind(instanceId, stepName, message, timestamp, type, logOrder,
|
|
32
|
+
).bind(instanceId, stepName, message, timestamp, type, logOrder, tenantId).run();
|
|
33
33
|
}
|
|
34
34
|
function tryDeserializeObj(obj, serializer) {
|
|
35
35
|
try {
|
|
@@ -159,14 +159,14 @@ async function updateWorkflowName(context, instanceId, newWorkflowName) {
|
|
|
159
159
|
WHERE instanceId = ?`
|
|
160
160
|
).bind(newWorkflowName, instanceId).run();
|
|
161
161
|
}
|
|
162
|
-
async function upsertWorkflowProperty({ context, instanceId, key, valueType, value }) {
|
|
162
|
+
async function upsertWorkflowProperty({ context, instanceId, key, valueType, value, tenantId }) {
|
|
163
163
|
const serializedValue = valueType === "object" ? JSON.stringify(value) : String(value);
|
|
164
164
|
const res = await context.D1.prepare(
|
|
165
165
|
/* sql */
|
|
166
166
|
`INSERT OR REPLACE INTO WorkflowProperties
|
|
167
167
|
(instanceId, key, value, valueType, tenantId)
|
|
168
168
|
VALUES (?, ?, ?, ?, ?)`
|
|
169
|
-
).bind(instanceId, key, serializedValue, valueType,
|
|
169
|
+
).bind(instanceId, key, serializedValue, valueType, tenantId).run();
|
|
170
170
|
if (res.error) {
|
|
171
171
|
console.error("Error inserting workflow property:", res.error);
|
|
172
172
|
return false;
|
|
@@ -239,7 +239,8 @@ async function createStepContext(context) {
|
|
|
239
239
|
message,
|
|
240
240
|
timestamp,
|
|
241
241
|
type,
|
|
242
|
-
logOrder
|
|
242
|
+
logOrder,
|
|
243
|
+
tenantId: context.tenantId
|
|
243
244
|
});
|
|
244
245
|
waitFor.push(logPromise);
|
|
245
246
|
};
|
|
@@ -311,7 +312,7 @@ async function createWorkflowContext(options) {
|
|
|
311
312
|
},
|
|
312
313
|
idFactory: options.idFactory ?? (() => crypto.randomUUID())
|
|
313
314
|
};
|
|
314
|
-
const call = async (workflow, input, workflowName, parentInstanceId
|
|
315
|
+
const call = async ({ workflow, input, workflowName, tenantId, parentInstanceId }) => {
|
|
315
316
|
const instanceId = internalContext.idFactory();
|
|
316
317
|
const startTime = Date.now();
|
|
317
318
|
await insertWorkflowRecord(internalContext, {
|
|
@@ -323,7 +324,8 @@ async function createWorkflowContext(options) {
|
|
|
323
324
|
workflowStatus: "pending",
|
|
324
325
|
startTime,
|
|
325
326
|
endTime: null,
|
|
326
|
-
parentInstanceId
|
|
327
|
+
parentInstanceId,
|
|
328
|
+
tenantId
|
|
327
329
|
});
|
|
328
330
|
let waitFor = [];
|
|
329
331
|
let logOrder = 0;
|
|
@@ -336,13 +338,14 @@ async function createWorkflowContext(options) {
|
|
|
336
338
|
message,
|
|
337
339
|
timestamp,
|
|
338
340
|
type,
|
|
339
|
-
logOrder
|
|
341
|
+
logOrder,
|
|
342
|
+
tenantId
|
|
340
343
|
});
|
|
341
344
|
waitFor.push(logPromise);
|
|
342
345
|
};
|
|
343
346
|
const stepContext = await createStepContext({
|
|
344
347
|
D1: options.D1,
|
|
345
|
-
tenantId
|
|
348
|
+
tenantId,
|
|
346
349
|
instanceId,
|
|
347
350
|
serializer: internalContext.serializer,
|
|
348
351
|
idFactory: internalContext.idFactory
|
|
@@ -373,7 +376,8 @@ async function createWorkflowContext(options) {
|
|
|
373
376
|
instanceId,
|
|
374
377
|
key,
|
|
375
378
|
valueType,
|
|
376
|
-
value
|
|
379
|
+
value,
|
|
380
|
+
tenantId
|
|
377
381
|
});
|
|
378
382
|
}
|
|
379
383
|
});
|
|
@@ -400,13 +404,21 @@ async function createWorkflowContext(options) {
|
|
|
400
404
|
const retry = async (workflow, retryInstanceId) => {
|
|
401
405
|
const oldRun = await options.D1.prepare(
|
|
402
406
|
/* sql */
|
|
403
|
-
`SELECT input, workflowName FROM WorkflowTable WHERE instanceId = ? `
|
|
407
|
+
`SELECT input, workflowName, tenantId FROM WorkflowTable WHERE instanceId = ? `
|
|
404
408
|
).bind(retryInstanceId).first();
|
|
405
409
|
const oldWorkflowName = oldRun?.workflowName;
|
|
410
|
+
const tenantId = oldRun?.tenantId;
|
|
411
|
+
if (!tenantId) throw new Error(`No tenantId found for instanceId ${retryInstanceId}`);
|
|
406
412
|
const encodedInput = oldRun?.input;
|
|
407
413
|
if (!encodedInput) throw new Error(`No input found for instanceId ${retryInstanceId}`);
|
|
408
414
|
const input = JSON.parse(encodedInput);
|
|
409
|
-
await call(
|
|
415
|
+
await call({
|
|
416
|
+
workflow,
|
|
417
|
+
input,
|
|
418
|
+
workflowName: oldWorkflowName ?? "unknown",
|
|
419
|
+
parentInstanceId: retryInstanceId,
|
|
420
|
+
tenantId
|
|
421
|
+
});
|
|
410
422
|
};
|
|
411
423
|
return {
|
|
412
424
|
call,
|
|
@@ -439,13 +451,17 @@ function createQueueWorkflowContext(options) {
|
|
|
439
451
|
if (!workflowFunction) throw new Error(`Workflow ${message.workflowType} not found`);
|
|
440
452
|
const wfc = await createWorkflowContext({
|
|
441
453
|
D1: env.LOG_DB,
|
|
442
|
-
tenantId: message.tenantId,
|
|
443
454
|
serializer: options.serializer,
|
|
444
455
|
idFactory: options.idFactory
|
|
445
456
|
});
|
|
446
457
|
if (message.type === "workflow-run") {
|
|
447
458
|
console.log("running workflow", message.input);
|
|
448
|
-
await wfc.call(
|
|
459
|
+
await wfc.call({
|
|
460
|
+
input: message.input,
|
|
461
|
+
workflow: workflowFunction,
|
|
462
|
+
workflowName: message.workflowName,
|
|
463
|
+
tenantId: message.tenantId
|
|
464
|
+
});
|
|
449
465
|
} else if (message.type === "workflow-retry") {
|
|
450
466
|
console.log("retrying workflow", message.retryInstanceId);
|
|
451
467
|
await wfc.retry(workflowFunction, message.retryInstanceId);
|