@phtngyn/cms 0.1.0-beta.5 → 0.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +114 -41
  3. package/package.json +13 -1
  4. package/src/ApplicationTypes.d.ts +84 -0
  5. package/src/ApplicationTypes.js +1 -0
  6. package/src/{Configuration-CDMYfTre.js → Configuration-BU-UyGoH.js} +4 -4
  7. package/src/{Configuration-CDMYfTre.js.map → Configuration-BU-UyGoH.js.map} +1 -1
  8. package/src/Configuration.d.ts +43 -21
  9. package/src/Configuration.js.map +1 -1
  10. package/src/Content.d.ts +67 -0
  11. package/src/Content.js +291 -0
  12. package/src/Content.js.map +1 -0
  13. package/src/{ContentTransfer-C3Av9sWz.js → ContentTransfer-BhF9G56s.js} +8 -4
  14. package/src/ContentTransfer-BhF9G56s.js.map +1 -0
  15. package/src/ContentTransfer-CRQet3QJ.d.ts +48 -0
  16. package/src/{DocumentEngine-J7g-emdf.js → DocumentEngine-ClhFXW9M.js} +4 -4
  17. package/src/{DocumentEngine-J7g-emdf.js.map → DocumentEngine-ClhFXW9M.js.map} +1 -1
  18. package/src/DocumentModel.d.ts +14 -2
  19. package/src/DocumentModel.js +32 -4
  20. package/src/DocumentModel.js.map +1 -1
  21. package/src/{Forms-CfcI3tPU.js → Forms-BbkE7QfC.js} +47 -16
  22. package/src/Forms-BbkE7QfC.js.map +1 -0
  23. package/src/{Forms-Dj6NuW66.js → Forms-DoB56hfe.js} +24 -7
  24. package/src/Forms-DoB56hfe.js.map +1 -0
  25. package/src/{Forms-BsJMev5_.d.ts → Forms-R0HoTR-o.d.ts} +31 -13
  26. package/src/Forms.d.ts +23 -11
  27. package/src/Forms.js.map +1 -1
  28. package/src/I18n-zbqpWxki.d.ts +29 -0
  29. package/src/I18n.d.ts +2 -20
  30. package/src/Module.js +18 -7
  31. package/src/Module.js.map +1 -1
  32. package/src/{S3MediaObjects-CpPSzJto.js → S3MediaObjects-D5Ns4FM6.js} +61 -40
  33. package/src/S3MediaObjects-D5Ns4FM6.js.map +1 -0
  34. package/src/cli/content.js +63 -221
  35. package/src/cli/content.js.map +1 -1
  36. package/src/cli.js +120 -5
  37. package/src/cli.js.map +1 -1
  38. package/src/{connection-CBAy2qGy.js → connection-D5S9Iph-.js} +2 -2
  39. package/src/{connection-CBAy2qGy.js.map → connection-D5S9Iph-.js.map} +1 -1
  40. package/src/dev-lifecycle-CZ7iCzG9.js +515 -0
  41. package/src/dev-lifecycle-CZ7iCzG9.js.map +1 -0
  42. package/src/{installation-CNfIriVm.js → installation-BNuoRDOz.js} +601 -468
  43. package/src/installation-BNuoRDOz.js.map +1 -0
  44. package/src/internal/application-types.js +43 -0
  45. package/src/internal/application-types.js.map +1 -0
  46. package/src/internal/authoring-catalog.js +9 -4
  47. package/src/internal/authoring-catalog.js.map +1 -1
  48. package/src/internal/authoring-metadata.js +1 -1
  49. package/src/internal/configuration.js +149 -46
  50. package/src/internal/configuration.js.map +1 -1
  51. package/src/internal/dev-lifecycle.js +3 -0
  52. package/src/internal/diagnostics.js +47 -0
  53. package/src/internal/diagnostics.js.map +1 -0
  54. package/src/internal/document-model.js +2 -2
  55. package/src/internal/document-model.js.map +1 -1
  56. package/src/internal/form-capabilities.js +1 -1
  57. package/src/internal/i18n.js +27 -1
  58. package/src/internal/i18n.js.map +1 -1
  59. package/src/{location-BTqdfIzX.js → location-CPX7oj0o.js} +2 -2
  60. package/src/{location-BTqdfIzX.js.map → location-CPX7oj0o.js.map} +1 -1
  61. package/src/{models-B4IoTmp7.js → models-C9kF9JlQ.js} +2 -2
  62. package/src/{models-B4IoTmp7.js.map → models-C9kF9JlQ.js.map} +1 -1
  63. package/src/{models-Bah5B3bT.js → models-ChRxBChy.js} +9 -2
  64. package/src/models-ChRxBChy.js.map +1 -0
  65. package/src/runtime/delivery/context.js +1 -1
  66. package/src/runtime/delivery/plugin.js +28 -5
  67. package/src/runtime/delivery/plugin.js.map +1 -1
  68. package/src/runtime/delivery/preview.d.ts +1 -1
  69. package/src/runtime/delivery/types.d.ts +2 -85
  70. package/src/runtime/delivery/useCmsDocumentSeo.d.ts +8 -1
  71. package/src/runtime/delivery/useCmsDocumentSeo.js +19 -7
  72. package/src/runtime/delivery/useCmsDocumentSeo.js.map +1 -1
  73. package/src/runtime/delivery/useDocument.d.ts +2 -2
  74. package/src/runtime/delivery/useDocument.js.map +1 -1
  75. package/src/runtime/delivery/useDocumentQuery.d.ts +3 -3
  76. package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
  77. package/src/runtime/forms/document.js +1 -1
  78. package/src/runtime/forms/useCmsForm.js +89 -45
  79. package/src/runtime/forms/useCmsForm.js.map +1 -1
  80. package/src/runtime/i18n/useCmsI18n.d.ts +9 -7
  81. package/src/runtime/i18n/useCmsI18n.js +5 -4
  82. package/src/runtime/i18n/useCmsI18n.js.map +1 -1
  83. package/src/runtime/installation.js +2 -2
  84. package/src/runtime/plugin.js +12 -4
  85. package/src/runtime/plugin.js.map +1 -1
  86. package/src/runtime/preview/connection.js +1 -1
  87. package/src/runtime/preview/controller.js +2 -2
  88. package/src/runtime/preview/plugin.client.js +3 -3
  89. package/src/runtime/preview/store.js +1 -1
  90. package/src/runtime/sitemap.js +1 -1
  91. package/src/scalars-CA6kyipS.d.ts +7 -0
  92. package/src/{store-b2CSXgMt.js → store-B49J21NA.js} +3 -3
  93. package/src/{store-b2CSXgMt.js.map → store-B49J21NA.js.map} +1 -1
  94. package/src/types-DutFRtaG.d.ts +90 -0
  95. package/studio/{CreateDocumentDialog-GGey1uBc.js → CreateDocumentDialog-DJ8c0WZb.js} +3 -3
  96. package/studio/{documentPlanning-DRErYmBU.js → documentPlanning-CDb31mnl.js} +5935 -5869
  97. package/studio/host.css +1 -1
  98. package/studio/host.js +7608 -7250
  99. package/src/ContentTransfer-C3Av9sWz.js.map +0 -1
  100. package/src/Forms-CfcI3tPU.js.map +0 -1
  101. package/src/Forms-Dj6NuW66.js.map +0 -1
  102. package/src/S3MediaObjects-CpPSzJto.js.map +0 -1
  103. package/src/installation-CNfIriVm.js.map +0 -1
  104. package/src/models-Bah5B3bT.js.map +0 -1
@@ -1,42 +1,548 @@
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 { i as FormResult, n as FORM_SUBMISSION_MAX_BYTES } from "./Forms-CfcI3tPU.js";
3
- import { a as encodeCmsEditorComponentAttributes, d as createCmsComarkRenderData, i as validateFormValues, t as documentForms } from "./Forms-Dj6NuW66.js";
4
- 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-Bah5B3bT.js";
5
- 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-CpPSzJto.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-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-D5Ns4FM6.js";
4
+ import { o as ContentTransferConflict } from "./ContentTransfer-BhF9G56s.js";
6
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 { 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";
7
8
  import { a as createEditorNodeId, o as editorNodeId, r as identifiedAttributes, t as assertCanonicalEditorContent } from "./metadata-BEZPWh-3.js";
8
- 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-CDMYfTre.js";
9
- import { o as ContentTransferConflict } from "./ContentTransfer-C3Av9sWz.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-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";
13
13
  import { FindMyWay, HttpEffect, HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse, Multipart } from "effect/unstable/http";
14
14
  import { HttpApiBuilder, HttpApiMiddleware } from "effect/unstable/httpapi";
15
- import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto";
16
- import { createAuthMiddleware, getSessionFromCtx, isAPIError } from "better-auth/api";
15
+ import { Pool } from "pg";
16
+ import { PgClient, PgPool } from "@effect/sql-pg";
17
+ import * as PgDrizzle from "drizzle-orm/effect-postgres";
18
+ import { migrate } from "drizzle-orm/pg-core/effect/session";
19
+ import { and, asc, count, desc, eq, gt, inArray, lt, lte, ne, or, sql } from "drizzle-orm";
20
+ import { alias, bigint, boolean, bytea, check, foreignKey, index, integer, jsonb, pgTable, primaryKey, text, timestamp, unique, uniqueIndex, uuid } from "drizzle-orm/pg-core";
21
+ import * as Client from "effect/unstable/sql/SqlClient";
22
+ import * as Statement from "effect/unstable/sql/Statement";
17
23
  import { betterAuth } from "better-auth";
18
24
  import { createAccessControl } from "better-auth/plugins/access";
19
25
  import { admin } from "better-auth/plugins/admin";
20
26
  import { defaultStatements } from "better-auth/plugins/admin/access";
27
+ import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto";
28
+ import { createAuthMiddleware, getSessionFromCtx, isAPIError } from "better-auth/api";
21
29
  import { Hocuspocus, IncomingMessage, MessageType, shouldSkipStoreHooks } from "@hocuspocus/server";
22
30
  import StarterKit from "@tiptap/starter-kit";
23
31
  import * as Y from "yjs";
24
32
  import { Doc, applyUpdate, encodeStateAsUpdate, encodeStateVector } from "yjs";
25
33
  import { RateLimiter } from "effect/unstable/persistence";
26
- import { PgClient } from "@effect/sql-pg";
27
34
  import { isDeepStrictEqual } from "node:util";
28
- import { and, asc, count, desc, eq, gt, inArray, lt, lte, ne, or, sql } from "drizzle-orm";
29
- import * as PgDrizzle from "drizzle-orm/effect-postgres";
30
35
  import { createInsertSchema, createSelectSchema } from "drizzle-orm/effect-schema";
31
- import { alias, bigint, boolean, bytea, check, foreignKey, index, integer, jsonb, pgTable, primaryKey, text, timestamp, unique, uniqueIndex, uuid } from "drizzle-orm/pg-core";
32
- import { migrate } from "drizzle-orm/pg-core/effect/session";
33
36
  import { EffectDrizzleQueryError } from "drizzle-orm/effect-core";
34
37
  import * as Cause$1 from "effect/Cause";
35
38
  import * as Option$1 from "effect/Option";
36
39
  import * as SqlError from "effect/unstable/sql/SqlError";
37
40
  import { Buffer } from "node:buffer";
38
- import { Pool } from "pg";
39
41
 
42
+ //#region ../sql-pg/src/internal/database/embedded-migrations.generated.ts
43
+ const embeddedMigrations = [
44
+ {
45
+ sql: [
46
+ "CREATE TABLE \"activity_entries\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"action\" text NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"target_kind\" text NOT NULL,\n \"target_id\" text,\n \"details\" jsonb DEFAULT '{}' NOT NULL,\n \"occurred_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"activity_entries_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset')),\n CONSTRAINT \"activity_entries_target_kind_check\" CHECK (\"target_kind\" in ('document', 'media', 'media-library', 'user')),\n CONSTRAINT \"activity_entries_target_check\" CHECK ((\"target_kind\" = 'media-library' AND \"target_id\" IS NULL)\n OR (\"target_kind\" <> 'media-library' AND \"target_id\" IS NOT NULL)),\n CONSTRAINT \"activity_entries_actor_roles_check\" CHECK (jsonb_typeof(\"actor_roles\") = 'array'),\n CONSTRAINT \"activity_entries_details_check\" CHECK (jsonb_typeof(\"details\") = 'object')\n);\n",
47
+ "\nCREATE TABLE \"auth_accounts\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"issuer\" text NOT NULL,\n \"account_id\" text NOT NULL,\n \"provider_id\" text NOT NULL,\n \"user_id\" uuid NOT NULL,\n \"access_token\" text,\n \"refresh_token\" text,\n \"id_token\" text,\n \"access_token_expires_at\" timestamp with time zone,\n \"refresh_token_expires_at\" timestamp with time zone,\n \"scope\" text,\n \"password\" text,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
48
+ "\nCREATE TABLE \"auth_rate_limits\" (\n \"key\" text PRIMARY KEY,\n \"count\" bigint NOT NULL,\n \"last_request\" bigint NOT NULL\n);\n",
49
+ "\nCREATE TABLE \"auth_sessions\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"expires_at\" timestamp with time zone NOT NULL,\n \"token\" text NOT NULL UNIQUE,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"ip_address\" text,\n \"user_agent\" text,\n \"user_id\" uuid NOT NULL,\n \"impersonated_by\" text\n);\n",
50
+ "\nCREATE TABLE \"auth_users\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"name\" text NOT NULL,\n \"email\" text NOT NULL UNIQUE,\n \"email_verified\" boolean DEFAULT false NOT NULL,\n \"image\" text,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"role\" text DEFAULT 'editor' NOT NULL,\n \"banned\" boolean DEFAULT false NOT NULL,\n \"ban_reason\" text,\n \"ban_expires\" timestamp with time zone,\n \"cms_creation_change_id\" uuid UNIQUE,\n \"cms_sessions_revoked_change_id\" uuid UNIQUE,\n CONSTRAINT \"auth_users_role_check\" CHECK (\"role\" in ('administrator', 'editor', 'viewer'))\n);\n",
51
+ "\nCREATE TABLE \"auth_verifications\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"identifier\" text NOT NULL,\n \"value\" text NOT NULL,\n \"expires_at\" timestamp with time zone NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
52
+ "\nCREATE TABLE \"change_receipts\" (\n \"change_id\" uuid PRIMARY KEY,\n \"fingerprint\" text NOT NULL,\n \"outcome\" text NOT NULL,\n \"activity_id\" uuid UNIQUE,\n \"completed_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"change_receipts_outcome_check\" CHECK ((\"outcome\" = 'applied' AND \"activity_id\" IS NOT NULL)\n OR (\"outcome\" = 'cancelled' AND \"activity_id\" IS NULL))\n);\n",
53
+ "\nCREATE TABLE \"cms_state\" (\n \"singleton\" boolean PRIMARY KEY DEFAULT true,\n \"generation\" bigint DEFAULT 0 NOT NULL,\n CONSTRAINT \"cms_state_singleton_check\" CHECK (\"singleton\"),\n CONSTRAINT \"cms_state_generation_check\" CHECK (\"generation\" >= 0)\n);\n",
54
+ "\nCREATE TABLE \"document_heads\" (\n \"document_id\" uuid PRIMARY KEY,\n \"authored_revision_id\" uuid NOT NULL,\n \"published_revision_id\" uuid\n);\n",
55
+ "\nCREATE TABLE \"document_media_references\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"document_id\" uuid NOT NULL,\n \"object_key\" text NOT NULL,\n \"path\" text NOT NULL,\n \"source_path\" text NOT NULL,\n \"node_path\" integer[] NOT NULL,\n CONSTRAINT \"document_media_references_identity_unique\" UNIQUE(\"document_id\",\"source_path\",\"node_path\",\"object_key\"),\n CONSTRAINT \"document_media_references_object_key_check\" CHECK (char_length(\"object_key\") between 1 and 1024\n AND btrim(\"object_key\") = \"object_key\"\n AND \"object_key\" !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'\n AND position(chr(92) in \"object_key\") = 0),\n CONSTRAINT \"document_media_references_node_path_check\" CHECK (array_position(\"node_path\", NULL) IS NULL AND 0 <= ALL(\"node_path\"))\n);\n",
56
+ "\nCREATE TABLE \"document_revisions\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"document_id\" uuid NOT NULL,\n \"action\" text NOT NULL,\n \"source_path\" text NOT NULL,\n \"markdown\" text NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"activity_details\" jsonb DEFAULT '{}' NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"document_revisions_document_id_unique\" UNIQUE(\"document_id\",\"id\"),\n CONSTRAINT \"document_revisions_action_check\" CHECK (\"action\" in ('document.create', 'document.move', 'document.remove', 'document.restore', 'document.undelete', 'document.update'))\n);\n",
57
+ "\nCREATE TABLE \"documents\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"source_path\" text NOT NULL,\n \"deleted_at\" timestamp with time zone,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL\n);\n",
58
+ "\nCREATE TABLE \"initialization_state\" (\n \"singleton\" boolean PRIMARY KEY DEFAULT true,\n \"state\" text DEFAULT 'uninitialized' NOT NULL,\n \"change_id\" uuid,\n \"claim\" jsonb,\n CONSTRAINT \"initialization_state_singleton_check\" CHECK (\"singleton\"),\n CONSTRAINT \"initialization_state_state_check\" CHECK (\"state\" in ('uninitialized', 'claiming', 'ready')),\n CONSTRAINT \"initialization_state_claim_check\" CHECK ((\"state\" = 'claiming' AND \"change_id\" IS NOT NULL AND jsonb_typeof(\"claim\") = 'object')\n OR (\"state\" <> 'claiming' AND \"change_id\" IS NULL AND \"claim\" IS NULL))\n);\n",
59
+ "\nCREATE TABLE \"media_assets\" (\n \"id\" uuid PRIMARY KEY,\n \"object_key\" text NOT NULL UNIQUE,\n \"name\" text NOT NULL,\n \"folder\" text DEFAULT '' NOT NULL,\n \"mime_type\" text NOT NULL,\n \"byte_size\" bigint NOT NULL,\n \"status\" text DEFAULT 'uploading' NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"media_assets_byte_size_check\" CHECK (\"byte_size\" > 0 AND \"byte_size\" <= 9007199254740991),\n CONSTRAINT \"media_assets_mime_type_check\" CHECK (\"mime_type\" in ('image/avif', 'image/gif', 'image/jpeg', 'image/png', 'image/webp')),\n CONSTRAINT \"media_assets_status_check\" CHECK (\"status\" in ('uploading', 'ready', 'deleting')),\n CONSTRAINT \"media_assets_name_check\" CHECK (char_length(\"name\") between 1 and 255\n AND btrim(\"name\") = \"name\"\n AND \"name\" not in ('.', '..')\n AND \"name\" !~ '[[:cntrl:]/]'\n AND position(chr(92) in \"name\") = 0),\n CONSTRAINT \"media_assets_folder_check\" CHECK (char_length(\"folder\") <= 512\n AND btrim(\"folder\") = \"folder\"\n AND \"folder\" !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'\n AND position(chr(92) in \"folder\") = 0),\n CONSTRAINT \"media_assets_object_key_check\" CHECK (\"object_key\" ~ '^media/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.(avif|gif|jpg|png|webp)$')\n);\n",
60
+ "\nCREATE TABLE \"media_replacements\" (\n \"media_id\" uuid PRIMARY KEY,\n \"object_key\" text NOT NULL,\n \"staging_object_key\" text NOT NULL UNIQUE,\n \"name\" text NOT NULL,\n \"folder\" text NOT NULL,\n \"mime_type\" text NOT NULL,\n \"byte_size\" bigint NOT NULL,\n \"staged\" boolean DEFAULT false NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"media_replacements_byte_size_check\" CHECK (\"byte_size\" > 0 AND \"byte_size\" <= 9007199254740991),\n CONSTRAINT \"media_replacements_mime_type_check\" CHECK (\"mime_type\" in ('image/avif', 'image/gif', 'image/jpeg', 'image/png', 'image/webp')),\n CONSTRAINT \"media_replacements_name_check\" CHECK (char_length(\"name\") between 1 and 255\n AND btrim(\"name\") = \"name\"\n AND \"name\" not in ('.', '..')\n AND \"name\" !~ '[[:cntrl:]/]'\n AND position(chr(92) in \"name\") = 0),\n CONSTRAINT \"media_replacements_folder_check\" CHECK (char_length(\"folder\") <= 512\n AND btrim(\"folder\") = \"folder\"\n AND \"folder\" !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'\n AND position(chr(92) in \"folder\") = 0),\n CONSTRAINT \"media_replacements_object_key_check\" CHECK (\"object_key\" ~ '^media/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.(avif|gif|jpg|png|webp)$'),\n CONSTRAINT \"media_replacements_staging_object_key_check\" CHECK (\"staging_object_key\" ~ '^media/replacements/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.(avif|gif|jpg|png|webp)$'),\n CONSTRAINT \"media_replacements_distinct_object_keys_check\" CHECK (\"staging_object_key\" <> \"object_key\")\n);\n",
61
+ "\nCREATE TABLE \"pending_changes\" (\n \"id\" uuid PRIMARY KEY,\n \"action\" text NOT NULL,\n \"subject\" text NOT NULL,\n \"scope\" text NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"target_kind\" text,\n \"target_id\" text,\n \"intent\" jsonb NOT NULL,\n \"fingerprint\" text NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"pending_changes_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset')),\n CONSTRAINT \"pending_changes_scope_check\" CHECK (\"scope\" in ('initialization', 'media', 'users')),\n CONSTRAINT \"pending_changes_subject_check\" CHECK (char_length(\"subject\") between 1 and 1024 AND btrim(\"subject\") = \"subject\"),\n CONSTRAINT \"pending_changes_actor_roles_check\" CHECK (jsonb_typeof(\"actor_roles\") = 'array'),\n CONSTRAINT \"pending_changes_intent_check\" CHECK (jsonb_typeof(\"intent\") = 'object'),\n CONSTRAINT \"pending_changes_target_check\" CHECK ((\"target_kind\" IS NULL AND \"target_id\" IS NULL)\n OR (\"target_kind\" = 'media-library' AND \"target_id\" IS NULL)\n OR (\"target_kind\" in ('document', 'media', 'user')\n AND \"target_id\" IS NOT NULL))\n);\n",
62
+ "\nCREATE TABLE \"working_document_publish_attempts\" (\n \"id\" uuid PRIMARY KEY,\n \"activity\" jsonb NOT NULL,\n \"document_id\" uuid NOT NULL,\n \"expected_generation\" uuid NOT NULL,\n \"expected_version\" uuid NOT NULL,\n \"high_watermark\" bigint NOT NULL,\n \"markdown_hash\" text NOT NULL,\n \"state\" bytea NOT NULL,\n \"state_vector\" bytea NOT NULL,\n \"checkpoint_version\" uuid,\n \"phase\" text DEFAULT 'pending' NOT NULL,\n \"failure\" text,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"working_document_publish_attempts_phase_check\" CHECK (\"phase\" in ('pending', 'checkpointed', 'published', 'failed')),\n CONSTRAINT \"working_document_publish_attempts_high_watermark_check\" CHECK (\"high_watermark\" between 0 and 9007199254740991),\n CONSTRAINT \"working_document_publish_attempts_markdown_hash_check\" CHECK (char_length(\"markdown_hash\") between 1 and 128),\n CONSTRAINT \"working_document_publish_attempts_state_check\" CHECK (octet_length(\"state\") > 0),\n CONSTRAINT \"working_document_publish_attempts_state_vector_check\" CHECK (octet_length(\"state_vector\") > 0),\n CONSTRAINT \"working_document_publish_attempts_payload_check\" CHECK ((\n \"phase\" = 'pending'\n AND \"checkpoint_version\" IS NULL\n AND \"failure\" IS NULL\n ) OR (\n \"phase\" in ('checkpointed', 'published')\n AND \"checkpoint_version\" IS NOT NULL\n AND \"failure\" IS NULL\n ) OR (\n \"phase\" = 'failed'\n AND \"checkpoint_version\" IS NULL\n AND char_length(\"failure\") between 1 and 128\n ))\n);\n",
63
+ "\nCREATE TABLE \"working_document_updates\" (\n \"document_id\" uuid,\n \"generation_id\" uuid NOT NULL,\n \"sequence\" bigint,\n \"update\" bytea NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"working_document_updates_pkey\" PRIMARY KEY(\"document_id\",\"sequence\"),\n CONSTRAINT \"working_document_updates_sequence_check\" CHECK (\"sequence\" between 1 and 9007199254740991),\n CONSTRAINT \"working_document_updates_update_check\" CHECK (octet_length(\"update\") > 0)\n);\n",
64
+ "\nCREATE TABLE \"working_documents\" (\n \"document_id\" uuid PRIMARY KEY,\n \"format_version\" integer NOT NULL,\n \"generation_id\" uuid NOT NULL,\n \"state\" bytea NOT NULL,\n \"saved_state_vector\" bytea NOT NULL,\n \"saved_version\" uuid NOT NULL,\n \"next_update_sequence\" bigint DEFAULT 1 NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"working_documents_generation_unique\" UNIQUE(\"document_id\",\"generation_id\"),\n CONSTRAINT \"working_documents_format_version_check\" CHECK (\"format_version\" = 1),\n CONSTRAINT \"working_documents_state_check\" CHECK (octet_length(\"state\") > 0),\n CONSTRAINT \"working_documents_saved_state_vector_check\" CHECK (octet_length(\"saved_state_vector\") > 0),\n CONSTRAINT \"working_documents_next_update_sequence_check\" CHECK (\"next_update_sequence\" between 1 and 9007199254740991)\n);\n",
65
+ "\nCREATE INDEX \"activity_entries_history\" ON \"activity_entries\" (\"occurred_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
66
+ "\nCREATE INDEX \"activity_entries_actor\" ON \"activity_entries\" (\"actor_id\",\"occurred_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
67
+ "\nCREATE INDEX \"activity_entries_target\" ON \"activity_entries\" (\"target_kind\",\"target_id\",\"occurred_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
68
+ "\nCREATE INDEX \"activity_entries_request\" ON \"activity_entries\" (\"request_id\");",
69
+ "\nCREATE INDEX \"auth_accounts_user_id\" ON \"auth_accounts\" (\"user_id\");",
70
+ "\nCREATE UNIQUE INDEX \"auth_accounts_identity\" ON \"auth_accounts\" (\"issuer\",\"account_id\");",
71
+ "\nCREATE INDEX \"auth_sessions_user_id\" ON \"auth_sessions\" (\"user_id\");",
72
+ "\nCREATE INDEX \"auth_verifications_identifier\" ON \"auth_verifications\" (\"identifier\");",
73
+ "\nCREATE INDEX \"change_receipts_activity\" ON \"change_receipts\" (\"activity_id\");",
74
+ "\nCREATE INDEX \"document_media_references_object_key\" ON \"document_media_references\" (\"object_key\");",
75
+ "\nCREATE INDEX \"document_revisions_history\" ON \"document_revisions\" (\"document_id\",\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
76
+ "\nCREATE UNIQUE INDEX \"documents_active_path\" ON \"documents\" (\"source_path\") WHERE \"deleted_at\" is null;",
77
+ "\nCREATE INDEX \"media_assets_catalog\" ON \"media_assets\" (\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST) WHERE \"status\" = 'ready';",
78
+ "\nCREATE INDEX \"media_assets_folder\" ON \"media_assets\" (\"folder\",\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST) WHERE \"status\" = 'ready';",
79
+ "\nCREATE INDEX \"media_assets_recovery\" ON \"media_assets\" (\"updated_at\",\"id\") WHERE \"status\" <> 'ready';",
80
+ "\nCREATE INDEX \"media_replacements_recovery\" ON \"media_replacements\" (\"updated_at\",\"media_id\");",
81
+ "\nCREATE UNIQUE INDEX \"pending_changes_subject\" ON \"pending_changes\" (\"subject\");",
82
+ "\nCREATE INDEX \"pending_changes_recovery\" ON \"pending_changes\" (\"scope\",\"updated_at\",\"id\");",
83
+ "\nCREATE UNIQUE INDEX \"working_document_publish_attempts_active\" ON \"working_document_publish_attempts\" (\"document_id\") WHERE \"phase\" in ('pending', 'checkpointed');",
84
+ "\nCREATE INDEX \"working_document_publish_attempts_recovery\" ON \"working_document_publish_attempts\" (\"document_id\",\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
85
+ "\nALTER TABLE \"auth_accounts\" ADD CONSTRAINT \"auth_accounts_user_id_auth_users_id_fkey\" FOREIGN KEY (\"user_id\") REFERENCES \"auth_users\"(\"id\") ON DELETE CASCADE;",
86
+ "\nALTER TABLE \"auth_sessions\" ADD CONSTRAINT \"auth_sessions_user_id_auth_users_id_fkey\" FOREIGN KEY (\"user_id\") REFERENCES \"auth_users\"(\"id\") ON DELETE CASCADE;",
87
+ "\nALTER TABLE \"change_receipts\" ADD CONSTRAINT \"change_receipts_activity_id_activity_entries_id_fkey\" FOREIGN KEY (\"activity_id\") REFERENCES \"activity_entries\"(\"id\") ON DELETE RESTRICT;",
88
+ "\nALTER TABLE \"document_heads\" ADD CONSTRAINT \"document_heads_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE RESTRICT;",
89
+ "\nALTER TABLE \"document_heads\" ADD CONSTRAINT \"document_heads_authored_revision_fkey\" FOREIGN KEY (\"document_id\",\"authored_revision_id\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
90
+ "\nALTER TABLE \"document_heads\" ADD CONSTRAINT \"document_heads_published_revision_fkey\" FOREIGN KEY (\"document_id\",\"published_revision_id\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
91
+ "\nALTER TABLE \"document_media_references\" ADD CONSTRAINT \"document_media_references_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE CASCADE;",
92
+ "\nALTER TABLE \"document_revisions\" ADD CONSTRAINT \"document_revisions_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE RESTRICT;",
93
+ "\nALTER TABLE \"media_replacements\" ADD CONSTRAINT \"media_replacements_media_id_media_assets_id_fkey\" FOREIGN KEY (\"media_id\") REFERENCES \"media_assets\"(\"id\") ON DELETE RESTRICT;",
94
+ "\nALTER TABLE \"working_document_publish_attempts\" ADD CONSTRAINT \"working_document_publish_attempts_document_generation_fkey\" FOREIGN KEY (\"document_id\",\"expected_generation\") REFERENCES \"working_documents\"(\"document_id\",\"generation_id\") ON DELETE CASCADE;",
95
+ "\nALTER TABLE \"working_document_publish_attempts\" ADD CONSTRAINT \"working_document_publish_attempts_expected_version_fkey\" FOREIGN KEY (\"document_id\",\"expected_version\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
96
+ "\nALTER TABLE \"working_document_publish_attempts\" ADD CONSTRAINT \"working_document_publish_attempts_checkpoint_version_fkey\" FOREIGN KEY (\"document_id\",\"checkpoint_version\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
97
+ "\nALTER TABLE \"working_document_updates\" ADD CONSTRAINT \"working_document_updates_document_generation_fkey\" FOREIGN KEY (\"document_id\",\"generation_id\") REFERENCES \"working_documents\"(\"document_id\",\"generation_id\") ON DELETE CASCADE;",
98
+ "\nALTER TABLE \"working_documents\" ADD CONSTRAINT \"working_documents_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE CASCADE;",
99
+ "\nALTER TABLE \"working_documents\" ADD CONSTRAINT \"working_documents_saved_version_fkey\" FOREIGN KEY (\"document_id\",\"saved_version\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;"
100
+ ],
101
+ bps: true,
102
+ folderMillis: 1788466567e3,
103
+ hash: "943a4996ef8c4324bd58280a80103e5a1632b088880164904b3857686e26f33e",
104
+ name: "20260903201607_cms_baseline"
105
+ },
106
+ {
107
+ sql: [
108
+ "ALTER TABLE \"auth_rate_limits\" ADD COLUMN \"id\" uuid DEFAULT gen_random_uuid();",
109
+ "\nALTER TABLE \"auth_rate_limits\" DROP CONSTRAINT \"auth_rate_limits_pkey\";",
110
+ "\nALTER TABLE \"auth_rate_limits\" ADD PRIMARY KEY (\"id\");",
111
+ "\nALTER TABLE \"auth_rate_limits\" ADD CONSTRAINT \"auth_rate_limits_key_key\" UNIQUE(\"key\");"
112
+ ],
113
+ bps: true,
114
+ folderMillis: 1788587191e3,
115
+ hash: "78b837c6b72a3de22d68e8db90bd211e61a0b97ff29bf8d16a0bba245eefa7ed",
116
+ name: "20260905054631_burly_northstar"
117
+ },
118
+ {
119
+ sql: ["ALTER TABLE \"auth_accounts\" DROP COLUMN \"issuer\";", "\nCREATE UNIQUE INDEX \"auth_accounts_identity\" ON \"auth_accounts\" (\"provider_id\",\"account_id\");"],
120
+ bps: true,
121
+ folderMillis: 178875937e4,
122
+ hash: "e442485fa6c2d611e3dae508a12d245481bc5ec8f2dd4f5d853910df34484787",
123
+ name: "20260907053610_fancy_lady_deathstrike"
124
+ },
125
+ {
126
+ sql: ["ALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_action_check\", ADD CONSTRAINT \"activity_entries_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));", "\nALTER TABLE \"pending_changes\" DROP CONSTRAINT \"pending_changes_action_check\", ADD CONSTRAINT \"pending_changes_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));"],
127
+ bps: true,
128
+ folderMillis: 1788866265e3,
129
+ hash: "24c56a37796caf8d76c0a97128a382b31e71808aa5b0ca7e5bac96795f9e16c7",
130
+ name: "20260908111745_classy_johnny_storm"
131
+ },
132
+ {
133
+ sql: [
134
+ "CREATE TABLE \"seo_media_references\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"scope\" text NOT NULL,\n \"media_id\" uuid NOT NULL,\n CONSTRAINT \"seo_media_references_scope_media_unique\" UNIQUE(\"scope\",\"media_id\"),\n CONSTRAINT \"seo_media_references_scope_check\" CHECK (\"scope\" in ('working', 'published'))\n);\n",
135
+ "\nCREATE TABLE \"seo_revisions\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"settings\" jsonb NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"seo_revisions_actor_roles_check\" CHECK (jsonb_typeof(\"actor_roles\") = 'array'),\n CONSTRAINT \"seo_revisions_settings_check\" CHECK (jsonb_typeof(\"settings\") = 'object')\n);\n",
136
+ "\nCREATE TABLE \"seo_state\" (\n \"singleton\" boolean PRIMARY KEY DEFAULT true,\n \"working_revision_id\" uuid NOT NULL,\n \"published_revision_id\" uuid NOT NULL,\n CONSTRAINT \"seo_state_singleton_check\" CHECK (\"singleton\")\n);\n",
137
+ "\nCREATE INDEX \"seo_media_references_media\" ON \"seo_media_references\" (\"media_id\");",
138
+ "\nCREATE INDEX \"seo_revisions_history\" ON \"seo_revisions\" (\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
139
+ "\nALTER TABLE \"seo_media_references\" ADD CONSTRAINT \"seo_media_references_media_id_media_assets_id_fkey\" FOREIGN KEY (\"media_id\") REFERENCES \"media_assets\"(\"id\") ON DELETE RESTRICT;",
140
+ "\nALTER TABLE \"seo_state\" ADD CONSTRAINT \"seo_state_working_revision_fkey\" FOREIGN KEY (\"working_revision_id\") REFERENCES \"seo_revisions\"(\"id\") ON DELETE RESTRICT;",
141
+ "\nALTER TABLE \"seo_state\" ADD CONSTRAINT \"seo_state_published_revision_fkey\" FOREIGN KEY (\"published_revision_id\") REFERENCES \"seo_revisions\"(\"id\") ON DELETE RESTRICT;",
142
+ "\nALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_action_check\", ADD CONSTRAINT \"activity_entries_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'seo.saved', 'seo.published', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));",
143
+ "\nALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_target_kind_check\", ADD CONSTRAINT \"activity_entries_target_kind_check\" CHECK (\"target_kind\" in ('document', 'media', 'media-library', 'seo', 'user'));",
144
+ "\nALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_target_check\", ADD CONSTRAINT \"activity_entries_target_check\" CHECK ((\"target_kind\" in ('media-library', 'seo') AND \"target_id\" IS NULL)\n OR (\"target_kind\" not in ('media-library', 'seo') AND \"target_id\" IS NOT NULL));",
145
+ "\nALTER TABLE \"pending_changes\" DROP CONSTRAINT \"pending_changes_action_check\", ADD CONSTRAINT \"pending_changes_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'seo.saved', 'seo.published', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));"
146
+ ],
147
+ bps: true,
148
+ folderMillis: 1789233351e3,
149
+ hash: "8e6a6abf5385ab3ecf8eb083c1923ac9c74d72aa71bd1d444b7402d3e7e77000",
150
+ name: "20260912171551_charming_valkyrie"
151
+ }
152
+ ];
153
+
154
+ //#endregion
155
+ //#region ../sql-pg/src/internal/database/table-helpers.ts
156
+ const transactionTimestamp = sql`transaction_timestamp()`;
157
+ function isOneOf(column, values) {
158
+ return sql`${column} in (${sql.join(values.map((value) => sql`${value}`), sql`, `)})`;
159
+ }
160
+
161
+ //#endregion
162
+ //#region ../sql-pg/src/internal/documents/tables.ts
163
+ const cmsState = pgTable("cms_state", {
164
+ singleton: boolean().default(true).primaryKey(),
165
+ generation: bigint({ mode: "bigint" }).default(sql`0`).notNull()
166
+ }, (table) => [check("cms_state_singleton_check", sql`${table.singleton}`), check("cms_state_generation_check", sql`${table.generation} >= 0`)]);
167
+ const documentsTable = pgTable("documents", {
168
+ id: uuid().defaultRandom().primaryKey(),
169
+ sourcePath: text("source_path").notNull(),
170
+ deletedAt: timestamp("deleted_at", {
171
+ mode: "string",
172
+ withTimezone: true
173
+ }),
174
+ createdAt: timestamp("created_at", {
175
+ mode: "string",
176
+ withTimezone: true
177
+ }).default(transactionTimestamp).notNull(),
178
+ updatedAt: timestamp("updated_at", {
179
+ mode: "string",
180
+ withTimezone: true
181
+ }).default(transactionTimestamp).notNull()
182
+ }, (table) => [uniqueIndex("documents_active_path").on(table.sourcePath).where(sql`${table.deletedAt} is null`)]);
183
+ const documentRevisions = pgTable("document_revisions", {
184
+ id: uuid().defaultRandom().primaryKey(),
185
+ documentId: uuid("document_id").notNull().references(() => documentsTable.id, { onDelete: "restrict" }),
186
+ action: text({ enum: DOCUMENT_REVISION_ACTIONS }).notNull(),
187
+ sourcePath: text("source_path").notNull(),
188
+ markdown: text().notNull(),
189
+ actorId: text("actor_id").notNull(),
190
+ actorEmail: text("actor_email").notNull(),
191
+ actorName: text("actor_name").notNull(),
192
+ actorRoles: jsonb("actor_roles").$type().notNull(),
193
+ requestId: uuid("request_id").notNull(),
194
+ reason: text(),
195
+ activityDetails: jsonb("activity_details").$type().default({}).notNull(),
196
+ createdAt: timestamp("created_at", {
197
+ mode: "string",
198
+ withTimezone: true
199
+ }).default(transactionTimestamp).notNull()
200
+ }, (table) => [
201
+ check("document_revisions_action_check", isOneOf(table.action, DOCUMENT_REVISION_ACTIONS)),
202
+ unique("document_revisions_document_id_unique").on(table.documentId, table.id),
203
+ index("document_revisions_history").on(table.documentId, table.createdAt.desc(), table.id.desc())
204
+ ]);
205
+ const documentHeads = pgTable("document_heads", {
206
+ documentId: uuid("document_id").primaryKey().references(() => documentsTable.id, { onDelete: "restrict" }),
207
+ authoredRevisionId: uuid("authored_revision_id").notNull(),
208
+ publishedRevisionId: uuid("published_revision_id")
209
+ }, (table) => [foreignKey({
210
+ columns: [table.documentId, table.authoredRevisionId],
211
+ foreignColumns: [documentRevisions.documentId, documentRevisions.id],
212
+ name: "document_heads_authored_revision_fkey"
213
+ }).onDelete("restrict"), foreignKey({
214
+ columns: [table.documentId, table.publishedRevisionId],
215
+ foreignColumns: [documentRevisions.documentId, documentRevisions.id],
216
+ name: "document_heads_published_revision_fkey"
217
+ }).onDelete("restrict")]);
218
+ const documentMediaReferences = pgTable("document_media_references", {
219
+ id: uuid().defaultRandom().primaryKey(),
220
+ documentId: uuid("document_id").notNull().references(() => documentsTable.id, { onDelete: "cascade" }),
221
+ objectKey: text("object_key").notNull(),
222
+ path: text().notNull(),
223
+ sourcePath: text("source_path").notNull(),
224
+ nodePath: integer("node_path").array().notNull()
225
+ }, (table) => [
226
+ unique("document_media_references_identity_unique").on(table.documentId, table.sourcePath, table.nodePath, table.objectKey),
227
+ check("document_media_references_object_key_check", sql`char_length(${table.objectKey}) between 1 and 1024
228
+ AND btrim(${table.objectKey}) = ${table.objectKey}
229
+ AND ${table.objectKey} !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'
230
+ AND position(chr(92) in ${table.objectKey}) = 0`),
231
+ check("document_media_references_node_path_check", sql`array_position(${table.nodePath}, NULL) IS NULL AND 0 <= ALL(${table.nodePath})`),
232
+ index("document_media_references_object_key").on(table.objectKey)
233
+ ]);
234
+
235
+ //#endregion
236
+ //#region ../sql-pg/src/internal/initialization/tables.ts
237
+ const INITIALIZATION_STATES = [
238
+ "uninitialized",
239
+ "claiming",
240
+ "ready"
241
+ ];
242
+ const initializationState = pgTable("initialization_state", {
243
+ singleton: boolean().default(true).primaryKey(),
244
+ state: text({ enum: INITIALIZATION_STATES }).default("uninitialized").notNull(),
245
+ changeId: uuid("change_id"),
246
+ claim: jsonb().$type()
247
+ }, (table) => [
248
+ check("initialization_state_singleton_check", sql`${table.singleton}`),
249
+ check("initialization_state_state_check", isOneOf(table.state, INITIALIZATION_STATES)),
250
+ check("initialization_state_claim_check", sql`(${table.state} = 'claiming' AND ${table.changeId} IS NOT NULL AND jsonb_typeof(${table.claim}) = 'object')
251
+ OR (${table.state} <> 'claiming' AND ${table.changeId} IS NULL AND ${table.claim} IS NULL)`)
252
+ ]);
253
+
254
+ //#endregion
255
+ //#region ../sql-pg/src/internal/database/migrations.ts
256
+ const MIGRATION_LOCK_KEY = "cms:database-migrations:v1";
257
+ const migrateCmsDatabase = Effect.fn("CmsDatabase.migrate")(function* (schema) {
258
+ const postgres = yield* PgClient.PgClient;
259
+ const database = yield* PgDrizzle.makeWithDefaults();
260
+ yield* postgres.withTransaction(Effect.gen(function* () {
261
+ yield* postgres.unsafe("select pg_advisory_xact_lock(hashtextextended($1, 0))", [MIGRATION_LOCK_KEY]);
262
+ yield* migrate(embeddedMigrations, database._.session, {
263
+ migrationsFolder: "embedded",
264
+ migrationsSchema: schema,
265
+ migrationsTable: "__drizzle_migrations"
266
+ });
267
+ yield* database.insert(cmsState).values({}).onConflictDoNothing({ target: cmsState.singleton });
268
+ yield* database.insert(initializationState).values({}).onConflictDoNothing({ target: initializationState.singleton });
269
+ }));
270
+ });
271
+ function cmsDatabaseMigrationLayer(schema) {
272
+ return Layer.effectDiscard(migrateCmsDatabase(schema));
273
+ }
274
+
275
+ //#endregion
276
+ //#region ../sql-pg/src/internal/postgres/scoped-client.ts
277
+ const PgJson = Statement.custom("PgJson");
278
+ /**
279
+ * Builds a PostgreSQL client whose every physical pool connection starts in
280
+ * the configured schema. The upstream driver does not yet expose PostgreSQL
281
+ * startup parameters, so the initialization belongs at our pool seam.
282
+ */
283
+ const makeSchemaClient = Effect.fn("Postgres.makeSchemaClient")(function* (options, schema) {
284
+ const pool = yield* PgPool.make(options);
285
+ const initialized = /* @__PURE__ */ new WeakSet();
286
+ const searchPath = `set search_path to "${schema}"`;
287
+ const initialize = (connection) => initialized.has(connection) ? Effect.succeed(connection) : connection.query(searchPath).pipe(Effect.tap(() => Effect.sync(() => initialized.add(connection))), Effect.as(connection));
288
+ const acquirer = Effect.map(Effect.flatMap(pool.get, initialize), makeConnection);
289
+ const transactionAcquirer = Effect.map(Effect.flatMap(pool.reserve, initialize), makeConnection);
290
+ const listenAcquirer = Effect.flatMap(pool.reserve, initialize);
291
+ const borrower = (use) => pool.use((connection) => Effect.flatMap(initialize(connection), (ready) => use(makeConnection(ready))));
292
+ const compiler = PgClient.makeCompiler(options.transformQueryNames, options.transformJson);
293
+ const transformRows = options.transformResultNames ? Statement.defaultTransforms(options.transformResultNames, options.transformJson).array : void 0;
294
+ const listen = (channel) => Effect.flatMap(listenAcquirer, (connection) => connection.listen(channel));
295
+ const json = (value) => Statement.fragment([PgJson(value, void 0, void 0)]);
296
+ return Object.assign(yield* Client.make({
297
+ acquirer,
298
+ borrower,
299
+ compiler,
300
+ prepareTransactionControls: true,
301
+ spanAttributes: [
302
+ ...options.spanAttributes ? Object.entries(options.spanAttributes) : [],
303
+ ["db.system.name", "postgresql"],
304
+ ["cms.database.schema", schema]
305
+ ],
306
+ transactionAcquirer,
307
+ transformRows
308
+ }), {
309
+ [PgClient.TypeId]: PgClient.TypeId,
310
+ config: options,
311
+ json,
312
+ listen,
313
+ notify: (channel, payload) => Effect.asVoid(Effect.scoped(Effect.flatMap(acquirer, (connection) => connection.executeRaw("select pg_notify($1, $2)", [channel, payload]))))
314
+ });
315
+ });
316
+ var ConnectionImpl = class {
317
+ connection;
318
+ constructor(connection) {
319
+ this.connection = connection;
320
+ }
321
+ run(query, params, prepare = true) {
322
+ return Effect.map(this.connection.query(query, params, prepare), (result) => result.rows);
323
+ }
324
+ execute(sql, params, transformRows) {
325
+ const operation = this.run(sql, params);
326
+ return transformRows ? Effect.map(operation, transformRows) : operation;
327
+ }
328
+ executeRaw(sql, params) {
329
+ return this.connection.query(sql, params);
330
+ }
331
+ executeWithoutTransform(sql, params) {
332
+ return this.run(sql, params);
333
+ }
334
+ executeValues(sql, params) {
335
+ return this.connection.queryValues(sql, params);
336
+ }
337
+ executeValuesUnprepared(sql, params) {
338
+ return this.connection.queryValues(sql, params, false);
339
+ }
340
+ executeUnprepared(sql, params, transformRows) {
341
+ const operation = this.run(sql, params, false);
342
+ return transformRows ? Effect.map(operation, transformRows) : operation;
343
+ }
344
+ executeStream(sql, params, transformRows) {
345
+ const stream = this.connection.stream(sql, params);
346
+ if (!transformRows) return stream;
347
+ return Stream.mapArray(stream, (rows) => {
348
+ const transformed = transformRows(rows);
349
+ const first = transformed[0];
350
+ return first === void 0 ? rows : [first, ...transformed.slice(1)];
351
+ });
352
+ }
353
+ };
354
+ function makeConnection(connection) {
355
+ return new ConnectionImpl(connection);
356
+ }
357
+ function schemaClientLayer(options, schema) {
358
+ return PgClient.layerFrom(makeSchemaClient(options, schema));
359
+ }
360
+
361
+ //#endregion
362
+ //#region ../auth/src/internal/user.ts
363
+ const cmsUserCreationChangeField = "cmsCreationChangeId";
364
+ const cmsUserSessionsRevokedChangeField = "cmsSessionsRevokedChangeId";
365
+ const BetterAuthUser = Schema.Struct({
366
+ banned: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),
367
+ createdAt: Schema.Date,
368
+ email: Schema.String,
369
+ emailVerified: Schema.Boolean,
370
+ id: Schema.String,
371
+ name: Schema.String,
372
+ role: Schema.optionalKey(Schema.NullOr(Schema.String)),
373
+ updatedAt: Schema.Date
374
+ });
375
+ const BetterAuthUserRecoveryEvidence = Schema.Struct({
376
+ [cmsUserCreationChangeField]: Schema.optionalKey(Schema.UndefinedOr(Schema.NullOr(ActivityId))),
377
+ [cmsUserSessionsRevokedChangeField]: Schema.optionalKey(Schema.UndefinedOr(Schema.NullOr(ActivityId)))
378
+ });
379
+ function decodeBetterAuthUser(value) {
380
+ return Schema.decodeEffect(BetterAuthUser)(value).pipe(Effect.flatMap((user) => Schema.decodeUnknownEffect(User)({
381
+ banned: user.banned === true,
382
+ createdAt: user.createdAt.toISOString(),
383
+ email: user.email,
384
+ emailVerified: user.emailVerified,
385
+ id: user.id,
386
+ name: user.name,
387
+ role: user.role,
388
+ updatedAt: user.updatedAt.toISOString()
389
+ })));
390
+ }
391
+ function decodeBetterAuthActor(user) {
392
+ return Schema.decodeEffect(StudioActor)(betterAuthActorInput(user));
393
+ }
394
+ function decodeBetterAuthActorOption(user) {
395
+ return Schema.decodeOption(StudioActor)(betterAuthActorInput(user));
396
+ }
397
+ function decodeBetterAuthUserCreationChangeId(user) {
398
+ return decodeChangeId(user, cmsUserCreationChangeField);
399
+ }
400
+ function decodeBetterAuthUserSessionsRevokedChangeId(user) {
401
+ return decodeChangeId(user, cmsUserSessionsRevokedChangeField);
402
+ }
403
+ function decodeChangeId(user, field) {
404
+ return Schema.decodeEffect(BetterAuthUserRecoveryEvidence)(user).pipe(Effect.map((evidence) => evidence[field] ?? null));
405
+ }
406
+ function betterAuthProviderRoles(value) {
407
+ return value ? [...new Set(value.split(",").map((role) => role.trim()).filter(Boolean))] : [];
408
+ }
409
+ function betterAuthActorInput(user) {
410
+ return {
411
+ email: user.email,
412
+ id: user.id,
413
+ name: user.name,
414
+ roles: betterAuthProviderRoles(user.role)
415
+ };
416
+ }
417
+
418
+ //#endregion
419
+ //#region ../auth/src/internal/better-auth.ts
420
+ const cmsBetterAuthAccess = createAccessControl(defaultStatements);
421
+ const cmsBetterAuthRoles = {
422
+ administrator: cmsBetterAuthAccess.newRole({
423
+ session: ["list", "revoke"],
424
+ user: [
425
+ "create",
426
+ "list",
427
+ "get",
428
+ "set-role",
429
+ "delete",
430
+ "update"
431
+ ]
432
+ }),
433
+ editor: cmsBetterAuthAccess.newRole({
434
+ session: [],
435
+ user: []
436
+ }),
437
+ viewer: cmsBetterAuthAccess.newRole({
438
+ session: [],
439
+ user: []
440
+ })
441
+ };
442
+ const timestampFields = {
443
+ createdAt: "created_at",
444
+ updatedAt: "updated_at"
445
+ };
446
+ function createCmsBetterAuthOptions(options, activity) {
447
+ return {
448
+ advanced: { database: {
449
+ generateId: "uuid",
450
+ joins: true
451
+ } },
452
+ appName: "CMS Studio",
453
+ basePath: options.basePath ?? "/api/cms/auth",
454
+ baseURL: options.baseURL,
455
+ database: options.database,
456
+ emailAndPassword: {
457
+ disableSignUp: true,
458
+ enabled: true,
459
+ ...activity?.emailAndPassword
460
+ },
461
+ hooks: activity?.hooks,
462
+ user: {
463
+ additionalFields: {
464
+ [cmsUserCreationChangeField]: hiddenChangeField("cms_creation_change_id"),
465
+ [cmsUserSessionsRevokedChangeField]: hiddenChangeField("cms_sessions_revoked_change_id")
466
+ },
467
+ modelName: "auth_users",
468
+ fields: {
469
+ ...timestampFields,
470
+ emailVerified: "email_verified"
471
+ }
472
+ },
473
+ session: {
474
+ cookieCache: {
475
+ enabled: false,
476
+ strategy: "jwt"
477
+ },
478
+ modelName: "auth_sessions",
479
+ fields: {
480
+ ...timestampFields,
481
+ expiresAt: "expires_at",
482
+ ipAddress: "ip_address",
483
+ userAgent: "user_agent",
484
+ userId: "user_id"
485
+ }
486
+ },
487
+ account: {
488
+ modelName: "auth_accounts",
489
+ fields: {
490
+ accessToken: "access_token",
491
+ accessTokenExpiresAt: "access_token_expires_at",
492
+ accountId: "account_id",
493
+ ...timestampFields,
494
+ idToken: "id_token",
495
+ providerId: "provider_id",
496
+ refreshToken: "refresh_token",
497
+ refreshTokenExpiresAt: "refresh_token_expires_at",
498
+ userId: "user_id"
499
+ }
500
+ },
501
+ verification: {
502
+ modelName: "auth_verifications",
503
+ fields: {
504
+ ...timestampFields,
505
+ expiresAt: "expires_at"
506
+ }
507
+ },
508
+ rateLimit: {
509
+ enabled: true,
510
+ storage: "database",
511
+ modelName: "auth_rate_limits",
512
+ fields: { lastRequest: "last_request" }
513
+ },
514
+ plugins: [admin({
515
+ ac: cmsBetterAuthAccess,
516
+ adminRoles: ["administrator"],
517
+ defaultRole: "editor",
518
+ roles: cmsBetterAuthRoles,
519
+ schema: {
520
+ session: { fields: { impersonatedBy: "impersonated_by" } },
521
+ user: { fields: {
522
+ banExpires: "ban_expires",
523
+ banReason: "ban_reason",
524
+ banned: "banned",
525
+ role: "role"
526
+ } }
527
+ }
528
+ })],
529
+ secret: options.secret
530
+ };
531
+ }
532
+ function createCmsBetterAuth(options, activity) {
533
+ return betterAuth(createCmsBetterAuthOptions(options, activity));
534
+ }
535
+ function hiddenChangeField(fieldName) {
536
+ return {
537
+ fieldName,
538
+ input: false,
539
+ required: false,
540
+ returned: false,
541
+ type: "string"
542
+ };
543
+ }
544
+
545
+ //#endregion
40
546
  //#region ../server/src/internal/activity/activity-storage.ts
41
547
  var ActivityStore = class extends Context.Service()("@internal/server/ActivityStore") {};
42
548
 
@@ -683,63 +1189,6 @@ function appliedResolution(change, intent, userId) {
683
1189
  };
684
1190
  }
685
1191
 
686
- //#endregion
687
- //#region ../auth/src/internal/user.ts
688
- const cmsUserCreationChangeField = "cmsCreationChangeId";
689
- const cmsUserSessionsRevokedChangeField = "cmsSessionsRevokedChangeId";
690
- const BetterAuthUser = Schema.Struct({
691
- banned: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),
692
- createdAt: Schema.Date,
693
- email: Schema.String,
694
- emailVerified: Schema.Boolean,
695
- id: Schema.String,
696
- name: Schema.String,
697
- role: Schema.optionalKey(Schema.NullOr(Schema.String)),
698
- updatedAt: Schema.Date
699
- });
700
- const BetterAuthUserRecoveryEvidence = Schema.Struct({
701
- [cmsUserCreationChangeField]: Schema.optionalKey(Schema.UndefinedOr(Schema.NullOr(ActivityId))),
702
- [cmsUserSessionsRevokedChangeField]: Schema.optionalKey(Schema.UndefinedOr(Schema.NullOr(ActivityId)))
703
- });
704
- function decodeBetterAuthUser(value) {
705
- return Schema.decodeEffect(BetterAuthUser)(value).pipe(Effect.flatMap((user) => Schema.decodeUnknownEffect(User)({
706
- banned: user.banned === true,
707
- createdAt: user.createdAt.toISOString(),
708
- email: user.email,
709
- emailVerified: user.emailVerified,
710
- id: user.id,
711
- name: user.name,
712
- role: user.role,
713
- updatedAt: user.updatedAt.toISOString()
714
- })));
715
- }
716
- function decodeBetterAuthActor(user) {
717
- return Schema.decodeEffect(StudioActor)(betterAuthActorInput(user));
718
- }
719
- function decodeBetterAuthActorOption(user) {
720
- return Schema.decodeOption(StudioActor)(betterAuthActorInput(user));
721
- }
722
- function decodeBetterAuthUserCreationChangeId(user) {
723
- return decodeChangeId(user, cmsUserCreationChangeField);
724
- }
725
- function decodeBetterAuthUserSessionsRevokedChangeId(user) {
726
- return decodeChangeId(user, cmsUserSessionsRevokedChangeField);
727
- }
728
- function decodeChangeId(user, field) {
729
- return Schema.decodeEffect(BetterAuthUserRecoveryEvidence)(user).pipe(Effect.map((evidence) => evidence[field] ?? null));
730
- }
731
- function betterAuthProviderRoles(value) {
732
- return value ? [...new Set(value.split(",").map((role) => role.trim()).filter(Boolean))] : [];
733
- }
734
- function betterAuthActorInput(user) {
735
- return {
736
- email: user.email,
737
- id: user.id,
738
- name: user.name,
739
- roles: betterAuthProviderRoles(user.role)
740
- };
741
- }
742
-
743
1192
  //#endregion
744
1193
  //#region ../auth/src/internal/activity-hooks.ts
745
1194
  function betterAuthActivityWriter(storage, crypto) {
@@ -790,141 +1239,14 @@ function activityDraft(action, actor, requestId) {
790
1239
  },
791
1240
  details: {},
792
1241
  target: {
793
- kind: "user",
794
- userId: actor.id
795
- }
796
- });
797
- }
798
- function decodeActor(user) {
799
- const option = decodeBetterAuthActorOption(user);
800
- return Option.getOrUndefined(option);
801
- }
802
-
803
- //#endregion
804
- //#region ../auth/src/internal/better-auth.ts
805
- const cmsBetterAuthAccess = createAccessControl(defaultStatements);
806
- const cmsBetterAuthRoles = {
807
- administrator: cmsBetterAuthAccess.newRole({
808
- session: ["list", "revoke"],
809
- user: [
810
- "create",
811
- "list",
812
- "get",
813
- "set-role",
814
- "delete",
815
- "update"
816
- ]
817
- }),
818
- editor: cmsBetterAuthAccess.newRole({
819
- session: [],
820
- user: []
821
- }),
822
- viewer: cmsBetterAuthAccess.newRole({
823
- session: [],
824
- user: []
825
- })
826
- };
827
- const timestampFields = {
828
- createdAt: "created_at",
829
- updatedAt: "updated_at"
830
- };
831
- function createCmsBetterAuthOptions(options, activity) {
832
- return {
833
- advanced: { database: {
834
- generateId: "uuid",
835
- joins: true
836
- } },
837
- appName: "CMS Studio",
838
- basePath: options.basePath ?? "/api/cms/auth",
839
- baseURL: options.baseURL,
840
- database: options.database,
841
- emailAndPassword: {
842
- disableSignUp: true,
843
- enabled: true,
844
- ...activity?.emailAndPassword
845
- },
846
- hooks: activity?.hooks,
847
- user: {
848
- additionalFields: {
849
- [cmsUserCreationChangeField]: hiddenChangeField("cms_creation_change_id"),
850
- [cmsUserSessionsRevokedChangeField]: hiddenChangeField("cms_sessions_revoked_change_id")
851
- },
852
- modelName: "auth_users",
853
- fields: {
854
- ...timestampFields,
855
- emailVerified: "email_verified"
856
- }
857
- },
858
- session: {
859
- cookieCache: {
860
- enabled: false,
861
- strategy: "jwt"
862
- },
863
- modelName: "auth_sessions",
864
- fields: {
865
- ...timestampFields,
866
- expiresAt: "expires_at",
867
- ipAddress: "ip_address",
868
- userAgent: "user_agent",
869
- userId: "user_id"
870
- }
871
- },
872
- account: {
873
- modelName: "auth_accounts",
874
- fields: {
875
- accessToken: "access_token",
876
- accessTokenExpiresAt: "access_token_expires_at",
877
- accountId: "account_id",
878
- ...timestampFields,
879
- idToken: "id_token",
880
- providerId: "provider_id",
881
- refreshToken: "refresh_token",
882
- refreshTokenExpiresAt: "refresh_token_expires_at",
883
- userId: "user_id"
884
- }
885
- },
886
- verification: {
887
- modelName: "auth_verifications",
888
- fields: {
889
- ...timestampFields,
890
- expiresAt: "expires_at"
891
- }
892
- },
893
- rateLimit: {
894
- enabled: true,
895
- storage: "database",
896
- modelName: "auth_rate_limits",
897
- fields: { lastRequest: "last_request" }
898
- },
899
- plugins: [admin({
900
- ac: cmsBetterAuthAccess,
901
- adminRoles: ["administrator"],
902
- defaultRole: "editor",
903
- roles: cmsBetterAuthRoles,
904
- schema: {
905
- session: { fields: { impersonatedBy: "impersonated_by" } },
906
- user: { fields: {
907
- banExpires: "ban_expires",
908
- banReason: "ban_reason",
909
- banned: "banned",
910
- role: "role"
911
- } }
912
- }
913
- })],
914
- secret: options.secret
915
- };
916
- }
917
- function createCmsBetterAuth(options, activity) {
918
- return betterAuth(createCmsBetterAuthOptions(options, activity));
919
- }
920
- function hiddenChangeField(fieldName) {
921
- return {
922
- fieldName,
923
- input: false,
924
- required: false,
925
- returned: false,
926
- type: "string"
927
- };
1242
+ kind: "user",
1243
+ userId: actor.id
1244
+ }
1245
+ });
1246
+ }
1247
+ function decodeActor(user) {
1248
+ const option = decodeBetterAuthActorOption(user);
1249
+ return Option.getOrUndefined(option);
928
1250
  }
929
1251
 
930
1252
  //#endregion
@@ -4953,25 +5275,16 @@ function targetError(operation) {
4953
5275
  //#endregion
4954
5276
  //#region ../server/src/Forms.ts
4955
5277
  /** Only the currently published definition can authorize a submission. Never trust client rules. */
4956
- const submitForm = Effect.fn("Forms.submit")(function* (input, components, handlers) {
5278
+ const submitForm = Effect.fn("Forms.submit")(function* (input, components, handlers, request) {
4957
5279
  const document = yield* (yield* PublishedDocuments).read({
4958
5280
  kind: "id",
4959
5281
  documentId: input.documentId
4960
5282
  }).pipe(Effect.orElseSucceed(() => void 0));
4961
- if (!document) return FormResult.make({
4962
- status: "unavailable",
4963
- errors: {}
4964
- });
5283
+ if (!document) return FormResult.make({ status: "unavailable" });
4965
5284
  const form = documentForms(document, components).find((candidate) => JSON.stringify(candidate.nodePath) === JSON.stringify(input.nodePath));
4966
- if (!form || form.revision !== input.revision) return FormResult.make({
4967
- status: "stale",
4968
- errors: {}
4969
- });
5285
+ if (!form || form.revision !== input.revision) return FormResult.make({ status: "stale" });
4970
5286
  const handler = Object.hasOwn(handlers, form.name) ? handlers[form.name] : void 0;
4971
- if (!handler) return FormResult.make({
4972
- status: "unavailable",
4973
- errors: {}
4974
- });
5287
+ if (!handler) return FormResult.make({ status: "unavailable" });
4975
5288
  const fields = form.steps.flatMap((step) => step.fields);
4976
5289
  const errors = validateFormValues(fields, input.values);
4977
5290
  if (Object.keys(input.values).some((id) => !fields.some((field) => field.id === id))) errors._form = "The submission contains unknown answers.";
@@ -4980,17 +5293,32 @@ const submitForm = Effect.fn("Forms.submit")(function* (input, components, handl
4980
5293
  errors
4981
5294
  });
4982
5295
  const values = Object.fromEntries(fields.map((field) => [field.id, normalizedAnswer(Object.hasOwn(input.values, field.id) ? input.values[field.id] : void 0)]));
5296
+ const startedAt = yield* Clock.currentTimeMillis;
4983
5297
  return yield* Effect.tryPromise(() => Promise.resolve(handler({
4984
5298
  form,
5299
+ request,
4985
5300
  values
4986
- }))).pipe(Effect.as(FormResult.make({
4987
- status: "accepted",
4988
- errors: {}
4989
- })), Effect.orElseSucceed(() => FormResult.make({
4990
- status: "failed",
4991
- errors: {}
4992
- })));
5301
+ }))).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({
5302
+ documentId: String(form.documentId),
5303
+ durationMillis: Math.max(0, finishedAt - startedAt),
5304
+ form: form.name,
5305
+ requestId: request.id
5306
+ }))))), Effect.orElseSucceed(() => FormResult.make({ status: "failed" })));
4993
5307
  });
5308
+ function formResult(outcome, fields) {
5309
+ if (outcome.status === "accepted") return FormResult.make({
5310
+ status: "accepted",
5311
+ ...outcome.reference ? { reference: outcome.reference } : void 0
5312
+ });
5313
+ if (outcome.status === "unavailable") return FormResult.make({ status: "unavailable" });
5314
+ const fieldIds = new Set(fields.map((field) => field.id));
5315
+ const errors = Object.fromEntries(Object.entries(outcome.errors).filter(([field]) => field === "_form" || fieldIds.has(field)));
5316
+ if (Object.keys(outcome.errors).some((field) => field !== "_form" && !fieldIds.has(field)) && !errors._form) errors._form = "The submission could not be accepted.";
5317
+ return FormResult.make({
5318
+ status: "invalid",
5319
+ errors
5320
+ });
5321
+ }
4994
5322
  function normalizedAnswer(value) {
4995
5323
  return value === void 0 || Predicate.isString(value) && !value.trim() ? null : value;
4996
5324
  }
@@ -5006,12 +5334,18 @@ function formsApiLayer(components, handlers) {
5006
5334
  limit: 60,
5007
5335
  window: "1 minute",
5008
5336
  onExceeded: "fail"
5009
- }).pipe(Effect.andThen(submitForm(payload, components, handlers).pipe(Effect.provideService(PublishedDocuments, documents))), Effect.orElseSucceed(() => FormResult.make({
5010
- status: "unavailable",
5011
- errors: {}
5012
- }))));
5337
+ }).pipe(Effect.andThen(Effect.gen(function* () {
5338
+ const request = {
5339
+ id: requestId(),
5340
+ submittedAt: DateTime.toDate(DateTime.makeUnsafe(yield* Clock.currentTimeMillis))
5341
+ };
5342
+ return yield* submitForm(payload, components, handlers, request);
5343
+ }).pipe(Effect.provideService(PublishedDocuments, documents))), Effect.orElseSucceed(() => FormResult.make({ status: "unavailable" }))));
5013
5344
  })).pipe(Layer.provide(RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))));
5014
5345
  }
5346
+ function requestId() {
5347
+ return globalThis.crypto.randomUUID();
5348
+ }
5015
5349
 
5016
5350
  //#endregion
5017
5351
  //#region ../platform-node/src/internal/http/errors.ts
@@ -5398,13 +5732,6 @@ function createCmsInstallationLayer(options) {
5398
5732
  });
5399
5733
  }
5400
5734
 
5401
- //#endregion
5402
- //#region ../sql-pg/src/internal/database/table-helpers.ts
5403
- const transactionTimestamp = sql`transaction_timestamp()`;
5404
- function isOneOf(column, values) {
5405
- return sql`${column} in (${sql.join(values.map((value) => sql`${value}`), sql`, `)})`;
5406
- }
5407
-
5408
5735
  //#endregion
5409
5736
  //#region ../sql-pg/src/internal/activity/tables.ts
5410
5737
  const ACTIVITY_TARGET_KINDS = [
@@ -5896,227 +6223,6 @@ function changeJournalUnavailable(operation, cause) {
5896
6223
  });
5897
6224
  }
5898
6225
 
5899
- //#endregion
5900
- //#region ../sql-pg/src/internal/database/embedded-migrations.generated.ts
5901
- const embeddedMigrations = [
5902
- {
5903
- sql: [
5904
- "CREATE TABLE \"activity_entries\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"action\" text NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"target_kind\" text NOT NULL,\n \"target_id\" text,\n \"details\" jsonb DEFAULT '{}' NOT NULL,\n \"occurred_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"activity_entries_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset')),\n CONSTRAINT \"activity_entries_target_kind_check\" CHECK (\"target_kind\" in ('document', 'media', 'media-library', 'user')),\n CONSTRAINT \"activity_entries_target_check\" CHECK ((\"target_kind\" = 'media-library' AND \"target_id\" IS NULL)\n OR (\"target_kind\" <> 'media-library' AND \"target_id\" IS NOT NULL)),\n CONSTRAINT \"activity_entries_actor_roles_check\" CHECK (jsonb_typeof(\"actor_roles\") = 'array'),\n CONSTRAINT \"activity_entries_details_check\" CHECK (jsonb_typeof(\"details\") = 'object')\n);\n",
5905
- "\nCREATE TABLE \"auth_accounts\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"issuer\" text NOT NULL,\n \"account_id\" text NOT NULL,\n \"provider_id\" text NOT NULL,\n \"user_id\" uuid NOT NULL,\n \"access_token\" text,\n \"refresh_token\" text,\n \"id_token\" text,\n \"access_token_expires_at\" timestamp with time zone,\n \"refresh_token_expires_at\" timestamp with time zone,\n \"scope\" text,\n \"password\" text,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
5906
- "\nCREATE TABLE \"auth_rate_limits\" (\n \"key\" text PRIMARY KEY,\n \"count\" bigint NOT NULL,\n \"last_request\" bigint NOT NULL\n);\n",
5907
- "\nCREATE TABLE \"auth_sessions\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"expires_at\" timestamp with time zone NOT NULL,\n \"token\" text NOT NULL UNIQUE,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"ip_address\" text,\n \"user_agent\" text,\n \"user_id\" uuid NOT NULL,\n \"impersonated_by\" text\n);\n",
5908
- "\nCREATE TABLE \"auth_users\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"name\" text NOT NULL,\n \"email\" text NOT NULL UNIQUE,\n \"email_verified\" boolean DEFAULT false NOT NULL,\n \"image\" text,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"role\" text DEFAULT 'editor' NOT NULL,\n \"banned\" boolean DEFAULT false NOT NULL,\n \"ban_reason\" text,\n \"ban_expires\" timestamp with time zone,\n \"cms_creation_change_id\" uuid UNIQUE,\n \"cms_sessions_revoked_change_id\" uuid UNIQUE,\n CONSTRAINT \"auth_users_role_check\" CHECK (\"role\" in ('administrator', 'editor', 'viewer'))\n);\n",
5909
- "\nCREATE TABLE \"auth_verifications\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"identifier\" text NOT NULL,\n \"value\" text NOT NULL,\n \"expires_at\" timestamp with time zone NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
5910
- "\nCREATE TABLE \"change_receipts\" (\n \"change_id\" uuid PRIMARY KEY,\n \"fingerprint\" text NOT NULL,\n \"outcome\" text NOT NULL,\n \"activity_id\" uuid UNIQUE,\n \"completed_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"change_receipts_outcome_check\" CHECK ((\"outcome\" = 'applied' AND \"activity_id\" IS NOT NULL)\n OR (\"outcome\" = 'cancelled' AND \"activity_id\" IS NULL))\n);\n",
5911
- "\nCREATE TABLE \"cms_state\" (\n \"singleton\" boolean PRIMARY KEY DEFAULT true,\n \"generation\" bigint DEFAULT 0 NOT NULL,\n CONSTRAINT \"cms_state_singleton_check\" CHECK (\"singleton\"),\n CONSTRAINT \"cms_state_generation_check\" CHECK (\"generation\" >= 0)\n);\n",
5912
- "\nCREATE TABLE \"document_heads\" (\n \"document_id\" uuid PRIMARY KEY,\n \"authored_revision_id\" uuid NOT NULL,\n \"published_revision_id\" uuid\n);\n",
5913
- "\nCREATE TABLE \"document_media_references\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"document_id\" uuid NOT NULL,\n \"object_key\" text NOT NULL,\n \"path\" text NOT NULL,\n \"source_path\" text NOT NULL,\n \"node_path\" integer[] NOT NULL,\n CONSTRAINT \"document_media_references_identity_unique\" UNIQUE(\"document_id\",\"source_path\",\"node_path\",\"object_key\"),\n CONSTRAINT \"document_media_references_object_key_check\" CHECK (char_length(\"object_key\") between 1 and 1024\n AND btrim(\"object_key\") = \"object_key\"\n AND \"object_key\" !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'\n AND position(chr(92) in \"object_key\") = 0),\n CONSTRAINT \"document_media_references_node_path_check\" CHECK (array_position(\"node_path\", NULL) IS NULL AND 0 <= ALL(\"node_path\"))\n);\n",
5914
- "\nCREATE TABLE \"document_revisions\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"document_id\" uuid NOT NULL,\n \"action\" text NOT NULL,\n \"source_path\" text NOT NULL,\n \"markdown\" text NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"activity_details\" jsonb DEFAULT '{}' NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"document_revisions_document_id_unique\" UNIQUE(\"document_id\",\"id\"),\n CONSTRAINT \"document_revisions_action_check\" CHECK (\"action\" in ('document.create', 'document.move', 'document.remove', 'document.restore', 'document.undelete', 'document.update'))\n);\n",
5915
- "\nCREATE TABLE \"documents\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"source_path\" text NOT NULL,\n \"deleted_at\" timestamp with time zone,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL\n);\n",
5916
- "\nCREATE TABLE \"initialization_state\" (\n \"singleton\" boolean PRIMARY KEY DEFAULT true,\n \"state\" text DEFAULT 'uninitialized' NOT NULL,\n \"change_id\" uuid,\n \"claim\" jsonb,\n CONSTRAINT \"initialization_state_singleton_check\" CHECK (\"singleton\"),\n CONSTRAINT \"initialization_state_state_check\" CHECK (\"state\" in ('uninitialized', 'claiming', 'ready')),\n CONSTRAINT \"initialization_state_claim_check\" CHECK ((\"state\" = 'claiming' AND \"change_id\" IS NOT NULL AND jsonb_typeof(\"claim\") = 'object')\n OR (\"state\" <> 'claiming' AND \"change_id\" IS NULL AND \"claim\" IS NULL))\n);\n",
5917
- "\nCREATE TABLE \"media_assets\" (\n \"id\" uuid PRIMARY KEY,\n \"object_key\" text NOT NULL UNIQUE,\n \"name\" text NOT NULL,\n \"folder\" text DEFAULT '' NOT NULL,\n \"mime_type\" text NOT NULL,\n \"byte_size\" bigint NOT NULL,\n \"status\" text DEFAULT 'uploading' NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"media_assets_byte_size_check\" CHECK (\"byte_size\" > 0 AND \"byte_size\" <= 9007199254740991),\n CONSTRAINT \"media_assets_mime_type_check\" CHECK (\"mime_type\" in ('image/avif', 'image/gif', 'image/jpeg', 'image/png', 'image/webp')),\n CONSTRAINT \"media_assets_status_check\" CHECK (\"status\" in ('uploading', 'ready', 'deleting')),\n CONSTRAINT \"media_assets_name_check\" CHECK (char_length(\"name\") between 1 and 255\n AND btrim(\"name\") = \"name\"\n AND \"name\" not in ('.', '..')\n AND \"name\" !~ '[[:cntrl:]/]'\n AND position(chr(92) in \"name\") = 0),\n CONSTRAINT \"media_assets_folder_check\" CHECK (char_length(\"folder\") <= 512\n AND btrim(\"folder\") = \"folder\"\n AND \"folder\" !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'\n AND position(chr(92) in \"folder\") = 0),\n CONSTRAINT \"media_assets_object_key_check\" CHECK (\"object_key\" ~ '^media/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.(avif|gif|jpg|png|webp)$')\n);\n",
5918
- "\nCREATE TABLE \"media_replacements\" (\n \"media_id\" uuid PRIMARY KEY,\n \"object_key\" text NOT NULL,\n \"staging_object_key\" text NOT NULL UNIQUE,\n \"name\" text NOT NULL,\n \"folder\" text NOT NULL,\n \"mime_type\" text NOT NULL,\n \"byte_size\" bigint NOT NULL,\n \"staged\" boolean DEFAULT false NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"media_replacements_byte_size_check\" CHECK (\"byte_size\" > 0 AND \"byte_size\" <= 9007199254740991),\n CONSTRAINT \"media_replacements_mime_type_check\" CHECK (\"mime_type\" in ('image/avif', 'image/gif', 'image/jpeg', 'image/png', 'image/webp')),\n CONSTRAINT \"media_replacements_name_check\" CHECK (char_length(\"name\") between 1 and 255\n AND btrim(\"name\") = \"name\"\n AND \"name\" not in ('.', '..')\n AND \"name\" !~ '[[:cntrl:]/]'\n AND position(chr(92) in \"name\") = 0),\n CONSTRAINT \"media_replacements_folder_check\" CHECK (char_length(\"folder\") <= 512\n AND btrim(\"folder\") = \"folder\"\n AND \"folder\" !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'\n AND position(chr(92) in \"folder\") = 0),\n CONSTRAINT \"media_replacements_object_key_check\" CHECK (\"object_key\" ~ '^media/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.(avif|gif|jpg|png|webp)$'),\n CONSTRAINT \"media_replacements_staging_object_key_check\" CHECK (\"staging_object_key\" ~ '^media/replacements/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.(avif|gif|jpg|png|webp)$'),\n CONSTRAINT \"media_replacements_distinct_object_keys_check\" CHECK (\"staging_object_key\" <> \"object_key\")\n);\n",
5919
- "\nCREATE TABLE \"pending_changes\" (\n \"id\" uuid PRIMARY KEY,\n \"action\" text NOT NULL,\n \"subject\" text NOT NULL,\n \"scope\" text NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"target_kind\" text,\n \"target_id\" text,\n \"intent\" jsonb NOT NULL,\n \"fingerprint\" text NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"pending_changes_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset')),\n CONSTRAINT \"pending_changes_scope_check\" CHECK (\"scope\" in ('initialization', 'media', 'users')),\n CONSTRAINT \"pending_changes_subject_check\" CHECK (char_length(\"subject\") between 1 and 1024 AND btrim(\"subject\") = \"subject\"),\n CONSTRAINT \"pending_changes_actor_roles_check\" CHECK (jsonb_typeof(\"actor_roles\") = 'array'),\n CONSTRAINT \"pending_changes_intent_check\" CHECK (jsonb_typeof(\"intent\") = 'object'),\n CONSTRAINT \"pending_changes_target_check\" CHECK ((\"target_kind\" IS NULL AND \"target_id\" IS NULL)\n OR (\"target_kind\" = 'media-library' AND \"target_id\" IS NULL)\n OR (\"target_kind\" in ('document', 'media', 'user')\n AND \"target_id\" IS NOT NULL))\n);\n",
5920
- "\nCREATE TABLE \"working_document_publish_attempts\" (\n \"id\" uuid PRIMARY KEY,\n \"activity\" jsonb NOT NULL,\n \"document_id\" uuid NOT NULL,\n \"expected_generation\" uuid NOT NULL,\n \"expected_version\" uuid NOT NULL,\n \"high_watermark\" bigint NOT NULL,\n \"markdown_hash\" text NOT NULL,\n \"state\" bytea NOT NULL,\n \"state_vector\" bytea NOT NULL,\n \"checkpoint_version\" uuid,\n \"phase\" text DEFAULT 'pending' NOT NULL,\n \"failure\" text,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"working_document_publish_attempts_phase_check\" CHECK (\"phase\" in ('pending', 'checkpointed', 'published', 'failed')),\n CONSTRAINT \"working_document_publish_attempts_high_watermark_check\" CHECK (\"high_watermark\" between 0 and 9007199254740991),\n CONSTRAINT \"working_document_publish_attempts_markdown_hash_check\" CHECK (char_length(\"markdown_hash\") between 1 and 128),\n CONSTRAINT \"working_document_publish_attempts_state_check\" CHECK (octet_length(\"state\") > 0),\n CONSTRAINT \"working_document_publish_attempts_state_vector_check\" CHECK (octet_length(\"state_vector\") > 0),\n CONSTRAINT \"working_document_publish_attempts_payload_check\" CHECK ((\n \"phase\" = 'pending'\n AND \"checkpoint_version\" IS NULL\n AND \"failure\" IS NULL\n ) OR (\n \"phase\" in ('checkpointed', 'published')\n AND \"checkpoint_version\" IS NOT NULL\n AND \"failure\" IS NULL\n ) OR (\n \"phase\" = 'failed'\n AND \"checkpoint_version\" IS NULL\n AND char_length(\"failure\") between 1 and 128\n ))\n);\n",
5921
- "\nCREATE TABLE \"working_document_updates\" (\n \"document_id\" uuid,\n \"generation_id\" uuid NOT NULL,\n \"sequence\" bigint,\n \"update\" bytea NOT NULL,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"working_document_updates_pkey\" PRIMARY KEY(\"document_id\",\"sequence\"),\n CONSTRAINT \"working_document_updates_sequence_check\" CHECK (\"sequence\" between 1 and 9007199254740991),\n CONSTRAINT \"working_document_updates_update_check\" CHECK (octet_length(\"update\") > 0)\n);\n",
5922
- "\nCREATE TABLE \"working_documents\" (\n \"document_id\" uuid PRIMARY KEY,\n \"format_version\" integer NOT NULL,\n \"generation_id\" uuid NOT NULL,\n \"state\" bytea NOT NULL,\n \"saved_state_vector\" bytea NOT NULL,\n \"saved_version\" uuid NOT NULL,\n \"next_update_sequence\" bigint DEFAULT 1 NOT NULL,\n \"updated_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"working_documents_generation_unique\" UNIQUE(\"document_id\",\"generation_id\"),\n CONSTRAINT \"working_documents_format_version_check\" CHECK (\"format_version\" = 1),\n CONSTRAINT \"working_documents_state_check\" CHECK (octet_length(\"state\") > 0),\n CONSTRAINT \"working_documents_saved_state_vector_check\" CHECK (octet_length(\"saved_state_vector\") > 0),\n CONSTRAINT \"working_documents_next_update_sequence_check\" CHECK (\"next_update_sequence\" between 1 and 9007199254740991)\n);\n",
5923
- "\nCREATE INDEX \"activity_entries_history\" ON \"activity_entries\" (\"occurred_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
5924
- "\nCREATE INDEX \"activity_entries_actor\" ON \"activity_entries\" (\"actor_id\",\"occurred_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
5925
- "\nCREATE INDEX \"activity_entries_target\" ON \"activity_entries\" (\"target_kind\",\"target_id\",\"occurred_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
5926
- "\nCREATE INDEX \"activity_entries_request\" ON \"activity_entries\" (\"request_id\");",
5927
- "\nCREATE INDEX \"auth_accounts_user_id\" ON \"auth_accounts\" (\"user_id\");",
5928
- "\nCREATE UNIQUE INDEX \"auth_accounts_identity\" ON \"auth_accounts\" (\"issuer\",\"account_id\");",
5929
- "\nCREATE INDEX \"auth_sessions_user_id\" ON \"auth_sessions\" (\"user_id\");",
5930
- "\nCREATE INDEX \"auth_verifications_identifier\" ON \"auth_verifications\" (\"identifier\");",
5931
- "\nCREATE INDEX \"change_receipts_activity\" ON \"change_receipts\" (\"activity_id\");",
5932
- "\nCREATE INDEX \"document_media_references_object_key\" ON \"document_media_references\" (\"object_key\");",
5933
- "\nCREATE INDEX \"document_revisions_history\" ON \"document_revisions\" (\"document_id\",\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
5934
- "\nCREATE UNIQUE INDEX \"documents_active_path\" ON \"documents\" (\"source_path\") WHERE \"deleted_at\" is null;",
5935
- "\nCREATE INDEX \"media_assets_catalog\" ON \"media_assets\" (\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST) WHERE \"status\" = 'ready';",
5936
- "\nCREATE INDEX \"media_assets_folder\" ON \"media_assets\" (\"folder\",\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST) WHERE \"status\" = 'ready';",
5937
- "\nCREATE INDEX \"media_assets_recovery\" ON \"media_assets\" (\"updated_at\",\"id\") WHERE \"status\" <> 'ready';",
5938
- "\nCREATE INDEX \"media_replacements_recovery\" ON \"media_replacements\" (\"updated_at\",\"media_id\");",
5939
- "\nCREATE UNIQUE INDEX \"pending_changes_subject\" ON \"pending_changes\" (\"subject\");",
5940
- "\nCREATE INDEX \"pending_changes_recovery\" ON \"pending_changes\" (\"scope\",\"updated_at\",\"id\");",
5941
- "\nCREATE UNIQUE INDEX \"working_document_publish_attempts_active\" ON \"working_document_publish_attempts\" (\"document_id\") WHERE \"phase\" in ('pending', 'checkpointed');",
5942
- "\nCREATE INDEX \"working_document_publish_attempts_recovery\" ON \"working_document_publish_attempts\" (\"document_id\",\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
5943
- "\nALTER TABLE \"auth_accounts\" ADD CONSTRAINT \"auth_accounts_user_id_auth_users_id_fkey\" FOREIGN KEY (\"user_id\") REFERENCES \"auth_users\"(\"id\") ON DELETE CASCADE;",
5944
- "\nALTER TABLE \"auth_sessions\" ADD CONSTRAINT \"auth_sessions_user_id_auth_users_id_fkey\" FOREIGN KEY (\"user_id\") REFERENCES \"auth_users\"(\"id\") ON DELETE CASCADE;",
5945
- "\nALTER TABLE \"change_receipts\" ADD CONSTRAINT \"change_receipts_activity_id_activity_entries_id_fkey\" FOREIGN KEY (\"activity_id\") REFERENCES \"activity_entries\"(\"id\") ON DELETE RESTRICT;",
5946
- "\nALTER TABLE \"document_heads\" ADD CONSTRAINT \"document_heads_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE RESTRICT;",
5947
- "\nALTER TABLE \"document_heads\" ADD CONSTRAINT \"document_heads_authored_revision_fkey\" FOREIGN KEY (\"document_id\",\"authored_revision_id\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
5948
- "\nALTER TABLE \"document_heads\" ADD CONSTRAINT \"document_heads_published_revision_fkey\" FOREIGN KEY (\"document_id\",\"published_revision_id\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
5949
- "\nALTER TABLE \"document_media_references\" ADD CONSTRAINT \"document_media_references_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE CASCADE;",
5950
- "\nALTER TABLE \"document_revisions\" ADD CONSTRAINT \"document_revisions_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE RESTRICT;",
5951
- "\nALTER TABLE \"media_replacements\" ADD CONSTRAINT \"media_replacements_media_id_media_assets_id_fkey\" FOREIGN KEY (\"media_id\") REFERENCES \"media_assets\"(\"id\") ON DELETE RESTRICT;",
5952
- "\nALTER TABLE \"working_document_publish_attempts\" ADD CONSTRAINT \"working_document_publish_attempts_document_generation_fkey\" FOREIGN KEY (\"document_id\",\"expected_generation\") REFERENCES \"working_documents\"(\"document_id\",\"generation_id\") ON DELETE CASCADE;",
5953
- "\nALTER TABLE \"working_document_publish_attempts\" ADD CONSTRAINT \"working_document_publish_attempts_expected_version_fkey\" FOREIGN KEY (\"document_id\",\"expected_version\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
5954
- "\nALTER TABLE \"working_document_publish_attempts\" ADD CONSTRAINT \"working_document_publish_attempts_checkpoint_version_fkey\" FOREIGN KEY (\"document_id\",\"checkpoint_version\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;",
5955
- "\nALTER TABLE \"working_document_updates\" ADD CONSTRAINT \"working_document_updates_document_generation_fkey\" FOREIGN KEY (\"document_id\",\"generation_id\") REFERENCES \"working_documents\"(\"document_id\",\"generation_id\") ON DELETE CASCADE;",
5956
- "\nALTER TABLE \"working_documents\" ADD CONSTRAINT \"working_documents_document_id_documents_id_fkey\" FOREIGN KEY (\"document_id\") REFERENCES \"documents\"(\"id\") ON DELETE CASCADE;",
5957
- "\nALTER TABLE \"working_documents\" ADD CONSTRAINT \"working_documents_saved_version_fkey\" FOREIGN KEY (\"document_id\",\"saved_version\") REFERENCES \"document_revisions\"(\"document_id\",\"id\") ON DELETE RESTRICT;"
5958
- ],
5959
- bps: true,
5960
- folderMillis: 1788466567e3,
5961
- hash: "943a4996ef8c4324bd58280a80103e5a1632b088880164904b3857686e26f33e",
5962
- name: "20260903201607_cms_baseline"
5963
- },
5964
- {
5965
- sql: [
5966
- "ALTER TABLE \"auth_rate_limits\" ADD COLUMN \"id\" uuid DEFAULT gen_random_uuid();",
5967
- "\nALTER TABLE \"auth_rate_limits\" DROP CONSTRAINT \"auth_rate_limits_pkey\";",
5968
- "\nALTER TABLE \"auth_rate_limits\" ADD PRIMARY KEY (\"id\");",
5969
- "\nALTER TABLE \"auth_rate_limits\" ADD CONSTRAINT \"auth_rate_limits_key_key\" UNIQUE(\"key\");"
5970
- ],
5971
- bps: true,
5972
- folderMillis: 1788587191e3,
5973
- hash: "78b837c6b72a3de22d68e8db90bd211e61a0b97ff29bf8d16a0bba245eefa7ed",
5974
- name: "20260905054631_burly_northstar"
5975
- },
5976
- {
5977
- sql: ["ALTER TABLE \"auth_accounts\" DROP COLUMN \"issuer\";", "\nCREATE UNIQUE INDEX \"auth_accounts_identity\" ON \"auth_accounts\" (\"provider_id\",\"account_id\");"],
5978
- bps: true,
5979
- folderMillis: 178875937e4,
5980
- hash: "e442485fa6c2d611e3dae508a12d245481bc5ec8f2dd4f5d853910df34484787",
5981
- name: "20260907053610_fancy_lady_deathstrike"
5982
- },
5983
- {
5984
- sql: ["ALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_action_check\", ADD CONSTRAINT \"activity_entries_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));", "\nALTER TABLE \"pending_changes\" DROP CONSTRAINT \"pending_changes_action_check\", ADD CONSTRAINT \"pending_changes_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));"],
5985
- bps: true,
5986
- folderMillis: 1788866265e3,
5987
- hash: "24c56a37796caf8d76c0a97128a382b31e71808aa5b0ca7e5bac96795f9e16c7",
5988
- name: "20260908111745_classy_johnny_storm"
5989
- },
5990
- {
5991
- sql: [
5992
- "CREATE TABLE \"seo_media_references\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"scope\" text NOT NULL,\n \"media_id\" uuid NOT NULL,\n CONSTRAINT \"seo_media_references_scope_media_unique\" UNIQUE(\"scope\",\"media_id\"),\n CONSTRAINT \"seo_media_references_scope_check\" CHECK (\"scope\" in ('working', 'published'))\n);\n",
5993
- "\nCREATE TABLE \"seo_revisions\" (\n \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n \"settings\" jsonb NOT NULL,\n \"actor_id\" text NOT NULL,\n \"actor_email\" text NOT NULL,\n \"actor_name\" text NOT NULL,\n \"actor_roles\" jsonb NOT NULL,\n \"request_id\" uuid NOT NULL,\n \"reason\" text,\n \"created_at\" timestamp with time zone DEFAULT transaction_timestamp() NOT NULL,\n CONSTRAINT \"seo_revisions_actor_roles_check\" CHECK (jsonb_typeof(\"actor_roles\") = 'array'),\n CONSTRAINT \"seo_revisions_settings_check\" CHECK (jsonb_typeof(\"settings\") = 'object')\n);\n",
5994
- "\nCREATE TABLE \"seo_state\" (\n \"singleton\" boolean PRIMARY KEY DEFAULT true,\n \"working_revision_id\" uuid NOT NULL,\n \"published_revision_id\" uuid NOT NULL,\n CONSTRAINT \"seo_state_singleton_check\" CHECK (\"singleton\")\n);\n",
5995
- "\nCREATE INDEX \"seo_media_references_media\" ON \"seo_media_references\" (\"media_id\");",
5996
- "\nCREATE INDEX \"seo_revisions_history\" ON \"seo_revisions\" (\"created_at\" DESC NULLS LAST,\"id\" DESC NULLS LAST);",
5997
- "\nALTER TABLE \"seo_media_references\" ADD CONSTRAINT \"seo_media_references_media_id_media_assets_id_fkey\" FOREIGN KEY (\"media_id\") REFERENCES \"media_assets\"(\"id\") ON DELETE RESTRICT;",
5998
- "\nALTER TABLE \"seo_state\" ADD CONSTRAINT \"seo_state_working_revision_fkey\" FOREIGN KEY (\"working_revision_id\") REFERENCES \"seo_revisions\"(\"id\") ON DELETE RESTRICT;",
5999
- "\nALTER TABLE \"seo_state\" ADD CONSTRAINT \"seo_state_published_revision_fkey\" FOREIGN KEY (\"published_revision_id\") REFERENCES \"seo_revisions\"(\"id\") ON DELETE RESTRICT;",
6000
- "\nALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_action_check\", ADD CONSTRAINT \"activity_entries_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'seo.saved', 'seo.published', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));",
6001
- "\nALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_target_kind_check\", ADD CONSTRAINT \"activity_entries_target_kind_check\" CHECK (\"target_kind\" in ('document', 'media', 'media-library', 'seo', 'user'));",
6002
- "\nALTER TABLE \"activity_entries\" DROP CONSTRAINT \"activity_entries_target_check\", ADD CONSTRAINT \"activity_entries_target_check\" CHECK ((\"target_kind\" in ('media-library', 'seo') AND \"target_id\" IS NULL)\n OR (\"target_kind\" not in ('media-library', 'seo') AND \"target_id\" IS NOT NULL));",
6003
- "\nALTER TABLE \"pending_changes\" DROP CONSTRAINT \"pending_changes_action_check\", ADD CONSTRAINT \"pending_changes_action_check\" CHECK (\"action\" in ('document.created', 'document.updated', 'document.moved', 'document.trashed', 'document.revision.restored', 'document.untrashed', 'document.published', 'document.unpublished', 'media.uploaded', 'media.replaced', 'media.removed', 'media.cleaned', 'seo.saved', 'seo.published', 'user.created', 'user.removed', 'user.role.changed', 'user.sessions.revoked', 'authentication.signed-in', 'authentication.signed-out', 'authentication.password.changed', 'authentication.password.reset'));"
6004
- ],
6005
- bps: true,
6006
- folderMillis: 1789233351e3,
6007
- hash: "8e6a6abf5385ab3ecf8eb083c1923ac9c74d72aa71bd1d444b7402d3e7e77000",
6008
- name: "20260912171551_charming_valkyrie"
6009
- }
6010
- ];
6011
-
6012
- //#endregion
6013
- //#region ../sql-pg/src/internal/documents/tables.ts
6014
- const cmsState = pgTable("cms_state", {
6015
- singleton: boolean().default(true).primaryKey(),
6016
- generation: bigint({ mode: "bigint" }).default(sql`0`).notNull()
6017
- }, (table) => [check("cms_state_singleton_check", sql`${table.singleton}`), check("cms_state_generation_check", sql`${table.generation} >= 0`)]);
6018
- const documentsTable = pgTable("documents", {
6019
- id: uuid().defaultRandom().primaryKey(),
6020
- sourcePath: text("source_path").notNull(),
6021
- deletedAt: timestamp("deleted_at", {
6022
- mode: "string",
6023
- withTimezone: true
6024
- }),
6025
- createdAt: timestamp("created_at", {
6026
- mode: "string",
6027
- withTimezone: true
6028
- }).default(transactionTimestamp).notNull(),
6029
- updatedAt: timestamp("updated_at", {
6030
- mode: "string",
6031
- withTimezone: true
6032
- }).default(transactionTimestamp).notNull()
6033
- }, (table) => [uniqueIndex("documents_active_path").on(table.sourcePath).where(sql`${table.deletedAt} is null`)]);
6034
- const documentRevisions = pgTable("document_revisions", {
6035
- id: uuid().defaultRandom().primaryKey(),
6036
- documentId: uuid("document_id").notNull().references(() => documentsTable.id, { onDelete: "restrict" }),
6037
- action: text({ enum: DOCUMENT_REVISION_ACTIONS }).notNull(),
6038
- sourcePath: text("source_path").notNull(),
6039
- markdown: text().notNull(),
6040
- actorId: text("actor_id").notNull(),
6041
- actorEmail: text("actor_email").notNull(),
6042
- actorName: text("actor_name").notNull(),
6043
- actorRoles: jsonb("actor_roles").$type().notNull(),
6044
- requestId: uuid("request_id").notNull(),
6045
- reason: text(),
6046
- activityDetails: jsonb("activity_details").$type().default({}).notNull(),
6047
- createdAt: timestamp("created_at", {
6048
- mode: "string",
6049
- withTimezone: true
6050
- }).default(transactionTimestamp).notNull()
6051
- }, (table) => [
6052
- check("document_revisions_action_check", isOneOf(table.action, DOCUMENT_REVISION_ACTIONS)),
6053
- unique("document_revisions_document_id_unique").on(table.documentId, table.id),
6054
- index("document_revisions_history").on(table.documentId, table.createdAt.desc(), table.id.desc())
6055
- ]);
6056
- const documentHeads = pgTable("document_heads", {
6057
- documentId: uuid("document_id").primaryKey().references(() => documentsTable.id, { onDelete: "restrict" }),
6058
- authoredRevisionId: uuid("authored_revision_id").notNull(),
6059
- publishedRevisionId: uuid("published_revision_id")
6060
- }, (table) => [foreignKey({
6061
- columns: [table.documentId, table.authoredRevisionId],
6062
- foreignColumns: [documentRevisions.documentId, documentRevisions.id],
6063
- name: "document_heads_authored_revision_fkey"
6064
- }).onDelete("restrict"), foreignKey({
6065
- columns: [table.documentId, table.publishedRevisionId],
6066
- foreignColumns: [documentRevisions.documentId, documentRevisions.id],
6067
- name: "document_heads_published_revision_fkey"
6068
- }).onDelete("restrict")]);
6069
- const documentMediaReferences = pgTable("document_media_references", {
6070
- id: uuid().defaultRandom().primaryKey(),
6071
- documentId: uuid("document_id").notNull().references(() => documentsTable.id, { onDelete: "cascade" }),
6072
- objectKey: text("object_key").notNull(),
6073
- path: text().notNull(),
6074
- sourcePath: text("source_path").notNull(),
6075
- nodePath: integer("node_path").array().notNull()
6076
- }, (table) => [
6077
- unique("document_media_references_identity_unique").on(table.documentId, table.sourcePath, table.nodePath, table.objectKey),
6078
- check("document_media_references_object_key_check", sql`char_length(${table.objectKey}) between 1 and 1024
6079
- AND btrim(${table.objectKey}) = ${table.objectKey}
6080
- AND ${table.objectKey} !~ '(^/|/$|//|(^|/)\\.{1,2}(/|$)|[[:cntrl:]])'
6081
- AND position(chr(92) in ${table.objectKey}) = 0`),
6082
- check("document_media_references_node_path_check", sql`array_position(${table.nodePath}, NULL) IS NULL AND 0 <= ALL(${table.nodePath})`),
6083
- index("document_media_references_object_key").on(table.objectKey)
6084
- ]);
6085
-
6086
- //#endregion
6087
- //#region ../sql-pg/src/internal/initialization/tables.ts
6088
- const INITIALIZATION_STATES = [
6089
- "uninitialized",
6090
- "claiming",
6091
- "ready"
6092
- ];
6093
- const initializationState = pgTable("initialization_state", {
6094
- singleton: boolean().default(true).primaryKey(),
6095
- state: text({ enum: INITIALIZATION_STATES }).default("uninitialized").notNull(),
6096
- changeId: uuid("change_id"),
6097
- claim: jsonb().$type()
6098
- }, (table) => [
6099
- check("initialization_state_singleton_check", sql`${table.singleton}`),
6100
- check("initialization_state_state_check", isOneOf(table.state, INITIALIZATION_STATES)),
6101
- check("initialization_state_claim_check", sql`(${table.state} = 'claiming' AND ${table.changeId} IS NOT NULL AND jsonb_typeof(${table.claim}) = 'object')
6102
- OR (${table.state} <> 'claiming' AND ${table.changeId} IS NULL AND ${table.claim} IS NULL)`)
6103
- ]);
6104
-
6105
- //#endregion
6106
- //#region ../sql-pg/src/internal/database/migrations.ts
6107
- const MIGRATION_LOCK_KEY = "cms:database-migrations:v1";
6108
- const migrateCmsDatabase = Effect.fn("CmsDatabase.migrate")(function* () {
6109
- const postgres = yield* PgClient.PgClient;
6110
- const database = yield* PgDrizzle.makeWithDefaults();
6111
- yield* postgres.withTransaction(Effect.gen(function* () {
6112
- yield* postgres.unsafe("select pg_advisory_xact_lock(hashtextextended($1, 0))", [MIGRATION_LOCK_KEY]);
6113
- yield* migrate(embeddedMigrations, database._.session, "__drizzle_migrations");
6114
- yield* database.insert(cmsState).values({}).onConflictDoNothing({ target: cmsState.singleton });
6115
- yield* database.insert(initializationState).values({}).onConflictDoNothing({ target: initializationState.singleton });
6116
- }));
6117
- });
6118
- const cmsDatabaseMigrationLayer = Layer.effectDiscard(migrateCmsDatabase());
6119
-
6120
6226
  //#endregion
6121
6227
  //#region ../sql-pg/src/internal/documents/commands.ts
6122
6228
  const isEffectDrizzleQueryError = Schema.is(EffectDrizzleQueryError);
@@ -8078,21 +8184,32 @@ function notifyWorkingDocumentChange(database, kind, documentId, generationId) {
8078
8184
  * Mutations that span seams remain transactions inside this adapter.
8079
8185
  */
8080
8186
  function postgresLayer(options) {
8081
- const database = PgClient.layer({
8082
- ...options,
8187
+ const { schema, ...poolOptions } = options;
8188
+ const clientOptions = {
8189
+ ...poolOptions,
8083
8190
  applicationName: options.applicationName ?? "@internal/sql-pg"
8084
- });
8085
- const migrations = cmsDatabaseMigrationLayer.pipe(Layer.provide(database));
8086
- const locks = postgresAdvisoryLockLayer(options);
8087
- return Layer.mergeAll(postgresActivityStoreLayer, changeJournalLayer, documentStoreLayer, mediaStoreLayer, seoStoreLayer, initializationStoreLayer.pipe(Layer.provide(locks)), postgresUserCommandFenceLayer.pipe(Layer.provide(locks)), postgresWorkingDocumentChangesLayer(options), workingDocumentStoreLayer).pipe(Layer.provide(migrations), Layer.provide(database));
8191
+ };
8192
+ const database = schemaClientLayer(clientOptions, schema);
8193
+ const migrations = cmsDatabaseMigrationLayer(schema).pipe(Layer.provide(database));
8194
+ const locks = postgresAdvisoryLockLayer(poolOptions);
8195
+ 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));
8088
8196
  }
8089
8197
 
8090
8198
  //#endregion
8091
8199
  //#region src/runtime/installation.ts
8200
+ var DatabaseSchemaProvisionFailed = class extends Schema.TaggedError()("NuxtCmsInstallation.DatabaseSchemaProvisionFailed", {
8201
+ cause: Schema.Defect(),
8202
+ schema: Schema.String
8203
+ }) {};
8092
8204
  const installCms = Effect.fn("NuxtCmsInstallation.install")(function* (options) {
8205
+ yield* provisionDatabaseSchema(options.database);
8093
8206
  const crypto = NodeCrypto.layer;
8094
- const postgres = postgresLayer({ url: Redacted.make(options.databaseUrl) });
8095
- const identity = Layer.unwrap(Effect.acquireRelease(Effect.sync(() => new Pool({ connectionString: options.databaseUrl })), (pool) => Effect.promise(() => pool.end()).pipe(Effect.asVoid)).pipe(Effect.map((pool) => betterAuthLayer({
8207
+ const databaseUrl = scopedDatabaseUrl(options.database);
8208
+ const postgres = postgresLayer({
8209
+ schema: options.database.schema,
8210
+ url: Redacted.make(options.database.url)
8211
+ });
8212
+ const identity = Layer.unwrap(Effect.acquireRelease(Effect.sync(() => new Pool({ connectionString: databaseUrl })), (pool) => Effect.promise(() => pool.end()).pipe(Effect.asVoid)).pipe(Effect.map((pool) => betterAuthLayer({
8096
8213
  baseURL: options.baseUrl,
8097
8214
  database: pool,
8098
8215
  secret: `cms-authentication:${options.secret}`
@@ -8119,6 +8236,16 @@ const installCms = Effect.fn("NuxtCmsInstallation.install")(function* (options)
8119
8236
  studioSecret: Redacted.make(`cms-collaboration:${options.secret}`)
8120
8237
  });
8121
8238
  });
8239
+ const provisionDatabaseSchema = Effect.fn("NuxtCmsInstallation.provisionDatabaseSchema")(function* (database) {
8240
+ const pool = new Pool({ connectionString: database.url });
8241
+ yield* Effect.tryPromise({
8242
+ try: () => pool.query(`create schema if not exists "${database.schema}"`),
8243
+ catch: (cause) => new DatabaseSchemaProvisionFailed({
8244
+ cause,
8245
+ schema: database.schema
8246
+ })
8247
+ }).pipe(Effect.ensuring(Effect.promise(() => pool.end())));
8248
+ });
8122
8249
  function toS3MediaObjectStoreOptions(options) {
8123
8250
  const { credentials: authoredCredentials, publicBaseUrl: _publicBaseUrl, ...storeOptions } = options;
8124
8251
  if (!authoredCredentials) return storeOptions;
@@ -8135,7 +8262,13 @@ function toS3MediaObjectStoreOptions(options) {
8135
8262
  credentials
8136
8263
  };
8137
8264
  }
8265
+ function scopedDatabaseUrl(database) {
8266
+ if (!/^[a-z_][a-z0-9_]{0,62}$/u.test(database.schema)) throw new Error("Invalid CMS PostgreSQL schema.");
8267
+ const url = new URL(database.url);
8268
+ url.searchParams.set("options", `-csearch_path=${database.schema}`);
8269
+ return url.href;
8270
+ }
8138
8271
 
8139
8272
  //#endregion
8140
- export { toS3MediaObjectStoreOptions as n, installCms as t };
8141
- //# sourceMappingURL=installation-CNfIriVm.js.map
8273
+ export { embeddedMigrations as a, createCmsBetterAuth as i, scopedDatabaseUrl as n, toS3MediaObjectStoreOptions as r, installCms as t };
8274
+ //# sourceMappingURL=installation-BNuoRDOz.js.map