Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c43dfe9
Merge remote-tracking branch 'origin/feat/runtime-emulate' into feat/…
toiroakr May 7, 2026
c62c3b0
feat(sdk): vendor function-types and add @tailor-platform/sdk/runtime
toiroakr May 7, 2026
e1aedd2
refactor(sdk): expose runtime types without ambient globals
toiroakr May 7, 2026
b546863
Merge remote-tracking branch 'origin/feat/runtime-emulate' into feat/…
toiroakr May 7, 2026
d5ad97e
chore: sync skills
tailor-platform-pr-trigger[bot] May 7, 2026
6327a78
Merge branch 'main' into feat/function-types
toiroakr May 13, 2026
0276343
fix(sdk): use existing workflowMock API names in runtime workflow test
toiroakr May 13, 2026
a84e861
refactor(sdk): make runtime wrappers opt-in to ambient globals
toiroakr May 13, 2026
1ae8a02
docs(sdk): correct contextMock references and document it in testing …
toiroakr May 13, 2026
4538886
refactor(sdk): unify runtime/context.Invoker with SDK-friendly attrib…
toiroakr May 13, 2026
997e0b0
refactor(sdk): align runtime types and file stream mock with platform…
toiroakr May 13, 2026
b407fa2
docs(sdk): drop runtime sequencing detail from user-facing workflow docs
toiroakr May 13, 2026
362c958
fix(sdk): broaden runtime globals and tighten file stream mock contract
toiroakr May 13, 2026
8d6cebb
fix(sdk): keep ambient runtime globals active when importing @tailor-…
toiroakr May 13, 2026
e5e0872
chore(sdk): exclude __test_fixtures__ from tsconfig and consolidate l…
toiroakr May 13, 2026
7cf3328
chore(sdk): address Copilot review feedback on runtime/vitest mocks
toiroakr May 13, 2026
f8a6781
docs(sdk): align openDownloadStream mock example with StreamValue type
toiroakr May 13, 2026
0d8f55d
docs(sdk): drop wrapper-internal shape conversion from runtime docs
toiroakr May 13, 2026
ba1171f
chore(example): revert unrelated User.schema fixture drift
toiroakr May 13, 2026
c391cde
refactor(sdk): move runtime types into per-service wrappers
toiroakr May 13, 2026
0749c01
fix(sdk): activate ambient runtime globals via tsdown banner
toiroakr May 14, 2026
08abf15
docs(sdk): drop function-types lockstep note from runtime guide
toiroakr May 14, 2026
ed326a0
docs(sdk): drop globals opt-in note from testing guide
toiroakr May 14, 2026
5349265
fix(sdk): scope ambient globals banner to the configure entry only
toiroakr May 14, 2026
d1a1215
fix(sdk): correct configure-entry banner scoping and download-mock note
toiroakr May 14, 2026
2d53012
chore: merge main into feat/function-types
toiroakr May 18, 2026
cdbd260
refactor(sdk): address PR review feedback
toiroakr May 18, 2026
bbbd42d
refactor(sdk): consolidate runtime globals to var tailor + namespace …
toiroakr May 19, 2026
f9723e5
fix(sdk): avoid ambient Tailor namespace in @tailor-platform/sdk/test
toiroakr May 19, 2026
4567e89
refactor(sdk): inline runtime aggregates into index.ts and drop inter…
toiroakr May 19, 2026
9697f73
refactor(sdk): merge type-only namespaces into var tailor / var tailordb
toiroakr May 19, 2026
5106842
fix(sdk): export deleteFile alongside delete alias for named imports
toiroakr May 19, 2026
ce83a92
refactor(sdk): consolidate runtime wrappers via indexed access types
toiroakr May 19, 2026
90fc6ff
refactor(sdk): reuse TailorWorkflowAPI in configure wait-point
toiroakr May 19, 2026
6e9b05a
Merge remote-tracking branch 'origin/main' into feat/function-types
toiroakr May 19, 2026
f5d3d38
feat(sdk-codemod): add v2/tailordb-namespace and v2/drop-function-typ…
toiroakr May 19, 2026
429cdf7
revert(sdk): move vitest tests back under __tests__/
toiroakr May 19, 2026
4416fed
chore(sdk-codemod): drop v2/drop-function-types-dep codemod
toiroakr May 19, 2026
50f302a
Merge remote-tracking branch 'origin/main' into feat/function-types
toiroakr May 20, 2026
10382b8
fix(sdk): add Client type alias to lowercase tailordb namespace
toiroakr May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/runtime-wrapper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@tailor-platform/sdk": minor
Comment thread
toiroakr marked this conversation as resolved.
---

Add `@tailor-platform/sdk/runtime` — typed wrappers for the Tailor Platform Function runtime APIs (`tailor.iconv`, `tailor.secretmanager`, `tailor.authconnection`, `tailor.idp`, `tailor.workflow`, `tailor.context`, and `tailordb.file`). The wrappers and their types are fully self-contained, so you can use them without activating any ambient globals.

```ts
import { iconv, secretmanager, idp, file } from "@tailor-platform/sdk/runtime";

const utf8 = iconv.convert(sjisBuffer, "Shift_JIS", "UTF-8");
const apiKey = await secretmanager.getSecret("my-vault", "API_KEY");
const client = new idp.Client({ namespace: "my-namespace" });
const { metadata } = await file.upload("ns", "Document", "attachment", recordId, bytes);
```

The SDK no longer depends on the external `@tailor-platform/function-types` package; its declarations are now vendored inside the SDK. For backwards compatibility the ambient `tailor.*` / `tailordb.*` types are still activated automatically when you import from `@tailor-platform/sdk`, so existing code keeps type-checking with no changes. This implicit activation will be removed in v2.0 — new code is encouraged to use the typed wrappers from `@tailor-platform/sdk/runtime`, or to opt into the globals explicitly via `import "@tailor-platform/sdk/runtime/globals"` (or by listing the entry in `tsconfig.json`'s `compilerOptions.types`).
Comment thread
toiroakr marked this conversation as resolved.

The capital-cased `Tailordb` ambient namespace (`Tailordb.QueryResult`, `Tailordb.CommandType`, `Tailordb.Client`) is preserved as a `@deprecated` alias of the new lowercase `tailordb.*` namespace for source-level compatibility with `@tailor-platform/function-types`. It will be removed in v2.0; run `pnpm dlx @tailor-platform/sdk-codemod v2/tailordb-namespace` to migrate. The `@tailor-platform/function-types` declarations are vendored inside the SDK and activated automatically, so you can simply remove `@tailor-platform/function-types` from your `package.json` (and from `tsconfig.json` `compilerOptions.types` if listed) once you've upgraded.

Other test-mock changes from `@tailor-platform/sdk/vitest`:

- Breaking: when an `openDownloadStream` (or `toFileStream()`) call consumes a queued mock result, raw `Uint8Array` / `ArrayBuffer` payloads are now rejected. Enqueue a structured iterable of `StreamValue` items (`{ type: "metadata" }`, `{ type: "chunk", data, position }`, `{ type: "complete" }`) so test streams stay aligned with the platform's structured stream contract. The shorthand `Uint8Array` enqueue is still accepted by `download` / `downloadAsBase64`.
5 changes: 5 additions & 0 deletions .changeset/sdk-codemod-tailordb-namespace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tailor-platform/sdk-codemod": patch
---

Add `v2/tailordb-namespace` codemod for the `@tailor-platform/function-types` → `@tailor-platform/sdk` vendoring: rewrite references to the deprecated capital-cased `Tailordb` ambient namespace (`Tailordb.QueryResult`, `Tailordb.CommandType`, `Tailordb.Client`, `typeof Tailordb.Client`) to the new lowercase `tailordb.*` namespace re-published by the SDK.
18 changes: 13 additions & 5 deletions example/generated/files.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import * as file from "@tailor-platform/sdk/runtime/file";
import type {
FileUploadOptions,
FileUploadResponse,
FileMetadata,
FileStreamIterator,
} from "@tailor-platform/sdk/runtime/file";

export interface TypeWithFiles {
SalesOrder: {
fields: "receipt" | "form";
Expand All @@ -21,7 +29,7 @@ export async function downloadFile<T extends keyof TypeWithFiles>(
field: TypeWithFiles[T]["fields"],
recordId: string,
) {
return await tailordb.file.download(namespaces[type], type, field, recordId);
return await file.download(namespaces[type], type, field, recordId);
}

export async function uploadFile<T extends keyof TypeWithFiles>(
Expand All @@ -31,29 +39,29 @@ export async function uploadFile<T extends keyof TypeWithFiles>(
data: string | ArrayBuffer | Uint8Array<ArrayBufferLike> | number[],
options?: FileUploadOptions,
): Promise<FileUploadResponse> {
return await tailordb.file.upload(namespaces[type], type, field, recordId, data, options);
return await file.upload(namespaces[type], type, field, recordId, data, options);
}

export async function deleteFile<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<void> {
return await tailordb.file.delete(namespaces[type], type, field, recordId);
return await file.delete(namespaces[type], type, field, recordId);
}

export async function getFileMetadata<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<FileMetadata> {
return await tailordb.file.getMetadata(namespaces[type], type, field, recordId);
return await file.getMetadata(namespaces[type], type, field, recordId);
}

export async function openFileDownloadStream<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<FileStreamIterator> {
return await tailordb.file.openDownloadStream(namespaces[type], type, field, recordId);
return await file.openDownloadStream(namespaces[type], type, field, recordId);
}
18 changes: 13 additions & 5 deletions example/tests/fixtures/expected/files.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import * as file from "@tailor-platform/sdk/runtime/file";
import type {
FileUploadOptions,
FileUploadResponse,
FileMetadata,
FileStreamIterator,
} from "@tailor-platform/sdk/runtime/file";

export interface TypeWithFiles {
SalesOrder: {
fields: "receipt" | "form";
Expand All @@ -21,7 +29,7 @@ export async function downloadFile<T extends keyof TypeWithFiles>(
field: TypeWithFiles[T]["fields"],
recordId: string,
) {
return await tailordb.file.download(namespaces[type], type, field, recordId);
return await file.download(namespaces[type], type, field, recordId);
}

export async function uploadFile<T extends keyof TypeWithFiles>(
Expand All @@ -31,29 +39,29 @@ export async function uploadFile<T extends keyof TypeWithFiles>(
data: string | ArrayBuffer | Uint8Array<ArrayBufferLike> | number[],
options?: FileUploadOptions,
): Promise<FileUploadResponse> {
return await tailordb.file.upload(namespaces[type], type, field, recordId, data, options);
return await file.upload(namespaces[type], type, field, recordId, data, options);
}

export async function deleteFile<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<void> {
return await tailordb.file.delete(namespaces[type], type, field, recordId);
return await file.delete(namespaces[type], type, field, recordId);
}

export async function getFileMetadata<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<FileMetadata> {
return await tailordb.file.getMetadata(namespaces[type], type, field, recordId);
return await file.getMetadata(namespaces[type], type, field, recordId);
}

export async function openFileDownloadStream<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<FileStreamIterator> {
return await tailordb.file.openDownloadStream(namespaces[type], type, field, recordId);
return await file.openDownloadStream(namespaces[type], type, field, recordId);
}
18 changes: 13 additions & 5 deletions packages/create-sdk/templates/generators/src/generated/files.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import * as file from "@tailor-platform/sdk/runtime/file";
import type {
FileUploadOptions,
FileUploadResponse,
FileMetadata,
FileStreamIterator,
} from "@tailor-platform/sdk/runtime/file";

export interface TypeWithFiles {
Product: {
fields: "image";
Expand All @@ -13,7 +21,7 @@ export async function downloadFile<T extends keyof TypeWithFiles>(
field: TypeWithFiles[T]["fields"],
recordId: string,
) {
return await tailordb.file.download(namespaces[type], type, field, recordId);
return await file.download(namespaces[type], type, field, recordId);
}

export async function uploadFile<T extends keyof TypeWithFiles>(
Expand All @@ -23,29 +31,29 @@ export async function uploadFile<T extends keyof TypeWithFiles>(
data: string | ArrayBuffer | Uint8Array<ArrayBufferLike> | number[],
options?: FileUploadOptions,
): Promise<FileUploadResponse> {
return await tailordb.file.upload(namespaces[type], type, field, recordId, data, options);
return await file.upload(namespaces[type], type, field, recordId, data, options);
}

export async function deleteFile<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<void> {
return await tailordb.file.delete(namespaces[type], type, field, recordId);
return await file.delete(namespaces[type], type, field, recordId);
}

export async function getFileMetadata<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<FileMetadata> {
return await tailordb.file.getMetadata(namespaces[type], type, field, recordId);
return await file.getMetadata(namespaces[type], type, field, recordId);
}

export async function openFileDownloadStream<T extends keyof TypeWithFiles>(
type: T,
field: TypeWithFiles[T]["fields"],
recordId: string,
): Promise<FileStreamIterator> {
return await tailordb.file.openDownloadStream(namespaces[type], type, field, recordId);
return await file.openDownloadStream(namespaces[type], type, field, recordId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: "@tailor-platform/tailordb-namespace"
version: "1.0.0"
description: "Rename the deprecated capital-cased `Tailordb` ambient namespace to lowercase `tailordb` (e.g. `Tailordb.QueryResult` → `tailordb.QueryResult`)"
engine: jssg
language: typescript
since: "1.0.0"
until: "2.0.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Members exposed by the deprecated `Tailordb` ambient namespace from
// `@tailor-platform/function-types`. Each was a type-only declaration that
// has been re-published under the new lowercase `tailordb` namespace by the
// SDK. Anything outside this list is left untouched so user-defined symbols
// that happen to share the `Tailordb.` prefix are not rewritten by accident.
const TAILORDB_MEMBERS = ["QueryResult", "CommandType", "Client"] as const;

const MEMBER_GROUP = TAILORDB_MEMBERS.join("|");

// Match `Tailordb.<Member>` with word boundaries so neither prefix nor
// suffix collisions (e.g. `MyTailordb.X`, `Tailordb.QueryResultExtra`) are
// rewritten. Generic-argument lists and `typeof` qualifiers are not part of
// the match — they fall outside the boundary and are preserved verbatim.
const PATTERN = new RegExp(String.raw`\bTailordb\.(${MEMBER_GROUP})\b`, "g");

/**
* Rewrite references to the deprecated capital-cased `Tailordb` ambient
* namespace to the new lowercase `tailordb` namespace. The capital-cased
* namespace was inherited from `@tailor-platform/function-types`; the SDK
* keeps it as a `@deprecated` alias in v1 and removes it in v2.
*
* Only the known type-only members (`QueryResult`, `CommandType`, `Client`)
* are rewritten so that unrelated user-defined symbols sharing the
* `Tailordb.` prefix remain untouched. Both type-position references
* (`Tailordb.QueryResult<T>`, `typeof Tailordb.Client`) and value-position
* references (`new Tailordb.Client(...)`) are handled by the same rule.
* @param source - File contents
* @param _filePath - Absolute path to the file (kept for the runner signature)
* @returns Transformed source or null when nothing matched.
*/
export default function transform(source: string, _filePath: string): string | null {
if (!source.includes("Tailordb.")) return null;
PATTERN.lastIndex = 0;
const updated = source.replace(PATTERN, (_match, member: string) => `tailordb.${member}`);
return updated === source ? null : updated;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
async function fetchRows<O>(): Promise<tailordb.QueryResult<O>> {
return {} as tailordb.QueryResult<O>;
}

const command: tailordb.CommandType = "SELECT";
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
async function fetchRows<O>(): Promise<Tailordb.QueryResult<O>> {
return {} as Tailordb.QueryResult<O>;
}

const command: Tailordb.CommandType = "SELECT";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function takeClient(client: tailordb.Client): void {
void client;
}

function makeClient(Ctor: typeof tailordb.Client): tailordb.Client {
return new Ctor({ namespace: "demo" });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function takeClient(client: Tailordb.Client): void {
void client;
}

function makeClient(Ctor: typeof Tailordb.Client): Tailordb.Client {
return new Ctor({ namespace: "demo" });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface Row {
id: string;
}

type RowsResult = tailordb.QueryResult<Row>;

function describe(result: tailordb.QueryResult<{ id: number; tags: readonly string[] }>): number {
return result.rowCount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface Row {
id: string;
}

type RowsResult = Tailordb.QueryResult<Row>;

function describe(result: Tailordb.QueryResult<{ id: number; tags: readonly string[] }>): number {
return result.rowCount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
async function run<O>(): Promise<tailordb.QueryResult<O>> {
const cmd: tailordb.CommandType = "SELECT";
const client: tailordb.Client = new (tailordb.Client as typeof tailordb.Client)({
namespace: "demo",
});
void cmd;
void client;
return {} as tailordb.QueryResult<O>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
async function run<O>(): Promise<Tailordb.QueryResult<O>> {
const cmd: Tailordb.CommandType = "SELECT";
const client: Tailordb.Client = new (Tailordb.Client as typeof Tailordb.Client)({
namespace: "demo",
});
void cmd;
void client;
return {} as Tailordb.QueryResult<O>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createResolver, t } from "@tailor-platform/sdk";

export default createResolver({
name: "hello",
type: "Query",
output: t.string(),
body: () => "world",
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Identifiers that merely *start* with `Tailordb` (or have an unknown
// member) must not be rewritten by the codemod.

namespace MyTailordb {
export type QueryResult<T> = { rows: T[] };
}

type Mine = MyTailordb.QueryResult<{ id: string }>;

// Unknown member on the deprecated namespace stays untouched (best-effort
// safety net — there is no `Tailordb.NotAType` on the SDK side).
type Untouched = Tailordb.NotAType;

// A suffix-extended member name must also stay intact.
type Extra = Tailordb.QueryResultExtra;
10 changes: 10 additions & 0 deletions packages/sdk-codemod/src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ const allCodemods: CodemodPackage[] = [
scriptPath: "v2/auth-invoker-unwrap/scripts/transform.js",
legacyPatterns: ["auth.invoker"],
},
{
id: "v2/tailordb-namespace",
name: "Tailordb → tailordb (lowercase ambient namespace)",
description:
"Rewrite references to the deprecated capital-cased `Tailordb` ambient namespace (`Tailordb.QueryResult`, `Tailordb.CommandType`, `Tailordb.Client`, `typeof Tailordb.Client`) to the new lowercase `tailordb.*` namespace re-published by the SDK in place of `@tailor-platform/function-types`.",
since: "1.0.0",
until: "2.0.0",
scriptPath: "v2/tailordb-namespace/scripts/transform.js",
legacyPatterns: ["Tailordb."],
},
];

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk-codemod/src/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,8 @@ describe("codemod transforms", () => {
it("v2/auth-invoker-unwrap transforms correctly", async () => {
await runFixtureCases("v2/auth-invoker-unwrap");
});

it("v2/tailordb-namespace transforms correctly", async () => {
await runFixtureCases("v2/tailordb-namespace");
});
});
2 changes: 2 additions & 0 deletions packages/sdk-codemod/tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export default defineConfig([
"v2/cli-rename/scripts/transform": "codemods/v2/cli-rename/scripts/transform.ts",
"v2/auth-invoker-unwrap/scripts/transform":
"codemods/v2/auth-invoker-unwrap/scripts/transform.ts",
"v2/tailordb-namespace/scripts/transform":
"codemods/v2/tailordb-namespace/scripts/transform.ts",
},
format: ["esm"],
target: "node18",
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ the installed SDK version. Files are copied (not symlinked) so they survive

### Guides

- [Runtime API](./docs/runtime.md) - Typed wrappers for `tailor.iconv`, `tailor.secretmanager`, `tailor.idp`, `tailor.workflow`, `tailor.context`, `tailor.authconnection`, and `tailordb.file`
- [Testing Guide](./docs/testing.md) - Unit and E2E testing patterns
- [CLI Reference](./docs/cli-reference.md) - Command-line interface documentation

Expand Down
Loading
Loading