@astrojs/db 0.11.2 → 0.11.4
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/utils.d.ts +0 -2
- package/dist/core/cli/commands/execute/index.js +1 -1
- package/dist/core/cli/commands/link/index.d.ts +10 -0
- package/dist/core/cli/commands/link/index.js +33 -17
- package/dist/core/cli/commands/login/index.js +1 -2
- package/dist/core/cli/commands/logout/index.js +1 -1
- package/dist/core/cli/commands/push/index.js +1 -1
- package/dist/core/cli/commands/shell/index.js +1 -1
- package/dist/core/cli/commands/verify/index.js +1 -1
- package/dist/core/cli/print-help.js +1 -1
- package/dist/core/errors.d.ts +0 -3
- package/dist/core/errors.js +1 -18
- package/dist/core/integration/index.js +1 -1
- package/dist/core/utils.d.ts +0 -2
- package/dist/core/utils.js +1 -10
- package/dist/runtime/db-client.js +13 -1
- package/package.json +4 -3
- package/dist/core/tokens.d.ts +0 -11
- package/dist/core/tokens.js +0 -190
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { AstroConfig, AstroIntegration } from 'astro';
|
|
2
2
|
import type { AstroDbIntegration } from './types.js';
|
|
3
3
|
export type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
|
|
4
|
-
export declare function getAstroStudioEnv(envMode?: string): Record<`ASTRO_STUDIO_${string}`, string>;
|
|
5
4
|
export declare function getAstroEnv(envMode?: string): Record<`ASTRO_${string}`, string>;
|
|
6
5
|
export declare function getRemoteDatabaseUrl(): string;
|
|
7
|
-
export declare function getAstroStudioUrl(): string;
|
|
8
6
|
export declare function getDbDirectoryUrl(root: URL | string): URL;
|
|
9
7
|
export declare function defineDbIntegration(integration: AstroDbIntegration): AstroIntegration;
|
|
10
8
|
export type Result<T> = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { getManagedAppTokenOrExit } from "@astrojs/studio";
|
|
2
3
|
import { LibsqlError } from "@libsql/client";
|
|
3
4
|
import { green } from "kleur/colors";
|
|
4
5
|
import {
|
|
@@ -12,7 +13,6 @@ import {
|
|
|
12
13
|
getStudioVirtualModContents
|
|
13
14
|
} from "../../../integration/vite-plugin-db.js";
|
|
14
15
|
import { bundleFile, importBundledFile } from "../../../load-file.js";
|
|
15
|
-
import { getManagedAppTokenOrExit } from "../../../tokens.js";
|
|
16
16
|
async function cmd({
|
|
17
17
|
astroConfig,
|
|
18
18
|
dbConfig,
|
|
@@ -11,10 +11,20 @@ export declare function promptExistingProjectName({ workspaceId }: {
|
|
|
11
11
|
workspaceId: string;
|
|
12
12
|
}): Promise<{
|
|
13
13
|
id: string;
|
|
14
|
+
name: string;
|
|
14
15
|
idName: string;
|
|
15
16
|
}>;
|
|
16
17
|
export declare function promptBegin(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Ask the user if they want to link to an existing Astro Studio project.
|
|
20
|
+
* @returns A `Promise` for the user’s answer: `true` if they answer yes, otherwise `false`.
|
|
21
|
+
*/
|
|
17
22
|
export declare function promptLinkExisting(): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Ask the user if they want to link to a new Astro Studio Project.
|
|
25
|
+
* **Exits the process if they answer no.**
|
|
26
|
+
* @returns A `Promise` for the user’s answer: `true` if they answer yes.
|
|
27
|
+
*/
|
|
18
28
|
export declare function promptLinkNew(): Promise<boolean>;
|
|
19
29
|
export declare function promptNewProjectName(): Promise<string>;
|
|
20
30
|
export declare function promptNewProjectRegion(): Promise<string>;
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
MISSING_SESSION_ID_ERROR,
|
|
6
|
+
PROJECT_ID_FILE,
|
|
7
|
+
getAstroStudioUrl,
|
|
8
|
+
getSessionIdFromFile
|
|
9
|
+
} from "@astrojs/studio";
|
|
4
10
|
import { slug } from "github-slugger";
|
|
5
11
|
import { bgRed, cyan } from "kleur/colors";
|
|
6
12
|
import ora from "ora";
|
|
7
13
|
import prompts from "prompts";
|
|
8
14
|
import { safeFetch } from "../../../../runtime/utils.js";
|
|
9
|
-
import {
|
|
10
|
-
import { PROJECT_ID_FILE, getSessionIdFromFile } from "../../../tokens.js";
|
|
11
|
-
import { getAstroStudioUrl } from "../../../utils.js";
|
|
15
|
+
import {} from "../../../utils.js";
|
|
12
16
|
async function cmd() {
|
|
13
17
|
const sessionToken = await getSessionIdFromFile();
|
|
14
18
|
if (!sessionToken) {
|
|
15
19
|
console.error(MISSING_SESSION_ID_ERROR);
|
|
16
20
|
process.exit(1);
|
|
17
21
|
}
|
|
18
|
-
const getWorkspaceIdAsync = getWorkspaceId().catch((err) => {
|
|
19
|
-
return err;
|
|
20
|
-
});
|
|
21
22
|
await promptBegin();
|
|
22
23
|
const isLinkExisting = await promptLinkExisting();
|
|
23
24
|
if (isLinkExisting) {
|
|
24
|
-
const workspaceId =
|
|
25
|
+
const workspaceId = await promptWorkspace(sessionToken);
|
|
25
26
|
const existingProjectData = await promptExistingProjectName({ workspaceId });
|
|
26
27
|
return await linkProject(existingProjectData.id);
|
|
27
28
|
}
|
|
28
29
|
const isLinkNew = await promptLinkNew();
|
|
29
30
|
if (isLinkNew) {
|
|
30
|
-
const workspaceId =
|
|
31
|
+
const workspaceId = await promptWorkspace(sessionToken);
|
|
31
32
|
const newProjectName = await promptNewProjectName();
|
|
32
33
|
const newProjectRegion = await promptNewProjectRegion();
|
|
33
34
|
const spinner = ora("Creating new project...").start();
|
|
@@ -46,14 +47,14 @@ async function linkProject(id) {
|
|
|
46
47
|
await writeFile(PROJECT_ID_FILE, `${id}`);
|
|
47
48
|
console.info("Project linked.");
|
|
48
49
|
}
|
|
49
|
-
async function
|
|
50
|
+
async function getWorkspaces(sessionToken) {
|
|
50
51
|
const linkUrl = new URL(getAstroStudioUrl() + "/api/cli/workspaces.list");
|
|
51
52
|
const response = await safeFetch(
|
|
52
53
|
linkUrl,
|
|
53
54
|
{
|
|
54
55
|
method: "POST",
|
|
55
56
|
headers: {
|
|
56
|
-
Authorization: `Bearer ${
|
|
57
|
+
Authorization: `Bearer ${sessionToken}`,
|
|
57
58
|
"Content-Type": "application/json"
|
|
58
59
|
}
|
|
59
60
|
},
|
|
@@ -64,7 +65,7 @@ async function getWorkspaceId() {
|
|
|
64
65
|
|
|
65
66
|
Are you logged in?
|
|
66
67
|
Run ${cyan(
|
|
67
|
-
"astro
|
|
68
|
+
"astro login"
|
|
68
69
|
)} to authenticate and then try linking again.
|
|
69
70
|
|
|
70
71
|
`
|
|
@@ -77,13 +78,28 @@ async function getWorkspaceId() {
|
|
|
77
78
|
if (!success) {
|
|
78
79
|
throw new Error(`Failed to fetch user's workspace.`);
|
|
79
80
|
}
|
|
80
|
-
return data
|
|
81
|
+
return data;
|
|
81
82
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
async function promptWorkspace(sessionToken) {
|
|
84
|
+
const workspaces = await getWorkspaces(sessionToken);
|
|
85
|
+
if (workspaces.length === 0) {
|
|
86
|
+
console.error("No workspaces found.");
|
|
85
87
|
process.exit(1);
|
|
86
88
|
}
|
|
89
|
+
if (workspaces.length === 1) {
|
|
90
|
+
return workspaces[0].id;
|
|
91
|
+
}
|
|
92
|
+
const { workspaceId } = await prompts({
|
|
93
|
+
type: "autocomplete",
|
|
94
|
+
name: "workspaceId",
|
|
95
|
+
message: "Select your workspace:",
|
|
96
|
+
limit: 5,
|
|
97
|
+
choices: workspaces.map((w) => ({ title: w.name, value: w.id }))
|
|
98
|
+
});
|
|
99
|
+
if (typeof workspaceId !== "string") {
|
|
100
|
+
console.log("Canceled.");
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
87
103
|
return workspaceId;
|
|
88
104
|
}
|
|
89
105
|
async function createNewProject({
|
|
@@ -109,7 +125,7 @@ async function createNewProject({
|
|
|
109
125
|
|
|
110
126
|
Are you logged in?
|
|
111
127
|
Run ${cyan(
|
|
112
|
-
"astro
|
|
128
|
+
"astro login"
|
|
113
129
|
)} to authenticate and then try linking again.
|
|
114
130
|
|
|
115
131
|
`
|
|
@@ -146,7 +162,7 @@ async function promptExistingProjectName({ workspaceId }) {
|
|
|
146
162
|
|
|
147
163
|
Are you logged in?
|
|
148
164
|
Run ${cyan(
|
|
149
|
-
"astro
|
|
165
|
+
"astro login"
|
|
150
166
|
)} to authenticate and then try linking again.
|
|
151
167
|
|
|
152
168
|
`
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { createServer as _createServer } from "node:http";
|
|
3
|
+
import { SESSION_LOGIN_FILE, getAstroStudioUrl } from "@astrojs/studio";
|
|
3
4
|
import { listen } from "async-listen";
|
|
4
5
|
import { cyan } from "kleur/colors";
|
|
5
6
|
import open from "open";
|
|
6
7
|
import ora from "ora";
|
|
7
8
|
import prompt from "prompts";
|
|
8
|
-
import { SESSION_LOGIN_FILE } from "../../../tokens.js";
|
|
9
|
-
import { getAstroStudioUrl } from "../../../utils.js";
|
|
10
9
|
const isWebContainer = (
|
|
11
10
|
// Stackblitz heuristic
|
|
12
11
|
process.versions?.webcontainer ?? // GitHub Codespaces heuristic
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { unlink } from "node:fs/promises";
|
|
2
|
-
import { SESSION_LOGIN_FILE } from "
|
|
2
|
+
import { SESSION_LOGIN_FILE } from "@astrojs/studio";
|
|
3
3
|
async function cmd() {
|
|
4
4
|
await unlink(SESSION_LOGIN_FILE);
|
|
5
5
|
console.log("Successfully logged out of Astro Studio.");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { getManagedAppTokenOrExit } from "@astrojs/studio";
|
|
1
2
|
import prompts from "prompts";
|
|
2
3
|
import { safeFetch } from "../../../../runtime/utils.js";
|
|
3
4
|
import { MIGRATION_VERSION } from "../../../consts.js";
|
|
4
|
-
import { getManagedAppTokenOrExit } from "../../../tokens.js";
|
|
5
5
|
import {} from "../../../types.js";
|
|
6
6
|
import { getRemoteDatabaseUrl } from "../../../utils.js";
|
|
7
7
|
import {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getManagedAppTokenOrExit } from "@astrojs/studio";
|
|
1
2
|
import { sql } from "drizzle-orm";
|
|
2
3
|
import {
|
|
3
4
|
createLocalDatabaseClient,
|
|
@@ -6,7 +7,6 @@ import {
|
|
|
6
7
|
import { normalizeDatabaseUrl } from "../../../../runtime/index.js";
|
|
7
8
|
import { DB_PATH } from "../../../consts.js";
|
|
8
9
|
import { SHELL_QUERY_MISSING_ERROR } from "../../../errors.js";
|
|
9
|
-
import { getManagedAppTokenOrExit } from "../../../tokens.js";
|
|
10
10
|
import { getAstroEnv, getRemoteDatabaseUrl } from "../../../utils.js";
|
|
11
11
|
async function cmd({
|
|
12
12
|
flags,
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export declare const MISSING_SESSION_ID_CI_ERROR: string;
|
|
2
|
-
export declare const MISSING_SESSION_ID_ERROR: string;
|
|
3
|
-
export declare const MISSING_PROJECT_ID_ERROR: string;
|
|
4
1
|
export declare const MISSING_EXECUTE_PATH_ERROR: string;
|
|
5
2
|
export declare const RENAME_TABLE_ERROR: (oldTable: string, newTable: string) => string;
|
|
6
3
|
export declare const RENAME_COLUMN_ERROR: (oldSelector: string, newSelector: string) => string;
|
package/dist/core/errors.js
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
import { bold, cyan, red } from "kleur/colors";
|
|
2
|
-
const MISSING_SESSION_ID_CI_ERROR = `${red("\u25B6 ASTRO_STUDIO_APP_TOKEN required")}
|
|
3
|
-
|
|
4
|
-
To authenticate with Astro Studio add the token to your CI's environment variables.
|
|
5
|
-
`;
|
|
6
|
-
const MISSING_SESSION_ID_ERROR = `${red("\u25B6 Login required!")}
|
|
7
|
-
|
|
8
|
-
To authenticate with Astro Studio, run
|
|
9
|
-
${cyan("astro db login")}
|
|
10
|
-
`;
|
|
11
|
-
const MISSING_PROJECT_ID_ERROR = `${red("\u25B6 Directory not linked.")}
|
|
12
|
-
|
|
13
|
-
To link this directory to an Astro Studio project, run
|
|
14
|
-
${cyan("astro db link")}
|
|
15
|
-
`;
|
|
16
2
|
const MISSING_EXECUTE_PATH_ERROR = `${red(
|
|
17
3
|
"\u25B6 No file path provided."
|
|
18
4
|
)} Provide a path by running ${cyan("astro db execute <path>")}
|
|
@@ -23,7 +9,7 @@ const RENAME_TABLE_ERROR = (oldTable, newTable) => {
|
|
|
23
9
|
|
|
24
10
|
1. Use "deprecated: true" to deprecate a table before renaming.
|
|
25
11
|
2. Use "--force-reset" to ignore this warning and reset the database (deleting all of your data).
|
|
26
|
-
|
|
12
|
+
|
|
27
13
|
Visit https://docs.astro.build/en/guides/astro-db/#renaming-tables to learn more.`;
|
|
28
14
|
};
|
|
29
15
|
const RENAME_COLUMN_ERROR = (oldSelector, newSelector) => {
|
|
@@ -56,9 +42,6 @@ export {
|
|
|
56
42
|
FILE_NOT_FOUND_ERROR,
|
|
57
43
|
INTEGRATION_TABLE_CONFLICT_ERROR,
|
|
58
44
|
MISSING_EXECUTE_PATH_ERROR,
|
|
59
|
-
MISSING_PROJECT_ID_ERROR,
|
|
60
|
-
MISSING_SESSION_ID_CI_ERROR,
|
|
61
|
-
MISSING_SESSION_ID_ERROR,
|
|
62
45
|
RENAME_COLUMN_ERROR,
|
|
63
46
|
RENAME_TABLE_ERROR,
|
|
64
47
|
SHELL_QUERY_MISSING_ERROR
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "fs";
|
|
2
2
|
import { dirname } from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
|
+
import { getManagedAppTokenOrExit } from "@astrojs/studio";
|
|
4
5
|
import { LibsqlError } from "@libsql/client";
|
|
5
6
|
import { mkdir, writeFile } from "fs/promises";
|
|
6
7
|
import { blue, yellow } from "kleur/colors";
|
|
@@ -15,7 +16,6 @@ import { CONFIG_FILE_NAMES, DB_PATH } from "../consts.js";
|
|
|
15
16
|
import { EXEC_DEFAULT_EXPORT_ERROR, EXEC_ERROR } from "../errors.js";
|
|
16
17
|
import { resolveDbConfig } from "../load-file.js";
|
|
17
18
|
import { SEED_DEV_FILE_NAME } from "../queries.js";
|
|
18
|
-
import { getManagedAppTokenOrExit } from "../tokens.js";
|
|
19
19
|
import { getDbDirectoryUrl } from "../utils.js";
|
|
20
20
|
import { fileURLIntegration } from "./file-url.js";
|
|
21
21
|
import { typegenInternal } from "./typegen.js";
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { AstroConfig, AstroIntegration } from 'astro';
|
|
2
2
|
import type { AstroDbIntegration } from './types.js';
|
|
3
3
|
export type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
|
|
4
|
-
export declare function getAstroStudioEnv(envMode?: string): Record<`ASTRO_STUDIO_${string}`, string>;
|
|
5
4
|
export declare function getAstroEnv(envMode?: string): Record<`ASTRO_${string}`, string>;
|
|
6
5
|
export declare function getRemoteDatabaseUrl(): string;
|
|
7
|
-
export declare function getAstroStudioUrl(): string;
|
|
8
6
|
export declare function getDbDirectoryUrl(root: URL | string): URL;
|
|
9
7
|
export declare function defineDbIntegration(integration: AstroDbIntegration): AstroIntegration;
|
|
10
8
|
export type Result<T> = {
|
package/dist/core/utils.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
+
import { getAstroStudioEnv } from "@astrojs/studio";
|
|
1
2
|
import { loadEnv } from "vite";
|
|
2
|
-
function getAstroStudioEnv(envMode = "") {
|
|
3
|
-
const env = loadEnv(envMode, process.cwd(), "ASTRO_STUDIO_");
|
|
4
|
-
return env;
|
|
5
|
-
}
|
|
6
3
|
function getAstroEnv(envMode = "") {
|
|
7
4
|
const env = loadEnv(envMode, process.cwd(), "ASTRO_");
|
|
8
5
|
return env;
|
|
@@ -11,10 +8,6 @@ function getRemoteDatabaseUrl() {
|
|
|
11
8
|
const env = getAstroStudioEnv();
|
|
12
9
|
return env.ASTRO_STUDIO_REMOTE_DB_URL || "https://db.services.astro.build";
|
|
13
10
|
}
|
|
14
|
-
function getAstroStudioUrl() {
|
|
15
|
-
const env = getAstroStudioEnv();
|
|
16
|
-
return env.ASTRO_STUDIO_URL || "https://studio.astro.build";
|
|
17
|
-
}
|
|
18
11
|
function getDbDirectoryUrl(root) {
|
|
19
12
|
return new URL("db/", root);
|
|
20
13
|
}
|
|
@@ -29,8 +22,6 @@ function mapObject(item, callback) {
|
|
|
29
22
|
export {
|
|
30
23
|
defineDbIntegration,
|
|
31
24
|
getAstroEnv,
|
|
32
|
-
getAstroStudioEnv,
|
|
33
|
-
getAstroStudioUrl,
|
|
34
25
|
getDbDirectoryUrl,
|
|
35
26
|
getRemoteDatabaseUrl,
|
|
36
27
|
mapObject
|
|
@@ -59,7 +59,19 @@ function createRemoteDatabaseClient(appToken, remoteDbURL) {
|
|
|
59
59
|
code: KNOWN_ERROR_CODES.SQL_QUERY_FAILED
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
if (method === "run")
|
|
62
|
+
if (method === "run") {
|
|
63
|
+
const rawRows = Array.from(remoteResult.rows);
|
|
64
|
+
remoteResult.rows.toJSON = () => rawRows;
|
|
65
|
+
for (let i = 0; i < remoteResult.rows.length; i++) {
|
|
66
|
+
let row = remoteResult.rows[i];
|
|
67
|
+
let item = {};
|
|
68
|
+
remoteResult.columns.forEach((col, index) => {
|
|
69
|
+
item[col] = row[index];
|
|
70
|
+
});
|
|
71
|
+
remoteResult.rows[i] = item;
|
|
72
|
+
}
|
|
73
|
+
return remoteResult;
|
|
74
|
+
}
|
|
63
75
|
const rowValues = [];
|
|
64
76
|
for (const row of remoteResult.rows) {
|
|
65
77
|
if (row != null && typeof row === "object") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/db",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
4
4
|
"description": "Add libSQL and Astro Studio support to your Astro site",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -75,7 +75,8 @@
|
|
|
75
75
|
"prompts": "^2.4.2",
|
|
76
76
|
"strip-ansi": "^7.1.0",
|
|
77
77
|
"yargs-parser": "^21.1.1",
|
|
78
|
-
"zod": "^3.23.8"
|
|
78
|
+
"zod": "^3.23.8",
|
|
79
|
+
"@astrojs/studio": "0.1.0"
|
|
79
80
|
},
|
|
80
81
|
"devDependencies": {
|
|
81
82
|
"@types/chai": "^4.3.16",
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
"mocha": "^10.4.0",
|
|
90
91
|
"typescript": "^5.4.5",
|
|
91
92
|
"vite": "^5.2.11",
|
|
92
|
-
"astro": "4.8.
|
|
93
|
+
"astro": "4.8.7",
|
|
93
94
|
"astro-scripts": "0.0.14"
|
|
94
95
|
},
|
|
95
96
|
"scripts": {
|
package/dist/core/tokens.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
-
export declare const SESSION_LOGIN_FILE: import("url").URL;
|
|
3
|
-
export declare const PROJECT_ID_FILE: import("url").URL;
|
|
4
|
-
export interface ManagedAppToken {
|
|
5
|
-
token: string;
|
|
6
|
-
renew(): Promise<void>;
|
|
7
|
-
destroy(): Promise<void>;
|
|
8
|
-
}
|
|
9
|
-
export declare function getProjectIdFromFile(): Promise<string | undefined>;
|
|
10
|
-
export declare function getSessionIdFromFile(): Promise<string | undefined>;
|
|
11
|
-
export declare function getManagedAppTokenOrExit(token?: string): Promise<ManagedAppToken>;
|
package/dist/core/tokens.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
|
-
import ci from "ci-info";
|
|
6
|
-
import { green } from "kleur/colors";
|
|
7
|
-
import ora from "ora";
|
|
8
|
-
import { safeFetch } from "../runtime/utils.js";
|
|
9
|
-
import {
|
|
10
|
-
MISSING_PROJECT_ID_ERROR,
|
|
11
|
-
MISSING_SESSION_ID_CI_ERROR,
|
|
12
|
-
MISSING_SESSION_ID_ERROR
|
|
13
|
-
} from "./errors.js";
|
|
14
|
-
import { getAstroStudioEnv, getAstroStudioUrl } from "./utils.js";
|
|
15
|
-
const SESSION_LOGIN_FILE = pathToFileURL(join(homedir(), ".astro", "session-token"));
|
|
16
|
-
const PROJECT_ID_FILE = pathToFileURL(join(process.cwd(), ".astro", "link"));
|
|
17
|
-
class ManagedLocalAppToken {
|
|
18
|
-
token;
|
|
19
|
-
constructor(token) {
|
|
20
|
-
this.token = token;
|
|
21
|
-
}
|
|
22
|
-
async renew() {
|
|
23
|
-
}
|
|
24
|
-
async destroy() {
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
class ManagedRemoteAppToken {
|
|
28
|
-
token;
|
|
29
|
-
session;
|
|
30
|
-
projectId;
|
|
31
|
-
ttl;
|
|
32
|
-
expires;
|
|
33
|
-
renewTimer;
|
|
34
|
-
static async create(sessionToken, projectId) {
|
|
35
|
-
const { token: shortLivedAppToken, ttl } = await this.createToken(sessionToken, projectId);
|
|
36
|
-
return new ManagedRemoteAppToken({
|
|
37
|
-
token: shortLivedAppToken,
|
|
38
|
-
session: sessionToken,
|
|
39
|
-
projectId,
|
|
40
|
-
ttl
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
static async createToken(sessionToken, projectId) {
|
|
44
|
-
const spinner = ora("Connecting to remote database...").start();
|
|
45
|
-
const response = await safeFetch(
|
|
46
|
-
new URL(`${getAstroStudioUrl()}/auth/cli/token-create`),
|
|
47
|
-
{
|
|
48
|
-
method: "POST",
|
|
49
|
-
headers: new Headers({
|
|
50
|
-
Authorization: `Bearer ${sessionToken}`
|
|
51
|
-
}),
|
|
52
|
-
body: JSON.stringify({ projectId })
|
|
53
|
-
},
|
|
54
|
-
(res) => {
|
|
55
|
-
throw new Error(`Failed to create token: ${res.status} ${res.statusText}`);
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
spinner.succeed(green("Connected to remote database."));
|
|
59
|
-
const { token, ttl } = await response.json();
|
|
60
|
-
return { token, ttl };
|
|
61
|
-
}
|
|
62
|
-
constructor(options) {
|
|
63
|
-
this.token = options.token;
|
|
64
|
-
this.session = options.session;
|
|
65
|
-
this.projectId = options.projectId;
|
|
66
|
-
this.ttl = options.ttl;
|
|
67
|
-
this.renewTimer = setTimeout(() => this.renew(), 1e3 * 60 * 5 / 2);
|
|
68
|
-
this.expires = getExpiresFromTtl(this.ttl);
|
|
69
|
-
}
|
|
70
|
-
async fetch(url, body) {
|
|
71
|
-
return safeFetch(
|
|
72
|
-
`${getAstroStudioUrl()}${url}`,
|
|
73
|
-
{
|
|
74
|
-
method: "POST",
|
|
75
|
-
headers: {
|
|
76
|
-
Authorization: `Bearer ${this.session}`,
|
|
77
|
-
"Content-Type": "application/json"
|
|
78
|
-
},
|
|
79
|
-
body: JSON.stringify(body)
|
|
80
|
-
},
|
|
81
|
-
() => {
|
|
82
|
-
throw new Error(`Failed to fetch ${url}.`);
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
tokenIsValid() {
|
|
87
|
-
return /* @__PURE__ */ new Date() > this.expires;
|
|
88
|
-
}
|
|
89
|
-
createRenewTimer() {
|
|
90
|
-
return setTimeout(() => this.renew(), 1e3 * 60 * this.ttl / 2);
|
|
91
|
-
}
|
|
92
|
-
async renew() {
|
|
93
|
-
clearTimeout(this.renewTimer);
|
|
94
|
-
delete this.renewTimer;
|
|
95
|
-
if (this.tokenIsValid()) {
|
|
96
|
-
const response = await this.fetch("/auth/cli/token-renew", {
|
|
97
|
-
token: this.token,
|
|
98
|
-
projectId: this.projectId
|
|
99
|
-
});
|
|
100
|
-
if (response.status === 200) {
|
|
101
|
-
this.expires = getExpiresFromTtl(this.ttl);
|
|
102
|
-
this.renewTimer = this.createRenewTimer();
|
|
103
|
-
} else {
|
|
104
|
-
throw new Error(`Unexpected response: ${response.status} ${response.statusText}`);
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
try {
|
|
108
|
-
const { token, ttl } = await ManagedRemoteAppToken.createToken(
|
|
109
|
-
this.session,
|
|
110
|
-
this.projectId
|
|
111
|
-
);
|
|
112
|
-
this.token = token;
|
|
113
|
-
this.ttl = ttl;
|
|
114
|
-
this.expires = getExpiresFromTtl(ttl);
|
|
115
|
-
this.renewTimer = this.createRenewTimer();
|
|
116
|
-
} catch {
|
|
117
|
-
throw new Error(
|
|
118
|
-
`Token has expired and attempts to renew it have failed, please try again.`
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
async destroy() {
|
|
124
|
-
try {
|
|
125
|
-
const response = await this.fetch("/auth/cli/token-delete", {
|
|
126
|
-
token: this.token,
|
|
127
|
-
projectId: this.projectId
|
|
128
|
-
});
|
|
129
|
-
if (response.status !== 200) {
|
|
130
|
-
throw new Error(`Unexpected response: ${response.status} ${response.statusText}`);
|
|
131
|
-
}
|
|
132
|
-
} catch (error) {
|
|
133
|
-
console.error("Failed to delete token.", error?.message);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
async function getProjectIdFromFile() {
|
|
138
|
-
try {
|
|
139
|
-
return await readFile(PROJECT_ID_FILE, "utf-8");
|
|
140
|
-
} catch (error) {
|
|
141
|
-
return void 0;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
async function getSessionIdFromFile() {
|
|
145
|
-
try {
|
|
146
|
-
return await readFile(SESSION_LOGIN_FILE, "utf-8");
|
|
147
|
-
} catch (error) {
|
|
148
|
-
return void 0;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
async function getManagedAppTokenOrExit(token) {
|
|
152
|
-
if (token) {
|
|
153
|
-
return new ManagedLocalAppToken(token);
|
|
154
|
-
}
|
|
155
|
-
if (process.env.ASTRO_INTERNAL_TEST_REMOTE) {
|
|
156
|
-
return new ManagedLocalAppToken(
|
|
157
|
-
"fake"
|
|
158
|
-
/* token ignored in test */
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
const { ASTRO_STUDIO_APP_TOKEN } = getAstroStudioEnv();
|
|
162
|
-
if (ASTRO_STUDIO_APP_TOKEN) {
|
|
163
|
-
return new ManagedLocalAppToken(ASTRO_STUDIO_APP_TOKEN);
|
|
164
|
-
}
|
|
165
|
-
const sessionToken = await getSessionIdFromFile();
|
|
166
|
-
if (!sessionToken) {
|
|
167
|
-
if (ci.isCI) {
|
|
168
|
-
console.error(MISSING_SESSION_ID_CI_ERROR);
|
|
169
|
-
} else {
|
|
170
|
-
console.error(MISSING_SESSION_ID_ERROR);
|
|
171
|
-
}
|
|
172
|
-
process.exit(1);
|
|
173
|
-
}
|
|
174
|
-
const projectId = await getProjectIdFromFile();
|
|
175
|
-
if (!projectId) {
|
|
176
|
-
console.error(MISSING_PROJECT_ID_ERROR);
|
|
177
|
-
process.exit(1);
|
|
178
|
-
}
|
|
179
|
-
return ManagedRemoteAppToken.create(sessionToken, projectId);
|
|
180
|
-
}
|
|
181
|
-
function getExpiresFromTtl(ttl) {
|
|
182
|
-
return new Date(Date.now() + ttl * 60 * 1e3);
|
|
183
|
-
}
|
|
184
|
-
export {
|
|
185
|
-
PROJECT_ID_FILE,
|
|
186
|
-
SESSION_LOGIN_FILE,
|
|
187
|
-
getManagedAppTokenOrExit,
|
|
188
|
-
getProjectIdFromFile,
|
|
189
|
-
getSessionIdFromFile
|
|
190
|
-
};
|