@astrojs/db 0.13.2-alpha.0 → 0.14.0

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.
@@ -2,7 +2,11 @@ import type { AstroConfig, AstroIntegration } from 'astro';
2
2
  import './types.js';
3
3
  export type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
4
4
  export declare function getAstroEnv(envMode?: string): Record<`ASTRO_${string}`, string>;
5
- export declare function getRemoteDatabaseUrl(): string;
5
+ export type RemoteDatabaseInfo = {
6
+ type: 'libsql' | 'studio';
7
+ url: string;
8
+ };
9
+ export declare function getRemoteDatabaseInfo(): RemoteDatabaseInfo;
6
10
  export declare function getDbDirectoryUrl(root: URL | string): URL;
7
11
  export declare function defineDbIntegration(integration: AstroIntegration): AstroIntegration;
8
12
  export type Result<T> = {
@@ -12,7 +12,6 @@ import { bgRed, cyan } from "kleur/colors";
12
12
  import ora from "ora";
13
13
  import prompts from "prompts";
14
14
  import { safeFetch } from "../../../../runtime/utils.js";
15
- import {} from "../../../utils.js";
16
15
  async function cmd() {
17
16
  const sessionToken = await getSessionIdFromFile();
18
17
  if (!sessionToken) {
@@ -1,6 +1,6 @@
1
1
  import type { AstroConfig } from 'astro';
2
2
  import type { Arguments } from 'yargs-parser';
3
- import { type DBConfig } from '../../../types.js';
3
+ import type { DBConfig } from '../../../types.js';
4
4
  export declare function cmd({ dbConfig, flags, }: {
5
5
  astroConfig: AstroConfig;
6
6
  dbConfig: DBConfig;
@@ -1,9 +1,10 @@
1
1
  import { getManagedAppTokenOrExit } from "@astrojs/studio";
2
+ import { sql } from "drizzle-orm";
2
3
  import prompts from "prompts";
4
+ import { createRemoteDatabaseClient } from "../../../../runtime/index.js";
3
5
  import { safeFetch } from "../../../../runtime/utils.js";
4
6
  import { MIGRATION_VERSION } from "../../../consts.js";
5
- import {} from "../../../types.js";
6
- import { getRemoteDatabaseUrl } from "../../../utils.js";
7
+ import { getRemoteDatabaseInfo } from "../../../utils.js";
7
8
  import {
8
9
  createCurrentSnapshot,
9
10
  createEmptySnapshot,
@@ -76,7 +77,32 @@ async function pushSchema({
76
77
  console.info("[DRY RUN] Batch query:", JSON.stringify(requestBody, null, 2));
77
78
  return new Response(null, { status: 200 });
78
79
  }
79
- const url = new URL("/db/push", getRemoteDatabaseUrl());
80
+ const dbInfo = getRemoteDatabaseInfo();
81
+ return dbInfo.type === "studio" ? pushToStudio(requestBody, appToken, dbInfo.url) : pushToDb(requestBody, appToken, dbInfo.url);
82
+ }
83
+ async function pushToDb(requestBody, appToken, remoteUrl) {
84
+ const client = createRemoteDatabaseClient({
85
+ dbType: "libsql",
86
+ appToken,
87
+ remoteUrl
88
+ });
89
+ await client.run(sql`create table if not exists _astro_db_snapshot (
90
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
91
+ version TEXT,
92
+ snapshot BLOB
93
+ );`);
94
+ await client.transaction(async (tx) => {
95
+ for (const stmt of requestBody.sql) {
96
+ await tx.run(sql.raw(stmt));
97
+ }
98
+ await tx.run(sql`insert into _astro_db_snapshot (version, snapshot) values (
99
+ ${requestBody.version},
100
+ ${JSON.stringify(requestBody.snapshot)}
101
+ )`);
102
+ });
103
+ }
104
+ async function pushToStudio(requestBody, appToken, remoteUrl) {
105
+ const url = new URL("/db/push", remoteUrl);
80
106
  const response = await safeFetch(
81
107
  url,
82
108
  {
@@ -7,7 +7,7 @@ import {
7
7
  import { normalizeDatabaseUrl } from "../../../../runtime/index.js";
8
8
  import { DB_PATH } from "../../../consts.js";
9
9
  import { SHELL_QUERY_MISSING_ERROR } from "../../../errors.js";
10
- import { getAstroEnv, getRemoteDatabaseUrl } from "../../../utils.js";
10
+ import { getAstroEnv, getRemoteDatabaseInfo } from "../../../utils.js";
11
11
  async function cmd({
12
12
  flags,
13
13
  astroConfig
@@ -17,9 +17,14 @@ async function cmd({
17
17
  console.error(SHELL_QUERY_MISSING_ERROR);
18
18
  process.exit(1);
19
19
  }
20
+ const dbInfo = getRemoteDatabaseInfo();
20
21
  if (flags.remote) {
21
22
  const appToken = await getManagedAppTokenOrExit(flags.token);
22
- const db = createRemoteDatabaseClient(appToken.token, getRemoteDatabaseUrl());
23
+ const db = createRemoteDatabaseClient({
24
+ dbType: dbInfo.type,
25
+ remoteUrl: dbInfo.url,
26
+ appToken: appToken.token
27
+ });
23
28
  const result = await db.run(sql.raw(query));
24
29
  await appToken.destroy();
25
30
  console.log(result);
@@ -29,7 +34,7 @@ async function cmd({
29
34
  ASTRO_DATABASE_FILE,
30
35
  new URL(DB_PATH, astroConfig.root).href
31
36
  );
32
- const db = createLocalDatabaseClient({ dbUrl });
37
+ const db = createLocalDatabaseClient({ dbUrl, enableTransations: dbInfo.type === "libsql" });
33
38
  const result = await db.run(sql.raw(query));
34
39
  console.log(result);
35
40
  }
@@ -1,4 +1,4 @@
1
- import { type DBConfig, type DBSnapshot, type ResolvedDBTable } from '../types.js';
1
+ import type { DBConfig, DBSnapshot, ResolvedDBTable } from '../types.js';
2
2
  export declare function getMigrationQueries({ oldSnapshot, newSnapshot, reset, }: {
3
3
  oldSnapshot: DBSnapshot;
4
4
  newSnapshot: DBSnapshot;
@@ -15,7 +15,7 @@ export declare function getTableChangeQueries({ tableName, oldTable, newTable, }
15
15
  queries: string[];
16
16
  confirmations: string[];
17
17
  }>;
18
- export declare function getProductionCurrentSnapshot({ appToken, }: {
18
+ export declare function getProductionCurrentSnapshot(options: {
19
19
  appToken: string;
20
20
  }): Promise<DBSnapshot | undefined>;
21
21
  export declare function createCurrentSnapshot({ tables }: DBConfig): DBSnapshot;
@@ -1,9 +1,11 @@
1
1
  import deepDiff from "deep-diff";
2
+ import { sql } from "drizzle-orm";
2
3
  import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
3
4
  import * as color from "kleur/colors";
4
5
  import { customAlphabet } from "nanoid";
5
6
  import stripAnsi from "strip-ansi";
6
7
  import { hasPrimaryKey } from "../../runtime/index.js";
8
+ import { createRemoteDatabaseClient } from "../../runtime/index.js";
7
9
  import { isSerializedSQL } from "../../runtime/types.js";
8
10
  import { safeFetch } from "../../runtime/utils.js";
9
11
  import { MIGRATION_VERSION } from "../consts.js";
@@ -18,9 +20,7 @@ import {
18
20
  schemaTypeToSqlType
19
21
  } from "../queries.js";
20
22
  import { columnSchema } from "../schemas.js";
21
- import {
22
- } from "../types.js";
23
- import { getRemoteDatabaseUrl } from "../utils.js";
23
+ import { getRemoteDatabaseInfo } from "../utils.js";
24
24
  const sqlite = new SQLiteAsyncDialect();
25
25
  const genTempTableName = customAlphabet("abcdefghijklmnopqrstuvwxyz", 10);
26
26
  async function getMigrationQueries({
@@ -304,10 +304,31 @@ function canChangeTypeWithoutQuery(oldColumn, newColumn) {
304
304
  function hasRuntimeDefault(column) {
305
305
  return !!(column.schema.default && isSerializedSQL(column.schema.default));
306
306
  }
307
- async function getProductionCurrentSnapshot({
308
- appToken
309
- }) {
310
- const url = new URL("/db/schema", getRemoteDatabaseUrl());
307
+ function getProductionCurrentSnapshot(options) {
308
+ const dbInfo = getRemoteDatabaseInfo();
309
+ return dbInfo.type === "studio" ? getStudioCurrentSnapshot(options.appToken, dbInfo.url) : getDbCurrentSnapshot(options.appToken, dbInfo.url);
310
+ }
311
+ async function getDbCurrentSnapshot(appToken, remoteUrl) {
312
+ const client = createRemoteDatabaseClient({
313
+ dbType: "libsql",
314
+ appToken,
315
+ remoteUrl
316
+ });
317
+ try {
318
+ const res = await client.get(
319
+ // Latest snapshot
320
+ sql`select snapshot from _astro_db_snapshot order by id desc limit 1;`
321
+ );
322
+ return JSON.parse(res.snapshot);
323
+ } catch (error) {
324
+ if (error.code === "SQLITE_UNKNOWN") {
325
+ return;
326
+ }
327
+ throw error;
328
+ }
329
+ }
330
+ async function getStudioCurrentSnapshot(appToken, remoteUrl) {
331
+ const url = new URL("/db/schema", remoteUrl);
311
332
  const response = await safeFetch(
312
333
  url,
313
334
  {
@@ -27,7 +27,7 @@ function printHelp({
27
27
  message.push(
28
28
  linebreak(),
29
29
  ` ${bgGreen(black(` ${commandName} `))} ${green(
30
- `v${"0.13.2-alpha.0"}`
30
+ `v${"0.14.0"}`
31
31
  )} ${headline}`
32
32
  );
33
33
  }
@@ -7,7 +7,11 @@ import { normalizeDatabaseUrl } from "../../runtime/index.js";
7
7
  import { DB_PATH, RUNTIME_IMPORT, RUNTIME_VIRTUAL_IMPORT, VIRTUAL_MODULE_ID } from "../consts.js";
8
8
  import { getResolvedFileUrl } from "../load-file.js";
9
9
  import { SEED_DEV_FILE_NAME, getCreateIndexQueries, getCreateTableQuery } from "../queries.js";
10
- import { getAstroEnv, getDbDirectoryUrl, getRemoteDatabaseUrl } from "../utils.js";
10
+ import {
11
+ getAstroEnv,
12
+ getDbDirectoryUrl,
13
+ getRemoteDatabaseInfo
14
+ } from "../utils.js";
11
15
  const resolved = {
12
16
  module: "\0" + VIRTUAL_MODULE_ID,
13
17
  importedFromSeedFile: "\0" + VIRTUAL_MODULE_ID + ":seed"
@@ -70,12 +74,13 @@ function getLocalVirtualModContents({
70
74
  tables,
71
75
  root
72
76
  }) {
77
+ const dbInfo = getRemoteDatabaseInfo();
73
78
  const dbUrl = new URL(DB_PATH, root);
74
79
  return `
75
80
  import { asDrizzleTable, createLocalDatabaseClient, normalizeDatabaseUrl } from ${RUNTIME_IMPORT};
76
81
 
77
82
  const dbUrl = normalizeDatabaseUrl(import.meta.env.ASTRO_DATABASE_FILE, ${JSON.stringify(dbUrl)});
78
- export const db = createLocalDatabaseClient({ dbUrl });
83
+ export const db = createLocalDatabaseClient({ dbUrl, enableTransactions: ${dbInfo.url === "libsql"} });
79
84
 
80
85
  export * from ${RUNTIME_VIRTUAL_IMPORT};
81
86
 
@@ -87,25 +92,31 @@ function getStudioVirtualModContents({
87
92
  isBuild,
88
93
  output
89
94
  }) {
95
+ const dbInfo = getRemoteDatabaseInfo();
90
96
  function appTokenArg() {
91
97
  if (isBuild) {
98
+ const envPrefix = dbInfo.type === "studio" ? "ASTRO_STUDIO" : "ASTRO_DB";
92
99
  if (output === "server") {
93
- return "process.env.ASTRO_STUDIO_APP_TOKEN";
100
+ return `process.env.${envPrefix}_APP_TOKEN`;
94
101
  } else {
95
- return `process.env.ASTRO_STUDIO_APP_TOKEN ?? ${JSON.stringify(appToken)}`;
102
+ return `process.env.${envPrefix}_APP_TOKEN ?? ${JSON.stringify(appToken)}`;
96
103
  }
97
104
  } else {
98
105
  return JSON.stringify(appToken);
99
106
  }
100
107
  }
101
108
  function dbUrlArg() {
102
- const dbStr = JSON.stringify(getRemoteDatabaseUrl());
103
- return `import.meta.env.ASTRO_STUDIO_REMOTE_DB_URL ?? ${dbStr}`;
109
+ const dbStr = JSON.stringify(dbInfo.url);
110
+ return dbInfo.type === "studio" ? `import.meta.env.ASTRO_STUDIO_REMOTE_DB_URL ?? ${dbStr}` : `import.meta.env.ASTRO_DB_REMOTE_URL ?? ${dbStr}`;
104
111
  }
105
112
  return `
106
113
  import {asDrizzleTable, createRemoteDatabaseClient} from ${RUNTIME_IMPORT};
107
114
 
108
- export const db = await createRemoteDatabaseClient(${appTokenArg()}, ${dbUrlArg()});
115
+ export const db = await createRemoteDatabaseClient({
116
+ dbType: ${JSON.stringify(dbInfo.type)},
117
+ remoteUrl: ${dbUrlArg()},
118
+ appToken: ${appTokenArg()},
119
+ });
109
120
 
110
121
  export * from ${RUNTIME_VIRTUAL_IMPORT};
111
122
 
@@ -121,9 +132,10 @@ function getStringifiedTableExports(tables) {
121
132
  }
122
133
  const sqlite = new SQLiteAsyncDialect();
123
134
  async function recreateTables({ tables, root }) {
135
+ const dbInfo = getRemoteDatabaseInfo();
124
136
  const { ASTRO_DATABASE_FILE } = getAstroEnv();
125
137
  const dbUrl = normalizeDatabaseUrl(ASTRO_DATABASE_FILE, new URL(DB_PATH, root).href);
126
- const db = createLocalDatabaseClient({ dbUrl });
138
+ const db = createLocalDatabaseClient({ dbUrl, enableTransations: dbInfo.type === "libsql" });
127
139
  const setupQueries = [];
128
140
  for (const [name, table] of Object.entries(tables.get() ?? {})) {
129
141
  const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${sqlite.escapeName(name)}`);
@@ -116,6 +116,7 @@ async function bundleFile({
116
116
  metafile: true,
117
117
  define: {
118
118
  "import.meta.env.ASTRO_STUDIO_REMOTE_DB_URL": "undefined",
119
+ "import.meta.env.ASTRO_DB_REMOTE_DB_URL": "undefined",
119
120
  "import.meta.env.ASTRO_DATABASE_FILE": JSON.stringify(ASTRO_DATABASE_FILE ?? "")
120
121
  },
121
122
  plugins: [
@@ -1,4 +1,3 @@
1
- import {} from "drizzle-orm";
2
1
  import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
3
2
  import { bold } from "kleur/colors";
4
3
  import {
@@ -2,7 +2,11 @@ import type { AstroConfig, AstroIntegration } from 'astro';
2
2
  import './types.js';
3
3
  export type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
4
4
  export declare function getAstroEnv(envMode?: string): Record<`ASTRO_${string}`, string>;
5
- export declare function getRemoteDatabaseUrl(): string;
5
+ export type RemoteDatabaseInfo = {
6
+ type: 'libsql' | 'studio';
7
+ url: string;
8
+ };
9
+ export declare function getRemoteDatabaseInfo(): RemoteDatabaseInfo;
6
10
  export declare function getDbDirectoryUrl(root: URL | string): URL;
7
11
  export declare function defineDbIntegration(integration: AstroIntegration): AstroIntegration;
8
12
  export type Result<T> = {
@@ -5,9 +5,23 @@ function getAstroEnv(envMode = "") {
5
5
  const env = loadEnv(envMode, process.cwd(), "ASTRO_");
6
6
  return env;
7
7
  }
8
- function getRemoteDatabaseUrl() {
9
- const env = getAstroStudioEnv();
10
- return env.ASTRO_STUDIO_REMOTE_DB_URL || "https://db.services.astro.build";
8
+ function getRemoteDatabaseInfo() {
9
+ const astroEnv = getAstroEnv();
10
+ const studioEnv = getAstroStudioEnv();
11
+ if (studioEnv.ASTRO_STUDIO_REMOTE_DB_URL)
12
+ return {
13
+ type: "studio",
14
+ url: studioEnv.ASTRO_STUDIO_REMOTE_DB_URL
15
+ };
16
+ if (astroEnv.ASTRO_DB_REMOTE_URL)
17
+ return {
18
+ type: "libsql",
19
+ url: astroEnv.ASTRO_DB_REMOTE_URL
20
+ };
21
+ return {
22
+ type: "studio",
23
+ url: "https://db.services.astro.build"
24
+ };
11
25
  }
12
26
  function getDbDirectoryUrl(root) {
13
27
  return new URL("db/", root);
@@ -24,6 +38,6 @@ export {
24
38
  defineDbIntegration,
25
39
  getAstroEnv,
26
40
  getDbDirectoryUrl,
27
- getRemoteDatabaseUrl,
41
+ getRemoteDatabaseInfo,
28
42
  mapObject
29
43
  };
@@ -1,6 +1,14 @@
1
1
  import type { LibSQLDatabase } from 'drizzle-orm/libsql';
2
2
  import { type SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
3
- export declare function createLocalDatabaseClient({ dbUrl }: {
3
+ type LocalDbClientOptions = {
4
4
  dbUrl: string;
5
- }): LibSQLDatabase;
6
- export declare function createRemoteDatabaseClient(appToken: string, remoteDbURL: string): SqliteRemoteDatabase<Record<string, never>>;
5
+ enableTransations: boolean;
6
+ };
7
+ export declare function createLocalDatabaseClient(options: LocalDbClientOptions): LibSQLDatabase;
8
+ type RemoteDbClientOptions = {
9
+ dbType: 'studio' | 'libsql';
10
+ appToken: string;
11
+ remoteUrl: string | URL;
12
+ };
13
+ export declare function createRemoteDatabaseClient(options: RemoteDbClientOptions): SqliteRemoteDatabase<Record<string, never>> | LibSQLDatabase<Record<string, never>>;
14
+ export {};
@@ -13,11 +13,13 @@ function applyTransactionNotSupported(db) {
13
13
  }
14
14
  });
15
15
  }
16
- function createLocalDatabaseClient({ dbUrl }) {
17
- const url = isWebContainer ? "file:content.db" : dbUrl;
16
+ function createLocalDatabaseClient(options) {
17
+ const url = isWebContainer ? "file:content.db" : options.dbUrl;
18
18
  const client = createClient({ url });
19
19
  const db = drizzleLibsql(client);
20
- applyTransactionNotSupported(db);
20
+ if (!options.enableTransations) {
21
+ applyTransactionNotSupported(db);
22
+ }
21
23
  return db;
22
24
  }
23
25
  const remoteResultSchema = z.object({
@@ -27,7 +29,21 @@ const remoteResultSchema = z.object({
27
29
  rowsAffected: z.number(),
28
30
  lastInsertRowid: z.unknown().optional()
29
31
  });
30
- function createRemoteDatabaseClient(appToken, remoteDbURL) {
32
+ function createRemoteDatabaseClient(options) {
33
+ const remoteUrl = new URL(options.remoteUrl);
34
+ return options.dbType === "studio" ? createStudioDatabaseClient(options.appToken, remoteUrl) : createRemoteLibSQLClient(options.appToken, remoteUrl);
35
+ }
36
+ function createRemoteLibSQLClient(appToken, remoteDbURL) {
37
+ const options = Object.fromEntries(remoteDbURL.searchParams.entries());
38
+ remoteDbURL.search = "";
39
+ const client = createClient({
40
+ ...options,
41
+ authToken: appToken,
42
+ url: remoteDbURL.protocol === "memory:" ? ":memory:" : remoteDbURL.toString()
43
+ });
44
+ return drizzleLibsql(client);
45
+ }
46
+ function createStudioDatabaseClient(appToken, remoteDbURL) {
31
47
  if (appToken == null) {
32
48
  throw new Error(`Cannot create a remote client: missing app token.`);
33
49
  }
@@ -1,5 +1,5 @@
1
1
  import { type ColumnDataType } from 'drizzle-orm';
2
- import { type LibSQLDatabase } from 'drizzle-orm/libsql';
2
+ import type { LibSQLDatabase } from 'drizzle-orm/libsql';
3
3
  import type { DBColumn, DBTable } from '../core/types.js';
4
4
  export type Database = Omit<LibSQLDatabase, 'transaction'>;
5
5
  export type { Table } from './types.js';
@@ -1,5 +1,4 @@
1
1
  import { sql } from "drizzle-orm";
2
- import {} from "drizzle-orm/libsql";
3
2
  import {
4
3
  customType,
5
4
  index,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/db",
3
- "version": "0.13.2-alpha.0",
3
+ "version": "0.14.0",
4
4
  "description": "Add libSQL and Astro Studio support to your Astro site",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -62,7 +62,7 @@
62
62
  "astro-integration"
63
63
  ],
64
64
  "dependencies": {
65
- "@libsql/client": "^0.9.0",
65
+ "@libsql/client": "^0.10.0",
66
66
  "async-listen": "^3.0.1",
67
67
  "deep-diff": "^1.0.2",
68
68
  "drizzle-orm": "^0.31.2",
@@ -70,7 +70,7 @@
70
70
  "kleur": "^4.1.5",
71
71
  "nanoid": "^5.0.7",
72
72
  "open": "^10.1.0",
73
- "ora": "^8.0.1",
73
+ "ora": "^8.1.0",
74
74
  "prompts": "^2.4.2",
75
75
  "strip-ansi": "^7.1.0",
76
76
  "yargs-parser": "^21.1.1",
@@ -83,8 +83,8 @@
83
83
  "@types/yargs-parser": "^21.0.3",
84
84
  "cheerio": "1.0.0",
85
85
  "typescript": "^5.5.4",
86
- "vite": "^5.4.1",
87
- "astro": "5.0.0-alpha.1",
86
+ "vite": "^5.4.2",
87
+ "astro": "4.15.0",
88
88
  "astro-scripts": "0.0.14"
89
89
  },
90
90
  "scripts": {