@astrojs/db 0.4.0 → 0.5.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 (57) hide show
  1. package/dist/core/cli/commands/execute/index.d.ts +8 -0
  2. package/dist/core/cli/commands/execute/index.js +32 -0
  3. package/dist/core/cli/commands/gen/index.d.ts +4 -2
  4. package/dist/core/cli/commands/gen/index.js +17 -9
  5. package/dist/core/cli/commands/link/index.d.ts +20 -8
  6. package/dist/core/cli/commands/link/index.js +191 -31
  7. package/dist/core/cli/commands/login/index.d.ts +4 -2
  8. package/dist/core/cli/commands/login/index.js +31 -22
  9. package/dist/core/cli/commands/logout/index.d.ts +1 -6
  10. package/dist/core/cli/commands/logout/index.js +1 -1
  11. package/dist/core/cli/commands/push/index.d.ts +4 -2
  12. package/dist/core/cli/commands/push/index.js +25 -77
  13. package/dist/core/cli/commands/shell/index.d.ts +4 -2
  14. package/dist/core/cli/commands/shell/index.js +3 -1
  15. package/dist/core/cli/commands/verify/index.d.ts +4 -2
  16. package/dist/core/cli/commands/verify/index.js +10 -6
  17. package/dist/core/cli/index.d.ts +1 -1
  18. package/dist/core/cli/index.js +19 -13
  19. package/dist/core/cli/migration-queries.d.ts +1 -1
  20. package/dist/core/cli/migration-queries.js +6 -6
  21. package/dist/core/cli/migrations.d.ts +12 -9
  22. package/dist/core/cli/migrations.js +27 -21
  23. package/dist/core/consts.d.ts +2 -0
  24. package/dist/core/consts.js +4 -0
  25. package/dist/core/errors.d.ts +7 -4
  26. package/dist/core/errors.js +38 -31
  27. package/dist/core/integration/file-url.js +1 -1
  28. package/dist/core/integration/index.js +56 -117
  29. package/dist/core/integration/typegen.js +1 -13
  30. package/dist/core/integration/vite-plugin-db.d.ts +10 -6
  31. package/dist/core/integration/vite-plugin-db.js +68 -23
  32. package/dist/core/integration/vite-plugin-inject-env-ts.d.ts +1 -1
  33. package/dist/core/load-file.d.ts +31 -0
  34. package/dist/core/load-file.js +98 -0
  35. package/dist/core/tokens.js +1 -1
  36. package/dist/core/types.d.ts +832 -5306
  37. package/dist/core/types.js +16 -84
  38. package/dist/core/utils.d.ts +2 -0
  39. package/dist/core/utils.js +8 -0
  40. package/dist/index.d.ts +2 -3
  41. package/dist/index.js +3 -5
  42. package/dist/runtime/config.d.ts +138 -0
  43. package/dist/runtime/config.js +42 -0
  44. package/dist/runtime/db-client.d.ts +2 -9
  45. package/dist/runtime/db-client.js +8 -39
  46. package/dist/runtime/index.d.ts +5 -4
  47. package/dist/runtime/index.js +12 -10
  48. package/dist/{core → runtime}/queries.d.ts +15 -17
  49. package/dist/{core → runtime}/queries.js +64 -80
  50. package/dist/runtime/types.d.ts +3 -3
  51. package/dist/utils.d.ts +1 -0
  52. package/dist/utils.js +4 -0
  53. package/index.d.ts +5 -3
  54. package/package.json +18 -3
  55. package/config-augment.d.ts +0 -4
  56. package/dist/core/integration/load-astro-config.d.ts +0 -6
  57. package/dist/core/integration/load-astro-config.js +0 -79
@@ -1,6 +1,8 @@
1
1
  import type { AstroConfig } from 'astro';
2
2
  import type { Arguments } from 'yargs-parser';
3
- export declare function cmd({ flags }: {
4
- config: AstroConfig;
3
+ import type { DBConfigInput } from '../../../types.js';
4
+ export declare function cmd({ flags, }: {
5
+ dbConfig: DBConfigInput;
6
+ astroConfig: AstroConfig;
5
7
  flags: Arguments;
6
8
  }): Promise<void>;
@@ -2,7 +2,9 @@ import { sql } from "drizzle-orm";
2
2
  import { createRemoteDatabaseClient } from "../../../../runtime/db-client.js";
3
3
  import { getManagedAppTokenOrExit } from "../../../tokens.js";
4
4
  import { getRemoteDatabaseUrl } from "../../../utils.js";
5
- async function cmd({ flags }) {
5
+ async function cmd({
6
+ flags
7
+ }) {
6
8
  const query = flags.query;
7
9
  const appToken = await getManagedAppTokenOrExit(flags.token);
8
10
  const db = createRemoteDatabaseClient(appToken.token, getRemoteDatabaseUrl());
@@ -1,6 +1,8 @@
1
1
  import type { AstroConfig } from 'astro';
2
2
  import type { Arguments } from 'yargs-parser';
3
- export declare function cmd({ config, flags }: {
4
- config: AstroConfig;
3
+ import type { DBConfig } from '../../../types.js';
4
+ export declare function cmd({ astroConfig, dbConfig, flags, }: {
5
+ astroConfig: AstroConfig;
6
+ dbConfig: DBConfig;
5
7
  flags: Arguments;
6
8
  }): Promise<void>;
@@ -1,12 +1,16 @@
1
+ import { getMigrationQueries } from "../../migration-queries.js";
1
2
  import {
2
- getMigrationStatus,
3
- MIGRATION_NEEDED,
4
3
  MIGRATIONS_NOT_INITIALIZED,
5
- MIGRATIONS_UP_TO_DATE
4
+ MIGRATIONS_UP_TO_DATE,
5
+ MIGRATION_NEEDED,
6
+ getMigrationStatus
6
7
  } from "../../migrations.js";
7
- import { getMigrationQueries } from "../../migration-queries.js";
8
- async function cmd({ config, flags }) {
9
- const status = await getMigrationStatus(config);
8
+ async function cmd({
9
+ astroConfig,
10
+ dbConfig,
11
+ flags
12
+ }) {
13
+ const status = await getMigrationStatus({ dbConfig, root: astroConfig.root });
10
14
  const { state } = status;
11
15
  if (flags.json) {
12
16
  if (state === "ahead") {
@@ -1,6 +1,6 @@
1
1
  import type { AstroConfig } from 'astro';
2
2
  import type { Arguments } from 'yargs-parser';
3
- export declare function cli({ flags, config }: {
3
+ export declare function cli({ flags, config: astroConfig, }: {
4
4
  flags: Arguments;
5
5
  config: AstroConfig;
6
6
  }): Promise<void>;
@@ -1,40 +1,46 @@
1
- import { STUDIO_CONFIG_MISSING_CLI_ERROR } from "../errors.js";
2
- async function cli({ flags, config }) {
1
+ import { loadDbConfigFile } from "../load-file.js";
2
+ import { dbConfigSchema } from "../types.js";
3
+ async function cli({
4
+ flags,
5
+ config: astroConfig
6
+ }) {
3
7
  const args = flags._;
4
8
  const command = args[2] === "db" ? args[3] : args[2];
5
- if (!config.db?.studio) {
6
- console.log(STUDIO_CONFIG_MISSING_CLI_ERROR);
7
- process.exit(1);
8
- }
9
+ const { mod } = await loadDbConfigFile(astroConfig.root);
10
+ const dbConfig = dbConfigSchema.parse(mod?.default ?? {});
9
11
  switch (command) {
10
12
  case "shell": {
11
13
  const { cmd } = await import("./commands/shell/index.js");
12
- return await cmd({ config, flags });
14
+ return await cmd({ astroConfig, dbConfig, flags });
13
15
  }
14
16
  case "gen":
15
17
  case "sync": {
16
18
  const { cmd } = await import("./commands/gen/index.js");
17
- return await cmd({ config, flags });
19
+ return await cmd({ astroConfig, dbConfig, flags });
18
20
  }
19
21
  case "push": {
20
22
  const { cmd } = await import("./commands/push/index.js");
21
- return await cmd({ config, flags });
23
+ return await cmd({ astroConfig, dbConfig, flags });
22
24
  }
23
25
  case "verify": {
24
26
  const { cmd } = await import("./commands/verify/index.js");
25
- return await cmd({ config, flags });
27
+ return await cmd({ astroConfig, dbConfig, flags });
28
+ }
29
+ case "execute": {
30
+ const { cmd } = await import("./commands/execute/index.js");
31
+ return await cmd({ astroConfig, dbConfig, flags });
26
32
  }
27
33
  case "login": {
28
34
  const { cmd } = await import("./commands/login/index.js");
29
- return await cmd({ config, flags });
35
+ return await cmd({ astroConfig, dbConfig, flags });
30
36
  }
31
37
  case "logout": {
32
38
  const { cmd } = await import("./commands/logout/index.js");
33
- return await cmd({ config, flags });
39
+ return await cmd();
34
40
  }
35
41
  case "link": {
36
42
  const { cmd } = await import("./commands/link/index.js");
37
- return await cmd({ config, flags });
43
+ return await cmd();
38
44
  }
39
45
  default: {
40
46
  if (command == null) {
@@ -1,4 +1,4 @@
1
- import { type DBTable, type DBSnapshot } from '../types.js';
1
+ import { type DBSnapshot, type DBTable } from '../types.js';
2
2
  /** Dependency injected for unit testing */
3
3
  type AmbiguityResponses = {
4
4
  collectionRenames: Record<string, string>;
@@ -1,11 +1,9 @@
1
- import * as color from "kleur/colors";
2
1
  import deepDiff from "deep-diff";
3
- import {
4
- columnSchema
5
- } from "../types.js";
6
2
  import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
3
+ import * as color from "kleur/colors";
7
4
  import { customAlphabet } from "nanoid";
8
5
  import prompts from "prompts";
6
+ import { hasPrimaryKey } from "../../runtime/index.js";
9
7
  import {
10
8
  getCreateIndexQueries,
11
9
  getCreateTableQuery,
@@ -13,9 +11,11 @@ import {
13
11
  getReferencesConfig,
14
12
  hasDefault,
15
13
  schemaTypeToSqlType
16
- } from "../queries.js";
17
- import { hasPrimaryKey } from "../../runtime/index.js";
14
+ } from "../../runtime/queries.js";
18
15
  import { isSerializedSQL } from "../../runtime/types.js";
16
+ import {
17
+ columnSchema
18
+ } from "../types.js";
19
19
  const sqlite = new SQLiteAsyncDialect();
20
20
  const genTempTableName = customAlphabet("abcdefghijklmnopqrstuvwxyz", 10);
21
21
  async function getMigrationQueries({
@@ -1,6 +1,5 @@
1
1
  import deepDiff from 'deep-diff';
2
- import { type DBSnapshot } from '../types.js';
3
- import type { AstroConfig } from 'astro';
2
+ import { type DBConfig, type DBSnapshot } from '../types.js';
4
3
  export type MigrationStatus = {
5
4
  state: 'no-migrations-found';
6
5
  currentSnapshot: DBSnapshot;
@@ -16,19 +15,23 @@ export type MigrationStatus = {
16
15
  state: 'up-to-date';
17
16
  currentSnapshot: DBSnapshot;
18
17
  };
19
- export declare function getMigrationStatus(config: AstroConfig): Promise<MigrationStatus>;
18
+ export declare const INITIAL_SNAPSHOT = "0000_snapshot.json";
19
+ export declare function getMigrationStatus({ dbConfig, root, }: {
20
+ dbConfig: DBConfig;
21
+ root: URL;
22
+ }): Promise<MigrationStatus>;
20
23
  export declare const MIGRATIONS_CREATED: string;
21
24
  export declare const MIGRATIONS_UP_TO_DATE: string;
22
25
  export declare const MIGRATIONS_NOT_INITIALIZED: string;
23
26
  export declare const MIGRATION_NEEDED: string;
24
- export declare function getMigrations(): Promise<string[]>;
25
- export declare function loadMigration(migration: string): Promise<{
27
+ export declare function getMigrations(dir: URL): Promise<string[]>;
28
+ export declare function loadMigration(migration: string, dir: URL): Promise<{
26
29
  diff: any[];
27
30
  db: string[];
28
31
  confirm?: string[];
29
32
  }>;
30
- export declare function loadInitialSnapshot(): Promise<DBSnapshot>;
31
- export declare function initializeMigrationsDirectory(currentSnapshot: DBSnapshot): Promise<void>;
32
- export declare function initializeFromMigrations(allMigrationFiles: string[]): Promise<DBSnapshot>;
33
- export declare function createCurrentSnapshot(config: AstroConfig): DBSnapshot;
33
+ export declare function loadInitialSnapshot(dir: URL): Promise<DBSnapshot>;
34
+ export declare function initializeMigrationsDirectory(currentSnapshot: DBSnapshot, dir: URL): Promise<void>;
35
+ export declare function initializeFromMigrations(allMigrationFiles: string[], dir: URL): Promise<DBSnapshot>;
36
+ export declare function createCurrentSnapshot({ tables }: DBConfig): DBSnapshot;
34
37
  export declare function createEmptySnapshot(): DBSnapshot;
@@ -1,18 +1,24 @@
1
1
  import deepDiff from "deep-diff";
2
2
  import { mkdir, readFile, readdir, writeFile } from "fs/promises";
3
- import { tablesSchema } from "../types.js";
4
3
  import { cyan, green, yellow } from "kleur/colors";
4
+ import {} from "../types.js";
5
+ import { getMigrationsDirectoryUrl } from "../utils.js";
5
6
  const { applyChange, diff: generateDiff } = deepDiff;
6
- async function getMigrationStatus(config) {
7
- const currentSnapshot = createCurrentSnapshot(config);
8
- const allMigrationFiles = await getMigrations();
7
+ const INITIAL_SNAPSHOT = "0000_snapshot.json";
8
+ async function getMigrationStatus({
9
+ dbConfig,
10
+ root
11
+ }) {
12
+ const currentSnapshot = createCurrentSnapshot(dbConfig);
13
+ const dir = getMigrationsDirectoryUrl(root);
14
+ const allMigrationFiles = await getMigrations(dir);
9
15
  if (allMigrationFiles.length === 0) {
10
16
  return {
11
17
  state: "no-migrations-found",
12
18
  currentSnapshot
13
19
  };
14
20
  }
15
- const previousSnapshot = await initializeFromMigrations(allMigrationFiles);
21
+ const previousSnapshot = await initializeFromMigrations(allMigrationFiles, dir);
16
22
  const diff = generateDiff(previousSnapshot, currentSnapshot);
17
23
  if (diff) {
18
24
  const n = getNewMigrationNumber(allMigrationFiles);
@@ -67,8 +73,8 @@ function getNewMigrationNumber(allMigrationFiles) {
67
73
  return num > acc ? num : acc;
68
74
  }, 0);
69
75
  }
70
- async function getMigrations() {
71
- const migrationFiles = await readdir("./migrations").catch((err) => {
76
+ async function getMigrations(dir) {
77
+ const migrationFiles = await readdir(dir).catch((err) => {
72
78
  if (err.code === "ENOENT") {
73
79
  return [];
74
80
  }
@@ -76,11 +82,11 @@ async function getMigrations() {
76
82
  });
77
83
  return migrationFiles;
78
84
  }
79
- async function loadMigration(migration) {
80
- return JSON.parse(await readFile(`./migrations/${migration}`, "utf-8"));
85
+ async function loadMigration(migration, dir) {
86
+ return JSON.parse(await readFile(new URL(migration, dir), "utf-8"));
81
87
  }
82
- async function loadInitialSnapshot() {
83
- const snapshot = JSON.parse(await readFile("./migrations/0000_snapshot.json", "utf-8"));
88
+ async function loadInitialSnapshot(dir) {
89
+ const snapshot = JSON.parse(await readFile(new URL(INITIAL_SNAPSHOT, dir), "utf-8"));
84
90
  if (snapshot.experimentalVersion === 1) {
85
91
  return snapshot;
86
92
  }
@@ -89,31 +95,31 @@ async function loadInitialSnapshot() {
89
95
  }
90
96
  throw new Error("Invalid snapshot format");
91
97
  }
92
- async function initializeMigrationsDirectory(currentSnapshot) {
93
- await mkdir("./migrations", { recursive: true });
94
- await writeFile("./migrations/0000_snapshot.json", JSON.stringify(currentSnapshot, void 0, 2));
98
+ async function initializeMigrationsDirectory(currentSnapshot, dir) {
99
+ await mkdir(dir, { recursive: true });
100
+ await writeFile(new URL(INITIAL_SNAPSHOT, dir), JSON.stringify(currentSnapshot, void 0, 2));
95
101
  }
96
- async function initializeFromMigrations(allMigrationFiles) {
97
- const prevSnapshot = await loadInitialSnapshot();
102
+ async function initializeFromMigrations(allMigrationFiles, dir) {
103
+ const prevSnapshot = await loadInitialSnapshot(dir);
98
104
  for (const migration of allMigrationFiles) {
99
- if (migration === "0000_snapshot.json")
105
+ if (migration === INITIAL_SNAPSHOT)
100
106
  continue;
101
- const migrationContent = await loadMigration(migration);
107
+ const migrationContent = await loadMigration(migration, dir);
102
108
  migrationContent.diff.forEach((change) => {
103
109
  applyChange(prevSnapshot, {}, change);
104
110
  });
105
111
  }
106
112
  return prevSnapshot;
107
113
  }
108
- function createCurrentSnapshot(config) {
109
- const tablesConfig = tablesSchema.parse(config.db?.tables ?? {});
110
- const schema = JSON.parse(JSON.stringify(tablesConfig));
114
+ function createCurrentSnapshot({ tables = {} }) {
115
+ const schema = JSON.parse(JSON.stringify(tables));
111
116
  return { experimentalVersion: 1, schema };
112
117
  }
113
118
  function createEmptySnapshot() {
114
119
  return { experimentalVersion: 1, schema: {} };
115
120
  }
116
121
  export {
122
+ INITIAL_SNAPSHOT,
117
123
  MIGRATIONS_CREATED,
118
124
  MIGRATIONS_NOT_INITIALIZED,
119
125
  MIGRATIONS_UP_TO_DATE,
@@ -1,6 +1,8 @@
1
1
  export declare const PACKAGE_NAME: any;
2
2
  export declare const RUNTIME_IMPORT: string;
3
3
  export declare const RUNTIME_DRIZZLE_IMPORT: string;
4
+ export declare const RUNTIME_CONFIG_IMPORT: string;
4
5
  export declare const DB_TYPES_FILE = "db-types.d.ts";
5
6
  export declare const VIRTUAL_MODULE_ID = "astro:db";
6
7
  export declare const DB_PATH = ".astro/content.db";
8
+ export declare const CONFIG_FILE_NAMES: string[];
@@ -4,13 +4,17 @@ const PACKAGE_NAME = JSON.parse(
4
4
  ).name;
5
5
  const RUNTIME_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime`);
6
6
  const RUNTIME_DRIZZLE_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime/drizzle`);
7
+ const RUNTIME_CONFIG_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime/config`);
7
8
  const DB_TYPES_FILE = "db-types.d.ts";
8
9
  const VIRTUAL_MODULE_ID = "astro:db";
9
10
  const DB_PATH = ".astro/content.db";
11
+ const CONFIG_FILE_NAMES = ["config.ts", "config.js", "config.mts", "config.mjs"];
10
12
  export {
13
+ CONFIG_FILE_NAMES,
11
14
  DB_PATH,
12
15
  DB_TYPES_FILE,
13
16
  PACKAGE_NAME,
17
+ RUNTIME_CONFIG_IMPORT,
14
18
  RUNTIME_DRIZZLE_IMPORT,
15
19
  RUNTIME_IMPORT,
16
20
  VIRTUAL_MODULE_ID
@@ -1,7 +1,10 @@
1
1
  export declare const MISSING_SESSION_ID_ERROR: string;
2
2
  export declare const MISSING_PROJECT_ID_ERROR: string;
3
- export declare const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR: (collectionName: string) => string;
4
- export declare const UNSAFE_WRITABLE_WARNING: string;
5
- export declare const STUDIO_CONFIG_MISSING_CLI_ERROR: string;
6
3
  export declare const MIGRATIONS_NOT_INITIALIZED: string;
7
- export declare const SEED_WRITABLE_IN_PROD_ERROR: (collectionName: string) => string;
4
+ export declare const MISSING_EXECUTE_PATH_ERROR: string;
5
+ export declare const FILE_NOT_FOUND_ERROR: (path: string) => string;
6
+ export declare const SEED_ERROR: (error: string) => string;
7
+ export declare const REFERENCE_DNE_ERROR: (columnName: string) => string;
8
+ export declare const FOREIGN_KEY_DNE_ERROR: (tableName: string) => string;
9
+ export declare const FOREIGN_KEY_REFERENCES_LENGTH_ERROR: (tableName: string) => string;
10
+ export declare const FOREIGN_KEY_REFERENCES_EMPTY_ERROR: (tableName: string) => string;
@@ -1,4 +1,4 @@
1
- import { cyan, bold, red, green, yellow } from "kleur/colors";
1
+ import { bold, cyan, green, red, yellow } from "kleur/colors";
2
2
  const MISSING_SESSION_ID_ERROR = `${red("\u25B6 Login required!")}
3
3
 
4
4
  To authenticate with Astro Studio, run
@@ -9,26 +9,6 @@ const MISSING_PROJECT_ID_ERROR = `${red("\u25B6 Directory not linked.")}
9
9
  To link this directory to an Astro Studio project, run
10
10
  ${cyan("astro db link")}
11
11
  `;
12
- const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR = (collectionName) => `${red(
13
- `\u25B6 Writable collection ${bold(collectionName)} requires Astro Studio or the ${yellow(
14
- "unsafeWritable"
15
- )} option.`
16
- )}
17
-
18
- Visit ${cyan("https://astro.build/studio")} to create your account
19
- and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
20
- `;
21
- const UNSAFE_WRITABLE_WARNING = `${yellow(
22
- "unsafeWritable"
23
- )} option is enabled and you are using writable tables.
24
- Redeploying your app may result in wiping away your database.
25
- I hope you know what you are doing.
26
- `;
27
- const STUDIO_CONFIG_MISSING_CLI_ERROR = `${red("\u25B6 This command requires Astro Studio.")}
28
-
29
- Visit ${cyan("https://astro.build/studio")} to create your account
30
- and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
31
- `;
32
12
  const MIGRATIONS_NOT_INITIALIZED = `${yellow(
33
13
  "\u25B6 No migrations found!"
34
14
  )}
@@ -36,19 +16,46 @@ const MIGRATIONS_NOT_INITIALIZED = `${yellow(
36
16
  To scaffold your migrations folder, run
37
17
  ${cyan("astro db sync")}
38
18
  `;
39
- const SEED_WRITABLE_IN_PROD_ERROR = (collectionName) => {
40
- return `${red(
41
- `Writable tables should not be seeded in production with data().`
42
- )} You can seed ${bold(
43
- collectionName
44
- )} in development mode only using the "mode" flag. See the docs for more: https://www.notion.so/astroinc/astrojs-db-README-dcf6fa10de9a4f528be56cee96e8c054?pvs=4#278aed3fc37e4cec80240d1552ff6ac5`;
19
+ const MISSING_EXECUTE_PATH_ERROR = `${red(
20
+ "\u25B6 No file path provided."
21
+ )} Provide a path by running ${cyan("astro db execute <path>")}
22
+ `;
23
+ const FILE_NOT_FOUND_ERROR = (path) => `${red("\u25B6 File not found:")} ${bold(path)}
24
+ `;
25
+ const SEED_ERROR = (error) => {
26
+ return `${red(`Error while seeding database:`)}
27
+
28
+ ${error}`;
29
+ };
30
+ const REFERENCE_DNE_ERROR = (columnName) => {
31
+ return `Column ${bold(
32
+ columnName
33
+ )} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
34
+ };
35
+ const FOREIGN_KEY_DNE_ERROR = (tableName) => {
36
+ return `Table ${bold(
37
+ tableName
38
+ )} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
39
+ };
40
+ const FOREIGN_KEY_REFERENCES_LENGTH_ERROR = (tableName) => {
41
+ return `Foreign key on ${bold(
42
+ tableName
43
+ )} is misconfigured. \`columns\` and \`references\` must be the same length.`;
44
+ };
45
+ const FOREIGN_KEY_REFERENCES_EMPTY_ERROR = (tableName) => {
46
+ return `Foreign key on ${bold(
47
+ tableName
48
+ )} is misconfigured. \`references\` array cannot be empty.`;
45
49
  };
46
50
  export {
51
+ FILE_NOT_FOUND_ERROR,
52
+ FOREIGN_KEY_DNE_ERROR,
53
+ FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
54
+ FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
47
55
  MIGRATIONS_NOT_INITIALIZED,
56
+ MISSING_EXECUTE_PATH_ERROR,
48
57
  MISSING_PROJECT_ID_ERROR,
49
58
  MISSING_SESSION_ID_ERROR,
50
- SEED_WRITABLE_IN_PROD_ERROR,
51
- STUDIO_CONFIG_MISSING_CLI_ERROR,
52
- STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
53
- UNSAFE_WRITABLE_WARNING
59
+ REFERENCE_DNE_ERROR,
60
+ SEED_ERROR
54
61
  };
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
- import { pathToFileURL } from "node:url";
3
2
  import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
4
  async function copyFile(toDir, fromUrl, toUrl) {
5
5
  await fs.promises.mkdir(toDir, { recursive: true });
6
6
  await fs.promises.rename(fromUrl, toUrl);
@@ -1,69 +1,27 @@
1
- var __knownSymbol = (name, symbol) => {
2
- return (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
3
- };
4
- var __using = (stack, value, async) => {
5
- if (value != null) {
6
- if (typeof value !== "object" && typeof value !== "function")
7
- throw TypeError("Object expected");
8
- var dispose;
9
- if (async)
10
- dispose = value[__knownSymbol("asyncDispose")];
11
- if (dispose === void 0)
12
- dispose = value[__knownSymbol("dispose")];
13
- if (typeof dispose !== "function")
14
- throw TypeError("Object not disposable");
15
- stack.push([async, dispose, value]);
16
- } else if (async) {
17
- stack.push([async]);
18
- }
19
- return value;
20
- };
21
- var __callDispose = (stack, error, hasError) => {
22
- var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
23
- return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
24
- };
25
- var fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e);
26
- var next = (it) => {
27
- while (it = stack.pop()) {
28
- try {
29
- var result = it[1] && it[1].call(it[2]);
30
- if (it[0])
31
- return Promise.resolve(result).then(next, (e) => (fail(e), next()));
32
- } catch (e) {
33
- fail(e);
34
- }
35
- }
36
- if (hasError)
37
- throw error;
38
- };
39
- return next();
40
- };
41
- import { vitePluginDb } from "./vite-plugin-db.js";
42
- import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
43
- import { typegen } from "./typegen.js";
44
1
  import { existsSync } from "fs";
45
- import { mkdir, rm, writeFile } from "fs/promises";
46
- import { DB_PATH } from "../consts.js";
47
- import { createLocalDatabaseClient } from "../../runtime/db-client.js";
48
- import { astroConfigWithDbSchema } from "../types.js";
49
- import {} from "../utils.js";
50
- import {
51
- STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
52
- UNSAFE_WRITABLE_WARNING
53
- } from "../errors.js";
54
- import { errorMap } from "./error-map.js";
55
2
  import { dirname } from "path";
56
3
  import { fileURLToPath } from "url";
4
+ import { mkdir, rm, writeFile } from "fs/promises";
57
5
  import { blue, yellow } from "kleur/colors";
58
- import { fileURLIntegration } from "./file-url.js";
59
- import { recreateTables, seedData } from "../queries.js";
6
+ import { CONFIG_FILE_NAMES, DB_PATH } from "../consts.js";
7
+ import { loadDbConfigFile } from "../load-file.js";
60
8
  import { getManagedAppTokenOrExit } from "../tokens.js";
9
+ import { dbConfigSchema } from "../types.js";
10
+ import { getDbDirectoryUrl } from "../utils.js";
11
+ import { errorMap } from "./error-map.js";
12
+ import { fileURLIntegration } from "./file-url.js";
13
+ import { typegen } from "./typegen.js";
14
+ import { vitePluginDb } from "./vite-plugin-db.js";
15
+ import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
61
16
  function astroDBIntegration() {
62
- let connectedToRemote = false;
17
+ let connectToStudio = false;
18
+ let configFileDependencies = [];
19
+ let root;
63
20
  let appToken;
64
- let schemas = {
65
- tables() {
66
- throw new Error("tables not found");
21
+ let dbConfig;
22
+ let tables = {
23
+ get() {
24
+ throw new Error("[astro:db] INTERNAL Tables not loaded yet");
67
25
  }
68
26
  };
69
27
  let command;
@@ -72,24 +30,26 @@ function astroDBIntegration() {
72
30
  hooks: {
73
31
  "astro:config:setup": async ({ updateConfig, config, command: _command, logger }) => {
74
32
  command = _command;
75
- if (_command === "preview")
33
+ root = config.root;
34
+ if (command === "preview")
76
35
  return;
77
36
  let dbPlugin = void 0;
78
- const studio = config.db?.studio ?? false;
79
- if (studio && command === "build" && process.env.ASTRO_DB_TEST_ENV !== "1") {
37
+ connectToStudio = command === "build";
38
+ if (connectToStudio) {
80
39
  appToken = await getManagedAppTokenOrExit();
81
- connectedToRemote = true;
82
40
  dbPlugin = vitePluginDb({
83
- connectToStudio: true,
41
+ connectToStudio,
84
42
  appToken: appToken.token,
85
- schemas,
86
- root: config.root
43
+ tables,
44
+ root: config.root,
45
+ srcDir: config.srcDir
87
46
  });
88
47
  } else {
89
48
  dbPlugin = vitePluginDb({
90
49
  connectToStudio: false,
91
- schemas,
92
- root: config.root
50
+ tables,
51
+ root: config.root,
52
+ srcDir: config.srcDir
93
53
  });
94
54
  }
95
55
  updateConfig({
@@ -99,65 +59,44 @@ function astroDBIntegration() {
99
59
  }
100
60
  });
101
61
  },
102
- "astro:config:done": async ({ config, logger }) => {
103
- const configWithDb = astroConfigWithDbSchema.parse(config, { errorMap });
104
- const tables = configWithDb.db?.tables ?? {};
105
- schemas.tables = () => tables;
106
- const studio = configWithDb.db?.studio ?? false;
107
- const unsafeWritable = Boolean(configWithDb.db?.unsafeWritable);
108
- const foundWritableCollection = Object.entries(tables).find(([, c]) => c.writable);
109
- const writableAllowed = studio || unsafeWritable;
110
- if (!writableAllowed && foundWritableCollection) {
111
- logger.error(
112
- STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR(foundWritableCollection[0])
113
- );
114
- process.exit(1);
115
- } else if (unsafeWritable && foundWritableCollection) {
116
- logger.warn(UNSAFE_WRITABLE_WARNING);
117
- }
118
- if (!connectedToRemote) {
119
- var _stack = [];
120
- try {
121
- const dbUrl = new URL(DB_PATH, config.root);
122
- if (existsSync(dbUrl)) {
123
- await rm(dbUrl);
124
- }
125
- await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
126
- await writeFile(dbUrl, "");
127
- const db = __using(_stack, await createLocalDatabaseClient({
128
- tables,
129
- dbUrl: dbUrl.toString(),
130
- seeding: true
131
- }));
132
- await recreateTables({ db, tables });
133
- if (configWithDb.db?.data) {
134
- await seedData({
135
- db,
136
- data: configWithDb.db.data,
137
- logger,
138
- mode: command === "dev" ? "dev" : "build"
139
- });
140
- }
141
- logger.debug("Database setup complete.");
142
- } catch (_) {
143
- var _error = _, _hasError = true;
144
- } finally {
145
- __callDispose(_stack, _error, _hasError);
62
+ "astro:config:done": async ({ config }) => {
63
+ const { mod, dependencies } = await loadDbConfigFile(config.root);
64
+ configFileDependencies = dependencies;
65
+ dbConfig = dbConfigSchema.parse(mod?.default ?? {}, {
66
+ errorMap
67
+ });
68
+ tables.get = () => dbConfig.tables ?? {};
69
+ if (!connectToStudio && !process.env.TEST_IN_MEMORY_DB) {
70
+ const dbUrl = new URL(DB_PATH, config.root);
71
+ if (existsSync(dbUrl)) {
72
+ await rm(dbUrl);
146
73
  }
74
+ await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
75
+ await writeFile(dbUrl, "");
147
76
  }
148
- await typegen({ tables, root: config.root });
77
+ await typegen({ tables: tables.get() ?? {}, root: config.root });
149
78
  },
150
79
  "astro:server:start": async ({ logger }) => {
151
80
  setTimeout(() => {
152
81
  logger.info(
153
- connectedToRemote ? "Connected to remote database." : "New local database created."
82
+ connectToStudio ? "Connected to remote database." : "New local database created."
154
83
  );
155
84
  }, 100);
156
85
  },
86
+ "astro:server:setup": async ({ server }) => {
87
+ const filesToWatch = [
88
+ ...CONFIG_FILE_NAMES.map((c) => new URL(c, getDbDirectoryUrl(root))),
89
+ ...configFileDependencies.map((c) => new URL(c, root))
90
+ ];
91
+ server.watcher.on("all", (event, relativeEntry) => {
92
+ const entry = new URL(relativeEntry, root);
93
+ if (filesToWatch.some((f) => entry.href === f.href)) {
94
+ server.restart();
95
+ }
96
+ });
97
+ },
157
98
  "astro:build:start": async ({ logger }) => {
158
- logger.info(
159
- "database: " + (connectedToRemote ? yellow("remote") : blue("local database."))
160
- );
99
+ logger.info("database: " + (connectToStudio ? yellow("remote") : blue("local database.")));
161
100
  },
162
101
  "astro:build:done": async ({}) => {
163
102
  await appToken?.destroy();