@nestjs/workflows 0.0.3 → 0.0.5

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 (38) hide show
  1. package/dist/core/interfaces/leased-worker-options.interface.d.ts +5 -1
  2. package/dist/core/interfaces/result-waiter-options.interface.d.ts +6 -2
  3. package/dist/core/results/result-waiter.d.ts +5 -3
  4. package/dist/core/results/result-waiter.js +34 -10
  5. package/dist/core/utils/timer.util.d.ts +12 -0
  6. package/dist/core/utils/timer.util.js +16 -0
  7. package/dist/core/workers/leased-worker.d.ts +5 -2
  8. package/dist/core/workers/leased-worker.js +104 -12
  9. package/dist/cqrs/workflow-event.publisher.js +3 -3
  10. package/dist/index.d.ts +1 -1
  11. package/dist/interfaces/workflow-client.interface.d.ts +4 -1
  12. package/dist/interfaces/workflow-context.interface.d.ts +2 -2
  13. package/dist/interfaces/workflow-store.interface.d.ts +18 -1
  14. package/dist/mysql/interfaces/mysql-workflow-store-options.interface.d.ts +1 -1
  15. package/dist/mysql/mysql-workflow.store.d.ts +5 -1
  16. package/dist/mysql/mysql-workflow.store.js +7 -0
  17. package/dist/postgres/interfaces/postgres-workflow-store-options.interface.d.ts +1 -1
  18. package/dist/postgres/postgres-workflow.store.d.ts +6 -1
  19. package/dist/postgres/postgres-workflow.store.js +8 -0
  20. package/dist/services/workflow-client.service.d.ts +11 -2
  21. package/dist/services/workflow-client.service.js +23 -5
  22. package/dist/services/workflow-execution.service.d.ts +3 -0
  23. package/dist/services/workflow-execution.service.js +31 -5
  24. package/dist/services/workflow-scheduler.service.d.ts +8 -0
  25. package/dist/services/workflow-scheduler.service.js +20 -1
  26. package/dist/services/workflow-schedules.service.js +2 -0
  27. package/dist/services/workflow-worker.service.js +3 -0
  28. package/dist/storage/encoded-workflow.store.d.ts +11 -0
  29. package/dist/storage/encoded-workflow.store.js +38 -3
  30. package/dist/testing/index.js +4 -4
  31. package/dist/utils/index.d.ts +1 -0
  32. package/dist/utils/index.js +1 -0
  33. package/dist/utils/new-instance.util.d.ts +3 -0
  34. package/dist/utils/new-instance.util.js +9 -2
  35. package/dist/utils/serialize-error.util.js +25 -1
  36. package/dist/utils/storable-text.util.d.ts +36 -0
  37. package/dist/utils/storable-text.util.js +96 -0
  38. package/package.json +37 -24
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Where the engine stores a piece of text, which decides what it asks the store (`WorkflowStore.unstorableText()`):
3
+ * - `payload`: an input, a result, a payload, a status, an output, in a JSON column, which a codec encodes;
4
+ * - `cancelReason`: a cancel's reason, in a text column, which a codec encodes;
5
+ * - `name`: a journal entry's name (a step's, a wait's, `$child:<id>`), which the entry's JSON holds too, never encoded;
6
+ * - `key`: an id, a name or a key in a text column of its own, never encoded.
7
+ */
8
+ export type TextPlace = 'payload' | 'cancelReason' | 'name' | 'key';
9
+ /** What the store can't keep of `text` at a place (such as `'U+0000'`), or `undefined`. */
10
+ export type TextCheck = (text: string) => string | undefined;
11
+ /** A place's check, or `undefined` where the store keeps any text (`EncodedWorkflowStore.textCheck()`). */
12
+ export type TextChecks = (place: TextPlace) => TextCheck | undefined;
13
+ /** `'U+0000'` when `text` holds it (PostgreSQL keeps it in neither `text` nor `jsonb`), else `undefined`. */
14
+ export declare function nulIn(text: string): string | undefined;
15
+ /** `'a lone UTF-16 surrogate'` when `text` holds one (PostgreSQL and MySQL refuse it in JSON), else `undefined`. */
16
+ export declare function loneSurrogateIn(text: string): string | undefined;
17
+ /**
18
+ * The first string of a JSON value (what `JSON.parse()` returns), a value or an object's key, that `check` refuses,
19
+ * with its path (`$.lines[0].note`), or `undefined`. Walks with a stack of its own, so a value as deep as
20
+ * `JSON.stringify()` takes can't overflow the call stack; the path is built only for what it finds.
21
+ */
22
+ export declare function findUnstorableText(value: unknown, check: TextCheck): {
23
+ path: string;
24
+ problem: string;
25
+ } | undefined;
26
+ /** Throws a `TypeError` that names `what` when `check` refuses `text`. */
27
+ export declare function assertStorableText(what: string, text: string | null | undefined, check: TextCheck | undefined): void;
28
+ /** The same for a JSON value (what `normalize()` returns), naming where in `what` the text sits. */
29
+ export declare function assertStorableJson(what: string, value: unknown, check: TextCheck | undefined): void;
30
+ /** `assertStorableJson()`'s error, for a caller that reports it in its own way, or `undefined`. */
31
+ export declare function unstorableJson(what: string, value: unknown, check: TextCheck | undefined): TypeError | undefined;
32
+ /**
33
+ * `text`, with U+0000 and lone surrogates replaced with U+FFFD when `check` refuses it: for an error's text, which is
34
+ * recorded whatever it holds.
35
+ */
36
+ export declare function storableText(text: string, check: TextCheck | undefined): string;
@@ -0,0 +1,96 @@
1
+ /** `'U+0000'` when `text` holds it (PostgreSQL keeps it in neither `text` nor `jsonb`), else `undefined`. */
2
+ export function nulIn(text) {
3
+ return text.includes('\u0000') ? 'U+0000' : undefined;
4
+ }
5
+ /** `'a lone UTF-16 surrogate'` when `text` holds one (PostgreSQL and MySQL refuse it in JSON), else `undefined`. */
6
+ export function loneSurrogateIn(text) {
7
+ return text.isWellFormed() ? undefined : 'a lone UTF-16 surrogate';
8
+ }
9
+ /**
10
+ * The first string of a JSON value (what `JSON.parse()` returns), a value or an object's key, that `check` refuses,
11
+ * with its path (`$.lines[0].note`), or `undefined`. Walks with a stack of its own, so a value as deep as
12
+ * `JSON.stringify()` takes can't overflow the call stack; the path is built only for what it finds.
13
+ */
14
+ export function findUnstorableText(value, check) {
15
+ const pending = [{ value, parent: undefined, at: undefined }];
16
+ for (let step = pending.pop(); step; step = pending.pop()) {
17
+ if (step.keyProblem) {
18
+ return { path: `${pathOf(step)} (its key)`, problem: step.keyProblem };
19
+ }
20
+ const current = step.value;
21
+ if (typeof current === 'string') {
22
+ const problem = check(current);
23
+ if (problem) {
24
+ return { path: pathOf(step), problem };
25
+ }
26
+ }
27
+ else if (Array.isArray(current)) {
28
+ // Last first, so the first is checked first. Numbers, booleans and null hold no text.
29
+ for (let i = current.length - 1; i >= 0; i--) {
30
+ if (holdsText(current[i])) {
31
+ pending.push({ value: current[i], parent: step, at: i });
32
+ }
33
+ }
34
+ }
35
+ else if (current !== null && typeof current === 'object') {
36
+ const keys = Object.keys(current);
37
+ for (let i = keys.length - 1; i >= 0; i--) {
38
+ const key = keys[i];
39
+ const child = current[key];
40
+ const keyProblem = check(key);
41
+ if (keyProblem || holdsText(child)) {
42
+ pending.push({ value: child, parent: step, at: key, keyProblem });
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return undefined;
48
+ }
49
+ /** Throws a `TypeError` that names `what` when `check` refuses `text`. */
50
+ export function assertStorableText(what, text, check) {
51
+ const problem = check && typeof text === 'string' ? check(text) : undefined;
52
+ if (problem) {
53
+ throw unstorable(what, problem);
54
+ }
55
+ }
56
+ /** The same for a JSON value (what `normalize()` returns), naming where in `what` the text sits. */
57
+ export function assertStorableJson(what, value, check) {
58
+ const refused = unstorableJson(what, value, check);
59
+ if (refused) {
60
+ throw refused;
61
+ }
62
+ }
63
+ /** `assertStorableJson()`'s error, for a caller that reports it in its own way, or `undefined`. */
64
+ export function unstorableJson(what, value, check) {
65
+ const found = check && findUnstorableText(value, check);
66
+ return found ? unstorable(`${what} at ${found.path}`, found.problem) : undefined;
67
+ }
68
+ /**
69
+ * `text`, with U+0000 and lone surrogates replaced with U+FFFD when `check` refuses it: for an error's text, which is
70
+ * recorded whatever it holds.
71
+ */
72
+ export function storableText(text, check) {
73
+ return check?.(text) === undefined ? text : text.replaceAll('\u0000', '�').toWellFormed();
74
+ }
75
+ function unstorable(where, problem) {
76
+ return new TypeError(`${where} holds ${problem}, which the workflow store can't keep.`);
77
+ }
78
+ function holdsText(value) {
79
+ return typeof value === 'string' || (value !== null && typeof value === 'object');
80
+ }
81
+ function pathOf(step) {
82
+ let path = '';
83
+ for (let at = step; at; at = at.parent) {
84
+ path = segment(at.at) + path;
85
+ }
86
+ return path;
87
+ }
88
+ function segment(at) {
89
+ if (at === undefined) {
90
+ return '$';
91
+ }
92
+ if (typeof at === 'number') {
93
+ return `[${at}]`;
94
+ }
95
+ return /^[A-Za-z_$][\w$]*$/.test(at) ? `.${at}` : `[${JSON.stringify(at)}]`;
96
+ }
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "@nestjs/workflows",
3
- "version": "0.0.3",
4
- "description": "Nest - modern, fast, powerful node.js web framework (@workflows)",
3
+ "version": "0.0.5",
4
+ "description": "Durable workflows for NestJS: long-running processes written as plain async code that survive restarts, with no workflow server to run.",
5
+ "keywords": [
6
+ "nestjs",
7
+ "nest",
8
+ "workflow",
9
+ "workflows",
10
+ "durable-execution",
11
+ "durable-workflows",
12
+ "saga",
13
+ "orchestration",
14
+ "long-running",
15
+ "compensation"
16
+ ],
5
17
  "author": "Kamil Mysliwiec",
6
18
  "license": "MIT",
7
19
  "url": "https://github.com/nestjs/workflows#readme",
@@ -51,6 +63,7 @@
51
63
  "build": "rm -rf dist && tsc -p tsconfig.build.json",
52
64
  "format": "prettier --write \"**/*.ts\"",
53
65
  "lint": "oxlint lib/",
66
+ "typecheck": "tsc --noEmit -p tsconfig.json",
54
67
  "generate:prisma": "prisma generate --config tests/fixtures/prisma/prisma.config.ts && prisma generate --config tests/fixtures/prisma-mysql/prisma.config.ts",
55
68
  "prepublish:npm": "npm run build",
56
69
  "publish:npm": "npm publish --access public",
@@ -66,40 +79,40 @@
66
79
  "@nestjs/store-kit": "^0.1.0"
67
80
  },
68
81
  "devDependencies": {
69
- "@commitlint/cli": "21.2.3",
70
- "@commitlint/config-angular": "21.2.3",
71
- "@electric-sql/pglite": "0.5.8",
72
- "@nestjs/common": "12.1.2",
73
- "@nestjs/core": "12.1.2",
74
- "@nestjs/cqrs": "12.1.0",
75
- "@nestjs/drizzle": "0.0.1",
76
- "@nestjs/locks": "0.0.2",
82
+ "@commitlint/cli": "21.2.4",
83
+ "@commitlint/config-angular": "21.2.4",
84
+ "@electric-sql/pglite": "0.5.15",
85
+ "@nestjs/common": "12.3.3",
86
+ "@nestjs/core": "12.3.3",
87
+ "@nestjs/cqrs": "12.1.2",
88
+ "@nestjs/drizzle": "0.0.2",
89
+ "@nestjs/locks": "0.0.5",
77
90
  "@nestjs/mail": "0.0.1",
78
- "@nestjs/outbox": "0.1.1",
79
- "@nestjs/platform-express": "12.1.2",
80
- "@nestjs/platform-fastify": "12.1.2",
81
- "@nestjs/testing": "12.1.2",
82
- "@prisma/adapter-mariadb": "7.10.0",
83
- "@prisma/adapter-pg": "7.10.0",
84
- "@prisma/client": "7.10.0",
91
+ "@nestjs/outbox": "0.1.4",
92
+ "@nestjs/platform-express": "12.3.3",
93
+ "@nestjs/platform-fastify": "12.3.3",
94
+ "@nestjs/testing": "12.3.3",
95
+ "@prisma/adapter-mariadb": "7.10.1",
96
+ "@prisma/adapter-pg": "7.10.1",
97
+ "@prisma/client": "7.10.1",
85
98
  "@types/node": "24.19.2",
86
99
  "@types/pg": "8.23.1",
87
100
  "drizzle-orm": "0.45.4",
88
101
  "husky": "9.1.7",
89
- "kysely": "0.29.6",
102
+ "kysely": "0.29.8",
90
103
  "lint-staged": "17.6.0",
91
- "mysql2": "3.24.5",
92
- "oxlint": "1.87.0",
104
+ "mysql2": "3.24.6",
105
+ "oxlint": "1.91.0",
93
106
  "pg": "8.23.1",
94
107
  "prettier": "3.9.10",
95
- "prisma": "7.10.0",
108
+ "prisma": "7.10.1",
96
109
  "reflect-metadata": "0.2.2",
97
- "release-it": "21.1.1",
110
+ "release-it": "21.1.2",
98
111
  "rxjs": "7.8.2",
99
112
  "typeorm": "1.1.2",
100
113
  "typescript": "7.0.2",
101
- "vite": "8.3.4",
102
- "vitest": "5.0.3"
114
+ "vite": "8.3.6",
115
+ "vitest": "5.1.0"
103
116
  },
104
117
  "peerDependencies": {
105
118
  "@nestjs/common": "^11.0.0 || ^12.0.0",