deepspace 0.2.4 → 0.2.6

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.
@@ -0,0 +1,115 @@
1
+ import * as _playwright_test from '@playwright/test';
2
+ import { BrowserContext, Page, Browser } from '@playwright/test';
3
+ export { expect } from '@playwright/test';
4
+
5
+ interface MultiplayerUser {
6
+ context: BrowserContext;
7
+ page: Page;
8
+ email: string;
9
+ name: string;
10
+ /** Test account user ID, if known from the accounts registry. */
11
+ userId?: string;
12
+ }
13
+ /**
14
+ * Fixture function signature. Pass either a count (`users(2)`) or an
15
+ * array of account names (`users(['Alice', 'Bob'])`). Returns one entry
16
+ * per requested user.
17
+ */
18
+ type UsersFixture = (selector: number | string[], options?: {
19
+ label?: string;
20
+ }) => Promise<MultiplayerUser[]>;
21
+ interface MultiplayerFixtures {
22
+ users: UsersFixture;
23
+ }
24
+ declare const test: _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions & MultiplayerFixtures, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions>;
25
+
26
+ /**
27
+ * Account-credential plumbing for the testing module.
28
+ *
29
+ * Reads test accounts from `~/.deepspace/test-accounts.json` (the same
30
+ * file `deepspace test-accounts create` writes). Each account has at
31
+ * minimum `{email, password}`; `name` and `label` are optional.
32
+ *
33
+ * Used by the multi-user Playwright fixture in `./fixtures.ts` and is
34
+ * also exported standalone in case suites want to do their own
35
+ * orchestration.
36
+ */
37
+ interface TestAccount {
38
+ email: string;
39
+ password: string;
40
+ name?: string;
41
+ label?: string | null;
42
+ id?: string;
43
+ userId?: string;
44
+ createdAt?: number;
45
+ }
46
+ /**
47
+ * Load all test accounts the developer has created. Returns an empty
48
+ * array if the file doesn't exist yet.
49
+ */
50
+ declare function loadAllTestAccounts(): TestAccount[];
51
+ /**
52
+ * Pick `count` test accounts from the local registry, optionally
53
+ * filtered by `label`. Order-stable: sorted by `createdAt` ascending so
54
+ * the first test account you created is always the first one returned.
55
+ *
56
+ * Throws with a helpful message if not enough accounts exist.
57
+ */
58
+ declare function pickTestAccounts(count: number, options?: {
59
+ label?: string;
60
+ }): TestAccount[];
61
+ /**
62
+ * Find a single account by name. Used by `users(['Alice', 'Bob'])`.
63
+ * Throws if not found.
64
+ */
65
+ declare function findTestAccountByName(name: string): TestAccount;
66
+
67
+ /**
68
+ * Per-account `storageState` cache for Playwright.
69
+ *
70
+ * Better Auth applies a per-IP rate limit on `/api/auth/sign-in/email`
71
+ * (~5 sign-ins / 60s / endpoint). A multiplayer suite that spins up
72
+ * 5+ users per spec would hit the limit and start failing in non-obvious
73
+ * ways. This module signs each account in *once*, persists the
74
+ * resulting browser cookies + storage to disk, and reuses the file on
75
+ * subsequent runs.
76
+ *
77
+ * Cache layout:
78
+ * ~/.deepspace/playwright-states/<sha256(email)>.json
79
+ *
80
+ * Validity: a cached file is reused if Playwright successfully loads it
81
+ * AND the resulting context produces a non-anonymous session on the
82
+ * target app. If validation fails, we fall back to a fresh sign-in and
83
+ * overwrite the cache.
84
+ */
85
+
86
+ interface EnsureStorageStateOptions {
87
+ /** Max age of a cached state file before we re-sign-in. Default 7 days. */
88
+ maxAgeMs?: number;
89
+ /** Force a fresh sign-in even if the cache is fresh. */
90
+ force?: boolean;
91
+ }
92
+ /**
93
+ * Ensure a Playwright `storageState` file exists for `account` and
94
+ * return its path. Signs in once if the cache is missing, stale, or
95
+ * `force: true`.
96
+ */
97
+ declare function ensureStorageState(browser: Browser, account: {
98
+ email: string;
99
+ password: string;
100
+ }, baseURL: string, options?: EnsureStorageStateOptions): Promise<string>;
101
+ /**
102
+ * Convenience: open a fresh `BrowserContext` for `account` using the
103
+ * cached storage state (signing in if needed). The caller is responsible
104
+ * for closing the context.
105
+ */
106
+ declare function newSignedInContext(browser: Browser, account: {
107
+ email: string;
108
+ password: string;
109
+ }, baseURL: string, options?: EnsureStorageStateOptions): Promise<BrowserContext>;
110
+ /** Read a cached storageState file (mostly for debugging). */
111
+ declare function readCachedState(email: string): unknown | null;
112
+ /** Where the cache for `email` lives. Useful for diagnostics. */
113
+ declare function getStatePathForEmail(email: string): string;
114
+
115
+ export { type EnsureStorageStateOptions, type MultiplayerUser, type TestAccount, type UsersFixture, ensureStorageState, findTestAccountByName, getStatePathForEmail, loadAllTestAccounts, newSignedInContext, pickTestAccounts, readCachedState, test };
@@ -0,0 +1,175 @@
1
+ // src/testing/fixtures.ts
2
+ import { test as baseTest } from "@playwright/test";
3
+
4
+ // src/testing/accounts.ts
5
+ import { existsSync, readFileSync } from "fs";
6
+ import { homedir } from "os";
7
+ import { join } from "path";
8
+ var ACCOUNTS_PATH = join(homedir(), ".deepspace", "test-accounts.json");
9
+ function loadAllTestAccounts() {
10
+ if (!existsSync(ACCOUNTS_PATH)) return [];
11
+ try {
12
+ const raw = JSON.parse(readFileSync(ACCOUNTS_PATH, "utf-8"));
13
+ if (!Array.isArray(raw)) return [];
14
+ return raw.filter(
15
+ (r) => r && typeof r.email === "string" && typeof r.password === "string"
16
+ );
17
+ } catch {
18
+ return [];
19
+ }
20
+ }
21
+ function pickTestAccounts(count, options) {
22
+ const all = loadAllTestAccounts();
23
+ const filtered = options?.label ? all.filter((a) => a.label === options.label) : all;
24
+ const sorted = filtered.slice().sort((a, b) => (a.createdAt ?? 0) - (b.createdAt ?? 0));
25
+ if (sorted.length < count) {
26
+ const labelHint = options?.label ? ` (label="${options.label}")` : "";
27
+ throw new Error(
28
+ `Multiplayer test needs ${count} test accounts${labelHint}, but only ${sorted.length} are present in ${ACCOUNTS_PATH}. Create more with:
29
+ deepspace test-accounts create --email <name>@deepspace.test --password <pw> --name "<name>"${options?.label ? ` --label ${options.label}` : ""}`
30
+ );
31
+ }
32
+ return sorted.slice(0, count);
33
+ }
34
+ function findTestAccountByName(name) {
35
+ const all = loadAllTestAccounts();
36
+ const match = all.find((a) => a.name === name);
37
+ if (!match) {
38
+ throw new Error(
39
+ `No test account named "${name}" in ${ACCOUNTS_PATH}. Create with:
40
+ deepspace test-accounts create --email ${name.toLowerCase()}@deepspace.test --password <pw> --name "${name}"`
41
+ );
42
+ }
43
+ return match;
44
+ }
45
+
46
+ // src/testing/storage-state.ts
47
+ import { createHash } from "crypto";
48
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, statSync } from "fs";
49
+ import { homedir as homedir2 } from "os";
50
+ import { join as join2 } from "path";
51
+ var STATES_DIR = join2(homedir2(), ".deepspace", "playwright-states");
52
+ var DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
53
+ function statePathForEmail(email) {
54
+ const hash = createHash("sha256").update(email.trim().toLowerCase()).digest("hex").slice(0, 24);
55
+ return join2(STATES_DIR, `${hash}.json`);
56
+ }
57
+ function ensureStatesDir() {
58
+ if (!existsSync2(STATES_DIR)) mkdirSync(STATES_DIR, { recursive: true });
59
+ }
60
+ function isCacheFresh(path, maxAgeMs) {
61
+ if (!existsSync2(path)) return false;
62
+ try {
63
+ const age = Date.now() - statSync(path).mtimeMs;
64
+ return age < maxAgeMs;
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+ async function signInAndSaveState(browser, account, baseURL, outPath) {
70
+ ensureStatesDir();
71
+ const ctx = await browser.newContext({ baseURL });
72
+ try {
73
+ const page = await ctx.newPage();
74
+ await page.goto("/");
75
+ const ok = await page.evaluate(
76
+ async ({ email, password }) => {
77
+ const res = await fetch("/api/auth/sign-in/email", {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json" },
80
+ body: JSON.stringify({ email, password })
81
+ });
82
+ return res.ok;
83
+ },
84
+ account
85
+ );
86
+ if (!ok) {
87
+ throw new Error(
88
+ `Sign-in failed for ${account.email}. Check the password is current; if the account was deleted on the server, re-create with \`deepspace test-accounts create\`.`
89
+ );
90
+ }
91
+ await ctx.storageState({ path: outPath });
92
+ return outPath;
93
+ } finally {
94
+ await ctx.close();
95
+ }
96
+ }
97
+ async function ensureStorageState(browser, account, baseURL, options = {}) {
98
+ const path = statePathForEmail(account.email);
99
+ const maxAgeMs = options.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
100
+ if (!options.force && isCacheFresh(path, maxAgeMs)) {
101
+ return path;
102
+ }
103
+ return signInAndSaveState(browser, account, baseURL, path);
104
+ }
105
+ async function newSignedInContext(browser, account, baseURL, options = {}) {
106
+ const statePath = await ensureStorageState(browser, account, baseURL, options);
107
+ return browser.newContext({ storageState: statePath, baseURL });
108
+ }
109
+ function readCachedState(email) {
110
+ const path = statePathForEmail(email);
111
+ if (!existsSync2(path)) return null;
112
+ try {
113
+ return JSON.parse(readFileSync2(path, "utf-8"));
114
+ } catch {
115
+ return null;
116
+ }
117
+ }
118
+ function getStatePathForEmail(email) {
119
+ return statePathForEmail(email);
120
+ }
121
+
122
+ // src/testing/fixtures.ts
123
+ import { expect } from "@playwright/test";
124
+ async function buildUser(browser, account, baseURL) {
125
+ const statePath = await ensureStorageState(browser, account, baseURL);
126
+ const context = await browser.newContext({ storageState: statePath, baseURL });
127
+ const page = await context.newPage();
128
+ return {
129
+ user: {
130
+ context,
131
+ page,
132
+ email: account.email,
133
+ name: account.name ?? account.email.split("@")[0],
134
+ userId: account.userId
135
+ },
136
+ cleanup: async () => {
137
+ await context.close();
138
+ }
139
+ };
140
+ }
141
+ var test = baseTest.extend({
142
+ users: async ({ browser, baseURL }, use) => {
143
+ if (!baseURL) {
144
+ throw new Error(
145
+ '`users` fixture requires a baseURL. Set it on your Playwright config (e.g. `use: { baseURL: "http://localhost:5173" }`) or via the webServer.url shortcut.'
146
+ );
147
+ }
148
+ const cleanups = [];
149
+ const usersFn = async (selector, options) => {
150
+ const accounts = Array.isArray(selector) ? selector.map((name) => findTestAccountByName(name)) : pickTestAccounts(selector, options);
151
+ const built = await Promise.all(
152
+ accounts.map((acct) => buildUser(browser, acct, baseURL))
153
+ );
154
+ for (const b of built) cleanups.push(b.cleanup);
155
+ return built.map((b) => b.user);
156
+ };
157
+ await use(usersFn);
158
+ for (const cleanup of cleanups) {
159
+ await cleanup().catch(() => {
160
+ });
161
+ }
162
+ }
163
+ });
164
+ export {
165
+ ensureStorageState,
166
+ expect,
167
+ findTestAccountByName,
168
+ getStatePathForEmail,
169
+ loadAllTestAccounts,
170
+ newSignedInContext,
171
+ pickTestAccounts,
172
+ readCachedState,
173
+ test
174
+ };
175
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing/fixtures.ts","../src/testing/accounts.ts","../src/testing/storage-state.ts"],"sourcesContent":["/**\n * Multi-user Playwright fixture for DeepSpace apps.\n *\n * Usage:\n *\n * import { test, expect } from 'deepspace/testing'\n *\n * test('A sends, B sees', async ({ users }) => {\n * const [a, b] = await users(2)\n * await a.page.goto('/chat')\n * await b.page.goto('/chat')\n * await a.page.getByTestId('message-input').fill('hi')\n * await a.page.getByTestId('send-message-btn').click()\n * await expect(b.page.getByText('hi')).toBeVisible()\n * })\n *\n * `users(N)` picks the first N test accounts from\n * `~/.deepspace/test-accounts.json` (created via\n * `deepspace test-accounts create`). `users(['Alice', 'Bob'])` picks\n * specific accounts by name.\n *\n * Each user gets a separate browser context with cached storageState\n * (per-account JSON in `~/.deepspace/playwright-states/`). Sign-in\n * happens once per account, not once per test, sidestepping Better\n * Auth's per-IP rate limit on `/api/auth/sign-in/email`.\n *\n * Contexts are auto-closed when the test finishes.\n */\n\nimport { test as baseTest, type Browser, type BrowserContext, type Page } from '@playwright/test'\nimport {\n type TestAccount,\n pickTestAccounts,\n findTestAccountByName,\n} from './accounts'\nimport { ensureStorageState } from './storage-state'\n\nexport interface MultiplayerUser {\n context: BrowserContext\n page: Page\n email: string\n name: string\n /** Test account user ID, if known from the accounts registry. */\n userId?: string\n}\n\n/**\n * Fixture function signature. Pass either a count (`users(2)`) or an\n * array of account names (`users(['Alice', 'Bob'])`). Returns one entry\n * per requested user.\n */\nexport type UsersFixture = (\n selector: number | string[],\n options?: { label?: string },\n) => Promise<MultiplayerUser[]>\n\ninterface MultiplayerFixtures {\n users: UsersFixture\n}\n\nasync function buildUser(\n browser: Browser,\n account: TestAccount,\n baseURL: string,\n): Promise<{ user: MultiplayerUser; cleanup: () => Promise<void> }> {\n const statePath = await ensureStorageState(browser, account, baseURL)\n const context = await browser.newContext({ storageState: statePath, baseURL })\n const page = await context.newPage()\n return {\n user: {\n context,\n page,\n email: account.email,\n name: account.name ?? account.email.split('@')[0],\n userId: account.userId,\n },\n cleanup: async () => {\n await context.close()\n },\n }\n}\n\nexport const test = baseTest.extend<MultiplayerFixtures>({\n users: async ({ browser, baseURL }, use) => {\n if (!baseURL) {\n throw new Error(\n '`users` fixture requires a baseURL. Set it on your Playwright config ' +\n '(e.g. `use: { baseURL: \"http://localhost:5173\" }`) or via the ' +\n 'webServer.url shortcut.',\n )\n }\n\n const cleanups: Array<() => Promise<void>> = []\n\n const usersFn: UsersFixture = async (selector, options) => {\n const accounts: TestAccount[] = Array.isArray(selector)\n ? selector.map((name) => findTestAccountByName(name))\n : pickTestAccounts(selector, options)\n\n const built = await Promise.all(\n accounts.map((acct) => buildUser(browser, acct, baseURL)),\n )\n for (const b of built) cleanups.push(b.cleanup)\n return built.map((b) => b.user)\n }\n\n await use(usersFn)\n\n // Tear down any contexts we created. Errors are swallowed — a test\n // failure shouldn't be masked by a cleanup error.\n for (const cleanup of cleanups) {\n await cleanup().catch(() => {})\n }\n },\n})\n\nexport { expect } from '@playwright/test'\n","/**\n * Account-credential plumbing for the testing module.\n *\n * Reads test accounts from `~/.deepspace/test-accounts.json` (the same\n * file `deepspace test-accounts create` writes). Each account has at\n * minimum `{email, password}`; `name` and `label` are optional.\n *\n * Used by the multi-user Playwright fixture in `./fixtures.ts` and is\n * also exported standalone in case suites want to do their own\n * orchestration.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport interface TestAccount {\n email: string\n password: string\n name?: string\n label?: string | null\n id?: string\n userId?: string\n createdAt?: number\n}\n\nconst ACCOUNTS_PATH = join(homedir(), '.deepspace', 'test-accounts.json')\n\n/**\n * Load all test accounts the developer has created. Returns an empty\n * array if the file doesn't exist yet.\n */\nexport function loadAllTestAccounts(): TestAccount[] {\n if (!existsSync(ACCOUNTS_PATH)) return []\n try {\n const raw = JSON.parse(readFileSync(ACCOUNTS_PATH, 'utf-8'))\n if (!Array.isArray(raw)) return []\n // Filter out any malformed entries (missing email or password). Keep\n // bare {email, password} rows so the file format stays forgiving.\n return raw.filter(\n (r) => r && typeof r.email === 'string' && typeof r.password === 'string',\n )\n } catch {\n return []\n }\n}\n\n/**\n * Pick `count` test accounts from the local registry, optionally\n * filtered by `label`. Order-stable: sorted by `createdAt` ascending so\n * the first test account you created is always the first one returned.\n *\n * Throws with a helpful message if not enough accounts exist.\n */\nexport function pickTestAccounts(\n count: number,\n options?: { label?: string },\n): TestAccount[] {\n const all = loadAllTestAccounts()\n const filtered = options?.label\n ? all.filter((a) => a.label === options.label)\n : all\n const sorted = filtered.slice().sort((a, b) => (a.createdAt ?? 0) - (b.createdAt ?? 0))\n\n if (sorted.length < count) {\n const labelHint = options?.label ? ` (label=\"${options.label}\")` : ''\n throw new Error(\n `Multiplayer test needs ${count} test accounts${labelHint}, but only ${sorted.length} ` +\n `are present in ${ACCOUNTS_PATH}. Create more with:\\n` +\n ` deepspace test-accounts create --email <name>@deepspace.test --password <pw> --name \"<name>\"${\n options?.label ? ` --label ${options.label}` : ''\n }`,\n )\n }\n\n return sorted.slice(0, count)\n}\n\n/**\n * Find a single account by name. Used by `users(['Alice', 'Bob'])`.\n * Throws if not found.\n */\nexport function findTestAccountByName(name: string): TestAccount {\n const all = loadAllTestAccounts()\n const match = all.find((a) => a.name === name)\n if (!match) {\n throw new Error(\n `No test account named \"${name}\" in ${ACCOUNTS_PATH}. Create with:\\n` +\n ` deepspace test-accounts create --email ${name.toLowerCase()}@deepspace.test --password <pw> --name \"${name}\"`,\n )\n }\n return match\n}\n","/**\n * Per-account `storageState` cache for Playwright.\n *\n * Better Auth applies a per-IP rate limit on `/api/auth/sign-in/email`\n * (~5 sign-ins / 60s / endpoint). A multiplayer suite that spins up\n * 5+ users per spec would hit the limit and start failing in non-obvious\n * ways. This module signs each account in *once*, persists the\n * resulting browser cookies + storage to disk, and reuses the file on\n * subsequent runs.\n *\n * Cache layout:\n * ~/.deepspace/playwright-states/<sha256(email)>.json\n *\n * Validity: a cached file is reused if Playwright successfully loads it\n * AND the resulting context produces a non-anonymous session on the\n * target app. If validation fails, we fall back to a fresh sign-in and\n * overwrite the cache.\n */\n\nimport { createHash } from 'node:crypto'\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { Browser, BrowserContext } from '@playwright/test'\n\nconst STATES_DIR = join(homedir(), '.deepspace', 'playwright-states')\n\n/** Default freshness window — re-sign-in if the cache is older than this. */\nconst DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000 // 7 days\n\nfunction statePathForEmail(email: string): string {\n const hash = createHash('sha256').update(email.trim().toLowerCase()).digest('hex').slice(0, 24)\n return join(STATES_DIR, `${hash}.json`)\n}\n\nfunction ensureStatesDir() {\n if (!existsSync(STATES_DIR)) mkdirSync(STATES_DIR, { recursive: true })\n}\n\n/** Returns true if a cache file exists and is younger than `maxAgeMs`. */\nfunction isCacheFresh(path: string, maxAgeMs: number): boolean {\n if (!existsSync(path)) return false\n try {\n const age = Date.now() - statSync(path).mtimeMs\n return age < maxAgeMs\n } catch {\n return false\n }\n}\n\n/**\n * Sign `account` in by POSTing `/api/auth/sign-in/email` against\n * `baseURL` and capturing the resulting cookies. Returns the path to the\n * Playwright `storageState` JSON file.\n *\n * The browser-driven approach is intentional: we want the cookies set\n * on the same origin Playwright contexts will load from, otherwise the\n * Set-Cookie domain attribute won't match.\n */\nasync function signInAndSaveState(\n browser: Browser,\n account: { email: string; password: string },\n baseURL: string,\n outPath: string,\n): Promise<string> {\n ensureStatesDir()\n const ctx = await browser.newContext({ baseURL })\n try {\n const page = await ctx.newPage()\n // Hit the app first so the origin is established (some auth plugins\n // require a same-origin Origin header on sign-in).\n await page.goto('/')\n const ok = await page.evaluate(\n async ({ email, password }: { email: string; password: string }) => {\n const res = await fetch('/api/auth/sign-in/email', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n })\n return res.ok\n },\n account,\n )\n if (!ok) {\n throw new Error(\n `Sign-in failed for ${account.email}. Check the password is current; ` +\n `if the account was deleted on the server, re-create with ` +\n `\\`deepspace test-accounts create\\`.`,\n )\n }\n await ctx.storageState({ path: outPath })\n return outPath\n } finally {\n await ctx.close()\n }\n}\n\nexport interface EnsureStorageStateOptions {\n /** Max age of a cached state file before we re-sign-in. Default 7 days. */\n maxAgeMs?: number\n /** Force a fresh sign-in even if the cache is fresh. */\n force?: boolean\n}\n\n/**\n * Ensure a Playwright `storageState` file exists for `account` and\n * return its path. Signs in once if the cache is missing, stale, or\n * `force: true`.\n */\nexport async function ensureStorageState(\n browser: Browser,\n account: { email: string; password: string },\n baseURL: string,\n options: EnsureStorageStateOptions = {},\n): Promise<string> {\n const path = statePathForEmail(account.email)\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_MAX_AGE_MS\n\n if (!options.force && isCacheFresh(path, maxAgeMs)) {\n return path\n }\n\n return signInAndSaveState(browser, account, baseURL, path)\n}\n\n/**\n * Convenience: open a fresh `BrowserContext` for `account` using the\n * cached storage state (signing in if needed). The caller is responsible\n * for closing the context.\n */\nexport async function newSignedInContext(\n browser: Browser,\n account: { email: string; password: string },\n baseURL: string,\n options: EnsureStorageStateOptions = {},\n): Promise<BrowserContext> {\n const statePath = await ensureStorageState(browser, account, baseURL, options)\n return browser.newContext({ storageState: statePath, baseURL })\n}\n\n/** Read a cached storageState file (mostly for debugging). */\nexport function readCachedState(email: string): unknown | null {\n const path = statePathForEmail(email)\n if (!existsSync(path)) return null\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n } catch {\n return null\n }\n}\n\n/** Where the cache for `email` lives. Useful for diagnostics. */\nexport function getStatePathForEmail(email: string): string {\n return statePathForEmail(email)\n}\n"],"mappings":"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","names":["existsSync","readFileSync","homedir","join"]}
package/dist/worker.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import * as Y from 'yjs';
2
- import * as _ai_sdk_openai_compatible from '@ai-sdk/openai-compatible';
3
- import * as _ai_sdk_openai from '@ai-sdk/openai';
4
- import * as _ai_sdk_anthropic from '@ai-sdk/anthropic';
2
+ import { LanguageModel, ModelMessage } from 'ai';
5
3
  import * as better_auth from 'better-auth';
6
4
  import * as better_auth_plugins from 'better-auth/plugins';
7
5
 
@@ -1653,6 +1651,16 @@ type DOBindings<T extends readonly DOManifestEntry[]> = {
1653
1651
  /** Default manifest for apps that don't declare one */
1654
1652
  declare const DEFAULT_DO_MANIFEST: DOManifest;
1655
1653
 
1654
+ /**
1655
+ * AI Chat Schemas
1656
+ *
1657
+ * Pre-built collection schemas for DO-backed AI chat history.
1658
+ * The worker is the only writer; the client reads via `useQuery`.
1659
+ */
1660
+
1661
+ declare const AI_CHATS_SCHEMA: CollectionSchema;
1662
+ declare const AI_MESSAGES_SCHEMA: CollectionSchema;
1663
+
1656
1664
  /**
1657
1665
  * Messaging Schemas
1658
1666
  *
@@ -2187,6 +2195,46 @@ declare function platformWorkerFetch(env: PlatformWorkerEnv, pathOrRequest: stri
2187
2195
  */
2188
2196
  declare function authWorkerFetch(env: AuthWorkerEnv, path: string, init?: RequestInit): Promise<Response>;
2189
2197
 
2198
+ /**
2199
+ * AI provider helpers — create Vercel AI SDK providers that route through
2200
+ * the DeepSpace API worker proxy for per-user billing.
2201
+ *
2202
+ * Supported providers: anthropic, openai, cerebras.
2203
+ *
2204
+ * The API worker can be reached in two ways:
2205
+ * - Service binding `env.API_WORKER` (Cloudflare Fetcher) — preferred in
2206
+ * production if the app has declared the binding in wrangler.toml.
2207
+ * - HTTPS URL `env.API_WORKER_URL` — used in local dev and in production
2208
+ * for apps that don't declare the binding. `deepspace dev` writes this
2209
+ * into `.dev.vars` automatically.
2210
+ *
2211
+ * Auth is automatic by default:
2212
+ * - For server-side autonomous calls (cron, DO alarms, background agents),
2213
+ * the helper reads the long-lived `env.APP_OWNER_JWT` minted at deploy
2214
+ * time (or by `deepspace dev` in local development) and uses it for the
2215
+ * proxy auth header. The owner is billed automatically via the JWT sub.
2216
+ * - For user-initiated calls (e.g. an `/api/ai/chat` route handling a
2217
+ * browser request), pass `options.authToken` explicitly with the user's
2218
+ * own JWT so the call is billed to the user.
2219
+ *
2220
+ * Usage:
2221
+ *
2222
+ * // Server-side autonomous — no auth config needed
2223
+ * import { createDeepSpaceAI } from 'deepspace/worker'
2224
+ * const cerebras = createDeepSpaceAI(env, 'cerebras')
2225
+ * const result = await generateText({ model: cerebras('llama-3.3-70b'), ... })
2226
+ *
2227
+ * // User-initiated (inside a request handler)
2228
+ * const jwt = c.req.header('Authorization')!.slice(7)
2229
+ * const anthropic = createDeepSpaceAI(c.env, 'anthropic', { authToken: jwt })
2230
+ */
2231
+
2232
+ /**
2233
+ * Model factory: `(modelId) => LanguageModel`. The explicit return type
2234
+ * keeps tsup's DTS build from leaking unportable `.pnpm/@ai-sdk+provider/...`
2235
+ * paths into the published `dist/index.d.ts`.
2236
+ */
2237
+ type DeepSpaceModelFactory = (modelId: string) => LanguageModel;
2190
2238
  type Provider = 'anthropic' | 'openai' | 'cerebras';
2191
2239
  interface DeepSpaceAIEnv extends ApiWorkerEnv {
2192
2240
  /**
@@ -2215,7 +2263,176 @@ interface DeepSpaceAIOptions {
2215
2263
  * (explicit or `env.APP_OWNER_JWT`) automatically. Throws a clear error if
2216
2264
  * either is unconfigured.
2217
2265
  */
2218
- declare function createDeepSpaceAI(env: DeepSpaceAIEnv, provider: Provider, options?: DeepSpaceAIOptions): _ai_sdk_anthropic.AnthropicProvider | _ai_sdk_openai.OpenAIProvider | _ai_sdk_openai_compatible.OpenAICompatibleProvider<string, string, string, string>;
2266
+ declare function createDeepSpaceAI(env: DeepSpaceAIEnv, provider: Provider, options?: DeepSpaceAIOptions): DeepSpaceModelFactory;
2267
+
2268
+ /**
2269
+ * Chat context pipeline — keeps the per-request payload to the LLM bounded.
2270
+ *
2271
+ * `prepareMessagesWithCompaction` runs before `streamText`: truncate old tool
2272
+ * results, apply a cached summary if available, otherwise summarize the older
2273
+ * half of history when over budget. Falls back to a sliding window if
2274
+ * summarization fails. `capToolResultSize` caps individual tool calls.
2275
+ */
2276
+
2277
+ interface ChatTurn {
2278
+ id?: string;
2279
+ role: 'user' | 'assistant' | 'system';
2280
+ content: string;
2281
+ parts?: unknown[];
2282
+ }
2283
+ type Summarizer = (messages: ChatTurn[]) => Promise<string>;
2284
+ interface ChatContextConfig {
2285
+ contextBudget: number;
2286
+ toolResultCap: number;
2287
+ keepRecentToolResults: number;
2288
+ minKept: number;
2289
+ }
2290
+ declare const DEFAULT_CONTEXT_CONFIG: ChatContextConfig;
2291
+ declare function totalChars(messages: ChatTurn[]): number;
2292
+ /**
2293
+ * Replace older tool-result payloads with a small marker. Keeps the last
2294
+ * `keepRecent` tool results intact. Errors (`success: false`) are preserved —
2295
+ * they're small and the agent needs them for reasoning.
2296
+ */
2297
+ declare function truncateOldToolResults(messages: ChatTurn[], keepRecent: number): ChatTurn[];
2298
+ /**
2299
+ * Drop oldest messages until total character count is under `charCap`,
2300
+ * never going below `minKept` messages. System messages (e.g. compaction
2301
+ * summaries) are pinned — dropping them would discard the most condensed
2302
+ * context first.
2303
+ */
2304
+ declare function applySlidingWindow(messages: ChatTurn[], charCap: number, minKept: number): ChatTurn[];
2305
+ /**
2306
+ * Replace oversized tool results with an error telling the agent to narrow
2307
+ * its query. Keeps a small preview so the agent can see what it got.
2308
+ */
2309
+ declare function capToolResultSize(result: unknown, byteCap: number): unknown;
2310
+ /**
2311
+ * Convert persisted ChatTurns into AI SDK ModelMessages.
2312
+ *
2313
+ * Persisted assistant rows store `parts` in UI shape (text + tool-invocation,
2314
+ * each invocation carrying its own `result`). When fed back to the LLM, the
2315
+ * shape MUST match the original multi-step flow: an assistant message
2316
+ * containing a `tool_use` block must end with that block, the IMMEDIATELY
2317
+ * NEXT message must be a tool/user message containing the matching
2318
+ * `tool_result`, and any text the model produced AFTER seeing the tool
2319
+ * result belongs in a SEPARATE assistant message after the tool message.
2320
+ *
2321
+ * Anthropic specifically rejects an assistant message of the form
2322
+ * `[text, tool_use, text]` — the trailing text breaks its `tool_use` →
2323
+ * `tool_result` pairing check. So we walk the parts in order and split at
2324
+ * each tool-invocation boundary, emitting a fresh assistant + tool pair per
2325
+ * tool call, and a final trailing assistant message for any post-tool text.
2326
+ *
2327
+ * Tool-invocation entries with `state: 'call'` (no result — typically an
2328
+ * interrupted stream) are dropped on both sides.
2329
+ */
2330
+ declare function turnsToCoreMessages(turns: ChatTurn[]): ModelMessage[];
2331
+ /**
2332
+ * Convert AI SDK response messages into our persisted UI shape (text +
2333
+ * tool-invocation parts), pairing each assistant tool-call with its tool-
2334
+ * result from the following tool message. Order is chronological.
2335
+ *
2336
+ * Inverse of `turnsToCoreMessages`: takes the v5 `ModelMessage[]` returned
2337
+ * from `streamText`'s `onFinish` and produces the flat `parts` array we
2338
+ * persist on `ai-messages` rows. Reads `c.input` / `c.output` (v5 wire
2339
+ * names) and unwraps `output`'s tagged-union via `unwrapToolOutput`.
2340
+ */
2341
+ declare function buildUiParts(responseMessages: ModelMessage[]): unknown[];
2342
+ /**
2343
+ * Unwrap v5's tagged tool-result `output` to the flat shape we persist.
2344
+ * Errors get remapped to `{ success: false, error }` because
2345
+ * `truncateOldToolResults` preserves entries with that shape across turns —
2346
+ * without the remap, error context would get truncated like a normal result.
2347
+ */
2348
+ declare function unwrapToolOutput(output: unknown): unknown;
2349
+ /**
2350
+ * Pre-stream pipeline with compaction.
2351
+ *
2352
+ * 1. Truncate old tool results.
2353
+ * 2. If a cached summary covers a known message id, replace prior turns with it.
2354
+ * 3. If still over budget, summarize the older half of `working` and return a
2355
+ * `newSummary` for persistence — runs even after cached-summary application
2356
+ * so a long-running chat can re-summarize on subsequent turns.
2357
+ * 4. On summarizer error or missing ids, fall back to a sliding window
2358
+ * (which preserves system messages — see `applySlidingWindow`).
2359
+ */
2360
+ declare function prepareMessagesWithCompaction(messages: ChatTurn[], config: ChatContextConfig, options: {
2361
+ summarizer: Summarizer;
2362
+ cachedSummary?: {
2363
+ text: string;
2364
+ throughId: string;
2365
+ };
2366
+ }): Promise<{
2367
+ messages: ChatTurn[];
2368
+ newSummary?: {
2369
+ text: string;
2370
+ throughId: string;
2371
+ };
2372
+ }>;
2373
+ /**
2374
+ * Build a default summarizer backed by Claude Haiku.
2375
+ *
2376
+ * Billing: defaults to the app owner via `APP_OWNER_JWT` — summarization is
2377
+ * usually infrastructure, not user work. Pass `{ authToken }` to bill a
2378
+ * specific user (e.g. the caller's JWT) instead.
2379
+ */
2380
+ declare function makeDefaultSummarizer(env: DeepSpaceAIEnv, options?: {
2381
+ authToken?: string;
2382
+ }): Summarizer;
2383
+
2384
+ /**
2385
+ * Chat history helpers — wrap RecordRoom's tools API for ai-chats / ai-messages.
2386
+ *
2387
+ * Trust model: every helper sends `X-App-Action: 'true'`, which bypasses
2388
+ * RecordRoom's per-record RBAC. The worker is the trust boundary, not
2389
+ * RecordRoom. Callers MUST verify ownership before invoking write helpers
2390
+ * (`updateChat`, `appendMessage`, `deleteChatCascade`); the worker's
2391
+ * `/api/ai/chat`, `PATCH /api/ai/chats/:id`, and `DELETE /api/ai/chats/:id`
2392
+ * routes do this via a `getChat()` precheck that 404s when the row is
2393
+ * missing or owned by another user. Read helpers (`getChat`, `loadMessages`)
2394
+ * filter by `chatId` against userBound rows, so cross-user reads return
2395
+ * empty — but new consumers should still consider an explicit ownership
2396
+ * check before exposing data.
2397
+ *
2398
+ * The tools API returns records as `{ recordId, data, createdAt, updatedAt }`
2399
+ * envelopes; helpers below flatten them into ChatRow / ChatMessageRow.
2400
+ */
2401
+ type ChatRow = {
2402
+ id: string;
2403
+ userId: string;
2404
+ title: string;
2405
+ model?: string;
2406
+ compactedSummary?: string;
2407
+ compactedThroughId?: string;
2408
+ createdAt: string;
2409
+ updatedAt: string;
2410
+ };
2411
+ type ChatMessageRow = {
2412
+ id: string;
2413
+ chatId: string;
2414
+ userId: string;
2415
+ role: 'user' | 'assistant' | 'system';
2416
+ content: string;
2417
+ parts?: unknown[];
2418
+ createdAt: string;
2419
+ };
2420
+ declare function getChat(stub: DurableObjectStub, chatId: string, userId: string): Promise<ChatRow | null>;
2421
+ declare function createChat(stub: DurableObjectStub, userId: string, opts?: {
2422
+ title?: string;
2423
+ model?: string;
2424
+ }): Promise<ChatRow>;
2425
+ declare function updateChat(stub: DurableObjectStub, chatId: string, userId: string, patch: Partial<Pick<ChatRow, 'title' | 'model' | 'compactedSummary' | 'compactedThroughId'>>): Promise<void>;
2426
+ declare function deleteChatCascade(stub: DurableObjectStub, chatId: string, userId: string): Promise<void>;
2427
+ declare function loadMessages(stub: DurableObjectStub, chatId: string, userId: string): Promise<ChatMessageRow[]>;
2428
+ declare function appendMessage(stub: DurableObjectStub, msg: {
2429
+ id: string;
2430
+ chatId: string;
2431
+ userId: string;
2432
+ role: 'user' | 'assistant' | 'system';
2433
+ content: string;
2434
+ parts?: unknown[];
2435
+ }): Promise<void>;
2219
2436
 
2220
2437
  /**
2221
2438
  * Auth types for the DeepSpace SDK.
@@ -3170,4 +3387,4 @@ type DeepSpaceAuth = ReturnType<typeof createDeepSpaceAuth>;
3170
3387
  /** Collections that bypass schema checks (permissive access) */
3171
3388
  declare const SYSTEM_COLLECTIONS: Set<string>;
3172
3389
 
3173
- export { type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AuthWorkerEnv, Awareness, type AwarenessState, type AwarenessStates, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, type BaseMessage, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, CanvasRoom, type CanvasShape, type ClientMessage, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ConnectionAttachment, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, DEFAULT_DO_MANIFEST, DEFAULT_MAX_SKEW_MS, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GameInput, GameRoom, type GameRoomConfig, type GlobalDOType, type HandlerContext, type InternalSignature, type JwtClaims, type JwtVerifierConfig, MESSAGES_SCHEMA, MSG, MSG_AWARENESS, MSG_SYNC, MSG_SYNC_STEP1, MSG_SYNC_STEP2, MSG_SYNC_UPDATE, MSG_YJS_AWARENESS, MSG_YJS_SYNC, type MessageHandlers, type MsgType, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlatformWorkerEnv, type Player, type PrefixResult, type PresencePeer, PresenceRoom, type ProtocolMessage, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, RESERVED_COLLECTION_NAMES, ROLE_ADMIN, ROLE_ANONYMOUS, ROLE_DEFAULT, RecordRoom, type RecordRoomConfig, type ResolvedColumn, type ResolvedPermission, type RolePermissions, SYSTEM_COLLECTIONS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ServerMessage, type SharedConnection, type SignInternalPayloadInput, type StoredRecord, type SyncResult, type TokenDebugInfo, type ToolResult, type ToolSchema, USERS_COLUMNS, type User, type UserAttachment, VOTING_SCHEMAS, type VerifiedAuth, type VerifyInternalSignatureInput, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, YjsRoom, analyzePermissions, apiWorkerFetch, authWorkerFetch, buildCronContext, buildInternalPayload, buildTableSelect, canCreate, canDelete, canRead, canUpdate, checkFieldPermissions, clientBuild, coerceValue, collectionTableName, columnId, computeHmacHex, createDecoder, createDeepSpaceAI, createDeepSpaceAuth, createEncoder, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, dispatch, encode, encodeAwarenessMessage, encodeSyncStep1, encodeSyncStep2, encodeUpdate, getGlobalDOSchemas, getGlobalDOType, getMessageType, getRolePermissions, handleAwarenessMessage, handleSyncMessage, hasContent, isOwner, noopPermissionContext, platformWorkerFetch, readVarUint, readVarUint8Array, resolveColumn, rowToData, serverBuild, signInternalPayload, timingSafeEqualHex, toUint8Array, verifyInternalSignature, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema, writeVarUint, writeVarUint8Array };
3390
+ export { AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AuthWorkerEnv, Awareness, type AwarenessState, type AwarenessStates, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, type BaseMessage, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type ClientMessage, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ConnectionAttachment, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DEFAULT_MAX_SKEW_MS, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GameInput, GameRoom, type GameRoomConfig, type GlobalDOType, type HandlerContext, type InternalSignature, type JwtClaims, type JwtVerifierConfig, MESSAGES_SCHEMA, MSG, MSG_AWARENESS, MSG_SYNC, MSG_SYNC_STEP1, MSG_SYNC_STEP2, MSG_SYNC_UPDATE, MSG_YJS_AWARENESS, MSG_YJS_SYNC, type MessageHandlers, type MsgType, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlatformWorkerEnv, type Player, type PrefixResult, type PresencePeer, PresenceRoom, type ProtocolMessage, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, RESERVED_COLLECTION_NAMES, ROLE_ADMIN, ROLE_ANONYMOUS, ROLE_DEFAULT, RecordRoom, type RecordRoomConfig, type ResolvedColumn, type ResolvedPermission, type RolePermissions, SYSTEM_COLLECTIONS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ServerMessage, type SharedConnection, type SignInternalPayloadInput, type StoredRecord, type Summarizer, type SyncResult, type TokenDebugInfo, type ToolResult, type ToolSchema, USERS_COLUMNS, type User, type UserAttachment, VOTING_SCHEMAS, type VerifiedAuth, type VerifyInternalSignatureInput, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, YjsRoom, analyzePermissions, apiWorkerFetch, appendMessage, applySlidingWindow, authWorkerFetch, buildCronContext, buildInternalPayload, buildTableSelect, buildUiParts, canCreate, canDelete, canRead, canUpdate, capToolResultSize, checkFieldPermissions, clientBuild, coerceValue, collectionTableName, columnId, computeHmacHex, createChat, createDecoder, createDeepSpaceAI, createDeepSpaceAuth, createEncoder, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deleteChatCascade, dispatch, encode, encodeAwarenessMessage, encodeSyncStep1, encodeSyncStep2, encodeUpdate, getChat, getGlobalDOSchemas, getGlobalDOType, getMessageType, getRolePermissions, handleAwarenessMessage, handleSyncMessage, hasContent, isOwner, loadMessages, makeDefaultSummarizer, noopPermissionContext, platformWorkerFetch, prepareMessagesWithCompaction, readVarUint, readVarUint8Array, resolveColumn, rowToData, serverBuild, signInternalPayload, timingSafeEqualHex, toUint8Array, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, verifyInternalSignature, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema, writeVarUint, writeVarUint8Array };