@byline/cli 2.7.0 → 3.0.1

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 (21) hide show
  1. package/dist/templates/byline-examples/collections/docs/admin.tsx +1 -1
  2. package/dist/templates/byline-examples/collections/docs/schema.ts +1 -2
  3. package/dist/templates/byline-examples/collections/news/admin.tsx +1 -1
  4. package/dist/templates/byline-examples/collections/news/schema.ts +1 -2
  5. package/dist/templates/byline-examples/collections/pages/admin.tsx +1 -1
  6. package/dist/templates/byline-examples/collections/pages/schema.ts +1 -2
  7. package/dist/templates/byline-examples/scripts/backfill-version-locales.ts +46 -0
  8. package/dist/templates/byline-examples/scripts/import-docs.ts +107 -23
  9. package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.test.node.ts +262 -0
  10. package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.ts +8 -3
  11. package/dist/templates/byline-examples/scripts/lib/rewrite-doc-links.ts +141 -0
  12. package/dist/templates/byline-examples/scripts/lib/strip-leading-h1.test.node.ts +66 -0
  13. package/dist/templates/byline-examples/scripts/re-anchor.ts +102 -0
  14. package/dist/templates/byline-examples/scripts/regenerate-media.ts +1 -1
  15. package/dist/templates/migrations/{0000_black_sabra.sql → 0000_yielding_northstar.sql} +22 -2
  16. package/dist/templates/migrations/meta/0000_snapshot.json +164 -3
  17. package/dist/templates/migrations/meta/_journal.json +2 -2
  18. package/dist/templates/routes/_byline/route.lazy.tsx +16 -6
  19. package/dist/templates/routes/_byline/route.tsx +34 -9
  20. package/package.json +1 -1
  21. package/dist/templates/byline-examples/fields/available-languages-field.ts +0 -99
@@ -272,10 +272,15 @@ const LANG_ALIASES: Record<string, string> = {
272
272
  xml: 'markup',
273
273
  }
274
274
 
275
- function normalizeCodeLang(lang: string | null | undefined): string | null {
276
- if (lang == null) return null
275
+ // Default for unfenced / language-less code blocks. Prism crashes on
276
+ // null/undefined languages, and the project's docs are predominantly
277
+ // TypeScript, so fall back to that rather than 'plain'.
278
+ const DEFAULT_CODE_LANG = 'typescript'
279
+
280
+ function normalizeCodeLang(lang: string | null | undefined): string {
281
+ if (lang == null) return DEFAULT_CODE_LANG
277
282
  const trimmed = lang.trim().toLowerCase()
278
- if (trimmed.length === 0) return null
283
+ if (trimmed.length === 0) return DEFAULT_CODE_LANG
279
284
  return LANG_ALIASES[trimmed] ?? trimmed
280
285
  }
281
286
 
@@ -0,0 +1,141 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ /**
10
+ * Rewrite relative markdown links so they work after import.
11
+ *
12
+ * Markdown docs commonly link to siblings via `./OTHER.md[#hash]`. Once
13
+ * imported into Lexical, those hrefs break — Lexical's link serializer
14
+ * passes them to `new URL(...)` and throws. We rewrite them in-place
15
+ * against a `sourcePath → importedDocPath` map built in a pre-pass.
16
+ *
17
+ * Links whose target isn't in the map (i.e. the .md file wasn't part of
18
+ * the same import batch) are stripped: the `link` node is replaced by
19
+ * its inline children, so the reader sees the link text but no broken
20
+ * URL. The original href is reported as a warning.
21
+ *
22
+ * Non-markdown hrefs (absolute URLs, mailto:, pure fragments, images,
23
+ * etc.) are left untouched.
24
+ */
25
+
26
+ import { dirname, resolve } from 'node:path'
27
+
28
+ import type { Parent, Root, RootContent } from 'mdast'
29
+
30
+ export interface DocLinkRewriteWarning {
31
+ kind: 'rewritten-doc-link' | 'unresolved-doc-link' | 'stripped-empty-link'
32
+ href: string
33
+ resolvedTo?: string
34
+ }
35
+
36
+ export interface RewriteDocLinksOptions {
37
+ /** Absolute path of the markdown file currently being converted. */
38
+ sourceFilePath: string
39
+ /** Map from absolute markdown source path → imported doc path (no leading slash). */
40
+ pathMap: Map<string, string>
41
+ /** URL prefix the imported docs live under, e.g. `/docs`. */
42
+ urlPrefix: string
43
+ }
44
+
45
+ const MD_EXT_RE = /\.(md|markdown)$/i
46
+ // A leading `scheme:` like `https:`, `mailto:`, `data:` — anything we
47
+ // must not touch.
48
+ const SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i
49
+
50
+ export function rewriteDocLinks(root: Root, opts: RewriteDocLinksOptions): DocLinkRewriteWarning[] {
51
+ const warnings: DocLinkRewriteWarning[] = []
52
+ const baseDir = dirname(opts.sourceFilePath)
53
+ const prefix = opts.urlPrefix.replace(/\/$/, '')
54
+ rewriteChildren(root as unknown as Parent, baseDir, prefix, opts.pathMap, warnings)
55
+ return warnings
56
+ }
57
+
58
+ function rewriteChildren(
59
+ parent: Parent,
60
+ baseDir: string,
61
+ prefix: string,
62
+ pathMap: Map<string, string>,
63
+ warnings: DocLinkRewriteWarning[]
64
+ ): void {
65
+ const next: RootContent[] = []
66
+ for (const child of parent.children as RootContent[]) {
67
+ if (child.type === 'link') {
68
+ const decision = classifyLink(child.url, baseDir, pathMap)
69
+ if (decision.kind === 'skip') {
70
+ // Still recurse — a link may contain other links via images, etc.
71
+ rewriteChildren(child as unknown as Parent, baseDir, prefix, pathMap, warnings)
72
+ next.push(child)
73
+ } else if (decision.kind === 'rewrite') {
74
+ const newUrl = `${prefix}/${decision.docPath}${decision.fragment}`
75
+ warnings.push({
76
+ kind: 'rewritten-doc-link',
77
+ href: child.url,
78
+ resolvedTo: newUrl,
79
+ })
80
+ child.url = newUrl
81
+ rewriteChildren(child as unknown as Parent, baseDir, prefix, pathMap, warnings)
82
+ next.push(child)
83
+ } else {
84
+ // Unresolved .md or empty/meaningless target — drop the link
85
+ // wrapper, keep the text so the reader still sees the prose.
86
+ warnings.push({
87
+ kind: decision.kind === 'unresolved' ? 'unresolved-doc-link' : 'stripped-empty-link',
88
+ href: child.url,
89
+ })
90
+ rewriteChildren(child as unknown as Parent, baseDir, prefix, pathMap, warnings)
91
+ for (const inner of child.children) next.push(inner as RootContent)
92
+ }
93
+ } else {
94
+ if (hasChildren(child)) {
95
+ rewriteChildren(child, baseDir, prefix, pathMap, warnings)
96
+ }
97
+ next.push(child)
98
+ }
99
+ }
100
+ parent.children = next as Parent['children']
101
+ }
102
+
103
+ type Decision =
104
+ | { kind: 'skip' }
105
+ | { kind: 'rewrite'; docPath: string; fragment: string }
106
+ | { kind: 'unresolved' }
107
+ | { kind: 'empty' }
108
+
109
+ // Targets that reference "the current directory" with no real path —
110
+ // `.`, `..`, `./`, `../`, etc. Authors sometimes write `[text](.)` as a
111
+ // placeholder; in the rendered doc it has no meaning and Lexical's
112
+ // link serializer crashes on it.
113
+ const EMPTY_TARGET_RE = /^\.{1,2}\/?$/
114
+
115
+ function classifyLink(
116
+ url: string | undefined | null,
117
+ baseDir: string,
118
+ pathMap: Map<string, string>
119
+ ): Decision {
120
+ if (url == null) return { kind: 'skip' }
121
+ if (url.length === 0) return { kind: 'empty' }
122
+ if (url.startsWith('#')) return { kind: 'skip' }
123
+ if (url.startsWith('//')) return { kind: 'skip' }
124
+ if (SCHEME_RE.test(url)) return { kind: 'skip' }
125
+
126
+ const hashIdx = url.indexOf('#')
127
+ const target = hashIdx >= 0 ? url.slice(0, hashIdx) : url
128
+ const fragment = hashIdx >= 0 ? url.slice(hashIdx) : ''
129
+
130
+ if (target.length === 0 || EMPTY_TARGET_RE.test(target)) return { kind: 'empty' }
131
+ if (!MD_EXT_RE.test(target)) return { kind: 'skip' }
132
+
133
+ const abs = resolve(baseDir, target)
134
+ const mapped = pathMap.get(abs)
135
+ if (mapped) return { kind: 'rewrite', docPath: mapped, fragment }
136
+ return { kind: 'unresolved' }
137
+ }
138
+
139
+ function hasChildren(node: RootContent): node is RootContent & Parent {
140
+ return 'children' in node && Array.isArray((node as Parent).children)
141
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ import type { Root } from 'mdast'
10
+ import remarkGfm from 'remark-gfm'
11
+ import remarkParse from 'remark-parse'
12
+ import { unified } from 'unified'
13
+ import { describe, expect, test } from 'vitest'
14
+
15
+ import { stripLeadingH1IfMatches } from './strip-leading-h1.js'
16
+
17
+ function parse(md: string): Root {
18
+ return unified().use(remarkParse).use(remarkGfm).parse(md) as Root
19
+ }
20
+
21
+ describe('stripLeadingH1IfMatches', () => {
22
+ test('removes the leading H1 when its text matches the title', () => {
23
+ const root = parse('# Authentication & Authorization\n\nbody')
24
+ const out = stripLeadingH1IfMatches(root, 'Authentication & Authorization')
25
+ expect(out.children).toHaveLength(1)
26
+ expect(out.children[0]).toMatchObject({ type: 'paragraph' })
27
+ })
28
+
29
+ test('match is case-insensitive and whitespace-tolerant', () => {
30
+ const root = parse('# authentication & authorization \n\nbody')
31
+ const out = stripLeadingH1IfMatches(root, 'Authentication & Authorization')
32
+ expect(out.children).toHaveLength(1)
33
+ })
34
+
35
+ test('match flattens inline formatting in the H1', () => {
36
+ // mdast-util-to-string drops backticks / emphasis markers from the
37
+ // H1's inline structure. Frontmatter titles are plain prose, so a
38
+ // body H1 of '# Client SDK (`@byline/client`)' compares equal to a
39
+ // frontmatter title of 'Client SDK (@byline/client)'.
40
+ const root = parse('# Client SDK (`@byline/client`)\n\nbody')
41
+ const out = stripLeadingH1IfMatches(root, 'Client SDK (@byline/client)')
42
+ expect(out.children).toHaveLength(1)
43
+ expect(out.children[0]).toMatchObject({ type: 'paragraph' })
44
+ })
45
+
46
+ test('leaves the body untouched when the H1 differs', () => {
47
+ const root = parse('# Different Title\n\nbody')
48
+ const out = stripLeadingH1IfMatches(root, 'Authentication & Authorization')
49
+ expect(out.children).toHaveLength(2)
50
+ expect(out.children[0]).toMatchObject({ type: 'heading', depth: 1 })
51
+ })
52
+
53
+ test('leaves the body untouched when there is no leading heading', () => {
54
+ const root = parse('just a paragraph')
55
+ const out = stripLeadingH1IfMatches(root, 'Anything')
56
+ expect(out.children).toHaveLength(1)
57
+ expect(out.children[0]).toMatchObject({ type: 'paragraph' })
58
+ })
59
+
60
+ test('leaves the body untouched when the leading heading is H2', () => {
61
+ const root = parse('## A Subheading\n\nbody')
62
+ const out = stripLeadingH1IfMatches(root, 'A Subheading')
63
+ expect(out.children).toHaveLength(2)
64
+ expect(out.children[0]).toMatchObject({ type: 'heading', depth: 2 })
65
+ })
66
+ })
@@ -0,0 +1,102 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ /**
10
+ * Bulk re-anchor: move every fully-translated document onto a new content
11
+ * source locale. This is the follow-up to switching `i18n.content.defaultLocale`
12
+ * — Slices 1–4 make the switch *safe* (existing docs keep reading their original
13
+ * anchor); this command actually moves the documents that are complete in the
14
+ * new locale onto it (its fallback floor, path locale, and completeness
15
+ * yardstick). Documents not yet fully translated into the target are skipped and
16
+ * listed — that list is the outstanding-translation backlog. Re-run as
17
+ * translation progresses; it is idempotent (each doc is its own transaction).
18
+ *
19
+ * cd apps/webapp && pnpm tsx byline/scripts/re-anchor.ts --to fr
20
+ * cd apps/webapp && pnpm tsx byline/scripts/re-anchor.ts --to fr --collection pages
21
+ * cd apps/webapp && pnpm tsx byline/scripts/re-anchor.ts --to fr --dry-run
22
+ *
23
+ * See docs/I18N.md.
24
+ */
25
+
26
+ import '../load-env.js'
27
+ import '../server.config.js'
28
+
29
+ import { parseArgs } from 'node:util'
30
+
31
+ import { getBylineCore, getServerConfig } from '@byline/core'
32
+ import type { PgAdapter } from '@byline/db-postgres'
33
+
34
+ const USAGE =
35
+ 'Usage: pnpm tsx byline/scripts/re-anchor.ts --to <locale> [--collection <path>] [--dry-run]'
36
+
37
+ async function run() {
38
+ const { values } = parseArgs({
39
+ options: {
40
+ to: { type: 'string' },
41
+ collection: { type: 'string' },
42
+ 'dry-run': { type: 'boolean', default: false },
43
+ },
44
+ })
45
+
46
+ const targetLocale = values.to
47
+ if (!targetLocale) {
48
+ console.error(`✗ missing required --to <locale>.\n${USAGE}`)
49
+ process.exit(1)
50
+ }
51
+
52
+ const config = getServerConfig()
53
+
54
+ const contentLocales = config.i18n.content.locales
55
+ if (!contentLocales.includes(targetLocale)) {
56
+ console.error(
57
+ `✗ --to '${targetLocale}' is not a configured content locale (${contentLocales.join(', ')})`
58
+ )
59
+ process.exit(1)
60
+ }
61
+
62
+ // Resolve an optional collection-path filter to its id via the registered
63
+ // collection records (throws a clear error for an unknown path).
64
+ const collectionPath = values.collection
65
+ const collectionId = collectionPath
66
+ ? getBylineCore().getCollectionRecord(collectionPath).collectionId
67
+ : undefined
68
+
69
+ const dryRun = values['dry-run'] ?? false
70
+ const db = config.db as PgAdapter
71
+ const scope = collectionPath ? `collection '${collectionPath}'` : 'all collections'
72
+
73
+ console.log(
74
+ `${dryRun ? '[dry-run] ' : ''}re-anchoring ${scope} → content source locale '${targetLocale}'…`
75
+ )
76
+
77
+ const report = await db.reAnchorDocuments({ targetLocale, collectionId, dryRun })
78
+
79
+ console.log(
80
+ `${dryRun ? '[dry-run] would re-anchor' : '✓ re-anchored'} ${report.reanchored}/${report.total} document(s) → '${targetLocale}'`
81
+ )
82
+ console.log(` • already anchored to '${targetLocale}': ${report.alreadyAnchored}`)
83
+ console.log(` • skipped (incomplete translation): ${report.skippedIncomplete}`)
84
+
85
+ if (report.skippedIncomplete > 0) {
86
+ console.log(
87
+ `\nDocuments needing a complete '${targetLocale}' translation before they can be re-anchored:`
88
+ )
89
+ for (const r of report.results) {
90
+ if (r.status === 'skipped-incomplete') {
91
+ console.log(` - ${r.documentId} (currently anchored to '${r.fromLocale}')`)
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ run()
98
+ .then(() => process.exit(0))
99
+ .catch((error) => {
100
+ console.error('✗ re-anchor failed:', error)
101
+ process.exit(1)
102
+ })
@@ -18,7 +18,7 @@
18
18
  * to `'avif'` in `byline/collections/media/schema.ts`) to bring existing
19
19
  * assets in line with the new pipeline:
20
20
  *
21
- * pnpm tsx --env-file=.env --env-file=.env.local byline/scripts/regenerate-media.ts
21
+ * pnpm tsx byline/scripts/regenerate-media.ts
22
22
  *
23
23
  * The script orchestrates the same two-step flow the admin UI uses
24
24
  * for an existing document — upload (createDocument: false) followed by
@@ -115,6 +115,15 @@ CREATE TABLE "byline_store_datetime" (
115
115
  CONSTRAINT "unique_datetime_field" UNIQUE("document_version_id","field_path","locale")
116
116
  );
117
117
  --> statement-breakpoint
118
+ CREATE TABLE "byline_document_available_locales" (
119
+ "document_id" uuid NOT NULL,
120
+ "locale" varchar(10) NOT NULL,
121
+ "collection_id" uuid NOT NULL,
122
+ "created_at" timestamp (6) with time zone DEFAULT now() NOT NULL,
123
+ "updated_at" timestamp (6) with time zone DEFAULT now() NOT NULL,
124
+ CONSTRAINT "byline_document_available_locales_document_id_locale_pk" PRIMARY KEY("document_id","locale")
125
+ );
126
+ --> statement-breakpoint
118
127
  CREATE TABLE "byline_document_paths" (
119
128
  "document_id" uuid NOT NULL,
120
129
  "locale" varchar(10) NOT NULL,
@@ -133,6 +142,12 @@ CREATE TABLE "byline_document_relationships" (
133
142
  CONSTRAINT "byline_document_relationships_parent_document_id_child_document_id_unique" UNIQUE("parent_document_id","child_document_id")
134
143
  );
135
144
  --> statement-breakpoint
145
+ CREATE TABLE "byline_document_version_locales" (
146
+ "document_version_id" uuid NOT NULL,
147
+ "locale" varchar(10) NOT NULL,
148
+ CONSTRAINT "byline_document_version_locales_document_version_id_locale_pk" PRIMARY KEY("document_version_id","locale")
149
+ );
150
+ --> statement-breakpoint
136
151
  CREATE TABLE "byline_document_versions" (
137
152
  "id" uuid PRIMARY KEY NOT NULL,
138
153
  "document_id" uuid NOT NULL,
@@ -152,6 +167,7 @@ CREATE TABLE "byline_documents" (
152
167
  "id" uuid PRIMARY KEY NOT NULL,
153
168
  "collection_id" uuid NOT NULL,
154
169
  "order_key" varchar(128) COLLATE "C",
170
+ "source_locale" varchar(10) NOT NULL,
155
171
  "created_at" timestamp (6) with time zone DEFAULT now() NOT NULL,
156
172
  "updated_at" timestamp (6) with time zone DEFAULT now() NOT NULL
157
173
  );
@@ -270,10 +286,13 @@ ALTER TABLE "byline_store_boolean" ADD CONSTRAINT "byline_store_boolean_document
270
286
  ALTER TABLE "byline_store_boolean" ADD CONSTRAINT "byline_store_boolean_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
271
287
  ALTER TABLE "byline_store_datetime" ADD CONSTRAINT "byline_store_datetime_document_version_id_byline_document_versions_id_fk" FOREIGN KEY ("document_version_id") REFERENCES "public"."byline_document_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
272
288
  ALTER TABLE "byline_store_datetime" ADD CONSTRAINT "byline_store_datetime_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
289
+ ALTER TABLE "byline_document_available_locales" ADD CONSTRAINT "byline_document_available_locales_document_id_byline_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."byline_documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
290
+ ALTER TABLE "byline_document_available_locales" ADD CONSTRAINT "byline_document_available_locales_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
273
291
  ALTER TABLE "byline_document_paths" ADD CONSTRAINT "byline_document_paths_document_id_byline_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."byline_documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
274
292
  ALTER TABLE "byline_document_paths" ADD CONSTRAINT "byline_document_paths_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
275
293
  ALTER TABLE "byline_document_relationships" ADD CONSTRAINT "byline_document_relationships_parent_document_id_byline_documents_id_fk" FOREIGN KEY ("parent_document_id") REFERENCES "public"."byline_documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
276
294
  ALTER TABLE "byline_document_relationships" ADD CONSTRAINT "byline_document_relationships_child_document_id_byline_documents_id_fk" FOREIGN KEY ("child_document_id") REFERENCES "public"."byline_documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
295
+ ALTER TABLE "byline_document_version_locales" ADD CONSTRAINT "byline_document_version_locales_document_version_id_byline_document_versions_id_fk" FOREIGN KEY ("document_version_id") REFERENCES "public"."byline_document_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
277
296
  ALTER TABLE "byline_document_versions" ADD CONSTRAINT "byline_document_versions_document_id_byline_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."byline_documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
278
297
  ALTER TABLE "byline_document_versions" ADD CONSTRAINT "byline_document_versions_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
279
298
  ALTER TABLE "byline_documents" ADD CONSTRAINT "byline_documents_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
@@ -304,6 +323,7 @@ CREATE INDEX "idx_datetime_date" ON "byline_store_datetime" USING btree ("value_
304
323
  CREATE INDEX "idx_datetime_timestamp_tz" ON "byline_store_datetime" USING btree ("value_timestamp_tz");--> statement-breakpoint
305
324
  CREATE INDEX "idx_datetime_path_date" ON "byline_store_datetime" USING btree ("field_path","value_timestamp_tz");--> statement-breakpoint
306
325
  CREATE INDEX "idx_datetime_collection_date" ON "byline_store_datetime" USING btree ("collection_id","value_timestamp_tz");--> statement-breakpoint
326
+ CREATE INDEX "idx_document_available_locales_document_id" ON "byline_document_available_locales" USING btree ("document_id");--> statement-breakpoint
307
327
  CREATE INDEX "idx_document_paths_document_id" ON "byline_document_paths" USING btree ("document_id");--> statement-breakpoint
308
328
  CREATE INDEX "idx_document_relationships_parent" ON "byline_document_relationships" USING btree ("parent_document_id");--> statement-breakpoint
309
329
  CREATE INDEX "idx_document_relationships_child" ON "byline_document_relationships" USING btree ("child_document_id");--> statement-breakpoint
@@ -342,5 +362,5 @@ CREATE INDEX "idx_text_value" ON "byline_store_text" USING btree ("value");--> s
342
362
  CREATE INDEX "idx_text_fulltext" ON "byline_store_text" USING gin (to_tsvector('english', "value"));--> statement-breakpoint
343
363
  CREATE INDEX "idx_text_locale_value" ON "byline_store_text" USING btree ("locale","value");--> statement-breakpoint
344
364
  CREATE INDEX "idx_text_path_value" ON "byline_store_text" USING btree ("field_path","value");--> statement-breakpoint
345
- CREATE VIEW "public"."byline_current_documents" AS (with "sq" as (select "id", "document_id", "collection_id", "collection_version", "event_type", "status", "is_deleted", "created_at", "updated_at", "created_by", "change_summary", row_number() OVER (PARTITION BY "document_id" ORDER BY "id" DESC) as "rn" from "byline_document_versions" where "byline_document_versions"."is_deleted" = false) select "sq"."id", "sq"."document_id", "sq"."collection_id", "sq"."collection_version", "sq"."event_type", "sq"."status", "sq"."is_deleted", "sq"."created_at", "sq"."updated_at", "sq"."created_by", "sq"."change_summary", "byline_documents"."order_key" from "sq" inner join "byline_documents" on "byline_documents"."id" = "sq"."document_id" where "rn" = 1);--> statement-breakpoint
346
- CREATE VIEW "public"."byline_current_published_documents" AS (with "sq" as (select "id", "document_id", "collection_id", "collection_version", "event_type", "status", "is_deleted", "created_at", "updated_at", "created_by", "change_summary", row_number() OVER (PARTITION BY "document_id" ORDER BY "id" DESC) as "rn" from "byline_document_versions" where "byline_document_versions"."is_deleted" = false AND "byline_document_versions"."status" = 'published') select "sq"."id", "sq"."document_id", "sq"."collection_id", "sq"."collection_version", "sq"."event_type", "sq"."status", "sq"."is_deleted", "sq"."created_at", "sq"."updated_at", "sq"."created_by", "sq"."change_summary", "byline_documents"."order_key" from "sq" inner join "byline_documents" on "byline_documents"."id" = "sq"."document_id" where "rn" = 1);
365
+ CREATE VIEW "public"."byline_current_documents" AS (with "sq" as (select "id", "document_id", "collection_id", "collection_version", "event_type", "status", "is_deleted", "created_at", "updated_at", "created_by", "change_summary", row_number() OVER (PARTITION BY "document_id" ORDER BY "id" DESC) as "rn" from "byline_document_versions" where "byline_document_versions"."is_deleted" = false) select "sq"."id", "sq"."document_id", "sq"."collection_id", "sq"."collection_version", "sq"."event_type", "sq"."status", "sq"."is_deleted", "sq"."created_at", "sq"."updated_at", "sq"."created_by", "sq"."change_summary", "byline_documents"."order_key", "byline_documents"."source_locale" from "sq" inner join "byline_documents" on "byline_documents"."id" = "sq"."document_id" where "rn" = 1);--> statement-breakpoint
366
+ CREATE VIEW "public"."byline_current_published_documents" AS (with "sq" as (select "id", "document_id", "collection_id", "collection_version", "event_type", "status", "is_deleted", "created_at", "updated_at", "created_by", "change_summary", row_number() OVER (PARTITION BY "document_id" ORDER BY "id" DESC) as "rn" from "byline_document_versions" where "byline_document_versions"."is_deleted" = false AND "byline_document_versions"."status" = 'published') select "sq"."id", "sq"."document_id", "sq"."collection_id", "sq"."collection_version", "sq"."event_type", "sq"."status", "sq"."is_deleted", "sq"."created_at", "sq"."updated_at", "sq"."created_by", "sq"."change_summary", "byline_documents"."order_key", "byline_documents"."source_locale" from "sq" inner join "byline_documents" on "byline_documents"."id" = "sq"."document_id" where "rn" = 1);
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "2d20cd37-0ecf-467c-86dd-9f880e9d41b4",
2
+ "id": "52560051-1da6-41f4-8a2c-b9a7b5421d26",
3
3
  "prevId": "00000000-0000-0000-0000-000000000000",
4
4
  "version": "7",
5
5
  "dialect": "postgresql",
@@ -1053,6 +1053,102 @@
1053
1053
  "checkConstraints": {},
1054
1054
  "isRLSEnabled": false
1055
1055
  },
1056
+ "public.byline_document_available_locales": {
1057
+ "name": "byline_document_available_locales",
1058
+ "schema": "",
1059
+ "columns": {
1060
+ "document_id": {
1061
+ "name": "document_id",
1062
+ "type": "uuid",
1063
+ "primaryKey": false,
1064
+ "notNull": true
1065
+ },
1066
+ "locale": {
1067
+ "name": "locale",
1068
+ "type": "varchar(10)",
1069
+ "primaryKey": false,
1070
+ "notNull": true
1071
+ },
1072
+ "collection_id": {
1073
+ "name": "collection_id",
1074
+ "type": "uuid",
1075
+ "primaryKey": false,
1076
+ "notNull": true
1077
+ },
1078
+ "created_at": {
1079
+ "name": "created_at",
1080
+ "type": "timestamp (6) with time zone",
1081
+ "primaryKey": false,
1082
+ "notNull": true,
1083
+ "default": "now()"
1084
+ },
1085
+ "updated_at": {
1086
+ "name": "updated_at",
1087
+ "type": "timestamp (6) with time zone",
1088
+ "primaryKey": false,
1089
+ "notNull": true,
1090
+ "default": "now()"
1091
+ }
1092
+ },
1093
+ "indexes": {
1094
+ "idx_document_available_locales_document_id": {
1095
+ "name": "idx_document_available_locales_document_id",
1096
+ "columns": [
1097
+ {
1098
+ "expression": "document_id",
1099
+ "isExpression": false,
1100
+ "asc": true,
1101
+ "nulls": "last"
1102
+ }
1103
+ ],
1104
+ "isUnique": false,
1105
+ "concurrently": false,
1106
+ "method": "btree",
1107
+ "with": {}
1108
+ }
1109
+ },
1110
+ "foreignKeys": {
1111
+ "byline_document_available_locales_document_id_byline_documents_id_fk": {
1112
+ "name": "byline_document_available_locales_document_id_byline_documents_id_fk",
1113
+ "tableFrom": "byline_document_available_locales",
1114
+ "tableTo": "byline_documents",
1115
+ "columnsFrom": [
1116
+ "document_id"
1117
+ ],
1118
+ "columnsTo": [
1119
+ "id"
1120
+ ],
1121
+ "onDelete": "cascade",
1122
+ "onUpdate": "no action"
1123
+ },
1124
+ "byline_document_available_locales_collection_id_byline_collections_id_fk": {
1125
+ "name": "byline_document_available_locales_collection_id_byline_collections_id_fk",
1126
+ "tableFrom": "byline_document_available_locales",
1127
+ "tableTo": "byline_collections",
1128
+ "columnsFrom": [
1129
+ "collection_id"
1130
+ ],
1131
+ "columnsTo": [
1132
+ "id"
1133
+ ],
1134
+ "onDelete": "cascade",
1135
+ "onUpdate": "no action"
1136
+ }
1137
+ },
1138
+ "compositePrimaryKeys": {
1139
+ "byline_document_available_locales_document_id_locale_pk": {
1140
+ "name": "byline_document_available_locales_document_id_locale_pk",
1141
+ "columns": [
1142
+ "document_id",
1143
+ "locale"
1144
+ ]
1145
+ }
1146
+ },
1147
+ "uniqueConstraints": {},
1148
+ "policies": {},
1149
+ "checkConstraints": {},
1150
+ "isRLSEnabled": false
1151
+ },
1056
1152
  "public.byline_document_paths": {
1057
1153
  "name": "byline_document_paths",
1058
1154
  "schema": "",
@@ -1264,6 +1360,53 @@
1264
1360
  "checkConstraints": {},
1265
1361
  "isRLSEnabled": false
1266
1362
  },
1363
+ "public.byline_document_version_locales": {
1364
+ "name": "byline_document_version_locales",
1365
+ "schema": "",
1366
+ "columns": {
1367
+ "document_version_id": {
1368
+ "name": "document_version_id",
1369
+ "type": "uuid",
1370
+ "primaryKey": false,
1371
+ "notNull": true
1372
+ },
1373
+ "locale": {
1374
+ "name": "locale",
1375
+ "type": "varchar(10)",
1376
+ "primaryKey": false,
1377
+ "notNull": true
1378
+ }
1379
+ },
1380
+ "indexes": {},
1381
+ "foreignKeys": {
1382
+ "byline_document_version_locales_document_version_id_byline_document_versions_id_fk": {
1383
+ "name": "byline_document_version_locales_document_version_id_byline_document_versions_id_fk",
1384
+ "tableFrom": "byline_document_version_locales",
1385
+ "tableTo": "byline_document_versions",
1386
+ "columnsFrom": [
1387
+ "document_version_id"
1388
+ ],
1389
+ "columnsTo": [
1390
+ "id"
1391
+ ],
1392
+ "onDelete": "cascade",
1393
+ "onUpdate": "no action"
1394
+ }
1395
+ },
1396
+ "compositePrimaryKeys": {
1397
+ "byline_document_version_locales_document_version_id_locale_pk": {
1398
+ "name": "byline_document_version_locales_document_version_id_locale_pk",
1399
+ "columns": [
1400
+ "document_version_id",
1401
+ "locale"
1402
+ ]
1403
+ }
1404
+ },
1405
+ "uniqueConstraints": {},
1406
+ "policies": {},
1407
+ "checkConstraints": {},
1408
+ "isRLSEnabled": false
1409
+ },
1267
1410
  "public.byline_document_versions": {
1268
1411
  "name": "byline_document_versions",
1269
1412
  "schema": "",
@@ -1530,6 +1673,12 @@
1530
1673
  "primaryKey": false,
1531
1674
  "notNull": false
1532
1675
  },
1676
+ "source_locale": {
1677
+ "name": "source_locale",
1678
+ "type": "varchar(10)",
1679
+ "primaryKey": false,
1680
+ "notNull": true
1681
+ },
1533
1682
  "created_at": {
1534
1683
  "name": "created_at",
1535
1684
  "type": "timestamp (6) with time zone",
@@ -2999,9 +3148,15 @@
2999
3148
  "type": "varchar(128) COLLATE \"C\"",
3000
3149
  "primaryKey": false,
3001
3150
  "notNull": false
3151
+ },
3152
+ "source_locale": {
3153
+ "name": "source_locale",
3154
+ "type": "varchar(10)",
3155
+ "primaryKey": false,
3156
+ "notNull": true
3002
3157
  }
3003
3158
  },
3004
- "definition": "with \"sq\" as (select \"id\", \"document_id\", \"collection_id\", \"collection_version\", \"event_type\", \"status\", \"is_deleted\", \"created_at\", \"updated_at\", \"created_by\", \"change_summary\", row_number() OVER (PARTITION BY \"document_id\" ORDER BY \"id\" DESC) as \"rn\" from \"byline_document_versions\" where \"byline_document_versions\".\"is_deleted\" = false) select \"sq\".\"id\", \"sq\".\"document_id\", \"sq\".\"collection_id\", \"sq\".\"collection_version\", \"sq\".\"event_type\", \"sq\".\"status\", \"sq\".\"is_deleted\", \"sq\".\"created_at\", \"sq\".\"updated_at\", \"sq\".\"created_by\", \"sq\".\"change_summary\", \"byline_documents\".\"order_key\" from \"sq\" inner join \"byline_documents\" on \"byline_documents\".\"id\" = \"sq\".\"document_id\" where \"rn\" = 1",
3159
+ "definition": "with \"sq\" as (select \"id\", \"document_id\", \"collection_id\", \"collection_version\", \"event_type\", \"status\", \"is_deleted\", \"created_at\", \"updated_at\", \"created_by\", \"change_summary\", row_number() OVER (PARTITION BY \"document_id\" ORDER BY \"id\" DESC) as \"rn\" from \"byline_document_versions\" where \"byline_document_versions\".\"is_deleted\" = false) select \"sq\".\"id\", \"sq\".\"document_id\", \"sq\".\"collection_id\", \"sq\".\"collection_version\", \"sq\".\"event_type\", \"sq\".\"status\", \"sq\".\"is_deleted\", \"sq\".\"created_at\", \"sq\".\"updated_at\", \"sq\".\"created_by\", \"sq\".\"change_summary\", \"byline_documents\".\"order_key\", \"byline_documents\".\"source_locale\" from \"sq\" inner join \"byline_documents\" on \"byline_documents\".\"id\" = \"sq\".\"document_id\" where \"rn\" = 1",
3005
3160
  "name": "byline_current_documents",
3006
3161
  "schema": "public",
3007
3162
  "isExisting": false,
@@ -3085,9 +3240,15 @@
3085
3240
  "type": "varchar(128) COLLATE \"C\"",
3086
3241
  "primaryKey": false,
3087
3242
  "notNull": false
3243
+ },
3244
+ "source_locale": {
3245
+ "name": "source_locale",
3246
+ "type": "varchar(10)",
3247
+ "primaryKey": false,
3248
+ "notNull": true
3088
3249
  }
3089
3250
  },
3090
- "definition": "with \"sq\" as (select \"id\", \"document_id\", \"collection_id\", \"collection_version\", \"event_type\", \"status\", \"is_deleted\", \"created_at\", \"updated_at\", \"created_by\", \"change_summary\", row_number() OVER (PARTITION BY \"document_id\" ORDER BY \"id\" DESC) as \"rn\" from \"byline_document_versions\" where \"byline_document_versions\".\"is_deleted\" = false AND \"byline_document_versions\".\"status\" = 'published') select \"sq\".\"id\", \"sq\".\"document_id\", \"sq\".\"collection_id\", \"sq\".\"collection_version\", \"sq\".\"event_type\", \"sq\".\"status\", \"sq\".\"is_deleted\", \"sq\".\"created_at\", \"sq\".\"updated_at\", \"sq\".\"created_by\", \"sq\".\"change_summary\", \"byline_documents\".\"order_key\" from \"sq\" inner join \"byline_documents\" on \"byline_documents\".\"id\" = \"sq\".\"document_id\" where \"rn\" = 1",
3251
+ "definition": "with \"sq\" as (select \"id\", \"document_id\", \"collection_id\", \"collection_version\", \"event_type\", \"status\", \"is_deleted\", \"created_at\", \"updated_at\", \"created_by\", \"change_summary\", row_number() OVER (PARTITION BY \"document_id\" ORDER BY \"id\" DESC) as \"rn\" from \"byline_document_versions\" where \"byline_document_versions\".\"is_deleted\" = false AND \"byline_document_versions\".\"status\" = 'published') select \"sq\".\"id\", \"sq\".\"document_id\", \"sq\".\"collection_id\", \"sq\".\"collection_version\", \"sq\".\"event_type\", \"sq\".\"status\", \"sq\".\"is_deleted\", \"sq\".\"created_at\", \"sq\".\"updated_at\", \"sq\".\"created_by\", \"sq\".\"change_summary\", \"byline_documents\".\"order_key\", \"byline_documents\".\"source_locale\" from \"sq\" inner join \"byline_documents\" on \"byline_documents\".\"id\" = \"sq\".\"document_id\" where \"rn\" = 1",
3091
3252
  "name": "byline_current_published_documents",
3092
3253
  "schema": "public",
3093
3254
  "isExisting": false,
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "7",
8
- "when": 1779971470037,
9
- "tag": "0000_black_sabra",
8
+ "when": 1780302968051,
9
+ "tag": "0000_yielding_northstar",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]