@prisma/compute-cli 0.13.0 → 0.15.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.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/logs.d.ts +26 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +141 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/lib/auth/guard.d.ts +14 -0
- package/dist/lib/auth/guard.d.ts.map +1 -1
- package/dist/lib/auth/guard.js +36 -0
- package/dist/lib/auth/guard.js.map +1 -1
- package/package.json +2 -2
- package/src/cli.ts +2 -0
- package/src/commands/logs.ts +171 -0
- package/src/lib/auth/guard.ts +42 -0
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,WAAW,qDAgBtB,CAAC;AAEH,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C"}
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { deployCommand } from "./commands/deploy.js";
|
|
|
3
3
|
import { envGroup } from "./commands/env.js";
|
|
4
4
|
import { loginCommand } from "./commands/login.js";
|
|
5
5
|
import { logoutCommand } from "./commands/logout.js";
|
|
6
|
+
import { logsCommand } from "./commands/logs.js";
|
|
6
7
|
import { projectsGroup } from "./commands/projects.js";
|
|
7
8
|
import { servicesGroup } from "./commands/services.js";
|
|
8
9
|
import { versionsGroup } from "./commands/versions.js";
|
|
@@ -16,6 +17,7 @@ export const mainCommand = defineCommand({
|
|
|
16
17
|
login: loginCommand,
|
|
17
18
|
logout: logoutCommand,
|
|
18
19
|
deploy: deployCommand,
|
|
20
|
+
logs: logsCommand,
|
|
19
21
|
env: envGroup,
|
|
20
22
|
projects: projectsGroup,
|
|
21
23
|
services: servicesGroup,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,WAAW,EACT,iKAAiK;KACpK;IACD,WAAW,EAAE;QACX,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,aAAa;QACrB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,aAAa;KACxB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;AAC7B,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,WAAW,EACT,iKAAiK;KACpK;IACD,WAAW,EAAE;QACX,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,aAAa;QACrB,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,aAAa;KACxB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const logsCommand: import("citty").CommandDef<{
|
|
2
|
+
readonly id: {
|
|
3
|
+
readonly type: "positional";
|
|
4
|
+
readonly description: "Compute version ID";
|
|
5
|
+
readonly required: true;
|
|
6
|
+
};
|
|
7
|
+
readonly tail: {
|
|
8
|
+
readonly type: "string";
|
|
9
|
+
readonly description: "Number of recent lines to show (default: 100)";
|
|
10
|
+
};
|
|
11
|
+
readonly "from-start": {
|
|
12
|
+
readonly type: "boolean";
|
|
13
|
+
readonly default: false;
|
|
14
|
+
readonly description: "Start from the beginning of the log buffer instead of tailing";
|
|
15
|
+
};
|
|
16
|
+
readonly cursor: {
|
|
17
|
+
readonly type: "string";
|
|
18
|
+
readonly description: "Resume from a byte offset cursor (from a previous stream)";
|
|
19
|
+
};
|
|
20
|
+
readonly json: {
|
|
21
|
+
readonly type: "boolean";
|
|
22
|
+
readonly default: false;
|
|
23
|
+
readonly description: "Output each log/terminal record as a JSON line";
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;EA+FtB,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { CancelledError, LogStreamError, streamLogs, } from "@prisma/compute-sdk";
|
|
2
|
+
import { defineCommand } from "citty";
|
|
3
|
+
import { requireAuthToken } from "../lib/auth/guard.js";
|
|
4
|
+
import { createCommandAbortSignal, handleError } from "./helpers.js";
|
|
5
|
+
export const logsCommand = defineCommand({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "logs",
|
|
8
|
+
description: "Stream logs for a compute version",
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
id: {
|
|
12
|
+
type: "positional",
|
|
13
|
+
description: "Compute version ID",
|
|
14
|
+
required: true,
|
|
15
|
+
},
|
|
16
|
+
tail: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Number of recent lines to show (default: 100)",
|
|
19
|
+
},
|
|
20
|
+
"from-start": {
|
|
21
|
+
type: "boolean",
|
|
22
|
+
default: false,
|
|
23
|
+
description: "Start from the beginning of the log buffer instead of tailing",
|
|
24
|
+
},
|
|
25
|
+
cursor: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Resume from a byte offset cursor (from a previous stream)",
|
|
28
|
+
},
|
|
29
|
+
json: {
|
|
30
|
+
type: "boolean",
|
|
31
|
+
default: false,
|
|
32
|
+
description: "Output each log/terminal record as a JSON line",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
run: async ({ args }) => {
|
|
36
|
+
const auth = await requireAuthToken();
|
|
37
|
+
if (!auth)
|
|
38
|
+
process.exit(1);
|
|
39
|
+
const { signal, cleanup } = createCommandAbortSignal();
|
|
40
|
+
try {
|
|
41
|
+
const versionId = args.id;
|
|
42
|
+
const tail = args.tail ? Number.parseInt(args.tail, 10) : undefined;
|
|
43
|
+
if (tail != null && (Number.isNaN(tail) || tail < 1)) {
|
|
44
|
+
console.error("--tail must be a positive integer");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const onRecord = args.json ? emitJson : emitText;
|
|
48
|
+
const result = await streamLogs({
|
|
49
|
+
baseUrl: auth.baseUrl,
|
|
50
|
+
token: auth.token,
|
|
51
|
+
versionId,
|
|
52
|
+
tail,
|
|
53
|
+
fromStart: args["from-start"],
|
|
54
|
+
cursor: args.cursor,
|
|
55
|
+
signal,
|
|
56
|
+
}, onRecord);
|
|
57
|
+
if (result.isErr()) {
|
|
58
|
+
const error = result.error;
|
|
59
|
+
if (CancelledError.is(error))
|
|
60
|
+
process.exit(130);
|
|
61
|
+
if (LogStreamError.is(error)) {
|
|
62
|
+
if (args.json) {
|
|
63
|
+
console.log(JSON.stringify({
|
|
64
|
+
ok: false,
|
|
65
|
+
error: {
|
|
66
|
+
statusCode: error.statusCode,
|
|
67
|
+
message: error.message,
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.error(error.message);
|
|
73
|
+
}
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
error;
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
const exitCode = handleStreamEnd(result.value, versionId, args.json);
|
|
80
|
+
if (exitCode !== 0)
|
|
81
|
+
process.exit(exitCode);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (signal.aborted)
|
|
85
|
+
process.exit(130);
|
|
86
|
+
process.exit(handleError(error));
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
cleanup();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
function emitJson(record) {
|
|
94
|
+
console.log(JSON.stringify(record));
|
|
95
|
+
}
|
|
96
|
+
function emitText(record) {
|
|
97
|
+
if (record.type === "log") {
|
|
98
|
+
process.stdout.write(`${record.text}\n`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function handleStreamEnd(result, versionId, json) {
|
|
102
|
+
const { terminal } = result;
|
|
103
|
+
if (!terminal) {
|
|
104
|
+
printResumeHint(result, versionId, json);
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
if (!json) {
|
|
108
|
+
if (terminal.kind === "error") {
|
|
109
|
+
console.error(`Log stream ended: ${terminal.message} (${terminal.code})`);
|
|
110
|
+
}
|
|
111
|
+
else if (terminal.code === "superseded") {
|
|
112
|
+
console.error("Log stream superseded by another client.");
|
|
113
|
+
}
|
|
114
|
+
else if (terminal.code === "segment_time_limit") {
|
|
115
|
+
console.error("Log stream segment ended (10-minute limit).");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
printResumeHint(result, versionId, json);
|
|
119
|
+
switch (terminal.code) {
|
|
120
|
+
case "vm_stopped":
|
|
121
|
+
case "superseded":
|
|
122
|
+
case "segment_time_limit":
|
|
123
|
+
return 0;
|
|
124
|
+
case "logs_unavailable":
|
|
125
|
+
case "upstream_error":
|
|
126
|
+
case "internal_error":
|
|
127
|
+
return 1;
|
|
128
|
+
default:
|
|
129
|
+
return terminal.kind === "error" ? 1 : 0;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function printResumeHint(result, versionId, json) {
|
|
133
|
+
if (json)
|
|
134
|
+
return;
|
|
135
|
+
const cursor = result.terminal?.cursor ??
|
|
136
|
+
(result.lastByteEnd != null ? String(result.lastByteEnd) : null);
|
|
137
|
+
if (!cursor)
|
|
138
|
+
return;
|
|
139
|
+
console.error(`\nTo resume: compute logs ${versionId} --cursor ${cursor}`);
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,cAAc,EAGd,UAAU,GACX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,mCAAmC;KACjD;IACD,IAAI,EAAE;QACJ,EAAE,EAAE;YACF,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,oBAAoB;YACjC,QAAQ,EAAE,IAAI;SACf;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,+CAA+C;SAC7D;QACD,YAAY,EAAE;YACZ,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,KAAK;YACd,WAAW,EACT,+DAA+D;SAClE;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,2DAA2D;SACzE;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,gDAAgD;SAC9D;KACF;IACD,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACtB,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE3B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,wBAAwB,EAAE,CAAC;QAEvD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC;YAE1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACpE,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrD,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YAEjD,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B;gBACE,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,SAAS;gBACT,IAAI;gBACJ,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC;gBAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,MAAM;aACP,EACD,QAAQ,CACT,CAAC;YAEF,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;gBACnB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3B,IAAI,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAEhD,IAAI,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7B,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;wBACd,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;4BACb,EAAE,EAAE,KAAK;4BACT,KAAK,EAAE;gCACL,UAAU,EAAE,KAAK,CAAC,UAAU;gCAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;6BACvB;yBACF,CAAC,CACH,CAAC;oBACJ,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC/B,CAAC;oBACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBAED,KAAqB,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACrE,IAAI,QAAQ,KAAK,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QACnC,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,QAAQ,CAAC,MAAoB;IACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,QAAQ,CAAC,MAAoB;IACpC,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACtB,MAAoB,EACpB,SAAiB,EACjB,IAAa;IAEb,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAE5B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACzC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,qBAAqB,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;QAC5E,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1C,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;YAClD,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAEzC,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,YAAY,CAAC;QAClB,KAAK,YAAY,CAAC;QAClB,KAAK,oBAAoB;YACvB,OAAO,CAAC,CAAC;QACX,KAAK,kBAAkB,CAAC;QACxB,KAAK,gBAAgB,CAAC;QACtB,KAAK,gBAAgB;YACnB,OAAO,CAAC,CAAC;QACX;YACE,OAAO,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACtB,MAAoB,EACpB,SAAiB,EACjB,IAAa;IAEb,IAAI,IAAI;QAAE,OAAO;IAEjB,MAAM,MAAM,GACV,MAAM,CAAC,QAAQ,EAAE,MAAM;QACvB,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEnE,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,OAAO,CAAC,KAAK,CAAC,6BAA6B,SAAS,aAAa,MAAM,EAAE,CAAC,CAAC;AAC7E,CAAC"}
|
package/dist/lib/auth/guard.d.ts
CHANGED
|
@@ -9,4 +9,18 @@ import { type ManagementApiClient } from "@prisma/management-api-sdk";
|
|
|
9
9
|
* Returns null if not authenticated (caller should print guidance and exit).
|
|
10
10
|
*/
|
|
11
11
|
export declare function requireAuth(): Promise<ManagementApiClient | null>;
|
|
12
|
+
export type AuthToken = {
|
|
13
|
+
token: string;
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Resolve authentication and return a raw token + base URL.
|
|
18
|
+
*
|
|
19
|
+
* Reuses {@link requireAuth} for the OAuth path so token refresh logic
|
|
20
|
+
* isn't duplicated. For service tokens the SDK isn't needed.
|
|
21
|
+
*
|
|
22
|
+
* TODO: The management-api-sdk should expose a dedicated token refresh method
|
|
23
|
+
* so callers needing raw tokens don't have to trigger a dummy API call.
|
|
24
|
+
*/
|
|
25
|
+
export declare function requireAuthToken(): Promise<AuthToken | null>;
|
|
12
26
|
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,4BAA4B,CAAC;AAIpC;;;;;;;;GAQG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAiCvE"}
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,4BAA4B,CAAC;AAIpC;;;;;;;;GAQG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAiCvE;AAED,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA6BlE"}
|
package/dist/lib/auth/guard.js
CHANGED
|
@@ -36,4 +36,40 @@ export async function requireAuth() {
|
|
|
36
36
|
});
|
|
37
37
|
return sdk.client;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve authentication and return a raw token + base URL.
|
|
41
|
+
*
|
|
42
|
+
* Reuses {@link requireAuth} for the OAuth path so token refresh logic
|
|
43
|
+
* isn't duplicated. For service tokens the SDK isn't needed.
|
|
44
|
+
*
|
|
45
|
+
* TODO: The management-api-sdk should expose a dedicated token refresh method
|
|
46
|
+
* so callers needing raw tokens don't have to trigger a dummy API call.
|
|
47
|
+
*/
|
|
48
|
+
export async function requireAuthToken() {
|
|
49
|
+
const rawServiceToken = process.env[SERVICE_TOKEN_ENV_VAR];
|
|
50
|
+
if (rawServiceToken !== undefined) {
|
|
51
|
+
const serviceToken = rawServiceToken.trim();
|
|
52
|
+
if (serviceToken.length > 0) {
|
|
53
|
+
return { token: serviceToken, baseUrl: getApiBaseUrl() };
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`${SERVICE_TOKEN_ENV_VAR} is set but empty. Provide a valid token or unset the variable.`);
|
|
56
|
+
}
|
|
57
|
+
const client = await requireAuth();
|
|
58
|
+
if (!client)
|
|
59
|
+
return null;
|
|
60
|
+
// Trigger a lightweight API call so the SDK can auto-refresh an expired
|
|
61
|
+
// token. On success the SDK writes refreshed tokens back into tokenStorage.
|
|
62
|
+
try {
|
|
63
|
+
await client.GET("/v1/projects", { params: { query: { limit: 1 } } });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Refresh failed — fall through with the stored token and let the caller
|
|
67
|
+
// surface the auth error from the actual request.
|
|
68
|
+
}
|
|
69
|
+
const tokenStorage = new FileTokenStorage();
|
|
70
|
+
const tokens = await tokenStorage.getTokens();
|
|
71
|
+
if (!tokens)
|
|
72
|
+
return null;
|
|
73
|
+
return { token: tokens.accessToken, baseUrl: getApiBaseUrl() };
|
|
74
|
+
}
|
|
39
75
|
//# sourceMappingURL=guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../../src/lib/auth/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,sBAAsB,GAEvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC3D,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,yBAAyB,CAAC;gBAC/B,OAAO,EAAE,aAAa,EAAE;gBACxB,KAAK,EAAE,YAAY;aACpB,CAAC,CAAC;QACL,CAAC;QACD,MAAM,IAAI,KAAK,CACb,GAAG,qBAAqB,iEAAiE,CAC1F,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,CAAC;IAE9C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CACX,iEAAiE,CAClE,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,sBAAsB,CAAC;QACjC,QAAQ,EAAE,SAAS;QACnB,WAAW,EAAE,kCAAkC;QAC/C,YAAY;QACZ,UAAU,EAAE,aAAa,EAAE;KAC5B,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC"}
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../../src/lib/auth/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,sBAAsB,GAEvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC3D,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,yBAAyB,CAAC;gBAC/B,OAAO,EAAE,aAAa,EAAE;gBACxB,KAAK,EAAE,YAAY;aACpB,CAAC,CAAC;QACL,CAAC;QACD,MAAM,IAAI,KAAK,CACb,GAAG,qBAAqB,iEAAiE,CAC1F,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,CAAC;IAE9C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CACX,iEAAiE,CAClE,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,sBAAsB,CAAC;QACjC,QAAQ,EAAE,SAAS;QACnB,WAAW,EAAE,kCAAkC;QAC/C,YAAY;QACZ,UAAU,EAAE,aAAa,EAAE;KAC5B,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAID;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC3D,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC;QAC3D,CAAC;QACD,MAAM,IAAI,KAAK,CACb,GAAG,qBAAqB,iEAAiE,CAC1F,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,wEAAwE;IACxE,4EAA4E;IAC5E,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,kDAAkD;IACpD,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,CAAC;IAC9C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC;AACjE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/compute-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"repository": "prisma/project-compute",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@clack/prompts": "^1.1.0",
|
|
34
|
-
"@prisma/compute-sdk": "0.
|
|
34
|
+
"@prisma/compute-sdk": "0.15.0",
|
|
35
35
|
"@prisma/credentials-store": "^7.5.0",
|
|
36
36
|
"@prisma/management-api-sdk": "^1.23.0",
|
|
37
37
|
"citty": "^0.2.1",
|
package/src/cli.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { deployCommand } from "./commands/deploy.ts";
|
|
|
3
3
|
import { envGroup } from "./commands/env.ts";
|
|
4
4
|
import { loginCommand } from "./commands/login.ts";
|
|
5
5
|
import { logoutCommand } from "./commands/logout.ts";
|
|
6
|
+
import { logsCommand } from "./commands/logs.ts";
|
|
6
7
|
import { projectsGroup } from "./commands/projects.ts";
|
|
7
8
|
import { servicesGroup } from "./commands/services.ts";
|
|
8
9
|
import { versionsGroup } from "./commands/versions.ts";
|
|
@@ -26,6 +27,7 @@ export const mainCommand = defineCommand({
|
|
|
26
27
|
login: loginCommand,
|
|
27
28
|
logout: logoutCommand,
|
|
28
29
|
deploy: deployCommand,
|
|
30
|
+
logs: logsCommand,
|
|
29
31
|
env: envGroup,
|
|
30
32
|
projects: projectsGroup,
|
|
31
33
|
services: servicesGroup,
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CancelledError,
|
|
3
|
+
LogStreamError,
|
|
4
|
+
type StreamRecord,
|
|
5
|
+
type StreamResult,
|
|
6
|
+
streamLogs,
|
|
7
|
+
} from "@prisma/compute-sdk";
|
|
8
|
+
import { defineCommand } from "citty";
|
|
9
|
+
import { requireAuthToken } from "../lib/auth/guard.ts";
|
|
10
|
+
import { createCommandAbortSignal, handleError } from "./helpers.ts";
|
|
11
|
+
|
|
12
|
+
export const logsCommand = defineCommand({
|
|
13
|
+
meta: {
|
|
14
|
+
name: "logs",
|
|
15
|
+
description: "Stream logs for a compute version",
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
id: {
|
|
19
|
+
type: "positional",
|
|
20
|
+
description: "Compute version ID",
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
tail: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Number of recent lines to show (default: 100)",
|
|
26
|
+
},
|
|
27
|
+
"from-start": {
|
|
28
|
+
type: "boolean",
|
|
29
|
+
default: false,
|
|
30
|
+
description:
|
|
31
|
+
"Start from the beginning of the log buffer instead of tailing",
|
|
32
|
+
},
|
|
33
|
+
cursor: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Resume from a byte offset cursor (from a previous stream)",
|
|
36
|
+
},
|
|
37
|
+
json: {
|
|
38
|
+
type: "boolean",
|
|
39
|
+
default: false,
|
|
40
|
+
description: "Output each log/terminal record as a JSON line",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
run: async ({ args }) => {
|
|
44
|
+
const auth = await requireAuthToken();
|
|
45
|
+
if (!auth) process.exit(1);
|
|
46
|
+
|
|
47
|
+
const { signal, cleanup } = createCommandAbortSignal();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const versionId = args.id;
|
|
51
|
+
|
|
52
|
+
const tail = args.tail ? Number.parseInt(args.tail, 10) : undefined;
|
|
53
|
+
if (tail != null && (Number.isNaN(tail) || tail < 1)) {
|
|
54
|
+
console.error("--tail must be a positive integer");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const onRecord = args.json ? emitJson : emitText;
|
|
59
|
+
|
|
60
|
+
const result = await streamLogs(
|
|
61
|
+
{
|
|
62
|
+
baseUrl: auth.baseUrl,
|
|
63
|
+
token: auth.token,
|
|
64
|
+
versionId,
|
|
65
|
+
tail,
|
|
66
|
+
fromStart: args["from-start"],
|
|
67
|
+
cursor: args.cursor,
|
|
68
|
+
signal,
|
|
69
|
+
},
|
|
70
|
+
onRecord,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (result.isErr()) {
|
|
74
|
+
const error = result.error;
|
|
75
|
+
if (CancelledError.is(error)) process.exit(130);
|
|
76
|
+
|
|
77
|
+
if (LogStreamError.is(error)) {
|
|
78
|
+
if (args.json) {
|
|
79
|
+
console.log(
|
|
80
|
+
JSON.stringify({
|
|
81
|
+
ok: false,
|
|
82
|
+
error: {
|
|
83
|
+
statusCode: error.statusCode,
|
|
84
|
+
message: error.message,
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
console.error(error.message);
|
|
90
|
+
}
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
error satisfies never;
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const exitCode = handleStreamEnd(result.value, versionId, args.json);
|
|
99
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (signal.aborted) process.exit(130);
|
|
102
|
+
process.exit(handleError(error));
|
|
103
|
+
} finally {
|
|
104
|
+
cleanup();
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
function emitJson(record: StreamRecord): void {
|
|
110
|
+
console.log(JSON.stringify(record));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function emitText(record: StreamRecord): void {
|
|
114
|
+
if (record.type === "log") {
|
|
115
|
+
process.stdout.write(`${record.text}\n`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function handleStreamEnd(
|
|
120
|
+
result: StreamResult,
|
|
121
|
+
versionId: string,
|
|
122
|
+
json: boolean,
|
|
123
|
+
): number {
|
|
124
|
+
const { terminal } = result;
|
|
125
|
+
|
|
126
|
+
if (!terminal) {
|
|
127
|
+
printResumeHint(result, versionId, json);
|
|
128
|
+
return 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!json) {
|
|
132
|
+
if (terminal.kind === "error") {
|
|
133
|
+
console.error(`Log stream ended: ${terminal.message} (${terminal.code})`);
|
|
134
|
+
} else if (terminal.code === "superseded") {
|
|
135
|
+
console.error("Log stream superseded by another client.");
|
|
136
|
+
} else if (terminal.code === "segment_time_limit") {
|
|
137
|
+
console.error("Log stream segment ended (10-minute limit).");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
printResumeHint(result, versionId, json);
|
|
142
|
+
|
|
143
|
+
switch (terminal.code) {
|
|
144
|
+
case "vm_stopped":
|
|
145
|
+
case "superseded":
|
|
146
|
+
case "segment_time_limit":
|
|
147
|
+
return 0;
|
|
148
|
+
case "logs_unavailable":
|
|
149
|
+
case "upstream_error":
|
|
150
|
+
case "internal_error":
|
|
151
|
+
return 1;
|
|
152
|
+
default:
|
|
153
|
+
return terminal.kind === "error" ? 1 : 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function printResumeHint(
|
|
158
|
+
result: StreamResult,
|
|
159
|
+
versionId: string,
|
|
160
|
+
json: boolean,
|
|
161
|
+
): void {
|
|
162
|
+
if (json) return;
|
|
163
|
+
|
|
164
|
+
const cursor =
|
|
165
|
+
result.terminal?.cursor ??
|
|
166
|
+
(result.lastByteEnd != null ? String(result.lastByteEnd) : null);
|
|
167
|
+
|
|
168
|
+
if (!cursor) return;
|
|
169
|
+
|
|
170
|
+
console.error(`\nTo resume: compute logs ${versionId} --cursor ${cursor}`);
|
|
171
|
+
}
|
package/src/lib/auth/guard.ts
CHANGED
|
@@ -49,3 +49,45 @@ export async function requireAuth(): Promise<ManagementApiClient | null> {
|
|
|
49
49
|
|
|
50
50
|
return sdk.client;
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
export type AuthToken = { token: string; baseUrl: string };
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Resolve authentication and return a raw token + base URL.
|
|
57
|
+
*
|
|
58
|
+
* Reuses {@link requireAuth} for the OAuth path so token refresh logic
|
|
59
|
+
* isn't duplicated. For service tokens the SDK isn't needed.
|
|
60
|
+
*
|
|
61
|
+
* TODO: The management-api-sdk should expose a dedicated token refresh method
|
|
62
|
+
* so callers needing raw tokens don't have to trigger a dummy API call.
|
|
63
|
+
*/
|
|
64
|
+
export async function requireAuthToken(): Promise<AuthToken | null> {
|
|
65
|
+
const rawServiceToken = process.env[SERVICE_TOKEN_ENV_VAR];
|
|
66
|
+
if (rawServiceToken !== undefined) {
|
|
67
|
+
const serviceToken = rawServiceToken.trim();
|
|
68
|
+
if (serviceToken.length > 0) {
|
|
69
|
+
return { token: serviceToken, baseUrl: getApiBaseUrl() };
|
|
70
|
+
}
|
|
71
|
+
throw new Error(
|
|
72
|
+
`${SERVICE_TOKEN_ENV_VAR} is set but empty. Provide a valid token or unset the variable.`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const client = await requireAuth();
|
|
77
|
+
if (!client) return null;
|
|
78
|
+
|
|
79
|
+
// Trigger a lightweight API call so the SDK can auto-refresh an expired
|
|
80
|
+
// token. On success the SDK writes refreshed tokens back into tokenStorage.
|
|
81
|
+
try {
|
|
82
|
+
await client.GET("/v1/projects", { params: { query: { limit: 1 } } });
|
|
83
|
+
} catch {
|
|
84
|
+
// Refresh failed — fall through with the stored token and let the caller
|
|
85
|
+
// surface the auth error from the actual request.
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const tokenStorage = new FileTokenStorage();
|
|
89
|
+
const tokens = await tokenStorage.getTokens();
|
|
90
|
+
if (!tokens) return null;
|
|
91
|
+
|
|
92
|
+
return { token: tokens.accessToken, baseUrl: getApiBaseUrl() };
|
|
93
|
+
}
|