@camox/api 0.2.0-alpha.5

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/src/schema.ts ADDED
@@ -0,0 +1,310 @@
1
+ import { int, sqliteTable, text, index, uniqueIndex } from "drizzle-orm/sqlite-core";
2
+
3
+ // --- Auth (column names use camelCase to match better-auth's internal field names) ---
4
+
5
+ export const user = sqliteTable("user", {
6
+ id: text().primaryKey(),
7
+ name: text().notNull(),
8
+ email: text().notNull().unique(),
9
+ emailVerified: int("emailVerified", { mode: "boolean" }).notNull().default(false),
10
+ image: text(),
11
+ createdAt: int("createdAt", { mode: "timestamp_ms" }).notNull(),
12
+ updatedAt: int("updatedAt", { mode: "timestamp_ms" }).notNull(),
13
+ });
14
+
15
+ export const session = sqliteTable("session", {
16
+ id: text().primaryKey(),
17
+ expiresAt: int("expiresAt", { mode: "timestamp_ms" }).notNull(),
18
+ token: text().notNull().unique(),
19
+ ipAddress: text("ipAddress"),
20
+ userAgent: text("userAgent"),
21
+ userId: text("userId")
22
+ .notNull()
23
+ .references(() => user.id),
24
+ activeOrganizationId: text("activeOrganizationId"),
25
+ createdAt: int("createdAt", { mode: "timestamp_ms" }).notNull(),
26
+ updatedAt: int("updatedAt", { mode: "timestamp_ms" }).notNull(),
27
+ });
28
+
29
+ export const account = sqliteTable("account", {
30
+ id: text().primaryKey(),
31
+ accountId: text("accountId").notNull(),
32
+ providerId: text("providerId").notNull(),
33
+ userId: text("userId")
34
+ .notNull()
35
+ .references(() => user.id),
36
+ accessToken: text("accessToken"),
37
+ refreshToken: text("refreshToken"),
38
+ idToken: text("idToken"),
39
+ accessTokenExpiresAt: int("accessTokenExpiresAt", { mode: "timestamp_ms" }),
40
+ refreshTokenExpiresAt: int("refreshTokenExpiresAt", { mode: "timestamp_ms" }),
41
+ scope: text(),
42
+ password: text(),
43
+ createdAt: int("createdAt", { mode: "timestamp_ms" }).notNull(),
44
+ updatedAt: int("updatedAt", { mode: "timestamp_ms" }).notNull(),
45
+ });
46
+
47
+ export const verification = sqliteTable("verification", {
48
+ id: text().primaryKey(),
49
+ identifier: text().notNull(),
50
+ value: text().notNull(),
51
+ expiresAt: int("expiresAt", { mode: "timestamp_ms" }).notNull(),
52
+ createdAt: int("createdAt", { mode: "timestamp_ms" }),
53
+ updatedAt: int("updatedAt", { mode: "timestamp_ms" }),
54
+ });
55
+
56
+ export const organizationTable = sqliteTable("organization", {
57
+ id: text().primaryKey(),
58
+ name: text().notNull(),
59
+ slug: text().unique(),
60
+ logo: text(),
61
+ metadata: text(),
62
+ createdAt: int("createdAt", { mode: "timestamp_ms" }).notNull(),
63
+ });
64
+
65
+ export const member = sqliteTable("member", {
66
+ id: text().primaryKey(),
67
+ organizationId: text("organizationId")
68
+ .notNull()
69
+ .references(() => organizationTable.id),
70
+ userId: text("userId")
71
+ .notNull()
72
+ .references(() => user.id),
73
+ role: text().notNull().default("member"),
74
+ createdAt: int("createdAt", { mode: "timestamp_ms" }).notNull(),
75
+ });
76
+
77
+ export const invitation = sqliteTable("invitation", {
78
+ id: text().primaryKey(),
79
+ organizationId: text("organizationId")
80
+ .notNull()
81
+ .references(() => organizationTable.id),
82
+ email: text().notNull(),
83
+ role: text(),
84
+ status: text().notNull().default("pending"),
85
+ expiresAt: int("expiresAt", { mode: "timestamp_ms" }).notNull(),
86
+ inviterId: text("inviterId")
87
+ .notNull()
88
+ .references(() => user.id),
89
+ });
90
+
91
+ // --- Projects ---
92
+
93
+ export const projects = sqliteTable(
94
+ "projects",
95
+ {
96
+ id: int().primaryKey({ autoIncrement: true }),
97
+ slug: text().notNull(),
98
+ name: text().notNull(),
99
+ syncSecret: text("sync_secret").notNull().default(""),
100
+ organizationSlug: text("organization_slug").notNull(),
101
+ createdAt: int("created_at").notNull(),
102
+ updatedAt: int("updated_at").notNull(),
103
+ },
104
+ (table) => [
105
+ uniqueIndex("projects_slug_idx").on(table.slug),
106
+ index("projects_organization_idx").on(table.organizationSlug),
107
+ ],
108
+ );
109
+
110
+ // --- Environments ---
111
+
112
+ export const environments = sqliteTable(
113
+ "environments",
114
+ {
115
+ id: int().primaryKey({ autoIncrement: true }),
116
+ projectId: int("project_id")
117
+ .notNull()
118
+ .references(() => projects.id),
119
+ name: text().notNull(),
120
+ type: text().notNull().$type<"production" | "development">(),
121
+ createdAt: int("created_at").notNull(),
122
+ updatedAt: int("updated_at").notNull(),
123
+ },
124
+ (table) => [
125
+ uniqueIndex("environments_project_name_idx").on(table.projectId, table.name),
126
+ index("environments_project_idx").on(table.projectId),
127
+ ],
128
+ );
129
+
130
+ // --- Layouts ---
131
+
132
+ export const layouts = sqliteTable(
133
+ "layouts",
134
+ {
135
+ id: int().primaryKey({ autoIncrement: true }),
136
+ projectId: int("project_id")
137
+ .notNull()
138
+ .references(() => projects.id),
139
+ environmentId: int("environment_id")
140
+ .notNull()
141
+ .references(() => environments.id),
142
+ layoutId: text("layout_id").notNull(),
143
+ description: text(),
144
+ createdAt: int("created_at").notNull(),
145
+ updatedAt: int("updated_at").notNull(),
146
+ },
147
+ (table) => [
148
+ index("layouts_project_idx").on(table.projectId),
149
+ index("layouts_project_layout_idx").on(table.projectId, table.layoutId),
150
+ index("layouts_environment_layout_idx").on(table.environmentId, table.layoutId),
151
+ ],
152
+ );
153
+
154
+ // --- Pages ---
155
+
156
+ export const pages = sqliteTable(
157
+ "pages",
158
+ {
159
+ id: int().primaryKey({ autoIncrement: true }),
160
+ projectId: int("project_id")
161
+ .notNull()
162
+ .references(() => projects.id),
163
+ environmentId: int("environment_id")
164
+ .notNull()
165
+ .references(() => environments.id),
166
+ pathSegment: text("path_segment").notNull(),
167
+ fullPath: text("full_path").notNull(),
168
+ parentPageId: int("parent_page_id"),
169
+ layoutId: int("layout_id")
170
+ .notNull()
171
+ .references(() => layouts.id),
172
+ metaTitle: text("meta_title"),
173
+ metaDescription: text("meta_description"),
174
+ aiSeoEnabled: int("ai_seo_enabled", { mode: "boolean" }),
175
+ createdAt: int("created_at").notNull(),
176
+ updatedAt: int("updated_at").notNull(),
177
+ },
178
+ (table) => [
179
+ index("pages_full_path_idx").on(table.fullPath),
180
+ index("pages_parent_idx").on(table.parentPageId),
181
+ index("pages_project_idx").on(table.projectId),
182
+ index("pages_environment_full_path_idx").on(table.environmentId, table.fullPath),
183
+ ],
184
+ );
185
+
186
+ // --- Block Definitions ---
187
+
188
+ export const blockDefinitions = sqliteTable(
189
+ "block_definitions",
190
+ {
191
+ id: int().primaryKey({ autoIncrement: true }),
192
+ projectId: int("project_id")
193
+ .notNull()
194
+ .references(() => projects.id),
195
+ environmentId: int("environment_id")
196
+ .notNull()
197
+ .references(() => environments.id),
198
+ blockId: text("block_id").notNull(),
199
+ title: text().notNull(),
200
+ description: text().notNull(),
201
+ contentSchema: text("content_schema", { mode: "json" }).notNull(),
202
+ settingsSchema: text("settings_schema", { mode: "json" }),
203
+ defaultContent: text("default_content", { mode: "json" }),
204
+ defaultSettings: text("default_settings", { mode: "json" }),
205
+ layoutOnly: int("layout_only", { mode: "boolean" }),
206
+ createdAt: int("created_at").notNull(),
207
+ updatedAt: int("updated_at").notNull(),
208
+ },
209
+ (table) => [
210
+ index("block_definitions_project_idx").on(table.projectId),
211
+ index("block_definitions_project_block_idx").on(table.projectId, table.blockId),
212
+ index("block_definitions_environment_block_idx").on(table.environmentId, table.blockId),
213
+ ],
214
+ );
215
+
216
+ // --- Blocks ---
217
+
218
+ export const blocks = sqliteTable(
219
+ "blocks",
220
+ {
221
+ id: int().primaryKey({ autoIncrement: true }),
222
+ pageId: int("page_id").references(() => pages.id),
223
+ layoutId: int("layout_id").references(() => layouts.id),
224
+ type: text().notNull(),
225
+ content: text({ mode: "json" }).notNull(),
226
+ settings: text({ mode: "json" }),
227
+ placement: text().$type<"before" | "after">(),
228
+ summary: text().notNull().default(""),
229
+ position: text().notNull(),
230
+ createdAt: int("created_at").notNull(),
231
+ updatedAt: int("updated_at").notNull(),
232
+ },
233
+ (table) => [
234
+ index("blocks_page_idx").on(table.pageId),
235
+ index("blocks_layout_idx").on(table.layoutId),
236
+ index("blocks_type_idx").on(table.type),
237
+ ],
238
+ );
239
+
240
+ // --- Repeatable Items ---
241
+
242
+ export const repeatableItems = sqliteTable(
243
+ "repeatable_items",
244
+ {
245
+ id: int().primaryKey({ autoIncrement: true }),
246
+ blockId: int("block_id")
247
+ .notNull()
248
+ .references(() => blocks.id),
249
+ parentItemId: int("parent_item_id"),
250
+ fieldName: text("field_name").notNull(),
251
+ content: text({ mode: "json" }).notNull(),
252
+ summary: text().notNull().default(""),
253
+ position: text().notNull(),
254
+ createdAt: int("created_at").notNull(),
255
+ updatedAt: int("updated_at").notNull(),
256
+ },
257
+ (table) => [
258
+ index("repeatable_items_block_field_idx").on(table.blockId, table.fieldName),
259
+ index("repeatable_items_block_idx").on(table.blockId),
260
+ index("repeatable_items_parent_idx").on(table.parentItemId),
261
+ ],
262
+ );
263
+
264
+ // --- Files ---
265
+
266
+ export const files = sqliteTable(
267
+ "files",
268
+ {
269
+ id: int().primaryKey({ autoIncrement: true }),
270
+ projectId: int("project_id").references(() => projects.id),
271
+ environmentId: int("environment_id")
272
+ .notNull()
273
+ .references(() => environments.id),
274
+ url: text().notNull(),
275
+ alt: text().notNull().default(""),
276
+ filename: text().notNull(),
277
+ mimeType: text("mime_type").notNull(),
278
+ size: int().notNull(),
279
+ blobId: text("blob_id").notNull(),
280
+ path: text().notNull(),
281
+ aiMetadataEnabled: int("ai_metadata_enabled", { mode: "boolean" }),
282
+ createdAt: int("created_at").notNull(),
283
+ updatedAt: int("updated_at").notNull(),
284
+ },
285
+ (table) => [
286
+ index("files_blob_id_idx").on(table.blobId),
287
+ index("files_project_idx").on(table.projectId),
288
+ index("files_environment_idx").on(table.environmentId),
289
+ ],
290
+ );
291
+
292
+ // --- AI Jobs ---
293
+
294
+ export const aiJobs = sqliteTable(
295
+ "ai_jobs",
296
+ {
297
+ id: int().primaryKey({ autoIncrement: true }),
298
+ entityTable: text("entity_table")
299
+ .notNull()
300
+ .$type<"repeatableItems" | "blocks" | "files" | "pages">(),
301
+ entityId: text("entity_id").notNull(),
302
+ type: text().notNull().$type<"summary" | "fileMetadata" | "seo">(),
303
+ status: text()
304
+ .notNull()
305
+ .default("pending")
306
+ .$type<"pending" | "running" | "completed" | "failed">(),
307
+ createdAt: int("created_at").notNull(),
308
+ },
309
+ (table) => [index("ai_jobs_entity_idx").on(table.entityTable, table.entityId, table.type)],
310
+ );
package/src/types.ts ADDED
@@ -0,0 +1,29 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import type { Database } from "./db";
3
+ import type { Auth } from "./routes/auth";
4
+
5
+ export type Bindings = {
6
+ DB: D1Database;
7
+ BETTER_AUTH_SECRET: string;
8
+ BETTER_AUTH_URL: string;
9
+ GITHUB_CLIENT_ID: string;
10
+ GITHUB_CLIENT_SECRET: string;
11
+ GOOGLE_CLIENT_ID: string;
12
+ GOOGLE_CLIENT_SECRET: string;
13
+ SITE_URL: string;
14
+ OPEN_ROUTER_API_KEY: string;
15
+ AI_JOB_SCHEDULER: DurableObjectNamespace;
16
+ ProjectRoom: DurableObjectNamespace;
17
+ FILES_BUCKET: R2Bucket;
18
+ SYNC_SECRET: string;
19
+ };
20
+
21
+ export type AppEnv = {
22
+ Bindings: Bindings;
23
+ Variables: {
24
+ db: Database;
25
+ user: Auth["$Infer"]["Session"]["user"] | null;
26
+ session: Auth["$Infer"]["Session"]["session"] | null;
27
+ environmentName: string;
28
+ };
29
+ };
package/src/worker.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { default } from "./index";
2
+ export { AiJobScheduler } from "./durable-objects/ai-job-scheduler";
3
+ export { ProjectRoom } from "./durable-objects/project-room";