@astrojs/db 0.15.0 → 0.16.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.
Files changed (39) hide show
  1. package/dist/_internal/core/schemas.d.ts +57 -57
  2. package/dist/_internal/core/types.d.ts +1 -1
  3. package/dist/_internal/core/utils.d.ts +1 -10
  4. package/dist/_internal/runtime/utils.d.ts +0 -15
  5. package/dist/_internal/runtime/virtual.d.ts +2 -2
  6. package/dist/core/cli/commands/execute/index.js +5 -5
  7. package/dist/core/cli/commands/push/index.js +6 -40
  8. package/dist/core/cli/commands/shell/index.js +3 -9
  9. package/dist/core/cli/commands/verify/index.js +2 -7
  10. package/dist/core/cli/index.js +4 -16
  11. package/dist/core/cli/migration-queries.d.ts +1 -4
  12. package/dist/core/cli/migration-queries.js +9 -32
  13. package/dist/core/cli/print-help.js +1 -1
  14. package/dist/core/integration/index.js +5 -8
  15. package/dist/core/integration/vite-plugin-db.d.ts +4 -4
  16. package/dist/core/integration/vite-plugin-db.js +13 -22
  17. package/dist/core/load-file.d.ts +5 -5
  18. package/dist/core/load-file.js +0 -2
  19. package/dist/core/queries.d.ts +3 -3
  20. package/dist/core/schemas.d.ts +257 -257
  21. package/dist/core/schemas.js +1 -1
  22. package/dist/core/types.d.ts +1 -1
  23. package/dist/core/utils.d.ts +1 -10
  24. package/dist/core/utils.js +2 -27
  25. package/dist/index.d.ts +1 -1
  26. package/dist/runtime/db-client.d.ts +5 -6
  27. package/dist/runtime/db-client.js +10 -167
  28. package/dist/runtime/index.d.ts +1 -1
  29. package/dist/runtime/index.js +1 -1
  30. package/dist/runtime/utils.d.ts +0 -15
  31. package/dist/runtime/utils.js +1 -26
  32. package/dist/runtime/virtual.js +21 -21
  33. package/package.json +4 -9
  34. package/dist/core/cli/commands/link/index.d.ts +0 -1
  35. package/dist/core/cli/commands/link/index.js +0 -266
  36. package/dist/core/cli/commands/login/index.d.ts +0 -8
  37. package/dist/core/cli/commands/login/index.js +0 -76
  38. package/dist/core/cli/commands/logout/index.d.ts +0 -1
  39. package/dist/core/cli/commands/logout/index.js +0 -9
@@ -65,7 +65,7 @@ const textColumnBaseSchema = baseColumnSchema.omit({ optional: true }).extend({
65
65
  z.object({
66
66
  // text primary key allows NULL values.
67
67
  // NULL values bypass unique checks, which could
68
- // lead to duplicate URLs per record in Astro Studio.
68
+ // lead to duplicate URLs per record.
69
69
  // disable `optional` for primary keys.
70
70
  primaryKey: z.literal(true),
71
71
  optional: z.literal(false).optional()
@@ -1,5 +1,5 @@
1
1
  import type { z } from 'zod';
2
- import type { MaybeArray, booleanColumnSchema, columnSchema, columnsSchema, dateColumnSchema, dbConfigSchema, indexSchema, jsonColumnSchema, numberColumnOptsSchema, numberColumnSchema, referenceableColumnSchema, resolvedIndexSchema, tableSchema, textColumnOptsSchema, textColumnSchema } from './schemas.js';
2
+ import type { booleanColumnSchema, columnSchema, columnsSchema, dateColumnSchema, dbConfigSchema, indexSchema, jsonColumnSchema, MaybeArray, numberColumnOptsSchema, numberColumnSchema, referenceableColumnSchema, resolvedIndexSchema, tableSchema, textColumnOptsSchema, textColumnSchema } from './schemas.js';
3
3
  export type ResolvedIndexes = z.output<typeof dbConfigSchema>['tables'][string]['indexes'];
4
4
  export type BooleanColumn = z.infer<typeof booleanColumnSchema>;
5
5
  export type BooleanColumnInput = z.input<typeof booleanColumnSchema>;
@@ -1,23 +1,14 @@
1
- import { type ManagedAppToken } from '@astrojs/studio';
2
1
  import type { AstroConfig, AstroIntegration } from 'astro';
3
2
  import './types.js';
4
3
  export type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
5
4
  export declare function getAstroEnv(envMode?: string): Record<`ASTRO_${string}`, string>;
6
5
  export type RemoteDatabaseInfo = {
7
- type: 'libsql' | 'studio';
8
6
  url: string;
7
+ token: string;
9
8
  };
10
9
  export declare function getRemoteDatabaseInfo(): RemoteDatabaseInfo;
11
- export declare function getManagedRemoteToken(token?: string, dbInfo?: RemoteDatabaseInfo): Promise<ManagedAppToken>;
12
10
  export declare function getDbDirectoryUrl(root: URL | string): URL;
13
11
  export declare function defineDbIntegration(integration: AstroIntegration): AstroIntegration;
14
- export type Result<T> = {
15
- success: true;
16
- data: T;
17
- } | {
18
- success: false;
19
- data: unknown;
20
- };
21
12
  /**
22
13
  * Map an object's values to a new set of values
23
14
  * while preserving types.
@@ -1,4 +1,3 @@
1
- import { getAstroStudioEnv, getManagedAppTokenOrExit } from "@astrojs/studio";
2
1
  import { loadEnv } from "vite";
3
2
  import "./types.js";
4
3
  function getAstroEnv(envMode = "") {
@@ -7,34 +6,11 @@ function getAstroEnv(envMode = "") {
7
6
  }
8
7
  function getRemoteDatabaseInfo() {
9
8
  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
9
  return {
22
- type: "studio",
23
- url: "https://db.services.astro.build"
10
+ url: astroEnv.ASTRO_DB_REMOTE_URL,
11
+ token: astroEnv.ASTRO_DB_APP_TOKEN
24
12
  };
25
13
  }
26
- function getManagedRemoteToken(token, dbInfo) {
27
- dbInfo ??= getRemoteDatabaseInfo();
28
- if (dbInfo.type === "studio") {
29
- return getManagedAppTokenOrExit(token);
30
- }
31
- const astroEnv = getAstroEnv();
32
- return Promise.resolve({
33
- token: token ?? astroEnv.ASTRO_DB_APP_TOKEN,
34
- renew: () => Promise.resolve(),
35
- destroy: () => Promise.resolve()
36
- });
37
- }
38
14
  function getDbDirectoryUrl(root) {
39
15
  return new URL("db/", root);
40
16
  }
@@ -50,7 +26,6 @@ export {
50
26
  defineDbIntegration,
51
27
  getAstroEnv,
52
28
  getDbDirectoryUrl,
53
- getManagedRemoteToken,
54
29
  getRemoteDatabaseInfo,
55
30
  mapObject
56
31
  };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export type { TableConfig } from './core/types.js';
2
1
  export { cli } from './core/cli/index.js';
3
2
  export { integration as default } from './core/integration/index.js';
3
+ export type { TableConfig } from './core/types.js';
@@ -1,16 +1,15 @@
1
1
  import { type Config as LibSQLConfig } from '@libsql/client';
2
2
  import type { LibSQLDatabase } from 'drizzle-orm/libsql';
3
- import { type SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
4
3
  type LocalDbClientOptions = {
5
4
  dbUrl: string;
6
- enableTransactions: boolean;
7
5
  };
8
6
  export declare function createLocalDatabaseClient(options: LocalDbClientOptions): LibSQLDatabase;
9
7
  type RemoteDbClientOptions = {
10
- dbType: 'studio' | 'libsql';
11
- appToken: string;
12
- remoteUrl: string | URL;
8
+ token: string;
9
+ url: string | URL;
10
+ };
11
+ export declare function createRemoteDatabaseClient(options: RemoteDbClientOptions): LibSQLDatabase<Record<string, never>> & {
12
+ $client: import("@libsql/client").Client;
13
13
  };
14
- export declare function createRemoteDatabaseClient(options: RemoteDbClientOptions): SqliteRemoteDatabase<Record<string, never>>;
15
14
  export declare function parseOpts(config: Record<string, string>): Partial<LibSQLConfig>;
16
15
  export {};
@@ -1,37 +1,15 @@
1
1
  import { createClient } from "@libsql/client";
2
2
  import { drizzle as drizzleLibsql } from "drizzle-orm/libsql";
3
- import { drizzle as drizzleProxy } from "drizzle-orm/sqlite-proxy";
4
- import { z } from "zod";
5
- import { DetailedLibsqlError, safeFetch } from "./utils.js";
6
3
  const isWebContainer = !!process.versions?.webcontainer;
7
- function applyTransactionNotSupported(db) {
8
- Object.assign(db, {
9
- transaction() {
10
- throw new Error(
11
- "`db.transaction()` is not currently supported. We recommend `db.batch()` for automatic error rollbacks across multiple queries."
12
- );
13
- }
14
- });
15
- }
16
4
  function createLocalDatabaseClient(options) {
17
5
  const url = isWebContainer ? "file:content.db" : options.dbUrl;
18
6
  const client = createClient({ url });
19
7
  const db = drizzleLibsql(client);
20
- if (!options.enableTransactions) {
21
- applyTransactionNotSupported(db);
22
- }
23
8
  return db;
24
9
  }
25
- const remoteResultSchema = z.object({
26
- columns: z.array(z.string()),
27
- columnTypes: z.array(z.string()),
28
- rows: z.array(z.array(z.unknown())),
29
- rowsAffected: z.number(),
30
- lastInsertRowid: z.unknown().optional()
31
- });
32
10
  function createRemoteDatabaseClient(options) {
33
- const remoteUrl = new URL(options.remoteUrl);
34
- return options.dbType === "studio" ? createStudioDatabaseClient(options.appToken, remoteUrl) : createRemoteLibSQLClient(options.appToken, remoteUrl, options.remoteUrl.toString());
11
+ const url = new URL(options.url);
12
+ return createRemoteLibSQLClient(options.token, url, options.url.toString());
35
13
  }
36
14
  function parseOpts(config) {
37
15
  return {
@@ -43,153 +21,18 @@ function parseOpts(config) {
43
21
  ...config.concurrency ? { concurrency: parseInt(config.concurrency) } : {}
44
22
  };
45
23
  }
46
- function createRemoteLibSQLClient(appToken, remoteDbURL, rawUrl) {
47
- const options = Object.fromEntries(remoteDbURL.searchParams.entries());
48
- remoteDbURL.search = "";
49
- let url = remoteDbURL.toString();
50
- if (remoteDbURL.protocol === "memory:") {
24
+ function createRemoteLibSQLClient(authToken, dbURL, rawUrl) {
25
+ const options = Object.fromEntries(dbURL.searchParams.entries());
26
+ dbURL.search = "";
27
+ let url = dbURL.toString();
28
+ if (dbURL.protocol === "memory:") {
51
29
  url = ":memory:";
52
- } else if (remoteDbURL.protocol === "file:" && remoteDbURL.pathname.startsWith("/") && !rawUrl.startsWith("file:/")) {
53
- url = "file:" + remoteDbURL.pathname.substring(1);
30
+ } else if (dbURL.protocol === "file:" && dbURL.pathname.startsWith("/") && !rawUrl.startsWith("file:/")) {
31
+ url = "file:" + dbURL.pathname.substring(1);
54
32
  }
55
- const client = createClient({ ...parseOpts(options), url, authToken: appToken });
33
+ const client = createClient({ ...parseOpts(options), url, authToken });
56
34
  return drizzleLibsql(client);
57
35
  }
58
- function createStudioDatabaseClient(appToken, remoteDbURL) {
59
- if (appToken == null) {
60
- throw new Error(`Cannot create a remote client: missing app token.`);
61
- }
62
- const url = new URL("/db/query", remoteDbURL);
63
- const db = drizzleProxy(
64
- async (sql, parameters, method) => {
65
- const requestBody = { sql, args: parameters };
66
- const res = await safeFetch(
67
- url,
68
- {
69
- method: "POST",
70
- headers: {
71
- Authorization: `Bearer ${appToken}`,
72
- "Content-Type": "application/json"
73
- },
74
- body: JSON.stringify(requestBody)
75
- },
76
- async (response) => {
77
- throw await parseRemoteError(response);
78
- }
79
- );
80
- let remoteResult;
81
- try {
82
- const json = await res.json();
83
- remoteResult = remoteResultSchema.parse(json);
84
- } catch {
85
- throw new DetailedLibsqlError({
86
- message: await getUnexpectedResponseMessage(res),
87
- code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
88
- });
89
- }
90
- if (method === "run") {
91
- const rawRows = Array.from(remoteResult.rows);
92
- remoteResult.rows.toJSON = () => rawRows;
93
- for (let i = 0; i < remoteResult.rows.length; i++) {
94
- let row = remoteResult.rows[i];
95
- let item = {};
96
- remoteResult.columns.forEach((col, index) => {
97
- item[col] = row[index];
98
- });
99
- remoteResult.rows[i] = item;
100
- }
101
- return remoteResult;
102
- }
103
- const rowValues = [];
104
- for (const row of remoteResult.rows) {
105
- if (row != null && typeof row === "object") {
106
- rowValues.push(Object.values(row));
107
- }
108
- }
109
- if (method === "get") {
110
- return { rows: rowValues[0] };
111
- }
112
- return { rows: rowValues };
113
- },
114
- async (queries) => {
115
- const stmts = queries.map(({ sql, params }) => ({ sql, args: params }));
116
- const res = await safeFetch(
117
- url,
118
- {
119
- method: "POST",
120
- headers: {
121
- Authorization: `Bearer ${appToken}`,
122
- "Content-Type": "application/json"
123
- },
124
- body: JSON.stringify(stmts)
125
- },
126
- async (response) => {
127
- throw await parseRemoteError(response);
128
- }
129
- );
130
- let remoteResults;
131
- try {
132
- const json = await res.json();
133
- remoteResults = z.array(remoteResultSchema).parse(json);
134
- } catch {
135
- throw new DetailedLibsqlError({
136
- message: await getUnexpectedResponseMessage(res),
137
- code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
138
- });
139
- }
140
- let results = [];
141
- for (const [idx, rawResult] of remoteResults.entries()) {
142
- if (queries[idx]?.method === "run") {
143
- results.push(rawResult);
144
- continue;
145
- }
146
- const rowValues = [];
147
- for (const row of rawResult.rows) {
148
- if (row != null && typeof row === "object") {
149
- rowValues.push(Object.values(row));
150
- }
151
- }
152
- if (queries[idx]?.method === "get") {
153
- results.push({ rows: rowValues[0] });
154
- }
155
- results.push({ rows: rowValues });
156
- }
157
- return results;
158
- }
159
- );
160
- applyTransactionNotSupported(db);
161
- return db;
162
- }
163
- const errorSchema = z.object({
164
- success: z.boolean(),
165
- error: z.object({
166
- code: z.string(),
167
- details: z.string().optional()
168
- })
169
- });
170
- const KNOWN_ERROR_CODES = {
171
- SQL_QUERY_FAILED: "SQL_QUERY_FAILED"
172
- };
173
- const getUnexpectedResponseMessage = async (response) => `Unexpected response from remote database:
174
- (Status ${response.status}) ${await response.clone().text()}`;
175
- async function parseRemoteError(response) {
176
- let error;
177
- try {
178
- error = errorSchema.parse(await response.clone().json()).error;
179
- } catch {
180
- return new DetailedLibsqlError({
181
- message: await getUnexpectedResponseMessage(response),
182
- code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
183
- });
184
- }
185
- let baseDetails = error.details?.replace(/.*SQLite error: /, "") ?? "Error querying remote database.";
186
- const details = baseDetails.slice(baseDetails.indexOf(":") + 1).trim();
187
- let hint = `See the Astro DB guide for query and push instructions: https://docs.astro.build/en/guides/astro-db/#query-your-database`;
188
- if (error.code === KNOWN_ERROR_CODES.SQL_QUERY_FAILED && details.includes("no such table")) {
189
- hint = `Did you run \`astro db push\` to push your latest table schemas?`;
190
- }
191
- return new DetailedLibsqlError({ message: details, code: error.code, hint });
192
- }
193
36
  export {
194
37
  createLocalDatabaseClient,
195
38
  createRemoteDatabaseClient,
@@ -2,8 +2,8 @@ import { type ColumnDataType } from 'drizzle-orm';
2
2
  import type { LibSQLDatabase } from 'drizzle-orm/libsql';
3
3
  import type { DBColumn, DBTable } from '../core/types.js';
4
4
  export type Database = LibSQLDatabase;
5
+ export { createLocalDatabaseClient, createRemoteDatabaseClient } from './db-client.js';
5
6
  export type { Table } from './types.js';
6
- export { createRemoteDatabaseClient, createLocalDatabaseClient } from './db-client.js';
7
7
  export declare function hasPrimaryKey(column: DBColumn): boolean;
8
8
  export declare function asDrizzleTable(name: string, table: DBTable): import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
9
9
  name: string;
@@ -8,7 +8,7 @@ import {
8
8
  } from "drizzle-orm/sqlite-core";
9
9
  import { isSerializedSQL } from "./types.js";
10
10
  import { pathToFileURL } from "./utils.js";
11
- import { createRemoteDatabaseClient, createLocalDatabaseClient } from "./db-client.js";
11
+ import { createLocalDatabaseClient, createRemoteDatabaseClient } from "./db-client.js";
12
12
  function hasPrimaryKey(column) {
13
13
  return "primaryKey" in column.schema && !!column.schema.primaryKey;
14
14
  }
@@ -1,22 +1,7 @@
1
1
  import { LibsqlError } from '@libsql/client';
2
2
  import { AstroError } from 'astro/errors';
3
- /**
4
- * Small wrapper around fetch that throws an error if the response is not OK. Allows for custom error handling as well through the onNotOK callback.
5
- */
6
- export declare function safeFetch(url: Parameters<typeof fetch>[0], options?: Parameters<typeof fetch>[1], onNotOK?: (response: Response) => void | Promise<void>): Promise<Response>;
7
3
  export declare class AstroDbError extends AstroError {
8
4
  name: string;
9
5
  }
10
- export declare class DetailedLibsqlError extends LibsqlError {
11
- name: string;
12
- hint?: string;
13
- constructor({ message, code, hint, rawCode, cause, }: {
14
- message: string;
15
- code: string;
16
- hint?: string;
17
- rawCode?: number;
18
- cause?: Error;
19
- });
20
- }
21
6
  export declare function isDbError(err: unknown): err is LibsqlError;
22
7
  export declare function pathToFileURL(path: string): URL;
@@ -1,32 +1,9 @@
1
1
  import { LibsqlError } from "@libsql/client";
2
2
  import { AstroError } from "astro/errors";
3
3
  const isWindows = process?.platform === "win32";
4
- async function safeFetch(url, options = {}, onNotOK = () => {
5
- throw new Error(`Request to ${url} returned a non-OK status code.`);
6
- }) {
7
- const response = await fetch(url, options);
8
- if (!response.ok) {
9
- await onNotOK(response);
10
- }
11
- return response;
12
- }
13
4
  class AstroDbError extends AstroError {
14
5
  name = "Astro DB Error";
15
6
  }
16
- class DetailedLibsqlError extends LibsqlError {
17
- name = "Astro DB Error";
18
- hint;
19
- constructor({
20
- message,
21
- code,
22
- hint,
23
- rawCode,
24
- cause
25
- }) {
26
- super(message, code, rawCode, cause);
27
- this.hint = hint;
28
- }
29
- }
30
7
  function isDbError(err) {
31
8
  return err instanceof LibsqlError || err instanceof Error && err.libsqlError === true;
32
9
  }
@@ -49,8 +26,6 @@ function pathToFileURL(path) {
49
26
  }
50
27
  export {
51
28
  AstroDbError,
52
- DetailedLibsqlError,
53
29
  isDbError,
54
- pathToFileURL,
55
- safeFetch
30
+ pathToFileURL
56
31
  };
@@ -35,37 +35,37 @@ const NOW = _sql`CURRENT_TIMESTAMP`;
35
35
  const TRUE = _sql`TRUE`;
36
36
  const FALSE = _sql`FALSE`;
37
37
  import {
38
- sql,
38
+ and,
39
+ asc,
40
+ avg,
41
+ avgDistinct,
42
+ between,
43
+ count,
44
+ countDistinct,
45
+ desc,
39
46
  eq,
47
+ exists,
40
48
  gt,
41
49
  gte,
50
+ ilike,
51
+ inArray,
52
+ isNotNull,
53
+ isNull,
54
+ like,
42
55
  lt,
43
56
  lte,
57
+ max,
58
+ min,
44
59
  ne,
45
- isNull,
46
- isNotNull,
47
- inArray,
48
- notInArray,
49
- exists,
50
- notExists,
51
- between,
60
+ not,
52
61
  notBetween,
53
- like,
54
- ilike,
62
+ notExists,
55
63
  notIlike,
56
- not,
57
- asc,
58
- desc,
59
- and,
64
+ notInArray,
60
65
  or,
61
- count,
62
- countDistinct,
63
- avg,
64
- avgDistinct,
66
+ sql,
65
67
  sum,
66
- sumDistinct,
67
- max,
68
- min
68
+ sumDistinct
69
69
  } from "drizzle-orm";
70
70
  import { alias } from "drizzle-orm/sqlite-core";
71
71
  import { isDbError } from "./utils.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrojs/db",
3
- "version": "0.15.0",
4
- "description": "Add libSQL and Astro Studio support to your Astro site",
3
+ "version": "0.16.0",
4
+ "description": "Add libSQL support to your Astro site",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -63,18 +63,13 @@
63
63
  ],
64
64
  "dependencies": {
65
65
  "@libsql/client": "^0.15.2",
66
- "async-listen": "^3.1.0",
67
66
  "deep-diff": "^1.0.2",
68
67
  "drizzle-orm": "^0.42.0",
69
- "github-slugger": "^2.0.0",
70
68
  "kleur": "^4.1.5",
71
69
  "nanoid": "^5.1.5",
72
- "open": "^10.1.0",
73
70
  "prompts": "^2.4.2",
74
71
  "yargs-parser": "^21.1.1",
75
- "yocto-spinner": "^0.2.1",
76
- "zod": "^3.24.2",
77
- "@astrojs/studio": "0.1.9"
72
+ "zod": "^3.24.4"
78
73
  },
79
74
  "devDependencies": {
80
75
  "@types/deep-diff": "^1.0.5",
@@ -83,7 +78,7 @@
83
78
  "cheerio": "1.0.0",
84
79
  "typescript": "^5.8.3",
85
80
  "vite": "^6.3.4",
86
- "astro": "5.8.1",
81
+ "astro": "5.12.8",
87
82
  "astro-scripts": "0.0.14"
88
83
  },
89
84
  "scripts": {
@@ -1 +0,0 @@
1
- export declare function cmd(): Promise<void>;