wizards 0.2.2 → 0.2.3

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.
Files changed (75) hide show
  1. package/apps/runtime/dist/app.js +44 -0
  2. package/apps/runtime/dist/auth/account.js +16 -2
  3. package/apps/runtime/dist/auth/index.js +14 -1
  4. package/apps/runtime/dist/connectors/external.js +5 -0
  5. package/apps/runtime/dist/db/control-schema.js +12 -3
  6. package/apps/runtime/dist/db/migrations/control/0005_chilly_oracle.sql +1 -0
  7. package/apps/runtime/dist/db/migrations/control/0006_sleepy_mojo.sql +1 -0
  8. package/apps/runtime/dist/db/migrations/control/meta/0005_snapshot.json +358 -0
  9. package/apps/runtime/dist/db/migrations/control/meta/0006_snapshot.json +365 -0
  10. package/apps/runtime/dist/db/migrations/control/meta/_journal.json +14 -0
  11. package/apps/runtime/dist/db/migrations/tenant/0005_reflective_forgotten_one.sql +2 -0
  12. package/apps/runtime/dist/db/migrations/tenant/meta/0005_snapshot.json +1659 -0
  13. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +7 -0
  14. package/apps/runtime/dist/db/schema.js +6 -0
  15. package/apps/runtime/dist/engine/asks.js +2 -0
  16. package/apps/runtime/dist/engine/push.js +58 -0
  17. package/apps/runtime/dist/engine/runner.js +6 -0
  18. package/apps/runtime/dist/env.js +13 -0
  19. package/apps/runtime/dist/limits.js +21 -0
  20. package/apps/runtime/dist/manage.js +16 -3
  21. package/apps/runtime/dist/mcp/tools.js +4 -2
  22. package/apps/runtime/dist/routes/api.js +96 -6
  23. package/apps/runtime/dist/routes/runs.js +68 -2
  24. package/apps/runtime/dist/routes/studio.js +79 -11
  25. package/apps/runtime/dist/services/access.js +62 -0
  26. package/apps/runtime/dist/services/architect.js +3 -2
  27. package/apps/runtime/dist/services/cloud.js +241 -39
  28. package/apps/runtime/dist/services/errors.js +1 -0
  29. package/apps/runtime/dist/services/files.js +3 -3
  30. package/apps/runtime/dist/services/project-files.js +6 -0
  31. package/apps/runtime/dist/services/projects.js +38 -14
  32. package/apps/runtime/dist/services/spaces.js +400 -0
  33. package/apps/runtime/dist/services/wizards.js +19 -8
  34. package/apps/runtime/dist/tenants/control.js +47 -0
  35. package/apps/web/dist/assets/{ChangelogDialog-4HCt88rf.js → ChangelogDialog-CbZBUMRu.js} +1 -1
  36. package/apps/web/dist/assets/ChatPanel-zurtfj6A.js +1 -0
  37. package/apps/web/dist/assets/{CreditsDialog-D3fZRqXH.js → CreditsDialog-BewZHZTR.js} +1 -1
  38. package/apps/web/dist/assets/EditorPage-B7ZOoW5h.js +2 -0
  39. package/apps/web/dist/assets/{FlowPreview-CjUK5046.js → FlowPreview-DHrhPps0.js} +1 -1
  40. package/apps/web/dist/assets/HomePage-CBvWxXsq.js +1 -0
  41. package/apps/web/dist/assets/ImportWizard-CKjVJMaG.js +1 -0
  42. package/apps/web/dist/assets/{LocalRuntime-DupxjXff.js → LocalRuntime-Brkvbzzg.js} +10 -10
  43. package/apps/web/dist/assets/NewWizardPage-B3XePMlp.js +2 -0
  44. package/apps/web/dist/assets/PublicRunner-Bn1g6HG9.js +1 -0
  45. package/apps/web/dist/assets/RunnerView-CO1Nk3jn.js +2 -0
  46. package/apps/web/dist/assets/SettingsPage-BIY4kHZl.js +2 -0
  47. package/apps/web/dist/assets/{SetupPage-xiqJMR0J.js → SetupPage-BvLwZH9i.js} +1 -1
  48. package/apps/web/dist/assets/{SharePage-C8B9BUSU.js → SharePage-CDESJ11B.js} +1 -1
  49. package/apps/web/dist/assets/{api-KMi35npD.js → api-9sHuNTkp.js} +1 -1
  50. package/apps/web/dist/assets/changelog-Cto0j5-V.js +1 -0
  51. package/apps/web/dist/assets/index-CIwJmOjo.css +1 -0
  52. package/apps/web/dist/assets/{index-2Ktgo6f1.js → index-VsRgvimv.js} +3 -3
  53. package/apps/web/dist/assets/{meta-4R1Lnr25.js → meta-B4mZqEso.js} +1 -1
  54. package/apps/web/dist/assets/oss-credits-Hu4LieLA.js +1 -0
  55. package/apps/web/dist/assets/outputs-boPx5ngv.js +69 -0
  56. package/apps/web/dist/assets/{session-B6-6VomQ.js → session-CJGuo1Tv.js} +1 -1
  57. package/apps/web/dist/assets/type-BMJpS6_D.js +1 -0
  58. package/apps/web/dist/assets/ui-iTYHqwvY.js +1 -0
  59. package/apps/web/dist/index.html +5 -5
  60. package/apps/web/dist/mcp/flow.html +54 -54
  61. package/package.json +1 -1
  62. package/apps/web/dist/assets/ChatPanel-B91fTrzg.js +0 -1
  63. package/apps/web/dist/assets/EditorPage-ZZjb9mGV.js +0 -2
  64. package/apps/web/dist/assets/HomePage-Cn5TCZk7.js +0 -1
  65. package/apps/web/dist/assets/ImportWizard-DiV62Uno.js +0 -1
  66. package/apps/web/dist/assets/NewWizardPage-Bz3PIQGp.js +0 -2
  67. package/apps/web/dist/assets/PublicRunner-Axs1zwqe.js +0 -1
  68. package/apps/web/dist/assets/RunnerView-Bhv6RNME.js +0 -2
  69. package/apps/web/dist/assets/SettingsPage-in_RmI8i.js +0 -2
  70. package/apps/web/dist/assets/changelog-C2LDEzLQ.js +0 -1
  71. package/apps/web/dist/assets/index-B9YVjvVY.css +0 -1
  72. package/apps/web/dist/assets/oss-credits-roB62QJu.js +0 -1
  73. package/apps/web/dist/assets/outputs-Dhqtf-SA.js +0 -69
  74. package/apps/web/dist/assets/type-Bj9H3eOK.js +0 -1
  75. package/apps/web/dist/assets/ui-Cs6lpsmj.js +0 -1
@@ -4,6 +4,7 @@ import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { serveStatic } from "@hono/node-server/serve-static";
6
6
  import { Hono } from "hono";
7
+ import { bodyLimit } from "hono/body-limit";
7
8
  import { HTTPException } from "hono/http-exception";
8
9
  import { ZodError } from "zod";
9
10
  import { authRoutes, principalOf } from "./auth/index.js";
@@ -114,6 +115,38 @@ app.get("/.well-known/oauth-protected-resource/*", async (c) => {
114
115
  bearer_methods_supported: ["header"],
115
116
  });
116
117
  });
118
+ // The mobile app opens this runtime's wizard and result links (Universal Links, App Links).
119
+ app.get("/.well-known/apple-app-site-association", (c) => {
120
+ if (!env.mobile.iosAppIds.length) {
121
+ return c.notFound();
122
+ }
123
+ const paths = [`${basePath}/w/*`, `${basePath}/s/*`];
124
+ return c.json({
125
+ applinks: {
126
+ details: [
127
+ {
128
+ appIDs: env.mobile.iosAppIds,
129
+ components: paths.map((path) => ({ "/": path })),
130
+ },
131
+ ],
132
+ },
133
+ });
134
+ });
135
+ app.get("/.well-known/assetlinks.json", (c) => {
136
+ if (!env.mobile.androidCertSha256.length) {
137
+ return c.notFound();
138
+ }
139
+ return c.json([
140
+ {
141
+ relation: ["delegate_permission/common.handle_all_urls"],
142
+ target: {
143
+ namespace: "android_app",
144
+ package_name: env.mobile.androidPackage,
145
+ sha256_cert_fingerprints: env.mobile.androidCertSha256,
146
+ },
147
+ },
148
+ ]);
149
+ });
117
150
  /** Studio requests act as the signed-in person, inside that person's tenant. */
118
151
  app.use("/api/studio/*", async (c, next) => {
119
152
  const user = await principalOf(c);
@@ -130,6 +163,17 @@ const mcp = mcpHandler();
130
163
  app.on(["GET", "POST", "DELETE"], "/api/mcp", (c) => mcp(c.req.raw));
131
164
  // The tools of one model call, for the installed Claude Code while it answers that call.
132
165
  app.on(["GET", "POST", "DELETE"], "/api/mcp/bridge/:token", (c) => bridgeRequest(c.req.param("token"), c.req.raw));
166
+ // What visitors send is read before anyone is known: a body is taken only up to a size. A page's
167
+ // answers are text; an upload is a photo, a recording or a clip from a phone (routes/delivery.ts).
168
+ const tooLarge = (max) => bodyLimit({
169
+ maxSize: max,
170
+ onError: (c) => c.json({ error: "Das ist zu groß.", code: "too_large" }, 413),
171
+ });
172
+ const answers = tooLarge(4 * 1024 * 1024);
173
+ const upload = tooLarge(48 * 1024 * 1024);
174
+ app.use("/api/public/*", answers);
175
+ app.use("/api/shares/*", answers);
176
+ app.use("/api/runs/*", (c, next) => /\/uploads$/.test(c.req.path) ? upload(c, next) : answers(c, next));
133
177
  app.route("/api/studio/wizards", wizardStream);
134
178
  app.route("/api/studio/marketplace", marketplaceStudio);
135
179
  app.route("/api/studio/plugins", pluginRoutes);
@@ -16,7 +16,11 @@ const SCOPE = "openid profile email offline_access wizards:read wizards:write wi
16
16
  function redirectUri() {
17
17
  return `http://127.0.0.1:${env.port}/api/auth/callback`;
18
18
  }
19
- export async function startLink() {
19
+ /**
20
+ * The address that links an account. `signup`: the person has none yet — the account's sign-up
21
+ * page takes the invitation code (`code` fills it in) and goes on to the same sign-in.
22
+ */
23
+ export async function startLink(options = {}) {
20
24
  const d = await discovery(env.local.accountUrl);
21
25
  const verifier = randomBytes(32).toString("base64url");
22
26
  const state = { verifier, redirect: redirectUri(), exp: Date.now() + 15 * 60_000 };
@@ -31,7 +35,17 @@ export async function startLink() {
31
35
  code_challenge_method: "S256",
32
36
  state: seal(state),
33
37
  }).toString();
34
- return url.toString();
38
+ if (!options.signup) {
39
+ return url.toString();
40
+ }
41
+ const signUp = new URL("/sign-up", env.local.accountUrl);
42
+ const code = options.code?.trim();
43
+ if (code) {
44
+ signUp.searchParams.set("code", code);
45
+ }
46
+ // The sign-up page goes on only to a path of its own origin.
47
+ signUp.searchParams.set("next", url.pathname + url.search);
48
+ return signUp.toString();
35
49
  }
36
50
  let cached = null;
37
51
  async function keep(tokens) {
@@ -4,7 +4,7 @@ import { eq, lt } from "drizzle-orm";
4
4
  import { Hono } from "hono";
5
5
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
6
6
  import { nanoid } from "nanoid";
7
- import { control, controlDb } from "../db/client.js";
7
+ import { control, controlDb, withTenant } from "../db/client.js";
8
8
  import { basePath, env } from "../env.js";
9
9
  import { discovery, managed, tokenRequest, verifyToken, } from "../manage.js";
10
10
  import { seal, unseal } from "../secrets/crypto.js";
@@ -24,6 +24,17 @@ let accessKey = managed
24
24
  export function localEntryUrl() {
25
25
  return accessKey ? `${env.appUrl}/api/local/enter?k=${accessKey}` : null;
26
26
  }
27
+ /** Sends everything published here to the cloud of the account that was just linked. */
28
+ async function firstSync() {
29
+ try {
30
+ // Loaded here: the services read the session this module makes.
31
+ const { syncAllToCloud } = await import("../services/cloud.js");
32
+ await withTenant(LOCAL_TENANT, () => syncAllToCloud(localUser().id));
33
+ }
34
+ catch (err) {
35
+ console.error("[cloud] first sync failed:", err);
36
+ }
37
+ }
27
38
  const localUser = () => ({
28
39
  id: "local",
29
40
  tenantId: LOCAL_TENANT,
@@ -265,6 +276,8 @@ export const authRoutes = new Hono()
265
276
  }
266
277
  try {
267
278
  await finishLink(code, rawState);
279
+ // What is published here goes to the account's cloud, from now on and once for all there is.
280
+ void firstSync();
268
281
  return c.html(closePage("Angemeldet. Du kannst dieses Fenster schließen."));
269
282
  }
270
283
  catch (err) {
@@ -9,6 +9,7 @@ import { discoverImportableSources, discoverOAuthFacts, registryDiscover, regist
9
9
  import { resolveRegistrySource } from "../engenty/connections-external/registry-source.js";
10
10
  import { encryptToken } from "../engenty/shims/connections-sdk.js";
11
11
  import { env } from "../env.js";
12
+ import { requireWritableProject } from "../services/access.js";
12
13
  import { ServiceError } from "../services/errors.js";
13
14
  import { BUILTIN_CONNECTORS, builtinConnector, missingSetup, usable } from "./builtin.js";
14
15
  /**
@@ -270,6 +271,7 @@ export async function resolveConnector(projectId, id) {
270
271
  : null;
271
272
  }
272
273
  export async function importConnector(userId, projectId, input) {
274
+ await requireWritableProject(projectId);
273
275
  if (await load(projectId, input.id)) {
274
276
  throw new ServiceError("invalid", `Connector "${input.id}" already exists in this project.`);
275
277
  }
@@ -311,6 +313,7 @@ export async function importConnector(userId, projectId, input) {
311
313
  * an MCP server is the service's own, curated set of actions.
312
314
  */
313
315
  export async function importFromRegistry(userId, projectId, input) {
316
+ await requireWritableProject(projectId);
314
317
  const service = await registryService(input.domain);
315
318
  const order = input.kind ? [input.kind] : ["mcp", "openapi"];
316
319
  const source = order
@@ -334,6 +337,7 @@ export async function importFromRegistry(userId, projectId, input) {
334
337
  });
335
338
  }
336
339
  export async function removeConnector(projectId, id) {
340
+ await requireWritableProject(projectId);
337
341
  await db.delete(schema.projectConnector).where(where(projectId, id));
338
342
  }
339
343
  /**
@@ -341,6 +345,7 @@ export async function removeConnector(projectId, id) {
341
345
  * tools to a signed-in account needs that account's token.
342
346
  */
343
347
  export async function refreshConnector(projectId, id, accessToken) {
348
+ await requireWritableProject(projectId);
344
349
  const record = await load(projectId, id);
345
350
  if (!record) {
346
351
  throw new ServiceError("not_found", "No such connector.");
@@ -17,11 +17,14 @@ export const tenant = sqliteTable("tenant", {
17
17
  export const link = sqliteTable("link", {
18
18
  token: text("token").primaryKey(),
19
19
  tenantId: text("tenant_id").notNull(),
20
- /** `wizard` = a share link `/w/<token>`, `result` = a shared result `/s/<token>`, `logo` = a brand logo. */
21
- kind: text("kind", { enum: ["wizard", "result", "logo"] }).notNull(),
20
+ /**
21
+ * `wizard` = a share link `/w/<token>`, `result` = a shared result `/s/<token>`, `logo` = a
22
+ * brand logo, `code` = a wizard's ID to type in (its `ref` is the wizard's share token).
23
+ */
24
+ kind: text("kind", { enum: ["wizard", "result", "logo", "code"] }).notNull(),
22
25
  ref: text("ref").notNull(),
23
26
  createdAt: createdAt(),
24
- }, (t) => [index("link_tenant").on(t.tenantId)]);
27
+ }, (t) => [index("link_tenant").on(t.tenantId), index("link_ref").on(t.kind, t.ref)]);
25
28
  /**
26
29
  * One row per run: finds the run's tenant, counts a visitor's runs across all wizards, and
27
30
  * marks the runs that are working (resumed after a restart, counted against the tenant's limit).
@@ -32,6 +35,12 @@ export const runIndex = sqliteTable("run_index", {
32
35
  visitorId: text("visitor_id"),
33
36
  ipHash: text("ip_hash"),
34
37
  active: integer("active", { mode: "boolean" }).notNull().default(false),
38
+ /**
39
+ * The mobile app's device for push, set by the app for this run (`POST /api/runs/:id/notify`):
40
+ * `{ token, platform: "ios" | "android", lang }`. Told through the Manage-App when the run is
41
+ * done, failed or waits for the person.
42
+ */
43
+ push: text("push", { mode: "json" }).$type(),
35
44
  createdAt: createdAt(),
36
45
  }, (t) => [
37
46
  index("run_index_visitor").on(t.visitorId, t.createdAt),
@@ -0,0 +1 @@
1
+ CREATE INDEX `link_ref` ON `link` (`kind`,`ref`);
@@ -0,0 +1 @@
1
+ ALTER TABLE `run_index` ADD `push` text;
@@ -0,0 +1,358 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "52cfe26f-c51b-49b6-abf7-21417f611007",
5
+ "prevId": "ded1f6e4-eee2-4ef4-99b7-171041cbe221",
6
+ "tables": {
7
+ "link": {
8
+ "name": "link",
9
+ "columns": {
10
+ "token": {
11
+ "name": "token",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "tenant_id": {
18
+ "name": "tenant_id",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "kind": {
25
+ "name": "kind",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "ref": {
32
+ "name": "ref",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "created_at": {
39
+ "name": "created_at",
40
+ "type": "integer",
41
+ "primaryKey": false,
42
+ "notNull": true,
43
+ "autoincrement": false,
44
+ "default": "(unixepoch() * 1000)"
45
+ }
46
+ },
47
+ "indexes": {
48
+ "link_tenant": {
49
+ "name": "link_tenant",
50
+ "columns": [
51
+ "tenant_id"
52
+ ],
53
+ "isUnique": false
54
+ },
55
+ "link_ref": {
56
+ "name": "link_ref",
57
+ "columns": [
58
+ "kind",
59
+ "ref"
60
+ ],
61
+ "isUnique": false
62
+ }
63
+ },
64
+ "foreignKeys": {},
65
+ "compositePrimaryKeys": {},
66
+ "uniqueConstraints": {},
67
+ "checkConstraints": {}
68
+ },
69
+ "marketplace_cache": {
70
+ "name": "marketplace_cache",
71
+ "columns": {
72
+ "id": {
73
+ "name": "id",
74
+ "type": "text",
75
+ "primaryKey": true,
76
+ "notNull": true,
77
+ "autoincrement": false
78
+ },
79
+ "hash": {
80
+ "name": "hash",
81
+ "type": "text",
82
+ "primaryKey": false,
83
+ "notNull": true,
84
+ "autoincrement": false
85
+ },
86
+ "entry": {
87
+ "name": "entry",
88
+ "type": "text",
89
+ "primaryKey": false,
90
+ "notNull": true,
91
+ "autoincrement": false
92
+ },
93
+ "fetched_at": {
94
+ "name": "fetched_at",
95
+ "type": "integer",
96
+ "primaryKey": false,
97
+ "notNull": true,
98
+ "autoincrement": false,
99
+ "default": "(unixepoch() * 1000)"
100
+ }
101
+ },
102
+ "indexes": {},
103
+ "foreignKeys": {},
104
+ "compositePrimaryKeys": {},
105
+ "uniqueConstraints": {},
106
+ "checkConstraints": {}
107
+ },
108
+ "run_index": {
109
+ "name": "run_index",
110
+ "columns": {
111
+ "run_id": {
112
+ "name": "run_id",
113
+ "type": "text",
114
+ "primaryKey": true,
115
+ "notNull": true,
116
+ "autoincrement": false
117
+ },
118
+ "tenant_id": {
119
+ "name": "tenant_id",
120
+ "type": "text",
121
+ "primaryKey": false,
122
+ "notNull": true,
123
+ "autoincrement": false
124
+ },
125
+ "visitor_id": {
126
+ "name": "visitor_id",
127
+ "type": "text",
128
+ "primaryKey": false,
129
+ "notNull": false,
130
+ "autoincrement": false
131
+ },
132
+ "ip_hash": {
133
+ "name": "ip_hash",
134
+ "type": "text",
135
+ "primaryKey": false,
136
+ "notNull": false,
137
+ "autoincrement": false
138
+ },
139
+ "active": {
140
+ "name": "active",
141
+ "type": "integer",
142
+ "primaryKey": false,
143
+ "notNull": true,
144
+ "autoincrement": false,
145
+ "default": false
146
+ },
147
+ "created_at": {
148
+ "name": "created_at",
149
+ "type": "integer",
150
+ "primaryKey": false,
151
+ "notNull": true,
152
+ "autoincrement": false,
153
+ "default": "(unixepoch() * 1000)"
154
+ }
155
+ },
156
+ "indexes": {
157
+ "run_index_visitor": {
158
+ "name": "run_index_visitor",
159
+ "columns": [
160
+ "visitor_id",
161
+ "created_at"
162
+ ],
163
+ "isUnique": false
164
+ },
165
+ "run_index_ip": {
166
+ "name": "run_index_ip",
167
+ "columns": [
168
+ "ip_hash",
169
+ "created_at"
170
+ ],
171
+ "isUnique": false
172
+ },
173
+ "run_index_active": {
174
+ "name": "run_index_active",
175
+ "columns": [
176
+ "active",
177
+ "tenant_id"
178
+ ],
179
+ "isUnique": false
180
+ }
181
+ },
182
+ "foreignKeys": {},
183
+ "compositePrimaryKeys": {},
184
+ "uniqueConstraints": {},
185
+ "checkConstraints": {}
186
+ },
187
+ "session": {
188
+ "name": "session",
189
+ "columns": {
190
+ "id": {
191
+ "name": "id",
192
+ "type": "text",
193
+ "primaryKey": true,
194
+ "notNull": true,
195
+ "autoincrement": false
196
+ },
197
+ "user_id": {
198
+ "name": "user_id",
199
+ "type": "text",
200
+ "primaryKey": false,
201
+ "notNull": true,
202
+ "autoincrement": false
203
+ },
204
+ "tenant_id": {
205
+ "name": "tenant_id",
206
+ "type": "text",
207
+ "primaryKey": false,
208
+ "notNull": true,
209
+ "autoincrement": false
210
+ },
211
+ "role": {
212
+ "name": "role",
213
+ "type": "text",
214
+ "primaryKey": false,
215
+ "notNull": true,
216
+ "autoincrement": false
217
+ },
218
+ "name": {
219
+ "name": "name",
220
+ "type": "text",
221
+ "primaryKey": false,
222
+ "notNull": true,
223
+ "autoincrement": false
224
+ },
225
+ "email": {
226
+ "name": "email",
227
+ "type": "text",
228
+ "primaryKey": false,
229
+ "notNull": true,
230
+ "autoincrement": false
231
+ },
232
+ "image": {
233
+ "name": "image",
234
+ "type": "text",
235
+ "primaryKey": false,
236
+ "notNull": false,
237
+ "autoincrement": false
238
+ },
239
+ "refresh_token": {
240
+ "name": "refresh_token",
241
+ "type": "text",
242
+ "primaryKey": false,
243
+ "notNull": false,
244
+ "autoincrement": false
245
+ },
246
+ "claims_expire_at": {
247
+ "name": "claims_expire_at",
248
+ "type": "integer",
249
+ "primaryKey": false,
250
+ "notNull": true,
251
+ "autoincrement": false
252
+ },
253
+ "expires_at": {
254
+ "name": "expires_at",
255
+ "type": "integer",
256
+ "primaryKey": false,
257
+ "notNull": true,
258
+ "autoincrement": false
259
+ },
260
+ "created_at": {
261
+ "name": "created_at",
262
+ "type": "integer",
263
+ "primaryKey": false,
264
+ "notNull": true,
265
+ "autoincrement": false,
266
+ "default": "(unixepoch() * 1000)"
267
+ }
268
+ },
269
+ "indexes": {
270
+ "session_expires": {
271
+ "name": "session_expires",
272
+ "columns": [
273
+ "expires_at"
274
+ ],
275
+ "isUnique": false
276
+ }
277
+ },
278
+ "foreignKeys": {},
279
+ "compositePrimaryKeys": {},
280
+ "uniqueConstraints": {},
281
+ "checkConstraints": {}
282
+ },
283
+ "setting": {
284
+ "name": "setting",
285
+ "columns": {
286
+ "key": {
287
+ "name": "key",
288
+ "type": "text",
289
+ "primaryKey": true,
290
+ "notNull": true,
291
+ "autoincrement": false
292
+ },
293
+ "value": {
294
+ "name": "value",
295
+ "type": "text",
296
+ "primaryKey": false,
297
+ "notNull": true,
298
+ "autoincrement": false
299
+ }
300
+ },
301
+ "indexes": {},
302
+ "foreignKeys": {},
303
+ "compositePrimaryKeys": {},
304
+ "uniqueConstraints": {},
305
+ "checkConstraints": {}
306
+ },
307
+ "tenant": {
308
+ "name": "tenant",
309
+ "columns": {
310
+ "id": {
311
+ "name": "id",
312
+ "type": "text",
313
+ "primaryKey": true,
314
+ "notNull": true,
315
+ "autoincrement": false
316
+ },
317
+ "status": {
318
+ "name": "status",
319
+ "type": "text",
320
+ "primaryKey": false,
321
+ "notNull": true,
322
+ "autoincrement": false,
323
+ "default": "'active'"
324
+ },
325
+ "db_url": {
326
+ "name": "db_url",
327
+ "type": "text",
328
+ "primaryKey": false,
329
+ "notNull": false,
330
+ "autoincrement": false
331
+ },
332
+ "created_at": {
333
+ "name": "created_at",
334
+ "type": "integer",
335
+ "primaryKey": false,
336
+ "notNull": true,
337
+ "autoincrement": false,
338
+ "default": "(unixepoch() * 1000)"
339
+ }
340
+ },
341
+ "indexes": {},
342
+ "foreignKeys": {},
343
+ "compositePrimaryKeys": {},
344
+ "uniqueConstraints": {},
345
+ "checkConstraints": {}
346
+ }
347
+ },
348
+ "views": {},
349
+ "enums": {},
350
+ "_meta": {
351
+ "schemas": {},
352
+ "tables": {},
353
+ "columns": {}
354
+ },
355
+ "internal": {
356
+ "indexes": {}
357
+ }
358
+ }