@astrojs/db 0.3.4 → 0.3.6-nightly-01234567890

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 (52) hide show
  1. package/dist/cli/bin.d.ts +2 -0
  2. package/dist/cli/commands/deploy/index.d.ts +1 -0
  3. package/dist/cli/commands/diff/index.d.ts +4 -0
  4. package/dist/cli/commands/run/index.d.ts +1 -0
  5. package/dist/cli/commands/snapshot/index.d.ts +4 -0
  6. package/dist/cli/util.d.ts +34 -0
  7. package/dist/config.d.ts +13 -137
  8. package/dist/core/cli/commands/gen/index.d.ts +6 -0
  9. package/dist/core/cli/commands/link/index.js +7 -3
  10. package/dist/core/cli/commands/push/index.js +3 -3
  11. package/dist/core/cli/commands/verify/index.js +6 -1
  12. package/dist/core/cli/index.js +8 -6
  13. package/dist/core/cli/migration-queries.d.ts +4 -4
  14. package/dist/core/cli/migration-queries.js +78 -77
  15. package/dist/core/cli/migrations.js +15 -7
  16. package/dist/core/errors.d.ts +2 -0
  17. package/dist/core/errors.js +26 -9
  18. package/dist/core/integration/file-url.js +2 -1
  19. package/dist/core/integration/index.js +106 -53
  20. package/dist/core/integration/typegen.d.ts +3 -3
  21. package/dist/core/integration/typegen.js +8 -8
  22. package/dist/core/integration/vite-plugin-db.d.ts +14 -9
  23. package/dist/core/integration/vite-plugin-db.js +15 -12
  24. package/dist/core/integration/vite-plugin-inject-env-ts.d.ts +4 -2
  25. package/dist/core/integration/vite-plugin-inject-env-ts.js +8 -4
  26. package/dist/core/queries.d.ts +20 -20
  27. package/dist/core/queries.js +50 -32
  28. package/dist/core/types.d.ts +1162 -1153
  29. package/dist/core/types.js +63 -61
  30. package/dist/core/utils.js +1 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +4 -4
  33. package/dist/integration.d.ts +1 -1
  34. package/dist/internal.d.ts +4 -4
  35. package/dist/runtime/db-client.d.ts +9 -4
  36. package/dist/runtime/db-client.js +11 -7
  37. package/dist/runtime/index.d.ts +7 -7
  38. package/dist/runtime/index.js +29 -43
  39. package/dist/runtime/types.d.ts +7 -7
  40. package/dist/types.d.ts +6 -124
  41. package/dist/utils-runtime.d.ts +1 -0
  42. package/dist/vite-plugin-db.d.ts +3 -3
  43. package/package.json +13 -15
  44. package/LICENSE +0 -59
  45. package/components/Renderer.astro +0 -14
  46. package/components/astro-env.d.ts +0 -1
  47. package/components/index.ts +0 -2
  48. package/components/tsconfig.json +0 -7
  49. package/dist/cli/seed.d.ts +0 -6
  50. package/dist/file-url-integration.d.ts +0 -2
  51. package/dist/root.d.ts +0 -3
  52. /package/dist/core/cli/commands/{sync → gen}/index.js +0 -0
@@ -1,5 +1,8 @@
1
1
  import * as color from "kleur/colors";
2
2
  import deepDiff from "deep-diff";
3
+ import {
4
+ columnSchema
5
+ } from "../types.js";
3
6
  import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
4
7
  import { customAlphabet } from "nanoid";
5
8
  import prompts from "prompts";
@@ -65,9 +68,9 @@ async function getCollectionChangeQueries({
65
68
  }) {
66
69
  const queries = [];
67
70
  const confirmations = [];
68
- const updated = getUpdatedFields(oldCollection.fields, newCollection.fields);
69
- let added = getAdded(oldCollection.fields, newCollection.fields);
70
- let dropped = getDropped(oldCollection.fields, newCollection.fields);
71
+ const updated = getUpdatedColumns(oldCollection.columns, newCollection.columns);
72
+ let added = getAdded(oldCollection.columns, newCollection.columns);
73
+ let dropped = getDropped(oldCollection.columns, newCollection.columns);
71
74
  const hasForeignKeyChanges = Boolean(
72
75
  deepDiff(oldCollection.foreignKeys, newCollection.foreignKeys)
73
76
  );
@@ -82,10 +85,10 @@ async function getCollectionChangeQueries({
82
85
  };
83
86
  }
84
87
  if (!hasForeignKeyChanges && !isEmpty(added) && !isEmpty(dropped)) {
85
- const resolved = await resolveFieldRenames(collectionName, added, dropped, ambiguityResponses);
88
+ const resolved = await resolveColumnRenames(collectionName, added, dropped, ambiguityResponses);
86
89
  added = resolved.added;
87
90
  dropped = resolved.dropped;
88
- queries.push(...getFieldRenameQueries(collectionName, resolved.renamed));
91
+ queries.push(...getColumnRenameQueries(collectionName, resolved.renamed));
89
92
  }
90
93
  if (!hasForeignKeyChanges && isEmpty(updated) && Object.values(dropped).every(canAlterTableDropColumn) && Object.values(added).every(canAlterTableAddColumn)) {
91
94
  queries.push(
@@ -100,33 +103,33 @@ async function getCollectionChangeQueries({
100
103
  }
101
104
  const dataLossCheck = canRecreateTableWithoutDataLoss(added, updated);
102
105
  if (dataLossCheck.dataLoss) {
103
- const { reason, fieldName } = dataLossCheck;
106
+ const { reason, columnName } = dataLossCheck;
104
107
  const reasonMsgs = {
105
- "added-required": `New field ${color.bold(
106
- collectionName + "." + fieldName
108
+ "added-required": `New column ${color.bold(
109
+ collectionName + "." + columnName
107
110
  )} is required with no default value.
108
111
  This requires deleting existing data in the ${color.bold(
109
112
  collectionName
110
113
  )} collection.`,
111
- "added-unique": `New field ${color.bold(
112
- collectionName + "." + fieldName
114
+ "added-unique": `New column ${color.bold(
115
+ collectionName + "." + columnName
113
116
  )} is marked as unique.
114
117
  This requires deleting existing data in the ${color.bold(
115
118
  collectionName
116
119
  )} collection.`,
117
- "updated-type": `Updated field ${color.bold(
118
- collectionName + "." + fieldName
119
- )} cannot convert data to new field data type.
120
+ "updated-type": `Updated column ${color.bold(
121
+ collectionName + "." + columnName
122
+ )} cannot convert data to new column data type.
120
123
  This requires deleting existing data in the ${color.bold(
121
124
  collectionName
122
125
  )} collection.`
123
126
  };
124
127
  confirmations.push(reasonMsgs[reason]);
125
128
  }
126
- const primaryKeyExists = Object.entries(newCollection.fields).find(
127
- ([, field]) => hasPrimaryKey(field)
129
+ const primaryKeyExists = Object.entries(newCollection.columns).find(
130
+ ([, column]) => hasPrimaryKey(column)
128
131
  );
129
- const droppedPrimaryKey = Object.entries(dropped).find(([, field]) => hasPrimaryKey(field));
132
+ const droppedPrimaryKey = Object.entries(dropped).find(([, column]) => hasPrimaryKey(column));
130
133
  const recreateTableQueries = getRecreateTableQueries({
131
134
  collectionName,
132
135
  newCollection,
@@ -155,20 +158,20 @@ function getChangeIndexQueries({
155
158
  queries.push(...getCreateIndexQueries(collectionName, { indexes: added }));
156
159
  return queries;
157
160
  }
158
- async function resolveFieldRenames(collectionName, mightAdd, mightDrop, ambiguityResponses) {
161
+ async function resolveColumnRenames(collectionName, mightAdd, mightDrop, ambiguityResponses) {
159
162
  const added = {};
160
163
  const dropped = {};
161
164
  const renamed = [];
162
- for (const [fieldName, field] of Object.entries(mightAdd)) {
163
- let oldFieldName = ambiguityResponses ? ambiguityResponses.fieldRenames[collectionName]?.[fieldName] ?? "__NEW__" : void 0;
164
- if (!oldFieldName) {
165
+ for (const [columnName, column] of Object.entries(mightAdd)) {
166
+ let oldColumnName = ambiguityResponses ? ambiguityResponses.columnRenames[collectionName]?.[columnName] ?? "__NEW__" : void 0;
167
+ if (!oldColumnName) {
165
168
  const res = await prompts(
166
169
  {
167
170
  type: "select",
168
- name: "fieldName",
169
- message: "New field " + color.blue(color.bold(`${collectionName}.${fieldName}`)) + " detected. Was this renamed from an existing field?",
171
+ name: "columnName",
172
+ message: "New column " + color.blue(color.bold(`${collectionName}.${columnName}`)) + " detected. Was this renamed from an existing column?",
170
173
  choices: [
171
- { title: "New field (not renamed from existing)", value: "__NEW__" },
174
+ { title: "New column (not renamed from existing)", value: "__NEW__" },
172
175
  ...Object.keys(mightDrop).filter((key) => !(key in renamed)).map((key) => ({ title: key, value: key }))
173
176
  ]
174
177
  },
@@ -178,17 +181,17 @@ async function resolveFieldRenames(collectionName, mightAdd, mightDrop, ambiguit
178
181
  }
179
182
  }
180
183
  );
181
- oldFieldName = res.fieldName;
184
+ oldColumnName = res.columnName;
182
185
  }
183
- if (oldFieldName === "__NEW__") {
184
- added[fieldName] = field;
186
+ if (oldColumnName === "__NEW__") {
187
+ added[columnName] = column;
185
188
  } else {
186
- renamed.push({ from: oldFieldName, to: fieldName });
189
+ renamed.push({ from: oldColumnName, to: columnName });
187
190
  }
188
191
  }
189
- for (const [droppedFieldName, droppedField] of Object.entries(mightDrop)) {
190
- if (!renamed.find((r) => r.from === droppedFieldName)) {
191
- dropped[droppedFieldName] = droppedField;
192
+ for (const [droppedColumnName, droppedColumn] of Object.entries(mightDrop)) {
193
+ if (!renamed.find((r) => r.from === droppedColumnName)) {
194
+ dropped[droppedColumnName] = droppedColumn;
192
195
  }
193
196
  }
194
197
  return { added, dropped, renamed };
@@ -247,7 +250,7 @@ function getDroppedCollections(oldCollections, newCollections) {
247
250
  }
248
251
  return dropped;
249
252
  }
250
- function getFieldRenameQueries(unescapedCollectionName, renamed) {
253
+ function getColumnRenameQueries(unescapedCollectionName, renamed) {
251
254
  const queries = [];
252
255
  const collectionName = sqlite.escapeName(unescapedCollectionName);
253
256
  for (const { from, to } of renamed) {
@@ -261,18 +264,18 @@ function getFieldRenameQueries(unescapedCollectionName, renamed) {
261
264
  function getAlterTableQueries(unescapedCollectionName, added, dropped) {
262
265
  const queries = [];
263
266
  const collectionName = sqlite.escapeName(unescapedCollectionName);
264
- for (const [unescFieldName, field] of Object.entries(added)) {
265
- const fieldName = sqlite.escapeName(unescFieldName);
266
- const type = schemaTypeToSqlType(field.type);
267
- const q = `ALTER TABLE ${collectionName} ADD COLUMN ${fieldName} ${type}${getModifiers(
268
- fieldName,
269
- field
267
+ for (const [unescColumnName, column] of Object.entries(added)) {
268
+ const columnName = sqlite.escapeName(unescColumnName);
269
+ const type = schemaTypeToSqlType(column.type);
270
+ const q = `ALTER TABLE ${collectionName} ADD COLUMN ${columnName} ${type}${getModifiers(
271
+ columnName,
272
+ column
270
273
  )}`;
271
274
  queries.push(q);
272
275
  }
273
- for (const unescFieldName of Object.keys(dropped)) {
274
- const fieldName = sqlite.escapeName(unescFieldName);
275
- const q = `ALTER TABLE ${collectionName} DROP COLUMN ${fieldName}`;
276
+ for (const unescColumnName of Object.keys(dropped)) {
277
+ const columnName = sqlite.escapeName(unescColumnName);
278
+ const q = `ALTER TABLE ${collectionName} DROP COLUMN ${columnName}`;
276
279
  queries.push(q);
277
280
  }
278
281
  return queries;
@@ -293,7 +296,7 @@ function getRecreateTableQueries({
293
296
  getCreateTableQuery(unescCollectionName, newCollection)
294
297
  ];
295
298
  }
296
- const newColumns = [...Object.keys(newCollection.fields)];
299
+ const newColumns = [...Object.keys(newCollection.columns)];
297
300
  if (migrateHiddenPrimaryKey) {
298
301
  newColumns.unshift("_id");
299
302
  }
@@ -308,41 +311,41 @@ function getRecreateTableQueries({
308
311
  function isEmpty(obj) {
309
312
  return Object.keys(obj).length === 0;
310
313
  }
311
- function canAlterTableAddColumn(field) {
312
- if (field.schema.unique)
314
+ function canAlterTableAddColumn(column) {
315
+ if (column.schema.unique)
313
316
  return false;
314
- if (hasRuntimeDefault(field))
317
+ if (hasRuntimeDefault(column))
315
318
  return false;
316
- if (!field.schema.optional && !hasDefault(field))
319
+ if (!column.schema.optional && !hasDefault(column))
317
320
  return false;
318
- if (hasPrimaryKey(field))
321
+ if (hasPrimaryKey(column))
319
322
  return false;
320
- if (getReferencesConfig(field))
323
+ if (getReferencesConfig(column))
321
324
  return false;
322
325
  return true;
323
326
  }
324
- function canAlterTableDropColumn(field) {
325
- if (field.schema.unique)
327
+ function canAlterTableDropColumn(column) {
328
+ if (column.schema.unique)
326
329
  return false;
327
- if (hasPrimaryKey(field))
330
+ if (hasPrimaryKey(column))
328
331
  return false;
329
332
  return true;
330
333
  }
331
334
  function canRecreateTableWithoutDataLoss(added, updated) {
332
- for (const [fieldName, a] of Object.entries(added)) {
335
+ for (const [columnName, a] of Object.entries(added)) {
333
336
  if (hasPrimaryKey(a) && a.type !== "number" && !hasDefault(a)) {
334
- return { dataLoss: true, fieldName, reason: "added-required" };
337
+ return { dataLoss: true, columnName, reason: "added-required" };
335
338
  }
336
339
  if (!a.schema.optional && !hasDefault(a)) {
337
- return { dataLoss: true, fieldName, reason: "added-required" };
340
+ return { dataLoss: true, columnName, reason: "added-required" };
338
341
  }
339
342
  if (!a.schema.optional && a.schema.unique) {
340
- return { dataLoss: true, fieldName, reason: "added-unique" };
343
+ return { dataLoss: true, columnName, reason: "added-unique" };
341
344
  }
342
345
  }
343
- for (const [fieldName, u] of Object.entries(updated)) {
346
+ for (const [columnName, u] of Object.entries(updated)) {
344
347
  if (u.old.type !== u.new.type && !canChangeTypeWithoutQuery(u.old, u.new)) {
345
- return { dataLoss: true, fieldName, reason: "updated-type" };
348
+ return { dataLoss: true, columnName, reason: "updated-type" };
346
349
  }
347
350
  }
348
351
  return { dataLoss: false };
@@ -374,21 +377,24 @@ function getUpdated(oldObj, newObj) {
374
377
  }
375
378
  return updated;
376
379
  }
377
- function getUpdatedFields(oldFields, newFields) {
380
+ function getUpdatedColumns(oldColumns, newColumns) {
378
381
  const updated = {};
379
- for (const [key, newField] of Object.entries(newFields)) {
380
- const oldField = oldFields[key];
381
- if (!oldField)
382
+ for (const [key, newColumn] of Object.entries(newColumns)) {
383
+ let oldColumn = oldColumns[key];
384
+ if (!oldColumn)
382
385
  continue;
383
- const diff = deepDiff(oldField, newField, (path, objKey) => {
384
- const isTypeKey = objKey === "type" && path.length === 0;
385
- return (
386
- // If we can safely update the type without a SQL query, ignore the diff
387
- isTypeKey && oldField.type !== newField.type && canChangeTypeWithoutQuery(oldField, newField)
388
- );
389
- });
386
+ if (oldColumn.type !== newColumn.type && canChangeTypeWithoutQuery(oldColumn, newColumn)) {
387
+ const asNewColumn = columnSchema.safeParse({
388
+ type: newColumn.type,
389
+ schema: oldColumn.schema
390
+ });
391
+ if (asNewColumn.success) {
392
+ oldColumn = asNewColumn.data;
393
+ }
394
+ }
395
+ const diff = deepDiff(oldColumn, newColumn);
390
396
  if (diff) {
391
- updated[key] = { old: oldField, new: newField };
397
+ updated[key] = { old: oldColumn, new: newColumn };
392
398
  }
393
399
  }
394
400
  return updated;
@@ -397,19 +403,14 @@ const typeChangesWithoutQuery = [
397
403
  { from: "boolean", to: "number" },
398
404
  { from: "date", to: "text" },
399
405
  { from: "json", to: "text" }
400
- // TODO: decide on these. They *could* work with SQLite CAST
401
- // { from: 'boolean', to: 'text' },
402
- // { from: 'boolean', to: 'json' },
403
- // { from: 'number', to: 'text' },
404
- // { from: 'number', to: 'json' },
405
406
  ];
406
- function canChangeTypeWithoutQuery(oldField, newField) {
407
+ function canChangeTypeWithoutQuery(oldColumn, newColumn) {
407
408
  return typeChangesWithoutQuery.some(
408
- ({ from, to }) => oldField.type === from && newField.type === to
409
+ ({ from, to }) => oldColumn.type === from && newColumn.type === to
409
410
  );
410
411
  }
411
- function hasRuntimeDefault(field) {
412
- return !!(field.schema.default && isSerializedSQL(field.schema.default));
412
+ function hasRuntimeDefault(column) {
413
+ return !!(column.schema.default && isSerializedSQL(column.schema.default));
413
414
  }
414
415
  export {
415
416
  getCollectionChangeQueries,
@@ -1,6 +1,6 @@
1
1
  import deepDiff from "deep-diff";
2
2
  import { mkdir, readFile, readdir, writeFile } from "fs/promises";
3
- import { collectionsSchema } from "../types.js";
3
+ import { tablesSchema } from "../types.js";
4
4
  import { cyan, green, yellow } from "kleur/colors";
5
5
  const { applyChange, diff: generateDiff } = deepDiff;
6
6
  async function getMigrationStatus(config) {
@@ -31,20 +31,28 @@ async function getMigrationStatus(config) {
31
31
  currentSnapshot
32
32
  };
33
33
  }
34
- const MIGRATIONS_CREATED = `${green("\u25A0 Migrations initialized!")}
34
+ const MIGRATIONS_CREATED = `${green(
35
+ "\u25A0 Migrations initialized!"
36
+ )}
35
37
 
36
38
  To execute your migrations, run
37
39
  ${cyan("astro db push")}`;
38
- const MIGRATIONS_UP_TO_DATE = `${green("\u25A0 No migrations needed!")}
40
+ const MIGRATIONS_UP_TO_DATE = `${green(
41
+ "\u25A0 No migrations needed!"
42
+ )}
39
43
 
40
44
  Your database is up to date.
41
45
  `;
42
- const MIGRATIONS_NOT_INITIALIZED = `${yellow("\u25B6 No migrations found!")}
46
+ const MIGRATIONS_NOT_INITIALIZED = `${yellow(
47
+ "\u25B6 No migrations found!"
48
+ )}
43
49
 
44
50
  To scaffold your migrations folder, run
45
51
  ${cyan("astro db sync")}
46
52
  `;
47
- const MIGRATION_NEEDED = `${yellow("\u25B6 Changes detected!")}
53
+ const MIGRATION_NEEDED = `${yellow(
54
+ "\u25B6 Changes detected!"
55
+ )}
48
56
 
49
57
  To create the necessary migration file, run
50
58
  ${cyan("astro db sync")}
@@ -98,8 +106,8 @@ async function initializeFromMigrations(allMigrationFiles) {
98
106
  return prevSnapshot;
99
107
  }
100
108
  function createCurrentSnapshot(config) {
101
- const collectionsConfig = collectionsSchema.parse(config.db?.collections ?? {});
102
- const schema = JSON.parse(JSON.stringify(collectionsConfig));
109
+ const tablesConfig = tablesSchema.parse(config.db?.tables ?? {});
110
+ const schema = JSON.parse(JSON.stringify(tablesConfig));
103
111
  return { experimentalVersion: 1, schema };
104
112
  }
105
113
  function createEmptySnapshot() {
@@ -1,5 +1,7 @@
1
1
  export declare const MISSING_SESSION_ID_ERROR: string;
2
2
  export declare const MISSING_PROJECT_ID_ERROR: string;
3
3
  export declare const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR: (collectionName: string) => string;
4
+ export declare const UNSAFE_WRITABLE_WARNING: string;
4
5
  export declare const STUDIO_CONFIG_MISSING_CLI_ERROR: string;
5
6
  export declare const MIGRATIONS_NOT_INITIALIZED: string;
7
+ export declare const SEED_WRITABLE_IN_PROD_ERROR: (collectionName: string) => string;
@@ -1,37 +1,54 @@
1
1
  import { cyan, bold, red, green, yellow } from "kleur/colors";
2
- const MISSING_SESSION_ID_ERROR = `${red(
3
- "\u25B6 Login required!"
4
- )}
2
+ const MISSING_SESSION_ID_ERROR = `${red("\u25B6 Login required!")}
5
3
 
6
4
  To authenticate with Astro Studio, run
7
5
  ${cyan("astro db login")}
8
6
  `;
9
- const MISSING_PROJECT_ID_ERROR = `${red(
10
- "\u25B6 Directory not linked."
11
- )}
7
+ const MISSING_PROJECT_ID_ERROR = `${red("\u25B6 Directory not linked.")}
12
8
 
13
9
  To link this directory to an Astro Studio project, run
14
10
  ${cyan("astro db link")}
15
11
  `;
16
- const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR = (collectionName) => `${red(`\u25B6 Writable collection ${bold(collectionName)} requires Astro Studio.`)}
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
17
 
18
18
  Visit ${cyan("https://astro.build/studio")} to create your account
19
19
  and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
20
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
+ `;
21
27
  const STUDIO_CONFIG_MISSING_CLI_ERROR = `${red("\u25B6 This command requires Astro Studio.")}
22
28
 
23
29
  Visit ${cyan("https://astro.build/studio")} to create your account
24
30
  and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
25
31
  `;
26
- const MIGRATIONS_NOT_INITIALIZED = `${yellow("\u25B6 No migrations found!")}
32
+ const MIGRATIONS_NOT_INITIALIZED = `${yellow(
33
+ "\u25B6 No migrations found!"
34
+ )}
27
35
 
28
36
  To scaffold your migrations folder, run
29
37
  ${cyan("astro db sync")}
30
38
  `;
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`;
45
+ };
31
46
  export {
32
47
  MIGRATIONS_NOT_INITIALIZED,
33
48
  MISSING_PROJECT_ID_ERROR,
34
49
  MISSING_SESSION_ID_ERROR,
50
+ SEED_WRITABLE_IN_PROD_ERROR,
35
51
  STUDIO_CONFIG_MISSING_CLI_ERROR,
36
- STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR
52
+ STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
53
+ UNSAFE_WRITABLE_WARNING
37
54
  };
@@ -8,7 +8,7 @@ async function copyFile(toDir, fromUrl, toUrl) {
8
8
  function fileURLIntegration() {
9
9
  const fileNames = [];
10
10
  function createVitePlugin(command) {
11
- const referenceIds = [];
11
+ let referenceIds = [];
12
12
  return {
13
13
  name: "@astrojs/db/file-url",
14
14
  enforce: "pre",
@@ -34,6 +34,7 @@ function fileURLIntegration() {
34
34
  for (const referenceId of referenceIds) {
35
35
  fileNames.push(this.getFileName(referenceId));
36
36
  }
37
+ referenceIds = [];
37
38
  }
38
39
  };
39
40
  }
@@ -1,3 +1,43 @@
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
+ };
1
41
  import { vitePluginDb } from "./vite-plugin-db.js";
2
42
  import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
3
43
  import { typegen } from "./typegen.js";
@@ -7,7 +47,10 @@ import { DB_PATH } from "../consts.js";
7
47
  import { createLocalDatabaseClient } from "../../runtime/db-client.js";
8
48
  import { astroConfigWithDbSchema } from "../types.js";
9
49
  import {} from "../utils.js";
10
- import { STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR } from "../errors.js";
50
+ import {
51
+ STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
52
+ UNSAFE_WRITABLE_WARNING
53
+ } from "../errors.js";
11
54
  import { errorMap } from "./error-map.js";
12
55
  import { dirname } from "path";
13
56
  import { fileURLToPath } from "url";
@@ -18,81 +61,91 @@ import { getManagedAppTokenOrExit } from "../tokens.js";
18
61
  function astroDBIntegration() {
19
62
  let connectedToRemote = false;
20
63
  let appToken;
64
+ let schemas = {
65
+ tables() {
66
+ throw new Error("tables not found");
67
+ }
68
+ };
69
+ let command;
21
70
  return {
22
71
  name: "astro:db",
23
72
  hooks: {
24
- "astro:config:setup": async ({ logger, updateConfig, config, command }) => {
25
- if (command === "preview")
73
+ "astro:config:setup": async ({ updateConfig, config, command: _command, logger }) => {
74
+ command = _command;
75
+ if (_command === "preview")
26
76
  return;
27
- const configWithDb = astroConfigWithDbSchema.parse(config, { errorMap });
28
- const collections = configWithDb.db?.collections ?? {};
29
- const studio = configWithDb.db?.studio ?? false;
30
- const foundWritableCollection = Object.entries(collections).find(([, c]) => c.writable);
31
- if (!studio && foundWritableCollection) {
32
- logger.error(
33
- STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR(foundWritableCollection[0])
34
- );
35
- process.exit(1);
36
- }
37
- let dbPlugin;
77
+ let dbPlugin = void 0;
78
+ const studio = config.db?.studio ?? false;
38
79
  if (studio && command === "build" && process.env.ASTRO_DB_TEST_ENV !== "1") {
39
80
  appToken = await getManagedAppTokenOrExit();
40
81
  connectedToRemote = true;
41
82
  dbPlugin = vitePluginDb({
42
83
  connectToStudio: true,
43
- collections,
44
84
  appToken: appToken.token,
85
+ schemas,
45
86
  root: config.root
46
87
  });
47
88
  } else {
48
- const dbUrl = new URL(DB_PATH, config.root);
49
- if (existsSync(dbUrl)) {
50
- await rm(dbUrl);
51
- }
52
- await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
53
- await writeFile(dbUrl, "");
54
- const db = await createLocalDatabaseClient({
55
- collections,
56
- dbUrl: dbUrl.toString(),
57
- seeding: true
58
- });
59
- await recreateTables({ db, collections });
60
- if (configWithDb.db?.data) {
61
- await seedData({
62
- db,
63
- data: configWithDb.db.data,
64
- logger,
65
- mode: command === "dev" ? "dev" : "build"
66
- });
67
- }
68
- logger.debug("Database setup complete.");
69
89
  dbPlugin = vitePluginDb({
70
90
  connectToStudio: false,
71
- collections,
91
+ schemas,
72
92
  root: config.root
73
93
  });
74
94
  }
75
95
  updateConfig({
76
96
  vite: {
77
97
  assetsInclude: [DB_PATH],
78
- plugins: [
79
- dbPlugin,
80
- vitePluginInjectEnvTs(config),
81
- {
82
- name: "my-plugin",
83
- resolveId(id) {
84
- if (id.endsWith("?server-path")) {
85
- }
86
- },
87
- load(id) {
88
- if (id.endsWith("?server-path")) {
89
- }
90
- }
91
- }
92
- ]
98
+ plugins: [dbPlugin, vitePluginInjectEnvTs(config, logger)]
93
99
  }
94
100
  });
95
- await typegen({ collections, root: config.root });
101
+ },
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);
146
+ }
147
+ }
148
+ await typegen({ tables, root: config.root });
96
149
  },
97
150
  "astro:server:start": async ({ logger }) => {
98
151
  setTimeout(() => {
@@ -1,5 +1,5 @@
1
- import type { DBCollections } from '../types.js';
2
- export declare function typegen({ collections, root }: {
3
- collections: DBCollections;
1
+ import type { DBTables } from '../types.js';
2
+ export declare function typegen({ tables, root }: {
3
+ tables: DBTables;
4
4
  root: URL;
5
5
  }): Promise<void>;