UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

596 lines (580 loc) 22.5 kB
import { logging_default, lucid_error_default, translations_default } from "./chunk-ZMWDUGJW.js"; // src/libs/db/adapters/postgres/index.ts import pg from "pg"; import { PostgresDialect } from "kysely"; // src/libs/db/adapter.ts import { Kysely, Migrator } from "kysely"; import { jsonArrayFrom } from "kysely/helpers/sqlite"; // src/libs/db/migrations/00000001-locales.ts import { sql as sql2 } from "kysely"; // src/libs/db/kysely/column-helpers.ts import { sql } from "kysely"; var defaultTimestamp = (col, adapter) => { switch (adapter) { case 0 /* SQLITE */: return col.defaultTo(sql`CURRENT_TIMESTAMP`); case 1 /* POSTGRES */: return col.defaultTo(sql`NOW()`); case 2 /* LIBSQL */: return col.defaultTo(sql`CURRENT_TIMESTAMP`); } }; var primaryKeyColumnType = (adapter) => { switch (adapter) { case 0 /* SQLITE */: return "integer"; case 1 /* POSTGRES */: return "serial"; case 2 /* LIBSQL */: return "integer"; } }; var primaryKeyColumn = (col, adapter) => { switch (adapter) { case 0 /* SQLITE */: return col.primaryKey().autoIncrement(); case 1 /* POSTGRES */: return col.primaryKey(); case 2 /* LIBSQL */: return col.primaryKey().autoIncrement(); } }; // src/libs/db/migrations/00000001-locales.ts var Migration00000001 = (adapter) => { return { async up(db) { if (adapter === 1 /* POSTGRES */) { await sql2`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db); } await db.schema.createTable("lucid_locales").addColumn("code", "text", (col) => col.primaryKey()).addColumn("is_deleted", "integer", (col) => col.defaultTo(0)).addColumn("is_deleted_at", "timestamp", (col) => col.defaultTo(null)).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); }, async down(db) { } }; }; var locales_default = Migration00000001; // src/libs/db/migrations/00000002-translations.ts var Migration00000002 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_translation_keys").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn("created_at", "timestamp", (col) => col.notNull()).execute(); await db.schema.createTable("lucid_translations").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "translation_key_id", "integer", (col) => col.references("lucid_translation_keys.id").notNull().onDelete("cascade").onUpdate("cascade") ).addColumn( "locale_code", "text", (col) => col.references("lucid_locales.code").notNull().onDelete("cascade").onUpdate("cascade") ).addColumn("value", "text").addUniqueConstraint( "lucid_translations_translation_key_id_locale_code_unique", ["translation_key_id", "locale_code"] ).execute(); await db.schema.createIndex("idx_translation_key_locale").on("lucid_translations").columns(["translation_key_id", "locale_code"]).execute(); }, async down(db) { } }; }; var translations_default2 = Migration00000002; // src/libs/db/migrations/00000003-options.ts var Migration00000003 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_options").addColumn("name", "text", (col) => col.unique().notNull().primaryKey()).addColumn("value_int", "integer").addColumn("value_text", "text").addColumn("value_bool", "integer").execute(); }, async down(db) { } }; }; var options_default = Migration00000003; // src/libs/db/migrations/00000004-users-and-permissions.ts var Migration00000004 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_users").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "super_admin", "integer", (col) => col.defaultTo(0).notNull() ).addColumn("email", "text", (col) => col.notNull().unique()).addColumn("username", "text", (col) => col.notNull().unique()).addColumn("first_name", "text").addColumn("last_name", "text").addColumn("password", "text").addColumn("secret", "text", (col) => col.notNull()).addColumn( "triggered_password_reset", "integer", (col) => col.defaultTo(0) ).addColumn("is_deleted", "integer", (col) => col.defaultTo(0)).addColumn("is_deleted_at", "timestamp").addColumn( "deleted_by", "integer", (col) => col.references("lucid_users.id").onDelete("set null") ).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createTable("lucid_roles").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn("name", "text", (col) => col.notNull().unique()).addColumn("description", "text").addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createTable("lucid_role_permissions").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "role_id", "integer", (col) => col.references("lucid_roles.id").onDelete("cascade") ).addColumn("permission", "text", (col) => col.notNull()).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createTable("lucid_user_roles").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "user_id", "integer", (col) => col.references("lucid_users.id").onDelete("cascade") ).addColumn( "role_id", "integer", (col) => col.references("lucid_roles.id").onDelete("cascade") ).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createTable("lucid_user_tokens").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "user_id", "integer", (col) => col.references("lucid_users.id").onDelete("cascade") ).addColumn("token_type", "varchar(255)").addColumn("token", "varchar(255)", (col) => col.notNull().unique()).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn("expiry_date", "timestamp", (col) => col.notNull()).execute(); }, async down(db) { } }; }; var users_and_permissions_default = Migration00000004; // src/libs/db/migrations/00000005-emails.ts var Migration00000005 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_emails").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn("email_hash", "char(64)", (col) => col.unique().notNull()).addColumn("from_address", "text", (col) => col.notNull()).addColumn("from_name", "text", (col) => col.notNull()).addColumn("to_address", "text", (col) => col.notNull()).addColumn("subject", "text", (col) => col.notNull()).addColumn("cc", "text").addColumn("bcc", "text").addColumn("delivery_status", "text", (col) => col.notNull()).addColumn("template", "text", (col) => col.notNull()).addColumn("data", "text").addColumn("type", "text", (col) => col.notNull()).addColumn("sent_count", "integer", (col) => col.notNull().defaultTo(0)).addColumn( "error_count", "integer", (col) => col.notNull().defaultTo(0) ).addColumn("last_error_message", "text").addColumn( "last_attempt_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn("last_success_at", "timestamp").addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); }, async down(db) { } }; }; var emails_default = Migration00000005; // src/libs/db/migrations/00000006-media.ts var Migration00000006 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_media").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn("key", "text", (col) => col.unique().notNull()).addColumn("e_tag", "text").addColumn("visible", "integer", (col) => col.notNull().defaultTo(1)).addColumn("type", "text", (col) => col.notNull()).addColumn("mime_type", "text", (col) => col.notNull()).addColumn("file_extension", "text", (col) => col.notNull()).addColumn("file_size", "integer", (col) => col.notNull()).addColumn("width", "integer").addColumn("height", "integer").addColumn("blur_hash", "text").addColumn("average_colour", "text").addColumn("is_dark", "integer").addColumn("is_light", "integer").addColumn( "title_translation_key_id", "integer", (col) => col.references("lucid_translation_keys.id").onDelete("set null").onUpdate("cascade") ).addColumn( "alt_translation_key_id", "integer", (col) => col.references("lucid_translation_keys.id").onDelete("set null").onUpdate("cascade") ).addColumn("custom_meta", "text").addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createIndex("idx_lucid_media_key").on("lucid_media").column("key").execute(); await db.schema.createTable("lucid_media_awaiting_sync").addColumn("key", "text", (col) => col.primaryKey()).addColumn("timestamp", "timestamp", (col) => col.notNull()).execute(); await db.schema.createTable("lucid_processed_images").addColumn("key", "text", (col) => col.primaryKey()).addColumn( "media_key", "text", (col) => col.references("lucid_media.key").onDelete("cascade").onUpdate("cascade") ).addColumn("file_size", "integer", (col) => col.notNull()).execute(); await db.schema.createIndex("idx_processed_images_media_key").on("lucid_processed_images").column("media_key").execute(); }, async down(db) { } }; }; var media_default = Migration00000006; // src/libs/db/migrations/00000007-collections.ts var Migration00000007 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_collection_documents").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn("collection_key", "text", (col) => col.notNull()).addColumn("is_deleted", "integer", (col) => col.defaultTo(0)).addColumn("is_deleted_at", "timestamp").addColumn( "deleted_by", "integer", (col) => col.references("lucid_users.id").onDelete("set null") ).addColumn( "created_by", "integer", (col) => col.references("lucid_users.id").onDelete("set null") ).addColumn( "updated_by", "integer", (col) => col.references("lucid_users.id").onDelete("set null") ).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createTable("lucid_collection_document_versions").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "document_id", "integer", (col) => col.references("lucid_collection_documents.id").onDelete("cascade").notNull() ).addColumn("version_type", "text", (col) => col.notNull()).addColumn( "promoted_from", "integer", (col) => col.references("lucid_collection_document_versions.id").onDelete("set null") ).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "created_by", "integer", (col) => col.references("lucid_users.id").onDelete("set null") ).execute(); await db.schema.createIndex("idx_document_versions_document_id").on("lucid_collection_document_versions").column("document_id").execute(); await db.schema.createTable("lucid_collection_document_bricks").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "collection_document_version_id", "integer", (col) => col.references("lucid_collection_document_versions.id").onDelete("cascade").notNull() ).addColumn("brick_type", "text", (col) => col.notNull()).addColumn("brick_key", "text").addColumn("brick_order", "integer").addColumn("brick_open", "integer", (col) => col.defaultTo(0)).execute(); await db.schema.createTable("lucid_collection_document_groups").addColumn( "group_id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "collection_document_version_id", "integer", (col) => col.references("lucid_collection_document_versions.id").onDelete("cascade").notNull() ).addColumn( "collection_document_id", "integer", (col) => col.references("lucid_collection_documents.id").onDelete("cascade").notNull() ).addColumn( "collection_brick_id", "integer", (col) => col.references("lucid_collection_document_bricks.id").onDelete("cascade").notNull() ).addColumn( "parent_group_id", "integer", (col) => col.references("lucid_collection_document_groups.group_id").onDelete("cascade") ).addColumn("group_open", "integer", (col) => col.defaultTo(0)).addColumn("repeater_key", "text", (col) => col.notNull()).addColumn("group_order", "integer", (col) => col.notNull()).addColumn("ref", "text").execute(); await db.schema.createIndex("idx_lucid_groups_collection_brick_id").on("lucid_collection_document_groups").column("collection_brick_id").execute(); await db.schema.createIndex("idx_lucid_groups_parent_group_id").on("lucid_collection_document_groups").column("parent_group_id").execute(); await db.schema.createTable("lucid_collection_document_fields").addColumn( "fields_id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn( "collection_document_version_id", "integer", (col) => col.references("lucid_collection_document_versions.id").onDelete("cascade").notNull() ).addColumn( "collection_document_id", "integer", (col) => col.references("lucid_collection_documents.id").onDelete("cascade").notNull() ).addColumn( "collection_brick_id", "integer", (col) => col.references("lucid_collection_document_bricks.id").onDelete("cascade").notNull() ).addColumn( "group_id", "integer", (col) => col.references("lucid_collection_document_groups.group_id").onDelete("cascade") ).addColumn( "locale_code", "text", (col) => col.references("lucid_locales.code").onDelete("cascade").notNull() ).addColumn("key", "text", (col) => col.notNull()).addColumn("type", "text", (col) => col.notNull()).addColumn("text_value", "text").addColumn("int_value", "integer").addColumn("bool_value", "integer").addColumn("json_value", "text").addColumn( "media_id", "integer", (col) => col.references("lucid_media.id").onDelete("set null") ).addColumn( "document_id", "integer", (col) => col.references("lucid_collection_documents.id").onDelete("set null") ).addColumn( "user_id", "integer", (col) => col.references("lucid_users.id").onDelete("set null") ).execute(); await db.schema.createIndex("idx_lucid_fields_locale_code").on("lucid_collection_document_fields").column("locale_code").execute(); await db.schema.createIndex("idx_lucid_fields_collection_brick_id").on("lucid_collection_document_fields").column("collection_brick_id").execute(); await db.schema.createIndex("idx_lucid_fields_group_id").on("lucid_collection_document_fields").column("group_id").execute(); }, async down(_db) { } }; }; var collections_default = Migration00000007; // src/libs/db/migrations/00000008-integrations.ts var Migration00000008 = (adapter) => { return { async up(db) { await db.schema.createTable("lucid_client_integrations").addColumn( "id", primaryKeyColumnType(adapter), (col) => primaryKeyColumn(col, adapter) ).addColumn("name", "text", (col) => col.notNull()).addColumn("description", "text").addColumn("enabled", "integer", (col) => col.notNull()).addColumn("key", "text", (col) => col.notNull().unique()).addColumn("api_key", "text", (col) => col.notNull()).addColumn("secret", "text", (col) => col.notNull()).addColumn( "created_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).addColumn( "updated_at", "timestamp", (col) => defaultTimestamp(col, adapter) ).execute(); await db.schema.createIndex("idx_lucid_client_integrations_key").on("lucid_client_integrations").column("key").execute(); await db.schema.createIndex("idx_lucid_client_integrations_api_key").on("lucid_client_integrations").column("api_key").execute(); await db.schema.createIndex("idx_lucid_client_integrations_secret").on("lucid_client_integrations").column("secret").execute(); }, async down(db) { } }; }; var integrations_default = Migration00000008; // src/libs/db/adapter.ts var DatabaseAdapter = class { db; adapter; constructor(config) { this.adapter = config.adapter; this.db = new Kysely({ dialect: config.dialect, plugins: config.plugins }); } // Public methods async migrateToLatest() { const migrator = this.migrator; const { error, results } = await migrator.migrateToLatest(); if (results) { for (const it of results) { if (it.status === "Success") { logging_default("info", { message: `"${it.migrationName}" was executed successfully`, scope: "migration" }); } else if (it.status === "Error") { logging_default("error", { message: `failed to execute migration "${it.migrationName}"`, scope: "migration" }); } } } if (error) { throw new lucid_error_default({ // @ts-expect-error message: error?.message || translations_default("db_migration_failed"), // @ts-expect-error data: error.errors, kill: true }); } } // getters get client() { if (!this.db) { throw new lucid_error_default({ message: translations_default("db_connection_error") }); } return this.db; } get jsonArrayFrom() { return jsonArrayFrom; } get fuzzOperator() { return "like"; } get migrations() { return { "00000001-locales": locales_default(this.adapter), "00000002-translations": translations_default2(this.adapter), "00000003-options": options_default(this.adapter), "00000004-users-and-permissions": users_and_permissions_default(this.adapter), "00000005-emails": emails_default(this.adapter), "00000006-media": media_default(this.adapter), "00000007-collections": collections_default(this.adapter), "00000008-integrations": integrations_default(this.adapter) }; } get migrator() { const m = this.migrations; return new Migrator({ db: this.client, provider: { async getMigrations() { return m; } } }); } }; // src/libs/db/adapters/postgres/index.ts import { jsonArrayFrom as jsonArrayFrom2 } from "kysely/helpers/postgres"; var { Pool } = pg; var PostgresAdapter = class extends DatabaseAdapter { constructor(config) { super({ adapter: 1 /* POSTGRES */, dialect: new PostgresDialect({ pool: new Pool(config) }) }); } // Getters get jsonArrayFrom() { return jsonArrayFrom2; } get fuzzOperator() { return "%"; } }; // src/libs/db/adapters/libsql/index.ts import { LibsqlDialect } from "@libsql/kysely-libsql"; import { ParseJSONResultsPlugin } from "kysely"; import { jsonArrayFrom as jsonArrayFrom3 } from "kysely/helpers/sqlite"; var LibsqlAdapter = class extends DatabaseAdapter { constructor(config) { super({ adapter: 2 /* LIBSQL */, dialect: new LibsqlDialect(config), plugins: [new ParseJSONResultsPlugin()] }); } // Getters get jsonArrayFrom() { return jsonArrayFrom3; } get fuzzOperator() { return "like"; } }; // src/libs/db/adapters/sqlite/index.ts import { SqliteDialect, ParseJSONResultsPlugin as ParseJSONResultsPlugin2 } from "kysely"; import { jsonArrayFrom as jsonArrayFrom4 } from "kysely/helpers/sqlite"; var SqliteAdapter = class extends DatabaseAdapter { constructor(config) { super({ adapter: 0 /* SQLITE */, dialect: new SqliteDialect(config), plugins: [new ParseJSONResultsPlugin2()] }); } // Getters get jsonArrayFrom() { return jsonArrayFrom4; } get fuzzOperator() { return "like"; } }; export { LibsqlAdapter as LibSQLAdapter, PostgresAdapter, SqliteAdapter as SQLiteAdapter }; //# sourceMappingURL=adapters.js.map