@astrojs/db 0.8.1 → 0.8.2
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.
- package/dist/_internal/core/schemas.d.ts +5 -5
- package/dist/_internal/core/utils.d.ts +19 -0
- package/dist/core/cli/commands/link/index.js +61 -52
- package/dist/core/cli/commands/push/index.js +16 -13
- package/dist/core/cli/migration-queries.js +15 -12
- package/dist/core/cli/print-help.js +1 -1
- package/dist/core/schemas.d.ts +5 -5
- package/dist/core/schemas.js +1 -1
- package/dist/core/tokens.js +36 -15
- package/dist/core/utils.d.ts +11 -0
- package/dist/core/utils.js +11 -1
- package/dist/runtime/db-client.js +33 -26
- package/package.json +2 -2
|
@@ -578,7 +578,7 @@ export declare const jsonColumnSchema: z.ZodObject<{
|
|
|
578
578
|
default?: unknown;
|
|
579
579
|
};
|
|
580
580
|
}>;
|
|
581
|
-
export declare const columnSchema: z.
|
|
581
|
+
export declare const columnSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
582
582
|
type: z.ZodLiteral<"boolean">;
|
|
583
583
|
schema: z.ZodObject<{
|
|
584
584
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -1379,7 +1379,7 @@ export declare const referenceableColumnSchema: z.ZodUnion<[z.ZodObject<{
|
|
|
1379
1379
|
references?: (() => z.input<typeof numberColumnSchema>) | undefined;
|
|
1380
1380
|
});
|
|
1381
1381
|
}>]>;
|
|
1382
|
-
export declare const columnsSchema: z.ZodRecord<z.ZodString, z.
|
|
1382
|
+
export declare const columnsSchema: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
1383
1383
|
type: z.ZodLiteral<"boolean">;
|
|
1384
1384
|
schema: z.ZodObject<{
|
|
1385
1385
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -1871,7 +1871,7 @@ type ForeignKeysOutput = Omit<ForeignKeysInput, 'references'> & {
|
|
|
1871
1871
|
references: MaybeArray<Omit<z.output<typeof referenceableColumnSchema>, 'references'>>;
|
|
1872
1872
|
};
|
|
1873
1873
|
export declare const tableSchema: z.ZodObject<{
|
|
1874
|
-
columns: z.ZodRecord<z.ZodString, z.
|
|
1874
|
+
columns: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
1875
1875
|
type: z.ZodLiteral<"boolean">;
|
|
1876
1876
|
schema: z.ZodObject<{
|
|
1877
1877
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -2441,7 +2441,7 @@ export declare const tableSchema: z.ZodObject<{
|
|
|
2441
2441
|
deprecated?: boolean | undefined;
|
|
2442
2442
|
}>;
|
|
2443
2443
|
export declare const tablesSchema: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
2444
|
-
columns: z.ZodRecord<z.ZodString, z.
|
|
2444
|
+
columns: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
2445
2445
|
type: z.ZodLiteral<"boolean">;
|
|
2446
2446
|
schema: z.ZodObject<{
|
|
2447
2447
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -3101,7 +3101,7 @@ export declare const tablesSchema: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodOb
|
|
|
3101
3101
|
}>, unknown>;
|
|
3102
3102
|
export declare const dbConfigSchema: z.ZodObject<{
|
|
3103
3103
|
tables: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
3104
|
-
columns: z.ZodRecord<z.ZodString, z.
|
|
3104
|
+
columns: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
3105
3105
|
type: z.ZodLiteral<"boolean">;
|
|
3106
3106
|
schema: z.ZodObject<{
|
|
3107
3107
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AstroConfig, AstroIntegration } from 'astro';
|
|
2
|
+
import type { AstroDbIntegration } from './types.js';
|
|
3
|
+
export type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
|
|
4
|
+
export declare function getAstroStudioEnv(envMode?: string): Record<`ASTRO_STUDIO_${string}`, string>;
|
|
5
|
+
export declare function getRemoteDatabaseUrl(): string;
|
|
6
|
+
export declare function getAstroStudioUrl(): string;
|
|
7
|
+
export declare function getDbDirectoryUrl(root: URL | string): URL;
|
|
8
|
+
export declare function defineDbIntegration(integration: AstroDbIntegration): AstroIntegration;
|
|
9
|
+
/**
|
|
10
|
+
* 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.
|
|
11
|
+
*/
|
|
12
|
+
export declare function safeFetch(url: Parameters<typeof fetch>[0], options?: Parameters<typeof fetch>[1], onNotOK?: (response: Response) => void | Promise<void>): Promise<Response>;
|
|
13
|
+
export type Result<T> = {
|
|
14
|
+
success: true;
|
|
15
|
+
data: T;
|
|
16
|
+
} | {
|
|
17
|
+
success: false;
|
|
18
|
+
data: unknown;
|
|
19
|
+
};
|
|
@@ -7,7 +7,7 @@ import ora from "ora";
|
|
|
7
7
|
import prompts from "prompts";
|
|
8
8
|
import { MISSING_SESSION_ID_ERROR } from "../../../errors.js";
|
|
9
9
|
import { PROJECT_ID_FILE, getSessionIdFromFile } from "../../../tokens.js";
|
|
10
|
-
import { getAstroStudioUrl } from "../../../utils.js";
|
|
10
|
+
import { getAstroStudioUrl, safeFetch } from "../../../utils.js";
|
|
11
11
|
async function cmd() {
|
|
12
12
|
const sessionToken = await getSessionIdFromFile();
|
|
13
13
|
if (!sessionToken) {
|
|
@@ -45,30 +45,33 @@ async function linkProject(id) {
|
|
|
45
45
|
}
|
|
46
46
|
async function getWorkspaceId() {
|
|
47
47
|
const linkUrl = new URL(getAstroStudioUrl() + "/api/cli/workspaces.list");
|
|
48
|
-
const response = await
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
const response = await safeFetch(
|
|
49
|
+
linkUrl,
|
|
50
|
+
{
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
|
54
|
+
"Content-Type": "application/json"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
(res) => {
|
|
58
|
+
if (res.status === 401) {
|
|
59
|
+
console.error(
|
|
60
|
+
`${bgRed("Unauthorized")}
|
|
59
61
|
|
|
60
62
|
Are you logged in?
|
|
61
63
|
Run ${cyan(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
"astro db login"
|
|
65
|
+
)} to authenticate and then try linking again.
|
|
64
66
|
|
|
65
67
|
`
|
|
66
|
-
|
|
68
|
+
);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
console.error(`Failed to fetch user workspace: ${res.status} ${res.statusText}`);
|
|
67
72
|
process.exit(1);
|
|
68
73
|
}
|
|
69
|
-
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
74
|
+
);
|
|
72
75
|
const { data, success } = await response.json();
|
|
73
76
|
if (!success) {
|
|
74
77
|
console.error(`Failed to fetch user's workspace.`);
|
|
@@ -82,31 +85,34 @@ async function createNewProject({
|
|
|
82
85
|
region
|
|
83
86
|
}) {
|
|
84
87
|
const linkUrl = new URL(getAstroStudioUrl() + "/api/cli/projects.create");
|
|
85
|
-
const response = await
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const response = await safeFetch(
|
|
89
|
+
linkUrl,
|
|
90
|
+
{
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
|
94
|
+
"Content-Type": "application/json"
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify({ workspaceId, name, region })
|
|
90
97
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
console.error(
|
|
96
|
-
`${bgRed("Unauthorized")}
|
|
98
|
+
(res) => {
|
|
99
|
+
if (res.status === 401) {
|
|
100
|
+
console.error(
|
|
101
|
+
`${bgRed("Unauthorized")}
|
|
97
102
|
|
|
98
103
|
Are you logged in?
|
|
99
104
|
Run ${cyan(
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
"astro db login"
|
|
106
|
+
)} to authenticate and then try linking again.
|
|
102
107
|
|
|
103
108
|
`
|
|
104
|
-
|
|
109
|
+
);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
console.error(`Failed to create project: ${res.status} ${res.statusText}`);
|
|
105
113
|
process.exit(1);
|
|
106
114
|
}
|
|
107
|
-
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
115
|
+
);
|
|
110
116
|
const { data, success } = await response.json();
|
|
111
117
|
if (!success) {
|
|
112
118
|
console.error(`Failed to create project.`);
|
|
@@ -116,31 +122,34 @@ async function createNewProject({
|
|
|
116
122
|
}
|
|
117
123
|
async function promptExistingProjectName({ workspaceId }) {
|
|
118
124
|
const linkUrl = new URL(getAstroStudioUrl() + "/api/cli/projects.list");
|
|
119
|
-
const response = await
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
const response = await safeFetch(
|
|
126
|
+
linkUrl,
|
|
127
|
+
{
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: {
|
|
130
|
+
Authorization: `Bearer ${await getSessionIdFromFile()}`,
|
|
131
|
+
"Content-Type": "application/json"
|
|
132
|
+
},
|
|
133
|
+
body: JSON.stringify({ workspaceId })
|
|
124
134
|
},
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
console.error(
|
|
130
|
-
`${bgRed("Unauthorized")}
|
|
135
|
+
(res) => {
|
|
136
|
+
if (res.status === 401) {
|
|
137
|
+
console.error(
|
|
138
|
+
`${bgRed("Unauthorized")}
|
|
131
139
|
|
|
132
140
|
Are you logged in?
|
|
133
141
|
Run ${cyan(
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
"astro db login"
|
|
143
|
+
)} to authenticate and then try linking again.
|
|
136
144
|
|
|
137
145
|
`
|
|
138
|
-
|
|
146
|
+
);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
console.error(`Failed to fetch projects: ${res.status} ${res.statusText}`);
|
|
139
150
|
process.exit(1);
|
|
140
151
|
}
|
|
141
|
-
|
|
142
|
-
process.exit(1);
|
|
143
|
-
}
|
|
152
|
+
);
|
|
144
153
|
const { data, success } = await response.json();
|
|
145
154
|
if (!success) {
|
|
146
155
|
console.error(`Failed to fetch projects.`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MIGRATION_VERSION } from "../../../consts.js";
|
|
2
2
|
import { getManagedAppTokenOrExit } from "../../../tokens.js";
|
|
3
3
|
import {} from "../../../types.js";
|
|
4
|
-
import { getRemoteDatabaseUrl } from "../../../utils.js";
|
|
4
|
+
import { getRemoteDatabaseUrl, safeFetch } from "../../../utils.js";
|
|
5
5
|
import {
|
|
6
6
|
createCurrentSnapshot,
|
|
7
7
|
createEmptySnapshot,
|
|
@@ -64,18 +64,21 @@ async function pushSchema({
|
|
|
64
64
|
return new Response(null, { status: 200 });
|
|
65
65
|
}
|
|
66
66
|
const url = new URL("/db/push", getRemoteDatabaseUrl());
|
|
67
|
-
const response = await
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
67
|
+
const response = await safeFetch(
|
|
68
|
+
url,
|
|
69
|
+
{
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: new Headers({
|
|
72
|
+
Authorization: `Bearer ${appToken}`
|
|
73
|
+
}),
|
|
74
|
+
body: JSON.stringify(requestBody)
|
|
75
|
+
},
|
|
76
|
+
async (res) => {
|
|
77
|
+
console.error(`${url.toString()} failed: ${res.status} ${res.statusText}`);
|
|
78
|
+
console.error(await res.text());
|
|
79
|
+
throw new Error(`/db/push fetch failed: ${res.status} ${res.statusText}`);
|
|
80
|
+
}
|
|
81
|
+
);
|
|
79
82
|
const result = await response.json();
|
|
80
83
|
if (!result.success) {
|
|
81
84
|
console.error(`${url.toString()} unsuccessful`);
|
|
@@ -19,7 +19,7 @@ import { RENAME_COLUMN_ERROR, RENAME_TABLE_ERROR } from "../errors.js";
|
|
|
19
19
|
import { columnSchema } from "../schemas.js";
|
|
20
20
|
import {
|
|
21
21
|
} from "../types.js";
|
|
22
|
-
import { getRemoteDatabaseUrl } from "../utils.js";
|
|
22
|
+
import { getRemoteDatabaseUrl, safeFetch } from "../utils.js";
|
|
23
23
|
const sqlite = new SQLiteAsyncDialect();
|
|
24
24
|
const genTempTableName = customAlphabet("abcdefghijklmnopqrstuvwxyz", 10);
|
|
25
25
|
async function getMigrationQueries({
|
|
@@ -324,17 +324,20 @@ async function getProductionCurrentSnapshot({
|
|
|
324
324
|
appToken
|
|
325
325
|
}) {
|
|
326
326
|
const url = new URL("/db/schema", getRemoteDatabaseUrl());
|
|
327
|
-
const response = await
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
327
|
+
const response = await safeFetch(
|
|
328
|
+
url,
|
|
329
|
+
{
|
|
330
|
+
method: "POST",
|
|
331
|
+
headers: new Headers({
|
|
332
|
+
Authorization: `Bearer ${appToken}`
|
|
333
|
+
})
|
|
334
|
+
},
|
|
335
|
+
async (res) => {
|
|
336
|
+
console.error(`${url.toString()} failed: ${res.status} ${res.statusText}`);
|
|
337
|
+
console.error(await res.text());
|
|
338
|
+
throw new Error(`/db/schema fetch failed: ${res.status} ${res.statusText}`);
|
|
339
|
+
}
|
|
340
|
+
);
|
|
338
341
|
const result = await response.json();
|
|
339
342
|
if (!result.success) {
|
|
340
343
|
console.error(`${url.toString()} unsuccessful`);
|
package/dist/core/schemas.d.ts
CHANGED
|
@@ -578,7 +578,7 @@ export declare const jsonColumnSchema: z.ZodObject<{
|
|
|
578
578
|
default?: unknown;
|
|
579
579
|
};
|
|
580
580
|
}>;
|
|
581
|
-
export declare const columnSchema: z.
|
|
581
|
+
export declare const columnSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
582
582
|
type: z.ZodLiteral<"boolean">;
|
|
583
583
|
schema: z.ZodObject<{
|
|
584
584
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -1379,7 +1379,7 @@ export declare const referenceableColumnSchema: z.ZodUnion<[z.ZodObject<{
|
|
|
1379
1379
|
references?: (() => z.input<typeof numberColumnSchema>) | undefined;
|
|
1380
1380
|
});
|
|
1381
1381
|
}>]>;
|
|
1382
|
-
export declare const columnsSchema: z.ZodRecord<z.ZodString, z.
|
|
1382
|
+
export declare const columnsSchema: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
1383
1383
|
type: z.ZodLiteral<"boolean">;
|
|
1384
1384
|
schema: z.ZodObject<{
|
|
1385
1385
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -1871,7 +1871,7 @@ type ForeignKeysOutput = Omit<ForeignKeysInput, 'references'> & {
|
|
|
1871
1871
|
references: MaybeArray<Omit<z.output<typeof referenceableColumnSchema>, 'references'>>;
|
|
1872
1872
|
};
|
|
1873
1873
|
export declare const tableSchema: z.ZodObject<{
|
|
1874
|
-
columns: z.ZodRecord<z.ZodString, z.
|
|
1874
|
+
columns: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
1875
1875
|
type: z.ZodLiteral<"boolean">;
|
|
1876
1876
|
schema: z.ZodObject<{
|
|
1877
1877
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -2441,7 +2441,7 @@ export declare const tableSchema: z.ZodObject<{
|
|
|
2441
2441
|
deprecated?: boolean | undefined;
|
|
2442
2442
|
}>;
|
|
2443
2443
|
export declare const tablesSchema: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
2444
|
-
columns: z.ZodRecord<z.ZodString, z.
|
|
2444
|
+
columns: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
2445
2445
|
type: z.ZodLiteral<"boolean">;
|
|
2446
2446
|
schema: z.ZodObject<{
|
|
2447
2447
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -3101,7 +3101,7 @@ export declare const tablesSchema: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodOb
|
|
|
3101
3101
|
}>, unknown>;
|
|
3102
3102
|
export declare const dbConfigSchema: z.ZodObject<{
|
|
3103
3103
|
tables: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
3104
|
-
columns: z.ZodRecord<z.ZodString, z.
|
|
3104
|
+
columns: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
3105
3105
|
type: z.ZodLiteral<"boolean">;
|
|
3106
3106
|
schema: z.ZodObject<{
|
|
3107
3107
|
name: z.ZodOptional<z.ZodString>;
|
package/dist/core/schemas.js
CHANGED
package/dist/core/tokens.js
CHANGED
|
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { MISSING_PROJECT_ID_ERROR, MISSING_SESSION_ID_ERROR } from "./errors.js";
|
|
6
|
-
import { getAstroStudioEnv, getAstroStudioUrl } from "./utils.js";
|
|
6
|
+
import { getAstroStudioEnv, getAstroStudioUrl, getRemoteDatabaseUrl, safeFetch } from "./utils.js";
|
|
7
7
|
const SESSION_LOGIN_FILE = pathToFileURL(join(homedir(), ".astro", "session-token"));
|
|
8
8
|
const PROJECT_ID_FILE = pathToFileURL(join(process.cwd(), ".astro", "link"));
|
|
9
9
|
class ManagedLocalAppToken {
|
|
@@ -19,21 +19,35 @@ class ManagedLocalAppToken {
|
|
|
19
19
|
class ManagedRemoteAppToken {
|
|
20
20
|
token;
|
|
21
21
|
session;
|
|
22
|
+
region;
|
|
22
23
|
projectId;
|
|
23
24
|
ttl;
|
|
24
25
|
renewTimer;
|
|
26
|
+
static async getRegionCode() {
|
|
27
|
+
const pingResponse = await safeFetch(new URL(`${getRemoteDatabaseUrl()}/ping`));
|
|
28
|
+
const pingResult = await pingResponse.json();
|
|
29
|
+
return pingResult.data.region;
|
|
30
|
+
}
|
|
25
31
|
static async create(sessionToken, projectId) {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const region = await ManagedRemoteAppToken.getRegionCode();
|
|
33
|
+
const response = await safeFetch(
|
|
34
|
+
new URL(`${getAstroStudioUrl()}/auth/cli/token-create`),
|
|
35
|
+
{
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: new Headers({
|
|
38
|
+
Authorization: `Bearer ${sessionToken}`
|
|
39
|
+
}),
|
|
40
|
+
body: JSON.stringify({ projectId, region })
|
|
41
|
+
},
|
|
42
|
+
(res) => {
|
|
43
|
+
throw new Error(`Failed to create token: ${res.status} ${res.statusText}`);
|
|
44
|
+
}
|
|
45
|
+
);
|
|
33
46
|
const { token: shortLivedAppToken, ttl } = await response.json();
|
|
34
47
|
return new ManagedRemoteAppToken({
|
|
35
48
|
token: shortLivedAppToken,
|
|
36
49
|
session: sessionToken,
|
|
50
|
+
region,
|
|
37
51
|
projectId,
|
|
38
52
|
ttl
|
|
39
53
|
});
|
|
@@ -41,19 +55,26 @@ class ManagedRemoteAppToken {
|
|
|
41
55
|
constructor(options) {
|
|
42
56
|
this.token = options.token;
|
|
43
57
|
this.session = options.session;
|
|
58
|
+
this.region = options.region;
|
|
44
59
|
this.projectId = options.projectId;
|
|
45
60
|
this.ttl = options.ttl;
|
|
46
61
|
this.renewTimer = setTimeout(() => this.renew(), 1e3 * 60 * 5 / 2);
|
|
47
62
|
}
|
|
48
63
|
async fetch(url, body) {
|
|
49
|
-
return
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
return safeFetch(
|
|
65
|
+
`${getAstroStudioUrl()}${url}`,
|
|
66
|
+
{
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${this.session}`,
|
|
70
|
+
"Content-Type": "application/json"
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({ ...body, region: this.region })
|
|
54
73
|
},
|
|
55
|
-
|
|
56
|
-
|
|
74
|
+
() => {
|
|
75
|
+
throw new Error(`Failed to fetch ${url}.`);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
57
78
|
}
|
|
58
79
|
async renew() {
|
|
59
80
|
clearTimeout(this.renewTimer);
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -6,3 +6,14 @@ export declare function getRemoteDatabaseUrl(): string;
|
|
|
6
6
|
export declare function getAstroStudioUrl(): string;
|
|
7
7
|
export declare function getDbDirectoryUrl(root: URL | string): URL;
|
|
8
8
|
export declare function defineDbIntegration(integration: AstroDbIntegration): AstroIntegration;
|
|
9
|
+
/**
|
|
10
|
+
* 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.
|
|
11
|
+
*/
|
|
12
|
+
export declare function safeFetch(url: Parameters<typeof fetch>[0], options?: Parameters<typeof fetch>[1], onNotOK?: (response: Response) => void | Promise<void>): Promise<Response>;
|
|
13
|
+
export type Result<T> = {
|
|
14
|
+
success: true;
|
|
15
|
+
data: T;
|
|
16
|
+
} | {
|
|
17
|
+
success: false;
|
|
18
|
+
data: unknown;
|
|
19
|
+
};
|
package/dist/core/utils.js
CHANGED
|
@@ -17,10 +17,20 @@ function getDbDirectoryUrl(root) {
|
|
|
17
17
|
function defineDbIntegration(integration) {
|
|
18
18
|
return integration;
|
|
19
19
|
}
|
|
20
|
+
async function safeFetch(url, options = {}, onNotOK = () => {
|
|
21
|
+
throw new Error(`Request to ${url} returned a non-OK status code.`);
|
|
22
|
+
}) {
|
|
23
|
+
const response = await fetch(url, options);
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
await onNotOK(response);
|
|
26
|
+
}
|
|
27
|
+
return response;
|
|
28
|
+
}
|
|
20
29
|
export {
|
|
21
30
|
defineDbIntegration,
|
|
22
31
|
getAstroStudioEnv,
|
|
23
32
|
getAstroStudioUrl,
|
|
24
33
|
getDbDirectoryUrl,
|
|
25
|
-
getRemoteDatabaseUrl
|
|
34
|
+
getRemoteDatabaseUrl,
|
|
35
|
+
safeFetch
|
|
26
36
|
};
|
|
@@ -2,6 +2,7 @@ import { createClient } from "@libsql/client";
|
|
|
2
2
|
import { drizzle as drizzleLibsql } from "drizzle-orm/libsql";
|
|
3
3
|
import { drizzle as drizzleProxy } from "drizzle-orm/sqlite-proxy";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { safeFetch } from "../core/utils.js";
|
|
5
6
|
const isWebContainer = !!process.versions?.webcontainer;
|
|
6
7
|
function createLocalDatabaseClient({ dbUrl }) {
|
|
7
8
|
const url = isWebContainer ? "file:content.db" : dbUrl;
|
|
@@ -21,21 +22,24 @@ function createRemoteDatabaseClient(appToken, remoteDbURL) {
|
|
|
21
22
|
const db = drizzleProxy(
|
|
22
23
|
async (sql, parameters, method) => {
|
|
23
24
|
const requestBody = { sql, args: parameters };
|
|
24
|
-
const res = await
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const res = await safeFetch(
|
|
26
|
+
url,
|
|
27
|
+
{
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: {
|
|
30
|
+
Authorization: `Bearer ${appToken}`,
|
|
31
|
+
"Content-Type": "application/json"
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(requestBody)
|
|
29
34
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
throw new Error(
|
|
34
|
-
`Failed to execute query.
|
|
35
|
+
(response) => {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Failed to execute query.
|
|
35
38
|
Query: ${sql}
|
|
36
|
-
Full error: ${
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
Full error: ${response.status} ${response.statusText}`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
);
|
|
39
43
|
let remoteResult;
|
|
40
44
|
try {
|
|
41
45
|
const json = await res.json();
|
|
@@ -62,20 +66,23 @@ Full error: Unexpected JSON response. ${e instanceof Error ? e.message : String(
|
|
|
62
66
|
},
|
|
63
67
|
async (queries) => {
|
|
64
68
|
const stmts = queries.map(({ sql, params }) => ({ sql, args: params }));
|
|
65
|
-
const res = await
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const res = await safeFetch(
|
|
70
|
+
url,
|
|
71
|
+
{
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: {
|
|
74
|
+
Authorization: `Bearer ${appToken}`,
|
|
75
|
+
"Content-Type": "application/json"
|
|
76
|
+
},
|
|
77
|
+
body: JSON.stringify(stmts)
|
|
70
78
|
},
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
+
(response) => {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Failed to execute batch queries.
|
|
82
|
+
Full error: ${response.status} ${response.statusText}}`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
);
|
|
79
86
|
let remoteResults;
|
|
80
87
|
try {
|
|
81
88
|
const json = await res.json();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/db",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"mocha": "^10.2.0",
|
|
81
81
|
"typescript": "^5.2.2",
|
|
82
82
|
"vite": "^5.1.4",
|
|
83
|
-
"astro": "4.5.
|
|
83
|
+
"astro": "4.5.3",
|
|
84
84
|
"astro-scripts": "0.0.14"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|