@rimelight/cms 0.0.2 → 0.0.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 (112) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +16 -14
  3. package/src/admin/api/media-file.ts +39 -0
  4. package/src/admin/api/media.ts +199 -0
  5. package/src/admin/layouts/CMSDashboardLayout.astro +178 -0
  6. package/src/admin/layouts/DefaultParentLayout.astro +50 -0
  7. package/src/admin/pages/assets.astro +424 -0
  8. package/src/admin/pages/byline-schema.astro +62 -0
  9. package/src/admin/pages/bylines.astro +16 -0
  10. package/src/admin/pages/categories.astro +21 -0
  11. package/src/admin/pages/content-types.astro +55 -0
  12. package/src/admin/pages/dashboard.astro +61 -0
  13. package/src/admin/pages/pages-edit.astro +595 -0
  14. package/src/admin/pages/pages-index.astro +146 -0
  15. package/src/admin/pages/pages-new.astro +130 -0
  16. package/src/admin/pages/pages-preview.astro +111 -0
  17. package/src/admin/pages/pages-review.astro +236 -0
  18. package/src/admin/pages/settings.astro +203 -0
  19. package/src/admin/pages/tags.astro +21 -0
  20. package/src/admin/pages/templates-edit.astro +234 -0
  21. package/src/admin/pages/templates-index.astro +95 -0
  22. package/src/admin/pages/templates-new.astro +193 -0
  23. package/src/admin/pages/users.astro +74 -0
  24. package/src/admin/pages/versions.astro +74 -0
  25. package/src/astro/BlockRenderer.astro +44 -102
  26. package/src/astro/PageRenderer.astro +9 -2
  27. package/src/astro/blocks/CalloutBlock.astro +7 -7
  28. package/src/astro/blocks/CardBlock.astro +5 -5
  29. package/src/astro/blocks/CodeBlock.astro +2 -2
  30. package/src/astro/blocks/FileTreeBlock.astro +7 -7
  31. package/src/astro/blocks/ImageBlock.astro +2 -2
  32. package/src/astro/blocks/OrderedListBlock.astro +2 -2
  33. package/src/astro/blocks/ParagraphBlock.astro +3 -3
  34. package/src/astro/blocks/SectionBlock.astro +6 -6
  35. package/src/astro/blocks/StepItemBlock.astro +3 -3
  36. package/src/astro/blocks/StepsBlock.astro +1 -1
  37. package/src/astro/blocks/TableBlock.astro +6 -6
  38. package/src/astro/blocks/TabsBlock.astro +9 -9
  39. package/src/astro/blocks/UnorderedListBlock.astro +2 -2
  40. package/src/astro/blocks/index.ts +35 -0
  41. package/src/client/components/RimelightBlock.tsx +19 -19
  42. package/src/client/components/RimelightBlockPicker.tsx +9 -13
  43. package/src/client/components/RimelightBylinesManager.tsx +438 -0
  44. package/src/client/components/RimelightEditor.tsx +3 -3
  45. package/src/client/components/RimelightPreview.tsx +37 -45
  46. package/src/client/components/RimelightPropertiesPanel.tsx +368 -26
  47. package/src/client/components/RimelightTaxonomyManager.tsx +369 -0
  48. package/src/client/components/RimelightTaxonomyMasterDetail.tsx +412 -0
  49. package/src/client/components/RimelightTemplateEditor.tsx +6 -8
  50. package/src/client/components/editors/CalloutEditor.tsx +2 -4
  51. package/src/client/components/editors/CardsEditor.tsx +2 -4
  52. package/src/client/components/editors/CodeEditor.tsx +1 -3
  53. package/src/client/components/editors/FileTreeEditor.tsx +2 -4
  54. package/src/client/components/editors/ImageEditor.tsx +3 -3
  55. package/src/client/components/editors/ParagraphEditor.tsx +2 -2
  56. package/src/client/components/editors/SceneEditor.tsx +6 -12
  57. package/src/client/components/editors/ScriptEditor.tsx +8 -16
  58. package/src/client/components/editors/SectionEditor.tsx +4 -4
  59. package/src/client/components/editors/StepItemEditor.tsx +2 -2
  60. package/src/client/components/editors/StepsEditor.tsx +2 -4
  61. package/src/client/components/editors/TabItemEditor.tsx +3 -3
  62. package/src/client/components/editors/TableEditor.tsx +5 -5
  63. package/src/client/components/editors/TabsEditor.tsx +2 -4
  64. package/src/client/components/index.ts +3 -0
  65. package/src/client/loader.ts +3 -0
  66. package/src/core/diff.ts +145 -0
  67. package/src/core/excerpt.ts +159 -0
  68. package/src/core/preview.ts +87 -0
  69. package/src/core/registry.ts +0 -86
  70. package/src/core/types/blocks.ts +6 -1
  71. package/src/core/types/bylines.ts +14 -0
  72. package/src/core/types/media.ts +13 -0
  73. package/src/core/types/taxonomies.ts +20 -0
  74. package/src/cron/scheduled.ts +57 -0
  75. package/src/docs/agent.ts +116 -0
  76. package/src/docs/config.ts +25 -0
  77. package/src/docs/index.ts +5 -0
  78. package/src/docs/routing.ts +104 -0
  79. package/src/docs/sidebar.ts +251 -0
  80. package/src/docs/toc.ts +47 -0
  81. package/src/env.d.ts +13 -0
  82. package/src/index.ts +40 -8
  83. package/src/integration.ts +196 -0
  84. package/src/loader/live.ts +254 -0
  85. package/src/markdown/index.ts +0 -1
  86. package/src/mcp/index.ts +228 -0
  87. package/src/schema/bylines.ts +23 -0
  88. package/src/schema/index.ts +3 -4
  89. package/src/schema/page_versions.ts +2 -0
  90. package/src/schema/pages.ts +2 -0
  91. package/src/schema/site_settings.ts +41 -0
  92. package/src/schema/taxonomies.ts +49 -0
  93. package/src/services/bylines.ts +74 -0
  94. package/src/services/search-indexer.ts +61 -0
  95. package/src/services/site-settings.ts +108 -0
  96. package/src/services/taxonomies.ts +276 -0
  97. package/src/storage/index.ts +253 -0
  98. package/src/astro/blocks/ApiDocumentationBlock.astro +0 -350
  99. package/src/astro/blocks/DialogueBlock.astro +0 -23
  100. package/src/astro/blocks/LivePreviewBlock.astro +0 -27
  101. package/src/astro/blocks/SceneBlock.astro +0 -65
  102. package/src/astro/blocks/ScriptBlock.astro +0 -59
  103. package/src/core/template-sync.ts +0 -75
  104. package/src/markdown/parser.ts +0 -347
  105. package/src/migration-tools.ts +0 -334
  106. package/src/migration.ts +0 -155
  107. package/src/schema/component_dependencies.ts +0 -21
  108. package/src/schema/component_metadata.ts +0 -31
  109. package/src/schema/component_metadata_cache.ts +0 -15
  110. package/src/schema/component_versions.ts +0 -19
  111. package/src/search/sync.ts +0 -32
  112. package/src/services/component-metadata.ts +0 -134
@@ -1,334 +0,0 @@
1
- import type { BaseBlock, ComponentShowcaseBlock } from "./core/types/blocks.ts"
2
-
3
- export interface ComponentReference {
4
- componentName: string
5
- componentPath: string
6
- framework: "astro" | "vue" | "solid"
7
- propsConfig: Record<string, string[]> | undefined
8
- defaultProps: Record<string, any> | undefined
9
- togglingPattern: "icon" | "select-option" | "tab-segmented" | "pill-toggle" | undefined
10
- codeExamples: {
11
- astro?: string
12
- vue?: string
13
- solid?: string
14
- } | undefined
15
- playgroundUrl: string | undefined
16
- }
17
-
18
- export interface MigrationReport {
19
- totalFiles: number
20
- migratedFiles: number
21
- totalComponentShowcases: number
22
- migratedComponentShowcases: number
23
- errors: string[]
24
- warnings: string[]
25
- }
26
-
27
- export interface ValidationResult {
28
- valid: boolean
29
- errors: string[]
30
- warnings: string[]
31
- }
32
-
33
- export class MigrationTools {
34
- convertMDXToBlocks(mdxContent: string): BaseBlock[] {
35
- const blocks: BaseBlock[] = []
36
- const lines = mdxContent.split("\n")
37
- let i = 0
38
-
39
- while (i < lines.length) {
40
- const line = lines[i] || ""
41
- const trimmed = line.trim()
42
-
43
- if (!trimmed) {
44
- i++
45
- continue
46
- }
47
-
48
- if (trimmed.startsWith("```")) {
49
- const lang = trimmed.slice(3).trim()
50
- const codeLines: string[] = []
51
- i++
52
- while (i < lines.length && !(lines[i] || "").trim().startsWith("```")) {
53
- codeLines.push(lines[i] || "")
54
- i++
55
- }
56
- i++
57
- blocks.push({
58
- id: crypto.randomUUID(),
59
- type: "CodeBlock",
60
- props: {
61
- language: lang || "text",
62
- code: codeLines.join("\n"),
63
- caption: ""
64
- }
65
- })
66
- continue
67
- }
68
-
69
- if (trimmed.startsWith("#")) {
70
- const match = line.match(/^(#{1,6})\s(.*)$/)
71
- if (match) {
72
- const level = Math.min(6, Math.max(2, match[1]!.length)) as 2 | 3 | 4 | 5 | 6
73
- blocks.push({
74
- id: crypto.randomUUID(),
75
- type: "SectionBlock",
76
- props: {
77
- title: match[2] || "",
78
- level,
79
- description: "",
80
- children: []
81
- },
82
- children: []
83
- })
84
- i++
85
- continue
86
- }
87
- }
88
-
89
- if (trimmed.startsWith(">")) {
90
- const calloutLines: string[] = []
91
- while (i < lines.length && (lines[i] || "").trim().startsWith(">")) {
92
- calloutLines.push((lines[i] || "").trim().replace(/^>\s?/, ""))
93
- i++
94
- }
95
- const firstLine = calloutLines[0] || ""
96
- const variantMatch = firstLine.match(/^\[!([A-Z]+)\]/i)
97
- const variant = variantMatch ? (variantMatch[1] || "info").toLowerCase() : "info"
98
-
99
- blocks.push({
100
- id: crypto.randomUUID(),
101
- type: "CalloutBlock",
102
- props: {
103
- variant: variant as "info" | "success" | "warning" | "error" | "commentary" | "ideation" | "source",
104
- children: []
105
- },
106
- children: []
107
- })
108
- continue
109
- }
110
-
111
- if (trimmed.startsWith("|") && trimmed.endsWith("|")) {
112
- const tableLines: string[] = []
113
- while (i < lines.length && (lines[i] || "").trim().startsWith("|") && (lines[i] || "").trim().endsWith("|")) {
114
- tableLines.push(lines[i] || "")
115
- i++
116
- }
117
- const tableBlock = this.parseMarkdownTable(tableLines.join("\n"))
118
- if (tableBlock) {
119
- blocks.push(tableBlock)
120
- continue
121
- }
122
- }
123
-
124
- if (trimmed.startsWith("!")) {
125
- const imageMatch = trimmed.match(/^!\[([^\]]*)\]\(([^)]+)\)$/)
126
- if (imageMatch) {
127
- blocks.push({
128
- id: crypto.randomUUID(),
129
- type: "ImageBlock",
130
- props: {
131
- alt: imageMatch[1] || "",
132
- src: imageMatch[2] || "",
133
- caption: ""
134
- }
135
- })
136
- i++
137
- continue
138
- }
139
- }
140
-
141
- const paragraphLines: string[] = []
142
- while (
143
- i < lines.length &&
144
- (lines[i] || "").trim() &&
145
- !(lines[i] || "").trim().startsWith("```") &&
146
- !(lines[i] || "").trim().startsWith("#") &&
147
- !(lines[i] || "").trim().startsWith(">") &&
148
- !((lines[i] || "").trim().startsWith("|") && (lines[i] || "").trim().endsWith("|"))
149
- ) {
150
- paragraphLines.push(lines[i] || "")
151
- i++
152
- }
153
-
154
- if (paragraphLines.length > 0) {
155
- blocks.push({
156
- id: crypto.randomUUID(),
157
- type: "ParagraphBlock",
158
- props: {
159
- text: { en: paragraphLines.join(" ").trim() }
160
- }
161
- })
162
- } else {
163
- i++
164
- }
165
- }
166
-
167
- return blocks
168
- }
169
-
170
- extractComponentReferences(mdxContent: string): ComponentReference[] {
171
- const references: ComponentReference[] = []
172
- const componentRegex = /<ComponentShowcase[^>]*>/g
173
- let match: RegExpExecArray | null
174
-
175
- while ((match = componentRegex.exec(mdxContent)) !== null) {
176
- const tag = match[0]
177
- const componentNameMatch = tag.match(/componentName=["']([^"']+)["']/)
178
- const componentPathMatch = tag.match(/componentPath=["']([^"']+)["']/)
179
- const frameworkMatch = tag.match(/framework=["']([^"']+)["']/)
180
- const propsConfigMatch = tag.match(/propsConfig=\{\{([^}]+)\}\}/)
181
- const defaultPropsMatch = tag.match(/defaultProps=\{\{([^}]+)\}\}/)
182
- const togglingPatternMatch = tag.match(/togglingPattern=["']([^"']+)["']/)
183
-
184
- references.push({
185
- componentName: componentNameMatch?.[1] || "unknown",
186
- componentPath: componentPathMatch?.[1] || "",
187
- framework: (frameworkMatch?.[1] as "astro" | "vue" | "solid") || "astro",
188
- propsConfig: propsConfigMatch?.[1] ? this.parseSimpleObject(propsConfigMatch[1]) : undefined,
189
- defaultProps: defaultPropsMatch?.[1] ? this.parseSimpleObject(defaultPropsMatch[1]) : undefined,
190
- togglingPattern: togglingPatternMatch?.[1] as "icon" | "select-option" | "tab-segmented" | "pill-toggle" || "tab-segmented",
191
- codeExamples: undefined,
192
- playgroundUrl: undefined
193
- })
194
- }
195
-
196
- return references
197
- }
198
-
199
- validateMigratedContent(blocks: BaseBlock[]): ValidationResult {
200
- const errors: string[] = []
201
- const warnings: string[] = []
202
-
203
- const seenIds = new Set<string>()
204
- const blockCounts: Record<string, number> = {}
205
-
206
- function checkBlocks(nodes: BaseBlock[]) {
207
- for (const b of nodes) {
208
- if (!b.id || typeof b.id !== "string") {
209
- errors.push(`Block of type '${b.type}' missing id`)
210
- } else if (seenIds.has(b.id)) {
211
- warnings.push(`Duplicate block id: ${b.id}`)
212
- } else {
213
- seenIds.add(b.id)
214
- }
215
-
216
- if (!b.type || typeof b.type !== "string") {
217
- errors.push("Block missing valid 'type' field")
218
- }
219
-
220
- blockCounts[b.type] = (blockCounts[b.type] || 0) + 1
221
-
222
- if (b.children && Array.isArray(b.children)) {
223
- checkBlocks(b.children)
224
- }
225
- }
226
- }
227
-
228
- checkBlocks(blocks)
229
-
230
- return {
231
- valid: errors.length === 0,
232
- errors,
233
- warnings
234
- }
235
- }
236
-
237
- generateMigrationReport(original: string, migrated: BaseBlock[]): MigrationReport {
238
- const componentRefs = this.extractComponentReferences(original)
239
- const validation = this.validateMigratedContent(migrated)
240
-
241
- return {
242
- totalFiles: 1,
243
- migratedFiles: validation.valid ? 1 : 0,
244
- totalComponentShowcases: componentRefs.length,
245
- migratedComponentShowcases: componentRefs.length,
246
- errors: validation.errors,
247
- warnings: validation.warnings
248
- }
249
- }
250
-
251
- convertComponentShowcaseToBlock(ref: ComponentReference): ComponentShowcaseBlock {
252
- return {
253
- id: crypto.randomUUID(),
254
- type: "ComponentShowcaseBlock",
255
- props: {
256
- componentName: ref.componentName,
257
- componentPath: ref.componentPath,
258
- framework: ref.framework,
259
- defaultProps: ref.defaultProps || {},
260
- propsConfig: ref.propsConfig || {},
261
- togglingPattern: ref.togglingPattern || "tab-segmented",
262
- codeExamples: ref.codeExamples || {},
263
- playgroundUrl: ref.playgroundUrl
264
- },
265
- children: []
266
- }
267
- }
268
-
269
- private parseSimpleObject(str: string): Record<string, any> {
270
- try {
271
- return new Function(`return ${str}`)()
272
- } catch {
273
- return {}
274
- }
275
- }
276
-
277
- private parseMarkdownTable(tableText: string): BaseBlock | null {
278
- const lines = tableText
279
- .trim()
280
- .split("\n")
281
- .map((l) => l.trim())
282
- .filter(Boolean)
283
- if (lines.length < 2) return null
284
-
285
- const parseRow = (line: string) =>
286
- line
287
- .replace(/^\|/, "")
288
- .replace(/\|$/, "")
289
- .split("|")
290
- .map((c) => c.trim())
291
-
292
- const headerCells = parseRow(lines[0] || "")
293
- const alignCells = parseRow(lines[1] || "")
294
-
295
- if (!alignCells.every((c) => /^[:-]+$/.test(c))) {
296
- return null
297
- }
298
-
299
- const columns = headerCells.map((header, idx) => {
300
- const alignStr = alignCells[idx] || ""
301
- let align: "left" | "center" | "right" = "left"
302
- if (alignStr.startsWith(":") && alignStr.endsWith(":")) {
303
- align = "center"
304
- } else if (alignStr.endsWith(":")) {
305
- align = "right"
306
- }
307
- return {
308
- key: `col_${idx}`,
309
- header,
310
- align
311
- }
312
- })
313
-
314
- const rows: Record<string, string>[] = []
315
- for (let i = 2; i < lines.length; i++) {
316
- const cells = parseRow(lines[i] || "")
317
- const rowObj: Record<string, string> = {}
318
- columns.forEach((col, idx) => {
319
- rowObj[col.key] = cells[idx] || ""
320
- })
321
- rows.push(rowObj)
322
- }
323
-
324
- return {
325
- id: crypto.randomUUID(),
326
- type: "TableBlock",
327
- props: {
328
- columns,
329
- rows,
330
- caption: ""
331
- }
332
- }
333
- }
334
- }
package/src/migration.ts DELETED
@@ -1,155 +0,0 @@
1
- import { sql } from "drizzle-orm"
2
- import { markdownToBlocks } from "./markdown/parser.ts"
3
- import type { BaseBlock } from "./core/types/blocks"
4
-
5
- export interface DocMigrationInput {
6
- slug: string
7
- title: string | Record<string, string>
8
- description?: string | Record<string, string>
9
- markdown: string
10
- properties?: Record<string, any>
11
- postedAt?: Date | null
12
- authorIds?: string[]
13
- }
14
-
15
- export function parseMarkdownWithFrontmatter(raw: string): {
16
- frontmatter: Record<string, any>
17
- body: string
18
- } {
19
- const frontmatter: Record<string, any> = {}
20
- const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/)
21
-
22
- if (!match) {
23
- return { frontmatter, body: raw.trim() }
24
- }
25
-
26
- const yamlBlock = match[1] || ""
27
- const body = (match[2] || "").trim()
28
-
29
- const lines = yamlBlock.split(/\r?\n/)
30
- for (const line of lines) {
31
- const trimmed = line.trim()
32
- if (!trimmed || trimmed.startsWith("#")) continue
33
- const colonIndex = trimmed.indexOf(":")
34
- if (colonIndex !== -1) {
35
- const key = trimmed.slice(0, colonIndex).trim()
36
- let value: any = trimmed.slice(colonIndex + 1).trim()
37
-
38
- if (value === "true") value = true
39
- else if (value === "false") value = false
40
- else if (value === "null") value = null
41
- else if (!isNaN(Number(value)) && value !== "") value = Number(value)
42
- else if (
43
- (value.startsWith('"') && value.endsWith('"')) ||
44
- (value.startsWith("'") && value.endsWith("'"))
45
- ) {
46
- value = value.slice(1, -1)
47
- }
48
-
49
- frontmatter[key] = value
50
- }
51
- }
52
-
53
- return { frontmatter, body }
54
- }
55
-
56
- export function convertMarkdownDocToPageRecord(input: DocMigrationInput) {
57
- const blocks: BaseBlock[] = markdownToBlocks(input.markdown)
58
- const titleObj =
59
- typeof input.title === "string" ? { en: input.title } : input.title || { en: input.slug }
60
- const descObj =
61
- typeof input.description === "string"
62
- ? { en: input.description }
63
- : input.description || undefined
64
-
65
- return {
66
- id: crypto.randomUUID(),
67
- slug: input.slug,
68
- type: "doc" as const,
69
- title: titleObj,
70
- description: descObj,
71
- tags: [],
72
- authorIds: input.authorIds || [],
73
- postedAt: input.postedAt !== undefined ? input.postedAt : new Date(),
74
- createdAt: new Date(),
75
- updatedAt: new Date(),
76
- content: {
77
- blocks,
78
- properties: input.properties || {}
79
- }
80
- }
81
- }
82
-
83
- export async function migrateLegacyPagesToCMSv2(db: any) {
84
- console.log("[Migration] Applying DDL schema updates...")
85
-
86
- await db.execute(sql`
87
- ALTER TABLE pages ADD COLUMN IF NOT EXISTS template_id UUID;
88
- ALTER TABLE pages ADD COLUMN IF NOT EXISTS template_version INTEGER DEFAULT 1 NOT NULL;
89
- ALTER TABLE page_versions ADD COLUMN IF NOT EXISTS version_number INTEGER DEFAULT 1 NOT NULL;
90
-
91
- CREATE UNIQUE INDEX IF NOT EXISTS page_versions_page_id_version_idx
92
- ON page_versions (page_id, version_number);
93
- `)
94
-
95
- console.log("[Migration] Transforming legacy page content in chunked batches...")
96
-
97
- const BATCH_SIZE = 100
98
- let offset = 0
99
-
100
- async function fetchBatch(currentOffset: number) {
101
- const batch = await db.execute(sql`
102
- SELECT id, content FROM pages ORDER BY id LIMIT ${BATCH_SIZE} OFFSET ${currentOffset};
103
- `)
104
-
105
- if (!batch || !batch.rows || batch.rows.length === 0) {
106
- return null
107
- }
108
-
109
- const rows: Array<{ id: string; content: unknown }> = batch.rows
110
- return rows
111
- }
112
-
113
- async function processBatch(pagesList: Array<{ id: string; content: unknown }>) {
114
- const updatePromises = pagesList.map((page) => {
115
- const transformed = transformLegacyContent(page.content)
116
- return db.execute(sql`
117
- UPDATE pages SET content = ${JSON.stringify(transformed)}::jsonb WHERE id = ${page.id}::uuid;
118
- `)
119
- })
120
-
121
- await Promise.all(updatePromises)
122
- }
123
-
124
- async function processAllBatches(currentOffset: number): Promise<void> {
125
- const pagesList = await fetchBatch(currentOffset)
126
- if (!pagesList) return
127
- await processBatch(pagesList)
128
- console.log(`[Migration] Migrated ${currentOffset + BATCH_SIZE} records...`)
129
- return processAllBatches(currentOffset + BATCH_SIZE)
130
- }
131
-
132
- await processAllBatches(offset)
133
-
134
- console.log("[Migration] Migration completed successfully.")
135
- }
136
-
137
- export function transformLegacyContent(raw: unknown) {
138
- if (typeof raw === "object" && raw !== null && "blocks" in raw) return raw
139
- let textContent = ""
140
- try {
141
- textContent = typeof raw === "string" ? raw : JSON.stringify(raw ?? "")
142
- } catch {
143
- textContent = ""
144
- }
145
- return {
146
- blocks: [
147
- {
148
- id: crypto.randomUUID(),
149
- type: "ParagraphBlock",
150
- props: { text: { en: textContent } }
151
- }
152
- ],
153
- properties: {}
154
- }
155
- }
@@ -1,21 +0,0 @@
1
- import { pgTable, text, uuid, uniqueIndex } from "drizzle-orm/pg-core"
2
-
3
- export const componentDependencies = pgTable(
4
- "component_dependencies",
5
- {
6
- id: uuid("id").defaultRandom().notNull().primaryKey(),
7
- sourceComponent: text("source_component").notNull(),
8
- targetComponent: text("target_component").notNull(),
9
- dependencyType: text("dependency_type").notNull()
10
- },
11
- (table) => [
12
- uniqueIndex("component_dependencies_unique_idx").on(
13
- table.sourceComponent,
14
- table.targetComponent,
15
- table.dependencyType
16
- )
17
- ]
18
- )
19
-
20
- export type ComponentDependency = typeof componentDependencies.$inferSelect
21
- export type NewComponentDependency = typeof componentDependencies.$inferInsert
@@ -1,31 +0,0 @@
1
- import {
2
- pgTable,
3
- text,
4
- timestamp,
5
- uuid,
6
- uniqueIndex,
7
- jsonb
8
- } from "drizzle-orm/pg-core"
9
-
10
- export const componentMetadata = pgTable(
11
- "component_metadata",
12
- {
13
- id: uuid("id").defaultRandom().notNull().primaryKey(),
14
- componentName: text("component_name").notNull(),
15
- version: text("version").notNull(),
16
- framework: text("framework").notNull(),
17
- filePath: text("file_path").notNull(),
18
- props: jsonb("props").$type<Record<string, any>>().notNull(),
19
- slots: jsonb("slots").$type<Record<string, any>>().notNull(),
20
- emits: jsonb("emits").$type<Record<string, any>>().notNull(),
21
- theme: jsonb("theme").$type<Record<string, any>>(),
22
- extractedAt: timestamp("extracted_at", { withTimezone: true }).defaultNow().notNull(),
23
- updatedAt: timestamp("updated_at", { withTimezone: true }).$onUpdate(() => new Date())
24
- },
25
- (table) => [
26
- uniqueIndex("component_metadata_name_version_idx").on(table.componentName, table.version)
27
- ]
28
- )
29
-
30
- export type ComponentMetadata = typeof componentMetadata.$inferSelect
31
- export type NewComponentMetadata = typeof componentMetadata.$inferInsert
@@ -1,15 +0,0 @@
1
- import { pgTable, text, timestamp, jsonb, index } from "drizzle-orm/pg-core"
2
-
3
- export const componentMetadataCache = pgTable(
4
- "component_metadata_cache",
5
- {
6
- componentName: text("component_name").primaryKey(),
7
- metadata: jsonb("metadata").$type<Record<string, any>>().notNull(),
8
- cacheKey: text("cache_key").notNull(),
9
- expiresAt: timestamp("expires_at", { withTimezone: true }).notNull()
10
- },
11
- (table) => [index("component_metadata_cache_expires_idx").on(table.expiresAt)]
12
- )
13
-
14
- export type ComponentMetadataCache = typeof componentMetadataCache.$inferSelect
15
- export type NewComponentMetadataCache = typeof componentMetadataCache.$inferInsert
@@ -1,19 +0,0 @@
1
- import { pgTable, text, timestamp, uuid, uniqueIndex } from "drizzle-orm/pg-core"
2
-
3
- export const componentVersions = pgTable(
4
- "component_versions",
5
- {
6
- id: uuid("id").defaultRandom().notNull().primaryKey(),
7
- componentName: text("component_name").notNull(),
8
- version: text("version").notNull(),
9
- filePath: text("file_path").notNull(),
10
- gitCommit: text("git_commit"),
11
- extractedAt: timestamp("extracted_at", { withTimezone: true }).defaultNow().notNull()
12
- },
13
- (table) => [
14
- uniqueIndex("component_versions_name_version_idx").on(table.componentName, table.version)
15
- ]
16
- )
17
-
18
- export type ComponentVersion = typeof componentVersions.$inferSelect
19
- export type NewComponentVersion = typeof componentVersions.$inferInsert
@@ -1,32 +0,0 @@
1
- import type { BaseBlock } from "../core/types/blocks"
2
-
3
- export function extractPlainTextFromBlocks(blocks: BaseBlock[], locale = "en"): string {
4
- const parts: string[] = []
5
-
6
- function walk(nodes: BaseBlock[]) {
7
- for (const node of nodes) {
8
- if (node.props) {
9
- if (typeof node.props.text === "object" && node.props.text !== null) {
10
- const locText = node.props.text[locale] || node.props.text.en
11
- if (locText) parts.push(String(locText))
12
- } else if (typeof node.props.text === "string") {
13
- parts.push(node.props.text)
14
- }
15
-
16
- if (typeof node.props.title === "object" && node.props.title !== null) {
17
- const locTitle = node.props.title[locale] || node.props.title.en
18
- if (locTitle) parts.push(String(locTitle))
19
- } else if (typeof node.props.title === "string") {
20
- parts.push(node.props.title)
21
- }
22
- }
23
-
24
- if (node.children?.length) {
25
- walk(node.children)
26
- }
27
- }
28
- }
29
-
30
- walk(blocks)
31
- return parts.join(" ")
32
- }