@krantho/persistence-sqlite 0.0.0-stage → 1.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.
- package/LICENSE +21 -0
- package/dist/auth-adapter.d.ts +23 -0
- package/dist/auth-adapter.d.ts.map +1 -0
- package/dist/auth-adapter.js +159 -0
- package/dist/auth-adapter.js.map +1 -0
- package/dist/checkpoints.d.ts +20 -0
- package/dist/checkpoints.d.ts.map +1 -0
- package/dist/checkpoints.js +119 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/connection.d.ts +29 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +77 -0
- package/dist/connection.js.map +1 -0
- package/dist/content-migration.d.ts +18 -0
- package/dist/content-migration.d.ts.map +1 -0
- package/dist/content-migration.js +68 -0
- package/dist/content-migration.js.map +1 -0
- package/dist/content-query.d.ts +16 -0
- package/dist/content-query.d.ts.map +1 -0
- package/dist/content-query.js +155 -0
- package/dist/content-query.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/lock-adapter.d.ts +11 -0
- package/dist/lock-adapter.d.ts.map +1 -0
- package/dist/lock-adapter.js +63 -0
- package/dist/lock-adapter.js.map +1 -0
- package/dist/media-adapter.d.ts +27 -0
- package/dist/media-adapter.d.ts.map +1 -0
- package/dist/media-adapter.js +175 -0
- package/dist/media-adapter.js.map +1 -0
- package/dist/media-folder-adapter.d.ts +13 -0
- package/dist/media-folder-adapter.d.ts.map +1 -0
- package/dist/media-folder-adapter.js +58 -0
- package/dist/media-folder-adapter.js.map +1 -0
- package/dist/migration-runner.d.ts +28 -0
- package/dist/migration-runner.d.ts.map +1 -0
- package/dist/migration-runner.js +109 -0
- package/dist/migration-runner.js.map +1 -0
- package/dist/migrations/index.d.ts +4 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +32 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/v001-initial-schema.d.ts +10 -0
- package/dist/migrations/v001-initial-schema.d.ts.map +1 -0
- package/dist/migrations/v001-initial-schema.js +94 -0
- package/dist/migrations/v001-initial-schema.js.map +1 -0
- package/dist/migrations/v002-auth-tables.d.ts +9 -0
- package/dist/migrations/v002-auth-tables.d.ts.map +1 -0
- package/dist/migrations/v002-auth-tables.js +38 -0
- package/dist/migrations/v002-auth-tables.js.map +1 -0
- package/dist/migrations/v003-user-permissions.d.ts +9 -0
- package/dist/migrations/v003-user-permissions.d.ts.map +1 -0
- package/dist/migrations/v003-user-permissions.js +21 -0
- package/dist/migrations/v003-user-permissions.js.map +1 -0
- package/dist/migrations/v004-media-hotspot.d.ts +14 -0
- package/dist/migrations/v004-media-hotspot.d.ts.map +1 -0
- package/dist/migrations/v004-media-hotspot.js +24 -0
- package/dist/migrations/v004-media-hotspot.js.map +1 -0
- package/dist/migrations/v005-content-locks.d.ts +9 -0
- package/dist/migrations/v005-content-locks.d.ts.map +1 -0
- package/dist/migrations/v005-content-locks.js +24 -0
- package/dist/migrations/v005-content-locks.js.map +1 -0
- package/dist/migrations/v006-webhook-deliveries.d.ts +6 -0
- package/dist/migrations/v006-webhook-deliveries.d.ts.map +1 -0
- package/dist/migrations/v006-webhook-deliveries.js +24 -0
- package/dist/migrations/v006-webhook-deliveries.js.map +1 -0
- package/dist/migrations/v007-media-folders.d.ts +10 -0
- package/dist/migrations/v007-media-folders.d.ts.map +1 -0
- package/dist/migrations/v007-media-folders.js +23 -0
- package/dist/migrations/v007-media-folders.js.map +1 -0
- package/dist/migrations/v008-site-settings.d.ts +9 -0
- package/dist/migrations/v008-site-settings.d.ts.map +1 -0
- package/dist/migrations/v008-site-settings.js +20 -0
- package/dist/migrations/v008-site-settings.js.map +1 -0
- package/dist/migrations/v009-seo-config.d.ts +15 -0
- package/dist/migrations/v009-seo-config.d.ts.map +1 -0
- package/dist/migrations/v009-seo-config.js +29 -0
- package/dist/migrations/v009-seo-config.js.map +1 -0
- package/dist/migrations/v010-content-live-version.d.ts +15 -0
- package/dist/migrations/v010-content-live-version.d.ts.map +1 -0
- package/dist/migrations/v010-content-live-version.js +40 -0
- package/dist/migrations/v010-content-live-version.js.map +1 -0
- package/dist/migrations/v011-media.d.ts +12 -0
- package/dist/migrations/v011-media.d.ts.map +1 -0
- package/dist/migrations/v011-media.js +43 -0
- package/dist/migrations/v011-media.js.map +1 -0
- package/dist/migrations/v012-page-cache.d.ts +12 -0
- package/dist/migrations/v012-page-cache.d.ts.map +1 -0
- package/dist/migrations/v012-page-cache.js +31 -0
- package/dist/migrations/v012-page-cache.js.map +1 -0
- package/dist/migrations/v013-content-contracts.d.ts +17 -0
- package/dist/migrations/v013-content-contracts.d.ts.map +1 -0
- package/dist/migrations/v013-content-contracts.js +46 -0
- package/dist/migrations/v013-content-contracts.js.map +1 -0
- package/dist/migrations/v014-content-manifest-commit.d.ts +7 -0
- package/dist/migrations/v014-content-manifest-commit.d.ts.map +1 -0
- package/dist/migrations/v014-content-manifest-commit.js +12 -0
- package/dist/migrations/v014-content-manifest-commit.js.map +1 -0
- package/dist/page-cache-store.d.ts +17 -0
- package/dist/page-cache-store.d.ts.map +1 -0
- package/dist/page-cache-store.js +76 -0
- package/dist/page-cache-store.js.map +1 -0
- package/dist/queries.d.ts +82 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +25 -0
- package/dist/queries.js.map +1 -0
- package/dist/retention-adapter.d.ts +13 -0
- package/dist/retention-adapter.d.ts.map +1 -0
- package/dist/retention-adapter.js +62 -0
- package/dist/retention-adapter.js.map +1 -0
- package/dist/row-mapping.d.ts +14 -0
- package/dist/row-mapping.d.ts.map +1 -0
- package/dist/row-mapping.js +71 -0
- package/dist/row-mapping.js.map +1 -0
- package/dist/seo-config-adapter.d.ts +14 -0
- package/dist/seo-config-adapter.d.ts.map +1 -0
- package/dist/seo-config-adapter.js +57 -0
- package/dist/seo-config-adapter.js.map +1 -0
- package/dist/site-settings-adapter.d.ts +10 -0
- package/dist/site-settings-adapter.d.ts.map +1 -0
- package/dist/site-settings-adapter.js +27 -0
- package/dist/site-settings-adapter.js.map +1 -0
- package/dist/sqlite-adapter.d.ts +69 -0
- package/dist/sqlite-adapter.d.ts.map +1 -0
- package/dist/sqlite-adapter.js +242 -0
- package/dist/sqlite-adapter.js.map +1 -0
- package/dist/webhook-delivery-adapter.d.ts +27 -0
- package/dist/webhook-delivery-adapter.d.ts.map +1 -0
- package/dist/webhook-delivery-adapter.js +93 -0
- package/dist/webhook-delivery-adapter.js.map +1 -0
- package/package.json +38 -3
- package/README.md +0 -3
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContentDocument, ContentSummary, DocumentMeta } from '@krantho/persistence';
|
|
2
|
+
import type { ContentRow, MetaRow, SummaryRow } from './queries.js';
|
|
3
|
+
/**
|
|
4
|
+
* Safely parse a JSON column value.
|
|
5
|
+
*
|
|
6
|
+
* Throws with a clear error if the column holds malformed JSON or a non-object
|
|
7
|
+
* value. Replaces the raw `JSON.parse(...) as Record<string, unknown>` pattern
|
|
8
|
+
* that previously hid parse errors behind an unchecked cast.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseJsonRecord(json: string, column: string): Record<string, unknown>;
|
|
11
|
+
export declare function rowToContentDocument(row: ContentRow): ContentDocument;
|
|
12
|
+
export declare function rowToSummary(row: SummaryRow): ContentSummary;
|
|
13
|
+
export declare function rowToDocumentMeta(row: MetaRow): DocumentMeta;
|
|
14
|
+
//# sourceMappingURL=row-mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-mapping.d.ts","sourceRoot":"","sources":["../src/row-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EACf,cAAc,EACd,YAAY,EAIb,MAAM,sBAAsB,CAAA;AAM7B,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEnE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWrF;AA6CD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,eAAe,CAErE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAE5D"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { contentDocumentFromRow, contentSummaryFromRow, documentMetaFromRow, } from '@krantho/persistence';
|
|
2
|
+
/**
|
|
3
|
+
* Safely parse a JSON column value.
|
|
4
|
+
*
|
|
5
|
+
* Throws with a clear error if the column holds malformed JSON or a non-object
|
|
6
|
+
* value. Replaces the raw `JSON.parse(...) as Record<string, unknown>` pattern
|
|
7
|
+
* that previously hid parse errors behind an unchecked cast.
|
|
8
|
+
*/
|
|
9
|
+
export function parseJsonRecord(json, column) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(json);
|
|
12
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
13
|
+
throw new Error(`Expected object, got ${parsed === null ? 'null' : typeof parsed}`);
|
|
14
|
+
}
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
19
|
+
throw new Error(`Invalid JSON in ${column} column: ${cause}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Normalize a raw SQLite row into the canonical shape shared by every adapter.
|
|
24
|
+
*
|
|
25
|
+
* This is the only place in the SQLite adapter that parses JSON columns or
|
|
26
|
+
* interprets status/source strings. All downstream conversions (to
|
|
27
|
+
* ContentDocument, DocumentMeta) go through the shared helpers in
|
|
28
|
+
* `@krantho/persistence`.
|
|
29
|
+
*/
|
|
30
|
+
function normalizeMetaRow(row) {
|
|
31
|
+
return {
|
|
32
|
+
collection: row.collection,
|
|
33
|
+
slug: row.slug,
|
|
34
|
+
locale: row.locale,
|
|
35
|
+
version: row.version,
|
|
36
|
+
liveVersion: row.live_version,
|
|
37
|
+
status: row.status,
|
|
38
|
+
source: row.source,
|
|
39
|
+
changedBy: row.changed_by,
|
|
40
|
+
createdAt: row.created_at,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function normalizeSummaryRow(row) {
|
|
44
|
+
return {
|
|
45
|
+
...normalizeMetaRow(row),
|
|
46
|
+
fields: parseJsonRecord(row.fields, 'fields'),
|
|
47
|
+
metadata: parseJsonRecord(row.metadata ?? '{}', 'metadata'),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function normalizeRow(row) {
|
|
51
|
+
const authored = JSON.parse(row.authored);
|
|
52
|
+
return {
|
|
53
|
+
...normalizeMetaRow(row),
|
|
54
|
+
fields: parseJsonRecord(row.fields, 'fields'),
|
|
55
|
+
metadata: authored.metadata,
|
|
56
|
+
authored,
|
|
57
|
+
body: row.body,
|
|
58
|
+
html: row.html,
|
|
59
|
+
sections: parseJsonRecord(row.sections, 'sections'),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function rowToContentDocument(row) {
|
|
63
|
+
return contentDocumentFromRow(normalizeRow(row));
|
|
64
|
+
}
|
|
65
|
+
export function rowToSummary(row) {
|
|
66
|
+
return contentSummaryFromRow(normalizeSummaryRow(row));
|
|
67
|
+
}
|
|
68
|
+
export function rowToDocumentMeta(row) {
|
|
69
|
+
return documentMetaFromRow(normalizeMetaRow(row));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=row-mapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-mapping.js","sourceRoot":"","sources":["../src/row-mapping.ts"],"names":[],"mappings":"AASA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,sBAAsB,CAAA;AAG7B;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAc;IAC1D,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC,CAAA;QACrF,CAAC;QACD,OAAO,MAAiC,CAAA;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC9D,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,YAAY,KAAK,EAAE,CAAC,CAAA;IAC/D,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB,CAAC,GAAY;IACpC,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;KAC1B,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAe;IAC1C,OAAO;QACL,GAAG,gBAAgB,CAAC,GAAG,CAAC;QACxB,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC7C,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,EAAE,UAAU,CAAiC;KAC5F,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,GAAe;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAqB,CAAA;IAC7D,OAAO;QACL,GAAG,gBAAgB,CAAC,GAAG,CAAC;QACxB,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC7C,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,QAAQ;QACR,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAA2B;KAC9E,CAAA;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAe;IAClD,OAAO,sBAAsB,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAe;IAC1C,OAAO,qBAAqB,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,OAAO,mBAAmB,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAA;AACnD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ISeoConfigAdapter, SeoConfig, SeoConfigScope } from '@krantho/persistence';
|
|
2
|
+
import type { Database } from 'better-sqlite3';
|
|
3
|
+
/** SQLite implementation of ISeoConfigAdapter */
|
|
4
|
+
export declare class SqliteSeoConfigAdapter implements ISeoConfigAdapter {
|
|
5
|
+
private readonly db;
|
|
6
|
+
constructor(db: Database);
|
|
7
|
+
getConfig(id: string): Promise<SeoConfig | null>;
|
|
8
|
+
saveConfig(config: Omit<SeoConfig, 'createdAt' | 'updatedAt'>): Promise<void>;
|
|
9
|
+
deleteConfig(id: string): Promise<void>;
|
|
10
|
+
listConfigs(scope?: SeoConfigScope): Promise<SeoConfig[]>;
|
|
11
|
+
listConfigsByPrefix(prefix: string): Promise<SeoConfig[]>;
|
|
12
|
+
deleteAllConfigs(): Promise<number>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=seo-config-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-config-adapter.d.ts","sourceRoot":"","sources":["../src/seo-config-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C,iDAAiD;AACjD,qBAAa,sBAAuB,YAAW,iBAAiB;IAClD,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEnC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAQhD,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7E,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,WAAW,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAUzD,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAQzD,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;CAI1C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { escapeSqlLikePattern } from '@krantho/persistence';
|
|
2
|
+
/** SQLite implementation of ISeoConfigAdapter */
|
|
3
|
+
export class SqliteSeoConfigAdapter {
|
|
4
|
+
db;
|
|
5
|
+
constructor(db) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
}
|
|
8
|
+
async getConfig(id) {
|
|
9
|
+
const row = this.db.prepare('SELECT * FROM seo_config WHERE id = ?').get(id);
|
|
10
|
+
return row ? toSeoConfig(row) : null;
|
|
11
|
+
}
|
|
12
|
+
async saveConfig(config) {
|
|
13
|
+
if (config.scope === 'document' || config.id.startsWith('doc:')) {
|
|
14
|
+
throw new Error('Document SEO belongs in versioned document metadata');
|
|
15
|
+
}
|
|
16
|
+
this.db
|
|
17
|
+
.prepare(`INSERT INTO seo_config (id, scope, config, updated_at)
|
|
18
|
+
VALUES (?, ?, ?, datetime('now'))
|
|
19
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
20
|
+
scope = excluded.scope,
|
|
21
|
+
config = excluded.config,
|
|
22
|
+
updated_at = datetime('now')`)
|
|
23
|
+
.run(config.id, config.scope, JSON.stringify(config.config));
|
|
24
|
+
}
|
|
25
|
+
async deleteConfig(id) {
|
|
26
|
+
this.db.prepare('DELETE FROM seo_config WHERE id = ?').run(id);
|
|
27
|
+
}
|
|
28
|
+
async listConfigs(scope) {
|
|
29
|
+
const rows = scope
|
|
30
|
+
? this.db
|
|
31
|
+
.prepare('SELECT * FROM seo_config WHERE scope = ? ORDER BY id')
|
|
32
|
+
.all(scope)
|
|
33
|
+
: this.db.prepare('SELECT * FROM seo_config ORDER BY id').all();
|
|
34
|
+
return rows.map(toSeoConfig);
|
|
35
|
+
}
|
|
36
|
+
async listConfigsByPrefix(prefix) {
|
|
37
|
+
const escaped = escapeSqlLikePattern(prefix);
|
|
38
|
+
const rows = this.db
|
|
39
|
+
.prepare("SELECT * FROM seo_config WHERE id LIKE ? ESCAPE '\\' ORDER BY id")
|
|
40
|
+
.all(`${escaped}%`);
|
|
41
|
+
return rows.map(toSeoConfig);
|
|
42
|
+
}
|
|
43
|
+
async deleteAllConfigs() {
|
|
44
|
+
const result = this.db.prepare('DELETE FROM seo_config').run();
|
|
45
|
+
return result.changes;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function toSeoConfig(row) {
|
|
49
|
+
return {
|
|
50
|
+
id: row.id,
|
|
51
|
+
scope: row.scope,
|
|
52
|
+
config: JSON.parse(row.config),
|
|
53
|
+
createdAt: row.created_at,
|
|
54
|
+
updatedAt: row.updated_at,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=seo-config-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-config-adapter.js","sourceRoot":"","sources":["../src/seo-config-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAI3D,iDAAiD;AACjD,MAAM,OAAO,sBAAsB;IACJ;IAA7B,YAA6B,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAE7C,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,EAAE,CAE9D,CAAA;QAEb,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACtC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAkD;QACjE,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU,IAAI,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAA;QACxE,CAAC;QACD,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;;;;wCAKgC,CACjC;aACA,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAU;QAC3B,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAChE,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAsB;QACtC,MAAM,IAAI,GAAG,KAAK;YAChB,CAAC,CAAE,IAAI,CAAC,EAAE;iBACL,OAAO,CAAC,sDAAsD,CAAC;iBAC/D,GAAG,CAAC,KAAK,CAAoB;YAClC,CAAC,CAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,EAAqB,CAAA;QAErF,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,MAAc;QACtC,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAA;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAC,kEAAkE,CAAC;aAC3E,GAAG,CAAC,GAAG,OAAO,GAAG,CAAmB,CAAA;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,GAAG,EAAE,CAAA;QAC9D,OAAO,MAAM,CAAC,OAAO,CAAA;IACvB,CAAC;CACF;AAUD,SAAS,WAAW,CAAC,GAAiB;IACpC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,KAAK,EAAE,GAAG,CAAC,KAAuB;QAClC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAkB;QAC/C,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;KAC1B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ISiteSettingsAdapter } from '@krantho/persistence';
|
|
2
|
+
/** SQLite implementation of runtime site settings */
|
|
3
|
+
export declare class SqliteSiteSettingsAdapter implements ISiteSettingsAdapter {
|
|
4
|
+
private readonly db;
|
|
5
|
+
constructor(db: import('better-sqlite3').Database);
|
|
6
|
+
getSetting(key: string): Promise<string | null>;
|
|
7
|
+
setSetting(key: string, value: string): Promise<void>;
|
|
8
|
+
getAllSettings(): Promise<Record<string, string>>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=site-settings-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-settings-adapter.d.ts","sourceRoot":"","sources":["../src/site-settings-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAEhE,qDAAqD;AACrD,qBAAa,yBAA0B,YAAW,oBAAoB;IACpE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAmC;gBAE1C,EAAE,EAAE,OAAO,gBAAgB,EAAE,QAAQ;IAI3C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAO/C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrD,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAWxD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** SQLite implementation of runtime site settings */
|
|
2
|
+
export class SqliteSiteSettingsAdapter {
|
|
3
|
+
db;
|
|
4
|
+
constructor(db) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
}
|
|
7
|
+
async getSetting(key) {
|
|
8
|
+
const row = this.db.prepare('SELECT value FROM site_settings WHERE key = ?').get(key);
|
|
9
|
+
return row?.value ?? null;
|
|
10
|
+
}
|
|
11
|
+
async setSetting(key, value) {
|
|
12
|
+
const now = new Date().toISOString();
|
|
13
|
+
this.db
|
|
14
|
+
.prepare(`INSERT INTO site_settings (key, value, updated_at) VALUES (?, ?, ?)
|
|
15
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`)
|
|
16
|
+
.run(key, value, now);
|
|
17
|
+
}
|
|
18
|
+
async getAllSettings() {
|
|
19
|
+
const rows = this.db.prepare('SELECT key, value FROM site_settings').all();
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
result[row.key] = row.value;
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=site-settings-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-settings-adapter.js","sourceRoot":"","sources":["../src/site-settings-adapter.ts"],"names":[],"mappings":"AAEA,qDAAqD;AACrD,MAAM,OAAO,yBAAyB;IACnB,EAAE,CAAmC;IAEtD,YAAY,EAAqC;QAC/C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC,CAAC,GAAG,CAAC,GAAG,CAEvE,CAAA;QACb,OAAO,GAAG,EAAE,KAAK,IAAI,IAAI,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,KAAa;QACzC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;iGACyF,CAC1F;aACA,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,EAGtE,CAAA;QACF,MAAM,MAAM,GAA2B,EAAE,CAAA;QACzC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAA;QAC7B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type ContentMetadata } from '@krantho/core';
|
|
2
|
+
import type { AuthoredMetadata, ContentDocument, ContentQuery, DocumentMeta, IPersistenceAdapter, Publication, QueryPage, QueryProjection, RuntimeSchemaDefinition, WriteContentData } from '@krantho/persistence';
|
|
3
|
+
import type Database from 'better-sqlite3';
|
|
4
|
+
import { type SqliteConnectionOptions } from './connection.js';
|
|
5
|
+
/** Status written when the caller supplies none */
|
|
6
|
+
export interface SqliteDefaultStatus {
|
|
7
|
+
/** Documents upserted from a markdown file whose frontmatter has no status */
|
|
8
|
+
filesystem: string;
|
|
9
|
+
}
|
|
10
|
+
/** Construction options for {@link SQLiteAdapter} */
|
|
11
|
+
export interface SQLiteAdapterOptions extends Partial<SqliteConnectionOptions> {
|
|
12
|
+
/**
|
|
13
|
+
* Locale of every read and write that names none: the site's default locale,
|
|
14
|
+
* `site.defaultLocale` in the krantho configuration.
|
|
15
|
+
*/
|
|
16
|
+
defaultLocale: string;
|
|
17
|
+
defaultStatus?: Partial<SqliteDefaultStatus> | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Status default used when a file declares none.
|
|
21
|
+
*
|
|
22
|
+
* A deployment sets it through `content.defaultStatus.filesystem` in the
|
|
23
|
+
* krantho configuration tree; the server passes the resolved value down. This
|
|
24
|
+
* literal is the standalone-library fallback and mirrors that tree's default.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_SQLITE_STATUS: SqliteDefaultStatus;
|
|
27
|
+
export declare class SQLiteAdapter implements IPersistenceAdapter {
|
|
28
|
+
/** @internal — exposed for checkpoint adapter co-location */
|
|
29
|
+
readonly database: Database.Database;
|
|
30
|
+
private readonly stmts;
|
|
31
|
+
private readonly defaultStatus;
|
|
32
|
+
private readonly defaultLocale;
|
|
33
|
+
constructor(dbPath: string, options: SQLiteAdapterOptions);
|
|
34
|
+
exists(slug: string): Promise<boolean>;
|
|
35
|
+
read(slug: string): Promise<string>;
|
|
36
|
+
getMetadata(slug: string): Promise<Pick<ContentMetadata, 'size' | 'lastModified'>>;
|
|
37
|
+
listSlugs(): Promise<string[]>;
|
|
38
|
+
writeContent(data: WriteContentData, changedBy?: string | undefined): Promise<void>;
|
|
39
|
+
deleteContent(collection: string, slug: string, locale?: string | undefined, changedBy?: string | undefined): Promise<void>;
|
|
40
|
+
getContent(collection: string, slug: string, locale?: string | undefined): Promise<ContentDocument | null>;
|
|
41
|
+
getPublished(collection: string, slug: string, locale?: string | undefined): Promise<ContentDocument | null>;
|
|
42
|
+
query<P extends QueryProjection>(spec: ContentQuery<P>): Promise<QueryPage<P>>;
|
|
43
|
+
listVersions(collection: string, slug: string, locale?: string | undefined): Promise<DocumentMeta[]>;
|
|
44
|
+
getVersion(collection: string, slug: string, version: number, locale?: string | undefined): Promise<ContentDocument | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Import a filesystem content item — creates a new version if content changed.
|
|
47
|
+
* `modifiedAt` (ISO 8601) dates the version when the file last changed, such as
|
|
48
|
+
* its last git commit; without it the version is dated now.
|
|
49
|
+
*/
|
|
50
|
+
upsertFromFile(collection: string, slug: string, fields: Record<string, unknown>, body: string, html: string, sections: Record<string, string>, filePath: string, locale?: string | undefined, modifiedAt?: string | undefined, authored?: (Partial<AuthoredMetadata> & {
|
|
51
|
+
publication: Publication | undefined;
|
|
52
|
+
expectedVersion?: number | undefined;
|
|
53
|
+
}) | undefined): Promise<void>;
|
|
54
|
+
/** Restore content to a specific version — a save: a new current version from the old one, the live version kept */
|
|
55
|
+
restoreVersion(collection: string, slug: string, version: number, changedBy?: string | undefined, locale?: string | undefined): Promise<boolean>;
|
|
56
|
+
/** Get runtime schema extensions for a collection */
|
|
57
|
+
getRuntimeSchema(collection: string): Promise<RuntimeSchemaDefinition | null>;
|
|
58
|
+
/** Save runtime schema extensions for a collection — creates a new schema version */
|
|
59
|
+
saveRuntimeSchema(collection: string, schema: RuntimeSchemaDefinition, changedBy?: string | undefined): Promise<void>;
|
|
60
|
+
/** Close the database connection */
|
|
61
|
+
close(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Core append-only write: flip current, insert the new version. Its live
|
|
64
|
+
* version follows the write's publication (a save keeps it) and its stored
|
|
65
|
+
* status follows the live version.
|
|
66
|
+
*/
|
|
67
|
+
private appendVersion;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=sqlite-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-adapter.d.ts","sourceRoot":"","sources":["../src/sqlite-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { canonicalJson } from '@krantho/core';
|
|
3
|
+
import { authoredOf, ContentWriteConflict, liveOnWrite, nextAuthored, publicationOfFile, resolveLiveVersion, sameAuthoredValues, storedStatus, } from '@krantho/persistence';
|
|
4
|
+
import { openDatabase } from './connection.js';
|
|
5
|
+
import { runContentQuery } from './content-query.js';
|
|
6
|
+
import { runMigrations } from './migration-runner.js';
|
|
7
|
+
import { sqliteMigrations } from './migrations/index.js';
|
|
8
|
+
import { prepareStatements } from './queries.js';
|
|
9
|
+
import { parseJsonRecord, rowToContentDocument, rowToDocumentMeta } from './row-mapping.js';
|
|
10
|
+
/** Safely parse a JSON array column value. */
|
|
11
|
+
function parseJsonArray(json, column) {
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(json);
|
|
14
|
+
if (!Array.isArray(parsed)) {
|
|
15
|
+
throw new Error(`Expected array, got ${parsed === null ? 'null' : typeof parsed}`);
|
|
16
|
+
}
|
|
17
|
+
return parsed;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
21
|
+
throw new Error(`Invalid JSON in ${column} column: ${cause}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Status default used when a file declares none.
|
|
26
|
+
*
|
|
27
|
+
* A deployment sets it through `content.defaultStatus.filesystem` in the
|
|
28
|
+
* krantho configuration tree; the server passes the resolved value down. This
|
|
29
|
+
* literal is the standalone-library fallback and mirrors that tree's default.
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_SQLITE_STATUS = {
|
|
32
|
+
filesystem: 'published',
|
|
33
|
+
};
|
|
34
|
+
export class SQLiteAdapter {
|
|
35
|
+
/** @internal — exposed for checkpoint adapter co-location */
|
|
36
|
+
database;
|
|
37
|
+
stmts;
|
|
38
|
+
defaultStatus;
|
|
39
|
+
defaultLocale;
|
|
40
|
+
constructor(dbPath, options) {
|
|
41
|
+
const { defaultStatus, defaultLocale, ...connection } = options;
|
|
42
|
+
this.defaultLocale = defaultLocale;
|
|
43
|
+
this.defaultStatus = { ...DEFAULT_SQLITE_STATUS, ...defaultStatus };
|
|
44
|
+
this.database = openDatabase(dbPath, connection);
|
|
45
|
+
runMigrations(this.database, sqliteMigrations);
|
|
46
|
+
this.stmts = prepareStatements(this.database);
|
|
47
|
+
}
|
|
48
|
+
// --- IContentLoader methods ---
|
|
49
|
+
async exists(slug) {
|
|
50
|
+
const result = this.stmts.existsBySlug.get(slug);
|
|
51
|
+
return (result?.count ?? 0) > 0;
|
|
52
|
+
}
|
|
53
|
+
async read(slug) {
|
|
54
|
+
const row = this.stmts.getBySlug.get(slug);
|
|
55
|
+
if (!row) {
|
|
56
|
+
throw new Error(`Content not found: ${slug}`);
|
|
57
|
+
}
|
|
58
|
+
// Reconstruct raw markdown with YAML frontmatter for IContentLoader compatibility
|
|
59
|
+
const fields = parseJsonRecord(row.fields, 'fields');
|
|
60
|
+
const yamlLines = Object.entries(fields).map(([k, v]) => `${k}: ${JSON.stringify(v)}`);
|
|
61
|
+
return `---\n${yamlLines.join('\n')}\n---\n${row.body}`;
|
|
62
|
+
}
|
|
63
|
+
async getMetadata(slug) {
|
|
64
|
+
const row = this.stmts.getBySlug.get(slug);
|
|
65
|
+
if (!row) {
|
|
66
|
+
throw new Error(`Content not found: ${slug}`);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
size: row.body.length + row.fields.length,
|
|
70
|
+
lastModified: new Date(row.created_at),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// --- IPersistenceAdapter methods ---
|
|
74
|
+
async listSlugs() {
|
|
75
|
+
const rows = this.stmts.listAllSlugs.all();
|
|
76
|
+
return rows.map((r) => r.slug);
|
|
77
|
+
}
|
|
78
|
+
async writeContent(data, changedBy) {
|
|
79
|
+
this.appendVersion(data.collection, data.slug, data.locale ?? this.defaultLocale, {
|
|
80
|
+
authored: authoredOf(data),
|
|
81
|
+
expectedVersion: data.expectedVersion,
|
|
82
|
+
fields: JSON.stringify(data.fields),
|
|
83
|
+
body: data.body,
|
|
84
|
+
html: data.html ?? '',
|
|
85
|
+
sections: data.sections ? JSON.stringify(data.sections) : '{}',
|
|
86
|
+
source: 'api',
|
|
87
|
+
filePath: null,
|
|
88
|
+
changedBy: changedBy ?? null,
|
|
89
|
+
publication: data.publication,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async deleteContent(collection, slug, locale, changedBy) {
|
|
93
|
+
const row = this.stmts.getByCollectionSlugLocale.get(collection, slug, locale ?? this.defaultLocale);
|
|
94
|
+
if (!row)
|
|
95
|
+
return;
|
|
96
|
+
const now = new Date().toISOString();
|
|
97
|
+
const maxResult = this.stmts.getMaxVersion.get(collection, slug, row.locale);
|
|
98
|
+
const nextVersion = (maxResult?.max_version ?? 0) + 1;
|
|
99
|
+
this.database
|
|
100
|
+
.transaction(() => {
|
|
101
|
+
this.stmts.flipCurrent.run(collection, slug, row.locale);
|
|
102
|
+
this.stmts.insertVersion.run(randomUUID(), collection, slug, row.locale, nextVersion, 'deleted', '{}', '', '', '{}', 'api', null, changedBy ?? null, now, now, null, // live_version: nothing is live after a delete
|
|
103
|
+
row.authored);
|
|
104
|
+
})
|
|
105
|
+
.immediate();
|
|
106
|
+
}
|
|
107
|
+
async getContent(collection, slug, locale) {
|
|
108
|
+
const row = this.stmts.getByCollectionSlugLocale.get(collection, slug, locale ?? this.defaultLocale);
|
|
109
|
+
return row ? rowToContentDocument(row) : null;
|
|
110
|
+
}
|
|
111
|
+
async getPublished(collection, slug, locale) {
|
|
112
|
+
const row = this.stmts.getPublished.get(collection, slug, locale ?? this.defaultLocale);
|
|
113
|
+
return row ? rowToContentDocument(row) : null;
|
|
114
|
+
}
|
|
115
|
+
async query(spec) {
|
|
116
|
+
return runContentQuery(this.database, spec);
|
|
117
|
+
}
|
|
118
|
+
async listVersions(collection, slug, locale) {
|
|
119
|
+
const rows = this.stmts.listVersionMeta.all(collection, slug, locale ?? this.defaultLocale);
|
|
120
|
+
return rows.map(rowToDocumentMeta);
|
|
121
|
+
}
|
|
122
|
+
async getVersion(collection, slug, version, locale) {
|
|
123
|
+
const row = this.stmts.getVersionByNumber.get(collection, slug, locale ?? this.defaultLocale, version);
|
|
124
|
+
return row ? rowToContentDocument(row) : null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Import a filesystem content item — creates a new version if content changed.
|
|
128
|
+
* `modifiedAt` (ISO 8601) dates the version when the file last changed, such as
|
|
129
|
+
* its last git commit; without it the version is dated now.
|
|
130
|
+
*/
|
|
131
|
+
async upsertFromFile(collection, slug, fields, body, html, sections, filePath, locale, modifiedAt, authored) {
|
|
132
|
+
const loc = locale ?? this.defaultLocale;
|
|
133
|
+
const status = typeof fields['status'] === 'string' ? fields['status'] : this.defaultStatus.filesystem;
|
|
134
|
+
const fieldsJson = JSON.stringify(fields);
|
|
135
|
+
const sectionsJson = JSON.stringify(sections);
|
|
136
|
+
// Check if content exists and is unchanged
|
|
137
|
+
const existing = this.stmts.getByCollectionSlugLocale.get(collection, slug, loc);
|
|
138
|
+
if (existing &&
|
|
139
|
+
canonicalJson(JSON.parse(existing.fields)) === canonicalJson(fields) &&
|
|
140
|
+
existing.body === body &&
|
|
141
|
+
sameAuthoredValues(JSON.parse(existing.authored), authored ?? {})) {
|
|
142
|
+
return; // No change — skip
|
|
143
|
+
}
|
|
144
|
+
this.appendVersion(collection, slug, loc, {
|
|
145
|
+
fields: fieldsJson,
|
|
146
|
+
body,
|
|
147
|
+
html,
|
|
148
|
+
sections: sectionsJson,
|
|
149
|
+
source: 'filesystem',
|
|
150
|
+
filePath,
|
|
151
|
+
changedBy: null,
|
|
152
|
+
publication: authored ? authored.publication : publicationOfFile(status),
|
|
153
|
+
authored: authoredOf(authored ?? {}),
|
|
154
|
+
expectedVersion: authored?.expectedVersion,
|
|
155
|
+
createdAt: modifiedAt,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/** Restore content to a specific version — a save: a new current version from the old one, the live version kept */
|
|
159
|
+
async restoreVersion(collection, slug, version, changedBy, locale) {
|
|
160
|
+
const target = this.stmts.getVersionByNumber.get(collection, slug, locale ?? this.defaultLocale, version);
|
|
161
|
+
if (!target)
|
|
162
|
+
return false;
|
|
163
|
+
this.appendVersion(collection, slug, target.locale, {
|
|
164
|
+
authored: JSON.parse(target.authored),
|
|
165
|
+
fields: target.fields,
|
|
166
|
+
body: target.body,
|
|
167
|
+
html: target.html,
|
|
168
|
+
sections: target.sections,
|
|
169
|
+
source: target.source,
|
|
170
|
+
filePath: target.file_path,
|
|
171
|
+
changedBy: changedBy ?? `restore:v${version}`,
|
|
172
|
+
publication: undefined,
|
|
173
|
+
});
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
/** Get runtime schema extensions for a collection */
|
|
177
|
+
async getRuntimeSchema(collection) {
|
|
178
|
+
const row = this.database
|
|
179
|
+
.prepare('SELECT collection, fields, metadata_groups, created_at FROM collection_schemas WHERE collection = ? AND is_current = 1 AND deleted_at IS NULL')
|
|
180
|
+
.get(collection);
|
|
181
|
+
if (!row)
|
|
182
|
+
return null;
|
|
183
|
+
return {
|
|
184
|
+
collection: row.collection,
|
|
185
|
+
fields: parseJsonArray(row.fields, 'fields'),
|
|
186
|
+
metadata: parseJsonArray(row.metadata_groups, 'metadata_groups'),
|
|
187
|
+
updatedAt: row.created_at,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Save runtime schema extensions for a collection — creates a new schema version */
|
|
191
|
+
async saveRuntimeSchema(collection, schema, changedBy) {
|
|
192
|
+
const now = new Date().toISOString();
|
|
193
|
+
const fieldsJson = JSON.stringify(schema.fields);
|
|
194
|
+
// Get current version
|
|
195
|
+
const current = this.database
|
|
196
|
+
.prepare('SELECT version FROM collection_schemas WHERE collection = ? AND is_current = 1')
|
|
197
|
+
.get(collection);
|
|
198
|
+
const nextVersion = current ? current.version + 1 : 1;
|
|
199
|
+
this.database
|
|
200
|
+
.transaction(() => {
|
|
201
|
+
if (current) {
|
|
202
|
+
this.database
|
|
203
|
+
.prepare('UPDATE collection_schemas SET is_current = 0 WHERE collection = ? AND is_current = 1')
|
|
204
|
+
.run(collection);
|
|
205
|
+
}
|
|
206
|
+
this.database
|
|
207
|
+
.prepare('INSERT INTO collection_schemas (row_id, collection, version, is_current, fields, changed_by, created_at, metadata_groups) VALUES (?, ?, ?, 1, ?, ?, ?, ?)')
|
|
208
|
+
.run(randomUUID(), collection, nextVersion, fieldsJson, changedBy ?? null, now, JSON.stringify(schema.metadata ?? []));
|
|
209
|
+
})
|
|
210
|
+
.immediate();
|
|
211
|
+
}
|
|
212
|
+
/** Close the database connection */
|
|
213
|
+
close() {
|
|
214
|
+
this.database.close();
|
|
215
|
+
}
|
|
216
|
+
// --- Private helpers ---
|
|
217
|
+
/**
|
|
218
|
+
* Core append-only write: flip current, insert the new version. Its live
|
|
219
|
+
* version follows the write's publication (a save keeps it) and its stored
|
|
220
|
+
* status follows the live version.
|
|
221
|
+
*/
|
|
222
|
+
appendVersion(collection, slug, locale, data) {
|
|
223
|
+
const now = data.createdAt ?? new Date().toISOString();
|
|
224
|
+
this.database
|
|
225
|
+
.transaction(() => {
|
|
226
|
+
const maxResult = this.stmts.getMaxVersion.get(collection, slug, locale);
|
|
227
|
+
if (data.expectedVersion !== undefined &&
|
|
228
|
+
data.expectedVersion !== (maxResult?.max_version ?? 0)) {
|
|
229
|
+
throw new ContentWriteConflict(maxResult?.max_version ?? 0, data.expectedVersion);
|
|
230
|
+
}
|
|
231
|
+
const nextVersion = (maxResult?.max_version ?? 0) + 1;
|
|
232
|
+
const previous = this.stmts.getCurrentState.get(collection, slug, locale);
|
|
233
|
+
const liveVersion = resolveLiveVersion(liveOnWrite(data.publication), nextVersion, previous?.live_version ?? null);
|
|
234
|
+
const status = storedStatus(data.publication, liveVersion, previous?.status);
|
|
235
|
+
this.stmts.flipCurrent.run(collection, slug, locale);
|
|
236
|
+
this.stmts.insertVersion.run(randomUUID(), collection, slug, locale, nextVersion, status, data.fields, data.body, data.html, data.sections, data.source, data.filePath, data.changedBy, null, // deleted_at
|
|
237
|
+
now, liveVersion, JSON.stringify(nextAuthored(previous ? JSON.parse(previous.authored) : null, data.authored ?? {}, nextVersion)));
|
|
238
|
+
})
|
|
239
|
+
.immediate();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=sqlite-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-adapter.js","sourceRoot":"","sources":["../src/sqlite-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IWebhookDeliveryAdapter, NewWebhookDelivery, StoredWebhookDelivery, WebhookDeliveryRecord } from '@krantho/persistence';
|
|
2
|
+
/** SQLite implementation of webhook delivery log */
|
|
3
|
+
export declare class SqliteWebhookDeliveryAdapter implements IWebhookDeliveryAdapter {
|
|
4
|
+
private readonly db;
|
|
5
|
+
constructor(db: import('better-sqlite3').Database);
|
|
6
|
+
listDeliveries(options: {
|
|
7
|
+
limit: number;
|
|
8
|
+
offset: number;
|
|
9
|
+
status?: 'pending' | 'delivered' | 'failed' | undefined;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
deliveries: WebhookDeliveryRecord[];
|
|
12
|
+
total: number;
|
|
13
|
+
}>;
|
|
14
|
+
getDelivery(id: number): Promise<StoredWebhookDelivery | null>;
|
|
15
|
+
requeueDelivery(id: number, dueAt: Date): Promise<WebhookDeliveryRecord | null>;
|
|
16
|
+
logDelivery(delivery: NewWebhookDelivery): Promise<number>;
|
|
17
|
+
markDelivered(id: number, status: number): Promise<void>;
|
|
18
|
+
markFailed(id: number, status: number, nextRetryAt: Date): Promise<void>;
|
|
19
|
+
claimDueDeliveries(options: {
|
|
20
|
+
urls: readonly string[];
|
|
21
|
+
now: Date;
|
|
22
|
+
leaseUntil: Date;
|
|
23
|
+
limit: number;
|
|
24
|
+
}): Promise<StoredWebhookDelivery[]>;
|
|
25
|
+
private row;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=webhook-delivery-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-delivery-adapter.d.ts","sourceRoot":"","sources":["../src/webhook-delivery-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,sBAAsB,CAAA;AA+B7B,oDAAoD;AACpD,qBAAa,4BAA6B,YAAW,uBAAuB;IAC1E,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAmC;gBAE1C,EAAE,EAAE,OAAO,gBAAgB,EAAE,QAAQ;IAI3C,cAAc,CAAC,OAAO,EAAE;QAC5B,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;KACxD,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,qBAAqB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAwB7D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAK9D,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAW/E,WAAW,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAY1D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxE,kBAAkB,CAAC,OAAO,EAAE;QAChC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;QACvB,GAAG,EAAE,IAAI,CAAA;QACT,UAAU,EAAE,IAAI,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IA0BpC,OAAO,CAAC,GAAG;CAKZ"}
|