From fbe06e611c3b56e91944ca1bf491d678c1a5e147 Mon Sep 17 00:00:00 2001 From: Jon <4leite@gmail.com> Date: Sun, 9 Jun 2024 23:13:49 +1200 Subject: [PATCH 1/3] move development mode to wrappers --- .../src/pages/docs/plugins/database/turso.mdx | 10 - apps/playground/oberon/adapter.ts | 12 +- apps/playground/oberon/prebuild.ts | 3 - apps/playground/package.json | 1 + package.json | 4 +- packages/create-oberon-app/package.json | 6 + .../plugins/database/custom.ts | 10 +- packages/create-oberon-app/src/index.ts | 50 +-- .../src/{program => installer}/config.ts | 0 .../src/{program => installer}/init-git.ts | 0 .../src/installer/install-adapter.ts | 100 +++++ .../write-env.ts => installer/install-env.ts} | 6 +- .../src/installer/install-packages.ts | 121 ++++++ .../install-template.ts} | 2 +- .../{program => installer}/prompt-options.ts | 11 +- .../src/program/install-packages.ts | 49 --- .../src/program/update-package.ts | 48 --- .../src/program/write-plugins.ts | 56 --- packages/oberoncms/core/package.json | 1 + packages/oberoncms/core/src/adapter.tsx | 402 +----------------- .../core/src/{app => adapter}/base-adapter.ts | 2 +- packages/oberoncms/core/src/adapter/dotenv.ts | 2 + .../export-tailwind-clases.ts | 2 +- .../core/src/adapter/init-actions.tsx | 360 ++++++++++++++++ .../core/src/adapter/init-adapter.tsx | 33 ++ .../core/src/{app => adapter}/mock-plugin.ts | 2 +- packages/oberoncms/core/src/auth.tsx | 2 + packages/oberoncms/core/src/auth/next-auth.ts | 14 +- .../core/src/auth/with-development-send.ts | 28 ++ .../oberoncms/core/src/components/editor.tsx | 2 +- .../oberoncms/core/src/components/images.tsx | 2 +- .../oberoncms/core/src/components/pages.tsx | 2 +- .../core/src/components/provider.tsx | 2 +- .../oberoncms/core/src/components/site.tsx | 2 +- .../oberoncms/core/src/components/users.tsx | 2 +- packages/oberoncms/core/src/editor.tsx | 4 +- .../core/src/hooks/use-oberon-images.ts | 2 +- packages/oberoncms/core/src/index.ts | 6 +- .../core/src/{app/schema.ts => lib/dtd.ts} | 0 .../core/src/{app => lib}/get-initial-data.ts | 2 +- .../core/src/{app => lib}/get-metadata.ts | 2 +- .../core/src/{app => lib}/transforms.ts | 2 +- .../oberoncms/core/src/{app => lib}/utils.ts | 2 +- packages/oberoncms/core/src/provider.tsx | 4 +- packages/oberoncms/core/src/render.tsx | 4 +- .../{fly-drive => flydrive}/.prettierignore | 0 .../{fly-drive => flydrive}/CHANGELOG.md | 0 .../plugins/{fly-drive => flydrive}/README.md | 0 .../{fly-drive => flydrive}/eslint.config.mjs | 0 .../{fly-drive => flydrive}/package.json | 0 .../src/blocks/client.tsx | 0 .../src/blocks/field.ts | 0 .../src/blocks/image-field.tsx | 0 .../src/blocks/server.tsx | 0 .../{fly-drive => flydrive}/src/index.ts | 0 .../src/internal/disk-handlers.ts | 0 .../src/internal/get-image-size.ts | 0 .../src/internal/plugin.ts | 0 .../{fly-drive => flydrive}/src/plugin.ts | 0 .../{fly-drive => flydrive}/src/server.ts | 0 .../{fly-drive => flydrive}/tsconfig.json | 0 .../{fly-drive => flydrive}/vite.config.js | 0 packages/plugins/pgsql/drizzle.config.ts | 3 - packages/plugins/pgsql/package.json | 7 +- packages/plugins/pgsql/src/adapter.ts | 6 + packages/plugins/pgsql/src/db/auth-adapter.ts | 6 +- packages/plugins/pgsql/src/db/client.ts | 4 +- .../plugins/pgsql/src/db/database-adapter.ts | 14 +- packages/plugins/pgsql/src/db/init.ts | 17 - packages/plugins/pgsql/src/index.ts | 29 +- packages/plugins/pgsql/src/schema.ts | 1 + packages/plugins/sqlite/.prettierignore | 5 + packages/plugins/sqlite/drizzle.config.ts | 10 + packages/plugins/sqlite/eslint.config.mjs | 1 + packages/plugins/sqlite/package.json | 67 +++ packages/plugins/sqlite/src/adapter.ts | 6 + .../{turso => sqlite}/src/db/auth-adapter.ts | 35 +- packages/plugins/sqlite/src/db/client.ts | 32 ++ .../src/db/database-adapter.ts | 61 ++- .../src/db/migrations/0000_faulty_menace.sql | 56 +++ .../src/db/migrations/0001_dear_vapor.sql | 7 + .../src/db/migrations/meta/0000_snapshot.json | 358 ++++++++++++++++ .../src/db/migrations/meta/0001_snapshot.json | 402 ++++++++++++++++++ .../src/db/migrations/meta/_journal.json | 20 + .../src/db/schema/image-schema.ts | 0 .../plugins/sqlite/src/db/schema/index.ts | 4 + .../src/db/schema/next-auth-schema.ts | 0 .../src/db/schema/puck-schema.ts | 0 .../src/db/schema/site-schema.ts | 0 packages/plugins/sqlite/src/index.ts | 56 +++ packages/plugins/sqlite/src/schema.ts | 1 + packages/plugins/sqlite/tsconfig.json | 10 + packages/plugins/sqlite/vite.config.js | 3 + packages/plugins/turso/drizzle.config.ts | 3 - packages/plugins/turso/package.json | 2 +- packages/plugins/turso/src/db/client.ts | 56 +-- .../plugins/turso/src/db/database-adapter.ts | 109 ----- .../src/db/drizzle-kit/meta/_journal.json | 1 - packages/plugins/turso/src/db/init.ts | 19 - packages/plugins/turso/src/db/schema/index.ts | 5 +- packages/plugins/turso/src/index.ts | 34 +- packages/plugins/vercel-postgres/package.json | 2 +- .../vercel-postgres/src/db/auth-adapter.ts | 5 - .../plugins/vercel-postgres/src/db/client.ts | 2 +- .../src/db/{env-config.ts => env.ts} | 0 .../plugins/vercel-postgres/src/db/init.ts | 18 - .../src/db/schema/image-schema.ts | 26 -- .../vercel-postgres/src/db/schema/index.ts | 5 +- .../src/db/schema/next-auth-schema.ts | 65 --- .../src/db/schema/puck-schema.ts | 23 - .../src/db/schema/site-schema.ts | 25 -- packages/plugins/vercel-postgres/src/index.ts | 30 +- playwright.config.ts | 8 +- pnpm-lock.yaml | 191 +++++++-- recipes/nextjs/oberon/prebuild.ts | 4 - recipes/nextjs/package.json | 1 - 116 files changed, 2079 insertions(+), 1153 deletions(-) rename packages/create-oberon-app/src/{program => installer}/config.ts (100%) rename packages/create-oberon-app/src/{program => installer}/init-git.ts (100%) create mode 100644 packages/create-oberon-app/src/installer/install-adapter.ts rename packages/create-oberon-app/src/{program/write-env.ts => installer/install-env.ts} (69%) create mode 100644 packages/create-oberon-app/src/installer/install-packages.ts rename packages/create-oberon-app/src/{program/copy-template.ts => installer/install-template.ts} (96%) rename packages/create-oberon-app/src/{program => installer}/prompt-options.ts (90%) delete mode 100644 packages/create-oberon-app/src/program/install-packages.ts delete mode 100644 packages/create-oberon-app/src/program/update-package.ts delete mode 100644 packages/create-oberon-app/src/program/write-plugins.ts rename packages/oberoncms/core/src/{app => adapter}/base-adapter.ts (96%) create mode 100644 packages/oberoncms/core/src/adapter/dotenv.ts rename packages/oberoncms/core/src/{app => adapter}/export-tailwind-clases.ts (95%) create mode 100644 packages/oberoncms/core/src/adapter/init-actions.tsx create mode 100644 packages/oberoncms/core/src/adapter/init-adapter.tsx rename packages/oberoncms/core/src/{app => adapter}/mock-plugin.ts (94%) create mode 100644 packages/oberoncms/core/src/auth/with-development-send.ts rename packages/oberoncms/core/src/{app/schema.ts => lib/dtd.ts} (100%) rename packages/oberoncms/core/src/{app => lib}/get-initial-data.ts (87%) rename packages/oberoncms/core/src/{app => lib}/get-metadata.ts (91%) rename packages/oberoncms/core/src/{app => lib}/transforms.ts (99%) rename packages/oberoncms/core/src/{app => lib}/utils.ts (94%) rename packages/plugins/{fly-drive => flydrive}/.prettierignore (100%) rename packages/plugins/{fly-drive => flydrive}/CHANGELOG.md (100%) rename packages/plugins/{fly-drive => flydrive}/README.md (100%) rename packages/plugins/{fly-drive => flydrive}/eslint.config.mjs (100%) rename packages/plugins/{fly-drive => flydrive}/package.json (100%) rename packages/plugins/{fly-drive => flydrive}/src/blocks/client.tsx (100%) rename packages/plugins/{fly-drive => flydrive}/src/blocks/field.ts (100%) rename packages/plugins/{fly-drive => flydrive}/src/blocks/image-field.tsx (100%) rename packages/plugins/{fly-drive => flydrive}/src/blocks/server.tsx (100%) rename packages/plugins/{fly-drive => flydrive}/src/index.ts (100%) rename packages/plugins/{fly-drive => flydrive}/src/internal/disk-handlers.ts (100%) rename packages/plugins/{fly-drive => flydrive}/src/internal/get-image-size.ts (100%) rename packages/plugins/{fly-drive => flydrive}/src/internal/plugin.ts (100%) rename packages/plugins/{fly-drive => flydrive}/src/plugin.ts (100%) rename packages/plugins/{fly-drive => flydrive}/src/server.ts (100%) rename packages/plugins/{fly-drive => flydrive}/tsconfig.json (100%) rename packages/plugins/{fly-drive => flydrive}/vite.config.js (100%) create mode 100644 packages/plugins/pgsql/src/adapter.ts delete mode 100644 packages/plugins/pgsql/src/db/init.ts create mode 100644 packages/plugins/pgsql/src/schema.ts create mode 100644 packages/plugins/sqlite/.prettierignore create mode 100644 packages/plugins/sqlite/drizzle.config.ts create mode 100644 packages/plugins/sqlite/eslint.config.mjs create mode 100644 packages/plugins/sqlite/package.json create mode 100644 packages/plugins/sqlite/src/adapter.ts rename packages/plugins/{turso => sqlite}/src/db/auth-adapter.ts (82%) create mode 100644 packages/plugins/sqlite/src/db/client.ts rename packages/plugins/{vercel-postgres => sqlite}/src/db/database-adapter.ts (79%) create mode 100644 packages/plugins/sqlite/src/db/migrations/0000_faulty_menace.sql create mode 100644 packages/plugins/sqlite/src/db/migrations/0001_dear_vapor.sql create mode 100644 packages/plugins/sqlite/src/db/migrations/meta/0000_snapshot.json create mode 100644 packages/plugins/sqlite/src/db/migrations/meta/0001_snapshot.json create mode 100644 packages/plugins/sqlite/src/db/migrations/meta/_journal.json rename packages/plugins/{turso => sqlite}/src/db/schema/image-schema.ts (100%) create mode 100644 packages/plugins/sqlite/src/db/schema/index.ts rename packages/plugins/{turso => sqlite}/src/db/schema/next-auth-schema.ts (100%) rename packages/plugins/{turso => sqlite}/src/db/schema/puck-schema.ts (100%) rename packages/plugins/{turso => sqlite}/src/db/schema/site-schema.ts (100%) create mode 100644 packages/plugins/sqlite/src/index.ts create mode 100644 packages/plugins/sqlite/src/schema.ts create mode 100644 packages/plugins/sqlite/tsconfig.json create mode 100644 packages/plugins/sqlite/vite.config.js delete mode 100644 packages/plugins/turso/src/db/database-adapter.ts delete mode 100644 packages/plugins/turso/src/db/drizzle-kit/meta/_journal.json delete mode 100755 packages/plugins/turso/src/db/init.ts delete mode 100644 packages/plugins/vercel-postgres/src/db/auth-adapter.ts rename packages/plugins/vercel-postgres/src/db/{env-config.ts => env.ts} (100%) delete mode 100644 packages/plugins/vercel-postgres/src/db/init.ts delete mode 100644 packages/plugins/vercel-postgres/src/db/schema/image-schema.ts delete mode 100644 packages/plugins/vercel-postgres/src/db/schema/next-auth-schema.ts delete mode 100644 packages/plugins/vercel-postgres/src/db/schema/puck-schema.ts delete mode 100644 packages/plugins/vercel-postgres/src/db/schema/site-schema.ts diff --git a/apps/documentation/src/pages/docs/plugins/database/turso.mdx b/apps/documentation/src/pages/docs/plugins/database/turso.mdx index 8371dcff..3edb40fb 100644 --- a/apps/documentation/src/pages/docs/plugins/database/turso.mdx +++ b/apps/documentation/src/pages/docs/plugins/database/turso.mdx @@ -32,13 +32,3 @@ To use Turso, you need to create a [Turso](https://https://turso.tech/) account TURSO_URL= TURSO_TOKEN= ``` - -### Local - -If you are self hosting, you can use a local sqlite database: - -```sh -TURSO_USE_REMOTE=false -TURSO_FILE=<"file:filename.db"> # optional, defaults to "file:.oberon/oberon.db" -``` - diff --git a/apps/playground/oberon/adapter.ts b/apps/playground/oberon/adapter.ts index 1ed22579..d006edb6 100644 --- a/apps/playground/oberon/adapter.ts +++ b/apps/playground/oberon/adapter.ts @@ -1,15 +1,17 @@ import "server-cli-only" -import { plugin as databasePlugin } from "@oberoncms/plugin-turso" -import { authPlugin } from "@oberoncms/core/auth" - import { initAdapter } from "@oberoncms/core/adapter" +import { authPlugin, withDevelopmentSend } from "@oberoncms/core/auth" +import { withDevelopmentDatabase } from "@oberoncms/plugin-sqlite" + +import { plugin as tursoPlugin } from "@oberoncms/plugin-turso" import { plugin as uploadthingPlugin } from "@oberoncms/plugin-uploadthing/plugin" + import { sendAdapterPlugin } from "./send" export const adapter = initAdapter([ - databasePlugin, + withDevelopmentDatabase(tursoPlugin), + withDevelopmentSend(sendAdapterPlugin), authPlugin, - sendAdapterPlugin, uploadthingPlugin, ]) diff --git a/apps/playground/oberon/prebuild.ts b/apps/playground/oberon/prebuild.ts index 6e3c4a0a..22c52e74 100644 --- a/apps/playground/oberon/prebuild.ts +++ b/apps/playground/oberon/prebuild.ts @@ -1,7 +1,4 @@ #!/usr/bin/env node -/* eslint-env node */ -import dotenv from "dotenv" -dotenv.config({ path: ".env.local" }) import { exportTailwindClasses } from "@oberoncms/core/adapter" import { adapter } from "./adapter" diff --git a/apps/playground/package.json b/apps/playground/package.json index e9c45a28..88d863e1 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -16,6 +16,7 @@ "@datacom-digital/ui-sample-components": "^0.3.2", "@oberoncms/core": "workspace:*", "@oberoncms/plugin-turso": "workspace:*", + "@oberoncms/plugin-sqlite": "workspace:*", "@oberoncms/plugin-uploadthing": "workspace:*", "next": "^14.2.3", "react": "^18.2.0", diff --git a/package.json b/package.json index 522acaf6..314d389c 100644 --- a/package.json +++ b/package.json @@ -34,14 +34,12 @@ "lint-staged": { "**/*.{ts,tsx,js,jsx,css,md,json}": "prettier -l --write" }, - "dependencies": { - "dotenv": "^16.4.5" - }, "devDependencies": { "@changesets/cli": "^2.27.1", "@tohuhono/dev": "workspace:*", "concurrently": "^8.2.2", "cross-env": "^7.0.3", + "dotenv": "^16.4.5", "eslint": "8.57.0", "husky": "^9.0.11", "lint-staged": "^15.2.2", diff --git a/packages/create-oberon-app/package.json b/packages/create-oberon-app/package.json index 1bee8521..f855a802 100644 --- a/packages/create-oberon-app/package.json +++ b/packages/create-oberon-app/package.json @@ -38,6 +38,12 @@ "zod": "^3.23.8" }, "devDependencies": { + "@oberoncms/plugin-flydrive": "workspace:*", + "@oberoncms/plugin-pgsql": "workspace:*", + "@oberoncms/plugin-sqlite": "workspace:*", + "@oberoncms/plugin-turso": "workspace:*", + "@oberoncms/plugin-uploadthing": "workspace:*", + "@oberoncms/plugin-vercel-postgres": "workspace:*", "@oberoncms/core": "workspace:*", "@sendgrid/mail": "8.1.3", "@tohuhono/utils": "workspace:*", diff --git a/packages/create-oberon-app/plugins/database/custom.ts b/packages/create-oberon-app/plugins/database/custom.ts index 2ce91e2a..edfbef56 100644 --- a/packages/create-oberon-app/plugins/database/custom.ts +++ b/packages/create-oberon-app/plugins/database/custom.ts @@ -1,11 +1,11 @@ -import type { - OberonAuthAdapter, - OberonDatabaseAdapter, - OberonPlugin, +import { + type OberonAuthAdapter, + type OberonDatabaseAdapter, + type OberonPlugin, } from "@oberoncms/core" import { notImplemented } from "@tohuhono/utils" -export const plugin: OberonPlugin = () => ({ +export const databasePlugin: OberonPlugin = () => ({ name: "Custom Database Plugin", adapter: { // OberonDatabaseAdapter diff --git a/packages/create-oberon-app/src/index.ts b/packages/create-oberon-app/src/index.ts index b01ace9a..fece1966 100755 --- a/packages/create-oberon-app/src/index.ts +++ b/packages/create-oberon-app/src/index.ts @@ -9,22 +9,20 @@ import { Option, InvalidArgumentError, } from "@commander-js/extra-typings" -import { initGit } from "./program/init-git" -import { installPackages } from "./program/install-packages" +import { initGit } from "./installer/init-git" +import { installPackages, packageManagers } from "./installer/install-packages" + +import { promptOptions, recipes } from "./installer/prompt-options" +import { installTemplate } from "./installer/install-template" +import { installEnv } from "./installer/install-env" import { databaseIds, databasePlugins, - packageManagers, - Plugin, - recipes, + installAdapter, sendIds, sendPlugins, -} from "./program/config" -import { promptOptions } from "./program/prompt-options" -import { copyTemplate } from "./program/copy-template" -import { writeEnv } from "./program/write-env" -import { updatePackageJson } from "./program/update-package" -import { writePlugins } from "./program/write-plugins" + Plugin, +} from "./installer/install-adapter" program .command("create") @@ -78,35 +76,17 @@ program }, ] - /* - * Copy and apply template files into new directory - */ - await copyTemplate(appName, appPath, templatePath) - - await writePlugins(oberonPath, pluginPath, plugins) - - /* - * Adjust package.json - */ - const { workspaceDeps, workspaceDevDeps } = await updatePackageJson( - appName, - appPath, - ) + await installTemplate(appName, appPath, templatePath) - await writeEnv(appPath, email) + await installAdapter(oberonPath, pluginPath, plugins) - const pluginDependencies = plugins.flatMap( - ({ packageName, dependencies = [] }) => [ - ...dependencies, - ...(packageName ? [packageName] : []), - ], - ) + await installEnv(appPath, email) await installPackages({ - packageManager, + appName, appPath, - dependencies: [...workspaceDeps, ...pluginDependencies], - devDependencies: workspaceDevDeps, + packageManager, + plugins, }) execSync(`${packageManager} run prettier:fix`, { diff --git a/packages/create-oberon-app/src/program/config.ts b/packages/create-oberon-app/src/installer/config.ts similarity index 100% rename from packages/create-oberon-app/src/program/config.ts rename to packages/create-oberon-app/src/installer/config.ts diff --git a/packages/create-oberon-app/src/program/init-git.ts b/packages/create-oberon-app/src/installer/init-git.ts similarity index 100% rename from packages/create-oberon-app/src/program/init-git.ts rename to packages/create-oberon-app/src/installer/init-git.ts diff --git a/packages/create-oberon-app/src/installer/install-adapter.ts b/packages/create-oberon-app/src/installer/install-adapter.ts new file mode 100644 index 00000000..2a032637 --- /dev/null +++ b/packages/create-oberon-app/src/installer/install-adapter.ts @@ -0,0 +1,100 @@ +import { copyFile, writeFile } from "fs/promises" +import path from "path" + +export type Plugin = { + id: string + type: string + label: string + packageName?: string + dependencies?: string[] +} + +export const databasePlugins = { + turso: { + label: "Turso (Recommended)", + packageName: "@oberoncms/plugin-turso", + }, + pgsql: { + label: "PostgreSQL", + packageName: "@oberoncms/plugin-pgsql", + }, + "vercel-postgres": { + label: "Vercel Postgres", + packageName: "@oberoncms/plugin-vercel-postgres", + }, + custom: { + label: "Custom", + dependencies: ["@tohuhono/utils"], + }, +} +export type DatabasePlugin = keyof typeof databasePlugins +export const databaseIds = Object.keys(databasePlugins) as DatabasePlugin[] + +export const sendPlugins = { + resend: { label: "Resend (Recommended)", dependencies: ["resend"] }, + sendgrid: { label: "Sendgrid", dependencies: ["@sendgrid/mail"] }, + custom: { label: "Custom", dependencies: ["@tohuhono/utils"] }, +} +export type SendPlugin = keyof typeof sendPlugins +export const sendIds = Object.keys(sendPlugins) as SendPlugin[] + +const createAdapter = (plugins: Plugin[]) => { + const aliasedPlugins = plugins.map(({ packageName, type }) => ({ + packageName, + type, + alias: `${type}Plugin`, + })) + + const pluginImports = aliasedPlugins + .map(({ packageName, type, alias }) => { + if (packageName) { + return `import { plugin as ${alias} } from "${packageName}"` + } + + return `import { plugin as ${alias} } from "./${type}"` + }) + .join("\n") + + const adapterPlugins = [ + "databasePlugin", + ...aliasedPlugins.map(({ alias }) => alias), + // Auth plugin should be last + "authPlugin", + ] + + return ` +import "server-cli-only" + +import { USE_DEVELOPMENT_DATABASE } from "@oberoncms/core" +import { initAdapter } from "@oberoncms/core/adapter" +import { authPlugin } from "@oberoncms/core/auth" + +import { plugin as sqlitePlugin } from "@oberoncms/plugin-sqlite" + +${pluginImports} + +const databasePlugin = USE_DEVELOPMENT_DATABASE ? sqlitePlugin : databasePlugin + +export const adapter = initAdapter([${adapterPlugins.join(", ")}]) +` +} + +export async function installAdapter( + oberonPath: string, + pluginPath: string, + plugins: Plugin[], +) { + for (const { packageName, type, id } of plugins) { + if (packageName) { + continue + } + await copyFile( + path.join(pluginPath, type, `${id}.ts`), + path.join(oberonPath, `${type}.ts`), + ) + } + + const adapter = createAdapter(plugins) + + await writeFile(path.join(oberonPath, "adapter.ts"), adapter) +} diff --git a/packages/create-oberon-app/src/program/write-env.ts b/packages/create-oberon-app/src/installer/install-env.ts similarity index 69% rename from packages/create-oberon-app/src/program/write-env.ts rename to packages/create-oberon-app/src/installer/install-env.ts index 5932c986..791462d0 100644 --- a/packages/create-oberon-app/src/program/write-env.ts +++ b/packages/create-oberon-app/src/installer/install-env.ts @@ -2,9 +2,9 @@ import { writeFile } from "fs/promises" import { randomBytes } from "crypto" import path from "path" -export async function writeEnv(appPath: string, email: string) { +export async function installEnv(appPath: string, email: string) { await writeFile( - path.join(appPath, "./.env.local"), + path.join(appPath, "./.env"), ` MASTER_EMAIL=${email} EMAIL_FROM=${email} @@ -12,7 +12,7 @@ EMAIL_FROM=${email} AUTH_SECRET=${randomBytes(64).toString("hex")} # Development builds -RESEND_USE_REMOTE=false + AUTH_TRUST_HOST=true ANALYZE=false `, diff --git a/packages/create-oberon-app/src/installer/install-packages.ts b/packages/create-oberon-app/src/installer/install-packages.ts new file mode 100644 index 00000000..fad8891b --- /dev/null +++ b/packages/create-oberon-app/src/installer/install-packages.ts @@ -0,0 +1,121 @@ +import { execSync } from "child_process" +import { readFile, writeFile } from "fs/promises" +import path from "path" +import { Plugin } from "./install-adapter" + +export const packageManagers = ["npm", "pnpm", "yarn"] as const +export type PackageManager = (typeof packageManagers)[number] +export const packageManagerChoices = [ + { title: "npm", value: "npm" }, + { title: "pnpm", value: "pnpm" }, + { title: "yarn", value: "yarn" }, +] + +async function updatePackageJson(appName: string, appPath: string) { + const packageFilePath = path.join(appPath, "./package.json") + + const packageJson = JSON.parse(await readFile(packageFilePath, "utf-8")) as { + name?: string + dependencies?: Record + devDependencies?: Record + } + + const workspaceDeps = [] as string[] + const dependencies = + packageJson.dependencies || ({} as Record) + + for (const dependancy in dependencies) { + if (dependencies[dependancy]?.startsWith("workspace")) { + workspaceDeps.push(dependancy) + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete dependencies[dependancy] + } + } + + const devDependencies = + packageJson.devDependencies || ({} as Record) + const workspaceDevDeps = [] as string[] + + for (const dependancy in devDependencies) { + if (devDependencies[dependancy]?.startsWith("workspace")) { + workspaceDevDeps.push(dependancy) + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete devDependencies[dependancy] + } + } + + await writeFile( + packageFilePath, + JSON.stringify({ + ...packageJson, + name: appName, + dependencies, + devDependencies, + }), + ) + + return { workspaceDeps, workspaceDevDeps } +} + +export async function installPackages({ + packageManager, + appPath, + appName, + plugins, +}: { + packageManager: PackageManager + appPath: string + appName: string + plugins: Plugin[] +}) { + /* + * Adjust package.json + */ + const { workspaceDeps, workspaceDevDeps } = await updatePackageJson( + appName, + appPath, + ) + + const pluginDependencies = plugins.flatMap( + ({ packageName, dependencies = [] }) => [ + ...dependencies, + ...(packageName ? [packageName] : []), + ], + ) + + const dependencies = [...workspaceDeps, ...pluginDependencies] + const devDependencies = workspaceDevDeps + + // https://github.com/tursodatabase/libsql-client-ts/issues/74 + if (packageManager === "pnpm") { + await writeFile( + path.join(appPath, "./.npmrc"), + ` +# https://github.com/tursodatabase/libsql-client-ts/issues/74 +shamefully-hoist=true +`, + ) + } + + execSync(`${packageManager} install`, { + cwd: appPath, + stdio: "inherit", + }) + + if (dependencies.length) { + execSync(`${packageManager} install ${dependencies.join(" ")}`, { + cwd: appPath, + stdio: "inherit", + }) + } + + if (devDependencies.length) { + execSync( + `${packageManager} install --save-dev ${devDependencies.join(" ")}`, + { + cwd: appPath, + stdio: "inherit", + }, + ) + } +} diff --git a/packages/create-oberon-app/src/program/copy-template.ts b/packages/create-oberon-app/src/installer/install-template.ts similarity index 96% rename from packages/create-oberon-app/src/program/copy-template.ts rename to packages/create-oberon-app/src/installer/install-template.ts index e17fffc2..6e0c699b 100644 --- a/packages/create-oberon-app/src/program/copy-template.ts +++ b/packages/create-oberon-app/src/installer/install-template.ts @@ -4,7 +4,7 @@ import path from "path" import { exit } from "process" import fg from "fast-glob" -export async function copyTemplate( +export async function installTemplate( appName: string, appPath: string, templatePath: string, diff --git a/packages/create-oberon-app/src/program/prompt-options.ts b/packages/create-oberon-app/src/installer/prompt-options.ts similarity index 90% rename from packages/create-oberon-app/src/program/prompt-options.ts rename to packages/create-oberon-app/src/installer/prompt-options.ts index eba61dd2..fee36be7 100644 --- a/packages/create-oberon-app/src/program/prompt-options.ts +++ b/packages/create-oberon-app/src/installer/prompt-options.ts @@ -2,20 +2,21 @@ import { exit } from "process" import prompts from "prompts" import { z } from "zod" import validateName from "validate-npm-package-name" +import { packageManagerChoices, type PackageManager } from "./install-packages" import { databaseIds, databasePlugins, - packageManagerChoices, - recipeChoices, sendIds, sendPlugins, type DatabasePlugin, - type PackageManager, type SendPlugin, -} from "./config" +} from "./install-adapter" + +export const recipes = ["nextjs"] as const +export const recipeChoices = [{ title: "Next js", value: "nextjs" }] // Lifted from https://github.com/vercel/next.js/blob/c2d7bbd1b82c71808b99e9a7944fb16717a581db/packages/create-next-app/helpers/get-pkg-manager.ts -export function getPackageManager(): PackageManager | undefined { +function getPackageManager(): PackageManager | undefined { const userAgent = process.env.npm_config_user_agent || "" if (userAgent.startsWith("yarn")) { diff --git a/packages/create-oberon-app/src/program/install-packages.ts b/packages/create-oberon-app/src/program/install-packages.ts deleted file mode 100644 index f275255c..00000000 --- a/packages/create-oberon-app/src/program/install-packages.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { execSync } from "child_process" -import { writeFile } from "fs/promises" -import path from "path" -import type { PackageManager } from "./config" - -export async function installPackages({ - packageManager, - appPath, - dependencies, - devDependencies, -}: { - packageManager: PackageManager - appPath: string - dependencies: string[] - devDependencies: string[] -}) { - // https://github.com/tursodatabase/libsql-client-ts/issues/74 - if (packageManager === "pnpm") { - await writeFile( - path.join(appPath, "./.npmrc"), - ` -# https://github.com/tursodatabase/libsql-client-ts/issues/74 -shamefully-hoist=true -`, - ) - } - - execSync(`${packageManager} install`, { - cwd: appPath, - stdio: "inherit", - }) - - if (dependencies.length) { - execSync(`${packageManager} install ${dependencies.join(" ")}`, { - cwd: appPath, - stdio: "inherit", - }) - } - - if (devDependencies.length) { - execSync( - `${packageManager} install --save-dev ${devDependencies.join(" ")}`, - { - cwd: appPath, - stdio: "inherit", - }, - ) - } -} diff --git a/packages/create-oberon-app/src/program/update-package.ts b/packages/create-oberon-app/src/program/update-package.ts deleted file mode 100644 index 31bcd776..00000000 --- a/packages/create-oberon-app/src/program/update-package.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { readFile, writeFile } from "fs/promises" -import path from "path" - -export async function updatePackageJson(appName: string, appPath: string) { - const packageFilePath = path.join(appPath, "./package.json") - - const packageJson = JSON.parse(await readFile(packageFilePath, "utf-8")) as { - name?: string - dependencies?: Record - devDependencies?: Record - } - - const workspaceDeps = [] as string[] - const dependencies = - packageJson.dependencies || ({} as Record) - - for (const dependancy in dependencies) { - if (dependencies[dependancy]?.startsWith("workspace")) { - workspaceDeps.push(dependancy) - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete dependencies[dependancy] - } - } - - const devDependencies = - packageJson.devDependencies || ({} as Record) - const workspaceDevDeps = [] as string[] - - for (const dependancy in devDependencies) { - if (devDependencies[dependancy]?.startsWith("workspace")) { - workspaceDevDeps.push(dependancy) - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete devDependencies[dependancy] - } - } - - await writeFile( - packageFilePath, - JSON.stringify({ - ...packageJson, - name: appName, - dependencies, - devDependencies, - }), - ) - - return { workspaceDeps, workspaceDevDeps } -} diff --git a/packages/create-oberon-app/src/program/write-plugins.ts b/packages/create-oberon-app/src/program/write-plugins.ts deleted file mode 100644 index c388ff8d..00000000 --- a/packages/create-oberon-app/src/program/write-plugins.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { copyFile, writeFile } from "fs/promises" -import path from "path" -import type { Plugin } from "./config" - -const adapter = (plugins: Plugin[]) => { - const aliasedPlugins = plugins.map(({ packageName, type }) => ({ - packageName, - type, - alias: `${type}Plugin`, - })) - - const pluginImports = aliasedPlugins - .map(({ packageName, type, alias }) => { - if (packageName) { - return `import { plugin as ${alias} } from "${packageName}"` - } - - return `import { plugin as ${alias} } from "./${type}"` - }) - .join("\n") - - const adapterPlugins = [ - ...aliasedPlugins.map(({ alias }) => alias), - // Auth plugin should be last - "authPlugin", - ] - - return ` -import "server-cli-only" - -import { initAdapter } from "@oberoncms/core/adapter" -${pluginImports} - -import { authPlugin } from "@oberoncms/core/auth" - -export const adapter = initAdapter([${adapterPlugins.join(", ")}]) -` -} - -export async function writePlugins( - oberonPath: string, - pluginPath: string, - plugins: Plugin[], -) { - for (const { packageName, type, id } of plugins) { - if (packageName) { - continue - } - await copyFile( - path.join(pluginPath, type, `${id}.ts`), - path.join(oberonPath, `${type}.ts`), - ) - } - - await writeFile(path.join(oberonPath, "adapter.ts"), adapter(plugins)) -} diff --git a/packages/oberoncms/core/package.json b/packages/oberoncms/core/package.json index 356bb51d..ba392317 100644 --- a/packages/oberoncms/core/package.json +++ b/packages/oberoncms/core/package.json @@ -49,6 +49,7 @@ "@measured/puck": "^0.14.2", "@tohuhono/ui": "workspace:*", "@tohuhono/utils": "workspace:*", + "dotenv": "^16.4.5", "filesize": "^10.1.0", "next": "^14.2.3", "next-auth": "5.0.0-beta.17", diff --git a/packages/oberoncms/core/src/adapter.tsx b/packages/oberoncms/core/src/adapter.tsx index 3511d502..d4951acb 100644 --- a/packages/oberoncms/core/src/adapter.tsx +++ b/packages/oberoncms/core/src/adapter.tsx @@ -1,399 +1,9 @@ -import { - revalidatePath, - revalidateTag, - unstable_cache as cache, -} from "next/cache" -import { type Data } from "@measured/puck" -import { streamResponse } from "@tohuhono/utils" -import { version } from "../package.json" with { type: "json" } -import { - AddImageSchema, - AddUserSchema, - ChangeRoleSchema, - DeletePageSchema, - DeleteUserSchema, - INITIAL_DATA, - AddPageSchema, - PublishPageSchema, - type AdapterActionGroup, - type AdapterPermission, - type OberonActions, - type OberonPlugin, - type OberonUser, - type OberonConfig, - type MigrationResult, - type TransformResult, - type OberonPage, - type PageData, - type OberonAdapter, -} from "./app/schema" -import { - applyTransforms, - getComponentTransformVersions, - getTransforms, -} from "./app/transforms" -import { baseAdapter } from "./app/base-adapter" -import { getInitialData } from "./app/get-initial-data" +// Must be first - ensures env variables are available for other imports at instantiation +import "./adapter/dotenv" -export { mockPlugin } from "./app/mock-plugin" +export { mockPlugin } from "./adapter/mock-plugin" -export { exportTailwindClasses } from "./app/export-tailwind-clases" +export { exportTailwindClasses } from "./adapter/export-tailwind-clases" -export function initAdapter(plugins: OberonPlugin[] = []) { - const adapter = plugins.reduce((accumulator, plugin) => { - const { name, version, adapter, handlers = {} } = plugin(accumulator) - return { - ...accumulator, - plugins: { - ...accumulator.plugins, - ...(name && { [name]: version || "" }), - }, - handlers: { - ...accumulator.handlers, - ...handlers, - }, - ...adapter, - } - }, baseAdapter) - - return { - ...adapter, - init: async () => { - await adapter.init() - const allPages = await adapter.getAllPages() - if (!allPages.length) { - console.log("Updating welcome page") - await adapter.updatePageData(getInitialData()) - } - }, - } satisfies OberonAdapter -} - -export function initActions({ - config, - adapter, -}: { - config: OberonConfig - adapter: OberonAdapter -}): OberonActions { - console.log("Initialising adapter") - - const can: OberonActions["can"] = async (action, permission = "read") => { - // Check unauthenticated first so we can do it outside of request context - if (adapter.hasPermission({ action, permission })) { - return true - } - - const user = await adapter.getCurrentUser() - - return adapter.hasPermission({ user, action, permission }) - } - - const will = async ( - action: AdapterActionGroup, - permission: AdapterPermission, - ) => { - if (await can(action, permission)) { - return - } - throw new Error("Unauthorized") - } - - const whoWill = async ( - action: AdapterActionGroup, - permission: AdapterPermission, - ) => { - const user = await adapter.getCurrentUser() - - if (user && adapter.hasPermission({ user, action, permission })) { - return user - } - throw new Error("Unauthorized") - } - - const getAllPagesCached = cache( - async () => { - const sortPages = (a: { key: string }, b: { key: string }) => { - if (a.key < b.key) { - return -1 - } - if (a.key > b.key) { - return 1 - } - return 0 - } - const result = await adapter.getAllPages() - - const data = result.sort(sortPages) - return data - }, - undefined, - { tags: ["oberon-pages"] }, - ) - - const getAllPathsCached = cache( - async () => { - const result = await adapter.getAllPages() - const data = result.map((row) => ({ - puckPath: row["key"].split("/").slice(1), - })) - return data - }, - undefined, - { tags: ["oberon-pages"] }, - ) - - // TODO zod ; maybeGet - const getPageDataCached = async (key: string): Promise => { - const dataString = await adapter.getPageData(key) - - return dataString - } - - const getAllUsersCached = cache( - async () => { - const allUsers = await adapter.getAllUsers() - return allUsers || [] - }, - undefined, - { - tags: ["oberon-users"], - }, - ) - - const getAllImagesCached = cache( - async () => { - const allImages = await adapter.getAllImages() - return allImages || [] - }, - undefined, - { - tags: ["oberon-images"], - }, - ) - - const updatePageData = async ({ - key, - data, - updatedBy, - }: Pick) => { - await adapter.updatePageData({ - key, - data, - updatedAt: new Date(), - updatedBy, - }) - revalidatePath(key) - revalidateTag("oberon-pages") - } - - const getConfigCached = cache( - async () => { - const site = await adapter.getSite() - - const { components, transforms } = getTransforms(site?.components, config) - - const siteConfig = { - version, - plugins: adapter.plugins, - components, - pendingMigrations: transforms && Object.keys(transforms), - } - - if (!site) { - await adapter.updateSite({ - version: config.version, - components: getComponentTransformVersions(config), - updatedAt: new Date(), - updatedBy: "system", - }) - } - - return siteConfig - }, - undefined, - { - tags: ["oberon-config"], - }, - ) - - const migrate = streamResponse< - TransformResult | MigrationResult, - [OberonUser] - >(async function* (user: OberonUser) { - const summary: MigrationResult = { - type: "summary", - error: [], - success: [], - total: 0, - } - - const site = await adapter.getSite() - - const { transforms } = getTransforms(site?.components, config) - - if (!transforms) { - return summary - } - - const pages = await getAllPagesCached() - - const results = applyTransforms({ - transforms, - pages, - getPageData: getPageDataCached, - updatePageData, - }) - - for await (const result of results) { - summary[result.status].push(result.key) - yield result - } - - await adapter.updateSite({ - version: config.version, - components: getComponentTransformVersions(config), - updatedAt: new Date(), - updatedBy: user.email, - }) - - revalidateTag("oberon-config") - - yield { ...summary, total: pages.length } - }) - - return { - /* - * Auth - */ - can, - /* - * Site actions - */ - getConfig: async () => { - await will("site", "read") - return await getConfigCached() - }, - migrateData: async () => { - const user = await whoWill("site", "write") - return migrate(user) - }, - - /* - * Page actions - */ - getAllPaths: async function () { - await will("pages", "read") - return getAllPathsCached() - }, - getAllPages: async function () { - await will("pages", "read") - return getAllPagesCached() - }, - getPageData: async function (key) { - await will("pages", "read") - return getPageDataCached(key) - }, - // TODO return value - addPage: async function (data: unknown) { - const user = await whoWill("pages", "write") - const { key } = AddPageSchema.parse(data) - await adapter.addPage({ - key, - data: INITIAL_DATA, - updatedAt: new Date(), - updatedBy: user.email, - }) - revalidatePath(key) - revalidateTag("oberon-pages") - }, - // TODO return value - deletePage: async function (data: unknown) { - await will("pages", "write") - const { key } = DeletePageSchema.parse(data) - await adapter.deletePage(key) - revalidatePath(key) - revalidateTag("oberon-pages") - }, - // TODO zod ; return value - publishPageData: async function (data: unknown) { - const user = await whoWill("pages", "write") - const { key, data: pageData } = PublishPageSchema.parse(data) - await updatePageData({ - key, - data: pageData as PageData, - updatedBy: user.email, - }) - }, - - /* - * Image actions - */ - getAllImages: async function () { - await will("images", "read") - return getAllImagesCached() - }, - addImage: async function (data: unknown) { - await will("images", "write") - - const image = AddImageSchema.parse(data) - await adapter.addImage(image) - revalidateTag("oberon-images") - return adapter.getAllImages() - }, - // TODO uploadthing - deleteImage: async function (data) { - await will("images", "write") - revalidateTag("oberon-images") - return adapter.deleteImage(data) - }, - - /* - * User actions - */ - getAllUsers: async function () { - await will("users", "read") - return getAllUsersCached() - }, - addUser: async function (data: unknown) { - await will("users", "write") - const { email, role } = AddUserSchema.parse(data) - - try { - const { id } = await adapter.addUser({ - email, - role, - }) - revalidateTag("oberon-users") - return { id, email, role } - } catch (_error) { - console.error("Create user failed") - return null - } - }, - deleteUser: async function (data: unknown) { - await will("users", "write") - const { id } = DeleteUserSchema.parse(data) - try { - await adapter.deleteUser(id) - revalidateTag("oberon-users") - return { id } - } catch (_error) { - console.error("Delete user failed") - return null - } - }, - changeRole: async function (data: unknown) { - await will("users", "write") - const { role, id } = ChangeRoleSchema.parse(data) - try { - await adapter.changeRole({ role, id }) - revalidateTag("oberon-users") - return { role, id } - } catch (_error) { - console.error("Change role failed") - return null - } - }, - } -} +export { initAdapter } from "./adapter/init-adapter" +export { initActions } from "./adapter/init-actions" diff --git a/packages/oberoncms/core/src/app/base-adapter.ts b/packages/oberoncms/core/src/adapter/base-adapter.ts similarity index 96% rename from packages/oberoncms/core/src/app/base-adapter.ts rename to packages/oberoncms/core/src/adapter/base-adapter.ts index d2b1b72d..18301769 100644 --- a/packages/oberoncms/core/src/app/base-adapter.ts +++ b/packages/oberoncms/core/src/adapter/base-adapter.ts @@ -1,5 +1,5 @@ import { notImplemented } from "@tohuhono/utils" -import type { OberonPermissions, OberonAdapter } from "./schema" +import type { OberonPermissions, OberonAdapter } from "../lib/dtd" export const baseAdapter: OberonAdapter = { plugins: {}, diff --git a/packages/oberoncms/core/src/adapter/dotenv.ts b/packages/oberoncms/core/src/adapter/dotenv.ts new file mode 100644 index 00000000..ae07afe8 --- /dev/null +++ b/packages/oberoncms/core/src/adapter/dotenv.ts @@ -0,0 +1,2 @@ +import dotenv from "dotenv" +dotenv.config({ path: ".env.local" }) diff --git a/packages/oberoncms/core/src/app/export-tailwind-clases.ts b/packages/oberoncms/core/src/adapter/export-tailwind-clases.ts similarity index 95% rename from packages/oberoncms/core/src/app/export-tailwind-clases.ts rename to packages/oberoncms/core/src/adapter/export-tailwind-clases.ts index c4fd851d..dde97343 100644 --- a/packages/oberoncms/core/src/app/export-tailwind-clases.ts +++ b/packages/oberoncms/core/src/adapter/export-tailwind-clases.ts @@ -2,7 +2,7 @@ import { once } from "events" import { mkdir } from "fs/promises" import { createWriteStream } from "fs" import { walkAsyncStep } from "walkjs" -import type { OberonAdapter, OberonPageMeta } from "./schema" +import type { OberonAdapter, OberonPageMeta } from "../lib/dtd" export async function exportTailwindClasses({ getAllPages, diff --git a/packages/oberoncms/core/src/adapter/init-actions.tsx b/packages/oberoncms/core/src/adapter/init-actions.tsx new file mode 100644 index 00000000..996ae166 --- /dev/null +++ b/packages/oberoncms/core/src/adapter/init-actions.tsx @@ -0,0 +1,360 @@ +import { + revalidatePath, + revalidateTag, + unstable_cache as cache, +} from "next/cache" +import { type Data } from "@measured/puck" +import { streamResponse } from "@tohuhono/utils" +import { version } from "../../package.json" with { type: "json" } +import { + AddImageSchema, + AddUserSchema, + ChangeRoleSchema, + DeletePageSchema, + DeleteUserSchema, + INITIAL_DATA, + AddPageSchema, + PublishPageSchema, + type AdapterActionGroup, + type AdapterPermission, + type OberonActions, + type OberonUser, + type OberonConfig, + type MigrationResult, + type TransformResult, + type OberonPage, + type PageData, + type OberonAdapter, +} from "../lib/dtd" +import { + applyTransforms, + getComponentTransformVersions, + getTransforms, +} from "../lib/transforms" + +export function initActions({ + config, + adapter, +}: { + config: OberonConfig + adapter: OberonAdapter +}): OberonActions { + const can: OberonActions["can"] = async (action, permission = "read") => { + // Check unauthenticated first so we can do it outside of request context + if (adapter.hasPermission({ action, permission })) { + return true + } + + const user = await adapter.getCurrentUser() + + return adapter.hasPermission({ user, action, permission }) + } + + const will = async ( + action: AdapterActionGroup, + permission: AdapterPermission, + ) => { + if (await can(action, permission)) { + return + } + throw new Error("Unauthorized") + } + + const whoWill = async ( + action: AdapterActionGroup, + permission: AdapterPermission, + ) => { + const user = await adapter.getCurrentUser() + + if (user && adapter.hasPermission({ user, action, permission })) { + return user + } + throw new Error("Unauthorized") + } + + const getAllPagesCached = cache( + async () => { + const sortPages = (a: { key: string }, b: { key: string }) => { + if (a.key < b.key) { + return -1 + } + if (a.key > b.key) { + return 1 + } + return 0 + } + const result = await adapter.getAllPages() + + const data = result.sort(sortPages) + return data + }, + undefined, + { tags: ["oberon-pages"] }, + ) + + const getAllPathsCached = cache( + async () => { + const result = await adapter.getAllPages() + const data = result.map((row) => ({ + puckPath: row["key"].split("/").slice(1), + })) + return data + }, + undefined, + { tags: ["oberon-pages"] }, + ) + + // TODO zod ; maybeGet + const getPageDataCached = async (key: string): Promise => { + const dataString = await adapter.getPageData(key) + + return dataString + } + + const getAllUsersCached = cache( + async () => { + const allUsers = await adapter.getAllUsers() + return allUsers || [] + }, + undefined, + { + tags: ["oberon-users"], + }, + ) + + const getAllImagesCached = cache( + async () => { + const allImages = await adapter.getAllImages() + return allImages || [] + }, + undefined, + { + tags: ["oberon-images"], + }, + ) + + const updatePageData = async ({ + key, + data, + updatedBy, + }: Pick) => { + await adapter.updatePageData({ + key, + data, + updatedAt: new Date(), + updatedBy, + }) + revalidatePath(key) + revalidateTag("oberon-pages") + } + + const getConfigCached = cache( + async () => { + const site = await adapter.getSite() + + const { components, transforms } = getTransforms(site?.components, config) + + const siteConfig = { + version, + plugins: adapter.plugins, + components, + pendingMigrations: transforms && Object.keys(transforms), + } + + if (!site) { + await adapter.updateSite({ + version: config.version, + components: getComponentTransformVersions(config), + updatedAt: new Date(), + updatedBy: "system", + }) + } + + return siteConfig + }, + undefined, + { + tags: ["oberon-config"], + }, + ) + + const migrate = streamResponse< + TransformResult | MigrationResult, + [OberonUser] + >(async function* (user: OberonUser) { + const summary: MigrationResult = { + type: "summary", + error: [], + success: [], + total: 0, + } + + const site = await adapter.getSite() + + const { transforms } = getTransforms(site?.components, config) + + if (!transforms) { + return summary + } + + const pages = await getAllPagesCached() + + const results = applyTransforms({ + transforms, + pages, + getPageData: getPageDataCached, + updatePageData, + }) + + for await (const result of results) { + summary[result.status].push(result.key) + yield result + } + + await adapter.updateSite({ + version: config.version, + components: getComponentTransformVersions(config), + updatedAt: new Date(), + updatedBy: user.email, + }) + + revalidateTag("oberon-config") + + yield { ...summary, total: pages.length } + }) + + return { + /* + * Auth + */ + can, + /* + * Site actions + */ + getConfig: async () => { + await will("site", "read") + return await getConfigCached() + }, + migrateData: async () => { + const user = await whoWill("site", "write") + return migrate(user) + }, + + /* + * Page actions + */ + getAllPaths: async function () { + await will("pages", "read") + return getAllPathsCached() + }, + getAllPages: async function () { + await will("pages", "read") + return getAllPagesCached() + }, + getPageData: async function (key) { + await will("pages", "read") + return getPageDataCached(key) + }, + // TODO return value + addPage: async function (data: unknown) { + const user = await whoWill("pages", "write") + const { key } = AddPageSchema.parse(data) + await adapter.addPage({ + key, + data: INITIAL_DATA, + updatedAt: new Date(), + updatedBy: user.email, + }) + revalidatePath(key) + revalidateTag("oberon-pages") + }, + // TODO return value + deletePage: async function (data: unknown) { + await will("pages", "write") + const { key } = DeletePageSchema.parse(data) + await adapter.deletePage(key) + revalidatePath(key) + revalidateTag("oberon-pages") + }, + // TODO zod ; return value + publishPageData: async function (data: unknown) { + const user = await whoWill("pages", "write") + const { key, data: pageData } = PublishPageSchema.parse(data) + await updatePageData({ + key, + data: pageData as PageData, + updatedBy: user.email, + }) + }, + + /* + * Image actions + */ + getAllImages: async function () { + await will("images", "read") + return getAllImagesCached() + }, + addImage: async function (data: unknown) { + await will("images", "write") + + const image = AddImageSchema.parse(data) + await adapter.addImage(image) + revalidateTag("oberon-images") + return adapter.getAllImages() + }, + // TODO uploadthing + deleteImage: async function (data) { + await will("images", "write") + revalidateTag("oberon-images") + return adapter.deleteImage(data) + }, + + /* + * User actions + */ + getAllUsers: async function () { + await will("users", "read") + return getAllUsersCached() + }, + addUser: async function (data: unknown) { + await will("users", "write") + const { email, role } = AddUserSchema.parse(data) + + try { + const { id } = await adapter.addUser({ + email, + role, + }) + revalidateTag("oberon-users") + return { id, email, role } + } catch (_error) { + console.error("Create user failed") + return null + } + }, + deleteUser: async function (data: unknown) { + await will("users", "write") + const { id } = DeleteUserSchema.parse(data) + try { + await adapter.deleteUser(id) + revalidateTag("oberon-users") + return { id } + } catch (_error) { + console.error("Delete user failed") + return null + } + }, + changeRole: async function (data: unknown) { + await will("users", "write") + const { role, id } = ChangeRoleSchema.parse(data) + try { + await adapter.changeRole({ role, id }) + revalidateTag("oberon-users") + return { role, id } + } catch (_error) { + console.error("Change role failed") + return null + } + }, + } +} diff --git a/packages/oberoncms/core/src/adapter/init-adapter.tsx b/packages/oberoncms/core/src/adapter/init-adapter.tsx new file mode 100644 index 00000000..8a82cff5 --- /dev/null +++ b/packages/oberoncms/core/src/adapter/init-adapter.tsx @@ -0,0 +1,33 @@ +import { type OberonPlugin, type OberonAdapter } from "../lib/dtd" +import { baseAdapter } from "./base-adapter" +import { getInitialData } from "../lib/get-initial-data" + +export function initAdapter(plugins: OberonPlugin[] = []) { + const adapter = plugins.reduce((accumulator, plugin) => { + const { name, version, adapter, handlers = {} } = plugin(accumulator) + return { + ...accumulator, + plugins: { + ...accumulator.plugins, + ...(name && { [name]: version || "" }), + }, + handlers: { + ...accumulator.handlers, + ...handlers, + }, + ...adapter, + } + }, baseAdapter) + + return { + ...adapter, + init: async () => { + await adapter.init() + const allPages = await adapter.getAllPages() + if (!allPages.length) { + console.log("Initialising welcome page") + await adapter.updatePageData(getInitialData()) + } + }, + } satisfies OberonAdapter +} diff --git a/packages/oberoncms/core/src/app/mock-plugin.ts b/packages/oberoncms/core/src/adapter/mock-plugin.ts similarity index 94% rename from packages/oberoncms/core/src/app/mock-plugin.ts rename to packages/oberoncms/core/src/adapter/mock-plugin.ts index 457479bd..92a2af5d 100644 --- a/packages/oberoncms/core/src/app/mock-plugin.ts +++ b/packages/oberoncms/core/src/adapter/mock-plugin.ts @@ -1,4 +1,4 @@ -import type { OberonPlugin } from "./schema" +import type { OberonPlugin } from "../lib/dtd" const mockUser = { id: "test-id", diff --git a/packages/oberoncms/core/src/auth.tsx b/packages/oberoncms/core/src/auth.tsx index 32c1e260..a19e1b73 100644 --- a/packages/oberoncms/core/src/auth.tsx +++ b/packages/oberoncms/core/src/auth.tsx @@ -2,3 +2,5 @@ export { authPlugin } from "./auth/next-auth" export { VerifyPage } from "./auth/verify" export { ConfirmPage } from "./auth/confirm" + +export { withDevelopmentSend } from "./auth/with-development-send" diff --git a/packages/oberoncms/core/src/auth/next-auth.ts b/packages/oberoncms/core/src/auth/next-auth.ts index d932121f..f092bc41 100644 --- a/packages/oberoncms/core/src/auth/next-auth.ts +++ b/packages/oberoncms/core/src/auth/next-auth.ts @@ -5,7 +5,7 @@ import NextAuth from "next-auth" import { NextRequest } from "next/server" import { redirect } from "next/navigation" import { name, version } from "../../package.json" with { type: "json" } -import type { OberonPlugin, OberonUser } from ".." +import { type OberonPlugin, type OberonUser } from "../lib/dtd" const masterEmail = process.env.MASTER_EMAIL || null @@ -23,10 +23,6 @@ const withCallback = (url: string) => { return withCallback.toString() } -const SEND_VERIFICATION_REQUEST = - process.env.EMAIL_SEND === "true" || - (process.env.NODE_ENV === "production" && process.env.EMAIL_SEND !== "false") - export const authPlugin: OberonPlugin = (adapter) => { const config = { pages: { @@ -53,14 +49,6 @@ export const authPlugin: OberonPlugin = (adapter) => { }) => { const url = withCallback(baseUrl) - if (!SEND_VERIFICATION_REQUEST) { - console.log(`sendVerificationRequest email not sent`, { - email, - url, - }) - return - } - await adapter.sendVerificationRequest({ email, url, diff --git a/packages/oberoncms/core/src/auth/with-development-send.ts b/packages/oberoncms/core/src/auth/with-development-send.ts new file mode 100644 index 00000000..c128dbef --- /dev/null +++ b/packages/oberoncms/core/src/auth/with-development-send.ts @@ -0,0 +1,28 @@ +import { type OberonPlugin, type OberonSendAdapter } from "@oberoncms/core" + +const devSendPlugin: OberonPlugin = () => ({ + adapter: { + sendVerificationRequest: async ({ email, url }) => { + console.log(`Logging sendVerificationRequest`, { + email, + url, + }) + }, + } satisfies OberonSendAdapter, +}) + +export const withDevelopmentSend = (sendPlugin: OberonPlugin) => { + if (process.env.USE_DEVELOPMENT_SEND === "true") { + return devSendPlugin + } + + if (process.env.USE_DEVELOPMENT_SEND === "false") { + return sendPlugin + } + + if (process.env.NODE_ENV === "development" && !process.env.CI) { + return devSendPlugin + } + + return sendPlugin +} diff --git a/packages/oberoncms/core/src/components/editor.tsx b/packages/oberoncms/core/src/components/editor.tsx index fd2dfce9..0aab3c44 100644 --- a/packages/oberoncms/core/src/components/editor.tsx +++ b/packages/oberoncms/core/src/components/editor.tsx @@ -6,7 +6,7 @@ import { Config, Data, Puck, usePuck } from "@measured/puck" import { Button } from "@tohuhono/ui/button" import { useState } from "react" import { useLocalData } from "../hooks/use-local-data" -import { INITIAL_DATA } from "../app/schema" +import { INITIAL_DATA } from "../lib/dtd" import { useOberonActions } from "../hooks/use-oberon" import { Menu } from "./menu" diff --git a/packages/oberoncms/core/src/components/images.tsx b/packages/oberoncms/core/src/components/images.tsx index 69eca0a0..44c527bf 100644 --- a/packages/oberoncms/core/src/components/images.tsx +++ b/packages/oberoncms/core/src/components/images.tsx @@ -12,7 +12,7 @@ import Image from "next/image" import { Table, ColumnHeading } from "@tohuhono/ui/table" import { useOberonActions } from "../hooks/use-oberon" -import type { OberonImage } from "../app/schema" +import type { OberonImage } from "../lib/dtd" const useOberonImages = (images: OberonImage[]) => { const { deleteImage } = useOberonActions() diff --git a/packages/oberoncms/core/src/components/pages.tsx b/packages/oberoncms/core/src/components/pages.tsx index 850549a7..9160d980 100644 --- a/packages/oberoncms/core/src/components/pages.tsx +++ b/packages/oberoncms/core/src/components/pages.tsx @@ -17,7 +17,7 @@ import { z } from "zod" import { ColumnHeading, Table } from "@tohuhono/ui/table" import { LocalDate } from "@tohuhono/ui/date" import { useOberonActions } from "../hooks/use-oberon" -import { AddPageSchema, type OberonPageMeta } from "../app/schema" +import { AddPageSchema, type OberonPageMeta } from "../lib/dtd" function copyKey( optimisticPages: OberonPageMeta[], diff --git a/packages/oberoncms/core/src/components/provider.tsx b/packages/oberoncms/core/src/components/provider.tsx index a78f5686..243e9ac9 100644 --- a/packages/oberoncms/core/src/components/provider.tsx +++ b/packages/oberoncms/core/src/components/provider.tsx @@ -1,7 +1,7 @@ "use client" import { createContext, type PropsWithChildren } from "react" -import type { OberonActions, OberonClientContext } from "../app/schema" +import type { OberonActions, OberonClientContext } from "../lib/dtd" export const ClientContext = createContext(null) diff --git a/packages/oberoncms/core/src/components/site.tsx b/packages/oberoncms/core/src/components/site.tsx index e2d6b196..312f1ed9 100644 --- a/packages/oberoncms/core/src/components/site.tsx +++ b/packages/oberoncms/core/src/components/site.tsx @@ -12,7 +12,7 @@ import { type MigrationResult, type OberonSiteConfig, type TransformResult, -} from "../app/schema" +} from "../lib/dtd" function useMigration() { const { migrateData } = useOberonActions() diff --git a/packages/oberoncms/core/src/components/users.tsx b/packages/oberoncms/core/src/components/users.tsx index 01bff19b..672364ca 100644 --- a/packages/oberoncms/core/src/components/users.tsx +++ b/packages/oberoncms/core/src/components/users.tsx @@ -23,7 +23,7 @@ import { } from "@tohuhono/ui/form" import { ColumnHeading, Table } from "@tohuhono/ui/table" -import { AddUserSchema, OberonUser, roles } from "../app/schema" +import { AddUserSchema, OberonUser, roles } from "../lib/dtd" import { useOberonActions } from "../hooks/use-oberon" type OptimisticUser = OberonUser & { pending?: boolean } diff --git a/packages/oberoncms/core/src/editor.tsx b/packages/oberoncms/core/src/editor.tsx index 9b262e40..154e0810 100644 --- a/packages/oberoncms/core/src/editor.tsx +++ b/packages/oberoncms/core/src/editor.tsx @@ -1,7 +1,7 @@ import type { Config } from "@measured/puck" import { DynamicTailwind, PreviewFrameTailwind } from "@tohuhono/ui/theme" -import type { OberonConfig } from "./app/schema" -import { getTitle } from "./app/utils" +import type { OberonConfig } from "./lib/dtd" +import { getTitle } from "./lib/utils" import { useOberonClientContext } from "./hooks/use-oberon" import { Editor } from "./components/editor" import { Preview } from "./components/preview" diff --git a/packages/oberoncms/core/src/hooks/use-oberon-images.ts b/packages/oberoncms/core/src/hooks/use-oberon-images.ts index 3091e892..3cb76b54 100644 --- a/packages/oberoncms/core/src/hooks/use-oberon-images.ts +++ b/packages/oberoncms/core/src/hooks/use-oberon-images.ts @@ -1,5 +1,5 @@ import useSWR from "swr" -import { OberonImage } from "../app/schema" +import { OberonImage } from "../lib/dtd" import { useOberonActions } from "./use-oberon" export const useOberonImages = () => { diff --git a/packages/oberoncms/core/src/index.ts b/packages/oberoncms/core/src/index.ts index 4a7a9e4a..b95ed3be 100644 --- a/packages/oberoncms/core/src/index.ts +++ b/packages/oberoncms/core/src/index.ts @@ -1,4 +1,4 @@ -export * from "./app/schema" -export * from "./app/utils" -export * from "./app/get-metadata" +export * from "./lib/dtd" +export * from "./lib/utils" +export * from "./lib/get-metadata" export { cn } from "@tohuhono/utils" diff --git a/packages/oberoncms/core/src/app/schema.ts b/packages/oberoncms/core/src/lib/dtd.ts similarity index 100% rename from packages/oberoncms/core/src/app/schema.ts rename to packages/oberoncms/core/src/lib/dtd.ts diff --git a/packages/oberoncms/core/src/app/get-initial-data.ts b/packages/oberoncms/core/src/lib/get-initial-data.ts similarity index 87% rename from packages/oberoncms/core/src/app/get-initial-data.ts rename to packages/oberoncms/core/src/lib/get-initial-data.ts index 94e5a04f..109a8fb2 100644 --- a/packages/oberoncms/core/src/app/get-initial-data.ts +++ b/packages/oberoncms/core/src/lib/get-initial-data.ts @@ -1,4 +1,4 @@ -import type { OberonPage } from "./schema" +import type { OberonPage } from "./dtd" export function getInitialData(): OberonPage { return { diff --git a/packages/oberoncms/core/src/app/get-metadata.ts b/packages/oberoncms/core/src/lib/get-metadata.ts similarity index 91% rename from packages/oberoncms/core/src/app/get-metadata.ts rename to packages/oberoncms/core/src/lib/get-metadata.ts index dd879073..e0cd37e7 100644 --- a/packages/oberoncms/core/src/app/get-metadata.ts +++ b/packages/oberoncms/core/src/lib/get-metadata.ts @@ -1,5 +1,5 @@ import type { Metadata } from "next" -import type { OberonActions } from "./schema" +import type { OberonActions } from "./dtd" import { getTitle, parseClientAction, resolveSlug } from "./utils" export async function getMetaData( diff --git a/packages/oberoncms/core/src/app/transforms.ts b/packages/oberoncms/core/src/lib/transforms.ts similarity index 99% rename from packages/oberoncms/core/src/app/transforms.ts rename to packages/oberoncms/core/src/lib/transforms.ts index d53013c8..b1a781e9 100644 --- a/packages/oberoncms/core/src/app/transforms.ts +++ b/packages/oberoncms/core/src/lib/transforms.ts @@ -69,7 +69,7 @@ import type { OberonPageMeta, TransformResult, TransformVersions, -} from "./schema" +} from "./dtd" async function applyTransform( key: string, diff --git a/packages/oberoncms/core/src/app/utils.ts b/packages/oberoncms/core/src/lib/utils.ts similarity index 94% rename from packages/oberoncms/core/src/app/utils.ts rename to packages/oberoncms/core/src/lib/utils.ts index a2106c5f..c367c4ab 100644 --- a/packages/oberoncms/core/src/app/utils.ts +++ b/packages/oberoncms/core/src/lib/utils.ts @@ -1,5 +1,5 @@ import { notFound } from "next/navigation" -import type { ClientAction } from "./schema" +import type { ClientAction } from "./dtd" export function getTitle(action: ClientAction, slug?: string) { switch (action) { diff --git a/packages/oberoncms/core/src/provider.tsx b/packages/oberoncms/core/src/provider.tsx index 79c7c8d2..85b6b78e 100644 --- a/packages/oberoncms/core/src/provider.tsx +++ b/packages/oberoncms/core/src/provider.tsx @@ -1,8 +1,8 @@ import type { PropsWithChildren } from "react" import { OberonClientProvider } from "./components/provider" -import type { ClientAction, OberonActions } from "./app/schema" -import { parseClientAction, resolveSlug } from "./app/utils" +import type { ClientAction, OberonActions } from "./lib/dtd" +import { parseClientAction, resolveSlug } from "./lib/utils" async function getContext( { diff --git a/packages/oberoncms/core/src/render.tsx b/packages/oberoncms/core/src/render.tsx index 22b6b49a..9256c3ee 100644 --- a/packages/oberoncms/core/src/render.tsx +++ b/packages/oberoncms/core/src/render.tsx @@ -1,8 +1,8 @@ import { Render as PuckRender } from "@measured/puck/rsc" import { notFound } from "next/navigation" import type { Config } from "@measured/puck" -import { OberonActions, type OberonConfig } from "./app/schema" -import { resolveSlug } from "./app/utils" +import { OberonActions, type OberonConfig } from "./lib/dtd" +import { resolveSlug } from "./lib/utils" export async function Render({ path = [], diff --git a/packages/plugins/fly-drive/.prettierignore b/packages/plugins/flydrive/.prettierignore similarity index 100% rename from packages/plugins/fly-drive/.prettierignore rename to packages/plugins/flydrive/.prettierignore diff --git a/packages/plugins/fly-drive/CHANGELOG.md b/packages/plugins/flydrive/CHANGELOG.md similarity index 100% rename from packages/plugins/fly-drive/CHANGELOG.md rename to packages/plugins/flydrive/CHANGELOG.md diff --git a/packages/plugins/fly-drive/README.md b/packages/plugins/flydrive/README.md similarity index 100% rename from packages/plugins/fly-drive/README.md rename to packages/plugins/flydrive/README.md diff --git a/packages/plugins/fly-drive/eslint.config.mjs b/packages/plugins/flydrive/eslint.config.mjs similarity index 100% rename from packages/plugins/fly-drive/eslint.config.mjs rename to packages/plugins/flydrive/eslint.config.mjs diff --git a/packages/plugins/fly-drive/package.json b/packages/plugins/flydrive/package.json similarity index 100% rename from packages/plugins/fly-drive/package.json rename to packages/plugins/flydrive/package.json diff --git a/packages/plugins/fly-drive/src/blocks/client.tsx b/packages/plugins/flydrive/src/blocks/client.tsx similarity index 100% rename from packages/plugins/fly-drive/src/blocks/client.tsx rename to packages/plugins/flydrive/src/blocks/client.tsx diff --git a/packages/plugins/fly-drive/src/blocks/field.ts b/packages/plugins/flydrive/src/blocks/field.ts similarity index 100% rename from packages/plugins/fly-drive/src/blocks/field.ts rename to packages/plugins/flydrive/src/blocks/field.ts diff --git a/packages/plugins/fly-drive/src/blocks/image-field.tsx b/packages/plugins/flydrive/src/blocks/image-field.tsx similarity index 100% rename from packages/plugins/fly-drive/src/blocks/image-field.tsx rename to packages/plugins/flydrive/src/blocks/image-field.tsx diff --git a/packages/plugins/fly-drive/src/blocks/server.tsx b/packages/plugins/flydrive/src/blocks/server.tsx similarity index 100% rename from packages/plugins/fly-drive/src/blocks/server.tsx rename to packages/plugins/flydrive/src/blocks/server.tsx diff --git a/packages/plugins/fly-drive/src/index.ts b/packages/plugins/flydrive/src/index.ts similarity index 100% rename from packages/plugins/fly-drive/src/index.ts rename to packages/plugins/flydrive/src/index.ts diff --git a/packages/plugins/fly-drive/src/internal/disk-handlers.ts b/packages/plugins/flydrive/src/internal/disk-handlers.ts similarity index 100% rename from packages/plugins/fly-drive/src/internal/disk-handlers.ts rename to packages/plugins/flydrive/src/internal/disk-handlers.ts diff --git a/packages/plugins/fly-drive/src/internal/get-image-size.ts b/packages/plugins/flydrive/src/internal/get-image-size.ts similarity index 100% rename from packages/plugins/fly-drive/src/internal/get-image-size.ts rename to packages/plugins/flydrive/src/internal/get-image-size.ts diff --git a/packages/plugins/fly-drive/src/internal/plugin.ts b/packages/plugins/flydrive/src/internal/plugin.ts similarity index 100% rename from packages/plugins/fly-drive/src/internal/plugin.ts rename to packages/plugins/flydrive/src/internal/plugin.ts diff --git a/packages/plugins/fly-drive/src/plugin.ts b/packages/plugins/flydrive/src/plugin.ts similarity index 100% rename from packages/plugins/fly-drive/src/plugin.ts rename to packages/plugins/flydrive/src/plugin.ts diff --git a/packages/plugins/fly-drive/src/server.ts b/packages/plugins/flydrive/src/server.ts similarity index 100% rename from packages/plugins/fly-drive/src/server.ts rename to packages/plugins/flydrive/src/server.ts diff --git a/packages/plugins/fly-drive/tsconfig.json b/packages/plugins/flydrive/tsconfig.json similarity index 100% rename from packages/plugins/fly-drive/tsconfig.json rename to packages/plugins/flydrive/tsconfig.json diff --git a/packages/plugins/fly-drive/vite.config.js b/packages/plugins/flydrive/vite.config.js similarity index 100% rename from packages/plugins/fly-drive/vite.config.js rename to packages/plugins/flydrive/vite.config.js diff --git a/packages/plugins/pgsql/drizzle.config.ts b/packages/plugins/pgsql/drizzle.config.ts index d1d8ac97..a5dc6e60 100644 --- a/packages/plugins/pgsql/drizzle.config.ts +++ b/packages/plugins/pgsql/drizzle.config.ts @@ -1,6 +1,3 @@ -import dotenv from "dotenv" -dotenv.config({ path: ".env.local" }) - import type { Config } from "drizzle-kit" export default { diff --git a/packages/plugins/pgsql/package.json b/packages/plugins/pgsql/package.json index ae1f4414..ceb819ad 100644 --- a/packages/plugins/pgsql/package.json +++ b/packages/plugins/pgsql/package.json @@ -29,7 +29,9 @@ "LICENSE*" ], "exports": { - ".": "./dist/index.js" + ".": "./dist/index.js", + "./adapter": "./dist/adapter.js", + "./schema": "./dist/schema.js" }, "scripts": { "build": "vite build", @@ -42,10 +44,11 @@ "wait:clean": "rimraf ./dist/version" }, "dependencies": { - "pg": "^8.11.5", + "@auth/drizzle-adapter": "^1.2.0", "@oberoncms/core": "workspace:*", "drizzle-orm": "^0.30.10", "next": "^14.2.3", + "pg": "^8.11.5", "server-cli-only": "^0.3.2" }, "peerDependencies": { diff --git a/packages/plugins/pgsql/src/adapter.ts b/packages/plugins/pgsql/src/adapter.ts new file mode 100644 index 00000000..b3087ff6 --- /dev/null +++ b/packages/plugins/pgsql/src/adapter.ts @@ -0,0 +1,6 @@ +import "server-cli-only" + +export { migrate } from "drizzle-orm/libsql/migrator" + +export { getDatabaseAdapter } from "./db/database-adapter" +export { getAuthAdapter } from "./db/auth-adapter" diff --git a/packages/plugins/pgsql/src/db/auth-adapter.ts b/packages/plugins/pgsql/src/db/auth-adapter.ts index f0d34986..30f21b0c 100644 --- a/packages/plugins/pgsql/src/db/auth-adapter.ts +++ b/packages/plugins/pgsql/src/db/auth-adapter.ts @@ -1,4 +1,6 @@ import { DrizzleAdapter } from "@auth/drizzle-adapter" import type { OberonAuthAdapter } from "@oberoncms/core" -import { db } from "./client" -export const authAdapter = DrizzleAdapter(db) as OberonAuthAdapter +import { type DatabaseClient } from "./client" + +export const getAuthAdapter: (db: DatabaseClient) => OberonAuthAdapter = (db) => + DrizzleAdapter(db) as OberonAuthAdapter diff --git a/packages/plugins/pgsql/src/db/client.ts b/packages/plugins/pgsql/src/db/client.ts index 8587af26..991e7f61 100644 --- a/packages/plugins/pgsql/src/db/client.ts +++ b/packages/plugins/pgsql/src/db/client.ts @@ -1,8 +1,10 @@ -import { drizzle } from "drizzle-orm/node-postgres" +import { drizzle, NodePgDatabase } from "drizzle-orm/node-postgres" import { Pool } from "pg" import * as schema from "./schema" +export type DatabaseClient = NodePgDatabase + const createRemoteClient = () => { if (!process.env.DATABASE_URL) { throw new Error( diff --git a/packages/plugins/pgsql/src/db/database-adapter.ts b/packages/plugins/pgsql/src/db/database-adapter.ts index d9b08568..46fe435c 100644 --- a/packages/plugins/pgsql/src/db/database-adapter.ts +++ b/packages/plugins/pgsql/src/db/database-adapter.ts @@ -2,11 +2,13 @@ import { eq } from "drizzle-orm" import { type OberonDatabaseAdapter } from "@oberoncms/core" -import { db } from "./client" +import { type DatabaseClient } from "./client" import { images, pages, users, site } from "./schema" -import { authAdapter } from "./auth-adapter" +import { getAuthAdapter } from "./auth-adapter" -export const databaseAdapter: OberonDatabaseAdapter = { +export const getDatabaseAdapter: ( + db: DatabaseClient, +) => OberonDatabaseAdapter = (db) => ({ getSite: async () => { const result = await db .select({ @@ -37,14 +39,14 @@ export const databaseAdapter: OberonDatabaseAdapter = { .execute() }, addUser: async ({ email, role }) => { - return await authAdapter.createUser({ + return await getAuthAdapter(db).createUser({ email, role, emailVerified: null, }) }, deleteUser: async (id) => { - await authAdapter.deleteUser?.(id) + await getAuthAdapter(db).deleteUser?.(id) }, changeRole: async ({ role, id }) => { await db.update(users).set({ role }).where(eq(users.id, id)).execute() @@ -107,4 +109,4 @@ export const databaseAdapter: OberonDatabaseAdapter = { .from(pages) .execute() }, -} +}) diff --git a/packages/plugins/pgsql/src/db/init.ts b/packages/plugins/pgsql/src/db/init.ts deleted file mode 100644 index 4c4e45d4..00000000 --- a/packages/plugins/pgsql/src/db/init.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { migrate } from "drizzle-orm/node-postgres/migrator" -import { db } from "./client" - -export async function init() { - console.log(`Migrating database`) - - if (!db) { - console.log("Prepare: No Database Connection Configured") - return - } - - await migrate(db, { - migrationsFolder: "node_modules/@oberoncms/plugin-pgsql/src/db/migrations", - }) - - console.log(`Database migration complete`) -} diff --git a/packages/plugins/pgsql/src/index.ts b/packages/plugins/pgsql/src/index.ts index c3845779..76b19663 100644 --- a/packages/plugins/pgsql/src/index.ts +++ b/packages/plugins/pgsql/src/index.ts @@ -1,22 +1,37 @@ import "server-cli-only" -import { type OberonPlugin } from "@oberoncms/core" +import type { OberonPlugin } from "@oberoncms/core" +import { migrate } from "drizzle-orm/node-postgres/migrator" import { name, version } from "../package.json" with { type: "json" } -import { databaseAdapter } from "./db/database-adapter" -import { authAdapter } from "./db/auth-adapter" -import { init } from "./db/init" +import { getDatabaseAdapter } from "./db/database-adapter" +import { getAuthAdapter } from "./db/auth-adapter" + +import { db } from "./db/client" export const plugin: OberonPlugin = (adapter) => ({ name, version, adapter: { - ...databaseAdapter, - ...authAdapter, + ...getDatabaseAdapter(db), + ...getAuthAdapter(db), init: async () => { await adapter.init() - await init() + + console.log(`Migrating database`) + + if (!db) { + console.log("Prepare: No Database Connection Configured") + return + } + + await migrate(db, { + migrationsFolder: + "node_modules/@oberoncms/plugin-pgsql/src/db/migrations", + }) + + console.log(`Database migration complete`) }, }, }) diff --git a/packages/plugins/pgsql/src/schema.ts b/packages/plugins/pgsql/src/schema.ts new file mode 100644 index 00000000..1044dbdb --- /dev/null +++ b/packages/plugins/pgsql/src/schema.ts @@ -0,0 +1 @@ +export * from "./db/schema" diff --git a/packages/plugins/sqlite/.prettierignore b/packages/plugins/sqlite/.prettierignore new file mode 100644 index 00000000..5b2d2209 --- /dev/null +++ b/packages/plugins/sqlite/.prettierignore @@ -0,0 +1,5 @@ +node_modules +dist +.next +.vercel +**/meta/** \ No newline at end of file diff --git a/packages/plugins/sqlite/drizzle.config.ts b/packages/plugins/sqlite/drizzle.config.ts new file mode 100644 index 00000000..8e75e2e2 --- /dev/null +++ b/packages/plugins/sqlite/drizzle.config.ts @@ -0,0 +1,10 @@ +import type { Config } from "drizzle-kit" + +export default { + schema: "./src/db/schema/index.ts", + out: "./src/db/migrations", + driver: "libsql", + dbCredentials: { + url: "file:.oberon/oberon.db", + }, +} satisfies Config diff --git a/packages/plugins/sqlite/eslint.config.mjs b/packages/plugins/sqlite/eslint.config.mjs new file mode 100644 index 00000000..af093df6 --- /dev/null +++ b/packages/plugins/sqlite/eslint.config.mjs @@ -0,0 +1 @@ +export { default } from "@tohuhono/dev/eslint.config" diff --git a/packages/plugins/sqlite/package.json b/packages/plugins/sqlite/package.json new file mode 100644 index 00000000..8d2d0f44 --- /dev/null +++ b/packages/plugins/sqlite/package.json @@ -0,0 +1,67 @@ +{ + "name": "@oberoncms/plugin-sqlite", + "version": "0.1.0", + "author": "Tohuhono ltd", + "license": "MIT", + "description": "A Sqlite libsql database plugin for OberonCMS", + "keywords": [ + "oberon", + "oberoncms", + "cms", + "nextjs", + "react", + "adapter", + "plugin" + ], + "repository": { + "type": "git", + "url": "https://github.com/Tohuhono/Oberon.git", + "directory": "oberoncms/adapter-turso" + }, + "type": "module", + "files": [ + "dist", + "src", + "scripts", + "CHANGELOG*", + "README*", + "LICENSE*" + ], + "exports": { + ".": "./dist/index.js", + "./adapter": "./dist/adapter.js", + "./schema": "./dist/schema.js" + }, + "scripts": { + "build": "vite build", + "clean": "odt clean", + "generate:migrations": "drizzle-kit generate:sqlite", + "dev": "vite build --watch", + "lint": "eslint .", + "tsc": "tsc --pretty", + "wait": "wait-on ./dist/version && echo done", + "wait:clean": "rimraf ./dist/version" + }, + "dependencies": { + "@libsql/client": "^0.5.6", + "@libsql/core": "^0.5.6", + "@oberoncms/core": "workspace:*", + "drizzle-orm": "^0.30.10", + "server-cli-only": "^0.3.2" + }, + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@auth/core": "^0.30.0", + "@measured/puck": "^0.14.2", + "@tohuhono/dev": "workspace:*", + "@types/node": "20.11.26", + "@types/react": "18.2.66", + "@types/react-dom": "18.2.22", + "drizzle-kit": "^0.20.18", + "typescript": "5.4.2", + "vite": "^5.1.6" + } +} diff --git a/packages/plugins/sqlite/src/adapter.ts b/packages/plugins/sqlite/src/adapter.ts new file mode 100644 index 00000000..b3087ff6 --- /dev/null +++ b/packages/plugins/sqlite/src/adapter.ts @@ -0,0 +1,6 @@ +import "server-cli-only" + +export { migrate } from "drizzle-orm/libsql/migrator" + +export { getDatabaseAdapter } from "./db/database-adapter" +export { getAuthAdapter } from "./db/auth-adapter" diff --git a/packages/plugins/turso/src/db/auth-adapter.ts b/packages/plugins/sqlite/src/db/auth-adapter.ts similarity index 82% rename from packages/plugins/turso/src/db/auth-adapter.ts rename to packages/plugins/sqlite/src/db/auth-adapter.ts index abc579d0..1ddef28b 100644 --- a/packages/plugins/turso/src/db/auth-adapter.ts +++ b/packages/plugins/sqlite/src/db/auth-adapter.ts @@ -1,7 +1,7 @@ import { randomUUID } from "crypto" import { eq, and } from "drizzle-orm" import type { OberonAuthAdapter } from "@oberoncms/core" -import { db } from "./client" +import type { DatabaseClient } from "./client" import { users, accounts, @@ -9,9 +9,9 @@ import { verificationTokens, } from "./schema/next-auth-schema" -export const authAdapter: OberonAuthAdapter = { +export const getAuthAdapter = (db: DatabaseClient): OberonAuthAdapter => ({ async createUser(data) { - return db() + return db .insert(users) .values({ ...data, id: randomUUID() }) .returning() @@ -19,21 +19,20 @@ export const authAdapter: OberonAuthAdapter = { }, async getUser(data) { return ( - (await db().select().from(users).where(eq(users.id, data)).get()) ?? null + (await db.select().from(users).where(eq(users.id, data)).get()) ?? null ) }, async getUserByEmail(data) { return ( - (await db().select().from(users).where(eq(users.email, data)).get()) ?? - null + (await db.select().from(users).where(eq(users.email, data)).get()) ?? null ) }, async createSession(data) { - return db().insert(sessions).values(data).returning().get() + return db.insert(sessions).values(data).returning().get() }, async getSessionAndUser(data) { return ( - (await db() + (await db .select({ session: sessions, user: users, @@ -49,7 +48,7 @@ export const authAdapter: OberonAuthAdapter = { throw new Error("No user id.") } - return db() + return db .update(users) .set(data) .where(eq(users.id, data.id)) @@ -57,7 +56,7 @@ export const authAdapter: OberonAuthAdapter = { .get() }, async updateSession(data) { - return db() + return db .update(sessions) .set(data) .where(eq(sessions.sessionToken, data.sessionToken)) @@ -65,7 +64,7 @@ export const authAdapter: OberonAuthAdapter = { .get() }, async linkAccount(rawAccount) { - const updatedAccount = await db() + const updatedAccount = await db .insert(accounts) .values(rawAccount) .returning() @@ -86,7 +85,7 @@ export const authAdapter: OberonAuthAdapter = { return account }, async getUserByAccount(account) { - const results = await db() + const results = await db .select() .from(accounts) .leftJoin(users, eq(users.id, accounts.userId)) @@ -102,7 +101,7 @@ export const authAdapter: OberonAuthAdapter = { }, async deleteSession(sessionToken) { return ( - (await db() + (await db .delete(sessions) .where(eq(sessions.sessionToken, sessionToken)) .returning() @@ -110,12 +109,12 @@ export const authAdapter: OberonAuthAdapter = { ) }, async createVerificationToken(token) { - return db().insert(verificationTokens).values(token).returning().get() + return db.insert(verificationTokens).values(token).returning().get() }, async useVerificationToken(token) { try { return ( - (await db() + (await db .delete(verificationTokens) .where( and( @@ -131,10 +130,10 @@ export const authAdapter: OberonAuthAdapter = { } }, async deleteUser(id) { - await db().delete(users).where(eq(users.id, id)).returning().get() + await db.delete(users).where(eq(users.id, id)).returning().get() }, async unlinkAccount(account) { - await db() + await db .delete(accounts) .where( and( @@ -146,4 +145,4 @@ export const authAdapter: OberonAuthAdapter = { return undefined }, -} +}) diff --git a/packages/plugins/sqlite/src/db/client.ts b/packages/plugins/sqlite/src/db/client.ts new file mode 100644 index 00000000..979db7be --- /dev/null +++ b/packages/plugins/sqlite/src/db/client.ts @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +import { mkdir } from "fs/promises" +import { drizzle, type LibSQLDatabase } from "drizzle-orm/libsql" +import { createClient } from "@libsql/client" +// import type from here as +import type { Client } from "@libsql/core/api" + +import { sql } from "drizzle-orm/sql" +import * as schema from "./schema" + +declare global { + // eslint-disable-next-line no-var + var oberonDb: Client +} + +const url = process.env.SQLITE_FILE || "file:.oberon/oberon.db" + +// ensure there is only one database client +const getGlobalClient: () => Client = () => + globalThis.oberonDb || (globalThis.oberonDb = createClient({ url })) + +export const getClient = () => + drizzle(getGlobalClient(), { + schema, + }) + +export type DatabaseClient = LibSQLDatabase + +export async function initialise() { + await mkdir(".oberon", { recursive: true }) + await getClient().run(sql`PRAGMA journal_mode=WAL;`) +} diff --git a/packages/plugins/vercel-postgres/src/db/database-adapter.ts b/packages/plugins/sqlite/src/db/database-adapter.ts similarity index 79% rename from packages/plugins/vercel-postgres/src/db/database-adapter.ts rename to packages/plugins/sqlite/src/db/database-adapter.ts index 4779890c..3d32b1b9 100644 --- a/packages/plugins/vercel-postgres/src/db/database-adapter.ts +++ b/packages/plugins/sqlite/src/db/database-adapter.ts @@ -1,13 +1,32 @@ -import "server-cli-only" - +import { randomUUID } from "crypto" import { eq } from "drizzle-orm" -import { type OberonDatabaseAdapter } from "@oberoncms/core" +import { type OberonDatabaseAdapter, type PageData } from "@oberoncms/core" -import { db } from "./client" -import { images, pages, users, site } from "./schema" -import { authAdapter } from "./auth-adapter" +import { images, pages, site, users } from "./schema" +import type { DatabaseClient } from "./client" -export const databaseAdapter: OberonDatabaseAdapter = { +export const getDatabaseAdapter = ( + db: DatabaseClient, +): OberonDatabaseAdapter => ({ + getAllUsers: async () => { + return await db + .select({ id: users.id, email: users.email, role: users.role }) + .from(users) + .execute() + }, + addUser: async ({ email, role }) => { + return db + .insert(users) + .values({ email, role, id: randomUUID(), emailVerified: null }) + .returning() + .get() + }, + deleteUser: async (id) => { + await db.delete(users).where(eq(users.id, id)).returning().get() + }, + changeRole: async ({ role, id }) => { + await db.update(users).set({ role }).where(eq(users.id, id)).execute() + }, getSite: async () => { const result = await db .select({ @@ -31,25 +50,6 @@ export const databaseAdapter: OberonDatabaseAdapter = { }) .execute() }, - getAllUsers: async () => { - return await db - .select({ id: users.id, email: users.email, role: users.role }) - .from(users) - .execute() - }, - addUser: async ({ email, role }) => { - return await authAdapter.createUser({ - email, - role, - emailVerified: null, - }) - }, - deleteUser: async (id) => { - await authAdapter.deleteUser?.(id) - }, - changeRole: async ({ role, id }) => { - await db.update(users).set({ role }).where(eq(users.id, id)).execute() - }, addImage: async (image) => { await db.insert(images).values(image).execute() }, @@ -86,16 +86,13 @@ export const databaseAdapter: OberonDatabaseAdapter = { .where(eq(pages.key, key)) .execute() - return result[0]?.data || null + return (result[0]?.data as PageData) || null }, updatePageData: async ({ key, data, updatedAt, updatedBy }) => { await db .insert(pages) .values({ key, data, updatedAt, updatedBy }) - .onConflictDoUpdate({ - target: pages.key, - set: { data, updatedAt, updatedBy }, - }) + .onConflictDoUpdate({ target: pages.key, set: { data } }) .execute() }, getAllPages: async () => { @@ -108,4 +105,4 @@ export const databaseAdapter: OberonDatabaseAdapter = { .from(pages) .execute() }, -} +}) diff --git a/packages/plugins/sqlite/src/db/migrations/0000_faulty_menace.sql b/packages/plugins/sqlite/src/db/migrations/0000_faulty_menace.sql new file mode 100644 index 00000000..adc7d971 --- /dev/null +++ b/packages/plugins/sqlite/src/db/migrations/0000_faulty_menace.sql @@ -0,0 +1,56 @@ +CREATE TABLE `account` ( + `userId` text NOT NULL, + `type` text NOT NULL, + `provider` text NOT NULL, + `providerAccountId` text NOT NULL, + `refresh_token` text, + `access_token` text, + `expires_at` integer, + `token_type` text, + `scope` text, + `id_token` text, + `session_state` text, + PRIMARY KEY(`provider`, `providerAccountId`), + FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `session` ( + `sessionToken` text PRIMARY KEY NOT NULL, + `userId` text NOT NULL, + `expires` integer NOT NULL, + FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `user` ( + `id` text PRIMARY KEY NOT NULL, + `name` text, + `email` text NOT NULL, + `emailVerified` integer, + `image` text, + `role` text DEFAULT 'user' NOT NULL +); +--> statement-breakpoint +CREATE TABLE `verificationToken` ( + `identifier` text NOT NULL, + `token` text NOT NULL, + `expires` integer NOT NULL, + PRIMARY KEY(`identifier`, `token`) +); +--> statement-breakpoint +CREATE TABLE `pages` ( + `key` text PRIMARY KEY NOT NULL, + `data` text NOT NULL, + `updated_at` integer NOT NULL, + `updated_by` text NOT NULL +) WITHOUT ROWID; +--> statement-breakpoint +CREATE TABLE `images` ( + `key` text PRIMARY KEY NOT NULL, + `url` text NOT NULL, + `alt` text NOT NULL, + `size` integer NOT NULL, + `height` integer NOT NULL, + `width` integer NOT NULL, + `updated_at` integer NOT NULL, + `updated_by` text NOT NULL +) WITHOUT ROWID; diff --git a/packages/plugins/sqlite/src/db/migrations/0001_dear_vapor.sql b/packages/plugins/sqlite/src/db/migrations/0001_dear_vapor.sql new file mode 100644 index 00000000..219cbe0d --- /dev/null +++ b/packages/plugins/sqlite/src/db/migrations/0001_dear_vapor.sql @@ -0,0 +1,7 @@ +CREATE TABLE `site` ( + `id` integer PRIMARY KEY NOT NULL, + `version` integer NOT NULL, + `components` text NOT NULL, + `updated_at` integer NOT NULL, + `updated_by` text NOT NULL +); diff --git a/packages/plugins/sqlite/src/db/migrations/meta/0000_snapshot.json b/packages/plugins/sqlite/src/db/migrations/meta/0000_snapshot.json new file mode 100644 index 00000000..0b1f93c0 --- /dev/null +++ b/packages/plugins/sqlite/src/db/migrations/meta/0000_snapshot.json @@ -0,0 +1,358 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "ec4c520b-45f9-4193-a499-69af65f87af4", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": [ + "provider", + "providerAccountId" + ], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": [ + "identifier", + "token" + ], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {} + }, + "pages": { + "name": "pages", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "images": { + "name": "images", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/packages/plugins/sqlite/src/db/migrations/meta/0001_snapshot.json b/packages/plugins/sqlite/src/db/migrations/meta/0001_snapshot.json new file mode 100644 index 00000000..a2d40123 --- /dev/null +++ b/packages/plugins/sqlite/src/db/migrations/meta/0001_snapshot.json @@ -0,0 +1,402 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "1910b96a-b294-4a72-b622-9673f407535e", + "prevId": "ec4c520b-45f9-4193-a499-69af65f87af4", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": [ + "provider", + "providerAccountId" + ], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": [ + "identifier", + "token" + ], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {} + }, + "pages": { + "name": "pages", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "images": { + "name": "images", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "site": { + "name": "site", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "components": { + "name": "components", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/packages/plugins/sqlite/src/db/migrations/meta/_journal.json b/packages/plugins/sqlite/src/db/migrations/meta/_journal.json new file mode 100644 index 00000000..a1f6d1b0 --- /dev/null +++ b/packages/plugins/sqlite/src/db/migrations/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "5", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1715339559516, + "tag": "0000_faulty_menace", + "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1715905837965, + "tag": "0001_dear_vapor", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/packages/plugins/turso/src/db/schema/image-schema.ts b/packages/plugins/sqlite/src/db/schema/image-schema.ts similarity index 100% rename from packages/plugins/turso/src/db/schema/image-schema.ts rename to packages/plugins/sqlite/src/db/schema/image-schema.ts diff --git a/packages/plugins/sqlite/src/db/schema/index.ts b/packages/plugins/sqlite/src/db/schema/index.ts new file mode 100644 index 00000000..bb0f379c --- /dev/null +++ b/packages/plugins/sqlite/src/db/schema/index.ts @@ -0,0 +1,4 @@ +export * from "./next-auth-schema" +export * from "./puck-schema" +export * from "./image-schema" +export * from "./site-schema" diff --git a/packages/plugins/turso/src/db/schema/next-auth-schema.ts b/packages/plugins/sqlite/src/db/schema/next-auth-schema.ts similarity index 100% rename from packages/plugins/turso/src/db/schema/next-auth-schema.ts rename to packages/plugins/sqlite/src/db/schema/next-auth-schema.ts diff --git a/packages/plugins/turso/src/db/schema/puck-schema.ts b/packages/plugins/sqlite/src/db/schema/puck-schema.ts similarity index 100% rename from packages/plugins/turso/src/db/schema/puck-schema.ts rename to packages/plugins/sqlite/src/db/schema/puck-schema.ts diff --git a/packages/plugins/turso/src/db/schema/site-schema.ts b/packages/plugins/sqlite/src/db/schema/site-schema.ts similarity index 100% rename from packages/plugins/turso/src/db/schema/site-schema.ts rename to packages/plugins/sqlite/src/db/schema/site-schema.ts diff --git a/packages/plugins/sqlite/src/index.ts b/packages/plugins/sqlite/src/index.ts new file mode 100644 index 00000000..4796d70f --- /dev/null +++ b/packages/plugins/sqlite/src/index.ts @@ -0,0 +1,56 @@ +import "server-cli-only" + +import { type OberonPlugin } from "@oberoncms/core" + +import { migrate } from "drizzle-orm/libsql/migrator" +import { name, version } from "../package.json" with { type: "json" } + +import { getDatabaseAdapter } from "./db/database-adapter" +import { getAuthAdapter } from "./db/auth-adapter" +import { getClient, initialise } from "./db/client" + +export const plugin: OberonPlugin = (adapter) => ({ + name, + version, + adapter: { + ...getDatabaseAdapter(getClient()), + ...getAuthAdapter(getClient()), + init: async () => { + await adapter.init() + + console.log(`Migrating database`) + + await initialise() + + const db = getClient() + + if (!db) { + console.log("Prepare: No Database Connection Configured") + return + } + + await migrate(db, { + migrationsFolder: + "node_modules/@oberoncms/plugin-sqlite/src/db/migrations", + }) + + console.log(`Database migration complete`) + }, + }, +}) + +export const withDevelopmentDatabase = (databasePlugin: OberonPlugin) => { + if (process.env.USE_DEVELOPMENT_DATABASE === "true") { + return plugin + } + + if (process.env.USE_DEVELOPMENT_DATABASE === "false") { + return databasePlugin + } + + if (process.env.NODE_ENV === "development" && !process.env.CI) { + return plugin + } + + return databasePlugin +} diff --git a/packages/plugins/sqlite/src/schema.ts b/packages/plugins/sqlite/src/schema.ts new file mode 100644 index 00000000..1044dbdb --- /dev/null +++ b/packages/plugins/sqlite/src/schema.ts @@ -0,0 +1 @@ +export * from "./db/schema" diff --git a/packages/plugins/sqlite/tsconfig.json b/packages/plugins/sqlite/tsconfig.json new file mode 100644 index 00000000..21b7e67e --- /dev/null +++ b/packages/plugins/sqlite/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "jsx": "react-jsx" + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.spec.tsx"] +} diff --git a/packages/plugins/sqlite/vite.config.js b/packages/plugins/sqlite/vite.config.js new file mode 100644 index 00000000..f910705c --- /dev/null +++ b/packages/plugins/sqlite/vite.config.js @@ -0,0 +1,3 @@ +import { initConfig } from "@tohuhono/dev/vite.config" + +export default initConfig() diff --git a/packages/plugins/turso/drizzle.config.ts b/packages/plugins/turso/drizzle.config.ts index 167ee1d1..8e75e2e2 100644 --- a/packages/plugins/turso/drizzle.config.ts +++ b/packages/plugins/turso/drizzle.config.ts @@ -1,6 +1,3 @@ -import dotenv from "dotenv" -dotenv.config({ path: ".env.local" }) - import type { Config } from "drizzle-kit" export default { diff --git a/packages/plugins/turso/package.json b/packages/plugins/turso/package.json index 23f51af3..0dcb52d1 100644 --- a/packages/plugins/turso/package.json +++ b/packages/plugins/turso/package.json @@ -43,8 +43,8 @@ }, "dependencies": { "@libsql/client": "^0.5.6", - "@libsql/core": "^0.5.6", "@oberoncms/core": "workspace:*", + "@oberoncms/plugin-sqlite": "workspace:*", "drizzle-orm": "^0.30.10", "server-cli-only": "^0.3.2" }, diff --git a/packages/plugins/turso/src/db/client.ts b/packages/plugins/turso/src/db/client.ts index 2d785f2d..d24cdda3 100644 --- a/packages/plugins/turso/src/db/client.ts +++ b/packages/plugins/turso/src/db/client.ts @@ -1,56 +1,22 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { mkdir } from "fs/promises" import { drizzle } from "drizzle-orm/libsql" -import { createClient as createRemoteClient } from "@libsql/client/web" -import { createClient as createLocalClient } from "@libsql/client" -// import type from here as -import type { Client } from "@libsql/core/api" - -import { sql } from "drizzle-orm/sql" +import { createClient } from "@libsql/client/web" import * as schema from "./schema" -declare global { - // eslint-disable-next-line no-var - var oberonDb: Client -} - -export const IS_LOCAL_CLIENT = - process.env.TURSO_USE_REMOTE === "false" || - (process.env.TURSO_USE_REMOTE !== "true" && - process.env.NODE_ENV !== "production") - -function createClient() { - if (IS_LOCAL_CLIENT) { - const url = process.env.TURSO_FILE || "file:.oberon/oberon.db" - - return createLocalClient({ url }) - } - +export const getClient = () => { if (!process.env.TURSO_URL || !process.env.TURSO_TOKEN) { throw new Error( "No remote database credentials supplied: have you set TURSO_URL and TURSO_TOKEN?", ) } - return createRemoteClient({ - url: process.env.TURSO_URL, - authToken: process.env.TURSO_TOKEN, - }) -} - -// ensure there is only one database client -const getClient: () => Client = () => - globalThis.oberonDb || (globalThis.oberonDb = createClient()) - -export const db = () => - drizzle(getClient(), { - schema, - }) - -export async function initialise() { - if (!IS_LOCAL_CLIENT) { - return - } - await mkdir(".oberon", { recursive: true }) - await db().run(sql`PRAGMA journal_mode=WAL;`) + return drizzle( + createClient({ + url: process.env.TURSO_URL, + authToken: process.env.TURSO_TOKEN, + }), + { + schema, + }, + ) } diff --git a/packages/plugins/turso/src/db/database-adapter.ts b/packages/plugins/turso/src/db/database-adapter.ts deleted file mode 100644 index ebb70d09..00000000 --- a/packages/plugins/turso/src/db/database-adapter.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { randomUUID } from "crypto" -import { eq } from "drizzle-orm" -import { type OberonDatabaseAdapter, type PageData } from "@oberoncms/core" - -import { images, pages, site, users } from "./schema" -import { db } from "./client" - -export const databaseAdapter: OberonDatabaseAdapter = { - getAllUsers: async () => { - return await db() - .select({ id: users.id, email: users.email, role: users.role }) - .from(users) - .execute() - }, - addUser: async ({ email, role }) => { - return db() - .insert(users) - .values({ email, role, id: randomUUID(), emailVerified: null }) - .returning() - .get() - }, - deleteUser: async (id) => { - await db().delete(users).where(eq(users.id, id)).returning().get() - }, - changeRole: async ({ role, id }) => { - await db().update(users).set({ role }).where(eq(users.id, id)).execute() - }, - getSite: async () => { - const result = await db() - .select({ - version: site.version, - components: site.components, - updatedAt: site.updatedAt, - updatedBy: site.updatedBy, - }) - .from(site) - .where(eq(site.id, 1)) - .execute() - return result[0] - }, - updateSite: async ({ version, components, updatedAt, updatedBy }) => { - await db() - .insert(site) - .values({ id: 1, version, components, updatedAt, updatedBy }) - .onConflictDoUpdate({ - target: site.id, - set: { version, components, updatedAt, updatedBy }, - }) - .execute() - }, - addImage: async (image) => { - await db().insert(images).values(image).execute() - }, - deleteImage: async (key) => { - await db().delete(images).where(eq(images.key, key)).execute() - }, - getAllImages: async () => { - return await db() - .select({ - key: images.key, - alt: images.alt, - url: images.url, - size: images.size, - height: images.height, - width: images.width, - updatedAt: images.updatedAt, - updatedBy: images.updatedBy, - }) - .from(images) - .execute() - }, - addPage: async ({ key, data, updatedAt, updatedBy }) => { - await db() - .insert(pages) - .values({ key, data, updatedAt, updatedBy }) - .execute() - }, - deletePage: async (key) => { - await db().delete(pages).where(eq(pages.key, key)).execute() - }, - getPageData: async (key) => { - const result = await db() - .select({ - data: pages.data, - }) - .from(pages) - .where(eq(pages.key, key)) - .execute() - - return (result[0]?.data as PageData) || null - }, - updatePageData: async ({ key, data, updatedAt, updatedBy }) => { - await db() - .insert(pages) - .values({ key, data, updatedAt, updatedBy }) - .onConflictDoUpdate({ target: pages.key, set: { data } }) - .execute() - }, - getAllPages: async () => { - return await db() - .select({ - key: pages.key, - updatedAt: pages.updatedAt, - updatedBy: pages.updatedBy, - }) - .from(pages) - .execute() - }, -} diff --git a/packages/plugins/turso/src/db/drizzle-kit/meta/_journal.json b/packages/plugins/turso/src/db/drizzle-kit/meta/_journal.json deleted file mode 100644 index 1cf6b33c..00000000 --- a/packages/plugins/turso/src/db/drizzle-kit/meta/_journal.json +++ /dev/null @@ -1 +0,0 @@ -{ "version": "5", "dialect": "sqlite", "entries": [] } diff --git a/packages/plugins/turso/src/db/init.ts b/packages/plugins/turso/src/db/init.ts deleted file mode 100755 index d275bd29..00000000 --- a/packages/plugins/turso/src/db/init.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { migrate } from "drizzle-orm/libsql/migrator" -import { initialise, db } from "./client" - -export async function init() { - console.log(`Migrating database`) - - await initialise() - - if (!db()) { - console.log("Prepare: No Database Connection Configured") - return - } - - await migrate(db(), { - migrationsFolder: "node_modules/@oberoncms/plugin-turso/src/db/migrations", - }) - - console.log(`Database migration complete`) -} diff --git a/packages/plugins/turso/src/db/schema/index.ts b/packages/plugins/turso/src/db/schema/index.ts index bb0f379c..7d26081b 100644 --- a/packages/plugins/turso/src/db/schema/index.ts +++ b/packages/plugins/turso/src/db/schema/index.ts @@ -1,4 +1 @@ -export * from "./next-auth-schema" -export * from "./puck-schema" -export * from "./image-schema" -export * from "./site-schema" +export * from "@oberoncms/plugin-sqlite/schema" diff --git a/packages/plugins/turso/src/index.ts b/packages/plugins/turso/src/index.ts index c3845779..532952b8 100644 --- a/packages/plugins/turso/src/index.ts +++ b/packages/plugins/turso/src/index.ts @@ -1,22 +1,38 @@ import "server-cli-only" -import { type OberonPlugin } from "@oberoncms/core" - +import { + getAuthAdapter, + getDatabaseAdapter, + migrate, +} from "@oberoncms/plugin-sqlite/adapter" +import type { OberonPlugin } from "@oberoncms/core" import { name, version } from "../package.json" with { type: "json" } - -import { databaseAdapter } from "./db/database-adapter" -import { authAdapter } from "./db/auth-adapter" -import { init } from "./db/init" +import { getClient } from "./db/client" export const plugin: OberonPlugin = (adapter) => ({ name, version, adapter: { - ...databaseAdapter, - ...authAdapter, + ...getDatabaseAdapter(getClient()), + ...getAuthAdapter(getClient()), init: async () => { await adapter.init() - await init() + + console.log(`Migrating database`) + + const db = getClient() + + if (!db) { + console.log("Prepare: No Database Connection Configured") + return + } + + await migrate(db, { + migrationsFolder: + "node_modules/@oberoncms/plugin-turso/src/db/migrations", + }) + + console.log(`Database migration complete`) }, }, }) diff --git a/packages/plugins/vercel-postgres/package.json b/packages/plugins/vercel-postgres/package.json index c480dcb0..acbeb9c4 100644 --- a/packages/plugins/vercel-postgres/package.json +++ b/packages/plugins/vercel-postgres/package.json @@ -43,8 +43,8 @@ "wait:clean": "rimraf ./dist/version" }, "dependencies": { - "@auth/drizzle-adapter": "^1.0.1", "@next/env": "^14.2.3", + "@oberoncms/plugin-pgsql": "workspace:*", "@vercel/postgres": "0.8.0", "drizzle-orm": "^0.30.10", "next": "^14.2.3", diff --git a/packages/plugins/vercel-postgres/src/db/auth-adapter.ts b/packages/plugins/vercel-postgres/src/db/auth-adapter.ts deleted file mode 100644 index 9ce84c67..00000000 --- a/packages/plugins/vercel-postgres/src/db/auth-adapter.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DrizzleAdapter } from "@auth/drizzle-adapter" -import type { OberonAuthAdapter } from "@oberoncms/core" -import { db } from "./client" - -export const authAdapter = DrizzleAdapter(db) as OberonAuthAdapter diff --git a/packages/plugins/vercel-postgres/src/db/client.ts b/packages/plugins/vercel-postgres/src/db/client.ts index bba94f35..ca0f1caf 100644 --- a/packages/plugins/vercel-postgres/src/db/client.ts +++ b/packages/plugins/vercel-postgres/src/db/client.ts @@ -1,4 +1,4 @@ -import "./env-config" +import "./env" import { drizzle } from "drizzle-orm/vercel-postgres" import { sql } from "@vercel/postgres" import * as schema from "./schema" diff --git a/packages/plugins/vercel-postgres/src/db/env-config.ts b/packages/plugins/vercel-postgres/src/db/env.ts similarity index 100% rename from packages/plugins/vercel-postgres/src/db/env-config.ts rename to packages/plugins/vercel-postgres/src/db/env.ts diff --git a/packages/plugins/vercel-postgres/src/db/init.ts b/packages/plugins/vercel-postgres/src/db/init.ts deleted file mode 100644 index b81d3afd..00000000 --- a/packages/plugins/vercel-postgres/src/db/init.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { migrate } from "drizzle-orm/vercel-postgres/migrator" -import { db } from "./client" - -export async function init() { - console.log(`Migrating database`) - - if (!db) { - console.log("Prepare: No Database Connection Configured") - return - } - - await migrate(db, { - migrationsFolder: - "node_modules/@oberoncms/plugin-vercel-postgres/src/db/migrations", - }) - - console.log(`Database migration complete`) -} diff --git a/packages/plugins/vercel-postgres/src/db/schema/image-schema.ts b/packages/plugins/vercel-postgres/src/db/schema/image-schema.ts deleted file mode 100644 index d99d8ddf..00000000 --- a/packages/plugins/vercel-postgres/src/db/schema/image-schema.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - pgTable, - text, - integer, - uniqueIndex, - timestamp, -} from "drizzle-orm/pg-core" - -export const images = pgTable( - "images", - { - key: text("key").notNull().primaryKey(), - url: text("url").notNull(), - alt: text("alt").notNull(), - size: integer("size").notNull(), - height: integer("height").notNull(), - width: integer("width").notNull(), - updatedAt: timestamp("updated_at", { mode: "date" }).notNull(), - updatedBy: text("updated_by").notNull(), - }, - (images) => { - return { - imagesKeyIdx: uniqueIndex("images_key_idx").on(images.key), - } - }, -) diff --git a/packages/plugins/vercel-postgres/src/db/schema/index.ts b/packages/plugins/vercel-postgres/src/db/schema/index.ts index bb0f379c..66c54f5c 100644 --- a/packages/plugins/vercel-postgres/src/db/schema/index.ts +++ b/packages/plugins/vercel-postgres/src/db/schema/index.ts @@ -1,4 +1 @@ -export * from "./next-auth-schema" -export * from "./puck-schema" -export * from "./image-schema" -export * from "./site-schema" +export * from "@oberoncms/plugin-pgsql/schema" diff --git a/packages/plugins/vercel-postgres/src/db/schema/next-auth-schema.ts b/packages/plugins/vercel-postgres/src/db/schema/next-auth-schema.ts deleted file mode 100644 index 3fd05f38..00000000 --- a/packages/plugins/vercel-postgres/src/db/schema/next-auth-schema.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - timestamp, - pgTable, - text, - primaryKey, - integer, -} from "drizzle-orm/pg-core" -import type { AdapterAccount } from "next-auth/adapters" - -export const users = pgTable("user", { - id: text("id") - .primaryKey() - .$defaultFn(() => crypto.randomUUID()), - name: text("name"), - email: text("email").notNull(), - emailVerified: timestamp("emailVerified", { mode: "date" }), - image: text("image"), - role: text("role", { enum: ["admin", "user"] }) - .notNull() - .default("user"), -}) - -export const accounts = pgTable( - "account", - { - userId: text("userId") - .notNull() - .references(() => users.id, { onDelete: "cascade" }), - type: text("type").$type().notNull(), - provider: text("provider").notNull(), - providerAccountId: text("providerAccountId").notNull(), - refresh_token: text("refresh_token"), - access_token: text("access_token"), - expires_at: integer("expires_at"), - token_type: text("token_type"), - scope: text("scope"), - id_token: text("id_token"), - session_state: text("session_state"), - }, - (account) => ({ - compoundKey: primaryKey({ - columns: [account.provider, account.providerAccountId], - }), - }), -) - -export const sessions = pgTable("session", { - sessionToken: text("sessionToken").primaryKey(), - userId: text("userId") - .notNull() - .references(() => users.id, { onDelete: "cascade" }), - expires: timestamp("expires", { mode: "date" }).notNull(), -}) - -export const verificationTokens = pgTable( - "verificationToken", - { - identifier: text("identifier").notNull(), - token: text("token").notNull(), - expires: timestamp("expires", { mode: "date" }).notNull(), - }, - (vt) => ({ - compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - }), -) diff --git a/packages/plugins/vercel-postgres/src/db/schema/puck-schema.ts b/packages/plugins/vercel-postgres/src/db/schema/puck-schema.ts deleted file mode 100644 index 3efaf923..00000000 --- a/packages/plugins/vercel-postgres/src/db/schema/puck-schema.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { PageData } from "@oberoncms/core" -import { - pgTable, - jsonb, - text, - timestamp, - uniqueIndex, -} from "drizzle-orm/pg-core" - -export const pages = pgTable( - "pages", - { - key: text("key").notNull().primaryKey(), - data: jsonb("data").notNull().$type(), - updatedAt: timestamp("updated_at", { mode: "date" }).notNull(), - updatedBy: text("updated_by").notNull(), - }, - (pages) => { - return { - pagesKeyIdx: uniqueIndex("pages_key_idx").on(pages.key), - } - }, -) diff --git a/packages/plugins/vercel-postgres/src/db/schema/site-schema.ts b/packages/plugins/vercel-postgres/src/db/schema/site-schema.ts deleted file mode 100644 index 505a0500..00000000 --- a/packages/plugins/vercel-postgres/src/db/schema/site-schema.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { TransformVersions } from "@oberoncms/core" -import { - pgTable, - jsonb, - text, - timestamp, - uniqueIndex, - integer, -} from "drizzle-orm/pg-core" - -export const site = pgTable( - "site", - { - id: integer("id").notNull().primaryKey(), - version: integer("version").notNull(), - components: jsonb("components").notNull().$type(), - updatedAt: timestamp("updated_at", { mode: "date" }).notNull(), - updatedBy: text("updated_by").notNull(), - }, - (pages) => { - return { - pagesKeyIdx: uniqueIndex("site_id_idx").on(pages.id), - } - }, -) diff --git a/packages/plugins/vercel-postgres/src/index.ts b/packages/plugins/vercel-postgres/src/index.ts index c3845779..9c43148d 100644 --- a/packages/plugins/vercel-postgres/src/index.ts +++ b/packages/plugins/vercel-postgres/src/index.ts @@ -1,22 +1,36 @@ import "server-cli-only" -import { type OberonPlugin } from "@oberoncms/core" +import type { OberonPlugin } from "@oberoncms/core" +import { migrate } from "drizzle-orm/vercel-postgres/migrator" +import { + getDatabaseAdapter, + getAuthAdapter, +} from "@oberoncms/plugin-pgsql/adapter" import { name, version } from "../package.json" with { type: "json" } - -import { databaseAdapter } from "./db/database-adapter" -import { authAdapter } from "./db/auth-adapter" -import { init } from "./db/init" +import { db } from "./db/client" export const plugin: OberonPlugin = (adapter) => ({ name, version, adapter: { - ...databaseAdapter, - ...authAdapter, + ...getDatabaseAdapter(db), + ...getAuthAdapter(db), init: async () => { await adapter.init() - await init() + console.log(`Migrating database`) + + if (!db) { + console.log("Prepare: No Database Connection Configured") + return + } + + await migrate(db, { + migrationsFolder: + "node_modules/@oberoncms/plugin-vercel-postgres/src/db/migrations", + }) + + console.log(`Database migration complete`) }, }, }) diff --git a/playwright.config.ts b/playwright.config.ts index ca67567d..717e2cc3 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,7 +1,3 @@ -import { resolve } from "path" -import { defineConfig, devices } from "@playwright/experimental-ct-react" -import react from "@vitejs/plugin-react" - /** * Read environment variables from file. * https://github.com/motdotla/dotenv @@ -9,6 +5,10 @@ import react from "@vitejs/plugin-react" import dotenv from "dotenv" dotenv.config({ path: ".env.local" }) +import { resolve } from "path" +import { defineConfig, devices } from "@playwright/experimental-ct-react" +import react from "@vitejs/plugin-react" + /** * See https://playwright.dev/docs/test-configuration. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d52ecdae..b598d4b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,10 +7,6 @@ settings: importers: .: - dependencies: - dotenv: - specifier: ^16.4.5 - version: 16.4.5 devDependencies: '@changesets/cli': specifier: ^2.27.1 @@ -24,6 +20,9 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 eslint: specifier: 8.57.0 version: 8.57.0 @@ -179,6 +178,9 @@ importers: '@oberoncms/core': specifier: workspace:* version: link:../../packages/oberoncms/core + '@oberoncms/plugin-sqlite': + specifier: workspace:* + version: link:../../packages/plugins/sqlite '@oberoncms/plugin-turso': specifier: workspace:* version: link:../../packages/plugins/turso @@ -317,6 +319,24 @@ importers: '@oberoncms/core': specifier: workspace:* version: link:../oberoncms/core + '@oberoncms/plugin-flydrive': + specifier: workspace:* + version: link:../plugins/flydrive + '@oberoncms/plugin-pgsql': + specifier: workspace:* + version: link:../plugins/pgsql + '@oberoncms/plugin-sqlite': + specifier: workspace:* + version: link:../plugins/sqlite + '@oberoncms/plugin-turso': + specifier: workspace:* + version: link:../plugins/turso + '@oberoncms/plugin-uploadthing': + specifier: workspace:* + version: link:../plugins/uploadthing + '@oberoncms/plugin-vercel-postgres': + specifier: workspace:* + version: link:../plugins/vercel-postgres '@sendgrid/mail': specifier: 8.1.3 version: 8.1.3 @@ -374,6 +394,9 @@ importers: '@tohuhono/utils': specifier: workspace:* version: link:../../tohuhono/utils + dotenv: + specifier: ^16.4.5 + version: 16.4.5 filesize: specifier: ^10.1.0 version: 10.1.1 @@ -421,7 +444,50 @@ importers: specifier: ^5.1.6 version: 5.2.8(@types/node@20.11.26) - packages/plugins/fly-drive: + packages/plugins/development: + dependencies: + '@oberoncms/core': + specifier: workspace:* + version: link:../../oberoncms/core + '@oberoncms/plugin-sqlite': + specifier: workspace:* + version: link:../sqlite + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + devDependencies: + '@auth/core': + specifier: ^0.30.0 + version: 0.30.0 + '@measured/puck': + specifier: ^0.14.2 + version: 0.14.2(@types/react-dom@18.2.22)(@types/react@18.2.66)(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) + '@tohuhono/dev': + specifier: workspace:* + version: link:../../tohuhono/dev + '@types/node': + specifier: 20.11.26 + version: 20.11.26 + '@types/react': + specifier: 18.2.66 + version: 18.2.66 + '@types/react-dom': + specifier: 18.2.22 + version: 18.2.22 + drizzle-kit: + specifier: ^0.20.18 + version: 0.20.18 + typescript: + specifier: 5.4.2 + version: 5.4.2 + vite: + specifier: ^5.1.6 + version: 5.2.8(@types/node@20.11.26) + + packages/plugins/flydrive: dependencies: '@oberoncms/core': specifier: workspace:* @@ -475,6 +541,9 @@ importers: packages/plugins/pgsql: dependencies: + '@auth/drizzle-adapter': + specifier: ^1.2.0 + version: 1.2.0 '@oberoncms/core': specifier: workspace:* version: link:../../oberoncms/core @@ -528,7 +597,7 @@ importers: specifier: ^5.1.6 version: 5.2.8(@types/node@20.11.26) - packages/plugins/turso: + packages/plugins/sqlite: dependencies: '@libsql/client': specifier: ^0.5.6 @@ -580,6 +649,58 @@ importers: specifier: ^5.1.6 version: 5.2.8(@types/node@20.11.26) + packages/plugins/turso: + dependencies: + '@libsql/client': + specifier: ^0.5.6 + version: 0.5.6 + '@oberoncms/core': + specifier: workspace:* + version: link:../../oberoncms/core + '@oberoncms/plugin-sqlite': + specifier: workspace:* + version: link:../sqlite + drizzle-orm: + specifier: ^0.30.10 + version: 0.30.10(@libsql/client@0.5.6)(@types/react@18.2.66)(react@18.2.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + server-cli-only: + specifier: ^0.3.2 + version: 0.3.2 + devDependencies: + '@auth/core': + specifier: ^0.30.0 + version: 0.30.0 + '@measured/puck': + specifier: ^0.14.2 + version: 0.14.2(@types/react-dom@18.2.22)(@types/react@18.2.66)(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) + '@tohuhono/dev': + specifier: workspace:* + version: link:../../tohuhono/dev + '@types/node': + specifier: 20.11.26 + version: 20.11.26 + '@types/react': + specifier: 18.2.66 + version: 18.2.66 + '@types/react-dom': + specifier: 18.2.22 + version: 18.2.22 + drizzle-kit: + specifier: ^0.20.18 + version: 0.20.18 + typescript: + specifier: 5.4.2 + version: 5.4.2 + vite: + specifier: ^5.1.6 + version: 5.2.8(@types/node@20.11.26) + packages/plugins/uploadthing: dependencies: '@oberoncms/core': @@ -637,12 +758,12 @@ importers: packages/plugins/vercel-postgres: dependencies: - '@auth/drizzle-adapter': - specifier: ^1.0.1 - version: 1.0.1 '@next/env': specifier: ^14.2.3 version: 14.2.3 + '@oberoncms/plugin-pgsql': + specifier: workspace:* + version: link:../pgsql '@vercel/postgres': specifier: 0.8.0 version: 0.8.0 @@ -1012,9 +1133,6 @@ importers: '@oberoncms/core': specifier: workspace:* version: link:../../packages/oberoncms/core - dotenv: - specifier: ^16.4.5 - version: 16.4.5 next: specifier: ^14.2.3 version: 14.2.3(react-dom@18.2.0)(react@18.2.0) @@ -1103,10 +1221,33 @@ packages: preact: 10.11.3 preact-render-to-string: 5.2.3(preact@10.11.3) - /@auth/drizzle-adapter@1.0.1: - resolution: {integrity: sha512-E4np2F48p930q+YeQ5ipZPv/L+9gmQcB7g6NQQyux2wtanRNOXNW4TG8wMjSRfTzccNq161YZ8Fm5le/5snkGQ==} + /@auth/core@0.32.0: + resolution: {integrity: sha512-3+ssTScBd+1fd0/fscAyQN1tSygXzuhysuVVzB942ggU4mdfiTbv36P0ccVnExKWYJKvu3E2r3/zxXCCAmTOrg==} + peerDependencies: + '@simplewebauthn/browser': ^9.0.1 + '@simplewebauthn/server': ^9.0.2 + nodemailer: ^6.8.0 + peerDependenciesMeta: + '@simplewebauthn/browser': + optional: true + '@simplewebauthn/server': + optional: true + nodemailer: + optional: true dependencies: - '@auth/core': 0.30.0 + '@panva/hkdf': 1.1.1 + '@types/cookie': 0.6.0 + cookie: 0.6.0 + jose: 5.2.4 + oauth4webapi: 2.10.4 + preact: 10.11.3 + preact-render-to-string: 5.2.3(preact@10.11.3) + dev: false + + /@auth/drizzle-adapter@1.2.0: + resolution: {integrity: sha512-95LHWlgtR4rQeHy4bACiVgTZdWkkEpVXYJim1IqbF1Hy0MnnMalmfGuIlNcOi64+6iC17j5FkDsMchqGwvj2Dg==} + dependencies: + '@auth/core': 0.32.0 transitivePeerDependencies: - '@simplewebauthn/browser' - '@simplewebauthn/server' @@ -4197,7 +4338,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: false optional: true /@rollup/rollup-android-arm64@4.17.2: @@ -4212,7 +4352,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: false optional: true /@rollup/rollup-darwin-arm64@4.17.2: @@ -4227,7 +4366,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@rollup/rollup-darwin-x64@4.17.2: @@ -4242,7 +4380,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-arm-gnueabihf@4.17.2: @@ -4257,7 +4394,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-arm-musleabihf@4.17.2: @@ -4272,7 +4408,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-arm64-gnu@4.17.2: @@ -4287,7 +4422,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-arm64-musl@4.17.2: @@ -4302,7 +4436,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-powerpc64le-gnu@4.17.2: @@ -4317,7 +4450,6 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-riscv64-gnu@4.17.2: @@ -4332,7 +4464,6 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-s390x-gnu@4.17.2: @@ -4347,7 +4478,6 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-x64-gnu@4.17.2: @@ -4362,7 +4492,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-linux-x64-musl@4.17.2: @@ -4377,7 +4506,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@rollup/rollup-win32-arm64-msvc@4.17.2: @@ -4392,7 +4520,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@rollup/rollup-win32-ia32-msvc@4.17.2: @@ -4407,7 +4534,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@rollup/rollup-win32-x64-msvc@4.17.2: @@ -4422,7 +4548,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@rushstack/eslint-patch@1.10.2: @@ -6509,7 +6634,6 @@ packages: /dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} - dev: false /dreamopt@0.8.0: resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} @@ -11476,7 +11600,6 @@ packages: '@rollup/rollup-win32-ia32-msvc': 4.18.0 '@rollup/rollup-win32-x64-msvc': 4.18.0 fsevents: 2.3.3 - dev: false /rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} @@ -12884,7 +13007,7 @@ packages: '@types/node': 20.11.26 esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.17.2 + rollup: 4.18.0 optionalDependencies: fsevents: 2.3.3 dev: true diff --git a/recipes/nextjs/oberon/prebuild.ts b/recipes/nextjs/oberon/prebuild.ts index c918c4f1..54cfaf27 100644 --- a/recipes/nextjs/oberon/prebuild.ts +++ b/recipes/nextjs/oberon/prebuild.ts @@ -1,8 +1,4 @@ #!/usr/bin/env node -/* eslint-env node */ -import dotenv from "dotenv"; -dotenv.config({ path: ".env.local" }); - import { exportTailwindClasses } from "@oberoncms/core/adapter"; import { adapter } from "./adapter"; diff --git a/recipes/nextjs/package.json b/recipes/nextjs/package.json index 9cbcdd10..f7668a69 100644 --- a/recipes/nextjs/package.json +++ b/recipes/nextjs/package.json @@ -16,7 +16,6 @@ "dependencies": { "@oberoncms/core": "workspace:*", "@datacom-digital/ui-sample-components": "^0.3.2", - "dotenv": "^16.4.5", "next": "^14.2.3", "react": "^18.2.0", "react-dom": "^18.2.0", From b8fe761cd09e1cf85ad42b6f894f0a6d630b5818 Mon Sep 17 00:00:00 2001 From: Jon <4leite@gmail.com> Date: Sun, 9 Jun 2024 23:15:15 +1200 Subject: [PATCH 2/3] move development mode to wrappers --- .changeset/mean-cows-change.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .changeset/mean-cows-change.md diff --git a/.changeset/mean-cows-change.md b/.changeset/mean-cows-change.md new file mode 100644 index 00000000..6325c715 --- /dev/null +++ b/.changeset/mean-cows-change.md @@ -0,0 +1,15 @@ +--- +"@oberoncms/plugin-vercel-postgres": patch +"create-oberon-app": patch +"@oberoncms/plugin-flydrive": patch +"@oberoncms/core": patch +"@oberoncms/plugin-sqlite": patch +"@oberoncms/plugin-pgsql": patch +"@oberoncms/plugin-turso": patch +"@oberon/docs": patch +"@oberon/playground": patch +"@oberon/nextjs-recipe": patch +--- + +Move development fallback to wrappers +Move local sqlite to separate plugin From b0c7c998fb48d66e933eedc4b232fe68f06c086f Mon Sep 17 00:00:00 2001 From: Jon <4leite@gmail.com> Date: Sun, 9 Jun 2024 23:42:17 +1200 Subject: [PATCH 3/3] move development mode to wrappers --- .../oberoncms/core/src/{lib => adapter}/get-initial-data.ts | 2 +- packages/oberoncms/core/src/adapter/init-actions.tsx | 2 +- packages/oberoncms/core/src/adapter/init-adapter.tsx | 2 +- packages/oberoncms/core/src/{lib => adapter}/transforms.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename packages/oberoncms/core/src/{lib => adapter}/get-initial-data.ts (86%) rename packages/oberoncms/core/src/{lib => adapter}/transforms.ts (99%) diff --git a/packages/oberoncms/core/src/lib/get-initial-data.ts b/packages/oberoncms/core/src/adapter/get-initial-data.ts similarity index 86% rename from packages/oberoncms/core/src/lib/get-initial-data.ts rename to packages/oberoncms/core/src/adapter/get-initial-data.ts index 109a8fb2..b073fbe1 100644 --- a/packages/oberoncms/core/src/lib/get-initial-data.ts +++ b/packages/oberoncms/core/src/adapter/get-initial-data.ts @@ -1,4 +1,4 @@ -import type { OberonPage } from "./dtd" +import type { OberonPage } from "../lib/dtd" export function getInitialData(): OberonPage { return { diff --git a/packages/oberoncms/core/src/adapter/init-actions.tsx b/packages/oberoncms/core/src/adapter/init-actions.tsx index 996ae166..7eca2793 100644 --- a/packages/oberoncms/core/src/adapter/init-actions.tsx +++ b/packages/oberoncms/core/src/adapter/init-actions.tsx @@ -30,7 +30,7 @@ import { applyTransforms, getComponentTransformVersions, getTransforms, -} from "../lib/transforms" +} from "./transforms" export function initActions({ config, diff --git a/packages/oberoncms/core/src/adapter/init-adapter.tsx b/packages/oberoncms/core/src/adapter/init-adapter.tsx index 8a82cff5..1bf6724c 100644 --- a/packages/oberoncms/core/src/adapter/init-adapter.tsx +++ b/packages/oberoncms/core/src/adapter/init-adapter.tsx @@ -1,6 +1,6 @@ import { type OberonPlugin, type OberonAdapter } from "../lib/dtd" +import { getInitialData } from "./get-initial-data" import { baseAdapter } from "./base-adapter" -import { getInitialData } from "../lib/get-initial-data" export function initAdapter(plugins: OberonPlugin[] = []) { const adapter = plugins.reduce((accumulator, plugin) => { diff --git a/packages/oberoncms/core/src/lib/transforms.ts b/packages/oberoncms/core/src/adapter/transforms.ts similarity index 99% rename from packages/oberoncms/core/src/lib/transforms.ts rename to packages/oberoncms/core/src/adapter/transforms.ts index b1a781e9..1e70dd6d 100644 --- a/packages/oberoncms/core/src/lib/transforms.ts +++ b/packages/oberoncms/core/src/adapter/transforms.ts @@ -69,7 +69,7 @@ import type { OberonPageMeta, TransformResult, TransformVersions, -} from "./dtd" +} from "../lib/dtd" async function applyTransform( key: string,