@rimelight/cms 0.0.3 → 0.0.4
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/dist/bylines-Csggkl-g.d.mts +405 -0
- package/dist/index.d.mts +724 -0
- package/dist/index.mjs +2382 -0
- package/dist/integration.d.mts +33 -0
- package/dist/integration.mjs +161 -0
- package/dist/schema/index.d.mts +2063 -0
- package/dist/schema/index.mjs +176 -0
- package/dist/schema/sqlite.d.mts +2132 -0
- package/dist/schema/sqlite.mjs +137 -0
- package/dist/storage/index.d.mts +59 -0
- package/dist/storage/index.mjs +133 -0
- package/package.json +30 -14
- package/src/admin/api/media.ts +28 -3
- package/src/admin/layouts/CMSDashboardLayout.astro +16 -3
- package/src/admin/pages/pages-preview.astro +1 -1
- package/src/astro/PageRenderer.astro +4 -4
- package/src/env.d.ts +6 -0
- package/src/index.ts +17 -4
- package/src/integration.ts +54 -0
- package/src/schema/sqlite.ts +344 -0
- package/src/storage/index.ts +4 -1
package/src/integration.ts
CHANGED
|
@@ -3,6 +3,7 @@ import path from "node:path"
|
|
|
3
3
|
import fs from "node:fs"
|
|
4
4
|
import { fileURLToPath } from "node:url"
|
|
5
5
|
import type { StorageConfig } from "./storage/index"
|
|
6
|
+
import type { AuthAdapter } from "@rimelight/auth"
|
|
6
7
|
|
|
7
8
|
export interface RimelightCmsOptions {
|
|
8
9
|
/**
|
|
@@ -27,6 +28,12 @@ export interface RimelightCmsOptions {
|
|
|
27
28
|
* "https://media.example.com" })).
|
|
28
29
|
*/
|
|
29
30
|
storage?: StorageConfig | undefined
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Pluggable Auth Adapter instance or module path (RFC-0004 / RFC-0006). E.g. cfAccessAuth({ ...
|
|
34
|
+
* }), auth0Auth({ ... }), or mockAuth().
|
|
35
|
+
*/
|
|
36
|
+
auth?: AuthAdapter | string | undefined
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
export function rimelightCms(options: RimelightCmsOptions = {}): AstroIntegration {
|
|
@@ -66,6 +73,47 @@ export function rimelightCms(options: RimelightCmsOptions = {}): AstroIntegratio
|
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
// Resolve auth module / adapter code
|
|
77
|
+
let resolvedAuthCode: string
|
|
78
|
+
if (typeof options.auth === "string") {
|
|
79
|
+
const resolvedAuthPath = path.isAbsolute(options.auth)
|
|
80
|
+
? options.auth
|
|
81
|
+
: path.resolve(rootDir, options.auth)
|
|
82
|
+
resolvedAuthCode = `export { authAdapter, authAdapter as default } from ${JSON.stringify(resolvedAuthPath)};`
|
|
83
|
+
} else if (options.auth && typeof options.auth === "object") {
|
|
84
|
+
const authObj = options.auth as any
|
|
85
|
+
const adapterName = authObj.name || "mock"
|
|
86
|
+
const adapterOpts = authObj.options || {}
|
|
87
|
+
|
|
88
|
+
if (adapterName === "cf-access") {
|
|
89
|
+
resolvedAuthCode = `import { cfAccessAuth } from "@rimelight/auth/cf-access";
|
|
90
|
+
export const authAdapter = cfAccessAuth(${JSON.stringify(adapterOpts)});
|
|
91
|
+
export default authAdapter;`
|
|
92
|
+
} else if (adapterName === "auth0") {
|
|
93
|
+
resolvedAuthCode = `import { auth0Auth } from "@rimelight/auth/auth0";
|
|
94
|
+
export const authAdapter = auth0Auth(${JSON.stringify(adapterOpts)});
|
|
95
|
+
export default authAdapter;`
|
|
96
|
+
} else {
|
|
97
|
+
resolvedAuthCode = `import { mockAuth } from "@rimelight/auth/mock";
|
|
98
|
+
export const authAdapter = mockAuth(${JSON.stringify(adapterOpts)});
|
|
99
|
+
export default authAdapter;`
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
// Default fallback mock admin adapter for development
|
|
103
|
+
resolvedAuthCode = `import { mockAuth } from "@rimelight/auth/mock";
|
|
104
|
+
export const authAdapter = mockAuth({
|
|
105
|
+
session: {
|
|
106
|
+
userId: "cms-admin",
|
|
107
|
+
name: "CMS Administrator",
|
|
108
|
+
email: "admin@rimelight.com",
|
|
109
|
+
roles: ["admin", "editor"],
|
|
110
|
+
permissions: ["*"],
|
|
111
|
+
userType: "employee"
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
export default authAdapter;`
|
|
115
|
+
}
|
|
116
|
+
|
|
69
117
|
// 1. Inject CMS admin routes
|
|
70
118
|
injectRoute({
|
|
71
119
|
pattern: `${routePrefix}`,
|
|
@@ -166,6 +214,9 @@ export function rimelightCms(options: RimelightCmsOptions = {}): AstroIntegratio
|
|
|
166
214
|
if (id === "virtual:rimelight-cms/storage") {
|
|
167
215
|
return "\0virtual:rimelight-cms/storage"
|
|
168
216
|
}
|
|
217
|
+
if (id === "virtual:rimelight-cms/auth") {
|
|
218
|
+
return "\0virtual:rimelight-cms/auth"
|
|
219
|
+
}
|
|
169
220
|
return undefined
|
|
170
221
|
},
|
|
171
222
|
load(id) {
|
|
@@ -184,6 +235,9 @@ export function rimelightCms(options: RimelightCmsOptions = {}): AstroIntegratio
|
|
|
184
235
|
if (id === "\0virtual:rimelight-cms/storage") {
|
|
185
236
|
return `export const storageConfig = ${JSON.stringify(storageConfig)};`
|
|
186
237
|
}
|
|
238
|
+
if (id === "\0virtual:rimelight-cms/auth") {
|
|
239
|
+
return resolvedAuthCode
|
|
240
|
+
}
|
|
187
241
|
return undefined
|
|
188
242
|
}
|
|
189
243
|
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm"
|
|
2
|
+
import {
|
|
3
|
+
sqliteTable,
|
|
4
|
+
text,
|
|
5
|
+
integer,
|
|
6
|
+
uniqueIndex,
|
|
7
|
+
index,
|
|
8
|
+
type AnySQLiteColumn
|
|
9
|
+
} from "drizzle-orm/sqlite-core"
|
|
10
|
+
import type { BaseBlock } from "../core/types/blocks"
|
|
11
|
+
import type { Localized, PageType } from "../core/types/pages"
|
|
12
|
+
import type { BylineCredit } from "../core/types/bylines"
|
|
13
|
+
import type { PageVersionStatus } from "../core/types/versioning"
|
|
14
|
+
import type { TemplateApprovalRules, TemplateRolePermissions } from "../core/types/templates"
|
|
15
|
+
|
|
16
|
+
export interface SiteSettingsBranding {
|
|
17
|
+
logo: {
|
|
18
|
+
alt: string
|
|
19
|
+
}
|
|
20
|
+
favicon: {
|
|
21
|
+
svg: string
|
|
22
|
+
}
|
|
23
|
+
colors: {
|
|
24
|
+
themeColor: string
|
|
25
|
+
backgroundColor: string
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SiteSettingsSeo {
|
|
30
|
+
titleTemplate: string
|
|
31
|
+
ogImageFallback: string
|
|
32
|
+
maxDescriptionLength: number
|
|
33
|
+
authorHandle?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 1. Page Templates
|
|
37
|
+
export const pageTemplates = sqliteTable("page_templates", {
|
|
38
|
+
id: text("id")
|
|
39
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
40
|
+
.notNull()
|
|
41
|
+
.primaryKey(),
|
|
42
|
+
slug: text("slug").notNull().unique(),
|
|
43
|
+
title: text("title", { mode: "json" }).$type<Localized>().notNull(),
|
|
44
|
+
description: text("description", { mode: "json" }).$type<Localized>(),
|
|
45
|
+
pageType: text("page_type").$type<PageType>().notNull(),
|
|
46
|
+
version: integer("version").default(1).notNull(),
|
|
47
|
+
allowedRoles: text("allowed_roles", { mode: "json" })
|
|
48
|
+
.$type<string[]>()
|
|
49
|
+
.default(sql`'[]'`)
|
|
50
|
+
.notNull(),
|
|
51
|
+
rolePermissions: text("role_permissions", { mode: "json" })
|
|
52
|
+
.$type<TemplateRolePermissions>()
|
|
53
|
+
.default(sql`'{"whoCanCreate":[],"whoCanEdit":[],"whoCanReview":[],"whoCanView":[]}'`)
|
|
54
|
+
.notNull(),
|
|
55
|
+
requiredPermission: text("required_permission"),
|
|
56
|
+
approvalRules: text("approval_rules", { mode: "json" })
|
|
57
|
+
.$type<TemplateApprovalRules>()
|
|
58
|
+
.default(sql`'{"allowSelfApproval":true,"minApprovals":1}'`)
|
|
59
|
+
.notNull(),
|
|
60
|
+
defaultProperties: text("default_properties", { mode: "json" })
|
|
61
|
+
.default(sql`'{}'`)
|
|
62
|
+
.notNull(),
|
|
63
|
+
initialBlocks: text("initial_blocks", { mode: "json" })
|
|
64
|
+
.$type<BaseBlock[]>()
|
|
65
|
+
.default(sql`'[]'`)
|
|
66
|
+
.notNull(),
|
|
67
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
68
|
+
.$defaultFn(() => new Date())
|
|
69
|
+
.notNull(),
|
|
70
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).$onUpdate(() => new Date())
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// 2. Page Versions
|
|
74
|
+
export const pageVersions = sqliteTable(
|
|
75
|
+
"page_versions",
|
|
76
|
+
{
|
|
77
|
+
id: text("id")
|
|
78
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
79
|
+
.notNull()
|
|
80
|
+
.primaryKey(),
|
|
81
|
+
pageId: text("page_id").notNull(),
|
|
82
|
+
versionNumber: integer("version_number").notNull(),
|
|
83
|
+
status: text("status").$type<PageVersionStatus>().default("pending").notNull(),
|
|
84
|
+
slug: text("slug").notNull(),
|
|
85
|
+
type: text("type").$type<PageType>().notNull(),
|
|
86
|
+
title: text("title", { mode: "json" }).$type<Localized>().notNull(),
|
|
87
|
+
description: text("description", { mode: "json" }).$type<Localized>(),
|
|
88
|
+
tags: text("tags", { mode: "json" })
|
|
89
|
+
.$type<Localized[]>()
|
|
90
|
+
.default(sql`'[]'`)
|
|
91
|
+
.notNull(),
|
|
92
|
+
authorIds: text("author_ids", { mode: "json" })
|
|
93
|
+
.$type<string[]>()
|
|
94
|
+
.default(sql`'[]'`),
|
|
95
|
+
bylines: text("bylines", { mode: "json" })
|
|
96
|
+
.$type<BylineCredit[]>()
|
|
97
|
+
.default(sql`'[]'`),
|
|
98
|
+
content: text("content", { mode: "json" })
|
|
99
|
+
.$type<{
|
|
100
|
+
blocks: BaseBlock[]
|
|
101
|
+
properties: Record<string, any>
|
|
102
|
+
}>()
|
|
103
|
+
.notNull(),
|
|
104
|
+
createdBy: text("created_by").notNull(),
|
|
105
|
+
approvedBy: text("approved_by", { mode: "json" })
|
|
106
|
+
.$type<string[]>()
|
|
107
|
+
.default(sql`'[]'`)
|
|
108
|
+
.notNull(),
|
|
109
|
+
approvedAt: integer("approved_at", { mode: "timestamp" }),
|
|
110
|
+
changeSummary: text("change_summary"),
|
|
111
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
112
|
+
.$defaultFn(() => new Date())
|
|
113
|
+
.notNull()
|
|
114
|
+
},
|
|
115
|
+
(table) => [
|
|
116
|
+
uniqueIndex("page_versions_page_id_version_idx").on(table.pageId, table.versionNumber)
|
|
117
|
+
]
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
// 3. Pages
|
|
121
|
+
export const pages = sqliteTable(
|
|
122
|
+
"pages",
|
|
123
|
+
{
|
|
124
|
+
id: text("id")
|
|
125
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
126
|
+
.notNull()
|
|
127
|
+
.primaryKey(),
|
|
128
|
+
slug: text("slug").notNull(),
|
|
129
|
+
type: text("type").$type<PageType>().notNull(),
|
|
130
|
+
templateId: text("template_id").references(() => pageTemplates.id, { onDelete: "set null" }),
|
|
131
|
+
templateVersion: integer("template_version").default(1).notNull(),
|
|
132
|
+
title: text("title", { mode: "json" }).$type<Localized>().notNull(),
|
|
133
|
+
description: text("description", { mode: "json" }).$type<Localized>(),
|
|
134
|
+
tags: text("tags", { mode: "json" })
|
|
135
|
+
.$type<Localized[]>()
|
|
136
|
+
.default(sql`'[]'`)
|
|
137
|
+
.notNull(),
|
|
138
|
+
authorIds: text("author_ids", { mode: "json" })
|
|
139
|
+
.$type<string[]>()
|
|
140
|
+
.default(sql`'[]'`),
|
|
141
|
+
bylines: text("bylines", { mode: "json" })
|
|
142
|
+
.$type<BylineCredit[]>()
|
|
143
|
+
.default(sql`'[]'`),
|
|
144
|
+
content: text("content", { mode: "json" })
|
|
145
|
+
.$type<{
|
|
146
|
+
blocks: BaseBlock[]
|
|
147
|
+
properties: Record<string, any>
|
|
148
|
+
}>()
|
|
149
|
+
.notNull(),
|
|
150
|
+
publishedVersionId: text("published_version_id").references(() => pageVersions.id, {
|
|
151
|
+
onDelete: "set null"
|
|
152
|
+
}),
|
|
153
|
+
postedAt: integer("posted_at", { mode: "timestamp" }),
|
|
154
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
155
|
+
.$defaultFn(() => new Date())
|
|
156
|
+
.notNull(),
|
|
157
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).$onUpdate(() => new Date()),
|
|
158
|
+
deletedAt: integer("deleted_at", { mode: "timestamp" })
|
|
159
|
+
},
|
|
160
|
+
(table) => [
|
|
161
|
+
uniqueIndex("pages_slug_active_unique_idx")
|
|
162
|
+
.on(table.slug)
|
|
163
|
+
.where(sql`deleted_at IS NULL`)
|
|
164
|
+
]
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
// 4. Page Drafts
|
|
168
|
+
export const pageDrafts = sqliteTable("page_drafts", {
|
|
169
|
+
pageId: text("page_id")
|
|
170
|
+
.notNull()
|
|
171
|
+
.primaryKey()
|
|
172
|
+
.references(() => pages.id, { onDelete: "cascade" }),
|
|
173
|
+
content: text("content", { mode: "json" })
|
|
174
|
+
.$type<{
|
|
175
|
+
blocks: BaseBlock[]
|
|
176
|
+
properties: Record<string, any>
|
|
177
|
+
}>()
|
|
178
|
+
.notNull(),
|
|
179
|
+
updatedBy: text("updated_by").notNull(),
|
|
180
|
+
updatedAt: integer("updated_at", { mode: "timestamp" })
|
|
181
|
+
.$defaultFn(() => new Date())
|
|
182
|
+
.notNull()
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
// 5. Page Draft Locks
|
|
186
|
+
export const pageDraftLocks = sqliteTable("page_draft_locks", {
|
|
187
|
+
pageId: text("page_id")
|
|
188
|
+
.notNull()
|
|
189
|
+
.primaryKey()
|
|
190
|
+
.references(() => pages.id, { onDelete: "cascade" }),
|
|
191
|
+
lockedByUserId: text("locked_by_user_id").notNull(),
|
|
192
|
+
lockedByUserName: text("locked_by_user_name").notNull(),
|
|
193
|
+
acquiredAt: integer("acquired_at", { mode: "timestamp" })
|
|
194
|
+
.$defaultFn(() => new Date())
|
|
195
|
+
.notNull(),
|
|
196
|
+
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull()
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
// 6. Page Version Approvals
|
|
200
|
+
export const pageVersionApprovals = sqliteTable("page_version_approvals", {
|
|
201
|
+
id: text("id")
|
|
202
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
203
|
+
.notNull()
|
|
204
|
+
.primaryKey(),
|
|
205
|
+
versionId: text("version_id")
|
|
206
|
+
.notNull()
|
|
207
|
+
.references(() => pageVersions.id, { onDelete: "cascade" }),
|
|
208
|
+
userId: text("user_id").notNull(),
|
|
209
|
+
userRole: text("user_role").notNull(),
|
|
210
|
+
approvedAt: integer("approved_at", { mode: "timestamp" })
|
|
211
|
+
.$defaultFn(() => new Date())
|
|
212
|
+
.notNull()
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
// 7. Page Version Comments
|
|
216
|
+
export const pageVersionComments = sqliteTable("page_version_comments", {
|
|
217
|
+
id: text("id")
|
|
218
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
219
|
+
.notNull()
|
|
220
|
+
.primaryKey(),
|
|
221
|
+
versionId: text("version_id")
|
|
222
|
+
.notNull()
|
|
223
|
+
.references(() => pageVersions.id, { onDelete: "cascade" }),
|
|
224
|
+
userId: text("user_id").notNull(),
|
|
225
|
+
userRole: text("user_role").notNull(),
|
|
226
|
+
content: text("content").notNull(),
|
|
227
|
+
blockId: text("block_id"),
|
|
228
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
229
|
+
.$defaultFn(() => new Date())
|
|
230
|
+
.notNull()
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
// 8. Search
|
|
234
|
+
export const contentSearchIndex = sqliteTable(
|
|
235
|
+
"content_search_index",
|
|
236
|
+
{
|
|
237
|
+
id: text("id")
|
|
238
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
239
|
+
.notNull()
|
|
240
|
+
.primaryKey(),
|
|
241
|
+
pageId: text("page_id")
|
|
242
|
+
.notNull()
|
|
243
|
+
.references(() => pages.id, { onDelete: "cascade" }),
|
|
244
|
+
locale: text("locale").notNull(),
|
|
245
|
+
titleText: text("title_text").notNull(),
|
|
246
|
+
contentText: text("content_text").notNull()
|
|
247
|
+
},
|
|
248
|
+
(table) => [index("content_search_index_page_id_idx").on(table.pageId)]
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
// 9. Site Settings
|
|
252
|
+
export const siteSettings = sqliteTable("site_settings", {
|
|
253
|
+
id: text("id").primaryKey().default("default"),
|
|
254
|
+
name: text("name").notNull(),
|
|
255
|
+
description: text("description").notNull(),
|
|
256
|
+
url: text("url").notNull(),
|
|
257
|
+
ogImage: text("og_image").notNull(),
|
|
258
|
+
author: text("author").notNull(),
|
|
259
|
+
email: text("email").notNull().default(""),
|
|
260
|
+
branding: text("branding", { mode: "json" }).$type<SiteSettingsBranding>().notNull(),
|
|
261
|
+
seo: text("seo", { mode: "json" }).$type<SiteSettingsSeo>().notNull(),
|
|
262
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
263
|
+
.$defaultFn(() => new Date())
|
|
264
|
+
.notNull(),
|
|
265
|
+
updatedAt: integer("updated_at", { mode: "timestamp" })
|
|
266
|
+
.$defaultFn(() => new Date())
|
|
267
|
+
.$onUpdate(() => new Date())
|
|
268
|
+
.notNull()
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
// 10. Taxonomies
|
|
272
|
+
export const taxonomyTerms = sqliteTable(
|
|
273
|
+
"taxonomy_terms",
|
|
274
|
+
{
|
|
275
|
+
id: text("id")
|
|
276
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
277
|
+
.notNull()
|
|
278
|
+
.primaryKey(),
|
|
279
|
+
taxonomy: text("taxonomy").notNull(),
|
|
280
|
+
slug: text("slug").notNull(),
|
|
281
|
+
label: text("label", { mode: "json" }).$type<Localized | string>().notNull(),
|
|
282
|
+
description: text("description", { mode: "json" }).$type<Localized | string>(),
|
|
283
|
+
parentId: text("parent_id").references((): AnySQLiteColumn => taxonomyTerms.id, {
|
|
284
|
+
onDelete: "cascade"
|
|
285
|
+
}),
|
|
286
|
+
displayOrder: integer("display_order").default(0).notNull(),
|
|
287
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
288
|
+
.$defaultFn(() => new Date())
|
|
289
|
+
.notNull(),
|
|
290
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).$onUpdate(() => new Date())
|
|
291
|
+
},
|
|
292
|
+
(table) => [uniqueIndex("taxonomy_terms_tax_slug_idx").on(table.taxonomy, table.slug)]
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
export const pageTaxonomyTerms = sqliteTable(
|
|
296
|
+
"page_taxonomy_terms",
|
|
297
|
+
{
|
|
298
|
+
pageId: text("page_id")
|
|
299
|
+
.notNull()
|
|
300
|
+
.references(() => pages.id, { onDelete: "cascade" }),
|
|
301
|
+
termId: text("term_id")
|
|
302
|
+
.notNull()
|
|
303
|
+
.references(() => taxonomyTerms.id, { onDelete: "cascade" }),
|
|
304
|
+
assignedAt: integer("assigned_at", { mode: "timestamp" })
|
|
305
|
+
.$defaultFn(() => new Date())
|
|
306
|
+
.notNull()
|
|
307
|
+
},
|
|
308
|
+
(table) => [uniqueIndex("page_taxonomy_terms_page_term_idx").on(table.pageId, table.termId)]
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
// 11. Bylines
|
|
312
|
+
export const bylines = sqliteTable(
|
|
313
|
+
"bylines",
|
|
314
|
+
{
|
|
315
|
+
id: text("id")
|
|
316
|
+
.$defaultFn(() => crypto.randomUUID())
|
|
317
|
+
.primaryKey(),
|
|
318
|
+
name: text("name").notNull(),
|
|
319
|
+
slug: text("slug").notNull(),
|
|
320
|
+
websiteUrl: text("website_url"),
|
|
321
|
+
bio: text("bio"),
|
|
322
|
+
avatar: text("avatar"),
|
|
323
|
+
userId: text("user_id"),
|
|
324
|
+
socials: text("socials", { mode: "json" })
|
|
325
|
+
.$type<Record<string, string>>()
|
|
326
|
+
.default(sql`'{}'`),
|
|
327
|
+
metadata: text("metadata", { mode: "json" })
|
|
328
|
+
.$type<Record<string, any>>()
|
|
329
|
+
.default(sql`'{}'`),
|
|
330
|
+
createdAt: integer("created_at", { mode: "timestamp" })
|
|
331
|
+
.$defaultFn(() => new Date())
|
|
332
|
+
.notNull(),
|
|
333
|
+
updatedAt: integer("updated_at", { mode: "timestamp" })
|
|
334
|
+
.$defaultFn(() => new Date())
|
|
335
|
+
.notNull(),
|
|
336
|
+
deletedAt: integer("deleted_at", { mode: "timestamp" })
|
|
337
|
+
},
|
|
338
|
+
(table) => [uniqueIndex("bylines_slug_idx").on(table.slug)]
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
export type Byline = typeof bylines.$inferSelect
|
|
342
|
+
export type NewByline = typeof bylines.$inferInsert
|
|
343
|
+
export type SiteSettings = typeof siteSettings.$inferSelect
|
|
344
|
+
export type InsertSiteSettings = typeof siteSettings.$inferInsert
|
package/src/storage/index.ts
CHANGED
|
@@ -65,8 +65,11 @@ export async function getR2Bucket(locals?: any, bindingName = "BLOB"): Promise<a
|
|
|
65
65
|
}
|
|
66
66
|
} catch {}
|
|
67
67
|
|
|
68
|
-
// 2. Direct locals property check (locals.env or locals[bindingName])
|
|
68
|
+
// 2. Direct locals property check (locals.runtime.env, locals.env or locals[bindingName])
|
|
69
69
|
if (locals) {
|
|
70
|
+
if (locals.runtime?.env && locals.runtime.env[bindingName]) {
|
|
71
|
+
return locals.runtime.env[bindingName]
|
|
72
|
+
}
|
|
70
73
|
if (locals.env && locals.env[bindingName]) {
|
|
71
74
|
return locals.env[bindingName]
|
|
72
75
|
}
|