@aexol/spectral 0.9.229 → 0.9.230
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/auth-helper.d.ts.map +1 -1
- package/dist/auth-helper.js +14 -8
- package/dist/commands/login.d.ts +12 -4
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +36 -15
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +3 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -1
- package/dist/generated/zeus/const.d.ts.map +1 -1
- package/dist/generated/zeus/const.js +21 -0
- package/dist/generated/zeus/index.d.ts +98 -0
- package/dist/generated/zeus/index.d.ts.map +1 -1
- package/dist/relay/registration.d.ts +10 -2
- package/dist/relay/registration.d.ts.map +1 -1
- package/dist/relay/registration.js +32 -3
- package/package.json +1 -1
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Contract (Batch 1 backend):
|
|
5
5
|
* POST <backend>/api/machines/register
|
|
6
|
-
* Headers: Authorization: Bearer <teamApiKey
|
|
6
|
+
* Headers: Authorization: Bearer <userJwt|userApiKey|teamApiKey>
|
|
7
7
|
* Body: { name?: string, hostname: string, version: string, pid: number }
|
|
8
|
-
* 200: { machineId: string, jwt: string, name: string, ownerId
|
|
8
|
+
* 200: { machineId: string, jwt: string, name: string, teamId?, ownerId?, visibility? }
|
|
9
9
|
*
|
|
10
10
|
* Auth priority:
|
|
11
11
|
* - If `userJwt` is set → used as Bearer token (machine gets ownerId)
|
|
12
|
+
* - Else if `userApiKey` is set → used as Bearer token (machine is PRIVATE
|
|
13
|
+
* with ownerId derived from the key by the backend)
|
|
12
14
|
* - Else → `apiKey` (team API key, machine gets no owner)
|
|
13
15
|
*
|
|
14
16
|
* Why this lives in its own module:
|
|
@@ -30,6 +32,12 @@ export interface RegistrationDeps {
|
|
|
30
32
|
backendUrl: string;
|
|
31
33
|
/** Team API key — used when `userJwt` is not set. */
|
|
32
34
|
apiKey: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional user API key ("sk-aexol-user-"), pinned to a team but owned by a
|
|
37
|
+
* single user. Used when `userJwt` is not set; takes priority over `apiKey`.
|
|
38
|
+
* The backend registers the machine as PRIVATE with ownerId from the key.
|
|
39
|
+
*/
|
|
40
|
+
userApiKey?: string;
|
|
33
41
|
/** Optional user JWT from OAuth login. When set, used instead of `apiKey` for registration. */
|
|
34
42
|
userJwt?: string;
|
|
35
43
|
/** Display name override (from `--machine-name`). Falls back to hostname. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/relay/registration.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/relay/registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAElF,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWvD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUvD;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,CAI/D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,gBAAgB,CAAC,CA2I3B"}
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Contract (Batch 1 backend):
|
|
5
5
|
* POST <backend>/api/machines/register
|
|
6
|
-
* Headers: Authorization: Bearer <teamApiKey
|
|
6
|
+
* Headers: Authorization: Bearer <userJwt|userApiKey|teamApiKey>
|
|
7
7
|
* Body: { name?: string, hostname: string, version: string, pid: number }
|
|
8
|
-
* 200: { machineId: string, jwt: string, name: string, ownerId
|
|
8
|
+
* 200: { machineId: string, jwt: string, name: string, teamId?, ownerId?, visibility? }
|
|
9
9
|
*
|
|
10
10
|
* Auth priority:
|
|
11
11
|
* - If `userJwt` is set → used as Bearer token (machine gets ownerId)
|
|
12
|
+
* - Else if `userApiKey` is set → used as Bearer token (machine is PRIVATE
|
|
13
|
+
* with ownerId derived from the key by the backend)
|
|
12
14
|
* - Else → `apiKey` (team API key, machine gets no owner)
|
|
13
15
|
*
|
|
14
16
|
* Why this lives in its own module:
|
|
@@ -92,6 +94,7 @@ export async function ensureMachineRegistered(deps) {
|
|
|
92
94
|
const skew = deps.expirySkewSec ?? 60;
|
|
93
95
|
const existing = await loadMachine();
|
|
94
96
|
const forceRefresh = deps.forceRefresh === true;
|
|
97
|
+
const usingUserApiKey = !deps.userJwt && !!deps.userApiKey;
|
|
95
98
|
if (!forceRefresh && existing && !isJwtExpired(existing.machineJwt, skew)) {
|
|
96
99
|
// The cached machine JWT is still valid. If the caller authenticated with a
|
|
97
100
|
// user JWT (OAuth login) and the cached machine was previously owned by a
|
|
@@ -106,6 +109,21 @@ export async function ensureMachineRegistered(deps) {
|
|
|
106
109
|
shouldReuse = false;
|
|
107
110
|
}
|
|
108
111
|
}
|
|
112
|
+
else if (usingUserApiKey) {
|
|
113
|
+
// A user API key carries no `sub` claim, so identity is tracked by the
|
|
114
|
+
// key itself: `ensureMachineRegistered` records the key used for the
|
|
115
|
+
// last registration in `machine.json` extra. A different key means a
|
|
116
|
+
// different user (the backend derives `ownerId` from the key), so the
|
|
117
|
+
// machine must be re-registered to transfer ownership and flip
|
|
118
|
+
// visibility to PRIVATE. A missing marker means the cached machine was
|
|
119
|
+
// registered with a team key — re-register so the backend can make it
|
|
120
|
+
// PRIVATE for this user.
|
|
121
|
+
const previousKey = existing.extra?.userApiKey;
|
|
122
|
+
if (previousKey !== deps.userApiKey) {
|
|
123
|
+
console.log("Machine registered under a different user API key, re-registering to transfer ownership...");
|
|
124
|
+
shouldReuse = false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
109
127
|
if (shouldReuse) {
|
|
110
128
|
return { reused: true, record: existing };
|
|
111
129
|
}
|
|
@@ -114,6 +132,8 @@ export async function ensureMachineRegistered(deps) {
|
|
|
114
132
|
console.warn("Re-registering machine: cached JWT was rejected by the backend (forceRefresh).");
|
|
115
133
|
}
|
|
116
134
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
135
|
+
// Token priority: userJwt (OAuth) > userApiKey (user-pinned key) > team key.
|
|
136
|
+
const authToken = deps.userJwt ?? deps.userApiKey ?? deps.apiKey;
|
|
117
137
|
const url = `${deps.backendUrl.replace(/\/$/, "")}/api/machines/register`;
|
|
118
138
|
const body = {
|
|
119
139
|
// Reuse the cached display name on JWT-expiry refresh so the backend's
|
|
@@ -129,7 +149,7 @@ export async function ensureMachineRegistered(deps) {
|
|
|
129
149
|
res = await fetchImpl(url, {
|
|
130
150
|
method: "POST",
|
|
131
151
|
headers: {
|
|
132
|
-
Authorization: `Bearer ${
|
|
152
|
+
Authorization: `Bearer ${authToken}`,
|
|
133
153
|
"Content-Type": "application/json",
|
|
134
154
|
},
|
|
135
155
|
body: JSON.stringify(body),
|
|
@@ -163,6 +183,14 @@ export async function ensureMachineRegistered(deps) {
|
|
|
163
183
|
typeof obj.name !== "string") {
|
|
164
184
|
throw new Error(`Machine registration: backend response missing required fields (machineId, jwt, name)`);
|
|
165
185
|
}
|
|
186
|
+
const extra = { ...(existing?.extra ?? {}) };
|
|
187
|
+
delete extra.userApiKey;
|
|
188
|
+
if (usingUserApiKey) {
|
|
189
|
+
// Record which key was used so a later run with a different user key
|
|
190
|
+
// (a different account) forces re-registration. machine.json is 0600,
|
|
191
|
+
// same as config.json where the key already lives.
|
|
192
|
+
extra.userApiKey = deps.userApiKey;
|
|
193
|
+
}
|
|
166
194
|
const record = {
|
|
167
195
|
machineId: obj.machineId,
|
|
168
196
|
machineName: obj.name,
|
|
@@ -173,6 +201,7 @@ export async function ensureMachineRegistered(deps) {
|
|
|
173
201
|
registeredAt: Date.now(),
|
|
174
202
|
hostname: hostname(),
|
|
175
203
|
version: deps.version,
|
|
204
|
+
extra: Object.keys(extra).length > 0 ? extra : undefined,
|
|
176
205
|
};
|
|
177
206
|
await saveMachine(record);
|
|
178
207
|
return { reused: false, forced: forceRefresh, record };
|