@rimelight/config 0.0.8 → 0.0.9

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/astro/index.ts CHANGED
@@ -1,421 +1,422 @@
1
- import fs from "node:fs"
2
- import path from "node:path"
3
- import cloudflare from "@astrojs/cloudflare"
4
- import { cacheCloudflare } from "@astrojs/cloudflare/cache"
5
- import { fontProviders } from "astro/config"
6
-
7
- export interface CacheRulesPresetOptions {
8
- apiSwrSeconds?: number
9
- pageMaxAgeSeconds?: number
10
- customRules?: Record<string, any>
11
- }
12
-
13
- export function cacheRulesPreset(options: CacheRulesPresetOptions = {}): any {
14
- const { apiSwrSeconds = 600, pageMaxAgeSeconds = 300, customRules = {} } = options
15
- return {
16
- routeRules: {
17
- "/api/[...path]": {
18
- swr: apiSwrSeconds
19
- },
20
- "/[...path]": {
21
- maxAge: pageMaxAgeSeconds
22
- },
23
- ...customRules
24
- }
25
- }
26
- }
27
-
28
- export interface FontsPresetOptions {
29
- fontProviders?: any
30
- fonts?: any[]
31
- }
32
-
33
- export function fontsPreset(options: FontsPresetOptions = {}): any {
34
- const defaultFonts = [
35
- {
36
- name: "Noto Sans",
37
- cssVariable: "--font-sans",
38
- fallbacks: ["sans-serif"],
39
- subsets: ["latin", "latin-ext"],
40
- weights: [400, 500, 600, 700],
41
- styles: ["normal"]
42
- },
43
- {
44
- name: "Noto Serif",
45
- cssVariable: "--font-serif",
46
- fallbacks: ["serif"],
47
- subsets: ["latin", "latin-ext"],
48
- weights: [400, 700],
49
- styles: ["normal"]
50
- },
51
- {
52
- name: "JetBrains Mono",
53
- cssVariable: "--font-mono",
54
- fallbacks: ["monospace"],
55
- subsets: ["latin", "latin-ext"],
56
- weights: [400, 500, 700],
57
- styles: ["normal"]
58
- }
59
- ]
60
-
61
- const provider = (options.fontProviders || fontProviders)?.fontsource
62
- ? (options.fontProviders || fontProviders).fontsource()
63
- : undefined
64
-
65
- return {
66
- fonts: (options.fonts || defaultFonts).map((font) => ({
67
- ...(provider ? { provider } : {}),
68
- ...font
69
- }))
70
- }
71
- }
72
-
73
- export interface ImagePresetOptions {
74
- domains?: string[]
75
- layout?: "constrained" | "fixed" | "full-width" | "responsive"
76
- responsiveStyles?: boolean
77
- }
78
-
79
- export function imagePreset(options: ImagePresetOptions = {}): any {
80
- const { domains = [], layout = "constrained", responsiveStyles = true } = options
81
- return {
82
- image: {
83
- domains,
84
- layout,
85
- responsiveStyles
86
- }
87
- }
88
- }
89
-
90
- export interface CloudflarePresetOptions {
91
- adapter?: any
92
- cacheProvider?: any
93
- session?: boolean
94
- }
95
-
96
- export function cloudflarePreset(options: CloudflarePresetOptions = {}): any {
97
- const { adapter = cloudflare(), cacheProvider = cacheCloudflare(), session = false } = options
98
- return {
99
- output: "server" as const,
100
- session,
101
- adapter,
102
- cache: { provider: cacheProvider }
103
- }
104
- }
105
-
106
- export interface RimelightAstroOptions {
107
- domain?: string
108
- site?: string
109
- imageDomains?: string[]
110
- apiSwrSeconds?: number
111
- pageMaxAgeSeconds?: number
112
- adapter?: any
113
- cacheProvider?: any
114
- fonts?: any[]
115
- solid?: boolean | { include?: string[]; [key: string]: any }
116
- security?:
117
- | boolean
118
- | {
119
- domain?: string
120
- imgSrc?: string[]
121
- directives?: Record<string, any>
122
- [key: string]: any
123
- }
124
- i18n?:
125
- | boolean
126
- | {
127
- translations?: Record<string, any>
128
- locales?: string[]
129
- defaultLocale?: string
130
- prefixDefaultLocale?: boolean
131
- kvBinding?: string
132
- [key: string]: any
133
- }
134
- seo?:
135
- | boolean
136
- | {
137
- robots?: boolean | Record<string, any>
138
- sitemap?: boolean | Record<string, any>
139
- rss?: boolean | Record<string, any>
140
- llms?: boolean | Record<string, any>
141
- llmsFull?: boolean | Record<string, any>
142
- [key: string]: any
143
- }
144
- cms?:
145
- | boolean
146
- | {
147
- storage?: any
148
- binding?: string
149
- auth?: string
150
- [key: string]: any
151
- }
152
- ui?:
153
- | boolean
154
- | {
155
- logos?: any
156
- shortcuts?: any
157
- [key: string]: any
158
- }
159
- integrations?: any[]
160
- vite?: {
161
- plugins?: any[]
162
- [key: string]: any
163
- }
164
- [key: string]: any
165
- }
166
-
167
- function discoverTranslations(dir = "./src/translations"): Record<string, any> {
168
- const translations: Record<string, any> = {}
169
- try {
170
- const resolvedDir = path.resolve(process.cwd(), dir)
171
- if (fs.existsSync(resolvedDir)) {
172
- const files = fs.readdirSync(resolvedDir)
173
- for (const file of files) {
174
- if (file.endsWith(".json")) {
175
- const locale = path.basename(file, ".json")
176
- const content = JSON.parse(fs.readFileSync(path.join(resolvedDir, file), "utf8"))
177
- translations[locale] = content
178
- }
179
- }
180
- }
181
- } catch {}
182
- return translations
183
- }
184
-
185
- function discoverLogos(dir = "./src/assets/logos"): Record<string, any> | undefined {
186
- try {
187
- const candidateDirs = [dir, "./src/assets/logo"]
188
- let resolvedDir: string | null = null
189
- for (const d of candidateDirs) {
190
- const p = path.resolve(process.cwd(), d)
191
- if (fs.existsSync(p) && fs.statSync(p).isDirectory()) {
192
- resolvedDir = p
193
- break
194
- }
195
- }
196
- if (!resolvedDir) return undefined
197
-
198
- const files = fs.readdirSync(resolvedDir)
199
- const logos: Record<string, any> = {}
200
-
201
- const variants = ["logomark", "logotype", "logo"]
202
- const modes = ["color", "white", "black", "light", "dark"]
203
- const extensions = [".svg", ".png", ".webp", ".jpg", ".jpeg", ".gif"]
204
-
205
- for (const variant of variants) {
206
- for (const mode of modes) {
207
- for (const ext of extensions) {
208
- const fileName = `${variant}_${mode}${ext}`
209
- if (files.includes(fileName)) {
210
- if (!logos[variant]) logos[variant] = {}
211
- const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
212
- logos[variant][mode] = relPath
213
- }
214
- }
215
- }
216
- for (const ext of extensions) {
217
- const fileName = `${variant}${ext}`
218
- if (files.includes(fileName) && !logos[variant]) {
219
- const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
220
- logos[variant] = relPath
221
- }
222
- }
223
- }
224
-
225
- return Object.keys(logos).length > 0 ? logos : undefined
226
- } catch {
227
- return undefined
228
- }
229
- }
230
-
231
- function defaultShortcuts(): Record<string, any> {
232
- return {
233
- categories: {
234
- system: { label: "System" },
235
- navigation: { label: "Navigation" }
236
- }
237
- }
238
- }
239
-
240
- function rimelightIntegration(
241
- options: RimelightAstroOptions,
242
- imageDomains: string[],
243
- domain?: string
244
- ) {
245
- return {
246
- name: "rimelight-auto-plugins",
247
- hooks: {
248
- "astro:config:setup": async ({ updateConfig }: { updateConfig: (config: any) => void }) => {
249
- const integrations: any[] = []
250
- const plugins: any[] = []
251
-
252
- if (options.solid) {
253
- const solidMod = await import("@astrojs/solid-js")
254
- const solidFn = (solidMod as any).default || solidMod
255
- const solidOpts =
256
- typeof options.solid === "object"
257
- ? options.solid
258
- : { include: ["**/solid/**", "**/*.tsx"] }
259
- integrations.push(solidFn(solidOpts))
260
- }
261
-
262
- if (options.seo) {
263
- const seoMod = await import("@rimelight/seo")
264
- const seoFn =
265
- (seoMod as any).rimelightSeo ||
266
- (seoMod as any).default?.rimelightSeo ||
267
- (seoMod as any).default ||
268
- seoMod
269
- const seoOpts = typeof options.seo === "object" ? options.seo : {}
270
- integrations.push(seoFn(seoOpts))
271
- }
272
-
273
- if (options.cms) {
274
- const cmsMod = await import("@rimelight/cms/integration")
275
- const { rimelightCms } = cmsMod as any
276
- const cmsOpts = typeof options.cms === "object" ? options.cms : {}
277
- let storage = cmsOpts.storage
278
- if (!storage) {
279
- const storageMod = await import("@rimelight/cms/storage")
280
- const { r2 } = storageMod as any
281
- storage = r2({ binding: cmsOpts.binding || "BLOB" })
282
- }
283
- integrations.push(
284
- rimelightCms({
285
- storage,
286
- auth: cmsOpts.auth || "./src/auth/auth.ts",
287
- ...cmsOpts
288
- })
289
- )
290
- }
291
-
292
- if (options.security) {
293
- const secMod = await import("@rimelight/security")
294
- const { security: securityFn } = secMod as any
295
- const secOpts = typeof options.security === "object" ? options.security : {}
296
- const defaultImgSrc = imageDomains.map((d: string) =>
297
- d.startsWith("http://") || d.startsWith("https://") ? d : `https://${d}`
298
- )
299
- const imgSrc = secOpts.imgSrc
300
- ? Array.from(new Set([...defaultImgSrc, ...secOpts.imgSrc]))
301
- : defaultImgSrc
302
-
303
- plugins.push(
304
- securityFn({
305
- domain: secOpts.domain || domain,
306
- imgSrc,
307
- ...secOpts
308
- })
309
- )
310
- }
311
-
312
- if (options.i18n) {
313
- const i18nMod = await import("@rimelight/i18n")
314
- const { i18n: i18nFn } = i18nMod as any
315
- const i18nOpts = typeof options.i18n === "object" ? options.i18n : {}
316
- const translations = i18nOpts.translations || discoverTranslations()
317
- const locales = i18nOpts.locales || Object.keys(translations)
318
- const defaultLocale = i18nOpts.defaultLocale || (locales.length > 0 ? locales[0] : "en")
319
- const kvBinding =
320
- i18nOpts.kvBinding ||
321
- (domain ? `${domain.replaceAll(".", "-")}_translations` : undefined)
322
-
323
- plugins.push(
324
- i18nFn({
325
- locales,
326
- defaultLocale,
327
- prefixDefaultLocale: i18nOpts.prefixDefaultLocale ?? true,
328
- translations,
329
- ...(kvBinding ? { kvBinding } : {}),
330
- ...i18nOpts
331
- })
332
- )
333
- }
334
-
335
- if (options.ui) {
336
- const uiMod = await import("@rimelight/ui")
337
- const { ui: uiFn } = uiMod as any
338
- const uiOpts = typeof options.ui === "object" ? options.ui : {}
339
- const discoveredLogos = discoverLogos()
340
-
341
- const mergedLogos = uiOpts.logos
342
- ? { ...discoveredLogos, ...uiOpts.logos }
343
- : discoveredLogos
344
-
345
- const mergedShortcuts =
346
- uiOpts.shortcuts === false
347
- ? undefined
348
- : {
349
- ...defaultShortcuts(),
350
- ...(typeof uiOpts.shortcuts === "object" ? uiOpts.shortcuts : {})
351
- }
352
-
353
- plugins.push(
354
- uiFn({
355
- ...(mergedLogos ? { logos: mergedLogos } : {}),
356
- ...(mergedShortcuts ? { shortcuts: mergedShortcuts } : {}),
357
- ...uiOpts
358
- })
359
- )
360
- }
361
-
362
- updateConfig({
363
- integrations,
364
- vite: {
365
- plugins
366
- }
367
- })
368
- }
369
- }
370
- }
371
- }
372
-
373
- export function rimelightAstroConfig(options: RimelightAstroOptions = {}): any {
374
- const {
375
- domain,
376
- site = domain ? `https://${domain}` : undefined,
377
- imageDomains = domain ? [domain, `cdn.${domain}`, "cdn.rimelight.com"] : [],
378
- apiSwrSeconds = 600,
379
- pageMaxAgeSeconds = 300,
380
- adapter,
381
- cacheProvider,
382
- fonts,
383
- solid,
384
- security,
385
- i18n,
386
- cms,
387
- ui,
388
- seo,
389
- integrations = [],
390
- vite = {},
391
- ...rest
392
- } = options
393
-
394
- const hasFlags = Boolean(solid || security || i18n || cms || ui || seo)
395
-
396
- return {
397
- ...(site ? { site } : {}),
398
- prefetch: {
399
- prefetchAll: true
400
- },
401
- ...cloudflarePreset({
402
- ...(adapter !== undefined ? { adapter } : {}),
403
- ...(cacheProvider !== undefined ? { cacheProvider } : {})
404
- }),
405
- ...cacheRulesPreset({
406
- ...(apiSwrSeconds !== undefined ? { apiSwrSeconds } : {}),
407
- ...(pageMaxAgeSeconds !== undefined ? { pageMaxAgeSeconds } : {})
408
- }),
409
- ...fontsPreset(fonts !== undefined ? { fonts } : {}),
410
- ...imagePreset({ domains: imageDomains }),
411
- markdown: {
412
- syntaxHighlight: "prism" as const
413
- },
414
- integrations: [
415
- ...(hasFlags ? [rimelightIntegration(options, imageDomains, domain)] : []),
416
- ...integrations
417
- ],
418
- vite,
419
- ...rest
420
- }
421
- }
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import cloudflare from "@astrojs/cloudflare"
4
+ import { cacheCloudflare } from "@astrojs/cloudflare/cache"
5
+ import { fontProviders } from "astro/config"
6
+
7
+ export interface CacheRulesPresetOptions {
8
+ apiSwrSeconds?: number
9
+ pageMaxAgeSeconds?: number
10
+ customRules?: Record<string, any>
11
+ }
12
+
13
+ export function cacheRulesPreset(options: CacheRulesPresetOptions = {}): any {
14
+ const { apiSwrSeconds = 600, pageMaxAgeSeconds = 300, customRules = {} } = options
15
+ return {
16
+ routeRules: {
17
+ "/api/[...path]": {
18
+ swr: apiSwrSeconds
19
+ },
20
+ "/[...path]": {
21
+ maxAge: pageMaxAgeSeconds
22
+ },
23
+ ...customRules
24
+ }
25
+ }
26
+ }
27
+
28
+ export interface FontsPresetOptions {
29
+ fontProviders?: any
30
+ fonts?: any[]
31
+ }
32
+
33
+ export function fontsPreset(options: FontsPresetOptions = {}): any {
34
+ const defaultFonts = [
35
+ {
36
+ name: "Noto Sans",
37
+ cssVariable: "--font-sans",
38
+ fallbacks: ["sans-serif"],
39
+ subsets: ["latin", "latin-ext"],
40
+ weights: [400, 500, 600, 700],
41
+ styles: ["normal"]
42
+ },
43
+ {
44
+ name: "Noto Serif",
45
+ cssVariable: "--font-serif",
46
+ fallbacks: ["serif"],
47
+ subsets: ["latin", "latin-ext"],
48
+ weights: [400, 700],
49
+ styles: ["normal"]
50
+ },
51
+ {
52
+ name: "JetBrains Mono",
53
+ cssVariable: "--font-mono",
54
+ fallbacks: ["monospace"],
55
+ subsets: ["latin", "latin-ext"],
56
+ weights: [400, 500, 700],
57
+ styles: ["normal"]
58
+ }
59
+ ]
60
+
61
+ const provider = (options.fontProviders || fontProviders)?.fontsource
62
+ ? (options.fontProviders || fontProviders).fontsource()
63
+ : undefined
64
+
65
+ return {
66
+ fonts: (options.fonts || defaultFonts).map((font) => ({
67
+ ...(provider ? { provider } : {}),
68
+ ...font
69
+ }))
70
+ }
71
+ }
72
+
73
+ export interface ImagePresetOptions {
74
+ domains?: string[]
75
+ layout?: "constrained" | "fixed" | "full-width" | "responsive"
76
+ responsiveStyles?: boolean
77
+ }
78
+
79
+ export function imagePreset(options: ImagePresetOptions = {}): any {
80
+ const { domains = [], layout = "constrained", responsiveStyles = true } = options
81
+ return {
82
+ image: {
83
+ domains,
84
+ layout,
85
+ responsiveStyles
86
+ }
87
+ }
88
+ }
89
+
90
+ export interface CloudflarePresetOptions {
91
+ adapter?: any
92
+ cacheProvider?: any
93
+ session?: boolean
94
+ }
95
+
96
+ export function cloudflarePreset(options: CloudflarePresetOptions = {}): any {
97
+ const { adapter = cloudflare(), cacheProvider = cacheCloudflare(), session = false } = options
98
+ return {
99
+ output: "server" as const,
100
+ session,
101
+ adapter,
102
+ cache: { provider: cacheProvider }
103
+ }
104
+ }
105
+
106
+ export interface RimelightAstroOptions {
107
+ domain?: string
108
+ site?: string
109
+ imageDomains?: string[]
110
+ apiSwrSeconds?: number
111
+ pageMaxAgeSeconds?: number
112
+ adapter?: any
113
+ cacheProvider?: any
114
+ fonts?: any[]
115
+ solid?: boolean | { include?: string[]; [key: string]: any }
116
+ security?:
117
+ | boolean
118
+ | {
119
+ domain?: string
120
+ imgSrc?: string[]
121
+ directives?: Record<string, any>
122
+ [key: string]: any
123
+ }
124
+ i18n?:
125
+ | boolean
126
+ | {
127
+ translations?: Record<string, any>
128
+ locales?: string[]
129
+ defaultLocale?: string
130
+ prefixDefaultLocale?: boolean
131
+ kvBinding?: string
132
+ [key: string]: any
133
+ }
134
+ seo?:
135
+ | boolean
136
+ | {
137
+ robots?: boolean | Record<string, any>
138
+ sitemap?: boolean | Record<string, any>
139
+ rss?: boolean | Record<string, any>
140
+ llms?: boolean | Record<string, any>
141
+ llmsFull?: boolean | Record<string, any>
142
+ assets?: boolean | Record<string, any>
143
+ [key: string]: any
144
+ }
145
+ cms?:
146
+ | boolean
147
+ | {
148
+ storage?: any
149
+ binding?: string
150
+ auth?: string
151
+ [key: string]: any
152
+ }
153
+ ui?:
154
+ | boolean
155
+ | {
156
+ logos?: any
157
+ shortcuts?: any
158
+ [key: string]: any
159
+ }
160
+ integrations?: any[]
161
+ vite?: {
162
+ plugins?: any[]
163
+ [key: string]: any
164
+ }
165
+ [key: string]: any
166
+ }
167
+
168
+ function discoverTranslations(dir = "./src/i18n"): Record<string, any> {
169
+ const translations: Record<string, any> = {}
170
+ try {
171
+ const resolvedDir = path.resolve(process.cwd(), dir)
172
+ if (fs.existsSync(resolvedDir)) {
173
+ const files = fs.readdirSync(resolvedDir)
174
+ for (const file of files) {
175
+ if (file.endsWith(".json")) {
176
+ const locale = path.basename(file, ".json")
177
+ const content = JSON.parse(fs.readFileSync(path.join(resolvedDir, file), "utf8"))
178
+ translations[locale] = content
179
+ }
180
+ }
181
+ }
182
+ } catch {}
183
+ return translations
184
+ }
185
+
186
+ function discoverLogos(dir = "./src/assets/logos"): Record<string, any> | undefined {
187
+ try {
188
+ const candidateDirs = [dir, "./src/assets/logo"]
189
+ let resolvedDir: string | null = null
190
+ for (const d of candidateDirs) {
191
+ const p = path.resolve(process.cwd(), d)
192
+ if (fs.existsSync(p) && fs.statSync(p).isDirectory()) {
193
+ resolvedDir = p
194
+ break
195
+ }
196
+ }
197
+ if (!resolvedDir) return undefined
198
+
199
+ const files = fs.readdirSync(resolvedDir)
200
+ const logos: Record<string, any> = {}
201
+
202
+ const variants = ["logomark", "logotype", "logo"]
203
+ const modes = ["color", "white", "black", "light", "dark"]
204
+ const extensions = [".svg", ".png", ".webp", ".jpg", ".jpeg", ".gif"]
205
+
206
+ for (const variant of variants) {
207
+ for (const mode of modes) {
208
+ for (const ext of extensions) {
209
+ const fileName = `${variant}_${mode}${ext}`
210
+ if (files.includes(fileName)) {
211
+ if (!logos[variant]) logos[variant] = {}
212
+ const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
213
+ logos[variant][mode] = relPath
214
+ }
215
+ }
216
+ }
217
+ for (const ext of extensions) {
218
+ const fileName = `${variant}${ext}`
219
+ if (files.includes(fileName) && !logos[variant]) {
220
+ const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
221
+ logos[variant] = relPath
222
+ }
223
+ }
224
+ }
225
+
226
+ return Object.keys(logos).length > 0 ? logos : undefined
227
+ } catch {
228
+ return undefined
229
+ }
230
+ }
231
+
232
+ function defaultShortcuts(): Record<string, any> {
233
+ return {
234
+ categories: {
235
+ system: { label: "System" },
236
+ navigation: { label: "Navigation" }
237
+ }
238
+ }
239
+ }
240
+
241
+ function rimelightIntegration(
242
+ options: RimelightAstroOptions,
243
+ imageDomains: string[],
244
+ domain?: string
245
+ ) {
246
+ return {
247
+ name: "rimelight-auto-plugins",
248
+ hooks: {
249
+ "astro:config:setup": async ({ updateConfig }: { updateConfig: (config: any) => void }) => {
250
+ const integrations: any[] = []
251
+ const plugins: any[] = []
252
+
253
+ if (options.solid) {
254
+ const solidMod = await import("@astrojs/solid-js")
255
+ const solidFn = (solidMod as any).default || solidMod
256
+ const solidOpts =
257
+ typeof options.solid === "object"
258
+ ? options.solid
259
+ : { include: ["**/solid/**", "**/*.tsx"] }
260
+ integrations.push(solidFn(solidOpts))
261
+ }
262
+
263
+ if (options.seo) {
264
+ const seoMod = await import("@rimelight/seo")
265
+ const seoFn =
266
+ (seoMod as any).rimelightSeo ||
267
+ (seoMod as any).default?.rimelightSeo ||
268
+ (seoMod as any).default ||
269
+ seoMod
270
+ const seoOpts = typeof options.seo === "object" ? options.seo : {}
271
+ integrations.push(seoFn(seoOpts))
272
+ }
273
+
274
+ if (options.cms) {
275
+ const cmsMod = await import("@rimelight/cms/integration")
276
+ const { rimelightCms } = cmsMod as any
277
+ const cmsOpts = typeof options.cms === "object" ? options.cms : {}
278
+ let storage = cmsOpts.storage
279
+ if (!storage) {
280
+ const storageMod = await import("@rimelight/cms/storage")
281
+ const { r2 } = storageMod as any
282
+ storage = r2({ binding: cmsOpts.binding || "BLOB" })
283
+ }
284
+ integrations.push(
285
+ rimelightCms({
286
+ storage,
287
+ auth: cmsOpts.auth || "./src/auth/auth.ts",
288
+ ...cmsOpts
289
+ })
290
+ )
291
+ }
292
+
293
+ if (options.security) {
294
+ const secMod = await import("@rimelight/security")
295
+ const { security: securityFn } = secMod as any
296
+ const secOpts = typeof options.security === "object" ? options.security : {}
297
+ const defaultImgSrc = imageDomains.map((d: string) =>
298
+ d.startsWith("http://") || d.startsWith("https://") ? d : `https://${d}`
299
+ )
300
+ const imgSrc = secOpts.imgSrc
301
+ ? Array.from(new Set([...defaultImgSrc, ...secOpts.imgSrc]))
302
+ : defaultImgSrc
303
+
304
+ plugins.push(
305
+ securityFn({
306
+ domain: secOpts.domain || domain,
307
+ imgSrc,
308
+ ...secOpts
309
+ })
310
+ )
311
+ }
312
+
313
+ if (options.i18n) {
314
+ const i18nMod = await import("@rimelight/i18n")
315
+ const { i18n: i18nFn } = i18nMod as any
316
+ const i18nOpts = typeof options.i18n === "object" ? options.i18n : {}
317
+ const translations = i18nOpts.translations || discoverTranslations()
318
+ const locales = i18nOpts.locales || Object.keys(translations)
319
+ const defaultLocale = i18nOpts.defaultLocale || (locales.length > 0 ? locales[0] : "en")
320
+ const kvBinding =
321
+ i18nOpts.kvBinding ||
322
+ (domain ? `${domain.replaceAll(".", "-")}_translations` : undefined)
323
+
324
+ plugins.push(
325
+ i18nFn({
326
+ locales,
327
+ defaultLocale,
328
+ prefixDefaultLocale: i18nOpts.prefixDefaultLocale ?? true,
329
+ translations,
330
+ ...(kvBinding ? { kvBinding } : {}),
331
+ ...i18nOpts
332
+ })
333
+ )
334
+ }
335
+
336
+ if (options.ui) {
337
+ const uiMod = await import("@rimelight/ui")
338
+ const { ui: uiFn } = uiMod as any
339
+ const uiOpts = typeof options.ui === "object" ? options.ui : {}
340
+ const discoveredLogos = discoverLogos()
341
+
342
+ const mergedLogos = uiOpts.logos
343
+ ? { ...discoveredLogos, ...uiOpts.logos }
344
+ : discoveredLogos
345
+
346
+ const mergedShortcuts =
347
+ uiOpts.shortcuts === false
348
+ ? undefined
349
+ : {
350
+ ...defaultShortcuts(),
351
+ ...(typeof uiOpts.shortcuts === "object" ? uiOpts.shortcuts : {})
352
+ }
353
+
354
+ plugins.push(
355
+ uiFn({
356
+ ...(mergedLogos ? { logos: mergedLogos } : {}),
357
+ ...(mergedShortcuts ? { shortcuts: mergedShortcuts } : {}),
358
+ ...uiOpts
359
+ })
360
+ )
361
+ }
362
+
363
+ updateConfig({
364
+ integrations,
365
+ vite: {
366
+ plugins
367
+ }
368
+ })
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ export function rimelightAstroConfig(options: RimelightAstroOptions = {}): any {
375
+ const {
376
+ domain,
377
+ site = domain ? `https://${domain}` : undefined,
378
+ imageDomains = domain ? [domain, `cdn.${domain}`, "cdn.rimelight.com"] : [],
379
+ apiSwrSeconds = 600,
380
+ pageMaxAgeSeconds = 300,
381
+ adapter,
382
+ cacheProvider,
383
+ fonts,
384
+ solid,
385
+ security,
386
+ i18n,
387
+ cms,
388
+ ui,
389
+ seo,
390
+ integrations = [],
391
+ vite = {},
392
+ ...rest
393
+ } = options
394
+
395
+ const hasFlags = Boolean(solid || security || i18n || cms || ui || seo)
396
+
397
+ return {
398
+ ...(site ? { site } : {}),
399
+ prefetch: {
400
+ prefetchAll: true
401
+ },
402
+ ...cloudflarePreset({
403
+ ...(adapter !== undefined ? { adapter } : {}),
404
+ ...(cacheProvider !== undefined ? { cacheProvider } : {})
405
+ }),
406
+ ...cacheRulesPreset({
407
+ ...(apiSwrSeconds !== undefined ? { apiSwrSeconds } : {}),
408
+ ...(pageMaxAgeSeconds !== undefined ? { pageMaxAgeSeconds } : {})
409
+ }),
410
+ ...fontsPreset(fonts !== undefined ? { fonts } : {}),
411
+ ...imagePreset({ domains: imageDomains }),
412
+ markdown: {
413
+ syntaxHighlight: "prism" as const
414
+ },
415
+ integrations: [
416
+ ...(hasFlags ? [rimelightIntegration(options, imageDomains, domain)] : []),
417
+ ...integrations
418
+ ],
419
+ vite,
420
+ ...rest
421
+ }
422
+ }