@cpajs/cpa 0.0.1-alpha-3 → 0.1.0-rc.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/README.md +108 -12
- package/dist/client/resources/oauth.d.ts +6 -2
- package/dist/client/resources/oauth.d.ts.map +1 -1
- package/dist/client/resources/oauth.js +28 -8
- package/dist/client/resources/oauth.js.map +1 -1
- package/dist/client/transport.d.ts.map +1 -1
- package/dist/client/transport.js +7 -3
- package/dist/client/transport.js.map +1 -1
- package/dist/server/args.js +1 -1
- package/dist/server/args.js.map +1 -1
- package/dist/server/binary.d.ts +19 -0
- package/dist/server/binary.d.ts.map +1 -1
- package/dist/server/binary.js +35 -1
- package/dist/server/binary.js.map +1 -1
- package/dist/server/config.d.ts +46 -7
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +148 -22
- package/dist/server/config.js.map +1 -1
- package/dist/server/errors.d.ts +4 -2
- package/dist/server/errors.d.ts.map +1 -1
- package/dist/server/errors.js +1 -1
- package/dist/server/errors.js.map +1 -1
- package/dist/server/index.d.ts +18 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +383 -79
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +19 -0
- package/dist/server/internal.d.ts.map +1 -0
- package/dist/server/internal.js +10 -0
- package/dist/server/internal.js.map +1 -0
- package/dist/server/management.d.ts +29 -0
- package/dist/server/management.d.ts.map +1 -0
- package/dist/server/management.js +64 -0
- package/dist/server/management.js.map +1 -0
- package/dist/server/process.d.ts +12 -1
- package/dist/server/process.d.ts.map +1 -1
- package/dist/server/process.js +55 -13
- package/dist/server/process.js.map +1 -1
- package/dist/server/readiness.d.ts +16 -2
- package/dist/server/readiness.d.ts.map +1 -1
- package/dist/server/readiness.js +32 -2
- package/dist/server/readiness.js.map +1 -1
- package/dist/server/targets.d.ts +4 -0
- package/dist/server/targets.d.ts.map +1 -1
- package/dist/server/targets.js +6 -0
- package/dist/server/targets.js.map +1 -1
- package/dist/server/types.d.ts +88 -14
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +31 -24
- package/src/client/resources/oauth.ts +28 -13
- package/src/client/transport.ts +7 -3
- package/src/server/args.ts +1 -1
- package/src/server/binary.ts +46 -1
- package/src/server/config.ts +169 -22
- package/src/server/errors.ts +4 -2
- package/src/server/index.ts +459 -94
- package/src/server/internal.ts +20 -0
- package/src/server/management.ts +89 -0
- package/src/server/process.ts +60 -13
- package/src/server/readiness.ts +38 -3
- package/src/server/targets.ts +8 -0
- package/src/server/types.ts +90 -14
package/dist/server/types.d.ts
CHANGED
|
@@ -15,6 +15,22 @@ export interface HomeOptions {
|
|
|
15
15
|
/** Keep using the JWT's address instead of discovering cluster nodes (`-home-disable-cluster-discovery`). */
|
|
16
16
|
disableClusterDiscovery?: boolean;
|
|
17
17
|
}
|
|
18
|
+
export interface ManagementOptions {
|
|
19
|
+
/** Management API key. Empty keys are rejected. */
|
|
20
|
+
key: string;
|
|
21
|
+
/**
|
|
22
|
+
* Write `management.allow-remote`, which lets non-loopback clients use the
|
|
23
|
+
* management API. Default `false`; ignored by `viaEnvironment`, which always
|
|
24
|
+
* enables remote access upstream.
|
|
25
|
+
*/
|
|
26
|
+
allowRemote?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Pass the key to CPA through `MANAGEMENT_PASSWORD` instead of writing a
|
|
29
|
+
* bcrypt hash into the managed config. Upstream treats that variable as
|
|
30
|
+
* enabling remote management and compares the key in plaintext.
|
|
31
|
+
*/
|
|
32
|
+
viaEnvironment?: boolean;
|
|
33
|
+
}
|
|
18
34
|
interface CommonServerOptions {
|
|
19
35
|
/** Use this executable instead of the bundled platform package. */
|
|
20
36
|
binaryPath?: string;
|
|
@@ -23,10 +39,15 @@ interface CommonServerOptions {
|
|
|
23
39
|
* directory. When omitted, a temporary directory is created and removed on stop.
|
|
24
40
|
*/
|
|
25
41
|
stateDir?: string;
|
|
42
|
+
/** Management API key and how it reaches CPA. */
|
|
43
|
+
management?: ManagementOptions;
|
|
26
44
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
45
|
+
* Deprecated alias for `management: { key }`. It uses the safe default
|
|
46
|
+
* (bcrypt hash in the config, remote management disabled) and will be removed
|
|
47
|
+
* in a future release. Use `management.viaEnvironment` for the old
|
|
48
|
+
* `MANAGEMENT_PASSWORD` behaviour.
|
|
49
|
+
*
|
|
50
|
+
* @deprecated Use `management` instead.
|
|
30
51
|
*/
|
|
31
52
|
managementKey?: string;
|
|
32
53
|
/**
|
|
@@ -34,6 +55,22 @@ interface CommonServerOptions {
|
|
|
34
55
|
* (`-local-model`). Explicit `models.*` config sources still win.
|
|
35
56
|
*/
|
|
36
57
|
localModel?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Start CPA through `cpa-launcher` so it cannot outlive this process, even
|
|
60
|
+
* when this process is killed with SIGKILL or crashes. Default `true`.
|
|
61
|
+
*
|
|
62
|
+
* - Linux: the launcher sets PR_SET_PDEATHSIG and execs CPA (no extra process).
|
|
63
|
+
* - macOS / BSD: the launcher stays as CPA's parent and stops it when this
|
|
64
|
+
* process dies; `pid` is then the launcher's pid, and signals sent to it are
|
|
65
|
+
* forwarded to CPA.
|
|
66
|
+
* - Windows: not needed; Node already kills child processes with their parent.
|
|
67
|
+
*
|
|
68
|
+
* The launcher ships next to the CPA binary in every platform package. With a
|
|
69
|
+
* custom `binaryPath` it is looked up next to that binary and then in an
|
|
70
|
+
* installed platform package; if none is found CPA is started directly and a
|
|
71
|
+
* notice is logged through `onLog`.
|
|
72
|
+
*/
|
|
73
|
+
launcher?: boolean;
|
|
37
74
|
/** Run as a node of a CPA Home control plane. Home mode disables the local management API. */
|
|
38
75
|
home?: HomeOptions;
|
|
39
76
|
/**
|
|
@@ -52,23 +89,39 @@ interface CommonServerOptions {
|
|
|
52
89
|
onLog?: (log: LogLine) => void;
|
|
53
90
|
/** Additional strings to redact from logs and errors. */
|
|
54
91
|
redact?: readonly string[];
|
|
55
|
-
/** Default grace period for `stop()` before the process is killed. Default 10 000 ms. */
|
|
92
|
+
/** Default grace period for `stop()` before the process is killed. Ignored on Windows, where `stop()` terminates forcefully. Default 10 000 ms. */
|
|
56
93
|
stopTimeoutMs?: number;
|
|
57
94
|
}
|
|
58
95
|
export interface StartWithConfigOptions extends CommonServerOptions {
|
|
59
96
|
/**
|
|
60
|
-
* Native CPA configuration.
|
|
61
|
-
*
|
|
97
|
+
* Native CPA configuration.
|
|
98
|
+
*
|
|
99
|
+
* Written as YAML to `<stateDir>/config.yaml` only when that file does not
|
|
100
|
+
* exist. On later starts the existing file is reused, so changes made through
|
|
101
|
+
* the management API (or by CPA itself) survive a `stop()` / `startServer()`
|
|
102
|
+
* cycle. Set `overwriteConfig: true` to replace it with this object.
|
|
62
103
|
*/
|
|
63
104
|
config?: CpaConfig;
|
|
64
105
|
configPath?: never;
|
|
65
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* Replace `<stateDir>/config.yaml` even when it already exists. Default
|
|
108
|
+
* `false`. When the existing file is kept, `config`, `host` and `port` are not
|
|
109
|
+
* applied and a message is emitted through `onLog`.
|
|
110
|
+
*/
|
|
111
|
+
overwriteConfig?: boolean;
|
|
112
|
+
/** Bind host, when cpajs writes the managed file. Default `config.server.host`, else `127.0.0.1`. */
|
|
66
113
|
host?: string;
|
|
67
|
-
/** Bind port.
|
|
114
|
+
/** Bind port, when cpajs writes the managed file. Default `config.server.port`, else `0` (a free port is picked). */
|
|
68
115
|
port?: number;
|
|
69
116
|
}
|
|
70
117
|
export interface StartWithConfigPathOptions extends CommonServerOptions {
|
|
71
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* Existing CPA config file, handed to CPA as-is. CPA may rewrite it on
|
|
120
|
+
* startup: it hashes a plaintext `management.secret-key`, removes legacy
|
|
121
|
+
* keys that conflict with their v8 equivalents, and normalizes the layout.
|
|
122
|
+
* The file must set a fixed positive port; a missing or non-positive port
|
|
123
|
+
* makes CPA bind a random port it does not report.
|
|
124
|
+
*/
|
|
72
125
|
configPath: string;
|
|
73
126
|
config?: never;
|
|
74
127
|
host?: never;
|
|
@@ -80,9 +133,18 @@ export interface ExitResult {
|
|
|
80
133
|
signal: NodeJS.Signals | null;
|
|
81
134
|
}
|
|
82
135
|
export interface StopOptions {
|
|
83
|
-
/** Grace period after the termination signal before the process is killed. */
|
|
136
|
+
/** Grace period after the termination signal before the process is killed. Ignored on Windows, where the process is terminated forcefully right away. */
|
|
84
137
|
timeoutMs?: number;
|
|
85
138
|
}
|
|
139
|
+
export interface RestartOptions {
|
|
140
|
+
/**
|
|
141
|
+
* Grace period after the termination signal before the old process is killed.
|
|
142
|
+
* Defaults to `stopTimeoutMs`.
|
|
143
|
+
*/
|
|
144
|
+
timeoutMs?: number;
|
|
145
|
+
/** Cancels the restart. The server is left stopped, like any other failed restart. */
|
|
146
|
+
signal?: AbortSignal;
|
|
147
|
+
}
|
|
86
148
|
export interface CpaServer {
|
|
87
149
|
/** e.g. `http://127.0.0.1:8317`. Use as the client `baseUrl`. */
|
|
88
150
|
readonly origin: string;
|
|
@@ -94,15 +156,27 @@ export interface CpaServer {
|
|
|
94
156
|
readonly binaryPath: string;
|
|
95
157
|
readonly configPath: string;
|
|
96
158
|
readonly stateDir: string;
|
|
97
|
-
/** The management key given in the options, if any. */
|
|
98
|
-
readonly managementKey: string | undefined;
|
|
99
159
|
readonly process: ChildProcess;
|
|
100
160
|
/** Recent output lines (redacted), oldest first. */
|
|
101
161
|
readonly recentLogs: readonly LogLine[];
|
|
102
|
-
/**
|
|
162
|
+
/**
|
|
163
|
+
* Settles when the process exits for good: on `stop()` or an unexpected exit.
|
|
164
|
+
* A restart stops one process and starts another, so it does not settle this.
|
|
165
|
+
*/
|
|
103
166
|
readonly exited: Promise<ExitResult>;
|
|
104
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* Stops CPA. On POSIX it sends SIGTERM and then SIGKILL after the grace
|
|
169
|
+
* period. On Windows Node cannot deliver a graceful signal, so the process is
|
|
170
|
+
* terminated forcefully (there is no grace period and CPA is not asked to
|
|
171
|
+
* flush state or update auth files). Idempotent.
|
|
172
|
+
*/
|
|
105
173
|
stop(options?: StopOptions): Promise<ExitResult>;
|
|
174
|
+
/**
|
|
175
|
+
* Restarts CPA with the original options, reusing `origin`, `baseUrl`, `host`,
|
|
176
|
+
* `port`, `stateDir` and the existing config file. Concurrent calls share one
|
|
177
|
+
* operation. A failed or cancelled restart leaves the server stopped.
|
|
178
|
+
*/
|
|
179
|
+
restart(options?: RestartOptions): Promise<void>;
|
|
106
180
|
}
|
|
107
181
|
export {};
|
|
108
182
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,6GAA6G;IAC7G,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,UAAU,mBAAmB;IAC3B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cpajs/cpa",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.1.0-rc.2",
|
|
4
4
|
"description": "Run the official CLIProxyAPI from JavaScript and talk to its v8 management API with a typed client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "akarachen",
|
|
@@ -35,7 +35,11 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
37
37
|
"typecheck": "tsc -p tsconfig.json",
|
|
38
|
+
"lint": "biome lint .",
|
|
39
|
+
"format": "biome format --write .",
|
|
40
|
+
"format:check": "biome format .",
|
|
38
41
|
"test": "vitest run",
|
|
42
|
+
"test:coverage": "vitest run --coverage",
|
|
39
43
|
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
40
44
|
"cpa:source": "node scripts/fetch-source.ts",
|
|
41
45
|
"cpa:build": "node scripts/build-binary.ts",
|
|
@@ -46,10 +50,13 @@
|
|
|
46
50
|
"test:install": "node scripts/install-test.ts"
|
|
47
51
|
},
|
|
48
52
|
"dependencies": {
|
|
53
|
+
"bcryptjs": "^3.0.3",
|
|
49
54
|
"yaml": "^2.9.1"
|
|
50
55
|
},
|
|
51
56
|
"devDependencies": {
|
|
57
|
+
"@biomejs/biome": "^2.6.3",
|
|
52
58
|
"@types/node": "^24.0.0",
|
|
59
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
53
60
|
"typescript": "^7.0.2",
|
|
54
61
|
"vitest": "^5.0.5"
|
|
55
62
|
},
|
|
@@ -58,28 +65,28 @@
|
|
|
58
65
|
"access": "public"
|
|
59
66
|
},
|
|
60
67
|
"optionalDependencies": {
|
|
61
|
-
"@cpajs/darwin-x64": "0.0.
|
|
62
|
-
"@cpajs/darwin-arm64": "0.0.
|
|
63
|
-
"@cpajs/win32-x64": "0.0.
|
|
64
|
-
"@cpajs/win32-arm64": "0.0.
|
|
65
|
-
"@cpajs/win32-ia32": "0.0.
|
|
66
|
-
"@cpajs/linux-x64-gnu": "0.0.
|
|
67
|
-
"@cpajs/linux-arm64-gnu": "0.0.
|
|
68
|
-
"@cpajs/linux-x64-musl": "0.0.
|
|
69
|
-
"@cpajs/linux-arm64-musl": "0.0.
|
|
70
|
-
"@cpajs/linux-arm": "0.0.
|
|
71
|
-
"@cpajs/linux-ia32": "0.0.
|
|
72
|
-
"@cpajs/linux-riscv64": "0.0.
|
|
73
|
-
"@cpajs/linux-ppc64": "0.0.
|
|
74
|
-
"@cpajs/linux-s390x": "0.0.
|
|
75
|
-
"@cpajs/linux-loong64": "0.0.
|
|
76
|
-
"@cpajs/linux-mips": "0.0.
|
|
77
|
-
"@cpajs/linux-mipsel": "0.0.
|
|
78
|
-
"@cpajs/freebsd-x64": "0.0.
|
|
79
|
-
"@cpajs/freebsd-arm64": "0.0.
|
|
80
|
-
"@cpajs/freebsd-ia32": "0.0.
|
|
81
|
-
"@cpajs/openbsd-x64": "0.0.
|
|
82
|
-
"@cpajs/openbsd-arm64": "0.0.
|
|
83
|
-
"@cpajs/netbsd-x64": "0.0.
|
|
68
|
+
"@cpajs/darwin-x64": "0.1.0-rc.2",
|
|
69
|
+
"@cpajs/darwin-arm64": "0.1.0-rc.2",
|
|
70
|
+
"@cpajs/win32-x64": "0.1.0-rc.2",
|
|
71
|
+
"@cpajs/win32-arm64": "0.1.0-rc.2",
|
|
72
|
+
"@cpajs/win32-ia32": "0.1.0-rc.2",
|
|
73
|
+
"@cpajs/linux-x64-gnu": "0.1.0-rc.2",
|
|
74
|
+
"@cpajs/linux-arm64-gnu": "0.1.0-rc.2",
|
|
75
|
+
"@cpajs/linux-x64-musl": "0.1.0-rc.2",
|
|
76
|
+
"@cpajs/linux-arm64-musl": "0.1.0-rc.2",
|
|
77
|
+
"@cpajs/linux-arm": "0.1.0-rc.2",
|
|
78
|
+
"@cpajs/linux-ia32": "0.1.0-rc.2",
|
|
79
|
+
"@cpajs/linux-riscv64": "0.1.0-rc.2",
|
|
80
|
+
"@cpajs/linux-ppc64": "0.1.0-rc.2",
|
|
81
|
+
"@cpajs/linux-s390x": "0.1.0-rc.2",
|
|
82
|
+
"@cpajs/linux-loong64": "0.1.0-rc.2",
|
|
83
|
+
"@cpajs/linux-mips": "0.1.0-rc.2",
|
|
84
|
+
"@cpajs/linux-mipsel": "0.1.0-rc.2",
|
|
85
|
+
"@cpajs/freebsd-x64": "0.1.0-rc.2",
|
|
86
|
+
"@cpajs/freebsd-arm64": "0.1.0-rc.2",
|
|
87
|
+
"@cpajs/freebsd-ia32": "0.1.0-rc.2",
|
|
88
|
+
"@cpajs/openbsd-x64": "0.1.0-rc.2",
|
|
89
|
+
"@cpajs/openbsd-arm64": "0.1.0-rc.2",
|
|
90
|
+
"@cpajs/netbsd-x64": "0.1.0-rc.2"
|
|
84
91
|
}
|
|
85
92
|
}
|
|
@@ -9,7 +9,8 @@ import type {
|
|
|
9
9
|
VertexImportResponse,
|
|
10
10
|
} from '../types/oauth.ts';
|
|
11
11
|
import type { SIWCStatusResponse } from '../types/credentials.ts';
|
|
12
|
-
import
|
|
12
|
+
import { CpaAbortError } from '../errors.ts';
|
|
13
|
+
import { managementUrl, type RequestOptions, type Transport } from '../transport.ts';
|
|
13
14
|
import type { CredentialContent, CredentialSelector } from './credentials.ts';
|
|
14
15
|
|
|
15
16
|
export interface WaitForOAuthOptions extends RequestOptions {
|
|
@@ -38,23 +39,20 @@ export class OAuthResource {
|
|
|
38
39
|
return (await this.#t.request<OAuthStatusResponse>({ ...options, method: 'GET', path: '/oauth/status', query: { state } })).data;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Polls {@link status} until the session leaves `wait`. Abort with `signal`
|
|
44
|
+
* (for an overall limit use `AbortSignal.timeout()`); cancellation always
|
|
45
|
+
* rejects with `CpaAbortError`, whether it happens during a request or between polls.
|
|
46
|
+
*/
|
|
42
47
|
async waitForCompletion(state: string, options: WaitForOAuthOptions = {}): Promise<Exclude<OAuthStatusResponse, { status: 'wait' }>> {
|
|
43
48
|
const { intervalMs = 2_000, ...requestOptions } = options;
|
|
49
|
+
const url = managementUrl(this.#t.baseUrl, '/oauth/status');
|
|
50
|
+
url.searchParams.set('state', state);
|
|
51
|
+
const target = { method: 'GET', url: url.toString() };
|
|
44
52
|
while (true) {
|
|
45
53
|
const result = await this.status(state, requestOptions);
|
|
46
54
|
if (result.status !== 'wait') return result;
|
|
47
|
-
await
|
|
48
|
-
const timer = setTimeout(resolve, intervalMs);
|
|
49
|
-
requestOptions.signal?.addEventListener(
|
|
50
|
-
'abort',
|
|
51
|
-
() => {
|
|
52
|
-
clearTimeout(timer);
|
|
53
|
-
reject(requestOptions.signal!.reason);
|
|
54
|
-
},
|
|
55
|
-
{ once: true },
|
|
56
|
-
);
|
|
57
|
-
});
|
|
55
|
+
await abortableDelay(intervalMs, requestOptions.signal, target);
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -103,3 +101,20 @@ export class OAuthResource {
|
|
|
103
101
|
return (await this.#t.request<SIWCStatusResponse>({ ...options, method: 'GET', path: '/oauth/siwc/status', query: { ...selector } })).data;
|
|
104
102
|
}
|
|
105
103
|
}
|
|
104
|
+
|
|
105
|
+
/** Waits `ms`, rejecting with `CpaAbortError` if `signal` aborts; never leaves a listener behind. */
|
|
106
|
+
function abortableDelay(ms: number, signal: AbortSignal | undefined, target: { method: string; url: string }): Promise<void> {
|
|
107
|
+
const aborted = () => new CpaAbortError(`${target.method} ${target.url} was aborted`, target, { cause: signal!.reason });
|
|
108
|
+
if (signal?.aborted) return Promise.reject(aborted());
|
|
109
|
+
return new Promise<void>((resolve, reject) => {
|
|
110
|
+
const onAbort = (): void => {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
reject(aborted());
|
|
113
|
+
};
|
|
114
|
+
const timer = setTimeout(() => {
|
|
115
|
+
signal?.removeEventListener('abort', onAbort);
|
|
116
|
+
resolve();
|
|
117
|
+
}, ms);
|
|
118
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
119
|
+
});
|
|
120
|
+
}
|
package/src/client/transport.ts
CHANGED
|
@@ -163,6 +163,8 @@ export class Transport {
|
|
|
163
163
|
if (body !== undefined) init.body = body;
|
|
164
164
|
|
|
165
165
|
const responseType = req.responseType ?? 'json';
|
|
166
|
+
// Set once a Response is handed to the caller, who then owns reading its body.
|
|
167
|
+
let handedOff = false;
|
|
166
168
|
try {
|
|
167
169
|
let response: Response;
|
|
168
170
|
try {
|
|
@@ -175,6 +177,7 @@ export class Transport {
|
|
|
175
177
|
throw new CpaHttpError(target, response, await guard(response.text()));
|
|
176
178
|
}
|
|
177
179
|
if (responseType === 'response') {
|
|
180
|
+
handedOff = true;
|
|
178
181
|
return { data: response as T, status: response.status, headers: response.headers };
|
|
179
182
|
}
|
|
180
183
|
if (responseType === 'blob') {
|
|
@@ -194,9 +197,10 @@ export class Transport {
|
|
|
194
197
|
}
|
|
195
198
|
throw classify(error);
|
|
196
199
|
} finally {
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
+
// A handed-off Response is read by the caller: the timeout covered the headers
|
|
201
|
+
// only, and the caller's signal must keep cancelling the body, so its listener
|
|
202
|
+
// stays until that signal aborts. Every other outcome releases everything.
|
|
203
|
+
if (handedOff) clearTimeout(timer);
|
|
200
204
|
else release();
|
|
201
205
|
}
|
|
202
206
|
}
|
package/src/server/args.ts
CHANGED
|
@@ -26,7 +26,7 @@ const MANAGED_FLAGS: Record<string, string> = {
|
|
|
26
26
|
'local-model': 'localModel',
|
|
27
27
|
'home-jwt': 'home.jwt',
|
|
28
28
|
'home-disable-cluster-discovery': 'home.disableClusterDiscovery',
|
|
29
|
-
password: '
|
|
29
|
+
password: 'management.key',
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
function flagName(arg: string): string | undefined {
|
package/src/server/binary.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { accessSync, chmodSync, constants, existsSync, readdirSync, statSync } f
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { CpaBinaryError } from './errors.ts';
|
|
5
|
-
import { TARGETS, UNSUPPORTED_PLATFORMS, binaryName, packageName, type Target } from './targets.ts';
|
|
5
|
+
import { LAUNCHER_NAME, TARGETS, UNSUPPORTED_PLATFORMS, binaryName, packageName, type Target } from './targets.ts';
|
|
6
6
|
|
|
7
7
|
const require = createRequire(import.meta.url);
|
|
8
8
|
|
|
@@ -126,3 +126,48 @@ export function resolveBinary(options: { binaryPath?: string; platform?: HostPla
|
|
|
126
126
|
'make sure your lockfile was not created on another platform without it, or pass binaryPath.',
|
|
127
127
|
);
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
/** How the launcher keeps CPA from outliving this process. */
|
|
131
|
+
export type LauncherMode = 'exec' | 'supervise';
|
|
132
|
+
|
|
133
|
+
export interface ResolvedLauncher {
|
|
134
|
+
path: string;
|
|
135
|
+
/**
|
|
136
|
+
* `exec` (Linux): the launcher sets PR_SET_PDEATHSIG and becomes CPA.
|
|
137
|
+
* `supervise` (macOS, BSD): the launcher stays as CPA's parent and stops it
|
|
138
|
+
* when its stdin pipe from this process closes.
|
|
139
|
+
*/
|
|
140
|
+
mode: LauncherMode;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isExecutable(path: string): boolean {
|
|
144
|
+
try {
|
|
145
|
+
if (!statSync(path).isFile()) return false;
|
|
146
|
+
accessSync(path, constants.X_OK);
|
|
147
|
+
return true;
|
|
148
|
+
} catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Finds `cpa-launcher` for a CPA binary: next to the binary first (platform
|
|
155
|
+
* packages and local builds keep both in one directory), then in an installed
|
|
156
|
+
* platform package. Returns undefined on Windows, where Node already places
|
|
157
|
+
* child processes in a job object that is closed (and its processes killed)
|
|
158
|
+
* when this process exits.
|
|
159
|
+
*/
|
|
160
|
+
export function resolveLauncher(cpaPath: string, platform: HostPlatform = currentPlatform()): ResolvedLauncher | undefined {
|
|
161
|
+
if (platform.os === 'win32') return undefined;
|
|
162
|
+
const mode: LauncherMode = platform.os === 'linux' ? 'exec' : 'supervise';
|
|
163
|
+
const candidates = [join(dirname(cpaPath), LAUNCHER_NAME)];
|
|
164
|
+
for (const target of candidateTargets(platform)) {
|
|
165
|
+
try {
|
|
166
|
+
candidates.push(join(dirname(require.resolve(`${packageName(target)}/package.json`)), 'bin', LAUNCHER_NAME));
|
|
167
|
+
} catch {
|
|
168
|
+
// Package not installed.
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const path = candidates.find(isExecutable);
|
|
172
|
+
return path === undefined ? undefined : { path, mode };
|
|
173
|
+
}
|