@tailor-platform/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 +161 -0
- package/dist/application-Dtqap5jM.mjs +3 -0
- package/dist/{client-CobIRHl-.mjs → application-XuMWK4eq.mjs} +5869 -25
- package/dist/application-XuMWK4eq.mjs.map +1 -0
- package/dist/{assert-CKfwrmCV.mjs → assert-DBxo8jPo.mjs} +1 -2
- package/dist/{assert-CKfwrmCV.mjs.map → assert-DBxo8jPo.mjs.map} +1 -1
- package/dist/{authconnection-D8SJGMpj.mjs → authconnection-D2MhtTN5.mjs} +2 -3
- package/dist/{authconnection-D8SJGMpj.mjs.map → authconnection-D2MhtTN5.mjs.map} +1 -1
- package/dist/{authconnection-BIYzEh2p.d.mts → authconnection-DvUQAjQS.d.mts} +1 -1
- package/dist/{brand-DlnJ375c.mjs → brand-Eo4pLXPJ.mjs} +1 -2
- package/dist/{brand-DlnJ375c.mjs.map → brand-Eo4pLXPJ.mjs.map} +1 -1
- package/dist/cli/index.mjs +241 -237
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +547 -620
- package/dist/cli/lib.mjs +9 -11
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/completion/zsh-worker.zsh +4108 -0
- package/dist/configure/index.d.mts +9 -7
- package/dist/configure/index.mjs +76 -40
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{context-s0lxhu8_.mjs → context-Bd266-ru.mjs} +2 -3
- package/dist/context-Bd266-ru.mjs.map +1 -0
- package/dist/{context-CUBwSBq4.d.mts → context-C2lEi9uw.d.mts} +7 -28
- package/dist/{crashreport-D1wKBJ8N.mjs → crashreport-BMWcxeSE.mjs} +1 -2
- package/dist/{crashreport-BhD0y14F.mjs → crashreport-DFq-vsU0.mjs} +21 -14
- package/dist/{crashreport-BhD0y14F.mjs.map → crashreport-DFq-vsU0.mjs.map} +1 -1
- package/dist/{enum-constants-C7DaWeQo.mjs → enum-constants-j9QBF0cB.mjs} +1 -2
- package/dist/enum-constants-j9QBF0cB.mjs.map +1 -0
- package/dist/{errors-EsY4XO6O.mjs → errors-Dtf2WPaW.mjs} +1 -2
- package/dist/{errors-EsY4XO6O.mjs.map → errors-Dtf2WPaW.mjs.map} +1 -1
- package/dist/{field-C4zdJLW5.mjs → field-DOsJCPFa.mjs} +1 -2
- package/dist/field-DOsJCPFa.mjs.map +1 -0
- package/dist/{file-B58Dm-2P.mjs → file-BbdFGdMV.mjs} +3 -12
- package/dist/file-BbdFGdMV.mjs.map +1 -0
- package/dist/{file-BzK8z3X-.d.mts → file-Dq3NIt_F.d.mts} +3 -42
- package/dist/{file-utils-BHPxPXmn.mjs → file-utils-CYZnO1pX.mjs} +6 -7
- package/dist/file-utils-CYZnO1pX.mjs.map +1 -0
- package/dist/{globals-ByrCoDip.mjs → globals-Cf0sxIt8.mjs} +53 -5
- package/dist/globals-Cf0sxIt8.mjs.map +1 -0
- package/dist/http-adapter.generated-DFsXDdm5.d.mts +581 -0
- package/dist/{iconv-kwrmd1U_.d.mts → iconv-Co-TOPuH.d.mts} +1 -1
- package/dist/{iconv-DreIffeM.mjs → iconv-D2vi8G36.mjs} +2 -3
- package/dist/{iconv-DreIffeM.mjs.map → iconv-D2vi8G36.mjs.map} +1 -1
- package/dist/{idp-Ch95ag8h.mjs → idp-BDbK5gjm.mjs} +2 -3
- package/dist/{idp-Ch95ag8h.mjs.map → idp-BDbK5gjm.mjs.map} +1 -1
- package/dist/{idp-BlBPtXJ-.d.mts → idp-DrhVrLmV.d.mts} +1 -1
- package/dist/{index-CLxubakC.d.mts → index-BI-_j9Z3.d.mts} +49 -261
- package/dist/{index-CPRnOjjt.d.mts → index-C4JirJH8.d.mts} +2 -2
- package/dist/{index-CQZVJ5SX.d.mts → index-CZfWhr0a.d.mts} +2 -2
- package/dist/{index-DRhMpdnA.d.mts → index-Cg8VKAdN.d.mts} +8 -8
- package/dist/{index-CfRFkXIO.d.mts → index-DYRjoLXD.d.mts} +2 -2
- package/dist/index-lFpcjHPU.d.mts +201 -0
- package/dist/{index-DUupuPhZ.d.mts → index-nW7hE6oE.d.mts} +2 -2
- package/dist/{interceptor-DOqRkCya.mjs → interceptor-D-q1rvRl.mjs} +1 -2
- package/dist/{interceptor-DOqRkCya.mjs.map → interceptor-D-q1rvRl.mjs.map} +1 -1
- package/dist/kysely/index.mjs +0 -1
- package/dist/kysely/index.mjs.map +1 -1
- package/dist/{kysely-type-D1e0Vwkd.mjs → kysely-type-DR8uzZTA.mjs} +2 -3
- package/dist/kysely-type-DR8uzZTA.mjs.map +1 -0
- package/dist/{logger-DpJyJvNz.mjs → logger-CxF-Ex5d.mjs} +1 -2
- package/dist/{logger-DpJyJvNz.mjs.map → logger-CxF-Ex5d.mjs.map} +1 -1
- package/dist/{mock-DMgIygjE.mjs → mock-FPxmnt-y.mjs} +9 -56
- package/dist/mock-FPxmnt-y.mjs.map +1 -0
- package/dist/{multiline-Cf9ODpr1.mjs → multiline-sfHpTZZK.mjs} +1 -2
- package/dist/{multiline-Cf9ODpr1.mjs.map → multiline-sfHpTZZK.mjs.map} +1 -1
- package/dist/{package-json-DcQApfPQ.mjs → package-json-8b0O9TlX.mjs} +1 -2
- package/dist/{package-json-DcQApfPQ.mjs.map → package-json-8b0O9TlX.mjs.map} +1 -1
- package/dist/package-json-Cv2Z-TqQ.mjs +3 -0
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/enum-constants/index.mjs +1 -2
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.mjs +1 -2
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -2
- package/dist/plugin/builtin/seed/index.d.mts +1 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -2
- package/dist/plugin/index.d.mts +4 -5
- package/dist/plugin/index.mjs +0 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/registry-DH4m7eYo.mjs +53 -0
- package/dist/registry-DH4m7eYo.mjs.map +1 -0
- package/dist/{repl-editor-CJG3sz7A.mjs → repl-editor-DmGr9zMw.mjs} +2 -3
- package/dist/{repl-editor-CJG3sz7A.mjs.map → repl-editor-DmGr9zMw.mjs.map} +1 -1
- package/dist/{chunk-BkoGK1jX.mjs → rolldown-runtime-DXywRVcq.mjs} +0 -1
- package/dist/runtime/authconnection.d.mts +1 -1
- package/dist/runtime/authconnection.mjs +1 -2
- package/dist/runtime/context.d.mts +1 -1
- package/dist/runtime/context.mjs +1 -2
- package/dist/runtime/file.d.mts +2 -2
- package/dist/runtime/file.mjs +2 -3
- package/dist/runtime/globals.d.mts +8 -41
- package/dist/runtime/globals.mjs +0 -1
- package/dist/runtime/iconv.d.mts +1 -1
- package/dist/runtime/iconv.mjs +1 -2
- package/dist/runtime/idp.d.mts +1 -1
- package/dist/runtime/idp.mjs +1 -2
- package/dist/runtime/index.d.mts +8 -8
- package/dist/runtime/index.mjs +7 -8
- package/dist/runtime/secretmanager.d.mts +1 -1
- package/dist/runtime/secretmanager.mjs +1 -2
- package/dist/runtime/workflow.d.mts +2 -2
- package/dist/runtime/workflow.mjs +1 -2
- package/dist/{runtime-C7qTBDD2.mjs → runtime-CY4JvrDj.mjs} +1069 -542
- package/dist/runtime-CY4JvrDj.mjs.map +1 -0
- package/dist/{schema-1msIhXwA.mjs → schema-Dtw9Orye.mjs} +18 -16
- package/dist/schema-Dtw9Orye.mjs.map +1 -0
- package/dist/{secret-file-CWzF8rry.mjs → secret-file-VSVGy1V0.mjs} +27 -3
- package/dist/{secret-file-CWzF8rry.mjs.map → secret-file-VSVGy1V0.mjs.map} +1 -1
- package/dist/{secretmanager-CKLB3wAQ.d.mts → secretmanager-B3n4KHfm.d.mts} +1 -1
- package/dist/{secretmanager-B9h-U_8U.mjs → secretmanager-BVxw3ih_.mjs} +2 -3
- package/dist/{secretmanager-B9h-U_8U.mjs.map → secretmanager-BVxw3ih_.mjs.map} +1 -1
- package/dist/seed/index.mjs +0 -1
- package/dist/seed/index.mjs.map +1 -1
- package/dist/{seed-BH2FbrPV.mjs → seed-izIEyP3z.mjs} +7 -19
- package/dist/seed-izIEyP3z.mjs.map +1 -0
- package/dist/service-DCqIWibD.mjs +3 -0
- package/dist/{service-DMohAx8a2.mjs → service-DU1mVzri2.mjs} +3 -4
- package/dist/{service-DMohAx8a2.mjs.map → service-DU1mVzri2.mjs.map} +1 -1
- package/dist/{service-wI3Hvrgx.mjs → service-DjyqbCaJ.mjs} +9 -10
- package/dist/service-DjyqbCaJ.mjs.map +1 -0
- package/dist/{telemetry-BQbbVo2t.mjs → telemetry-CdqJEzkj.mjs} +2 -3
- package/dist/{telemetry-BQbbVo2t.mjs.map → telemetry-CdqJEzkj.mjs.map} +1 -1
- package/dist/telemetry-ClwW5ohF.mjs +3 -0
- package/dist/test-env-key-D7UkZp99.mjs +75 -0
- package/dist/test-env-key-D7UkZp99.mjs.map +1 -0
- package/dist/type-source-DH_LH20p.mjs +13 -0
- package/dist/type-source-DH_LH20p.mjs.map +1 -0
- package/dist/types-74etvaxy.mjs +4 -0
- package/dist/{plugin-C_FyVSdl.d.mts → types-BDRml5C3.d.mts} +128 -188
- package/dist/{types-CmzfQP_m.mjs → types-BQijbo4m.mjs} +10 -11
- package/dist/types-BQijbo4m.mjs.map +1 -0
- package/dist/types-BX4q6Mo6.d.mts +339 -0
- package/dist/types-BZ7QKVE8.d.mts +21 -0
- package/dist/{tailordb-BlBGmQK-.d.mts → types-CdcQh4Z2.d.mts} +92 -242
- package/dist/utils/test/index.d.mts +6 -14
- package/dist/utils/test/index.mjs +4 -14
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/environment.mjs +1 -2
- package/dist/vitest/environment.mjs.map +1 -1
- package/dist/vitest/index.d.mts +42 -5
- package/dist/vitest/index.mjs +133 -4
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/setup.mjs +2 -3
- package/dist/vitest/setup.mjs.map +1 -1
- package/dist/{workflow--aPbA8Uq.mjs → workflow-BOmaZwwG.mjs} +9 -5
- package/dist/workflow-BOmaZwwG.mjs.map +1 -0
- package/dist/{workflow-CMamswkK.d.mts → workflow-BVy4XWjS.d.mts} +15 -10
- package/dist/workflow.generated-ClEjBYhm.d.mts +671 -0
- package/docs/cli/application.md +0 -2
- package/docs/cli/completion.md +3 -0
- package/docs/cli/crashreport.md +0 -2
- package/docs/cli/executor.md +53 -0
- package/docs/cli/function.md +1 -1
- package/docs/cli/setup.md +35 -33
- package/docs/cli/user.md +3 -3
- package/docs/cli/workflow.md +157 -20
- package/docs/cli/workspace.md +3 -3
- package/docs/cli-reference.md +26 -20
- package/docs/configuration.md +0 -2
- package/docs/github-actions.md +29 -16
- package/docs/migration/v2.md +475 -0
- package/docs/plugin/custom.md +2 -2
- package/docs/plugin/index.md +1 -1
- package/docs/runtime.md +4 -4
- package/docs/services/aigateway.md +97 -0
- package/docs/services/auth.md +31 -14
- package/docs/services/executor.md +3 -5
- package/docs/services/resolver.md +8 -10
- package/docs/services/tailordb.md +15 -13
- package/docs/services/workflow.md +17 -19
- package/docs/testing.md +75 -56
- package/package.json +18 -17
- package/dist/actor-J2gJ0eK5.d.mts +0 -24
- package/dist/application-76hhIhnJ.mjs +0 -5594
- package/dist/application-76hhIhnJ.mjs.map +0 -1
- package/dist/application-av2raLs6.mjs +0 -4
- package/dist/cli/skills.d.mts +0 -1
- package/dist/cli/skills.mjs +0 -22
- package/dist/cli/skills.mjs.map +0 -1
- package/dist/client-C68VWo4g.mjs +0 -4
- package/dist/client-CobIRHl-.mjs.map +0 -1
- package/dist/context-s0lxhu8_.mjs.map +0 -1
- package/dist/enum-constants-C7DaWeQo.mjs.map +0 -1
- package/dist/env-B-g-qgE4.d.mts +0 -7
- package/dist/field-C4zdJLW5.mjs.map +0 -1
- package/dist/file-B58Dm-2P.mjs.map +0 -1
- package/dist/file-utils-BHPxPXmn.mjs.map +0 -1
- package/dist/globals-ByrCoDip.mjs.map +0 -1
- package/dist/job-BpsFXPbi.mjs +0 -54
- package/dist/job-BpsFXPbi.mjs.map +0 -1
- package/dist/kysely-type-D1e0Vwkd.mjs.map +0 -1
- package/dist/mock-DMgIygjE.mjs.map +0 -1
- package/dist/package-json-wzO6nV9O.mjs +0 -4
- package/dist/registry-D0uB0OrK.mjs +0 -178
- package/dist/registry-D0uB0OrK.mjs.map +0 -1
- package/dist/runtime-C7qTBDD2.mjs.map +0 -1
- package/dist/schema-1msIhXwA.mjs.map +0 -1
- package/dist/seed-BH2FbrPV.mjs.map +0 -1
- package/dist/service-BHQIerYh.mjs +0 -4
- package/dist/service-wI3Hvrgx.mjs.map +0 -1
- package/dist/telemetry-w92bvGdC.mjs +0 -4
- package/dist/types-2Be3wSMc.mjs +0 -5
- package/dist/types-CmzfQP_m.mjs.map +0 -1
- package/dist/workflow--aPbA8Uq.mjs.map +0 -1
- package/dist/workflow.generated-Bf1tWylx.d.mts +0 -1416
- package/docs/generator/builtin.md +0 -257
- package/docs/generator/custom.md +0 -147
- package/docs/generator/index.md +0 -66
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# AI Gateway
|
|
2
|
+
|
|
3
|
+
AI Gateway provides a unified endpoint for accessing multiple LLM providers (Azure OpenAI, Google Vertex AI Gemini, Anthropic via Vertex AI) through a single OpenAI-compatible API, with platform-managed credentials and workspace-scoped authentication.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
AI Gateway provides:
|
|
8
|
+
|
|
9
|
+
- A unified, OpenAI-compatible endpoint for multiple LLM providers
|
|
10
|
+
- Mandatory authentication via your workspace's auth (request tokens are resolved against the configured auth namespace)
|
|
11
|
+
- Per-workspace isolation: each gateway is provisioned with its own platform-assigned URL
|
|
12
|
+
- Optional CORS allow-list for browser-based clients
|
|
13
|
+
- Built-in usage tracking and rate limiting (configured platform-side)
|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
Configure an AI Gateway using `defineAIGateway()`:
|
|
18
|
+
|
|
19
|
+
**Definition Rules:**
|
|
20
|
+
|
|
21
|
+
- **Multiple gateways allowed**: You can define multiple AI Gateways in your config file
|
|
22
|
+
- **Configuration location**: Define in `tailor.config.ts` and add to the `aiGateways` array
|
|
23
|
+
- **Uniqueness**: Gateway names must be unique across all AI Gateways
|
|
24
|
+
- **Name pattern**: `name` must match `^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$` (lowercase alphanumeric and hyphens, 3-30 characters)
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { defineAIGateway, defineConfig } from "@tailor-platform/sdk";
|
|
28
|
+
|
|
29
|
+
const aiGateway = defineAIGateway("my-aigateway", {
|
|
30
|
+
authNamespace: "default",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
aiGateways: [aiGateway],
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Options
|
|
39
|
+
|
|
40
|
+
### authNamespace
|
|
41
|
+
|
|
42
|
+
The auth namespace used to resolve request tokens against your workspace's auth configuration. Must match an existing auth namespace.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
defineAIGateway("my-aigateway", {
|
|
46
|
+
authNamespace: "default",
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### cors
|
|
51
|
+
|
|
52
|
+
Optional list of allowed origins for browser-based clients. Each entry is one of:
|
|
53
|
+
|
|
54
|
+
- `*` — any origin (any scheme, any host)
|
|
55
|
+
- `http(s)://*` — any host on the given scheme
|
|
56
|
+
- `http(s)://*.example.com` — any subdomain of `example.com` on the given scheme
|
|
57
|
+
- `http(s)://app.example.com` — an exact origin
|
|
58
|
+
|
|
59
|
+
An optional `:port` may be appended in all URL forms. Omitting `cors` (or passing `[]`) disables cross-origin access — browsers will block any cross-origin reads.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
defineAIGateway("my-aigateway", {
|
|
63
|
+
authNamespace: "default",
|
|
64
|
+
cors: ["https://app.example.com", "https://*.example.com"],
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Complete Example
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import {
|
|
72
|
+
defineAIGateway,
|
|
73
|
+
defineAuth,
|
|
74
|
+
defineConfig,
|
|
75
|
+
defineStaticWebSite,
|
|
76
|
+
} from "@tailor-platform/sdk";
|
|
77
|
+
|
|
78
|
+
const website = defineStaticWebSite("my-frontend", {
|
|
79
|
+
description: "Frontend application",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const aiGateway = defineAIGateway("my-aigateway", {
|
|
83
|
+
authNamespace: "default",
|
|
84
|
+
cors: [website.url],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const auth = defineAuth("my-auth", {
|
|
88
|
+
// ...auth configuration...
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export default defineConfig({
|
|
92
|
+
name: "my-app",
|
|
93
|
+
auth,
|
|
94
|
+
staticWebsites: [website],
|
|
95
|
+
aiGateways: [aiGateway],
|
|
96
|
+
});
|
|
97
|
+
```
|
package/docs/services/auth.md
CHANGED
|
@@ -139,18 +139,18 @@ export const user = db.type("User", {
|
|
|
139
139
|
});
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
The `attributeList` values are accessible via `
|
|
142
|
+
The `attributeList` values are accessible via the runtime principal's `attributeList` as a tuple:
|
|
143
143
|
|
|
144
144
|
```typescript
|
|
145
145
|
// In a resolver
|
|
146
146
|
body: (context) => {
|
|
147
|
-
const [organizationId, teamId] = context.
|
|
147
|
+
const [organizationId, teamId] = context.caller?.attributeList ?? [];
|
|
148
148
|
},
|
|
149
149
|
|
|
150
150
|
// In TailorDB hooks
|
|
151
151
|
.hooks({
|
|
152
152
|
field: {
|
|
153
|
-
create: ({
|
|
153
|
+
create: ({ invoker }) => invoker?.attributeList[0] ?? null, // First UUID from list
|
|
154
154
|
},
|
|
155
155
|
})
|
|
156
156
|
```
|
|
@@ -160,7 +160,7 @@ body: (context) => {
|
|
|
160
160
|
When you want to use machine users without defining a `userProfile`, define `machineUserAttributes` instead. These attributes are used for:
|
|
161
161
|
|
|
162
162
|
- type-safe `machineUsers[*].attributes`
|
|
163
|
-
- `
|
|
163
|
+
- runtime principal `attributes` typing (via `tailor.d.ts`)
|
|
164
164
|
|
|
165
165
|
```typescript
|
|
166
166
|
import { defineAuth, t } from "@tailor-platform/sdk";
|
|
@@ -200,12 +200,12 @@ machineUsers: {
|
|
|
200
200
|
},
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
**attributes**: Values for attributes enabled in `userProfile.attributes` (or all fields defined in `machineUserAttributes` when `userProfile` is omitted). All enabled fields must be set here. These values are accessible via `
|
|
203
|
+
**attributes**: Values for attributes enabled in `userProfile.attributes` (or all fields defined in `machineUserAttributes` when `userProfile` is omitted). All enabled fields must be set here. These values are accessible via the runtime principal's `attributes`:
|
|
204
204
|
|
|
205
205
|
```typescript
|
|
206
206
|
// In a resolver
|
|
207
207
|
body: (context) => {
|
|
208
|
-
const role = context.
|
|
208
|
+
const role = context.caller?.attributes.role;
|
|
209
209
|
},
|
|
210
210
|
```
|
|
211
211
|
|
|
@@ -230,25 +230,25 @@ machineUsers: {
|
|
|
230
230
|
},
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
These values are accessible via `
|
|
233
|
+
These values are accessible via the runtime principal's `attributeList`:
|
|
234
234
|
|
|
235
235
|
```typescript
|
|
236
236
|
// In a resolver
|
|
237
237
|
body: (context) => {
|
|
238
|
-
const [organizationId, teamId] = context.
|
|
238
|
+
const [organizationId, teamId] = context.caller?.attributeList ?? [];
|
|
239
239
|
},
|
|
240
240
|
|
|
241
241
|
// In TailorDB hooks
|
|
242
242
|
.hooks({
|
|
243
243
|
field: {
|
|
244
|
-
create: ({
|
|
244
|
+
create: ({ invoker }) => invoker?.attributes.role === "ADMIN" ? "default" : null,
|
|
245
245
|
},
|
|
246
246
|
})
|
|
247
247
|
|
|
248
248
|
// In TailorDB validate
|
|
249
249
|
.validate({
|
|
250
250
|
field: [
|
|
251
|
-
({
|
|
251
|
+
({ invoker }) => invoker?.attributes.role === "ADMIN",
|
|
252
252
|
"Only admins can set this field",
|
|
253
253
|
],
|
|
254
254
|
})
|
|
@@ -269,7 +269,7 @@ tailor-sdk machineuser token <name>
|
|
|
269
269
|
|
|
270
270
|
### Specifying a machine user invoker
|
|
271
271
|
|
|
272
|
-
Resolvers, executors, and `workflow.trigger()` accept an `
|
|
272
|
+
Resolvers, executors, and `workflow.trigger()` accept an `invoker` option that chooses which machine user runs the operation. Pass the machine user name as a plain string — it is type-narrowed to the names you registered in `machineUsers`.
|
|
273
273
|
|
|
274
274
|
```typescript
|
|
275
275
|
// tailor.config.ts
|
|
@@ -298,7 +298,7 @@ export default createResolver({
|
|
|
298
298
|
// Trigger workflow with machine user permissions
|
|
299
299
|
const workflowRunId = await myWorkflow.trigger(
|
|
300
300
|
{ id: input.id },
|
|
301
|
-
{
|
|
301
|
+
{ invoker: "admin-machine-user" },
|
|
302
302
|
);
|
|
303
303
|
return { workflowRunId };
|
|
304
304
|
},
|
|
@@ -310,8 +310,6 @@ export default createResolver({
|
|
|
310
310
|
|
|
311
311
|
Type narrowing is provided by the generated `tailor.d.ts` (the `MachineUserNameRegistry` interface). Run `tailor-sdk generate` (or `apply`) after defining new machine users to refresh it.
|
|
312
312
|
|
|
313
|
-
> **Deprecated:** The `auth.invoker("<name>")` helper is still available for backward compatibility. Prefer the string form — it does not require importing `auth` from `tailor.config.ts` into runtime files, avoiding bundling config-layer (Node-only) dependencies.
|
|
314
|
-
|
|
315
313
|
## OAuth 2.0 Clients
|
|
316
314
|
|
|
317
315
|
Configure OAuth 2.0 clients for third-party applications:
|
|
@@ -515,6 +513,25 @@ export const auth = defineAuth("my-auth", {
|
|
|
515
513
|
|
|
516
514
|
**invoker**: The machine user whose permissions are used to execute the hook. Must reference a machine user defined in the same auth configuration.
|
|
517
515
|
|
|
516
|
+
### Federated identity claims
|
|
517
|
+
|
|
518
|
+
When a user signs in through a Built-in IdP OAuth provider (Google or Microsoft), the upstream provider's profile is available on `claims.federated_identity`. It is `undefined` for password logins, so guard before reading it. Commonly present claims (`name`, `given_name`, `family_name`, `picture`, `locale`) are typed; any other claim the provider issues is forwarded as-is. Availability varies by provider (for example, Microsoft does not issue `picture`).
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
hooks: {
|
|
522
|
+
beforeLogin: {
|
|
523
|
+
handler: async ({ claims }) => {
|
|
524
|
+
const federated = claims.federated_identity;
|
|
525
|
+
if (federated?.provider === "google") {
|
|
526
|
+
// Populate the user record from the upstream profile
|
|
527
|
+
const avatarUrl = federated.claims.picture;
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
invoker: "hook-invoker",
|
|
531
|
+
},
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
518
535
|
## CLI Commands
|
|
519
536
|
|
|
520
537
|
Manage Auth resources using the CLI:
|
|
@@ -219,7 +219,7 @@ createExecutor({
|
|
|
219
219
|
});
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
Executor callbacks receive the trigger args, including `env` from `defineConfig({ env })`. `function` and `jobFunction` `body` args also include an `invoker` field: the principal running this function,
|
|
222
|
+
Executor callbacks receive the trigger args, including `env` from `defineConfig({ env })`. `function` and `jobFunction` `body` args also include an `invoker` field: the principal running this function, or the machine user configured through the operation `invoker` option; `null` for anonymous calls. Other operation kinds (`graphql`, `webhook`, `workflow`) receive `env` through their callback args but do not pass `invoker` into those callbacks.
|
|
223
223
|
|
|
224
224
|
### Job Function Operation
|
|
225
225
|
|
|
@@ -331,7 +331,7 @@ createExecutor({
|
|
|
331
331
|
|
|
332
332
|
### Authentication for Operations
|
|
333
333
|
|
|
334
|
-
GraphQL and Workflow operations can specify an `
|
|
334
|
+
GraphQL and Workflow operations can specify an `invoker` to execute with machine user credentials. Pass the machine user name as a plain string — it is type-narrowed to the names defined in your auth config:
|
|
335
335
|
|
|
336
336
|
```typescript
|
|
337
337
|
import { createExecutor, scheduleTrigger } from "@tailor-platform/sdk";
|
|
@@ -342,13 +342,11 @@ export default createExecutor({
|
|
|
342
342
|
operation: {
|
|
343
343
|
kind: "graphql",
|
|
344
344
|
query: `mutation { cleanupOldRecords { count } }`,
|
|
345
|
-
|
|
345
|
+
invoker: "batch-processor",
|
|
346
346
|
},
|
|
347
347
|
});
|
|
348
348
|
```
|
|
349
349
|
|
|
350
|
-
> **Deprecated:** `auth.invoker("batch-processor")` still works, but is deprecated. Prefer the string form to avoid importing config-layer modules into runtime files.
|
|
351
|
-
|
|
352
350
|
## Event Payloads
|
|
353
351
|
|
|
354
352
|
Each trigger type provides specific context data in the callback functions.
|
|
@@ -208,7 +208,7 @@ Validation functions receive:
|
|
|
208
208
|
|
|
209
209
|
- `value` - The field value being validated
|
|
210
210
|
- `data` - The entire input object
|
|
211
|
-
- `
|
|
211
|
+
- `invoker` - The principal performing the operation
|
|
212
212
|
|
|
213
213
|
You can specify validation as:
|
|
214
214
|
|
|
@@ -234,13 +234,13 @@ Validation runs automatically before the `body` function executes. When validati
|
|
|
234
234
|
Define actual resolver logic in the `body` function. Function arguments include:
|
|
235
235
|
|
|
236
236
|
- `input` - Input data from GraphQL request
|
|
237
|
-
- `
|
|
238
|
-
- `invoker` - The principal running this function; equals `
|
|
237
|
+
- `caller` - The user or machine user who called this resolver; unaffected by `invoker`. `null` for anonymous calls.
|
|
238
|
+
- `invoker` - The principal running this function; equals `caller` by default, or the machine user configured through the resolver `invoker` option. `null` for anonymous calls.
|
|
239
239
|
- `env` - Environment variables declared in `tailor.config.ts`
|
|
240
240
|
|
|
241
241
|
### Using Kysely for Database Access
|
|
242
242
|
|
|
243
|
-
If you're generating Kysely types with
|
|
243
|
+
If you're generating Kysely types with `kyselyTypePlugin`, you can use `getDB` to execute typed queries:
|
|
244
244
|
|
|
245
245
|
```typescript
|
|
246
246
|
import { getDB } from "../generated/tailordb";
|
|
@@ -306,7 +306,7 @@ createResolver({
|
|
|
306
306
|
|
|
307
307
|
- When `publishEvents: true`, resolver execution events are published
|
|
308
308
|
- When not specified, it is **automatically set to `true`** if an executor uses this resolver with `resolverExecutedTrigger`
|
|
309
|
-
- When explicitly set to `false` while an executor uses this resolver, an error is thrown during `tailor
|
|
309
|
+
- When explicitly set to `false` while an executor uses this resolver, an error is thrown during `tailor-sdk deploy`
|
|
310
310
|
|
|
311
311
|
**Use cases:**
|
|
312
312
|
|
|
@@ -352,7 +352,7 @@ createResolver({
|
|
|
352
352
|
|
|
353
353
|
## Authentication
|
|
354
354
|
|
|
355
|
-
Specify an `
|
|
355
|
+
Specify an `invoker` to execute the resolver with machine user credentials. Pass the machine user name as a plain string — it is type-narrowed to the names you defined in your auth config:
|
|
356
356
|
|
|
357
357
|
```typescript
|
|
358
358
|
import { createResolver, t } from "@tailor-platform/sdk";
|
|
@@ -365,12 +365,10 @@ export default createResolver({
|
|
|
365
365
|
// Executes as "batch-processor" machine user
|
|
366
366
|
return { result: "ok" };
|
|
367
367
|
},
|
|
368
|
-
|
|
368
|
+
invoker: "batch-processor",
|
|
369
369
|
});
|
|
370
370
|
```
|
|
371
371
|
|
|
372
372
|
The machine user name is looked up in the auth service configured on your app (`machineUsers` in `defineAuth`). The namespace is resolved automatically — no need to import `auth` from `tailor.config.ts` in resolver files.
|
|
373
373
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
**Note:** `authInvoker` controls the permissions for database operations and other platform actions. The `user` object passed to `body` still reflects the original caller, while `invoker` reflects the principal actually running the body.
|
|
374
|
+
**Note:** The `invoker` option controls the permissions for database operations and other platform actions. The `caller` object passed to `body` still reflects the original caller, while the `invoker` body field reflects the principal actually running the body.
|
|
@@ -260,7 +260,7 @@ Add hooks to execute functions during data creation or update. Hooks receive thr
|
|
|
260
260
|
|
|
261
261
|
- `value`: User input if provided, otherwise existing value on update or null on create
|
|
262
262
|
- `data`: Entire record data (for accessing other field values)
|
|
263
|
-
- `
|
|
263
|
+
- `invoker`: Principal performing the operation
|
|
264
264
|
|
|
265
265
|
#### Field-level Hooks
|
|
266
266
|
|
|
@@ -268,7 +268,7 @@ Set hooks directly on individual fields:
|
|
|
268
268
|
|
|
269
269
|
```typescript
|
|
270
270
|
db.string().hooks({
|
|
271
|
-
create: ({
|
|
271
|
+
create: ({ invoker }) => invoker?.id ?? "",
|
|
272
272
|
update: ({ value }) => value,
|
|
273
273
|
});
|
|
274
274
|
```
|
|
@@ -323,7 +323,7 @@ Add validation rules to fields. Validators receive three arguments (executed aft
|
|
|
323
323
|
|
|
324
324
|
- `value`: Field value after hook transformation
|
|
325
325
|
- `data`: Entire record data after hook transformations (for accessing other field values)
|
|
326
|
-
- `
|
|
326
|
+
- `invoker`: Principal performing the operation
|
|
327
327
|
|
|
328
328
|
Validators return `true` for success, `false` for failure. Use array form `[validator, errorMessage]` for custom error messages.
|
|
329
329
|
|
|
@@ -409,6 +409,8 @@ export const user = db.type("User", {
|
|
|
409
409
|
});
|
|
410
410
|
```
|
|
411
411
|
|
|
412
|
+
`db.fields.timestamps()` adds non-null `createdAt` and `updatedAt` datetime fields. Both fields are populated when a record is created; provided values are preserved so seed data can use historical timestamps. `updatedAt` is also refreshed automatically when a record is updated.
|
|
413
|
+
|
|
412
414
|
## Type Modifiers
|
|
413
415
|
|
|
414
416
|
### Composite Indexes
|
|
@@ -461,7 +463,7 @@ db.type("User", {
|
|
|
461
463
|
|
|
462
464
|
- When `publishEvents: true`, record creation/update/deletion events are published
|
|
463
465
|
- When not specified, it is **automatically set to `true`** if an executor uses this type with `recordCreatedTrigger`, `recordUpdatedTrigger`, or `recordDeletedTrigger`
|
|
464
|
-
- When explicitly set to `false` while an executor uses this type, an error is thrown during `tailor
|
|
466
|
+
- When explicitly set to `false` while an executor uses this type, an error is thrown during `tailor-sdk deploy`
|
|
465
467
|
|
|
466
468
|
**Use cases:**
|
|
467
469
|
|
|
@@ -516,8 +518,8 @@ const user = db.type("User", {
|
|
|
516
518
|
...db.fields.timestamps(),
|
|
517
519
|
});
|
|
518
520
|
|
|
519
|
-
// Pick id and
|
|
520
|
-
user.pickFields(["id", "createdAt"], { optional: true });
|
|
521
|
+
// Pick id, createdAt, and updatedAt, making them optional
|
|
522
|
+
user.pickFields(["id", "createdAt", "updatedAt"], { optional: true });
|
|
521
523
|
```
|
|
522
524
|
|
|
523
525
|
Available options:
|
|
@@ -532,8 +534,8 @@ Available options:
|
|
|
532
534
|
Return all fields except the specified ones:
|
|
533
535
|
|
|
534
536
|
```typescript
|
|
535
|
-
// All fields except id and
|
|
536
|
-
user.omitFields(["id", "createdAt"]);
|
|
537
|
+
// All fields except id, createdAt, and updatedAt
|
|
538
|
+
user.omitFields(["id", "createdAt", "updatedAt"]);
|
|
537
539
|
```
|
|
538
540
|
|
|
539
541
|
#### Common Pattern: Input Schema Composition
|
|
@@ -548,9 +550,9 @@ export default createResolver({
|
|
|
548
550
|
name: "createUser",
|
|
549
551
|
operation: "mutation",
|
|
550
552
|
input: {
|
|
551
|
-
// id/createdAt are optional (auto-generated), other fields are required
|
|
552
|
-
...user.pickFields(["id", "createdAt"], { optional: true }),
|
|
553
|
-
...user.omitFields(["id", "createdAt"]),
|
|
553
|
+
// id/createdAt/updatedAt are optional (auto-generated), other fields are required
|
|
554
|
+
...user.pickFields(["id", "createdAt", "updatedAt"], { optional: true }),
|
|
555
|
+
...user.omitFields(["id", "createdAt", "updatedAt"]),
|
|
554
556
|
},
|
|
555
557
|
output: t.object({ id: t.uuid() }),
|
|
556
558
|
body: async (context) => {
|
|
@@ -567,8 +569,8 @@ import { t } from "@tailor-platform/sdk";
|
|
|
567
569
|
import { invoice } from "../../tailordb/invoice";
|
|
568
570
|
|
|
569
571
|
const schemaType = t.object({
|
|
570
|
-
...invoice.pickFields(["id", "createdAt"], { optional: true }),
|
|
571
|
-
...invoice.omitFields(["id", "createdAt", "invoiceNumber", "sequentialId"]),
|
|
572
|
+
...invoice.pickFields(["id", "createdAt", "updatedAt"], { optional: true }),
|
|
573
|
+
...invoice.omitFields(["id", "createdAt", "updatedAt", "invoiceNumber", "sequentialId"]),
|
|
572
574
|
});
|
|
573
575
|
```
|
|
574
576
|
|
|
@@ -105,11 +105,11 @@ import { sendNotification } from "./jobs/send-notification";
|
|
|
105
105
|
|
|
106
106
|
export const mainJob = createWorkflowJob({
|
|
107
107
|
name: "main-job",
|
|
108
|
-
body:
|
|
109
|
-
const customer =
|
|
108
|
+
body: (input: { customerId: string }) => {
|
|
109
|
+
const customer = fetchCustomer.trigger({
|
|
110
110
|
customerId: input.customerId,
|
|
111
111
|
});
|
|
112
|
-
const notification =
|
|
112
|
+
const notification = sendNotification.trigger({
|
|
113
113
|
message: "Order processed",
|
|
114
114
|
recipient: customer.email,
|
|
115
115
|
});
|
|
@@ -130,31 +130,31 @@ Using `.trigger()` inside a loop works correctly, as long as the loop is determi
|
|
|
130
130
|
// ✅ OK: deterministic loop — same calls in the same order on every execution
|
|
131
131
|
const regions = ["us", "eu", "ap"];
|
|
132
132
|
for (const region of regions) {
|
|
133
|
-
const result =
|
|
133
|
+
const result = fetchData.trigger({ region });
|
|
134
134
|
results.push(result);
|
|
135
135
|
}
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
```typescript
|
|
139
139
|
// ❌ Bad: non-deterministic — argument changes between executions
|
|
140
|
-
|
|
140
|
+
processJob.trigger({ timestamp: Date.now() });
|
|
141
141
|
|
|
142
142
|
// ✅ OK: call Date.now() in separated job
|
|
143
|
-
const timestamp =
|
|
144
|
-
|
|
143
|
+
const timestamp = timestampJob.trigger();
|
|
144
|
+
processJob.trigger({ timestamp });
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
```typescript
|
|
148
148
|
// ❌ Bad: non-deterministic — external data may change between executions
|
|
149
149
|
const items = await fetch("https://api.example.com/items").then((r) => r.json());
|
|
150
150
|
for (const item of items) {
|
|
151
|
-
|
|
151
|
+
processItem.trigger({ id: item.id });
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// ✅ OK: call fetch("https://api.example.com/items").then((r) => r.json()); in separated job
|
|
155
|
-
const items =
|
|
155
|
+
const items = fetchItemsJob.trigger();
|
|
156
156
|
for (const item of items) {
|
|
157
|
-
|
|
157
|
+
processItem.trigger({ id: item.id });
|
|
158
158
|
}
|
|
159
159
|
```
|
|
160
160
|
|
|
@@ -178,15 +178,15 @@ import { sendNotification } from "./jobs/send-notification";
|
|
|
178
178
|
// Jobs must be named exports
|
|
179
179
|
export const processOrder = createWorkflowJob({
|
|
180
180
|
name: "process-order",
|
|
181
|
-
body:
|
|
181
|
+
body: (input: { customerId: string }, { env, invoker }) => {
|
|
182
182
|
// `env` contains values from `tailor.config.ts` -> `env`.
|
|
183
|
-
// `invoker` is the principal running this job,
|
|
184
|
-
//
|
|
183
|
+
// `invoker` is the principal running this job, or the machine user
|
|
184
|
+
// configured through the trigger `invoker` option; `null` for anonymous calls.
|
|
185
185
|
// Trigger other jobs by calling .trigger() on the job object.
|
|
186
|
-
const customer =
|
|
186
|
+
const customer = fetchCustomer.trigger({
|
|
187
187
|
customerId: input.customerId,
|
|
188
188
|
});
|
|
189
|
-
|
|
189
|
+
sendNotification.trigger({
|
|
190
190
|
message: "Order processed",
|
|
191
191
|
recipient: customer.email,
|
|
192
192
|
});
|
|
@@ -356,7 +356,7 @@ export default createWorkflow({
|
|
|
356
356
|
You can start a workflow execution from a resolver using `workflow.trigger()`.
|
|
357
357
|
|
|
358
358
|
- `workflow.trigger(args, options?)` returns a workflow run ID (`Promise<string>`).
|
|
359
|
-
- To run with machine-user permissions, pass `{
|
|
359
|
+
- To run with machine-user permissions, pass `{ invoker: "<machine-user>" }`. The name is type-narrowed to the machine users defined in your auth config.
|
|
360
360
|
|
|
361
361
|
```typescript
|
|
362
362
|
import { createResolver, t } from "@tailor-platform/sdk";
|
|
@@ -372,7 +372,7 @@ export default createResolver({
|
|
|
372
372
|
body: async ({ input }) => {
|
|
373
373
|
const workflowRunId = await orderProcessingWorkflow.trigger(
|
|
374
374
|
{ orderId: input.orderId, customerId: input.customerId },
|
|
375
|
-
{
|
|
375
|
+
{ invoker: "manager-machine-user" },
|
|
376
376
|
);
|
|
377
377
|
|
|
378
378
|
return { workflowRunId };
|
|
@@ -383,8 +383,6 @@ export default createResolver({
|
|
|
383
383
|
});
|
|
384
384
|
```
|
|
385
385
|
|
|
386
|
-
> **Deprecated:** `auth.invoker("manager-machine-user")` still works but is deprecated. Using the string form avoids importing `auth` into runtime code.
|
|
387
|
-
|
|
388
386
|
See the full working example in the repository: [example/resolvers/triggerWorkflow.ts](https://github.com/tailor-platform/sdk/blob/main/example/resolvers/triggerWorkflow.ts).
|
|
389
387
|
|
|
390
388
|
## File Organization
|