@studiocms/migrator 0.0.0-beta.0 → 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/package.json +54 -7
  4. package/public/favicon.svg +5 -0
  5. package/src/components/ErrorCard.astro +20 -0
  6. package/src/components/MigrationMeta.astro +74 -0
  7. package/src/components/MigrationStatus.astro +71 -0
  8. package/src/components/PageHeader.astro +24 -0
  9. package/src/components/StatusTables.astro +45 -0
  10. package/src/db/astro-db-drizzle-client.ts +14 -0
  11. package/src/db/astro-db-schema.ts +193 -0
  12. package/src/db/astrodb.ts +88 -0
  13. package/src/db/client.ts +155 -0
  14. package/src/db/drizzle-schema.ts +54 -0
  15. package/src/env.d.ts +3 -0
  16. package/src/fonts/css/onest-variable.css +16 -0
  17. package/src/fonts/woff2/onest-variable.woff2 +0 -0
  18. package/src/layouts/Layout.astro +30 -0
  19. package/src/lib/astro-db-drizzle-compat/core-types.ts +88 -0
  20. package/src/lib/astro-db-drizzle-compat/error-map.ts +105 -0
  21. package/src/lib/astro-db-drizzle-compat/index.ts +149 -0
  22. package/src/lib/astro-db-drizzle-compat/schemas.ts +249 -0
  23. package/src/lib/astro-db-drizzle-compat/types.ts +141 -0
  24. package/src/lib/astro-db-drizzle-compat/utils.ts +55 -0
  25. package/src/lib/astro-db-drizzle-compat/virtual.ts +91 -0
  26. package/src/lib/errors.ts +57 -0
  27. package/src/lib/logger.ts +4 -0
  28. package/src/lib/remapUtils.ts +170 -0
  29. package/src/lib/response-utils.ts +12 -0
  30. package/src/lib/tableMap.ts +236 -0
  31. package/src/pages/data-migrations.ts +268 -0
  32. package/src/pages/index.astro +259 -0
  33. package/src/pages/schema-migrations.ts +31 -0
  34. package/src/styles/global.css +165 -0
  35. package/start.mjs +163 -0
  36. package/utils/logger.mjs +93 -0
  37. package/utils/resolver.mjs +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 StudioCMS - withstudiocms (https://github.com/withstudiocms)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @studiocms/migrator
2
+
3
+ Utility tool to ensure that all your content, configurations, and settings are preserved during the migration process to the latest version, allowing you to take advantage of the new features and improvements in StudioCMS without losing any of your valuable data.
4
+
5
+ ## Usage
6
+
7
+ Run the following command in the root of your StudioCMS project that contains the `.env` file as well as the `studiocms.config.*` config file.
8
+
9
+ ```sh
10
+ npx @studiocms/migrator
11
+ ```
12
+
13
+ ### Environment variable requirements
14
+
15
+ #### AstroDB
16
+
17
+ For migrating data from previous version you simply need your previous DB's env data.
18
+
19
+ ```sh
20
+ # AstroDB
21
+ ASTRO_DB_REMOTE_URL=libsql://your-old-database.turso.io
22
+ ASTRO_DB_APP_TOKEN=<your-auth-token>
23
+ ```
24
+
25
+ #### StudioCMS Database
26
+
27
+ For running this migrator you will need a fresh empty DB to work against. With the latest version's of StudioCMS, we now support libSQL, MySQL, and PostgreSQL.
28
+
29
+ ##### LibSQL
30
+
31
+ ```sh
32
+ # libSQL
33
+ CMS_LIBSQL_URL=libsql://your-new-database.turso.io or file:./path/to/your/database.db (required)
34
+ CMS_LIBSQL_AUTH_TOKEN=<your-auth-token> (optional)
35
+ CMS_LIBSQL_SYNC_INTERVAL= (optional)
36
+ CMS_LIBSQL_SYNC_URL= (optional)
37
+ ```
38
+
39
+ ##### MySQL
40
+
41
+ ```sh
42
+ # MySQL
43
+ CMS_MYSQL_DATABASE=<your-database-name>
44
+ CMS_MYSQL_USER=<your-database-user>
45
+ CMS_MYSQL_PASSWORD=<your-database-password>
46
+ CMS_MYSQL_HOST=<your-database-host>
47
+ CMS_MYSQL_PORT=<your-database-port>
48
+ ```
49
+
50
+ ##### PostgreSQL
51
+
52
+ ```sh
53
+ # PostgreSQL
54
+ CMS_PG_DATABASE=<your-database-name>
55
+ CMS_PG_USER=<your-database-user>
56
+ CMS_PG_PASSWORD=<your-database-password>
57
+ CMS_PG_HOST=<your-database-host>
58
+ CMS_PG_PORT=<your-database-port>
59
+ ```
60
+
61
+ ## License
62
+
63
+ [MIT License](./LICENSE)
package/package.json CHANGED
@@ -1,14 +1,61 @@
1
1
  {
2
2
  "name": "@studiocms/migrator",
3
- "version": "0.0.0-beta.0",
4
- "description": "",
5
- "publishConfig": {
6
- "access": "public"
3
+ "type": "module",
4
+ "version": "0.1.0-beta.1",
5
+ "description": "Tool for migrating from AstroDB based StudioCMS to Kysely based StudioCMS.",
6
+ "author": {
7
+ "name": "withstudiocms",
8
+ "url": "https://studiocms.dev"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/withstudiocms/studiocms.git",
13
+ "directory": "packages/@studiocms/migrator"
14
+ },
15
+ "contributors": [
16
+ "Adammatthiesen",
17
+ "jdtjenkins",
18
+ "dreyfus92",
19
+ "code.spirit"
20
+ ],
21
+ "bin": {
22
+ "studiocms-migrator": "./start.mjs",
23
+ "@studiocms/migrator": "./start.mjs"
7
24
  },
8
- "keywords": [],
9
- "author": "",
10
25
  "license": "MIT",
26
+ "homepage": "https://studiocms.dev",
27
+ "publishConfig": {
28
+ "access": "public",
29
+ "provenance": true
30
+ },
31
+ "sideEffects": false,
32
+ "files": [
33
+ "dist",
34
+ "src",
35
+ "utils",
36
+ "public",
37
+ "start.mjs"
38
+ ],
39
+ "devDependencies": {
40
+ "@types/node": "^22.0.0",
41
+ "typescript": "^5.9.3"
42
+ },
43
+ "dependencies": {
44
+ "@astrojs/node": "^9.5.1",
45
+ "@libsql/client": "^0.15.15",
46
+ "@studiocms/ui": "^1.0.0-beta.4",
47
+ "astro": "^5.16.4",
48
+ "dotenv": "^17.2.3",
49
+ "drizzle-orm": "^0.42.0",
50
+ "sharp": "^0.34.3",
51
+ "@withstudiocms/config-utils": "0.1.0-beta.5",
52
+ "@withstudiocms/effect": "0.1.0-beta.7",
53
+ "@withstudiocms/kysely": "0.1.0-beta.1"
54
+ },
55
+ "peerDependencies": {
56
+ "studiocms": "0.1.0-beta.31"
57
+ },
11
58
  "scripts": {
12
- "pre": "pnpm publish --tag beta"
59
+ "astro": "astro"
13
60
  }
14
61
  }
@@ -0,0 +1,5 @@
1
+ <svg width="755" height="792" viewBox="0 0 755 792" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="295" width="460" height="466" rx="32" fill="white"/>
3
+ <path d="M272 434V166H180C162.327 166 148 180.327 148 198V597C148 614.673 162.327 629 180 629H577.5C595.173 629 609.5 614.673 609.5 597V490H328C297.072 490 272 464.928 272 434Z" fill="white"/>
4
+ <path d="M124 597V329H32C14.3269 329 0 343.327 0 361V760C0 777.673 14.3269 792 32 792H429.5C447.173 792 461.5 777.673 461.5 760V653H180C149.072 653 124 627.928 124 597Z" fill="white"/>
5
+ </svg>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import { Card } from 'studiocms:ui/components/card';
3
+ import { Icon } from 'studiocms:ui/components/icon';
4
+
5
+ interface Props {
6
+ title: string;
7
+ description: string;
8
+ }
9
+
10
+ const { title, description } = Astro.props;
11
+ ---
12
+ <Card fullHeight fullWidth class="db-error-card">
13
+ <div slot="header">
14
+ <span class="error-header">
15
+ <Icon name="heroicons:exclamation-circle" height={24} width={24} />
16
+ <h2>{title}</h2>
17
+ </span>
18
+ </div>
19
+ <span>{description}</span>
20
+ </Card>
@@ -0,0 +1,74 @@
1
+ ---
2
+ import { Badge } from 'studiocms:ui/components/badge';
3
+ import { astroDBToKyselyMap, type MigrationMetaTables } from '../lib/tableMap.js';
4
+
5
+ interface Props {
6
+ migrationMetaData: MigrationMetaTables;
7
+ }
8
+
9
+ const { migrationMetaData } = Astro.props;
10
+ ---
11
+
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Table</th>
16
+ <th>AstroDB Records</th>
17
+ <th>StudioCMS Records</th>
18
+ <th>Status</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ {
23
+ Object.entries(migrationMetaData.astro).map(
24
+ ([tableName, astroCount]) => {
25
+ const kyselyCount =
26
+ migrationMetaData.kysely[
27
+ astroDBToKyselyMap[
28
+ tableName as keyof typeof astroDBToKyselyMap
29
+ ]
30
+ ] || 0;
31
+ const isMigrated =
32
+ astroCount === kyselyCount && astroCount > 0;
33
+
34
+ const isDualEmpty = astroCount === 0 && kyselyCount === 0;
35
+
36
+ return (
37
+ <tr class:list={[isDualEmpty ? "not-applicable" : ""]}>
38
+ <td>{tableName}</td>
39
+ <td>{astroCount}</td>
40
+ <td>{kyselyCount}</td>
41
+ <td>
42
+ {isDualEmpty ? (
43
+ <Badge
44
+ color="mono"
45
+ label="Not Applicable"
46
+ rounding="semi"
47
+ size="sm"
48
+ class="status"
49
+ />
50
+ ) : isMigrated ? (
51
+ <Badge
52
+ color="success"
53
+ label="Migrated"
54
+ rounding="semi"
55
+ size="sm"
56
+ class="status"
57
+ />
58
+ ) : (
59
+ <Badge
60
+ label="Pending"
61
+ color="warning"
62
+ rounding="semi"
63
+ size="sm"
64
+ class="status"
65
+ />
66
+ )}
67
+ </td>
68
+ </tr>
69
+ );
70
+ },
71
+ )
72
+ }
73
+ </tbody>
74
+ </table>
@@ -0,0 +1,71 @@
1
+ ---
2
+ import { Badge } from 'studiocms:ui/components/badge';
3
+ import type { MigrationInfo } from '@withstudiocms/kysely/kysely';
4
+
5
+ interface Props {
6
+ migrationStatus: readonly MigrationInfo[];
7
+ }
8
+
9
+ const { migrationStatus } = Astro.props;
10
+
11
+ /**
12
+ * Cleans up the migration name by removing timestamp prefixes and formatting.
13
+ *
14
+ * @param name - The original migration name.
15
+ * @returns The cleaned and formatted migration name.
16
+ */
17
+ const cleanName = (name: string) => {
18
+ const nameMatcher = name.match(/^\d{8}T\d{6}_(.+)$/);
19
+ const cleanName = nameMatcher ? nameMatcher[1] : name;
20
+
21
+ // Uppercase the first letter of each word and replace underscores with spaces
22
+ const formattedName = cleanName
23
+ .split('_')
24
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
25
+ .join(' ');
26
+ return formattedName;
27
+ };
28
+ ---
29
+
30
+ <table class="migration">
31
+ <thead>
32
+ <tr>
33
+ <th>Migration Name</th>
34
+ <th>Status</th>
35
+ <th>Executed At</th>
36
+ </tr>
37
+ </thead>
38
+ <tbody>
39
+ {
40
+ migrationStatus.map((migration) => (
41
+ <tr>
42
+ <td>{cleanName(migration.name)}</td>
43
+ <td>
44
+ {migration.executedAt ? (
45
+ <Badge
46
+ label="Applied"
47
+ color="success"
48
+ rounding="semi"
49
+ size="sm"
50
+ class="status"
51
+ />
52
+ ) : (
53
+ <Badge
54
+ label="Pending"
55
+ color="warning"
56
+ rounding="semi"
57
+ size="sm"
58
+ class="status"
59
+ />
60
+ )}
61
+ </td>
62
+ <td>
63
+ {migration.executedAt
64
+ ? new Date(migration.executedAt).toLocaleString()
65
+ : "N/A"}
66
+ </td>
67
+ </tr>
68
+ ))
69
+ }
70
+ </tbody>
71
+ </table>
@@ -0,0 +1,24 @@
1
+ ---
2
+ import { Card } from 'studiocms:ui/components/card';
3
+ ---
4
+ <Card variant='filled' fullWidth>
5
+ <div slot="header">
6
+ <div class="header-content">
7
+ <div class="header-logo">
8
+ <svg width="50" height="50" viewBox="0 0 755 792" fill="none" xmlns="http://www.w3.org/2000/svg">
9
+ <rect x="295" width="460" height="466" rx="32" fill="white"/>
10
+ <path d="M272 434V166H180C162.327 166 148 180.327 148 198V597C148 614.673 162.327 629 180 629H577.5C595.173 629 609.5 614.673 609.5 597V490H328C297.072 490 272 464.928 272 434Z" fill="white"/>
11
+ <path d="M124 597V329H32C14.3269 329 0 343.327 0 361V760C0 777.673 14.3269 792 32 792H429.5C447.173 792 461.5 777.673 461.5 760V653H180C149.072 653 124 627.928 124 597Z" fill="white"/>
12
+ </svg>
13
+ </div>
14
+ <div class="header-text">
15
+ <h1>StudioCMS Migrator Utility</h1>
16
+ <p class="prose">Migrate your data from previous AstroDB versions of StudioCMS to the new Kysely powered version</p>
17
+ </div>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="prose">
22
+ <span>This tool ensures that all your content, configurations, and settings are preserved during the migration process, allowing you to take advantage of the new features and improvements in StudioCMS without losing any of your valuable data.</span>
23
+ </div>
24
+ </Card>
@@ -0,0 +1,45 @@
1
+ ---
2
+ import { Badge } from 'studiocms:ui/components/badge';
3
+ import type { ComponentProps } from 'astro/types';
4
+
5
+ interface Props {
6
+ dbStatusTables: {
7
+ label: string;
8
+ conditions: {
9
+ label: string;
10
+ value: string;
11
+ color: ComponentProps<typeof Badge>['color'];
12
+ }[];
13
+ }[];
14
+ }
15
+
16
+ const { dbStatusTables } = Astro.props;
17
+ ---
18
+
19
+ {
20
+ dbStatusTables.map(({ label, conditions }) => (
21
+ <div class="split-screen-item">
22
+ <span class="status-label">{label}</span>
23
+ <table>
24
+ <tbody>
25
+ {conditions.map(
26
+ ({ label: conditionLabel, value, color }) => (
27
+ <tr>
28
+ <td>{conditionLabel}</td>
29
+ <td>
30
+ <Badge
31
+ label={value}
32
+ color={color}
33
+ rounding="semi"
34
+ size="sm"
35
+ class="status"
36
+ />
37
+ </td>
38
+ </tr>
39
+ ),
40
+ )}
41
+ </tbody>
42
+ </table>
43
+ </div>
44
+ ))
45
+ }
@@ -0,0 +1,14 @@
1
+ /** biome-ignore-all lint/style/noNonNullAssertion: This is okay */
2
+ import { createClient } from '@libsql/client';
3
+ import { drizzle } from 'drizzle-orm/libsql';
4
+ import * as schema from './drizzle-schema.js';
5
+
6
+ const client = createClient({
7
+ url: process.env.ASTRO_DB_REMOTE_URL!,
8
+ authToken: process.env.ASTRO_DB_APP_TOKEN!,
9
+ });
10
+
11
+ export const db = drizzle({ client, schema });
12
+
13
+ export * from '../lib/astro-db-drizzle-compat/virtual.js';
14
+ export * from './drizzle-schema.js';
@@ -0,0 +1,193 @@
1
+ import { column, defineTable, NOW } from '../lib/astro-db-drizzle-compat/virtual.js';
2
+
3
+ // Astro DB Configuration Tables for StudioCMS
4
+
5
+ // ====================================================
6
+ // Tables that do not require relationship definitions
7
+ // ====================================================
8
+
9
+ /** StudioCMS - Users Table for Astro DB */
10
+ export const StudioCMSUsers = defineTable({
11
+ columns: {
12
+ id: column.text({ primaryKey: true }),
13
+ url: column.text({ optional: true }),
14
+ name: column.text(),
15
+ email: column.text({ unique: true, optional: true }),
16
+ avatar: column.text({
17
+ optional: true,
18
+ default: 'https://seccdn.libravatar.org/static/img/mm/80.png',
19
+ }),
20
+ username: column.text(),
21
+ password: column.text({ optional: true }),
22
+ updatedAt: column.date({ default: NOW, optional: true }),
23
+ createdAt: column.date({ default: NOW, optional: true }),
24
+ emailVerified: column.boolean({ default: false }),
25
+ notifications: column.text({ optional: true }),
26
+ },
27
+ });
28
+
29
+ /** StudioCMS - Pages Data Table for Astro DB */
30
+ export const StudioCMSPageData = defineTable({
31
+ columns: {
32
+ id: column.text({ primaryKey: true }),
33
+ package: column.text({ default: 'studiocms' }),
34
+ title: column.text(),
35
+ description: column.text(),
36
+ showOnNav: column.boolean({ default: false }),
37
+ publishedAt: column.date({ default: NOW }),
38
+ updatedAt: column.date({ optional: true }),
39
+ slug: column.text(),
40
+ contentLang: column.text({ default: 'default' }),
41
+ heroImage: column.text({
42
+ default:
43
+ 'https://images.unsplash.com/photo-1707343843982-f8275f3994c5?q=80&w=1032&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
44
+ }),
45
+ categories: column.json({ default: [], optional: true }),
46
+ tags: column.json({ default: [], optional: true }),
47
+ authorId: column.text({ optional: true }),
48
+ contributorIds: column.json({ default: [], optional: true }),
49
+ showAuthor: column.boolean({ default: false, optional: true }),
50
+ showContributors: column.boolean({ default: false, optional: true }),
51
+ parentFolder: column.text({ optional: true }),
52
+ draft: column.boolean({ optional: true }),
53
+ },
54
+ });
55
+
56
+ /** StudioCMS - Page Folder Structure */
57
+ export const StudioCMSPageFolderStructure = defineTable({
58
+ columns: {
59
+ id: column.text({ primaryKey: true }),
60
+ name: column.text(),
61
+ parent: column.text({ optional: true }),
62
+ },
63
+ });
64
+
65
+ /** StudioCMS - Page Data Tags Table for Astro DB */
66
+ export const StudioCMSPageDataTags = defineTable({
67
+ columns: {
68
+ id: column.number({ primaryKey: true }),
69
+ description: column.text(),
70
+ name: column.text(),
71
+ slug: column.text(),
72
+ meta: column.json(),
73
+ },
74
+ });
75
+
76
+ /** StudioCMS - Page Data Categories Table for Astro DB */
77
+ export const StudioCMSPageDataCategories = defineTable({
78
+ columns: {
79
+ id: column.number({ primaryKey: true }),
80
+ parent: column.number({ optional: true }),
81
+ description: column.text(),
82
+ name: column.text(),
83
+ slug: column.text(),
84
+ meta: column.json(),
85
+ },
86
+ });
87
+
88
+ export const StudioCMSPluginData = defineTable({
89
+ columns: {
90
+ id: column.text({ primaryKey: true }),
91
+ data: column.json(),
92
+ },
93
+ });
94
+
95
+ /**
96
+ * StudioCMS - Dynamic Config Settings Table
97
+ *
98
+ * This table stores dynamic configuration settings for the StudioCMS application.
99
+ *
100
+ * @remarks
101
+ * This table is designed to store dynamic configuration settings that can be updated at runtime.
102
+ *
103
+ * Replaces:
104
+ * - `StudioCMSSiteConfig`
105
+ * - `StudioCMSMailerConfig`
106
+ * - `StudioCMSNotificationSettings`
107
+ */
108
+ export const StudioCMSDynamicConfigSettings = defineTable({
109
+ columns: {
110
+ id: column.text({ primaryKey: true }),
111
+ data: column.json(),
112
+ },
113
+ });
114
+
115
+ // ====================================================
116
+ // Tables that require relationship definitions
117
+ // ====================================================
118
+
119
+ export const StudioCMSAPIKeys = defineTable({
120
+ columns: {
121
+ id: column.text({ primaryKey: true }),
122
+ userId: column.text({ references: () => StudioCMSUsers.columns.id }),
123
+ key: column.text(),
124
+ creationDate: column.date({ default: NOW }),
125
+ description: column.text({ optional: true }),
126
+ },
127
+ });
128
+
129
+ export const StudioCMSUserResetTokens = defineTable({
130
+ columns: {
131
+ id: column.text({ primaryKey: true }),
132
+ userId: column.text({ references: () => StudioCMSUsers.columns.id }),
133
+ token: column.text(),
134
+ },
135
+ });
136
+
137
+ /** StudioCMS - OAuth Accounts Table for Astro DB */
138
+ export const StudioCMSOAuthAccounts = defineTable({
139
+ columns: {
140
+ provider: column.text(), // github, google, discord, auth0
141
+ providerUserId: column.text({ primaryKey: true }),
142
+ userId: column.text({ references: () => StudioCMSUsers.columns.id }),
143
+ },
144
+ });
145
+
146
+ /** StudioCMS - Session Table for Astro DB */
147
+ export const StudioCMSSessionTable = defineTable({
148
+ columns: {
149
+ id: column.text({ primaryKey: true }),
150
+ userId: column.text({ references: () => StudioCMSUsers.columns.id, optional: false }),
151
+ expiresAt: column.date(),
152
+ },
153
+ });
154
+
155
+ /** StudioCMS - Permissions Table for Astro DB */
156
+ export const StudioCMSPermissions = defineTable({
157
+ columns: {
158
+ user: column.text({ references: () => StudioCMSUsers.columns.id }),
159
+ rank: column.text({ enum: ['owner', 'admin', 'editor', 'visitor', 'unknown'] }),
160
+ },
161
+ });
162
+
163
+ /** StudioCMS - Diff Tracking Table for Astro DB */
164
+ export const StudioCMSDiffTracking = defineTable({
165
+ columns: {
166
+ id: column.text({ primaryKey: true }),
167
+ userId: column.text({ references: () => StudioCMSUsers.columns.id }),
168
+ pageId: column.text({ references: () => StudioCMSPageData.columns.id }),
169
+ timestamp: column.date({ default: NOW, optional: true }),
170
+ pageMetaData: column.json({ optional: true }),
171
+ pageContentStart: column.text({ multiline: true }),
172
+ diff: column.text({ multiline: true, optional: true }),
173
+ },
174
+ });
175
+
176
+ /** StudioCMS - Pages Content Table for Astro DB */
177
+ export const StudioCMSPageContent = defineTable({
178
+ columns: {
179
+ id: column.text({ primaryKey: true }),
180
+ contentId: column.text({ references: () => StudioCMSPageData.columns.id }),
181
+ contentLang: column.text({ default: 'default' }),
182
+ content: column.text({ multiline: true, optional: true }),
183
+ },
184
+ });
185
+
186
+ export const StudioCMSEmailVerificationTokens = defineTable({
187
+ columns: {
188
+ id: column.text({ primaryKey: true }),
189
+ userId: column.text({ references: () => StudioCMSUsers.columns.id }),
190
+ token: column.text(),
191
+ expiresAt: column.date(),
192
+ },
193
+ });