@tailor-platform/create-sdk 1.19.0 → 1.21.0
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 +4 -0
- package/dist/index.js +7 -2
- package/package.json +1 -1
- package/templates/executor/README.md +32 -0
- package/templates/{testing → executor}/eslint.config.js +0 -5
- package/templates/executor/package.json +30 -0
- package/templates/executor/src/db/auditLog.ts +24 -0
- package/templates/executor/src/db/notification.ts +27 -0
- package/templates/executor/src/db/user.ts +22 -0
- package/templates/executor/src/executor/dailyCleanup.ts +16 -0
- package/templates/executor/src/executor/externalWebhook.ts +18 -0
- package/templates/executor/src/executor/onDataProcessed.ts +26 -0
- package/templates/executor/src/executor/onIdpUserCreated.ts +19 -0
- package/templates/executor/src/executor/onIdpUserDeleted.ts +19 -0
- package/templates/executor/src/executor/onIdpUserUpdated.ts +19 -0
- package/templates/executor/src/executor/onTokenIssued.ts +19 -0
- package/templates/executor/src/executor/onTokenRefreshed.ts +19 -0
- package/templates/executor/src/executor/onTokenRevoked.ts +19 -0
- package/templates/executor/src/executor/onUserCreated.ts +23 -0
- package/templates/executor/src/executor/onUserDeleted.ts +22 -0
- package/templates/executor/src/executor/onUserUpdated.ts +22 -0
- package/templates/executor/src/executor/shared.test.ts +36 -0
- package/templates/executor/src/executor/shared.ts +13 -0
- package/templates/executor/src/generated/db.ts +59 -0
- package/templates/executor/src/resolver/processData.ts +22 -0
- package/templates/executor/src/workflow/cleanup.ts +13 -0
- package/templates/executor/tailor.config.ts +40 -0
- package/templates/executor/vitest.config.ts +15 -0
- package/templates/generators/.oxfmtrc.json +3 -0
- package/templates/generators/.oxlintrc.json +197 -0
- package/templates/generators/.prettierignore +1 -0
- package/templates/generators/.prettierrc +1 -0
- package/templates/generators/README.md +30 -0
- package/templates/generators/__dot__gitignore +3 -0
- package/templates/generators/eslint.config.js +24 -0
- package/templates/generators/package.json +30 -0
- package/templates/generators/src/db/category.ts +25 -0
- package/templates/generators/src/db/order.ts +38 -0
- package/templates/generators/src/db/product.ts +34 -0
- package/templates/generators/src/db/user.ts +26 -0
- package/templates/generators/src/generated/db.ts +68 -0
- package/templates/generators/src/generated/enums.ts +39 -0
- package/templates/generators/src/generated/files.ts +51 -0
- package/templates/generators/src/resolver/getProduct.test.ts +92 -0
- package/templates/generators/src/resolver/getProduct.ts +53 -0
- package/templates/generators/src/seed/data/Category.jsonl +0 -0
- package/templates/generators/src/seed/data/Category.schema.ts +23 -0
- package/templates/generators/src/seed/data/Order.jsonl +0 -0
- package/templates/generators/src/seed/data/Order.schema.ts +21 -0
- package/templates/generators/src/seed/data/Product.jsonl +0 -0
- package/templates/generators/src/seed/data/Product.schema.ts +23 -0
- package/templates/generators/src/seed/data/User.jsonl +0 -0
- package/templates/generators/src/seed/data/User.schema.ts +20 -0
- package/templates/generators/src/seed/exec.mjs +419 -0
- package/templates/generators/tailor.config.ts +36 -0
- package/templates/generators/tsconfig.json +16 -0
- package/templates/generators/vitest.config.ts +15 -0
- package/templates/hello-world/package.json +1 -1
- package/templates/inventory-management/package.json +1 -1
- package/templates/inventory-management/user-defined.d.ts +15 -0
- package/templates/multi-application/package.json +1 -1
- package/templates/resolver/.oxfmtrc.json +3 -0
- package/templates/resolver/.oxlintrc.json +197 -0
- package/templates/resolver/.prettierrc +1 -0
- package/templates/resolver/README.md +31 -0
- package/templates/resolver/__dot__gitignore +3 -0
- package/templates/resolver/eslint.config.js +24 -0
- package/templates/resolver/package.json +30 -0
- package/templates/resolver/src/resolver/add.test.ts +23 -0
- package/templates/{testing/src/resolver/mockTailordb.test.ts → resolver/src/resolver/queryUser.test.ts} +5 -6
- package/templates/{testing/src/resolver/mockTailordb.ts → resolver/src/resolver/queryUser.ts} +0 -5
- package/templates/resolver/src/resolver/showEnv.test.ts +14 -0
- package/templates/resolver/src/resolver/showEnv.ts +19 -0
- package/templates/resolver/src/resolver/showUserInfo.test.ts +37 -0
- package/templates/resolver/src/resolver/showUserInfo.ts +21 -0
- package/templates/{testing/src/resolver/wrapTailordb.test.ts → resolver/src/resolver/updateUser.test.ts} +3 -5
- package/templates/{testing/src/resolver/wrapTailordb.ts → resolver/src/resolver/updateUser.ts} +0 -5
- package/templates/resolver/tailor.config.ts +26 -0
- package/templates/resolver/tsconfig.json +16 -0
- package/templates/resolver/user-defined.d.ts +18 -0
- package/templates/resolver/vitest.config.ts +15 -0
- package/templates/static-web-site/.oxfmtrc.json +3 -0
- package/templates/static-web-site/.oxlintrc.json +197 -0
- package/templates/static-web-site/.prettierrc +1 -0
- package/templates/static-web-site/README.md +21 -0
- package/templates/static-web-site/__dot__gitignore +3 -0
- package/templates/static-web-site/eslint.config.js +24 -0
- package/templates/static-web-site/package.json +27 -0
- package/templates/static-web-site/public/callback.html +34 -0
- package/templates/static-web-site/public/index.html +55 -0
- package/templates/static-web-site/public/style.css +62 -0
- package/templates/static-web-site/src/db/user.ts +22 -0
- package/templates/static-web-site/tailor.config.ts +55 -0
- package/templates/static-web-site/tsconfig.json +16 -0
- package/templates/tailordb/.oxfmtrc.json +3 -0
- package/templates/tailordb/.oxlintrc.json +197 -0
- package/templates/tailordb/.prettierrc +1 -0
- package/templates/tailordb/README.md +29 -0
- package/templates/tailordb/__dot__gitignore +3 -0
- package/templates/tailordb/eslint.config.js +24 -0
- package/templates/tailordb/package.json +30 -0
- package/templates/tailordb/src/db/category.ts +15 -0
- package/templates/tailordb/src/db/comment.ts +26 -0
- package/templates/tailordb/src/db/permission.ts +43 -0
- package/templates/tailordb/src/db/task.test.ts +41 -0
- package/templates/tailordb/src/db/task.ts +58 -0
- package/templates/tailordb/src/db/user.ts +19 -0
- package/templates/tailordb/src/generated/db.ts +75 -0
- package/templates/tailordb/tailor.config.ts +26 -0
- package/templates/tailordb/tsconfig.json +16 -0
- package/templates/tailordb/user-defined.d.ts +15 -0
- package/templates/tailordb/vitest.config.ts +15 -0
- package/templates/workflow/.oxfmtrc.json +3 -0
- package/templates/workflow/.oxlintrc.json +197 -0
- package/templates/workflow/.prettierrc +1 -0
- package/templates/workflow/README.md +25 -0
- package/templates/workflow/__dot__gitignore +3 -0
- package/templates/{testing → workflow}/e2e/globalSetup.ts +5 -5
- package/templates/workflow/e2e/resolver.test.ts +90 -0
- package/templates/workflow/e2e/workflow.test.ts +31 -0
- package/templates/workflow/eslint.config.js +24 -0
- package/templates/{testing → workflow}/package.json +3 -2
- package/templates/workflow/src/db/order.ts +22 -0
- package/templates/workflow/src/db/user.ts +22 -0
- package/templates/workflow/src/generated/db.ts +48 -0
- package/templates/workflow/src/resolver/incrementAge.ts +40 -0
- package/templates/workflow/src/workflow/order-fulfillment.test.ts +148 -0
- package/templates/workflow/src/workflow/order-fulfillment.ts +69 -0
- package/templates/{testing/src/workflow/wrapTailordb.test.ts → workflow/src/workflow/sync-profile.test.ts} +1 -1
- package/templates/{testing → workflow}/tailor.config.ts +1 -1
- package/templates/workflow/tsconfig.json +16 -0
- package/templates/workflow/user-defined.d.ts +15 -0
- package/templates/testing/README.md +0 -130
- package/templates/testing/e2e/resolver.test.ts +0 -57
- package/templates/testing/e2e/workflow.test.ts +0 -47
- package/templates/testing/src/resolver/simple.test.ts +0 -14
- package/templates/testing/src/workflow/simple.test.ts +0 -88
- package/templates/testing/src/workflow/simple.ts +0 -36
- package/templates/testing/src/workflow/trigger.test.ts +0 -104
- /package/templates/{testing → executor}/.oxfmtrc.json +0 -0
- /package/templates/{testing → executor}/.oxlintrc.json +0 -0
- /package/templates/{testing → executor}/.prettierrc +0 -0
- /package/templates/{testing → executor}/__dot__gitignore +0 -0
- /package/templates/{testing → executor}/tsconfig.json +0 -0
- /package/templates/{testing → resolver}/src/db/user.ts +0 -0
- /package/templates/{testing → resolver}/src/generated/db.ts +0 -0
- /package/templates/{testing/src/resolver/simple.ts → resolver/src/resolver/add.ts} +0 -0
- /package/templates/{testing/src/workflow/wrapTailordb.ts → workflow/src/workflow/sync-profile.ts} +0 -0
- /package/templates/{testing → workflow}/vitest.config.ts +0 -0
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -18,8 +18,13 @@ const availableTemplates = async () => {
|
|
|
18
18
|
const templateHints = {
|
|
19
19
|
"hello-world": "Initial project to get started with Tailor Platform SDK",
|
|
20
20
|
"inventory-management": "Simple inventory management system",
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
"multi-application": "Multi-application setup with shared databases",
|
|
22
|
+
tailordb: "Comprehensive TailorDB type definitions with all features",
|
|
23
|
+
resolver: "Resolver patterns with testing (simple, DB, env, user)",
|
|
24
|
+
workflow: "Workflow patterns with job chaining and testing",
|
|
25
|
+
executor: "Executor trigger types (record, resolver, schedule, webhook)",
|
|
26
|
+
"static-web-site": "Static website with auth and IdP integration",
|
|
27
|
+
generators: "Built-in generators: kysely, enums, files, seed"
|
|
23
28
|
};
|
|
24
29
|
const validateName = (name) => {
|
|
25
30
|
if (name.length < 3 || name.length > 30) return "Project name must be between 3 and 30 characters long.";
|
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Executor Template
|
|
2
|
+
|
|
3
|
+
Demonstrates all executor trigger types with supporting infrastructure.
|
|
4
|
+
|
|
5
|
+
## Trigger Types
|
|
6
|
+
|
|
7
|
+
- `recordCreatedTrigger` - React to new record creation (with condition)
|
|
8
|
+
- `recordUpdatedTrigger` - React to record updates
|
|
9
|
+
- `resolverExecutedTrigger` - React to resolver execution
|
|
10
|
+
- `scheduleTrigger` - CRON-based scheduled execution
|
|
11
|
+
- `incomingWebhookTrigger` - React to external webhook calls
|
|
12
|
+
|
|
13
|
+
## Operation Kinds
|
|
14
|
+
|
|
15
|
+
- `function` - Custom function body
|
|
16
|
+
- `graphql` - Execute GraphQL mutations
|
|
17
|
+
- `webhook` - Send HTTP requests
|
|
18
|
+
- `workflow` - Trigger a workflow
|
|
19
|
+
|
|
20
|
+
## Getting Started
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm install
|
|
24
|
+
pnpm generate
|
|
25
|
+
pnpm deploy
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Testing
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm test
|
|
32
|
+
```
|
|
@@ -4,10 +4,7 @@ import { defineConfig, globalIgnores } from "eslint/config";
|
|
|
4
4
|
import oxlint from "eslint-plugin-oxlint";
|
|
5
5
|
|
|
6
6
|
export default defineConfig([
|
|
7
|
-
// Ignore sdk's output directory.
|
|
8
7
|
globalIgnores([".tailor-sdk/", "src/generated/"]),
|
|
9
|
-
// Use recommended rules.
|
|
10
|
-
// https://typescript-eslint.io/users/configs#projects-with-type-checking
|
|
11
8
|
eslint.configs.recommended,
|
|
12
9
|
tseslint.configs.recommendedTypeChecked,
|
|
13
10
|
tseslint.configs.stylisticTypeChecked,
|
|
@@ -19,8 +16,6 @@ export default defineConfig([
|
|
|
19
16
|
},
|
|
20
17
|
},
|
|
21
18
|
},
|
|
22
|
-
// Disable type-checked linting for root config files.
|
|
23
|
-
// https://typescript-eslint.io/troubleshooting/typed-linting/#how-do-i-disable-type-checked-linting-for-a-file
|
|
24
19
|
{
|
|
25
20
|
files: ["eslint.config.js"],
|
|
26
21
|
extends: [tseslint.configs.disableTypeChecked],
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "executor",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"generate": "tailor-sdk generate",
|
|
7
|
+
"deploy": "tailor-sdk apply",
|
|
8
|
+
"test": "vitest --project unit",
|
|
9
|
+
"test:unit": "vitest --project unit",
|
|
10
|
+
"format": "oxfmt --write .",
|
|
11
|
+
"format:check": "oxfmt --check .",
|
|
12
|
+
"lint": "oxlint --type-aware . && eslint --cache .",
|
|
13
|
+
"lint:fix": "oxlint --type-aware --fix . && eslint --cache --fix .",
|
|
14
|
+
"typecheck": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@eslint/js": "9.39.2",
|
|
18
|
+
"@tailor-platform/function-types": "0.8.0",
|
|
19
|
+
"@tailor-platform/sdk": "1.21.0",
|
|
20
|
+
"@types/node": "24.10.9",
|
|
21
|
+
"eslint": "9.39.2",
|
|
22
|
+
"eslint-plugin-oxlint": "1.39.0",
|
|
23
|
+
"oxfmt": "0.24.0",
|
|
24
|
+
"oxlint": "1.39.0",
|
|
25
|
+
"oxlint-tsgolint": "0.11.1",
|
|
26
|
+
"typescript": "5.9.3",
|
|
27
|
+
"typescript-eslint": "8.53.0",
|
|
28
|
+
"vitest": "4.0.17"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { db } from "@tailor-platform/sdk";
|
|
2
|
+
|
|
3
|
+
export const auditLog = db
|
|
4
|
+
.type("AuditLog", "Records system events for auditing", {
|
|
5
|
+
action: db.string(),
|
|
6
|
+
entityType: db.string(),
|
|
7
|
+
entityId: db.uuid(),
|
|
8
|
+
message: db.string(),
|
|
9
|
+
...db.fields.timestamps(),
|
|
10
|
+
})
|
|
11
|
+
.indexes({ fields: ["entityType", "entityId"], unique: false })
|
|
12
|
+
.permission({
|
|
13
|
+
create: [[{ user: "_loggedIn" }, "=", true]],
|
|
14
|
+
read: [[{ user: "_loggedIn" }, "=", true]],
|
|
15
|
+
update: [[{ user: "_loggedIn" }, "=", true]],
|
|
16
|
+
delete: [[{ user: "_loggedIn" }, "=", true]],
|
|
17
|
+
})
|
|
18
|
+
.gqlPermission([
|
|
19
|
+
{
|
|
20
|
+
conditions: [[{ user: "_loggedIn" }, "=", true]],
|
|
21
|
+
actions: "all",
|
|
22
|
+
permit: true,
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { db } from "@tailor-platform/sdk";
|
|
2
|
+
import { user } from "./user";
|
|
3
|
+
|
|
4
|
+
export const notification = db
|
|
5
|
+
.type("Notification", {
|
|
6
|
+
userId: db.uuid().relation({
|
|
7
|
+
type: "n-1",
|
|
8
|
+
toward: { type: user },
|
|
9
|
+
}),
|
|
10
|
+
title: db.string(),
|
|
11
|
+
body: db.string(),
|
|
12
|
+
isRead: db.bool(),
|
|
13
|
+
...db.fields.timestamps(),
|
|
14
|
+
})
|
|
15
|
+
.permission({
|
|
16
|
+
create: [[{ user: "_loggedIn" }, "=", true]],
|
|
17
|
+
read: [[{ user: "_loggedIn" }, "=", true]],
|
|
18
|
+
update: [[{ user: "_loggedIn" }, "=", true]],
|
|
19
|
+
delete: [[{ user: "_loggedIn" }, "=", true]],
|
|
20
|
+
})
|
|
21
|
+
.gqlPermission([
|
|
22
|
+
{
|
|
23
|
+
conditions: [[{ user: "_loggedIn" }, "=", true]],
|
|
24
|
+
actions: "all",
|
|
25
|
+
permit: true,
|
|
26
|
+
},
|
|
27
|
+
]);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { db } from "@tailor-platform/sdk";
|
|
2
|
+
|
|
3
|
+
export const user = db
|
|
4
|
+
.type("User", {
|
|
5
|
+
name: db.string(),
|
|
6
|
+
email: db.string().unique(),
|
|
7
|
+
role: db.enum(["ADMIN", "MEMBER"]),
|
|
8
|
+
...db.fields.timestamps(),
|
|
9
|
+
})
|
|
10
|
+
.permission({
|
|
11
|
+
create: [[{ user: "_loggedIn" }, "=", true]],
|
|
12
|
+
read: [[{ user: "_loggedIn" }, "=", true]],
|
|
13
|
+
update: [[{ user: "_loggedIn" }, "=", true]],
|
|
14
|
+
delete: [[{ user: "_loggedIn" }, "=", true]],
|
|
15
|
+
})
|
|
16
|
+
.gqlPermission([
|
|
17
|
+
{
|
|
18
|
+
conditions: [[{ user: "_loggedIn" }, "=", true]],
|
|
19
|
+
actions: "all",
|
|
20
|
+
permit: true,
|
|
21
|
+
},
|
|
22
|
+
]);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createExecutor, scheduleTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import cleanupWorkflow from "../workflow/cleanup";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "daily-cleanup",
|
|
6
|
+
description: "Runs cleanup workflow daily at midnight",
|
|
7
|
+
trigger: scheduleTrigger({
|
|
8
|
+
cron: "0 0 * * *",
|
|
9
|
+
timezone: "UTC",
|
|
10
|
+
}),
|
|
11
|
+
operation: {
|
|
12
|
+
kind: "workflow",
|
|
13
|
+
workflow: cleanupWorkflow,
|
|
14
|
+
args: () => ({ daysOld: 30 }),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createExecutor, incomingWebhookTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
|
|
3
|
+
export default createExecutor({
|
|
4
|
+
name: "external-webhook",
|
|
5
|
+
description: "Handles incoming webhook events",
|
|
6
|
+
trigger: incomingWebhookTrigger<{
|
|
7
|
+
body: { event: string; payload: Record<string, unknown> };
|
|
8
|
+
headers: Record<string, string>;
|
|
9
|
+
}>(),
|
|
10
|
+
operation: {
|
|
11
|
+
kind: "function",
|
|
12
|
+
body: (args) => {
|
|
13
|
+
console.log("Webhook event:", args.body.event);
|
|
14
|
+
console.log("Payload:", args.body.payload);
|
|
15
|
+
console.log("Headers:", args.headers);
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createExecutor, resolverExecutedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import processData from "../resolver/processData";
|
|
3
|
+
import { createAuditLog } from "./shared";
|
|
4
|
+
|
|
5
|
+
export default createExecutor({
|
|
6
|
+
name: "on-data-processed",
|
|
7
|
+
description: "Creates an audit log when data is processed",
|
|
8
|
+
trigger: resolverExecutedTrigger({
|
|
9
|
+
resolver: processData,
|
|
10
|
+
condition: ({ result }) => {
|
|
11
|
+
if (!result) return false;
|
|
12
|
+
return result.processed;
|
|
13
|
+
},
|
|
14
|
+
}),
|
|
15
|
+
operation: {
|
|
16
|
+
kind: "function",
|
|
17
|
+
body: async () => {
|
|
18
|
+
await createAuditLog({
|
|
19
|
+
action: "DATA_PROCESSED",
|
|
20
|
+
entityType: "Resolver",
|
|
21
|
+
entityId: "00000000-0000-0000-0000-000000000000",
|
|
22
|
+
message: "Data processing completed",
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExecutor, idpUserCreatedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "on-idp-user-created",
|
|
6
|
+
description: "Creates an audit log when an IdP user registers",
|
|
7
|
+
trigger: idpUserCreatedTrigger(),
|
|
8
|
+
operation: {
|
|
9
|
+
kind: "function",
|
|
10
|
+
body: async (args) => {
|
|
11
|
+
await createAuditLog({
|
|
12
|
+
action: "IDP_USER_CREATED",
|
|
13
|
+
entityType: "IdpUser",
|
|
14
|
+
entityId: args.userId,
|
|
15
|
+
message: `IdP user registered in namespace: ${args.namespaceName}`,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExecutor, idpUserDeletedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "on-idp-user-deleted",
|
|
6
|
+
description: "Creates an audit log when an IdP user is deleted",
|
|
7
|
+
trigger: idpUserDeletedTrigger(),
|
|
8
|
+
operation: {
|
|
9
|
+
kind: "function",
|
|
10
|
+
body: async (args) => {
|
|
11
|
+
await createAuditLog({
|
|
12
|
+
action: "IDP_USER_DELETED",
|
|
13
|
+
entityType: "IdpUser",
|
|
14
|
+
entityId: args.userId,
|
|
15
|
+
message: `IdP user deleted from namespace: ${args.namespaceName}`,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExecutor, idpUserUpdatedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "on-idp-user-updated",
|
|
6
|
+
description: "Creates an audit log when an IdP user profile is updated",
|
|
7
|
+
trigger: idpUserUpdatedTrigger(),
|
|
8
|
+
operation: {
|
|
9
|
+
kind: "function",
|
|
10
|
+
body: async (args) => {
|
|
11
|
+
await createAuditLog({
|
|
12
|
+
action: "IDP_USER_UPDATED",
|
|
13
|
+
entityType: "IdpUser",
|
|
14
|
+
entityId: args.userId,
|
|
15
|
+
message: `IdP user updated in namespace: ${args.namespaceName}`,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExecutor, authAccessTokenIssuedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "on-token-issued",
|
|
6
|
+
description: "Creates an audit log when an access token is issued",
|
|
7
|
+
trigger: authAccessTokenIssuedTrigger(),
|
|
8
|
+
operation: {
|
|
9
|
+
kind: "function",
|
|
10
|
+
body: async (args) => {
|
|
11
|
+
await createAuditLog({
|
|
12
|
+
action: "TOKEN_ISSUED",
|
|
13
|
+
entityType: "AuthToken",
|
|
14
|
+
entityId: args.userId,
|
|
15
|
+
message: `Access token issued for user: ${args.userId}`,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExecutor, authAccessTokenRefreshedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "on-token-refreshed",
|
|
6
|
+
description: "Creates an audit log when an access token is refreshed",
|
|
7
|
+
trigger: authAccessTokenRefreshedTrigger(),
|
|
8
|
+
operation: {
|
|
9
|
+
kind: "function",
|
|
10
|
+
body: async (args) => {
|
|
11
|
+
await createAuditLog({
|
|
12
|
+
action: "TOKEN_REFRESHED",
|
|
13
|
+
entityType: "AuthToken",
|
|
14
|
+
entityId: args.userId,
|
|
15
|
+
message: `Access token refreshed for user: ${args.userId}`,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExecutor, authAccessTokenRevokedTrigger } from "@tailor-platform/sdk";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
export default createExecutor({
|
|
5
|
+
name: "on-token-revoked",
|
|
6
|
+
description: "Creates an audit log when an access token is revoked",
|
|
7
|
+
trigger: authAccessTokenRevokedTrigger(),
|
|
8
|
+
operation: {
|
|
9
|
+
kind: "function",
|
|
10
|
+
body: async (args) => {
|
|
11
|
+
await createAuditLog({
|
|
12
|
+
action: "TOKEN_REVOKED",
|
|
13
|
+
entityType: "AuthToken",
|
|
14
|
+
entityId: args.userId,
|
|
15
|
+
message: `Access token revoked for user: ${args.userId}`,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createExecutor, recordCreatedTrigger, t } from "@tailor-platform/sdk";
|
|
2
|
+
import { user } from "../db/user";
|
|
3
|
+
import { createAuditLog } from "./shared";
|
|
4
|
+
|
|
5
|
+
export default createExecutor({
|
|
6
|
+
name: "on-user-created",
|
|
7
|
+
description: "Creates an audit log when a new admin user is created",
|
|
8
|
+
trigger: recordCreatedTrigger({
|
|
9
|
+
type: user,
|
|
10
|
+
condition: ({ newRecord }) => newRecord.role === "ADMIN",
|
|
11
|
+
}),
|
|
12
|
+
operation: {
|
|
13
|
+
kind: "function",
|
|
14
|
+
body: async (args: { newRecord: t.infer<typeof user> }) => {
|
|
15
|
+
await createAuditLog({
|
|
16
|
+
action: "USER_CREATED",
|
|
17
|
+
entityType: "User",
|
|
18
|
+
entityId: args.newRecord.id,
|
|
19
|
+
message: `Admin user created: ${args.newRecord.name} (${args.newRecord.email})`,
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createExecutor, recordDeletedTrigger, t } from "@tailor-platform/sdk";
|
|
2
|
+
import { user } from "../db/user";
|
|
3
|
+
import { createAuditLog } from "./shared";
|
|
4
|
+
|
|
5
|
+
export default createExecutor({
|
|
6
|
+
name: "on-user-deleted",
|
|
7
|
+
description: "Creates an audit log when a user is deleted",
|
|
8
|
+
trigger: recordDeletedTrigger({
|
|
9
|
+
type: user,
|
|
10
|
+
}),
|
|
11
|
+
operation: {
|
|
12
|
+
kind: "function",
|
|
13
|
+
body: async (args: { oldRecord: t.infer<typeof user> }) => {
|
|
14
|
+
await createAuditLog({
|
|
15
|
+
action: "USER_DELETED",
|
|
16
|
+
entityType: "User",
|
|
17
|
+
entityId: args.oldRecord.id,
|
|
18
|
+
message: `User deleted: ${args.oldRecord.name} (${args.oldRecord.email})`,
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createExecutor, recordUpdatedTrigger, t } from "@tailor-platform/sdk";
|
|
2
|
+
import { user } from "../db/user";
|
|
3
|
+
import { createAuditLog } from "./shared";
|
|
4
|
+
|
|
5
|
+
export default createExecutor({
|
|
6
|
+
name: "on-user-updated",
|
|
7
|
+
description: "Creates an audit log when a user is updated",
|
|
8
|
+
trigger: recordUpdatedTrigger({
|
|
9
|
+
type: user,
|
|
10
|
+
}),
|
|
11
|
+
operation: {
|
|
12
|
+
kind: "function",
|
|
13
|
+
body: async (args: { newRecord: t.infer<typeof user>; oldRecord: t.infer<typeof user> }) => {
|
|
14
|
+
await createAuditLog({
|
|
15
|
+
action: "USER_UPDATED",
|
|
16
|
+
entityType: "User",
|
|
17
|
+
entityId: args.newRecord.id,
|
|
18
|
+
message: `User updated: ${args.oldRecord.name} -> ${args.newRecord.name}`,
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { createAuditLog } from "./shared";
|
|
3
|
+
|
|
4
|
+
describe("createAuditLog", () => {
|
|
5
|
+
const mockQueryObject = vi.fn();
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
vi.stubGlobal("tailordb", {
|
|
8
|
+
Client: vi.fn(
|
|
9
|
+
class {
|
|
10
|
+
connect = vi.fn();
|
|
11
|
+
end = vi.fn();
|
|
12
|
+
queryObject = mockQueryObject;
|
|
13
|
+
},
|
|
14
|
+
),
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
afterAll(() => {
|
|
18
|
+
vi.unstubAllGlobals();
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
mockQueryObject.mockReset();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("inserts audit log record", async () => {
|
|
25
|
+
mockQueryObject.mockResolvedValueOnce({});
|
|
26
|
+
|
|
27
|
+
await createAuditLog({
|
|
28
|
+
action: "USER_CREATED",
|
|
29
|
+
entityType: "User",
|
|
30
|
+
entityId: "test-id",
|
|
31
|
+
message: "Test audit log",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(mockQueryObject).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getDB } from "../generated/db";
|
|
2
|
+
|
|
3
|
+
interface AuditLogInput {
|
|
4
|
+
action: string;
|
|
5
|
+
entityType: string;
|
|
6
|
+
entityId: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function createAuditLog(input: AuditLogInput): Promise<void> {
|
|
11
|
+
const db = getDB("main-db");
|
|
12
|
+
await db.insertInto("AuditLog").values(input).execute();
|
|
13
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createGetDB,
|
|
3
|
+
type Generated,
|
|
4
|
+
type Timestamp,
|
|
5
|
+
type NamespaceDB,
|
|
6
|
+
type NamespaceInsertable,
|
|
7
|
+
type NamespaceSelectable,
|
|
8
|
+
type NamespaceTable,
|
|
9
|
+
type NamespaceTableName,
|
|
10
|
+
type NamespaceTransaction,
|
|
11
|
+
type NamespaceUpdateable,
|
|
12
|
+
} from "@tailor-platform/sdk/kysely";
|
|
13
|
+
|
|
14
|
+
export interface Namespace {
|
|
15
|
+
"main-db": {
|
|
16
|
+
AuditLog: {
|
|
17
|
+
id: Generated<string>;
|
|
18
|
+
action: string;
|
|
19
|
+
entityType: string;
|
|
20
|
+
entityId: string;
|
|
21
|
+
message: string;
|
|
22
|
+
createdAt: Generated<Timestamp>;
|
|
23
|
+
updatedAt: Timestamp | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Notification: {
|
|
27
|
+
id: Generated<string>;
|
|
28
|
+
userId: string;
|
|
29
|
+
title: string;
|
|
30
|
+
body: string;
|
|
31
|
+
isRead: boolean;
|
|
32
|
+
createdAt: Generated<Timestamp>;
|
|
33
|
+
updatedAt: Timestamp | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
User: {
|
|
37
|
+
id: Generated<string>;
|
|
38
|
+
name: string;
|
|
39
|
+
email: string;
|
|
40
|
+
role: "ADMIN" | "MEMBER";
|
|
41
|
+
createdAt: Generated<Timestamp>;
|
|
42
|
+
updatedAt: Timestamp | null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const getDB = createGetDB<Namespace>();
|
|
48
|
+
|
|
49
|
+
export type DB<N extends keyof Namespace = keyof Namespace> = NamespaceDB<Namespace, N>;
|
|
50
|
+
|
|
51
|
+
export type Transaction<K extends keyof Namespace | DB = keyof Namespace> =
|
|
52
|
+
NamespaceTransaction<Namespace, K>;
|
|
53
|
+
|
|
54
|
+
type TableName = NamespaceTableName<Namespace>;
|
|
55
|
+
export type Table<T extends TableName> = NamespaceTable<Namespace, T>;
|
|
56
|
+
|
|
57
|
+
export type Insertable<T extends TableName> = NamespaceInsertable<Namespace, T>;
|
|
58
|
+
export type Selectable<T extends TableName> = NamespaceSelectable<Namespace, T>;
|
|
59
|
+
export type Updateable<T extends TableName> = NamespaceUpdateable<Namespace, T>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createResolver, t } from "@tailor-platform/sdk";
|
|
2
|
+
|
|
3
|
+
const resolver = createResolver({
|
|
4
|
+
name: "processData",
|
|
5
|
+
description: "Processes data and returns a summary",
|
|
6
|
+
operation: "mutation",
|
|
7
|
+
input: {
|
|
8
|
+
data: t.string(),
|
|
9
|
+
},
|
|
10
|
+
body: (context) => {
|
|
11
|
+
return {
|
|
12
|
+
processed: true,
|
|
13
|
+
summary: `Processed: ${context.input.data}`,
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
output: t.object({
|
|
17
|
+
processed: t.bool(),
|
|
18
|
+
summary: t.string(),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export default resolver;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createWorkflow, createWorkflowJob } from "@tailor-platform/sdk";
|
|
2
|
+
|
|
3
|
+
export const cleanupOldRecords = createWorkflowJob({
|
|
4
|
+
name: "cleanup-old-records",
|
|
5
|
+
body: (input: { daysOld: number }) => {
|
|
6
|
+
return { deletedCount: 0, daysOld: input.daysOld };
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default createWorkflow({
|
|
11
|
+
name: "cleanup-workflow",
|
|
12
|
+
mainJob: cleanupOldRecords,
|
|
13
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineAuth, defineConfig, defineIdp, definePlugins, t } from "@tailor-platform/sdk";
|
|
2
|
+
import { kyselyTypePlugin } from "@tailor-platform/sdk/plugin/kysely-type";
|
|
3
|
+
|
|
4
|
+
const idp = defineIdp("main-idp", {
|
|
5
|
+
authorization: "loggedIn",
|
|
6
|
+
clients: ["default-idp-client"],
|
|
7
|
+
userAuthPolicy: {
|
|
8
|
+
useNonEmailIdentifier: false,
|
|
9
|
+
allowSelfPasswordReset: true,
|
|
10
|
+
passwordRequireUppercase: true,
|
|
11
|
+
passwordRequireLowercase: true,
|
|
12
|
+
passwordRequireNonAlphanumeric: true,
|
|
13
|
+
passwordRequireNumeric: true,
|
|
14
|
+
passwordMinLength: 8,
|
|
15
|
+
passwordMaxLength: 128,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default defineConfig({
|
|
20
|
+
name: "executor",
|
|
21
|
+
auth: defineAuth("main-auth", {
|
|
22
|
+
machineUserAttributes: {
|
|
23
|
+
role: t.string(),
|
|
24
|
+
},
|
|
25
|
+
machineUsers: {
|
|
26
|
+
admin: {
|
|
27
|
+
attributes: {
|
|
28
|
+
role: "admin",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
idp: [idp],
|
|
34
|
+
db: { "main-db": { files: ["./src/db/*.ts"] } },
|
|
35
|
+
resolver: { "main-resolver": { files: ["./src/resolver/*.ts"] } },
|
|
36
|
+
executor: { files: ["./src/executor/*.ts"] },
|
|
37
|
+
workflow: { files: ["./src/workflow/*.ts"] },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const plugins = definePlugins(kyselyTypePlugin({ distPath: "./src/generated/db.ts" }));
|