@tailor-platform/sdk 2.32.0 → 2.33.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 +44 -0
- package/dist/{application-D0xNJbag.mjs → application-B9_NHiUC.mjs} +40 -32
- package/dist/application-B9_NHiUC.mjs.map +1 -0
- package/dist/application-Bet1K5C4.mjs +1 -0
- package/dist/cli/commands/deploy/staticwebsite.d.mts +1 -0
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/main.mjs +44 -33
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/services/resolver/service.d.mts +1 -0
- package/dist/cli/shared/client.d.mts +52 -1
- package/dist/cli/ts-hook.d.mts +0 -2
- package/dist/cli/ts-hook.mjs +0 -113
- package/dist/completion/zsh-worker.zsh +25 -5
- package/dist/configure/services/staticwebsite/index.d.mts +6 -1
- package/dist/{kysely-type-CBwsdx16.mjs → kysely-type-DxyIWXc6.mjs} +3 -3
- package/dist/kysely-type-DxyIWXc6.mjs.map +1 -0
- package/dist/manager-DTRhIupk.mjs +2 -0
- package/dist/manager-DTRhIupk.mjs.map +1 -0
- package/dist/plugin/builtin/enum-constants/index.mjs +2 -2
- package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/index.mjs +1 -1
- package/dist/plugin/types.d.mts +3 -0
- package/dist/register-ts-hook-Dp9reSRG.mjs +1053 -0
- package/dist/register-ts-hook-Dp9reSRG.mjs.map +1 -0
- package/dist/repl-editor-DkrCZmmg.mjs +2 -0
- package/dist/repl-editor-DkrCZmmg.mjs.map +1 -0
- package/dist/service_pb-6EkMfdOb.mjs +2 -0
- package/dist/service_pb-6EkMfdOb.mjs.map +1 -0
- package/dist/service_pb-CsJKokDl.mjs +1 -0
- package/dist/tailor-proto/src/tailor/v1/metadata_pb.d.mts +5 -2
- package/dist/tailor-proto/src/tailor/v1/security_pb.d.mts +213 -0
- package/dist/tailor-proto/src/tailor/v1/security_resource_pb.d.mts +301 -0
- package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +200 -8
- package/dist/tailor-proto/src/tailor/v1/staticwebsite_pb.d.mts +201 -1
- package/dist/tailor-proto/src/tailor/v1/staticwebsite_resource_pb.d.mts +88 -1
- package/dist/types/staticwebsite.generated.d.mts +9 -1
- package/dist/vitest/index.d.mts +2 -2
- package/dist/vitest/index.mjs +1 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/pglite-kysely.d.mts +19 -0
- package/dist/{workspace_resource_pb-CaoM2npP.mjs → workspace_resource_pb-C4CkoYww.mjs} +2 -2
- package/dist/workspace_resource_pb-C4CkoYww.mjs.map +1 -0
- package/docs/plugin/custom.md +34 -0
- package/docs/plugin/index.md +1 -0
- package/docs/services/staticwebsite.md +31 -1
- package/docs/services/tailordb/migration.md +33 -10
- package/package.json +5 -5
- package/dist/application-C2bPmmbh.mjs +0 -1
- package/dist/application-D0xNJbag.mjs.map +0 -1
- package/dist/kysely-type-CBwsdx16.mjs.map +0 -1
- package/dist/manager-Bk-7vkwd.mjs +0 -2
- package/dist/manager-Bk-7vkwd.mjs.map +0 -1
- package/dist/register-ts-hook-_dHIREtU.mjs +0 -1050
- package/dist/register-ts-hook-_dHIREtU.mjs.map +0 -1
- package/dist/repl-editor-DGJBfIt1.mjs +0 -2
- package/dist/repl-editor-DGJBfIt1.mjs.map +0 -1
- package/dist/service_pb-Bbu2QSIr.mjs +0 -2
- package/dist/service_pb-Bbu2QSIr.mjs.map +0 -1
- package/dist/service_pb-urxAIYHT.mjs +0 -1
- package/dist/workspace_resource_pb-CaoM2npP.mjs.map +0 -1
package/docs/plugin/custom.md
CHANGED
|
@@ -90,6 +90,40 @@ interface Plugin<TableConfig = unknown, PluginConfig = unknown> {
|
|
|
90
90
|
| `executors` | `PluginGeneratedExecutor[]` | Additional executors to generate |
|
|
91
91
|
| `extends` | `{ fields?: Record<string, TailorAnyDBField> }` | Fields to add to the source table |
|
|
92
92
|
|
|
93
|
+
Resolvers returned by `onTableLoaded` or `onNamespaceLoaded` are loaded, bundled, and deployed to
|
|
94
|
+
the resolver namespace (a `resolver` key in your config) with the same name as the hook's TailorDB
|
|
95
|
+
namespace (a `db` key). These are separate namespaces that only share the name: with
|
|
96
|
+
`db: { main: ... }` and `resolver: { billing: ... }`, generated resolvers go to a `main` resolver
|
|
97
|
+
namespace, not `billing`. If you configure a resolver namespace with that name, generated resolvers
|
|
98
|
+
join its configured files and use its `defaultPermission`. Otherwise, a resolver namespace is created
|
|
99
|
+
automatically. Configure `defaultPermission` to restrict access; without it, generated resolvers are
|
|
100
|
+
accessible to anonymous callers, like regular resolvers with no permission declared. Generating into
|
|
101
|
+
an external resolver namespace or duplicating a resolver name within a namespace fails the build.
|
|
102
|
+
|
|
103
|
+
For example, a namespace hook can return a query using `t` field builders:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
onNamespaceLoaded() {
|
|
107
|
+
return {
|
|
108
|
+
resolvers: [{
|
|
109
|
+
name: "greet",
|
|
110
|
+
operation: "query",
|
|
111
|
+
inputFields: { name: t.string() },
|
|
112
|
+
outputFields: { message: t.string() },
|
|
113
|
+
body: 'return { message: `Hello, ${context.input.name}!` };',
|
|
114
|
+
}],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The `body` string contains JavaScript statements with access to `context.input`, `context.caller`,
|
|
120
|
+
`context.invoker`, and `context.env`. It can use `await` and platform globals, but cannot capture
|
|
121
|
+
plugin-local variables. Embed configuration values as literals with `JSON.stringify` when building
|
|
122
|
+
the string. Field validators must also be self-contained: they can use their arguments and standard
|
|
123
|
+
JavaScript globals, and references to other names are rejected during generation. Input validation and date conversion follow the same rules as regular
|
|
124
|
+
resolvers. Invalid field definitions or JavaScript syntax fail the build with the plugin and namespace
|
|
125
|
+
identified in the error.
|
|
126
|
+
|
|
93
127
|
Tables in `tables` are validated as complete TailorDB table definitions before registration.
|
|
94
128
|
Fields in `extends.fields` are validated as part of the resulting source table. You can return a
|
|
95
129
|
table builder directly or a structural copy such as `{ ...db.table(...) }`; a copy is accepted as
|
package/docs/plugin/index.md
CHANGED
|
@@ -102,6 +102,7 @@ export const plugins = definePlugins(
|
|
|
102
102
|
Plugins can generate:
|
|
103
103
|
|
|
104
104
|
- **Tables**: Additional TailorDB tables (e.g., `CustomerHistory`, `Deleted_Customer`)
|
|
105
|
+
- **Resolvers**: Queries and mutations
|
|
105
106
|
- **Executors**: Event handlers triggered by record changes
|
|
106
107
|
- **Field Extensions**: Additional fields added to the source table
|
|
107
108
|
- **Output Files**: TypeScript code and other files via generation-time hooks
|
|
@@ -78,7 +78,37 @@ defineStaticWebSite("my-website", {
|
|
|
78
78
|
|
|
79
79
|
After deploying, use `tailor staticwebsite domain get <domain>` to check domain status and retrieve the CNAME targets required for DNS configuration.
|
|
80
80
|
|
|
81
|
-
A domain can be associated with only one workspace at a time. To set custom domains only in the workspace that owns the domain, see [Multi-Environment Configuration](../multi-environment.md#settings-that-belong-to-a-single-environment).
|
|
81
|
+
A domain can be associated with only one workspace at a time. To set custom domains only in the workspace that owns the domain, see [Multi-Environment Configuration](../multi-environment.md#settings-that-belong-to-a-single-environment). To hand a domain to another site or workspace without taking it offline, see [Moving a domain](#moving-a-domain).
|
|
82
|
+
|
|
83
|
+
### Moving a domain
|
|
84
|
+
|
|
85
|
+
A domain already serving traffic can be moved to another static website — in this workspace or another one — without downtime, without reissuing its certificate and without changing DNS. The site that currently holds the domain offers it; the receiving site accepts by listing the domain normally.
|
|
86
|
+
|
|
87
|
+
On the side giving the domain up, replace the plain entry with the destination:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
defineStaticWebSite("my-website", {
|
|
91
|
+
customDomains: [{ domain: "app.example.com", transferTo: { workspaceId: "..." } }],
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Deploying opens the offer. On the receiving side, list the domain as usual and deploy:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
defineStaticWebSite("new-website", {
|
|
99
|
+
customDomains: ["app.example.com"],
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
That deploy completes the move. The next plan on the giving side reports that the domain moved, and the entry should then be deleted — it describes a move that already happened, not ongoing state.
|
|
104
|
+
|
|
105
|
+
The two deploys must be separate runs, even when both sites live in the same workspace: the receiving side cannot accept an offer that the same run is still opening, and `tailor deploy` says so rather than failing partway.
|
|
106
|
+
|
|
107
|
+
These rules apply while an offer is open:
|
|
108
|
+
|
|
109
|
+
- An offer expires after 7 days. Deploying the entry again after that opens a fresh offer.
|
|
110
|
+
- Neither the domain nor the static website holding it can be removed. Change the entry back to a plain string and deploy to withdraw the offer first; `tailor deploy` and `tailor remove` both refuse before changing anything.
|
|
111
|
+
- An offer takes a moment to become ready. Until it is, the receiving side cannot accept it and its deploy is refused; the giving side's plan says so.
|
|
82
112
|
|
|
83
113
|
## Type-safe URL References
|
|
84
114
|
|
|
@@ -462,6 +462,25 @@ tailor deploy --migration-skip-steps main-db/backfillUser,main-db/backfillInvoic
|
|
|
462
462
|
|
|
463
463
|
Write every step so that running it again is safe: besides the cases above, a step can run a second time when a deploy is interrupted right after it commits. Use `where` clauses that skip rows a step already migrated, as in the example. Rows written while a migration is in progress are not seen by steps that already completed. [Maintenance mode](#maintenance-mode) blocks GraphQL writes but not the writes your resolvers, executors, or workflows make through Kysely, and without it GraphQL clients can write too, so stop such writers until the migration finishes or write steps that tolerate them.
|
|
464
464
|
|
|
465
|
+
#### Rolling back instead of resuming
|
|
466
|
+
|
|
467
|
+
By default a failure after another step has completed leaves the migration in progress and the namespace's tables in maintenance mode until you fix the step and deploy again. When you would rather restore the tables first and fix the script afterwards, export `onFailure` next to `steps`:
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
export const onFailure = "rollback";
|
|
471
|
+
|
|
472
|
+
export const steps = {
|
|
473
|
+
// ...
|
|
474
|
+
} satisfies MigrationSteps;
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
- `onFailure` is `"resume"` (the default, described above) or `"rollback"`. Write it as `export const onFailure = "rollback"` with one of those two string literals; `tailor tailordb migration validate` and `tailor deploy` reject anything else. A script that runs `main` ignores it.
|
|
478
|
+
- With `"rollback"`, a failed step after another step has completed, and post-migration schema changes that fail after every step completed, roll back the pre-migration schema changes like a failing `main` script: tables that already existed are restored to their previous shape and GraphQL permissions, and tables the migration newly introduced are dropped. The in-progress record is cleared before the schema is rolled back, the tables leave maintenance mode, and the checkpoint is not advanced. `tailor deploy` then fails with the step's error under the code `MIGRATION_ROLLED_BACK`, and its suggestion says the next deploy runs every step again. A migration that an earlier deploy left in progress is rolled back the same way once its script exports `"rollback"`, including the tables and GraphQL permissions its earlier Pre-phase wrote.
|
|
479
|
+
- Steps that already completed stay committed. Their changes to existing fields remain in the database, and nothing is recorded as in progress, so the next deploy runs every step again from the beginning. Every step must be safe to run again, or a rolled-back run applies those changes twice. Do not rely on data a step wrote to a field or table that the rollback removed.
|
|
480
|
+
- If `tailor deploy` cannot tell whether a step ran, or the migration's workflow execution may still be running (for example the connection to it was lost), it does not roll anything back even with `"rollback"`: the migration stays in progress as described for a `main` script below. A migration an earlier deploy left in progress is rolled back only when its earlier run is confirmed to have ended, so a failure before that run is inspected, such as a schema error while applying the Pre-phase, keeps it in progress.
|
|
481
|
+
- If the in-progress record cannot be cleared, `tailor deploy` does not roll the schema back. It logs a warning and keeps the migration in progress with its tables in maintenance mode, because a record that outlives a rollback would make the next deploy resume against a schema its completed steps no longer match. Deploy again to resume it as described above, or roll it back without deploying with `tailor tailordb migration resolve --rollback`.
|
|
482
|
+
- If the schema or GraphQL permission of some tables cannot be rolled back, `tailor deploy` still fails with the step's original error. It also warns `Migration <namespace>/<N> was not rolled back completely` and lists the tables that need manual repair, and separately the tables whose GraphQL permission could not be set back. Check them in the workspace and repair them by hand; deploying again does not release them.
|
|
483
|
+
|
|
465
484
|
### Settling a migration that stays in progress
|
|
466
485
|
|
|
467
486
|
When you do not want to resume the migration with another deploy — you abandoned it, or you repaired the data by hand — settle it with `tailor tailordb migration resolve`. Pass exactly one of two options:
|
|
@@ -905,10 +924,10 @@ Use `tailor tailordb migration rebaseline` rather than combining `migration gene
|
|
|
905
924
|
|
|
906
925
|
## Failure Recovery
|
|
907
926
|
|
|
908
|
-
A script that exports `steps` follows different rules once one of its steps has completed: the migration stays in progress and the next deploy resumes it
|
|
927
|
+
A script that exports `steps` follows different rules once one of its steps has completed: the migration stays in progress and the next deploy resumes it, unless the script exports `onFailure = "rollback"`. See [Splitting a migration into steps](#splitting-a-migration-into-steps) and [Rolling back instead of resuming](#rolling-back-instead-of-resuming). Otherwise, if the pre-migration phase or `migrate.ts` fails:
|
|
909
928
|
|
|
910
929
|
- **The transaction rolls back** for that migration's script. Database changes the script made are undone.
|
|
911
|
-
- **The pre-migration schema changes are rolled back** to the prior checkpoint: tables that already existed are restored to their previous shape, and tables the migration newly introduced are dropped. The workspace is left at its prior checkpoint and prior schema — not half-applied.
|
|
930
|
+
- **The pre-migration schema changes are rolled back** to the prior checkpoint: tables that already existed are restored to their previous shape and GraphQL permissions, and tables the migration newly introduced are dropped. The workspace is left at its prior checkpoint and prior schema — not half-applied.
|
|
912
931
|
- The whole `apply` aborts and the checkpoint label is not bumped. Subsequent migrations in the same run do not execute.
|
|
913
932
|
|
|
914
933
|
The rollback is best-effort per table; if reverting a table fails, a warning is logged and the original migration error is still reported. The next deploy then stops with remote schema drift on that table. Run `tailor tailordb migration validate` to see which tables differ, return the namespace to its checkpoint with `tailor tailordb migration sync <N>`, where `<N>` is the checkpoint `tailor tailordb migration status` reports, and deploy again. `sync` deletes the tables and fields that are not in that migration's snapshot, together with any rows the failed migration wrote to them; the next deploy runs the failed migration again.
|
|
@@ -1037,10 +1056,12 @@ npm install -D @electric-sql/pglite
|
|
|
1037
1056
|
|
|
1038
1057
|
The generated `db.pglite.ts` exports the `CREATE TABLE` script for the same schema `db.ts` types — the tables as the pre-migration phase leaves them while `migrate.ts` runs, including relaxed constraints, renamed fields under both names, and retained removed fields. Run it once on the PGlite instance, stage rows, then run the script in a transaction. `tailor tailordb migration script <N> --with-test` scaffolds this test too when `@electric-sql/pglite` is installed. Type the instance with `Unmigrated<Database>` rather than `Database`: `db.ts` types a column the migration makes required as `T | null` on read but `T` on write (and an enum it narrows as the old values on read but the new ones on write), so that `migrate.ts` cannot write what the migration is removing — which would also stop the test from staging the rows the script has to convert. `Unmigrated` lets every column be written with whatever it can still be read as; `main` still receives a `Transaction<Database>`.
|
|
1039
1058
|
|
|
1059
|
+
Relations are enforced as on the platform: a row that points at a parent that does not exist is rejected. Write the records the test starts from inside `prepareFixtures`, which leaves relations unchecked while it runs, so you can stage rows that predate a relation, such as rows whose parent does not exist that the script repairs. Relations are checked again when it returns, so the script itself still cannot write a missing parent. NOT NULL, UNIQUE, and CHECK constraints stay enforced. A relation is left unenforced while the pre-migration schema cannot satisfy it: when a pending type change leaves the field a different type from its target, when the migration retargets the relation to another table, or when the target field's unique constraint is still withheld. How relations on array fields and inside nested objects behave is described under [Real SQL execution with PGlite](../../testing.md#real-sql-execution-with-pglite-mocktailordbwithpglite).
|
|
1060
|
+
|
|
1040
1061
|
```typescript
|
|
1041
1062
|
// migrations/0005/migrate.pglite.test.ts
|
|
1042
1063
|
import { PGlite } from "@electric-sql/pglite";
|
|
1043
|
-
import { createKyselyPGlite, type Unmigrated } from "@tailor-platform/sdk/vitest";
|
|
1064
|
+
import { createKyselyPGlite, prepareFixtures, type Unmigrated } from "@tailor-platform/sdk/vitest";
|
|
1044
1065
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
1045
1066
|
import { pgliteSchema } from "./db.pglite";
|
|
1046
1067
|
import { main } from "./migrate";
|
|
@@ -1061,13 +1082,15 @@ afterAll(async () => {
|
|
|
1061
1082
|
describe("0005 add required email", () => {
|
|
1062
1083
|
test("backfills null emails and keeps existing ones", async () => {
|
|
1063
1084
|
const now = new Date();
|
|
1064
|
-
await
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1085
|
+
await prepareFixtures(pglite, async () => {
|
|
1086
|
+
await db
|
|
1087
|
+
.insertInto("User")
|
|
1088
|
+
.values([
|
|
1089
|
+
{ name: "a", email: null, createdAt: now, updatedAt: now },
|
|
1090
|
+
{ name: "b", email: "b@example.com", createdAt: now, updatedAt: now },
|
|
1091
|
+
])
|
|
1092
|
+
.execute();
|
|
1093
|
+
});
|
|
1071
1094
|
|
|
1072
1095
|
await db.transaction().execute((trx) => main(trx));
|
|
1073
1096
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.33.0",
|
|
4
4
|
"description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -160,10 +160,10 @@
|
|
|
160
160
|
"@bufbuild/protovalidate": "1.3.0",
|
|
161
161
|
"@connectrpc/connect": "2.2.0",
|
|
162
162
|
"@connectrpc/connect-node": "2.2.0",
|
|
163
|
-
"@inquirer/core": "12.0.
|
|
164
|
-
"@inquirer/prompts": "8.7.
|
|
163
|
+
"@inquirer/core": "12.0.5",
|
|
164
|
+
"@inquirer/prompts": "8.7.4",
|
|
165
165
|
"@jridgewell/trace-mapping": "0.3.31",
|
|
166
|
-
"@napi-rs/keyring": "2.1.
|
|
166
|
+
"@napi-rs/keyring": "2.1.2",
|
|
167
167
|
"@opentelemetry/api": "1.9.1",
|
|
168
168
|
"@opentelemetry/context-async-hooks": "2.12.0",
|
|
169
169
|
"@opentelemetry/exporter-trace-otlp-proto": "0.223.0",
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
"p-limit": "7.3.3",
|
|
197
197
|
"pathe": "2.0.3",
|
|
198
198
|
"pgsql-ast-parser": "12.0.2",
|
|
199
|
-
"pkg-types": "2.
|
|
199
|
+
"pkg-types": "2.4.0",
|
|
200
200
|
"rolldown": "1.2.14",
|
|
201
201
|
"semver": "7.8.5",
|
|
202
202
|
"sql-highlight": "6.1.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{t as defineApplication,n as generatePluginFilesIfNeeded}from"./application-D0xNJbag.mjs";
|