@phtngyn/cms 0.2.0-beta.1 → 0.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +40 -45
- package/package.json +7 -5
- package/src/ApplicationTypes.d.ts +7 -5
- package/src/{Configuration-CjVUBBwa.js → Configuration-BU-UyGoH.js} +4 -4
- package/src/{Configuration-CjVUBBwa.js.map → Configuration-BU-UyGoH.js.map} +1 -1
- package/src/Configuration.d.ts +41 -24
- package/src/Configuration.js.map +1 -1
- package/src/Content.js +42 -19
- package/src/Content.js.map +1 -1
- package/src/{ContentTransfer-CTzGGKFV.js → ContentTransfer-BhF9G56s.js} +2 -2
- package/src/{ContentTransfer-CTzGGKFV.js.map → ContentTransfer-BhF9G56s.js.map} +1 -1
- package/src/{DocumentEngine-BbhfnTAc.js → DocumentEngine-ClhFXW9M.js} +4 -4
- package/src/{DocumentEngine-BbhfnTAc.js.map → DocumentEngine-ClhFXW9M.js.map} +1 -1
- package/src/DocumentModel.d.ts +6 -1
- package/src/DocumentModel.js +4 -3
- package/src/DocumentModel.js.map +1 -1
- package/src/{Forms-CfcI3tPU.js → Forms-BbkE7QfC.js} +47 -16
- package/src/Forms-BbkE7QfC.js.map +1 -0
- package/src/{Forms-02-p8qEw.js → Forms-DoB56hfe.js} +24 -7
- package/src/Forms-DoB56hfe.js.map +1 -0
- package/src/{Forms-BorTcIlp.d.ts → Forms-R0HoTR-o.d.ts} +30 -9
- package/src/Forms.d.ts +16 -15
- package/src/Forms.js.map +1 -1
- package/src/{I18n-BXlVunfa.d.ts → I18n-zbqpWxki.d.ts} +3 -1
- package/src/I18n.d.ts +1 -1
- package/src/Module.js +4 -2
- package/src/Module.js.map +1 -1
- package/src/{S3MediaObjects-DC0c8sYC.js → S3MediaObjects-CR3p1WTg.js} +21 -13
- package/src/S3MediaObjects-CR3p1WTg.js.map +1 -0
- package/src/cli.js +60 -34
- package/src/cli.js.map +1 -1
- package/src/{connection-BPf4BQUZ.js → connection-D5S9Iph-.js} +2 -2
- package/src/{connection-BPf4BQUZ.js.map → connection-D5S9Iph-.js.map} +1 -1
- package/src/{dev-lifecycle-vQLxwCFq.js → dev-lifecycle-D3f9-upa.js} +129 -42
- package/src/dev-lifecycle-D3f9-upa.js.map +1 -0
- package/src/{installation-DsGst1BH.js → installation-fZtNxtoW.js} +68 -41
- package/src/installation-fZtNxtoW.js.map +1 -0
- package/src/internal/authoring-catalog.js +2 -2
- package/src/internal/authoring-metadata.js +1 -1
- package/src/internal/configuration.js +149 -50
- package/src/internal/configuration.js.map +1 -1
- package/src/internal/dev-lifecycle.js +2 -2
- package/src/internal/diagnostics.js +47 -0
- package/src/internal/diagnostics.js.map +1 -0
- package/src/internal/document-model.js +2 -2
- package/src/internal/form-capabilities.js +1 -1
- package/src/internal/i18n.js +6 -1
- package/src/internal/i18n.js.map +1 -1
- package/src/internal/studio-app.js +8 -6
- package/src/internal/studio-app.js.map +1 -1
- package/src/{location-BgYhXEZp.js → location-CPX7oj0o.js} +2 -2
- package/src/{location-BgYhXEZp.js.map → location-CPX7oj0o.js.map} +1 -1
- package/src/{models-k2nXyD6q.js → models-C9kF9JlQ.js} +2 -2
- package/src/{models-k2nXyD6q.js.map → models-C9kF9JlQ.js.map} +1 -1
- package/src/{models-DgkGTFus.js → models-ChRxBChy.js} +4 -2
- package/src/{models-DgkGTFus.js.map → models-ChRxBChy.js.map} +1 -1
- package/src/runtime/delivery/context.js +1 -1
- package/src/runtime/delivery/plugin.js +3 -2
- package/src/runtime/delivery/plugin.js.map +1 -1
- package/src/runtime/forms/document.js +1 -1
- package/src/runtime/forms/useCmsForm.js +73 -46
- package/src/runtime/forms/useCmsForm.js.map +1 -1
- package/src/runtime/i18n/useCmsI18n.d.ts +1 -1
- package/src/runtime/i18n/useCmsI18n.js.map +1 -1
- package/src/runtime/installation.js +1 -1
- package/src/runtime/plugin.js +12 -4
- package/src/runtime/plugin.js.map +1 -1
- package/src/runtime/preview/connection.js +1 -1
- package/src/runtime/preview/controller.js +2 -2
- package/src/runtime/preview/plugin.client.js +3 -3
- package/src/runtime/preview/plugin.client.js.map +1 -1
- package/src/runtime/preview/store.js +1 -1
- package/src/runtime/sitemap.js +1 -1
- package/src/{store-BYgSt7E3.js → store-CCsjHaZm.js} +8 -8
- package/src/store-CCsjHaZm.js.map +1 -0
- package/studio/{CreateDocumentDialog-BdiM77bb.js → CreateDocumentDialog-DJ8c0WZb.js} +3 -3
- package/studio/{documentPlanning-B7fyUj9r.js → documentPlanning-CDb31mnl.js} +6417 -6358
- package/studio/host.css +1 -1
- package/studio/host.js +7612 -7249
- package/src/Forms-02-p8qEw.js.map +0 -1
- package/src/Forms-CfcI3tPU.js.map +0 -1
- package/src/S3MediaObjects-DC0c8sYC.js.map +0 -1
- package/src/dev-lifecycle-vQLxwCFq.js.map +0 -1
- package/src/installation-DsGst1BH.js.map +0 -1
- package/src/store-BYgSt7E3.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-lifecycle-D3f9-upa.js","names":["AuthoringCatalogSchema"],"sources":["../../../../sql-pg/src/Migration.ts","../../../../auth/src/LocalDevelopment.ts","../../../src/internal/dev-lifecycle.ts"],"sourcesContent":["import type { PgPoolConfig } from '@effect/sql-pg/PgClient'\nimport { Effect, Schema } from 'effect'\nimport { embeddedMigrations } from './internal/database/embedded-migrations.generated'\nimport { migrateCmsDatabase } from './internal/database/migrations'\nimport { schemaClientLayer } from './internal/postgres/scoped-client'\n\nexport interface PostgresMigration {\n readonly createdAt: number\n readonly hash: string\n readonly name: string\n readonly statements: ReadonlyArray<string>\n}\n\n/** Migration history used by development tooling to verify pending SQL without mutating the database. */\nexport const postgresMigrations: ReadonlyArray<PostgresMigration> = Object.freeze(\n embeddedMigrations.map((migration) =>\n Object.freeze({\n createdAt: migration.folderMillis,\n hash: migration.hash,\n name: migration.name,\n statements: Object.freeze([...migration.sql]),\n }),\n ),\n)\n\nexport class MigrationFailed extends Schema.TaggedError<MigrationFailed>()('Postgres.MigrationFailed', {\n cause: Schema.Defect(),\n operation: Schema.String,\n}) {}\n\nexport interface PostgresMigrationOptions extends PgPoolConfig {\n readonly schema: string\n}\n\nexport function migratePostgres(options: PostgresMigrationOptions): Effect.Effect<void, MigrationFailed> {\n const { schema, ...poolOptions } = options\n\n return migrateCmsDatabase(schema).pipe(\n Effect.provide(\n schemaClientLayer({ ...poolOptions, applicationName: options.applicationName ?? '@internal/migrate' }, schema),\n ),\n Effect.mapError((cause) => new MigrationFailed({ cause, operation: 'Postgres.migrate' })),\n )\n}\n","import type { BetterAuthOptions } from 'better-auth'\nimport { Effect, Schema } from 'effect'\nimport { createCmsBetterAuth } from './internal/better-auth'\n\nexport interface LocalAdministratorOptions {\n readonly baseUrl: string\n readonly database: NonNullable<BetterAuthOptions['database']>\n readonly email: string\n readonly name: string\n readonly password: string\n readonly secret: string\n}\n\nexport type LocalAdministratorResult = 'created' | 'updated' | 'verified'\n\nexport class LocalAdministratorFailed extends Schema.TaggedError<LocalAdministratorFailed>()(\n 'LocalAdministrator.Failed',\n { cause: Schema.Defect() },\n) {}\n\n/** Reconciles the one local-development administrator without exposing Better Auth's admin routes. */\nexport const reconcileLocalAdministrator = Effect.fn('LocalAdministrator.reconcile')(function* (\n options: LocalAdministratorOptions,\n) {\n const auth = createCmsBetterAuth({\n baseURL: options.baseUrl,\n database: options.database,\n secret: options.secret,\n })\n\n return yield* Effect.tryPromise({\n // oxlint-disable-next-line effecttsgo/async-function -- Better Auth's internal adapter exposes its transaction as one Promise workflow.\n try: async () => {\n const context = await auth.$context\n const existing = await context.internalAdapter.findUserByEmail(options.email, { includeAccounts: true })\n\n if (!existing) {\n const user = await context.internalAdapter.createUser(\n { email: options.email, name: options.name, role: 'administrator' },\n { method: 'admin' },\n )\n\n const password = await context.password.hash(options.password)\n await context.internalAdapter.linkAccount({\n accountId: user.id,\n password,\n providerId: 'credential',\n userId: user.id,\n })\n\n return 'created' as const\n }\n\n const isAdministrator =\n Schema.is(Schema.Struct({ role: Schema.String }))(existing.user) && existing.user.role === 'administrator'\n\n let changed = existing.user.name !== options.name || !isAdministrator\n\n if (changed)\n await context.internalAdapter.updateUser(existing.user.id, {\n name: options.name,\n role: 'administrator',\n })\n\n const credential = existing.accounts.find(\n (account) => account.providerId === 'credential' && account.accountId === existing.user.id,\n )\n\n const passwordMatches = credential?.password\n ? await context.password.verify({ hash: credential.password, password: options.password })\n : false\n\n if (!passwordMatches) {\n const password = await context.password.hash(options.password)\n\n if (credential) await context.internalAdapter.updatePassword(existing.user.id, password)\n else\n await context.internalAdapter.createAccount({\n accountId: existing.user.id,\n password,\n providerId: 'credential',\n userId: existing.user.id,\n })\n\n changed = true\n }\n\n return changed ? ('updated' as const) : ('verified' as const)\n },\n catch: (cause) => new LocalAdministratorFailed({ cause }),\n })\n})\n","/* oxlint-disable effecttsgo/async-function effecttsgo/global-fetch effecttsgo/global-timers effecttsgo/new-promise effecttsgo/node-builtin-import -- The CLI boundary coordinates Promise-based Nuxt, pg, S3, fetch, WebSocket, and filesystem APIs. */\nimport type { AuthoringCatalog } from '@internal/protocol/Configuration'\nimport { AuthoringCatalog as AuthoringCatalogSchema } from '@internal/protocol/Configuration'\nimport { CMS_READINESS_PATH, STUDIO_API_PATH, STUDIO_COLLABORATION_PATH } from '@internal/protocol/HttpPaths'\nimport { NodeCrypto, NodeFileSystem, NodePath } from '@effect/platform-node-shared'\nimport {\n DeleteObjectCommand,\n HeadBucketCommand,\n ListObjectsV2Command,\n PutObjectCommand,\n S3Client,\n} from '@aws-sdk/client-s3'\nimport { loadNuxt, loadNuxtConfig } from '@nuxt/kit'\nimport { setupDotenv } from 'c12'\nimport { Effect, Layer, References, Result, Schema } from 'effect'\nimport { Pool } from 'pg'\nimport { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { randomUUID } from 'node:crypto'\nimport { resolve } from 'node:path'\nimport { createCmsContentClient, readCmsContentDirectory } from '../Content'\nimport { postgresMigrations } from '@internal/sql-pg/Migration'\nimport { reconcileLocalAdministrator } from '@internal/auth/LocalDevelopment'\nimport { loadCmsConfiguration } from './cms-config'\nimport {\n cmsRuntimeConfigurationDefaults,\n cmsRuntimeConfigurationFromEnvironment,\n compileCmsConfiguration,\n resolveCmsInstallation,\n} from './configuration'\nimport { installCms, scopedDatabaseUrl } from '../runtime/installation'\nimport type { NuxtCmsInstallationOptions } from '../runtime/installation'\n\nexport type CmsDoctorStatus = 'pass' | 'fail' | 'not-verified'\n\nexport interface CmsDoctorCheck {\n readonly id: string\n readonly label: string\n readonly phase: string\n readonly status: CmsDoctorStatus\n readonly detail?: string\n}\n\nexport interface CmsDoctorReport {\n readonly ok: boolean\n readonly checks: ReadonlyArray<CmsDoctorCheck>\n}\n\nexport interface CmsBootstrapOptions {\n readonly content?: string\n readonly email: string\n readonly name: string\n readonly password: string\n readonly publish: boolean\n readonly rootDir: string\n readonly envFile?: string\n readonly verbose?: boolean\n}\n\nexport interface CmsBootstrapReport {\n readonly administrator: 'created' | 'updated' | 'verified'\n readonly contentApplied: boolean\n}\n\nexport interface CmsResetOptions {\n readonly bootstrap?: Omit<CmsBootstrapOptions, 'rootDir'>\n readonly database: boolean\n readonly media: boolean\n readonly rootDir: string\n readonly envFile?: string\n readonly yes: boolean\n readonly verbose?: boolean\n}\n\nexport interface CmsResetReport {\n readonly executed: boolean\n readonly targets: ReadonlyArray<string>\n readonly bootstrapped: boolean\n}\n\nconst nodeLayer = Layer.merge(NodeCrypto.layer, Layer.merge(NodeFileSystem.layer, NodePath.layer))\n\nconst InitializationStatus = Schema.Struct({ needsAdministrator: Schema.optionalKey(Schema.Boolean) })\n\nconst CauseCarrier = Schema.Struct({ cause: Schema.Unknown })\n\nclass CmsLifecycleFailed extends Schema.TaggedError<CmsLifecycleFailed>()('CmsLifecycleFailed', {\n cause: Schema.Defect(),\n message: Schema.String,\n phase: Schema.String,\n}) {}\n\nconst isCmsLifecycleFailed = Schema.is(CmsLifecycleFailed)\n\nexport async function doctorCmsDevelopment(rootDir: string, full = false, envFile?: string): Promise<CmsDoctorReport> {\n const checks: CmsDoctorCheck[] = []\n let configuration: NuxtCmsInstallationOptions\n\n try {\n const project = await loadConfiguration(rootDir, envFile)\n compileCmsConfiguration(project.authored.configuration)\n configuration = resolveCmsInstallation(project.authored.configuration, project.runtime, {\n revision: 'doctor',\n components: [],\n })\n checks.push(pass('configuration', 'Configuration loaded'))\n } catch (cause) {\n checks.push(fail('configuration', 'Configuration loaded', message(cause)))\n\n return report(checks)\n }\n\n const pool = new Pool({ connectionString: configuration.database.url })\n\n try {\n await pool.query('select 1')\n checks.push(pass('postgres', 'PostgreSQL reachable'))\n\n try {\n const pending = await verifyMigrations(pool, configuration.database.schema)\n checks.push(\n pending === 0\n ? pass('migrations', 'Database schema current')\n : fail(\n 'migrations',\n 'Database schema current',\n `${pending} migration${pending === 1 ? ' is' : 's are'} pending; run cms dev bootstrap.`,\n ),\n )\n } catch (cause) {\n checks.push(fail('migrations', 'Database schema current', message(cause)))\n }\n\n if (full) {\n await pool.query('begin')\n\n try {\n await pool.query(\n `create table \"${configuration.database.schema}\".\"__cms_doctor_${randomUUID().replaceAll('-', '')}\" (id integer)`,\n )\n checks.push(pass('postgres-write', 'PostgreSQL write access'))\n } finally {\n await pool.query('rollback')\n }\n } else {\n checks.push(notVerified('postgres-write', 'PostgreSQL write access', 'Use --full for a transient write check.'))\n }\n } catch (cause) {\n checks.push(fail('postgres', 'PostgreSQL reachable', message(cause)))\n } finally {\n await pool.end()\n }\n\n if (configuration.media === undefined) {\n checks.push(pass('s3', 'Media storage disabled'))\n } else {\n const storage = configuration.media\n const client = s3Client(storage)\n let publicProbeKey: string | undefined\n\n try {\n await client.send(new HeadBucketCommand({ Bucket: storage.bucket }))\n checks.push(pass('s3', 'S3 bucket reachable'))\n\n if (full) {\n const relativeKey = `.doctor/${randomUUID()}`\n const key = `${storage.prefix}${relativeKey}`\n await client.send(new PutObjectCommand({ Bucket: storage.bucket, Key: key, Body: new Uint8Array() }))\n publicProbeKey = key\n checks.push(pass('s3-write', 'S3 write access'))\n } else {\n checks.push(notVerified('s3-write', 'S3 write access', 'Use --full for a transient write check.'))\n }\n } catch (cause) {\n checks.push(fail('s3', 'S3 bucket reachable', message(cause)))\n }\n\n try {\n if (full && !publicProbeKey) {\n checks.push(notVerified('media-url', 'Public media URL reachable', 'The transient S3 upload failed.'))\n } else {\n const url = publicProbeKey\n ? publicObjectUrl(storage.publicBaseUrl, publicProbeKey.slice(storage.prefix.length))\n : new URL(storage.publicBaseUrl)\n\n const response = await fetch(url, { method: 'HEAD' })\n checks.push(\n response.ok || (!full && response.status === 404)\n ? pass('media-url', 'Public media URL reachable')\n : fail('media-url', 'Public media URL reachable', `${url.href} returned HTTP ${response.status}.`),\n )\n }\n } catch (cause) {\n checks.push(fail('media-url', 'Public media URL reachable', message(cause)))\n } finally {\n if (publicProbeKey)\n try {\n await client.send(new DeleteObjectCommand({ Bucket: storage.bucket, Key: publicProbeKey }))\n } catch (cause) {\n checks.push(fail('s3-cleanup', 'S3 doctor cleanup', message(cause)))\n }\n\n client.destroy()\n }\n }\n\n const bundledStudio = new URL('../studio/host.js', import.meta.url)\n const publishedStudio = new URL('../../studio/host.js', import.meta.url)\n const workspaceStudio = new URL('../../../../apps/studio/dist/host.js', import.meta.url)\n checks.push(\n existsSync(bundledStudio) || existsSync(publishedStudio) || existsSync(workspaceStudio)\n ? pass('assets', 'CMS and Studio package assets complete')\n : fail('assets', 'CMS and Studio package assets complete', 'Run the package build before publishing.'),\n )\n\n try {\n const readiness = await fetch(new URL(CMS_READINESS_PATH, configuration.baseUrl), {\n signal: AbortSignal.timeout(2_000),\n })\n\n checks.push(\n readiness.ok\n ? pass('server', 'Running server readiness')\n : fail('server', 'Running server readiness', `Returned HTTP ${readiness.status}.`),\n )\n\n if (readiness.ok) {\n try {\n await probeWebSocket(new URL(STUDIO_COLLABORATION_PATH, configuration.baseUrl))\n checks.push(pass('websocket', 'Running server WebSocket support'))\n } catch (cause) {\n checks.push(fail('websocket', 'Running server WebSocket support', message(cause)))\n }\n } else {\n checks.push(notVerified('websocket', 'Running server WebSocket support', 'Readiness did not succeed.'))\n }\n } catch {\n checks.push(notVerified('server', 'Running server readiness', 'Start Nuxt to verify the readiness endpoint.'))\n checks.push(notVerified('websocket', 'Running server WebSocket support', 'Start Nuxt to verify WebSockets.'))\n }\n\n return report(checks)\n}\n\nexport async function bootstrapCmsDevelopment(options: CmsBootstrapOptions): Promise<CmsBootstrapReport> {\n if (!options.email || !options.password) throw new Error('CMS_EMAIL and CMS_PASSWORD are required for bootstrap.')\n const project = await inPhase('bootstrap.configuration', () => loadConfiguration(options.rootDir, options.envFile))\n const authoring = await inPhase('bootstrap.authoring', () => prepareAuthoring(options.rootDir, options.verbose))\n\n const resolved = inPhaseSync('bootstrap.configuration', () =>\n resolveCmsInstallation(project.authored.configuration, project.runtime, authoring),\n )\n\n const installation = await inPhase('bootstrap.installation', () =>\n Effect.runPromise(\n installCms(resolved).pipe(Effect.provideService(References.MinimumLogLevel, options.verbose ? 'Info' : 'None')),\n ),\n )\n\n const localFetch: typeof globalThis.fetch = (input, init) => {\n const request = input instanceof Request ? new Request(input, init) : new Request(input, init)\n const headers = new Headers(request.headers)\n headers.set('x-forwarded-for', '127.0.0.1')\n\n return installation.fetch(new Request(request, { headers }))\n }\n\n try {\n const status = await inPhase('bootstrap.initialization', () =>\n localFetch(new URL(`${STUDIO_API_PATH}/initialization`, resolved.baseUrl)),\n )\n\n const state = await inPhase('bootstrap.initialization', async () =>\n Result.getOrThrow(Schema.decodeUnknownResult(InitializationStatus)(await status.json())),\n )\n\n let initialized = false\n\n if (state.needsAdministrator) {\n const claimed = await inPhase('bootstrap.initialization', () =>\n localFetch(new URL(`${STUDIO_API_PATH}/initialization`, resolved.baseUrl), {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n email: options.email,\n initializationToken: resolved.initializationToken,\n name: options.name,\n password: options.password,\n }),\n }),\n )\n\n if (!claimed.ok)\n throw new CmsLifecycleFailed({\n cause: new Error(`Administrator initialization failed (${claimed.status}).`),\n message: `Administrator initialization failed (${claimed.status}).`,\n phase: 'bootstrap.initialization',\n })\n initialized = true\n }\n\n const administrator = initialized\n ? 'created'\n : await inPhase('bootstrap.administrator', () =>\n reconcileAdministrator(resolved, {\n email: options.email,\n name: options.name,\n password: options.password,\n }),\n )\n\n const content = createCmsContentClient({\n baseUrl: resolved.baseUrl,\n credentials: { email: options.email, password: options.password },\n fetch: localFetch,\n })\n\n if (!options.content) {\n await inPhase('bootstrap.content', () => content.diff({ sources: [] }))\n\n return { administrator, contentApplied: false }\n }\n\n const contentDirectory = options.content\n const source = await inPhase('bootstrap.content', () => readCmsContentDirectory(contentDirectory))\n\n const plan = await inPhase('bootstrap.content', () =>\n content.plan(source, { overwrite: true, publish: options.publish }),\n )\n\n if (!plan.valid) {\n const details = [\n ...plan.conflicts.map((entry) => `${entry.sourcePath}: conflicts with the current CMS content`),\n ...plan.issues.map(\n (issue) =>\n `${issue.sourcePath ?? issue.key ?? 'content'}${issue.field ? ` (${issue.field})` : ''}: ${issue.message}`,\n ),\n ]\n\n throw new CmsLifecycleFailed({\n cause: new Error(`Bootstrap content has conflicts or validation errors. ${details.join(' ')}`),\n message: `Bootstrap content has conflicts or validation errors. ${details.join(' ')}`,\n phase: 'bootstrap.content',\n })\n }\n\n await inPhase('bootstrap.content', () => content.apply(plan))\n\n return { administrator, contentApplied: true }\n } finally {\n await installation.close()\n }\n}\n\nasync function reconcileAdministrator(\n configuration: NuxtCmsInstallationOptions,\n administrator: Pick<CmsBootstrapOptions, 'email' | 'name' | 'password'>,\n): Promise<CmsBootstrapReport['administrator']> {\n const pool = new Pool({ connectionString: scopedDatabaseUrl(configuration.database) })\n\n try {\n return await Effect.runPromise(\n reconcileLocalAdministrator({\n baseUrl: configuration.baseUrl,\n database: pool,\n email: administrator.email,\n name: administrator.name,\n password: administrator.password,\n secret: `cms-authentication:${configuration.secret}`,\n }),\n )\n } finally {\n await pool.end()\n }\n}\n\nexport async function resetCmsDevelopment(options: CmsResetOptions): Promise<CmsResetReport> {\n const project = await inPhase('reset.configuration', () => loadConfiguration(options.rootDir, options.envFile))\n\n const configuration = inPhaseSync('reset.configuration', () =>\n resolveCmsInstallation(project.authored.configuration, project.runtime, {\n revision: 'reset',\n components: [],\n }),\n )\n\n const targets = [\n ...(options.database ? [`PostgreSQL schema ${configuration.database.schema}`] : []),\n ...(options.media && configuration.media !== undefined\n ? [`S3 prefix ${configuration.media.bucket}/${configuration.media.prefix}`]\n : []),\n ]\n\n if (!options.yes) return { executed: false, targets, bootstrapped: false }\n await inPhase('reset.safety', () => refuseRunningInstallation(configuration.baseUrl))\n\n if (options.database) await inPhase('reset.database', () => resetDatabase(configuration.database))\n\n const media = configuration.media\n\n if (options.media && media !== undefined) await inPhase('reset.media', () => resetMedia(media))\n\n if (options.bootstrap)\n await bootstrapCmsDevelopment({\n rootDir: options.rootDir,\n envFile: options.envFile,\n verbose: options.verbose,\n ...options.bootstrap,\n })\n\n return { executed: true, targets, bootstrapped: options.bootstrap !== undefined }\n}\n\nexport async function loadCmsProjectEnvironment(rootDir: string, envFile?: string): Promise<void> {\n await setupDotenv({ cwd: resolve(rootDir), fileName: envFile ? ['.env', envFile] : '.env' })\n}\n\nasync function loadConfiguration(rootDir: string, envFile?: string) {\n const absoluteRoot = resolve(rootDir)\n await loadCmsProjectEnvironment(absoluteRoot, envFile)\n const authored = await Effect.runPromise(loadCmsConfiguration(absoluteRoot).pipe(Effect.provide(nodeLayer)))\n const nuxt = await loadNuxtConfig({ cwd: absoluteRoot, dotenv: false })\n const defaults = cmsRuntimeConfigurationDefaults(authored.configuration, nuxt.runtimeConfig.cms)\n const runtime = await Effect.runPromise(cmsRuntimeConfigurationFromEnvironment(defaults))\n\n return { authored, runtime }\n}\n\nasync function prepareAuthoring(rootDir: string, verbose = false): Promise<AuthoringCatalog> {\n const nuxt = await loadNuxt({\n cwd: rootDir,\n dev: true,\n ready: true,\n overrides: {\n logLevel: verbose ? 'verbose' : 'silent',\n ...(verbose ? undefined : { devtools: { enabled: false }, seo: { metaDataFiles: false } }),\n },\n })\n\n try {\n const source = (await readFile(resolve(nuxt.options.buildDir, 'cms/authoring.mjs'), 'utf8'))\n .replace(/^export default /u, '')\n .trim()\n\n return Result.getOrThrow(Schema.decodeUnknownResult(AuthoringCatalogSchema)(JSON.parse(source)))\n } finally {\n await nuxt.close()\n }\n}\n\nasync function refuseRunningInstallation(baseUrl: string): Promise<void> {\n try {\n await fetch(new URL(CMS_READINESS_PATH, baseUrl), { signal: AbortSignal.timeout(1_000) })\n throw new Error('Refusing to reset while the CMS server is running.')\n } catch (cause) {\n if (cause instanceof Error && cause.message.startsWith('Refusing')) throw cause\n }\n}\n\nasync function verifyMigrations(pool: Pool, schema: string): Promise<number> {\n const ledger = await pool.query<{ exists: boolean }>(\n 'select exists(select 1 from information_schema.tables where table_schema = $1 and table_name = $2) as exists',\n [schema, '__drizzle_migrations'],\n )\n\n const applied = ledger.rows[0]?.exists\n ? (\n await pool.query<{ createdAt: string; hash: string }>(\n `select created_at as \"createdAt\", hash from \"${schema}\".\"__drizzle_migrations\" order by created_at`,\n )\n ).rows\n : []\n\n const matches = applied.every(\n (migration, index) =>\n migration.hash === postgresMigrations[index]?.hash &&\n Number(migration.createdAt) === postgresMigrations[index]?.createdAt,\n )\n\n if (!matches || applied.length > postgresMigrations.length)\n throw new Error('The applied migration history does not match this CMS release.')\n\n const pending = postgresMigrations.slice(applied.length)\n const connection = await pool.connect()\n\n try {\n await connection.query('begin')\n await connection.query(`create schema if not exists \"${schema}\"`)\n await connection.query(`set local search_path to \"${schema}\"`)\n\n for (const migration of pending) for (const statement of migration.statements) await connection.query(statement)\n } finally {\n await connection.query('rollback')\n connection.release()\n }\n\n return pending.length\n}\n\nfunction publicObjectUrl(baseUrl: string, key: string): URL {\n const base = new URL(baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`)\n\n return new URL(key.split('/').map(encodeURIComponent).join('/'), base)\n}\n\nasync function probeWebSocket(httpUrl: URL): Promise<void> {\n const url = new URL(httpUrl)\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'\n\n await new Promise<void>((resolve, reject) => {\n const socket = new WebSocket(url)\n\n const timeout = setTimeout(() => {\n socket.close()\n reject(new Error('The WebSocket handshake timed out.'))\n }, 2_000)\n\n socket.addEventListener('open', () => {\n clearTimeout(timeout)\n socket.close()\n resolve()\n })\n socket.addEventListener('error', () => {\n clearTimeout(timeout)\n reject(new Error(`Could not open ${url.href}.`))\n })\n })\n}\n\nasync function resetDatabase(database: NuxtCmsInstallationOptions['database']): Promise<void> {\n const pool = new Pool({ connectionString: database.url })\n\n try {\n const client = await pool.connect()\n\n try {\n await client.query('select pg_advisory_lock(hashtextextended($1, 0))', ['cms:development-reset:v1'])\n await client.query(`drop schema if exists \"${database.schema}\" cascade`)\n await client.query(`create schema \"${database.schema}\"`)\n } finally {\n client.release()\n }\n } finally {\n await pool.end()\n }\n}\n\nasync function resetMedia(storage: NonNullable<NuxtCmsInstallationOptions['media']>): Promise<void> {\n const client = s3Client(storage)\n\n try {\n let continuationToken: string | undefined\n\n do {\n const page = await client.send(\n new ListObjectsV2Command({\n Bucket: storage.bucket,\n Prefix: storage.prefix,\n ContinuationToken: continuationToken,\n }),\n )\n\n for (const object of page.Contents ?? [])\n if (object.Key) await client.send(new DeleteObjectCommand({ Bucket: storage.bucket, Key: object.Key }))\n continuationToken = page.IsTruncated ? page.NextContinuationToken : undefined\n } while (continuationToken)\n } finally {\n client.destroy()\n }\n}\n\nfunction s3Client(storage: NonNullable<NuxtCmsInstallationOptions['media']>): S3Client {\n return new S3Client({\n region: storage.region,\n endpoint: storage.endpoint,\n forcePathStyle: storage.forcePathStyle,\n credentials: storage.credentials,\n })\n}\n\nfunction pass(id: string, label: string): CmsDoctorCheck {\n return { id, label, phase: `doctor.${id}`, status: 'pass' }\n}\n\nfunction fail(id: string, label: string, detail: string): CmsDoctorCheck {\n return { id, label, phase: `doctor.${id}`, status: 'fail', detail }\n}\n\nfunction notVerified(id: string, label: string, detail: string): CmsDoctorCheck {\n return { id, label, phase: `doctor.${id}`, status: 'not-verified', detail }\n}\n\nfunction report(checks: ReadonlyArray<CmsDoctorCheck>): CmsDoctorReport {\n return { ok: checks.every((check) => check.status !== 'fail'), checks }\n}\n\nfunction message(cause: unknown): string {\n if (cause instanceof Error && cause.message) return cause.message\n\n if (Schema.is(CauseCarrier)(cause)) return message(cause.cause)\n\n return String(cause)\n}\n\nasync function inPhase<Value>(phase: string, operation: () => PromiseLike<Value>): Promise<Value> {\n try {\n return await operation()\n } catch (cause) {\n if (isCmsLifecycleFailed(cause)) throw cause\n throw new CmsLifecycleFailed({ cause, message: message(cause), phase })\n }\n}\n\nfunction inPhaseSync<Value>(phase: string, operation: () => Value): Value {\n try {\n return operation()\n } catch (cause) {\n if (isCmsLifecycleFailed(cause)) throw cause\n throw new CmsLifecycleFailed({ cause, message: message(cause), phase })\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { a as EditorNodeId, c as RevisionId, d as SourcePath, i as DocumentVersion, r as DocumentId, t as DocumentGeneration } from "./scalars-B2lgGUnj.js";
|
|
2
|
-
import { $ as StudioActor, A as UnpublishDocumentInput, B as SeoMediaUnavailable, D as RemoveDocumentInput, Et as RequestId, H as SeoRevision, J as AccessDenied, K as SeoVersionConflict, O as RestoreDocumentInput, Q as Role, S as PublishDocumentInput, Y as AuthenticationRequired, _t as MediaReference, a as DOCUMENT_REVISION_ACTIONS, at as MediaCleanupReport, b as MarkdownNode, bt as MediaTooLarge, ct as MediaFolder, dt as MediaInvalid, et as StudioEntryDenied, ft as MediaName, ht as MediaPage, it as MediaByteSize, j as UpdateDocumentInput, k as UndeleteDocumentInput, l as DocumentMutationResult, lt as MediaId, m as DocumentSource, mt as MediaObjectKey, n as CmsMarkdownDocument, nt as ImageMimeType, o as DeletedDocument, ot as MediaConflict, p as DocumentRevisionAction, pt as MediaNotFound, rt as MediaAsset, st as MediaCursor, tt as StudioRequestContext, ut as MediaIntegrityReport, vt as MediaReferenced, x as MoveDocumentInput, xt as MediaUpload, y as DuplicateDocumentInput, yt as MediaStatus, z as SeoConfirmationRequired } from "./models-
|
|
3
|
-
import { $ as DocumentRevision, A as StudioBadRequest, B as User, C as DocumentStore, D as CurrentStudioRequest, E as defaultAccessControlLayer, F as studioInternalError, G as UserSelfRemovalDenied, H as UserAlreadyExists, I as InitializationAlreadyCompleted, J as CollaborationServerMessage, K as UserSelfRoleChangeDenied, L as InitializationProofInvalid, M as StudioRequestConflict, N as StudioSchemaError, O as StudioApi, P as StudioInternalError, Q as DocumentHistoryInvalidCursor, R as InitializationState, S as DocumentPersistenceError, T as AccessControl, U as UserNotFound, V as UserAdministrationDenied, W as UserPage, X as StateVector, Y as CollaborationTicket, Z as DocumentHistoryComparisonTooLarge, _ as Documents, a as mediaObjectPrefix, at as ActivityEntry, b as cursorCodec, c as Seo, ct as ActivityPage, d as seoDeliveryLayer, dt as DocumentMediaUnavailable, et as ACTIVITY_ACTIONS, f as seoLayer, ft as DocumentNotFound, g as DocumentPreviews, gt as PublishedDocumentNotFound, h as DocumentMaintenance, ht as DocumentVersionConflict, i as MediaObjectStore, it as ActivityCursorInvalid, k as StudioAuthentication, l as SeoDelivery, lt as ActivityTarget, m as SeoStore, mt as DocumentValidationFailed, n as s3MediaObjectStoreLayer, nt as ActivityContext, o as PreviewSeo, ot as ActivityEntryDraft, p as SeoPersistenceError, pt as DocumentPathConflict, q as CollaborationClientMessage, r as MediaPersistenceError, rt as ActivityCursor, s as PublishedSeo, st as ActivityId, tt as ActivityAction, u as makeDefaultSeoOptions, ut as ActivityTargetKind, v as PublishedDocuments, w as renderEditorMarkdown, x as DocumentGenerationConflict, y as documentsLayer, z as CreateUserInput } from "./S3MediaObjects-
|
|
4
|
-
import { o as ContentTransferConflict } from "./ContentTransfer-
|
|
2
|
+
import { $ as StudioActor, A as UnpublishDocumentInput, B as SeoMediaUnavailable, D as RemoveDocumentInput, Et as RequestId, H as SeoRevision, J as AccessDenied, K as SeoVersionConflict, O as RestoreDocumentInput, Q as Role, S as PublishDocumentInput, Y as AuthenticationRequired, _t as MediaReference, a as DOCUMENT_REVISION_ACTIONS, at as MediaCleanupReport, b as MarkdownNode, bt as MediaTooLarge, ct as MediaFolder, dt as MediaInvalid, et as StudioEntryDenied, ft as MediaName, ht as MediaPage, it as MediaByteSize, j as UpdateDocumentInput, k as UndeleteDocumentInput, l as DocumentMutationResult, lt as MediaId, m as DocumentSource, mt as MediaObjectKey, n as CmsMarkdownDocument, nt as ImageMimeType, o as DeletedDocument, ot as MediaConflict, p as DocumentRevisionAction, pt as MediaNotFound, rt as MediaAsset, st as MediaCursor, tt as StudioRequestContext, ut as MediaIntegrityReport, vt as MediaReferenced, x as MoveDocumentInput, xt as MediaUpload, y as DuplicateDocumentInput, yt as MediaStatus, z as SeoConfirmationRequired } from "./models-ChRxBChy.js";
|
|
3
|
+
import { $ as DocumentRevision, A as StudioBadRequest, B as User, C as DocumentStore, D as CurrentStudioRequest, E as defaultAccessControlLayer, F as studioInternalError, G as UserSelfRemovalDenied, H as UserAlreadyExists, I as InitializationAlreadyCompleted, J as CollaborationServerMessage, K as UserSelfRoleChangeDenied, L as InitializationProofInvalid, M as StudioRequestConflict, N as StudioSchemaError, O as StudioApi, P as StudioInternalError, Q as DocumentHistoryInvalidCursor, R as InitializationState, S as DocumentPersistenceError, T as AccessControl, U as UserNotFound, V as UserAdministrationDenied, W as UserPage, X as StateVector, Y as CollaborationTicket, Z as DocumentHistoryComparisonTooLarge, _ as Documents, a as mediaObjectPrefix, at as ActivityEntry, b as cursorCodec, c as Seo, ct as ActivityPage, d as seoDeliveryLayer, dt as DocumentMediaUnavailable, et as ACTIVITY_ACTIONS, f as seoLayer, ft as DocumentNotFound, g as DocumentPreviews, gt as PublishedDocumentNotFound, h as DocumentMaintenance, ht as DocumentVersionConflict, i as MediaObjectStore, it as ActivityCursorInvalid, k as StudioAuthentication, l as SeoDelivery, lt as ActivityTarget, m as SeoStore, mt as DocumentValidationFailed, n as s3MediaObjectStoreLayer, nt as ActivityContext, o as PreviewSeo, ot as ActivityEntryDraft, p as SeoPersistenceError, pt as DocumentPathConflict, q as CollaborationClientMessage, r as MediaPersistenceError, rt as ActivityCursor, s as PublishedSeo, st as ActivityId, tt as ActivityAction, u as makeDefaultSeoOptions, ut as ActivityTargetKind, v as PublishedDocuments, w as renderEditorMarkdown, x as DocumentGenerationConflict, y as documentsLayer, z as CreateUserInput } from "./S3MediaObjects-CR3p1WTg.js";
|
|
4
|
+
import { o as ContentTransferConflict } from "./ContentTransfer-BhF9G56s.js";
|
|
5
5
|
import { a as CMS_FORM_SUBMIT_PATH, l as CMS_READINESS_PATH, o as CMS_LIVENESS_PATH, p as STUDIO_COLLABORATION_PATH, t as CMS_AUTHENTICATION_PATH, u as STUDIO_API_PATH } from "./HttpPaths-c9nLZ9H2.js";
|
|
6
|
-
import {
|
|
7
|
-
import { a as encodeCmsEditorComponentAttributes, d as createCmsComarkRenderData, i as validateFormValues, t as documentForms } from "./Forms-
|
|
6
|
+
import { n as FORM_SUBMISSION_MAX_BYTES, o as FormResult } from "./Forms-BbkE7QfC.js";
|
|
7
|
+
import { a as encodeCmsEditorComponentAttributes, d as createCmsComarkRenderData, i as validateFormValues, t as documentForms } from "./Forms-DoB56hfe.js";
|
|
8
8
|
import { a as createEditorNodeId, o as editorNodeId, r as identifiedAttributes, t as assertCanonicalEditorContent } from "./metadata-BEZPWh-3.js";
|
|
9
|
-
import { C as finiteNumberAttribute, S as compactJsonAttributes, _ as comarkTagForEditorMark, b as encodeEditorImageAttributes, g as EDITOR_MARK_TYPES, h as comarkToEditor, u as EditorDocumentInvalid, v as isEditorMark, w as nonEmptyStringAttribute, x as normalizeEditorImageLayout, y as EDITOR_IMAGE_LAYOUT_ATTRIBUTE } from "./Configuration-
|
|
9
|
+
import { C as finiteNumberAttribute, S as compactJsonAttributes, _ as comarkTagForEditorMark, b as encodeEditorImageAttributes, g as EDITOR_MARK_TYPES, h as comarkToEditor, u as EditorDocumentInvalid, v as isEditorMark, w as nonEmptyStringAttribute, x as normalizeEditorImageLayout, y as EDITOR_IMAGE_LAYOUT_ATTRIBUTE } from "./Configuration-BU-UyGoH.js";
|
|
10
10
|
import { Cause, Clock, Context, Crypto, Data, DateTime, Deferred, Effect, Encoding, Exit, Fiber, Layer, Option, Predicate, PubSub, Pull, Queue, Redacted, Ref, Result, Schedule, Schema, Scope, Semaphore, Stream, flow } from "effect";
|
|
11
11
|
import { Extension, Node, getSchema, mergeAttributes } from "@tiptap/core";
|
|
12
12
|
import { prosemirrorJSONToYDoc, ySyncPluginKey, yXmlFragmentToProseMirrorRootNode } from "@tiptap/y-tiptap";
|
|
@@ -4287,6 +4287,10 @@ const startInstallation = Effect.fn("CmsInstallation.start")(function* (options)
|
|
|
4287
4287
|
};
|
|
4288
4288
|
});
|
|
4289
4289
|
|
|
4290
|
+
//#endregion
|
|
4291
|
+
//#region ../server/src/internal/media/media-mutation-fence.ts
|
|
4292
|
+
var MediaMutationFence = class extends Context.Service()("@internal/server/MediaMutationFence") {};
|
|
4293
|
+
|
|
4290
4294
|
//#endregion
|
|
4291
4295
|
//#region ../server/src/internal/media/media-change.ts
|
|
4292
4296
|
const MediaUploadIntent = Schema.Struct({
|
|
@@ -4461,17 +4465,18 @@ function makeMediaChange(input) {
|
|
|
4461
4465
|
const recoveryBatchSize = 100;
|
|
4462
4466
|
function recoverPendingMedia(store, objectStore, operations, recoveryAge, cursor = {}) {
|
|
4463
4467
|
return Effect.gen(function* () {
|
|
4468
|
+
const mutationFence = yield* MediaMutationFence;
|
|
4464
4469
|
const before = DateTime.subtractDuration(yield* DateTime.now, recoveryAge);
|
|
4465
4470
|
const pending = yield* store.pending({
|
|
4466
4471
|
after: cursor.media,
|
|
4467
4472
|
before,
|
|
4468
4473
|
limit: recoveryBatchSize
|
|
4469
4474
|
});
|
|
4470
|
-
for (const record of pending) {
|
|
4475
|
+
for (const record of pending) yield* mutationFence.run(record.id, Effect.gen(function* () {
|
|
4471
4476
|
if (record.status === "deleting") {
|
|
4472
4477
|
yield* objectStore.remove(record.objectKey);
|
|
4473
4478
|
yield* store.finishDelete(record.id);
|
|
4474
|
-
|
|
4479
|
+
return;
|
|
4475
4480
|
}
|
|
4476
4481
|
const stored = yield* objectStore.stat(record.objectKey);
|
|
4477
4482
|
if (Option.isSome(stored) && stored.value.byteSize === record.byteSize && (stored.value.mimeType === void 0 || stored.value.mimeType === record.mimeType)) yield* store.activate(record.id);
|
|
@@ -4479,17 +4484,17 @@ function recoverPendingMedia(store, objectStore, operations, recoveryAge, cursor
|
|
|
4479
4484
|
if (Option.isSome(stored)) {
|
|
4480
4485
|
yield* objectStore.remove(record.objectKey);
|
|
4481
4486
|
const remaining = yield* objectStore.stat(record.objectKey);
|
|
4482
|
-
if (Option.isSome(remaining))
|
|
4487
|
+
if (Option.isSome(remaining)) return;
|
|
4483
4488
|
}
|
|
4484
4489
|
yield* store.abandonUpload(record.id);
|
|
4485
4490
|
}
|
|
4486
|
-
}
|
|
4491
|
+
}));
|
|
4487
4492
|
const replacements = yield* store.pendingReplacements({
|
|
4488
4493
|
after: cursor.replacements,
|
|
4489
4494
|
before,
|
|
4490
4495
|
limit: recoveryBatchSize
|
|
4491
4496
|
});
|
|
4492
|
-
yield* Effect.forEach(replacements, (replacement) => recoverReplacement(store, objectStore, replacement).pipe(Effect.catchTag("Media.Conflict", () => Effect.void)), { discard: true });
|
|
4497
|
+
yield* Effect.forEach(replacements, (replacement) => mutationFence.run(replacement.mediaId, recoverReplacement(store, objectStore, replacement)).pipe(Effect.catchTag("Media.Conflict", () => Effect.void)), { discard: true });
|
|
4493
4498
|
yield* recoverPendingMediaCleanup(operations, objectStore, before);
|
|
4494
4499
|
return {
|
|
4495
4500
|
media: pending.length < recoveryBatchSize ? void 0 : pending.at(-1)?.id,
|
|
@@ -4514,6 +4519,7 @@ function recoverPendingMediaCleanup(operations, objectStore, before) {
|
|
|
4514
4519
|
}
|
|
4515
4520
|
function recoverReplacement(store, objectStore, replacement) {
|
|
4516
4521
|
return Effect.gen(function* () {
|
|
4522
|
+
if ((yield* store.inspectReplacement(replacement)) !== "pending") return;
|
|
4517
4523
|
const staged = yield* objectStore.stat(replacement.stagingObjectKey);
|
|
4518
4524
|
if (Option.isNone(staged)) {
|
|
4519
4525
|
yield* recoverReplacementWithoutStaging(store, objectStore, replacement);
|
|
@@ -4678,6 +4684,7 @@ const makeMediaLibrary = Effect.fn("MediaLibrary.make")(function* (options) {
|
|
|
4678
4684
|
const operations = yield* ChangeJournal;
|
|
4679
4685
|
const documentOperations = yield* DocumentMaintenance;
|
|
4680
4686
|
const crypto = yield* Crypto.Crypto;
|
|
4687
|
+
const mutationFence = yield* MediaMutationFence;
|
|
4681
4688
|
const objectStore = yield* MediaObjectStore;
|
|
4682
4689
|
const store = yield* MediaStore;
|
|
4683
4690
|
const baseUrl = options.publicBaseUrl.replace(/\/+$/gu, "");
|
|
@@ -4791,7 +4798,7 @@ const makeMediaLibrary = Effect.fn("MediaLibrary.make")(function* (options) {
|
|
|
4791
4798
|
mediaId: id
|
|
4792
4799
|
}
|
|
4793
4800
|
});
|
|
4794
|
-
return yield* Effect.scoped(prepareUpload(input).pipe(Effect.flatMap((prepared) => mutations.withPermits(1)(Effect.gen(function* () {
|
|
4801
|
+
return yield* Effect.scoped(prepareUpload(input).pipe(Effect.flatMap((prepared) => mutations.withPermits(1)(mutationFence.run(id, Effect.gen(function* () {
|
|
4795
4802
|
const current = yield* store.find(id);
|
|
4796
4803
|
if (Option.isNone(current)) return yield* new MediaNotFound({ mediaId: id });
|
|
4797
4804
|
if (prepared.mimeType !== current.value.mimeType) return yield* new MediaInvalid({ message: "A media replacement must keep the original image type so existing references remain valid." });
|
|
@@ -4832,7 +4839,7 @@ const makeMediaLibrary = Effect.fn("MediaLibrary.make")(function* (options) {
|
|
|
4832
4839
|
const replaced = toAsset(yield* store.finishReplace(stagedReplacement));
|
|
4833
4840
|
yield* removeStagingBestEffort(objectStore, stagedReplacement.stagingObjectKey);
|
|
4834
4841
|
return replaced;
|
|
4835
|
-
})))));
|
|
4842
|
+
}))))));
|
|
4836
4843
|
});
|
|
4837
4844
|
const remove = Effect.fn("MediaLibrary.remove")(function* (context, id) {
|
|
4838
4845
|
yield* accessControl.require(context, {
|
|
@@ -4842,7 +4849,7 @@ const makeMediaLibrary = Effect.fn("MediaLibrary.make")(function* (options) {
|
|
|
4842
4849
|
mediaId: id
|
|
4843
4850
|
}
|
|
4844
4851
|
});
|
|
4845
|
-
yield* mutations.withPermits(1)(Effect.gen(function* () {
|
|
4852
|
+
yield* mutations.withPermits(1)(mutationFence.run(id, Effect.gen(function* () {
|
|
4846
4853
|
const operationId = ActivityId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie));
|
|
4847
4854
|
const deleting = yield* store.beginDelete(id, {
|
|
4848
4855
|
context,
|
|
@@ -4850,7 +4857,7 @@ const makeMediaLibrary = Effect.fn("MediaLibrary.make")(function* (options) {
|
|
|
4850
4857
|
});
|
|
4851
4858
|
yield* objectStore.remove(deleting.objectKey);
|
|
4852
4859
|
yield* store.finishDelete(id);
|
|
4853
|
-
}));
|
|
4860
|
+
})));
|
|
4854
4861
|
});
|
|
4855
4862
|
const cleanup = Effect.fn("MediaLibrary.cleanup")(function* (context) {
|
|
4856
4863
|
yield* accessControl.require(context, {
|
|
@@ -5275,25 +5282,16 @@ function targetError(operation) {
|
|
|
5275
5282
|
//#endregion
|
|
5276
5283
|
//#region ../server/src/Forms.ts
|
|
5277
5284
|
/** Only the currently published definition can authorize a submission. Never trust client rules. */
|
|
5278
|
-
const submitForm = Effect.fn("Forms.submit")(function* (input, components, handlers) {
|
|
5285
|
+
const submitForm = Effect.fn("Forms.submit")(function* (input, components, handlers, request) {
|
|
5279
5286
|
const document = yield* (yield* PublishedDocuments).read({
|
|
5280
5287
|
kind: "id",
|
|
5281
5288
|
documentId: input.documentId
|
|
5282
5289
|
}).pipe(Effect.orElseSucceed(() => void 0));
|
|
5283
|
-
if (!document) return FormResult.make({
|
|
5284
|
-
status: "unavailable",
|
|
5285
|
-
errors: {}
|
|
5286
|
-
});
|
|
5290
|
+
if (!document) return FormResult.make({ status: "unavailable" });
|
|
5287
5291
|
const form = documentForms(document, components).find((candidate) => JSON.stringify(candidate.nodePath) === JSON.stringify(input.nodePath));
|
|
5288
|
-
if (!form || form.revision !== input.revision) return FormResult.make({
|
|
5289
|
-
status: "stale",
|
|
5290
|
-
errors: {}
|
|
5291
|
-
});
|
|
5292
|
+
if (!form || form.revision !== input.revision) return FormResult.make({ status: "stale" });
|
|
5292
5293
|
const handler = Object.hasOwn(handlers, form.name) ? handlers[form.name] : void 0;
|
|
5293
|
-
if (!handler) return FormResult.make({
|
|
5294
|
-
status: "unavailable",
|
|
5295
|
-
errors: {}
|
|
5296
|
-
});
|
|
5294
|
+
if (!handler) return FormResult.make({ status: "unavailable" });
|
|
5297
5295
|
const fields = form.steps.flatMap((step) => step.fields);
|
|
5298
5296
|
const errors = validateFormValues(fields, input.values);
|
|
5299
5297
|
if (Object.keys(input.values).some((id) => !fields.some((field) => field.id === id))) errors._form = "The submission contains unknown answers.";
|
|
@@ -5302,17 +5300,32 @@ const submitForm = Effect.fn("Forms.submit")(function* (input, components, handl
|
|
|
5302
5300
|
errors
|
|
5303
5301
|
});
|
|
5304
5302
|
const values = Object.fromEntries(fields.map((field) => [field.id, normalizedAnswer(Object.hasOwn(input.values, field.id) ? input.values[field.id] : void 0)]));
|
|
5303
|
+
const startedAt = yield* Clock.currentTimeMillis;
|
|
5305
5304
|
return yield* Effect.tryPromise(() => Promise.resolve(handler({
|
|
5306
5305
|
form,
|
|
5306
|
+
request,
|
|
5307
5307
|
values
|
|
5308
|
-
}))).pipe(Effect.
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
})));
|
|
5308
|
+
}))).pipe(Effect.map((outcome) => formResult(outcome, fields)), Effect.tapError((cause) => Clock.currentTimeMillis.pipe(Effect.flatMap((finishedAt) => Effect.logError("CMS form submission handler failed.", cause).pipe(Effect.annotateLogs({
|
|
5309
|
+
documentId: String(form.documentId),
|
|
5310
|
+
durationMillis: Math.max(0, finishedAt - startedAt),
|
|
5311
|
+
form: form.name,
|
|
5312
|
+
requestId: request.id
|
|
5313
|
+
}))))), Effect.orElseSucceed(() => FormResult.make({ status: "failed" })));
|
|
5315
5314
|
});
|
|
5315
|
+
function formResult(outcome, fields) {
|
|
5316
|
+
if (outcome.status === "accepted") return FormResult.make({
|
|
5317
|
+
status: "accepted",
|
|
5318
|
+
...outcome.reference ? { reference: outcome.reference } : void 0
|
|
5319
|
+
});
|
|
5320
|
+
if (outcome.status === "unavailable") return FormResult.make({ status: "unavailable" });
|
|
5321
|
+
const fieldIds = new Set(fields.map((field) => field.id));
|
|
5322
|
+
const errors = Object.fromEntries(Object.entries(outcome.errors).filter(([field]) => field === "_form" || fieldIds.has(field)));
|
|
5323
|
+
if (Object.keys(outcome.errors).some((field) => field !== "_form" && !fieldIds.has(field)) && !errors._form) errors._form = "The submission could not be accepted.";
|
|
5324
|
+
return FormResult.make({
|
|
5325
|
+
status: "invalid",
|
|
5326
|
+
errors
|
|
5327
|
+
});
|
|
5328
|
+
}
|
|
5316
5329
|
function normalizedAnswer(value) {
|
|
5317
5330
|
return value === void 0 || Predicate.isString(value) && !value.trim() ? null : value;
|
|
5318
5331
|
}
|
|
@@ -5328,12 +5341,18 @@ function formsApiLayer(components, handlers) {
|
|
|
5328
5341
|
limit: 60,
|
|
5329
5342
|
window: "1 minute",
|
|
5330
5343
|
onExceeded: "fail"
|
|
5331
|
-
}).pipe(Effect.andThen(
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5344
|
+
}).pipe(Effect.andThen(Effect.gen(function* () {
|
|
5345
|
+
const request = {
|
|
5346
|
+
id: requestId(),
|
|
5347
|
+
submittedAt: DateTime.toDate(DateTime.makeUnsafe(yield* Clock.currentTimeMillis))
|
|
5348
|
+
};
|
|
5349
|
+
return yield* submitForm(payload, components, handlers, request);
|
|
5350
|
+
}).pipe(Effect.provideService(PublishedDocuments, documents))), Effect.orElseSucceed(() => FormResult.make({ status: "unavailable" }))));
|
|
5335
5351
|
})).pipe(Layer.provide(RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))));
|
|
5336
5352
|
}
|
|
5353
|
+
function requestId() {
|
|
5354
|
+
return globalThis.crypto.randomUUID();
|
|
5355
|
+
}
|
|
5337
5356
|
|
|
5338
5357
|
//#endregion
|
|
5339
5358
|
//#region ../platform-node/src/internal/http/errors.ts
|
|
@@ -7353,6 +7372,14 @@ function persistenceFailure$2(operation, cause) {
|
|
|
7353
7372
|
return Effect.fail(mediaPersistenceError(operation, cause));
|
|
7354
7373
|
}
|
|
7355
7374
|
|
|
7375
|
+
//#endregion
|
|
7376
|
+
//#region ../sql-pg/src/internal/media/media-mutation-fence.ts
|
|
7377
|
+
const LOCK_NAMESPACE$1 = "cms:media-mutation:v1:";
|
|
7378
|
+
const postgresMediaMutationFenceLayer = Layer.effect(MediaMutationFence, PostgresAdvisoryLock.pipe(Effect.map((locks) => MediaMutationFence.of({ run: (mediaId, effect) => locks.run(`${LOCK_NAMESPACE$1}${mediaId}`, () => effect).pipe(Effect.catchTag("PostgresAdvisoryLock.Unavailable", (cause) => Effect.fail(new MediaPersistenceError({
|
|
7379
|
+
cause,
|
|
7380
|
+
operation: "MediaMutationFence.Postgres.run"
|
|
7381
|
+
})))) }))));
|
|
7382
|
+
|
|
7356
7383
|
//#endregion
|
|
7357
7384
|
//#region ../sql-pg/src/internal/seo/seo-store.ts
|
|
7358
7385
|
const SeoStoreDomainError = Schema.Union([
|
|
@@ -8180,7 +8207,7 @@ function postgresLayer(options) {
|
|
|
8180
8207
|
const database = schemaClientLayer(clientOptions, schema);
|
|
8181
8208
|
const migrations = cmsDatabaseMigrationLayer(schema).pipe(Layer.provide(database));
|
|
8182
8209
|
const locks = postgresAdvisoryLockLayer(poolOptions);
|
|
8183
|
-
return Layer.mergeAll(postgresActivityStoreLayer, changeJournalLayer, documentStoreLayer, mediaStoreLayer, seoStoreLayer, initializationStoreLayer.pipe(Layer.provide(locks)), postgresUserCommandFenceLayer.pipe(Layer.provide(locks)), postgresWorkingDocumentChangesLayer(poolOptions), workingDocumentStoreLayer).pipe(Layer.provide(migrations), Layer.provide(database));
|
|
8210
|
+
return Layer.mergeAll(postgresActivityStoreLayer, changeJournalLayer, documentStoreLayer, mediaStoreLayer, postgresMediaMutationFenceLayer.pipe(Layer.provide(locks)), seoStoreLayer, initializationStoreLayer.pipe(Layer.provide(locks)), postgresUserCommandFenceLayer.pipe(Layer.provide(locks)), postgresWorkingDocumentChangesLayer(poolOptions), workingDocumentStoreLayer).pipe(Layer.provide(migrations), Layer.provide(database));
|
|
8184
8211
|
}
|
|
8185
8212
|
|
|
8186
8213
|
//#endregion
|
|
@@ -8259,4 +8286,4 @@ function scopedDatabaseUrl(database) {
|
|
|
8259
8286
|
|
|
8260
8287
|
//#endregion
|
|
8261
8288
|
export { embeddedMigrations as a, createCmsBetterAuth as i, scopedDatabaseUrl as n, toS3MediaObjectStoreOptions as r, installCms as t };
|
|
8262
|
-
//# sourceMappingURL=installation-
|
|
8289
|
+
//# sourceMappingURL=installation-fZtNxtoW.js.map
|