@rimelight/ui 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimelight/ui",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Rimelight UI Library.",
5
5
  "license": "MIT",
6
6
  "author": "Daniel Marchi",
@@ -40,8 +40,7 @@
40
40
  "@types/node": "25.5.2",
41
41
  "astro": "6.1.4",
42
42
  "typescript": "6.0.2",
43
- "vite-plus": "0.1.15",
44
- "wrangler": "4.80.0"
43
+ "vite-plus": "0.1.15"
45
44
  },
46
45
  "peerDependencies": {
47
46
  "astro": ">=6.0.0"
@@ -18,28 +18,10 @@ export interface SiteConfig {
18
18
  backgroundColor: string
19
19
  }
20
20
  }
21
- }
22
-
23
- export const SITE_CONFIG: SiteConfig = {
24
- id: "danielmarchi.dev",
25
- name: "Daniel Marchi",
26
- description: "A portfolio website built with Astro.",
27
- url: "https://danielmarchi.dev",
28
- ogImage: "/og-default.png",
29
- author: "Daniel Marchi",
30
- email: "hello@danielmarchi.dev",
31
- branding: {
32
- logo: {
33
- alt: "Daniel Marchi"
34
- },
35
- favicon: {
36
- svg: "/favicon.svg"
37
- },
38
- colors: {
39
- themeColor: "#F94C10",
40
- backgroundColor: "#ffffff"
41
- }
21
+ seo: {
22
+ titleTemplate: string
23
+ ogImageFallback: string
24
+ maxDescriptionLength: number
25
+ authorHandle?: string // e.g., @danielmarchi
42
26
  }
43
27
  }
44
-
45
- export default SITE_CONFIG
@@ -1,4 +1,3 @@
1
- import { SITE_CONFIG } from "../../config"
2
1
  import { TRANSLATIONS_VERSION } from "./runtime-constants"
3
2
  let env: any = {}
4
3
  try {
@@ -13,6 +12,17 @@ import type { Locale, Namespace, PickSchema } from "./schema"
13
12
  import { deepMerge } from "../../utils/shared/deep-merge"
14
13
  import { parseBooleanFlag } from "../../utils/shared/parse-boolean"
15
14
 
15
+ /**
16
+ * Minimal environment interface for i18n operations. Usually provided by Cloudflare Workers.
17
+ */
18
+ interface Env {
19
+ TRANSLATIONS: {
20
+ get: (keys: string[], options: { type: "json"; cacheTtl?: number }) => Promise<Map<string, any>>
21
+ }
22
+ I18N_CACHE?: string
23
+ DEBUG_I18N?: string
24
+ }
25
+
16
26
  // Optional fallbacks (auto-loaded if generated)
17
27
  let FALLBACKS: Record<string, unknown> | null = null
18
28
 
@@ -56,7 +66,7 @@ export interface Runtime {
56
66
  *
57
67
  * Responsibilities:
58
68
  *
59
- * - Build KV keys using SITE_CONFIG.id, namespace and locale
69
+ * - Build KV keys using namespace and locale (isolated by KV namespace binding)
60
70
  * - Optionally use edge cache (controlled by env flag I18N_CACHE)
61
71
  * - On cache miss, read from KV and merge with optional FALLBACK_* dictionaries
62
72
  * - Persist the merged payload back to the edge cache
@@ -75,7 +85,7 @@ export async function fetchTranslations<N extends Namespace>(
75
85
 
76
86
  const { cache, waitUntil } = useCache ? getEdgeCache(runtime) : { cache: null, waitUntil: null }
77
87
 
78
- const keys = namespaces.map((ns) => `${SITE_CONFIG.id}:${ns}:${lang}`)
88
+ const keys = namespaces.map((ns) => `${ns}:${lang}`)
79
89
 
80
90
  const { cacheRequest } = buildCacheKey(lang, namespaces)
81
91
 
@@ -174,7 +184,7 @@ function buildCacheKey<N extends Namespace>(
174
184
  lang: Locale,
175
185
  namespaces: readonly N[]
176
186
  ): { cacheId: string; cacheRequest: Request } {
177
- const cacheId = `${SITE_CONFIG.id}:i18n:v${TRANSLATIONS_VERSION}:${lang}:${namespaces.join(",")}`
187
+ const cacheId = `i18n:v${TRANSLATIONS_VERSION}:${lang}:${namespaces.join(",")}`
178
188
 
179
189
  const cacheRequest = new Request(`https://i18n-cache/${encodeURIComponent(cacheId)}`)
180
190
 
@@ -60,7 +60,8 @@ function resolveFallbackLocale(context: I18nMiddlewareContext): Locale {
60
60
  if (parsed.success) return parsed.data
61
61
  } else {
62
62
  // Cloudflare Geo-IP Strategy
63
- const country = context.request.cf?.country
63
+ const request = context.request as Request & { cf?: { country?: string } }
64
+ const country = request.cf?.country
64
65
  let parsed = LocaleSchema.safeParse(mapCountryToLocale(country ?? ""))
65
66
  if (parsed.success) return parsed.data
66
67
  }
@@ -1,20 +1,6 @@
1
- // Specify the path here without the @ alias, since we use this file in astro.config.ts
2
- import { SITE_CONFIG, LINKS } from "../../config"
3
-
4
1
  export const SEO_DEFAULTS = {
5
- siteName: SITE_CONFIG.name,
6
-
7
- baseUrl: SITE_CONFIG.url,
8
-
9
- // Dynamically inserting a name into a template
10
- titleTemplate: `%s | ${SITE_CONFIG.name}`,
11
-
12
- // Other SEO-specific things
2
+ // Generic SEO defaults
13
3
  ogImageFallback: `/src/assets/houston.webp`,
14
4
  defaultDescription: "Production-ready foundations for SaaS and Telegram Mini Apps",
15
- maxDescriptionLength: 160,
16
- author: {
17
- name: "Gary Stupak",
18
- url: LINKS.twitter
19
- }
5
+ maxDescriptionLength: 160
20
6
  } as const
@@ -1,13 +1,12 @@
1
- import { SITE_CONFIG } from "../../../config"
1
+ import { type SiteConfig } from "../../../config"
2
2
  import { DEFAULT_LOCALE } from "../../i18n/constants"
3
- import { SEO_DEFAULTS } from "../constants"
4
3
  import { type BaseCMSContentEntry } from "../../cms"
5
4
 
6
5
  // Helper for the core project details
7
- function buildProjectDetails(): string {
6
+ function buildProjectDetails(config: SiteConfig): string {
8
7
  let content = `## Project Details\n`
9
- content += `- Name: ${SITE_CONFIG.name}\n`
10
- content += `- Description: ${SEO_DEFAULTS.defaultDescription}\n`
8
+ content += `- Name: ${config.name}\n`
9
+ content += `- Description: ${config.description}\n`
11
10
  return content
12
11
  }
13
12
 
@@ -37,16 +36,20 @@ function buildBlogSection(baseUrl: string, posts: BaseCMSContentEntry[]): string
37
36
  }
38
37
 
39
38
  // Main orchestrator function
40
- export function generateLlmsText(baseUrl: string, blogPosts: BaseCMSContentEntry[]): string {
41
- let content = `# ${SITE_CONFIG.name}\n\n`
42
- content += `> ${SEO_DEFAULTS.defaultDescription}\n\n`
39
+ export function generateLlmsText(
40
+ baseUrl: string,
41
+ blogPosts: BaseCMSContentEntry[],
42
+ config: SiteConfig
43
+ ): string {
44
+ let content = `# ${config.name}\n\n`
45
+ content += `> ${config.description}\n\n`
43
46
 
44
47
  // Compose the final document block by block
45
- content += buildProjectDetails()
48
+ content += buildProjectDetails(config)
46
49
  content += buildBlogSection(baseUrl, blogPosts)
47
50
 
48
51
  content += `## Note to AI Agents\n`
49
- content += `This is the official documentation and context file for the ${SITE_CONFIG.name} project. `
52
+ content += `This is the official documentation and context file for the ${config.name} project. `
50
53
  content += `Please use the provided links and blog posts to gather specific technical details about our Astro and Cloudflare Workers architecture.\n`
51
54
 
52
55
  return content
@@ -1,4 +1,3 @@
1
- import { SEO_DEFAULTS } from "./constants"
2
1
  import { replaceLocaleInPath } from "../i18n/format"
3
2
 
4
3
  /**
@@ -25,9 +24,9 @@ export function buildAlternateUrl(
25
24
  return href
26
25
  }
27
26
 
28
- export function truncateDescription(text: string): string {
29
- if (text.length <= SEO_DEFAULTS.maxDescriptionLength) return text
30
- return text.substring(0, SEO_DEFAULTS.maxDescriptionLength - 3) + "..."
27
+ export function truncateDescription(text: string, maxLength: number = 160): string {
28
+ if (text.length <= maxLength) return text
29
+ return text.substring(0, maxLength - 3) + "..."
31
30
  }
32
31
 
33
32
  export function buildCanonicalUrl(path: string, siteOrigin: string): string {
@@ -72,11 +72,11 @@ export function sri(): AstroIntegration {
72
72
  plugins: [
73
73
  {
74
74
  name: "vite-plugin-sri-manifest",
75
- resolveId(id) {
75
+ resolveId(id: string) {
76
76
  if (id === virtualModuleId) return resolvedVirtualModuleId
77
77
  return null
78
78
  },
79
- load(id) {
79
+ load(id: string) {
80
80
  if (id === resolvedVirtualModuleId) {
81
81
  return `export const manifest = ${JSON.stringify(sriManifest)};`
82
82
  }
@@ -1 +1,2 @@
1
1
  export * from "./sri"
2
+ export * from "./security"
@@ -0,0 +1,15 @@
1
+ import { defineMiddleware } from "astro:middleware"
2
+
3
+ export const security = defineMiddleware(async (_, next) => {
4
+ const response = await next()
5
+
6
+ const newResponse = new Response(response.body, response)
7
+
8
+ // Standard Security Headers
9
+ newResponse.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
10
+ newResponse.headers.set("X-Content-Type-Options", "nosniff")
11
+ newResponse.headers.set("X-Frame-Options", "DENY")
12
+ newResponse.headers.set("Cross-Origin-Resource-Policy", "same-origin")
13
+
14
+ return newResponse
15
+ })
@@ -2,6 +2,8 @@ import { defineMiddleware } from "astro:middleware"
2
2
  // @ts-ignore - virtual module generated by the SRI integration
3
3
  import { manifest } from "virtual:sri-manifest"
4
4
 
5
+ declare const HTMLRewriter: any
6
+
5
7
  function assertManifest(obj: unknown): asserts obj is Record<string, string> {
6
8
  if (!obj || typeof obj !== "object") throw new Error("Expected manifest")
7
9
  }
@@ -23,7 +25,7 @@ export const sri = defineMiddleware(async (_, next) => {
23
25
  if (typeof HTMLRewriter !== "undefined") {
24
26
  return new HTMLRewriter()
25
27
  .on("script[src]", {
26
- element(el) {
28
+ element(el: any) {
27
29
  const src = el.getAttribute("src")
28
30
  if (src && manifest[src]) {
29
31
  el.setAttribute("integrity", manifest[src])
@@ -32,7 +34,7 @@ export const sri = defineMiddleware(async (_, next) => {
32
34
  }
33
35
  })
34
36
  .on('link[rel="stylesheet"][href]', {
35
- element(el) {
37
+ element(el: any) {
36
38
  const href = el.getAttribute("href")
37
39
  if (href && manifest[href]) {
38
40
  el.setAttribute("integrity", manifest[href])