@tailor-platform/create-sdk 2.0.0-next.0 → 2.0.0-next.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/CHANGELOG.md +30 -0
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/templates/executor/package.json +3 -3
- package/templates/executor/src/generated/db.ts +3 -3
- package/templates/generators/package.json +3 -3
- package/templates/generators/src/generated/db.ts +3 -3
- package/templates/generators/src/generated/files.ts +4 -4
- package/templates/generators/src/resolver/getProduct.test.ts +4 -3
- package/templates/generators/src/seed/data/Order.schema.ts +2 -2
- package/templates/generators/src/seed/data/Product.schema.ts +2 -2
- package/templates/generators/src/seed/data/User.schema.ts +2 -2
- package/templates/generators/src/seed/exec.mjs +1 -1
- package/templates/hello-world/package.json +3 -3
- package/templates/hello-world/src/generated/kysely-tailordb.ts +1 -1
- package/templates/inventory-management/package.json +3 -3
- package/templates/inventory-management/src/executor/checkInventory.ts +1 -2
- package/templates/inventory-management/src/generated/kysely-tailordb.ts +8 -8
- package/templates/inventory-management/src/resolver/registerOrder.ts +2 -2
- package/templates/multi-application/apps/admin/db/adminNote.ts +1 -1
- package/templates/multi-application/package.json +3 -3
- package/templates/resolver/README.md +2 -2
- package/templates/resolver/package.json +3 -3
- package/templates/resolver/src/generated/db.ts +1 -1
- package/templates/resolver/src/resolver/add.test.ts +4 -3
- package/templates/resolver/src/resolver/incrementUserAge.test.ts +4 -3
- package/templates/resolver/src/resolver/showEnv.test.ts +2 -2
- package/templates/resolver/src/resolver/showUserInfo.test.ts +12 -9
- package/templates/resolver/src/resolver/showUserInfo.ts +3 -3
- package/templates/resolver/src/resolver/upsertUsers.test.ts +2 -2
- package/templates/static-web-site/package.json +3 -3
- package/templates/tailordb/package.json +3 -3
- package/templates/tailordb/src/generated/db.ts +3 -3
- package/templates/workflow/README.md +1 -1
- package/templates/workflow/e2e/workflow.test.ts +1 -2
- package/templates/workflow/package.json +4 -4
- package/templates/workflow/src/generated/db.ts +2 -2
- package/templates/workflow/src/resolver/resolveApproval.test.ts +4 -3
- package/templates/workflow/src/workflow/approval.test.ts +8 -2
- package/templates/workflow/src/workflow/order-fulfillment.test.ts +30 -17
- package/templates/workflow/src/workflow/order-fulfillment.ts +4 -4
- package/templates/workflow/vitest.config.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
# @tailor-platform/create-sdk
|
|
2
2
|
|
|
3
|
+
## 2.0.0-next.2
|
|
4
|
+
### Major Changes
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
- [#1498](https://github.com/tailor-platform/sdk/pull/1498) [`83145db`](https://github.com/tailor-platform/sdk/commit/83145db9a0d243aa68c1b641c2b6026771a62188) Thanks [@dqn](https://github.com/dqn)! - Set `db.fields.timestamps()` `updatedAt` when records are created and make the generated field non-null. `createdAt` keeps its existing create-time behavior, while `updatedAt` keeps its update-time behavior and now also gets a create hook that preserves provided values and falls back to the current time.
|
|
9
|
+
|
|
10
|
+
Update create-sdk templates so scaffolded projects use the new non-null `updatedAt` Kysely types and seed schemas.
|
|
11
|
+
|
|
12
|
+
Existing TailorDB schemas that already use this helper will change `updatedAt` from optional to required. Backfill existing records that have `updatedAt: null` before applying the schema change.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
- [#1509](https://github.com/tailor-platform/sdk/pull/1509) [`7cadaa7`](https://github.com/tailor-platform/sdk/commit/7cadaa7c4987b81130ca80ba80bc5d5b26276394) Thanks [@dqn](https://github.com/dqn)! - Rename resolver, executor, workflow trigger, and typed workflow start machine-user options from `authInvoker` to `invoker`.
|
|
19
|
+
|
|
20
|
+
Update create-sdk templates and the v2 auth invoker codemod to generate the new `invoker` option.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
- [#1484](https://github.com/tailor-platform/sdk/pull/1484) [`a376dc8`](https://github.com/tailor-platform/sdk/commit/a376dc8cd053d20744c90104e8b44ed2729ffe8c) Thanks [@dqn](https://github.com/dqn)! - Remove the deprecated `openDownloadStream` file streaming API. Use `downloadStream` for streamed file downloads.
|
|
24
|
+
|
|
25
|
+
The generated file utilities now emit `downloadFileStream`, which calls `downloadStream` and returns `FileDownloadStreamResponse`, instead of the removed `openFileDownloadStream` helper.
|
|
26
|
+
|
|
27
|
+
## 2.0.0-next.1
|
|
28
|
+
|
|
3
29
|
## 2.0.0-next.0
|
|
4
30
|
|
|
31
|
+
## 1.66.0
|
|
32
|
+
|
|
33
|
+
## 1.65.0
|
|
34
|
+
|
|
5
35
|
## 1.64.0
|
|
6
36
|
|
|
7
37
|
## 1.63.0
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ const templateHints = {
|
|
|
23
23
|
workflow: "Workflow patterns with job chaining and testing",
|
|
24
24
|
executor: "Executor trigger types (record, resolver, schedule, webhook)",
|
|
25
25
|
"static-web-site": "Static website with auth and IdP integration",
|
|
26
|
-
generators: "Built-in
|
|
26
|
+
generators: "Built-in generation plugins: kysely, enums, files, seed"
|
|
27
27
|
};
|
|
28
28
|
const validateName = (name) => {
|
|
29
29
|
if (!name) return "Project name is required.";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/create-sdk",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.2",
|
|
4
4
|
"description": "A CLI tool to quickly create a new Tailor Platform SDK project",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
"execa": "9.6.1",
|
|
22
22
|
"picocolors": "1.1.1",
|
|
23
23
|
"pkg-types": "2.3.1",
|
|
24
|
-
"politty": "0.
|
|
24
|
+
"politty": "0.6.0",
|
|
25
25
|
"zod": "4.4.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@types/node": "24.13.
|
|
28
|
+
"@types/node": "24.13.2",
|
|
29
29
|
"oxlint": "1.69.0",
|
|
30
30
|
"oxlint-tsgolint": "0.23.0",
|
|
31
31
|
"tsdown": "0.22.2",
|
|
32
|
-
"typescript": "
|
|
32
|
+
"typescript": "6.0.3"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsdown",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"typecheck": "tsc --noEmit"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
18
|
-
"@types/node": "24.13.
|
|
17
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
18
|
+
"@types/node": "24.13.2",
|
|
19
19
|
"oxfmt": "0.54.0",
|
|
20
20
|
"oxlint": "1.69.0",
|
|
21
21
|
"oxlint-tsgolint": "0.23.0",
|
|
22
|
-
"typescript": "
|
|
22
|
+
"typescript": "6.0.3",
|
|
23
23
|
"vitest": "4.1.8"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -20,7 +20,7 @@ export interface Namespace {
|
|
|
20
20
|
entityId: string;
|
|
21
21
|
message: string;
|
|
22
22
|
createdAt: Generated<Timestamp>;
|
|
23
|
-
updatedAt: Timestamp
|
|
23
|
+
updatedAt: Generated<Timestamp>;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
Notification: {
|
|
@@ -30,7 +30,7 @@ export interface Namespace {
|
|
|
30
30
|
body: string;
|
|
31
31
|
isRead: boolean;
|
|
32
32
|
createdAt: Generated<Timestamp>;
|
|
33
|
-
updatedAt: Timestamp
|
|
33
|
+
updatedAt: Generated<Timestamp>;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
User: {
|
|
@@ -39,7 +39,7 @@ export interface Namespace {
|
|
|
39
39
|
email: string;
|
|
40
40
|
role: "ADMIN" | "MEMBER";
|
|
41
41
|
createdAt: Generated<Timestamp>;
|
|
42
|
-
updatedAt: Timestamp
|
|
42
|
+
updatedAt: Generated<Timestamp>;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"typecheck": "tsc --noEmit"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
18
|
-
"@types/node": "24.13.
|
|
17
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
18
|
+
"@types/node": "24.13.2",
|
|
19
19
|
"oxfmt": "0.54.0",
|
|
20
20
|
"oxlint": "1.69.0",
|
|
21
21
|
"oxlint-tsgolint": "0.23.0",
|
|
22
|
-
"typescript": "
|
|
22
|
+
"typescript": "6.0.3",
|
|
23
23
|
"vitest": "4.1.8"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -28,7 +28,7 @@ export interface Namespace {
|
|
|
28
28
|
totalPrice: number;
|
|
29
29
|
status: "PENDING" | "CONFIRMED" | "SHIPPED" | "DELIVERED" | "CANCELLED";
|
|
30
30
|
createdAt: Generated<Timestamp>;
|
|
31
|
-
updatedAt: Timestamp
|
|
31
|
+
updatedAt: Generated<Timestamp>;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
Product: {
|
|
@@ -39,7 +39,7 @@ export interface Namespace {
|
|
|
39
39
|
status: "DRAFT" | "ACTIVE" | "DISCONTINUED";
|
|
40
40
|
categoryId: string | null;
|
|
41
41
|
createdAt: Generated<Timestamp>;
|
|
42
|
-
updatedAt: Timestamp
|
|
42
|
+
updatedAt: Generated<Timestamp>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
User: {
|
|
@@ -48,7 +48,7 @@ export interface Namespace {
|
|
|
48
48
|
email: string;
|
|
49
49
|
role: "ADMIN" | "MEMBER" | "VIEWER";
|
|
50
50
|
createdAt: Generated<Timestamp>;
|
|
51
|
-
updatedAt: Timestamp
|
|
51
|
+
updatedAt: Generated<Timestamp>;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
FileUploadOptions,
|
|
4
4
|
FileUploadResponse,
|
|
5
5
|
FileMetadata,
|
|
6
|
-
|
|
6
|
+
FileDownloadStreamResponse,
|
|
7
7
|
} from "@tailor-platform/sdk/runtime/file";
|
|
8
8
|
|
|
9
9
|
export interface TypeWithFiles {
|
|
@@ -50,10 +50,10 @@ export async function getFileMetadata<T extends keyof TypeWithFiles>(
|
|
|
50
50
|
return await file.getMetadata(namespaces[type], type, field, recordId);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export async function
|
|
53
|
+
export async function downloadFileStream<T extends keyof TypeWithFiles>(
|
|
54
54
|
type: T,
|
|
55
55
|
field: TypeWithFiles[T]["fields"],
|
|
56
56
|
recordId: string,
|
|
57
|
-
): Promise<
|
|
58
|
-
return await file.
|
|
57
|
+
): Promise<FileDownloadStreamResponse> {
|
|
58
|
+
return await file.downloadStream(namespaces[type], type, field, recordId);
|
|
59
59
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
1
|
import { mockTailordb } from "@tailor-platform/sdk/vitest";
|
|
3
2
|
import { describe, expect, test } from "vitest";
|
|
4
3
|
import resolver from "./getProduct";
|
|
@@ -22,7 +21,8 @@ describe("getProduct resolver", () => {
|
|
|
22
21
|
|
|
23
22
|
const result = await resolver.body({
|
|
24
23
|
input: { productId: "product-1" },
|
|
25
|
-
|
|
24
|
+
caller: null,
|
|
25
|
+
invoker: null,
|
|
26
26
|
env: {},
|
|
27
27
|
});
|
|
28
28
|
|
|
@@ -51,7 +51,8 @@ describe("getProduct resolver", () => {
|
|
|
51
51
|
|
|
52
52
|
const result = await resolver.body({
|
|
53
53
|
input: { productId: "product-2" },
|
|
54
|
-
|
|
54
|
+
caller: null,
|
|
55
|
+
invoker: null,
|
|
55
56
|
env: {},
|
|
56
57
|
});
|
|
57
58
|
|
|
@@ -4,8 +4,8 @@ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/t
|
|
|
4
4
|
import { order } from "../../db/order";
|
|
5
5
|
|
|
6
6
|
const schemaType = t.object({
|
|
7
|
-
...order.pickFields(["id","createdAt"], { optional: true }),
|
|
8
|
-
...order.omitFields(["id","createdAt"]),
|
|
7
|
+
...order.pickFields(["id","createdAt","updatedAt"], { optional: true }),
|
|
8
|
+
...order.omitFields(["id","createdAt","updatedAt"]),
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
const hook = createTailorDBHook(order);
|
|
@@ -4,8 +4,8 @@ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/t
|
|
|
4
4
|
import { product } from "../../db/product";
|
|
5
5
|
|
|
6
6
|
const schemaType = t.object({
|
|
7
|
-
...product.pickFields(["id","createdAt"], { optional: true }),
|
|
8
|
-
...product.omitFields(["id","createdAt"]),
|
|
7
|
+
...product.pickFields(["id","createdAt","updatedAt"], { optional: true }),
|
|
8
|
+
...product.omitFields(["id","createdAt","updatedAt"]),
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
const hook = createTailorDBHook(product);
|
|
@@ -4,8 +4,8 @@ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/t
|
|
|
4
4
|
import { user } from "../../db/user";
|
|
5
5
|
|
|
6
6
|
const schemaType = t.object({
|
|
7
|
-
...user.pickFields(["id","createdAt"], { optional: true }),
|
|
8
|
-
...user.omitFields(["id","createdAt"]),
|
|
7
|
+
...user.pickFields(["id","createdAt","updatedAt"], { optional: true }),
|
|
8
|
+
...user.omitFields(["id","createdAt","updatedAt"]),
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
const hook = createTailorDBHook(user);
|
|
@@ -388,7 +388,7 @@ const seedViaTestExecScript = async (namespace, typesToSeed, deps, selfRefTypes)
|
|
|
388
388
|
workspaceId,
|
|
389
389
|
name: `seed-${namespace}.ts`,
|
|
390
390
|
code: bundled.bundledCode,
|
|
391
|
-
arg:
|
|
391
|
+
arg: { data: chunk.data, order: chunk.order, selfRefTypes },
|
|
392
392
|
invoker: {
|
|
393
393
|
namespace: authNamespace,
|
|
394
394
|
machineUserName,
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
16
|
-
"@types/node": "24.13.
|
|
15
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
16
|
+
"@types/node": "24.13.2",
|
|
17
17
|
"oxfmt": "0.54.0",
|
|
18
18
|
"oxlint": "1.69.0",
|
|
19
19
|
"oxlint-tsgolint": "0.23.0",
|
|
20
|
-
"typescript": "
|
|
20
|
+
"typescript": "6.0.3"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
16
|
-
"@types/node": "24.13.
|
|
15
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
16
|
+
"@types/node": "24.13.2",
|
|
17
17
|
"oxfmt": "0.54.0",
|
|
18
18
|
"oxlint": "1.69.0",
|
|
19
19
|
"oxlint-tsgolint": "0.23.0",
|
|
20
|
-
"typescript": "
|
|
20
|
+
"typescript": "6.0.3"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createExecutor, recordUpdatedTrigger } from "@tailor-platform/sdk";
|
|
2
2
|
import { inventory } from "../db/inventory";
|
|
3
|
-
import config from "../../tailor.config";
|
|
4
3
|
import { getDB } from "../generated/kysely-tailordb";
|
|
5
4
|
|
|
6
5
|
export default createExecutor({
|
|
@@ -22,6 +21,6 @@ export default createExecutor({
|
|
|
22
21
|
})
|
|
23
22
|
.execute();
|
|
24
23
|
},
|
|
25
|
-
invoker:
|
|
24
|
+
invoker: "manager",
|
|
26
25
|
},
|
|
27
26
|
});
|
|
@@ -18,7 +18,7 @@ export interface Namespace {
|
|
|
18
18
|
name: string;
|
|
19
19
|
description: string | null;
|
|
20
20
|
createdAt: Generated<Timestamp>;
|
|
21
|
-
updatedAt: Timestamp
|
|
21
|
+
updatedAt: Generated<Timestamp>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
Contact: {
|
|
@@ -28,7 +28,7 @@ export interface Namespace {
|
|
|
28
28
|
phone: string | null;
|
|
29
29
|
address: string | null;
|
|
30
30
|
createdAt: Generated<Timestamp>;
|
|
31
|
-
updatedAt: Timestamp
|
|
31
|
+
updatedAt: Generated<Timestamp>;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
Inventory: {
|
|
@@ -36,14 +36,14 @@ export interface Namespace {
|
|
|
36
36
|
productId: string;
|
|
37
37
|
quantity: number;
|
|
38
38
|
createdAt: Generated<Timestamp>;
|
|
39
|
-
updatedAt: Timestamp
|
|
39
|
+
updatedAt: Generated<Timestamp>;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
Notification: {
|
|
43
43
|
id: Generated<string>;
|
|
44
44
|
message: string;
|
|
45
45
|
createdAt: Generated<Timestamp>;
|
|
46
|
-
updatedAt: Timestamp
|
|
46
|
+
updatedAt: Generated<Timestamp>;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
Order: {
|
|
@@ -54,7 +54,7 @@ export interface Namespace {
|
|
|
54
54
|
orderType: "PURCHASE" | "SALES";
|
|
55
55
|
contactId: string;
|
|
56
56
|
createdAt: Generated<Timestamp>;
|
|
57
|
-
updatedAt: Timestamp
|
|
57
|
+
updatedAt: Generated<Timestamp>;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
OrderItem: {
|
|
@@ -65,7 +65,7 @@ export interface Namespace {
|
|
|
65
65
|
unitPrice: number;
|
|
66
66
|
totalPrice: Generated<number | null>;
|
|
67
67
|
createdAt: Generated<Timestamp>;
|
|
68
|
-
updatedAt: Timestamp
|
|
68
|
+
updatedAt: Generated<Timestamp>;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
Product: {
|
|
@@ -74,7 +74,7 @@ export interface Namespace {
|
|
|
74
74
|
description: string | null;
|
|
75
75
|
categoryId: string;
|
|
76
76
|
createdAt: Generated<Timestamp>;
|
|
77
|
-
updatedAt: Timestamp
|
|
77
|
+
updatedAt: Generated<Timestamp>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
User: {
|
|
@@ -83,7 +83,7 @@ export interface Namespace {
|
|
|
83
83
|
email: string;
|
|
84
84
|
role: "MANAGER" | "STAFF";
|
|
85
85
|
createdAt: Generated<Timestamp>;
|
|
86
|
-
updatedAt: Timestamp
|
|
86
|
+
updatedAt: Generated<Timestamp>;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -4,8 +4,8 @@ import { orderItem } from "../db/orderItem";
|
|
|
4
4
|
import { type DB, getDB } from "../generated/kysely-tailordb";
|
|
5
5
|
|
|
6
6
|
const input = {
|
|
7
|
-
order: t.object(order.omitFields(["id", "createdAt"])),
|
|
8
|
-
items: t.object(orderItem.omitFields(["id", "createdAt"]), { array: true }),
|
|
7
|
+
order: t.object(order.omitFields(["id", "createdAt", "updatedAt"])),
|
|
8
|
+
items: t.object(orderItem.omitFields(["id", "createdAt", "updatedAt"]), { array: true }),
|
|
9
9
|
};
|
|
10
10
|
interface Input {
|
|
11
11
|
order: t.infer<typeof input.order>;
|
|
@@ -8,7 +8,7 @@ export const adminNote = db
|
|
|
8
8
|
.type("AdminNote", {
|
|
9
9
|
title: db.string(),
|
|
10
10
|
content: db.string(),
|
|
11
|
-
authorId: db.uuid().hooks({ create: ({
|
|
11
|
+
authorId: db.uuid().hooks({ create: ({ invoker }) => invoker?.id ?? crypto.randomUUID() }),
|
|
12
12
|
...db.fields.timestamps(),
|
|
13
13
|
})
|
|
14
14
|
// NOTE: This permits all operations for simplicity.
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
"typecheck": "tsc --noEmit"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
17
|
-
"@types/node": "24.13.
|
|
16
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
17
|
+
"@types/node": "24.13.2",
|
|
18
18
|
"oxfmt": "0.54.0",
|
|
19
19
|
"oxlint": "1.69.0",
|
|
20
20
|
"oxlint-tsgolint": "0.23.0",
|
|
21
|
-
"typescript": "
|
|
21
|
+
"typescript": "6.0.3"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -8,11 +8,11 @@ Demonstrates all resolver patterns with comprehensive testing approaches.
|
|
|
8
8
|
- Database query resolver (Kysely with transactions)
|
|
9
9
|
- Database mutation resolver (dependency injection pattern)
|
|
10
10
|
- Environment variable access
|
|
11
|
-
-
|
|
11
|
+
- Caller and invoker context access
|
|
12
12
|
|
|
13
13
|
## Testing Approaches
|
|
14
14
|
|
|
15
|
-
1. **Direct `body()` call** - Simple resolvers with `
|
|
15
|
+
1. **Direct `body()` call** - Simple resolvers with explicit `caller` / `invoker` context values
|
|
16
16
|
2. **`tailor-runtime` environment + `mockTailordb`** - Database resolvers via `mockTailordb` from `@tailor-platform/sdk/vitest` (no `vi.stubGlobal` needed)
|
|
17
17
|
3. **Dependency injection** - Extract `DbOperations` interface for testability
|
|
18
18
|
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"typecheck": "tsc --noEmit"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
18
|
-
"@types/node": "24.13.
|
|
17
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
18
|
+
"@types/node": "24.13.2",
|
|
19
19
|
"oxfmt": "0.54.0",
|
|
20
20
|
"oxlint": "1.69.0",
|
|
21
21
|
"oxlint-tsgolint": "0.23.0",
|
|
22
|
-
"typescript": "
|
|
22
|
+
"typescript": "6.0.3",
|
|
23
23
|
"vitest": "4.1.8"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
1
|
import { describe, expect, test } from "vitest";
|
|
3
2
|
import resolver from "./add";
|
|
4
3
|
|
|
@@ -6,7 +5,8 @@ describe("add resolver", () => {
|
|
|
6
5
|
test("adds two positive numbers", async () => {
|
|
7
6
|
const result = await resolver.body({
|
|
8
7
|
input: { left: 1, right: 2 },
|
|
9
|
-
|
|
8
|
+
caller: null,
|
|
9
|
+
invoker: null,
|
|
10
10
|
env: { appName: "Resolver Template", version: 1 },
|
|
11
11
|
});
|
|
12
12
|
expect(result).toBe(3);
|
|
@@ -15,7 +15,8 @@ describe("add resolver", () => {
|
|
|
15
15
|
test("handles negative numbers", async () => {
|
|
16
16
|
const result = await resolver.body({
|
|
17
17
|
input: { left: -5, right: 3 },
|
|
18
|
-
|
|
18
|
+
caller: null,
|
|
19
|
+
invoker: null,
|
|
19
20
|
env: { appName: "Resolver Template", version: 1 },
|
|
20
21
|
});
|
|
21
22
|
expect(result).toBe(-2);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
1
|
import { mockTailordb } from "@tailor-platform/sdk/vitest";
|
|
3
2
|
import { describe, expect, test } from "vitest";
|
|
4
3
|
import resolver from "./incrementUserAge";
|
|
@@ -15,7 +14,8 @@ describe("incrementUserAge resolver", () => {
|
|
|
15
14
|
|
|
16
15
|
const result = await resolver.body({
|
|
17
16
|
input: { email: "test@example.com" },
|
|
18
|
-
|
|
17
|
+
caller: null,
|
|
18
|
+
invoker: null,
|
|
19
19
|
env: { appName: "Resolver Template", version: 1 },
|
|
20
20
|
});
|
|
21
21
|
expect(result).toEqual({ oldAge: 30, newAge: 31 });
|
|
@@ -32,7 +32,8 @@ describe("incrementUserAge resolver", () => {
|
|
|
32
32
|
|
|
33
33
|
const result = resolver.body({
|
|
34
34
|
input: { email: "test@example.com" },
|
|
35
|
-
|
|
35
|
+
caller: null,
|
|
36
|
+
invoker: null,
|
|
36
37
|
env: { appName: "Resolver Template", version: 1 },
|
|
37
38
|
});
|
|
38
39
|
await expect(result).rejects.toThrowError(/no result/i);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
1
|
import { describe, expect, test } from "vitest";
|
|
3
2
|
import resolver from "./showEnv";
|
|
4
3
|
|
|
@@ -6,7 +5,8 @@ describe("showEnv resolver", () => {
|
|
|
6
5
|
test("returns environment variables", async () => {
|
|
7
6
|
const result = await resolver.body({
|
|
8
7
|
input: undefined as never,
|
|
9
|
-
|
|
8
|
+
caller: null,
|
|
9
|
+
invoker: null,
|
|
10
10
|
env: { appName: "Resolver Template", version: 1 },
|
|
11
11
|
});
|
|
12
12
|
expect(result).toEqual({ appName: "Resolver Template", version: 1 });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TailorPrincipal } from "@tailor-platform/sdk";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
3
|
import resolver from "./showUserInfo";
|
|
4
4
|
|
|
@@ -6,26 +6,29 @@ describe("showUserInfo resolver", () => {
|
|
|
6
6
|
test("returns default user info", async () => {
|
|
7
7
|
const result = await resolver.body({
|
|
8
8
|
input: undefined as never,
|
|
9
|
-
|
|
9
|
+
caller: null,
|
|
10
|
+
invoker: null,
|
|
10
11
|
env: { appName: "Resolver Template", version: 1 },
|
|
11
12
|
});
|
|
12
13
|
expect(result).toEqual({
|
|
13
|
-
userId:
|
|
14
|
-
userType:
|
|
15
|
-
workspaceId:
|
|
14
|
+
userId: "anonymous",
|
|
15
|
+
userType: "anonymous",
|
|
16
|
+
workspaceId: "",
|
|
16
17
|
});
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
test("returns custom user info", async () => {
|
|
20
|
-
const
|
|
21
|
-
...unauthenticatedTailorUser,
|
|
21
|
+
const customCaller = {
|
|
22
22
|
id: "user-123",
|
|
23
23
|
type: "machine_user" as const,
|
|
24
24
|
workspaceId: "ws-456",
|
|
25
|
-
|
|
25
|
+
attributes: { role: "admin" },
|
|
26
|
+
attributeList: [],
|
|
27
|
+
} satisfies TailorPrincipal;
|
|
26
28
|
const result = await resolver.body({
|
|
27
29
|
input: undefined as never,
|
|
28
|
-
|
|
30
|
+
caller: customCaller,
|
|
31
|
+
invoker: customCaller,
|
|
29
32
|
env: { appName: "Resolver Template", version: 1 },
|
|
30
33
|
});
|
|
31
34
|
expect(result).toEqual({
|
|
@@ -6,9 +6,9 @@ const resolver = createResolver({
|
|
|
6
6
|
operation: "query",
|
|
7
7
|
body: (context) => {
|
|
8
8
|
return {
|
|
9
|
-
userId: context.
|
|
10
|
-
userType: context.
|
|
11
|
-
workspaceId: context.
|
|
9
|
+
userId: context.caller?.id ?? "anonymous",
|
|
10
|
+
userType: context.caller?.type ?? "anonymous",
|
|
11
|
+
workspaceId: context.caller?.workspaceId ?? "",
|
|
12
12
|
};
|
|
13
13
|
},
|
|
14
14
|
output: t.object({
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
2
1
|
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
|
|
3
2
|
import { describe, expect, test, vi } from "vitest";
|
|
4
3
|
import { getDB, type Namespace } from "../generated/db";
|
|
@@ -30,7 +29,8 @@ describe("upsertUsers resolver", () => {
|
|
|
30
29
|
{ name: "Existing", email: "exists@example.com", age: 41 },
|
|
31
30
|
],
|
|
32
31
|
},
|
|
33
|
-
|
|
32
|
+
caller: null,
|
|
33
|
+
invoker: null,
|
|
34
34
|
env: { appName: "Resolver Template", version: 1 },
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
16
|
-
"@types/node": "24.13.
|
|
15
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
16
|
+
"@types/node": "24.13.2",
|
|
17
17
|
"oxfmt": "0.54.0",
|
|
18
18
|
"oxlint": "1.69.0",
|
|
19
19
|
"oxlint-tsgolint": "0.23.0",
|
|
20
|
-
"typescript": "
|
|
20
|
+
"typescript": "6.0.3"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"typecheck": "tsc --noEmit"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
18
|
-
"@types/node": "24.13.
|
|
17
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
18
|
+
"@types/node": "24.13.2",
|
|
19
19
|
"oxfmt": "0.54.0",
|
|
20
20
|
"oxlint": "1.69.0",
|
|
21
21
|
"oxlint-tsgolint": "0.23.0",
|
|
22
|
-
"typescript": "
|
|
22
|
+
"typescript": "6.0.3",
|
|
23
23
|
"vitest": "4.1.8"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -32,7 +32,7 @@ export interface Namespace {
|
|
|
32
32
|
isInternal: boolean;
|
|
33
33
|
}>;
|
|
34
34
|
createdAt: Generated<Timestamp>;
|
|
35
|
-
updatedAt: Timestamp
|
|
35
|
+
updatedAt: Generated<Timestamp>;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
Task: {
|
|
@@ -46,7 +46,7 @@ export interface Namespace {
|
|
|
46
46
|
categoryId: string | null;
|
|
47
47
|
isArchived: Generated<boolean>;
|
|
48
48
|
createdAt: Generated<Timestamp>;
|
|
49
|
-
updatedAt: Timestamp
|
|
49
|
+
updatedAt: Generated<Timestamp>;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
User: {
|
|
@@ -56,7 +56,7 @@ export interface Namespace {
|
|
|
56
56
|
role: "ADMIN" | "MEMBER" | "VIEWER";
|
|
57
57
|
bio: string | null;
|
|
58
58
|
createdAt: Generated<Timestamp>;
|
|
59
|
-
updatedAt: Timestamp
|
|
59
|
+
updatedAt: Generated<Timestamp>;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -7,7 +7,7 @@ Demonstrates workflow patterns with job chaining, trigger testing, and dependenc
|
|
|
7
7
|
- Workflow with multiple jobs (`createWorkflow`, `createWorkflowJob`)
|
|
8
8
|
- Job chaining via `.trigger()`
|
|
9
9
|
- Database operations in workflow jobs (DI pattern)
|
|
10
|
-
- Integration testing with `
|
|
10
|
+
- Integration testing with `runWorkflowLocally()`
|
|
11
11
|
|
|
12
12
|
## Getting Started
|
|
13
13
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
3
|
import { startWorkflow } from "@tailor-platform/sdk/cli";
|
|
4
|
-
import config from "../tailor.config";
|
|
5
4
|
import userProfileSyncWorkflow from "../src/workflow/sync-profile";
|
|
6
5
|
|
|
7
6
|
describe("workflow", () => {
|
|
@@ -11,7 +10,7 @@ describe("workflow", () => {
|
|
|
11
10
|
|
|
12
11
|
const { executionId, wait } = await startWorkflow({
|
|
13
12
|
workflow: userProfileSyncWorkflow,
|
|
14
|
-
|
|
13
|
+
invoker: "admin",
|
|
15
14
|
arg: {
|
|
16
15
|
name: "workflow-test-user",
|
|
17
16
|
email: testEmail,
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
"typecheck": "tsc --noEmit"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@tailor-platform/sdk": "2.0.0-next.
|
|
19
|
-
"@types/node": "24.13.
|
|
20
|
-
"graphql": "16.14.
|
|
18
|
+
"@tailor-platform/sdk": "2.0.0-next.2",
|
|
19
|
+
"@types/node": "24.13.2",
|
|
20
|
+
"graphql": "16.14.2",
|
|
21
21
|
"graphql-request": "7.4.0",
|
|
22
22
|
"oxfmt": "0.54.0",
|
|
23
23
|
"oxlint": "1.69.0",
|
|
24
24
|
"oxlint-tsgolint": "0.23.0",
|
|
25
|
-
"typescript": "
|
|
25
|
+
"typescript": "6.0.3",
|
|
26
26
|
"vitest": "4.1.8"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -19,7 +19,7 @@ export interface Namespace {
|
|
|
19
19
|
amount: number;
|
|
20
20
|
status: "PENDING" | "PROCESSING" | "COMPLETED" | "FAILED";
|
|
21
21
|
createdAt: Generated<Timestamp>;
|
|
22
|
-
updatedAt: Timestamp
|
|
22
|
+
updatedAt: Generated<Timestamp>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
User: {
|
|
@@ -28,7 +28,7 @@ export interface Namespace {
|
|
|
28
28
|
email: string;
|
|
29
29
|
age: number;
|
|
30
30
|
createdAt: Generated<Timestamp>;
|
|
31
|
-
updatedAt: Timestamp
|
|
31
|
+
updatedAt: Generated<Timestamp>;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
2
|
import { mockWorkflow } from "@tailor-platform/sdk/vitest";
|
|
3
|
-
import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
|
|
4
3
|
import resolver from "./resolveApproval";
|
|
5
4
|
|
|
6
5
|
describe("resolveApproval resolver", () => {
|
|
@@ -16,7 +15,8 @@ describe("resolveApproval resolver", () => {
|
|
|
16
15
|
|
|
17
16
|
const result = await resolver.body({
|
|
18
17
|
input: { executionId: "exec-1", approved: true },
|
|
19
|
-
|
|
18
|
+
caller: null,
|
|
19
|
+
invoker: null,
|
|
20
20
|
env: {},
|
|
21
21
|
});
|
|
22
22
|
|
|
@@ -33,7 +33,8 @@ describe("resolveApproval resolver", () => {
|
|
|
33
33
|
|
|
34
34
|
const result = await resolver.body({
|
|
35
35
|
input: { executionId: "exec-2", approved: false },
|
|
36
|
-
|
|
36
|
+
caller: null,
|
|
37
|
+
invoker: null,
|
|
37
38
|
env: {},
|
|
38
39
|
});
|
|
39
40
|
|
|
@@ -7,7 +7,10 @@ describe("approval workflow", () => {
|
|
|
7
7
|
using wf = mockWorkflow();
|
|
8
8
|
wf.setWaitHandler((_key, _payload) => ({ approved: true }));
|
|
9
9
|
|
|
10
|
-
const result = await processWithApproval.body(
|
|
10
|
+
const result = await processWithApproval.body(
|
|
11
|
+
{ orderId: "order-1" },
|
|
12
|
+
{ env: {}, invoker: null },
|
|
13
|
+
);
|
|
11
14
|
|
|
12
15
|
expect(result).toEqual({ orderId: "order-1", status: "approved" });
|
|
13
16
|
expect(wf.waitCalls).toEqual([
|
|
@@ -22,7 +25,10 @@ describe("approval workflow", () => {
|
|
|
22
25
|
using wf = mockWorkflow();
|
|
23
26
|
wf.setWaitHandler({ approved: false });
|
|
24
27
|
|
|
25
|
-
const result = await processWithApproval.body(
|
|
28
|
+
const result = await processWithApproval.body(
|
|
29
|
+
{ orderId: "order-2" },
|
|
30
|
+
{ env: {}, invoker: null },
|
|
31
|
+
);
|
|
26
32
|
|
|
27
33
|
expect(result).toEqual({ orderId: "order-2", status: "rejected" });
|
|
28
34
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runWorkflowLocally } from "@tailor-platform/sdk/vitest";
|
|
1
2
|
import { describe, expect, test, vi } from "vitest";
|
|
2
3
|
import workflow, {
|
|
3
4
|
fulfillOrder,
|
|
@@ -9,18 +10,24 @@ import workflow, {
|
|
|
9
10
|
describe("order fulfillment workflow", () => {
|
|
10
11
|
describe("individual job tests with .body()", () => {
|
|
11
12
|
test("validateOrder accepts valid order", () => {
|
|
12
|
-
const result = validateOrder.body(
|
|
13
|
+
const result = validateOrder.body(
|
|
14
|
+
{ orderId: "order-1", amount: 100 },
|
|
15
|
+
{ env: {}, invoker: null },
|
|
16
|
+
);
|
|
13
17
|
expect(result).toEqual({ valid: true, orderId: "order-1" });
|
|
14
18
|
});
|
|
15
19
|
|
|
16
20
|
test("validateOrder rejects zero amount", () => {
|
|
17
|
-
expect(() =>
|
|
18
|
-
"
|
|
19
|
-
);
|
|
21
|
+
expect(() =>
|
|
22
|
+
validateOrder.body({ orderId: "order-1", amount: 0 }, { env: {}, invoker: null }),
|
|
23
|
+
).toThrow("Order amount must be positive");
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
test("processPayment returns transaction", () => {
|
|
23
|
-
const result = processPayment.body(
|
|
27
|
+
const result = processPayment.body(
|
|
28
|
+
{ orderId: "order-1", amount: 100 },
|
|
29
|
+
{ env: {}, invoker: null },
|
|
30
|
+
);
|
|
24
31
|
expect(result).toEqual({
|
|
25
32
|
transactionId: "txn-order-1",
|
|
26
33
|
amount: 100,
|
|
@@ -31,7 +38,7 @@ describe("order fulfillment workflow", () => {
|
|
|
31
38
|
test("sendConfirmation returns confirmation", () => {
|
|
32
39
|
const result = sendConfirmation.body(
|
|
33
40
|
{ orderId: "order-1", transactionId: "txn-1" },
|
|
34
|
-
{ env: {} },
|
|
41
|
+
{ env: {}, invoker: null },
|
|
35
42
|
);
|
|
36
43
|
expect(result).toEqual({
|
|
37
44
|
orderId: "order-1",
|
|
@@ -43,22 +50,25 @@ describe("order fulfillment workflow", () => {
|
|
|
43
50
|
|
|
44
51
|
describe("orchestration tests with mocked triggers", () => {
|
|
45
52
|
test("fulfillOrder chains all jobs", async () => {
|
|
46
|
-
using _validateSpy = vi.spyOn(validateOrder, "trigger").
|
|
53
|
+
using _validateSpy = vi.spyOn(validateOrder, "trigger").mockReturnValue({
|
|
47
54
|
valid: true,
|
|
48
55
|
orderId: "order-1",
|
|
49
56
|
});
|
|
50
|
-
using _paymentSpy = vi.spyOn(processPayment, "trigger").
|
|
57
|
+
using _paymentSpy = vi.spyOn(processPayment, "trigger").mockReturnValue({
|
|
51
58
|
transactionId: "txn-order-1",
|
|
52
59
|
amount: 100,
|
|
53
60
|
status: "completed" as const,
|
|
54
61
|
});
|
|
55
|
-
using _confirmSpy = vi.spyOn(sendConfirmation, "trigger").
|
|
62
|
+
using _confirmSpy = vi.spyOn(sendConfirmation, "trigger").mockReturnValue({
|
|
56
63
|
orderId: "order-1",
|
|
57
64
|
transactionId: "txn-order-1",
|
|
58
65
|
confirmed: true,
|
|
59
66
|
});
|
|
60
67
|
|
|
61
|
-
const result = await fulfillOrder.body(
|
|
68
|
+
const result = await fulfillOrder.body(
|
|
69
|
+
{ orderId: "order-1", amount: 100 },
|
|
70
|
+
{ env: {}, invoker: null },
|
|
71
|
+
);
|
|
62
72
|
|
|
63
73
|
expect(validateOrder.trigger).toHaveBeenCalledWith({
|
|
64
74
|
orderId: "order-1",
|
|
@@ -81,22 +91,25 @@ describe("order fulfillment workflow", () => {
|
|
|
81
91
|
});
|
|
82
92
|
|
|
83
93
|
test("workflow.mainJob.body() chains all jobs", async () => {
|
|
84
|
-
using _validateSpy = vi.spyOn(validateOrder, "trigger").
|
|
94
|
+
using _validateSpy = vi.spyOn(validateOrder, "trigger").mockReturnValue({
|
|
85
95
|
valid: true,
|
|
86
96
|
orderId: "order-2",
|
|
87
97
|
});
|
|
88
|
-
using _paymentSpy = vi.spyOn(processPayment, "trigger").
|
|
98
|
+
using _paymentSpy = vi.spyOn(processPayment, "trigger").mockReturnValue({
|
|
89
99
|
transactionId: "txn-order-2",
|
|
90
100
|
amount: 200,
|
|
91
101
|
status: "completed" as const,
|
|
92
102
|
});
|
|
93
|
-
using _confirmSpy = vi.spyOn(sendConfirmation, "trigger").
|
|
103
|
+
using _confirmSpy = vi.spyOn(sendConfirmation, "trigger").mockReturnValue({
|
|
94
104
|
orderId: "order-2",
|
|
95
105
|
transactionId: "txn-order-2",
|
|
96
106
|
confirmed: true,
|
|
97
107
|
});
|
|
98
108
|
|
|
99
|
-
const result = await workflow.mainJob.body(
|
|
109
|
+
const result = await workflow.mainJob.body(
|
|
110
|
+
{ orderId: "order-2", amount: 200 },
|
|
111
|
+
{ env: {}, invoker: null },
|
|
112
|
+
);
|
|
100
113
|
|
|
101
114
|
expect(result).toEqual({
|
|
102
115
|
orderId: "order-2",
|
|
@@ -107,9 +120,9 @@ describe("order fulfillment workflow", () => {
|
|
|
107
120
|
});
|
|
108
121
|
});
|
|
109
122
|
|
|
110
|
-
describe("integration tests with
|
|
111
|
-
test("
|
|
112
|
-
const result = await workflow
|
|
123
|
+
describe("integration tests with runWorkflowLocally()", () => {
|
|
124
|
+
test("runWorkflowLocally() executes all jobs", async () => {
|
|
125
|
+
const result = await runWorkflowLocally(workflow, {
|
|
113
126
|
orderId: "order-3",
|
|
114
127
|
amount: 300,
|
|
115
128
|
});
|
|
@@ -34,8 +34,8 @@ export const sendConfirmation = createWorkflowJob({
|
|
|
34
34
|
|
|
35
35
|
export const fulfillOrder = createWorkflowJob({
|
|
36
36
|
name: "fulfill-order",
|
|
37
|
-
body:
|
|
38
|
-
const validation =
|
|
37
|
+
body: (input: { orderId: string; amount: number }) => {
|
|
38
|
+
const validation = validateOrder.trigger({
|
|
39
39
|
orderId: input.orderId,
|
|
40
40
|
amount: input.amount,
|
|
41
41
|
});
|
|
@@ -44,12 +44,12 @@ export const fulfillOrder = createWorkflowJob({
|
|
|
44
44
|
throw new Error("Order validation failed");
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const payment =
|
|
47
|
+
const payment = processPayment.trigger({
|
|
48
48
|
orderId: input.orderId,
|
|
49
49
|
amount: input.amount,
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
const confirmation =
|
|
52
|
+
const confirmation = sendConfirmation.trigger({
|
|
53
53
|
orderId: input.orderId,
|
|
54
54
|
transactionId: payment.transactionId,
|
|
55
55
|
});
|