@ornncompute/cli 1.0.72 → 1.0.97
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 +55 -24
- package/package.json +4 -2
- package/src/admin-capacity-reservations.mjs +6 -13
- package/src/admin-command-handlers.mjs +2 -1
- package/src/admin-credits.mjs +1 -2
- package/src/admin-enrollment.mjs +22 -30
- package/src/admin-mutations.mjs +6 -56
- package/src/admin-node-diagnostics.mjs +3 -41
- package/src/admin-node-lifecycle.mjs +40 -160
- package/src/admin-node-sanitize.mjs +243 -0
- package/src/admin-shell.mjs +39 -32
- package/src/catalog-shell.mjs +6 -6
- package/src/evidence-commands.mjs +4 -6
- package/src/external-bucket-commands.mjs +76 -96
- package/src/interaction-runtime.mjs +5 -37
- package/src/kubernetes-commands.mjs +25 -183
- package/src/launch-mode-handlers.mjs +0 -1
- package/src/machine-reference.mjs +33 -56
- package/src/mount-commands.mjs +25 -131
- package/src/slurm-commands.mjs +13 -2
- package/src/storage-commands.mjs +2 -87
- package/src/vm-commands.mjs +48 -101
- package/vendor/api-client/commerce.js +743 -0
- package/vendor/capabilities/cli.js +7688 -7
- package/vendor/capabilities/capabilities/admin-capacity-reservations.js +0 -101
- package/vendor/capabilities/capabilities/admin-enrollment.js +0 -321
- package/vendor/capabilities/capabilities/admin-node-diagnostics.js +0 -88
- package/vendor/capabilities/capabilities/admin-nodes-lifecycle.js +0 -235
- package/vendor/capabilities/capabilities/admin.js +0 -91
- package/vendor/capabilities/capabilities/cli.js +0 -156
- package/vendor/capabilities/capabilities/clusters.js +0 -248
- package/vendor/capabilities/capabilities/commerce-market.js +0 -405
- package/vendor/capabilities/capabilities/compute.js +0 -523
- package/vendor/capabilities/capabilities/credits.js +0 -78
- package/vendor/capabilities/capabilities/evidence.js +0 -145
- package/vendor/capabilities/capabilities/external-buckets.js +0 -191
- package/vendor/capabilities/capabilities/fleet.js +0 -306
- package/vendor/capabilities/capabilities/identity.js +0 -129
- package/vendor/capabilities/capabilities/listings.js +0 -398
- package/vendor/capabilities/capabilities/locality.js +0 -42
- package/vendor/capabilities/capabilities/market-shared.js +0 -46
- package/vendor/capabilities/capabilities/markets.js +0 -482
- package/vendor/capabilities/capabilities/mounts.js +0 -176
- package/vendor/capabilities/capabilities/native-listing.js +0 -99
- package/vendor/capabilities/capabilities/networks.js +0 -1264
- package/vendor/capabilities/capabilities/observability.js +0 -218
- package/vendor/capabilities/capabilities/organization-invites.js +0 -53
- package/vendor/capabilities/capabilities/reservation-list.js +0 -68
- package/vendor/capabilities/capabilities/staff-shared.js +0 -64
- package/vendor/capabilities/capabilities/tokens.js +0 -165
- package/vendor/capabilities/capabilities/users.js +0 -159
- package/vendor/capabilities/capabilities/volumes.js +0 -178
- package/vendor/capabilities/capability.js +0 -99
- package/vendor/capabilities/cli-catalog.js +0 -73
- package/vendor/capabilities/cli-migrations.js +0 -264
- package/vendor/capabilities/names.js +0 -6
- package/vendor/capabilities/software-catalog.js +0 -82
- package/vendor/capabilities/spec-catalog.js +0 -151
- package/vendor/capabilities/supplier-directory.js +0 -20
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
import { ADMIN_MUTATION_SAFETY, AdminMutationError, runAdminMutation } from "./admin-mutations.mjs";
|
|
5
|
+
import { parseSemanticArguments } from "./interaction-runtime.mjs";
|
|
6
|
+
|
|
7
|
+
const MANUAL_CLEANUP = "ACCEPT MANUAL CLEANUP";
|
|
8
|
+
|
|
9
|
+
function usageError(capability, detail, field) {
|
|
10
|
+
return new AdminMutationError(
|
|
11
|
+
[`Usage: ${capability.cli.vnext.human}`, detail].filter(Boolean).join("\n"),
|
|
12
|
+
{ code: "usage_error", ...(field ? { field } : {}) }
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function semanticArguments(argv, capability) {
|
|
17
|
+
const { $positionals, ...options } = parseSemanticArguments(argv);
|
|
18
|
+
if ($positionals.length !== 1 || !$positionals[0]) {
|
|
19
|
+
throw usageError(capability, "Pass exactly one canonical node ID.", "node-id");
|
|
20
|
+
}
|
|
21
|
+
return { nodeId: $positionals[0], options };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function rejectExtra(capability, extra) {
|
|
25
|
+
const [name] = Object.keys(extra);
|
|
26
|
+
if (name) throw usageError(capability, `Unknown option: --${name}`, name);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function validated(capability, input) {
|
|
30
|
+
const parsed = capability.input.safeParse(input);
|
|
31
|
+
if (!parsed.success) throw usageError(capability, parsed.error.message);
|
|
32
|
+
return parsed.data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function evidenceSha256(capability, path) {
|
|
36
|
+
try {
|
|
37
|
+
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw usageError(
|
|
40
|
+
capability,
|
|
41
|
+
`Could not read --evidence-file: ${error instanceof Error ? error.message : String(error)}`,
|
|
42
|
+
"evidence-file"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseStart(argv, capability) {
|
|
48
|
+
const {
|
|
49
|
+
nodeId,
|
|
50
|
+
options: { operation, confirmation, jobId, batch, recoveryUuid, ...extra },
|
|
51
|
+
} = semanticArguments(argv, capability);
|
|
52
|
+
rejectExtra(capability, extra);
|
|
53
|
+
if (typeof operation !== "string") throw usageError(capability, "--operation is required.");
|
|
54
|
+
const input = validated(capability, {
|
|
55
|
+
node_id: nodeId,
|
|
56
|
+
job_id: jobId ?? randomUUID(),
|
|
57
|
+
operation,
|
|
58
|
+
...(batch ? { maintenance_batch_id: batch } : {}),
|
|
59
|
+
...(recoveryUuid ? { recovery_uuid: recoveryUuid } : {}),
|
|
60
|
+
confirmation,
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
input,
|
|
64
|
+
mutation: { idempotencyKey: input.job_id, safety: ADMIN_MUTATION_SAFETY.eligibleHumanOnly },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function parseStatus(argv, capability) {
|
|
69
|
+
const {
|
|
70
|
+
nodeId,
|
|
71
|
+
options: { job, ...extra },
|
|
72
|
+
} = semanticArguments(argv, capability);
|
|
73
|
+
rejectExtra(capability, extra);
|
|
74
|
+
return { input: validated(capability, { node_id: nodeId, job_id: job }) };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function parseDecision(argv, capability) {
|
|
78
|
+
const {
|
|
79
|
+
nodeId,
|
|
80
|
+
options: {
|
|
81
|
+
job,
|
|
82
|
+
confirmation,
|
|
83
|
+
reservation,
|
|
84
|
+
releaseOperation,
|
|
85
|
+
reason,
|
|
86
|
+
evidenceFile,
|
|
87
|
+
tenantAccessRevoked,
|
|
88
|
+
dataDrivesSanitized,
|
|
89
|
+
acknowledgeRetainedOs,
|
|
90
|
+
...extra
|
|
91
|
+
},
|
|
92
|
+
} = semanticArguments(argv, capability);
|
|
93
|
+
rejectExtra(capability, extra);
|
|
94
|
+
const cleanupOptions = {
|
|
95
|
+
reservation,
|
|
96
|
+
releaseOperation,
|
|
97
|
+
reason,
|
|
98
|
+
evidenceFile,
|
|
99
|
+
tenantAccessRevoked,
|
|
100
|
+
dataDrivesSanitized,
|
|
101
|
+
acknowledgeRetainedOs,
|
|
102
|
+
};
|
|
103
|
+
if (confirmation !== MANUAL_CLEANUP) {
|
|
104
|
+
const [supplied] =
|
|
105
|
+
Object.entries(cleanupOptions).find(([, value]) => value !== undefined) ?? [];
|
|
106
|
+
if (supplied) {
|
|
107
|
+
throw usageError(
|
|
108
|
+
capability,
|
|
109
|
+
`Manual cleanup options require --confirmation "${MANUAL_CLEANUP}".`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
input: validated(capability, { node_id: nodeId, job_id: job, confirmation }),
|
|
114
|
+
mutation: { safety: ADMIN_MUTATION_SAFETY.eligibleHumanOnly },
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Each attestation is the operator's own flag, never a default.
|
|
118
|
+
for (const [name, value] of Object.entries(cleanupOptions)) {
|
|
119
|
+
if (value === undefined || value === "") {
|
|
120
|
+
const flag = name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
121
|
+
throw usageError(capability, `--${flag} is required for manual cleanup.`, flag);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const input = validated(capability, {
|
|
125
|
+
node_id: nodeId,
|
|
126
|
+
job_id: job,
|
|
127
|
+
confirmation,
|
|
128
|
+
manual_cleanup: {
|
|
129
|
+
reservation_id: reservation,
|
|
130
|
+
lifecycle_operation_id: releaseOperation,
|
|
131
|
+
reason,
|
|
132
|
+
evidence_sha256: evidenceSha256(capability, evidenceFile),
|
|
133
|
+
acknowledge_retained_os: true,
|
|
134
|
+
tenant_access_revoked: true,
|
|
135
|
+
data_drives_sanitized: true,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
return { input, mutation: { safety: ADMIN_MUTATION_SAFETY.eligibleHumanOnly } };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const startConsequence = {
|
|
142
|
+
data_wipe: "Erases every local data drive; the OS drive is preserved.",
|
|
143
|
+
ram_roundtrip: "Boots the node through RAM and back without erasing drives.",
|
|
144
|
+
node_turnover: "Erases the whole node, including the OS drive, and restores a host image.",
|
|
145
|
+
host_restore: "Restores the host OS from its trusted image.",
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
function decisionReview(input) {
|
|
149
|
+
const fields = [
|
|
150
|
+
{ label: "Node", value: input.node_id },
|
|
151
|
+
{ label: "Sanitize job", value: input.job_id },
|
|
152
|
+
{ label: "Decision", value: input.confirmation },
|
|
153
|
+
];
|
|
154
|
+
if (input.confirmation === "APPROVE SANITIZATION") {
|
|
155
|
+
return { fields, consequence: "Starts the held destructive maintenance on this node." };
|
|
156
|
+
}
|
|
157
|
+
if (input.confirmation === "SKIP SANITIZATION") {
|
|
158
|
+
return {
|
|
159
|
+
fields,
|
|
160
|
+
consequence: "Skips an eligible first-use wipe; nothing is erased or certified.",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const cleanup = input.manual_cleanup;
|
|
164
|
+
return {
|
|
165
|
+
fields: [
|
|
166
|
+
...fields,
|
|
167
|
+
{ label: "Reservation", value: cleanup.reservation_id },
|
|
168
|
+
{ label: "Release operation", value: cleanup.lifecycle_operation_id },
|
|
169
|
+
{ label: "Reason", value: cleanup.reason },
|
|
170
|
+
{ label: "Evidence SHA-256", value: cleanup.evidence_sha256 },
|
|
171
|
+
{
|
|
172
|
+
label: "You attest",
|
|
173
|
+
value:
|
|
174
|
+
"tenant access revoked; every local data drive sanitized; existing OS retained and not certified",
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
consequence:
|
|
178
|
+
"Lets the held release finish without a full wipe. The boot disk and prior root exposure remain.",
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function runStart({ execute, input, mutation, runtime }) {
|
|
183
|
+
return runAdminMutation({
|
|
184
|
+
...runtime,
|
|
185
|
+
...mutation,
|
|
186
|
+
prepare: async () => ({
|
|
187
|
+
review: {
|
|
188
|
+
title: "Start node sanitization",
|
|
189
|
+
fields: [
|
|
190
|
+
{ label: "Node", value: input.node_id },
|
|
191
|
+
{ label: "Operation", value: input.operation ?? "data_wipe" },
|
|
192
|
+
...(input.recovery_uuid ? [{ label: "Recovery UUID", value: input.recovery_uuid }] : []),
|
|
193
|
+
{ label: "Sanitize job", value: input.job_id },
|
|
194
|
+
{ label: "Confirmation", value: input.confirmation },
|
|
195
|
+
],
|
|
196
|
+
consequence: `${startConsequence[input.operation ?? "data_wipe"]} The job waits for staff approval.`,
|
|
197
|
+
},
|
|
198
|
+
value: input,
|
|
199
|
+
}),
|
|
200
|
+
execute: (value) => execute(value, { confirmed: true }),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function runStatus({ execute, input }) {
|
|
205
|
+
return {
|
|
206
|
+
data: await execute(input),
|
|
207
|
+
exitCode: 0,
|
|
208
|
+
outcome: { class: "ready", phase: "complete" },
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function runDecision({ execute, input, mutation, runtime }) {
|
|
213
|
+
return runAdminMutation({
|
|
214
|
+
...runtime,
|
|
215
|
+
...mutation,
|
|
216
|
+
prepare: async () => ({
|
|
217
|
+
review: { title: "Decide node sanitize job", ...decisionReview(input) },
|
|
218
|
+
value: input,
|
|
219
|
+
}),
|
|
220
|
+
execute: (value) => execute(value, { confirmed: true }),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export const adminNodeSanitizeHandlers = [
|
|
225
|
+
{
|
|
226
|
+
capabilityId: "node.sanitize.start",
|
|
227
|
+
parse: parseStart,
|
|
228
|
+
run: runStart,
|
|
229
|
+
safety: ADMIN_MUTATION_SAFETY.eligibleHumanOnly,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
capabilityId: "node.sanitize.show",
|
|
233
|
+
parse: parseStatus,
|
|
234
|
+
run: runStatus,
|
|
235
|
+
safety: ADMIN_MUTATION_SAFETY.direct,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
capabilityId: "node.sanitize.update",
|
|
239
|
+
parse: parseDecision,
|
|
240
|
+
run: runDecision,
|
|
241
|
+
safety: ADMIN_MUTATION_SAFETY.eligibleHumanOnly,
|
|
242
|
+
},
|
|
243
|
+
];
|
package/src/admin-shell.mjs
CHANGED
|
@@ -185,13 +185,21 @@ function parseAdminInput(capability, argv) {
|
|
|
185
185
|
throw new AdminUsageError(usage);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
const offsetPagination = ["users.list", "organization.list"].includes(
|
|
188
|
+
const offsetPagination = ["users.list", "organization.list", "supplier.list"].includes(
|
|
189
|
+
capability.id
|
|
190
|
+
);
|
|
191
|
+
const directoryPagination = ["users.list", "organization.list"].includes(capability.id);
|
|
189
192
|
const reservationList = capability.id === "reservation.list";
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
"
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
const maxLimit = directoryPagination
|
|
194
|
+
? 100
|
|
195
|
+
: capability.id === "supplier.list"
|
|
196
|
+
? 1000
|
|
197
|
+
: reservationList
|
|
198
|
+
? 100
|
|
199
|
+
: MAX_PAGE_LIMIT;
|
|
200
|
+
const limit =
|
|
201
|
+
positiveInteger(options.limit, "limit", maxLimit) ??
|
|
202
|
+
(directoryPagination ? 25 : DEFAULT_PAGE_LIMIT);
|
|
195
203
|
const input = {};
|
|
196
204
|
if (nodeCommand) input.node_id = positionals[0];
|
|
197
205
|
if (options.supplier) input.organization_id = options.supplier;
|
|
@@ -232,13 +240,8 @@ function parseAdminInput(capability, argv) {
|
|
|
232
240
|
if (options.cursor) input.cursor = options.cursor;
|
|
233
241
|
}
|
|
234
242
|
if (offsetPagination) {
|
|
235
|
-
if (explicitOffset !== undefined && options.cursor) {
|
|
236
|
-
throw new AdminUsageError("--offset and --cursor cannot be used together.", {
|
|
237
|
-
field: "offset",
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
243
|
input.limit = limit;
|
|
241
|
-
input.offset = explicitOffset ??
|
|
244
|
+
input.offset = explicitOffset ?? 0;
|
|
242
245
|
}
|
|
243
246
|
|
|
244
247
|
return {
|
|
@@ -328,14 +331,9 @@ function collectionKey(capability) {
|
|
|
328
331
|
if (root === "nodes" && leaf === "logs") return "logs";
|
|
329
332
|
if (!["list", "search"].includes(leaf)) return null;
|
|
330
333
|
if (root === "enrollment-tokens") return "enrollment_tokens";
|
|
331
|
-
return [
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
"organizations",
|
|
335
|
-
"reservations",
|
|
336
|
-
"suppliers",
|
|
337
|
-
"users",
|
|
338
|
-
].includes(root)
|
|
334
|
+
return ["facilities", "nodes", "organizations", "reservations", "suppliers", "users"].includes(
|
|
335
|
+
root
|
|
336
|
+
)
|
|
339
337
|
? root
|
|
340
338
|
: null;
|
|
341
339
|
}
|
|
@@ -445,14 +443,19 @@ export function finalizeAdminResult(capability, payload, pagination) {
|
|
|
445
443
|
pagination.ownerOffsetPagination && payload && !Array.isArray(payload)
|
|
446
444
|
? payload.next_offset
|
|
447
445
|
: undefined;
|
|
446
|
+
const nextOffset = pagination.ownerOffsetPagination
|
|
447
|
+
? Number.isSafeInteger(ownerNextOffset) && ownerNextOffset > offset
|
|
448
|
+
? ownerNextOffset
|
|
449
|
+
: selected.length === pagination.limit
|
|
450
|
+
? offset + selected.length
|
|
451
|
+
: null
|
|
452
|
+
: undefined;
|
|
448
453
|
const ownerNextCursor =
|
|
449
454
|
payload && !Array.isArray(payload)
|
|
450
455
|
? (payload.next_cursor ?? payload.nextCursor ?? payload.page?.next_cursor ?? null)
|
|
451
456
|
: null;
|
|
452
457
|
let nextCursor = pagination.ownerOffsetPagination
|
|
453
|
-
?
|
|
454
|
-
? encodeCursor(command, ownerNextOffset)
|
|
455
|
-
: null
|
|
458
|
+
? null
|
|
456
459
|
: !pagination.ownerPagination && offset + selected.length < rows.length
|
|
457
460
|
? encodeCursor(command, offset + selected.length)
|
|
458
461
|
: (ownerNextCursor ?? null);
|
|
@@ -480,11 +483,9 @@ export function finalizeAdminResult(capability, payload, pagination) {
|
|
|
480
483
|
}
|
|
481
484
|
return {
|
|
482
485
|
data: { [key]: selected },
|
|
483
|
-
page:
|
|
484
|
-
limit: pagination.limit,
|
|
485
|
-
returned: selected.length,
|
|
486
|
-
next_cursor: nextCursor,
|
|
487
|
-
},
|
|
486
|
+
page: pagination.ownerOffsetPagination
|
|
487
|
+
? { limit: pagination.limit, returned: selected.length, next_offset: nextOffset }
|
|
488
|
+
: { limit: pagination.limit, returned: selected.length, next_cursor: nextCursor },
|
|
488
489
|
};
|
|
489
490
|
}
|
|
490
491
|
|
|
@@ -515,7 +516,15 @@ export function writeAdminResultHuman(stdout, command, result, input = {}) {
|
|
|
515
516
|
} else {
|
|
516
517
|
for (const row of rows) stdout.write(`${JSON.stringify(row)}\n`);
|
|
517
518
|
}
|
|
518
|
-
|
|
519
|
+
const nextPage =
|
|
520
|
+
result.page.next_offset !== undefined
|
|
521
|
+
? result.page.next_offset === null
|
|
522
|
+
? null
|
|
523
|
+
: `--offset ${result.page.next_offset}`
|
|
524
|
+
: result.page.next_cursor
|
|
525
|
+
? `--cursor ${shellSingleQuote(result.page.next_cursor)}`
|
|
526
|
+
: null;
|
|
527
|
+
if (nextPage) {
|
|
519
528
|
const target = command === "admin nodes logs" ? ` ${shellSingleQuote(input.node_id)}` : "";
|
|
520
529
|
const filters = [
|
|
521
530
|
["supplier", command === "admin users list" ? undefined : input.organization_id],
|
|
@@ -535,8 +544,6 @@ export function writeAdminResultHuman(stdout, command, result, input = {}) {
|
|
|
535
544
|
.filter(([, value]) => value !== undefined)
|
|
536
545
|
.map(([name, value]) => ` --${name} ${shellSingleQuote(String(value))}`)
|
|
537
546
|
.join("");
|
|
538
|
-
stdout.write(
|
|
539
|
-
`Next: ornn ${command}${target} --cursor ${shellSingleQuote(result.page.next_cursor)}${filters}\n`
|
|
540
|
-
);
|
|
547
|
+
stdout.write(`Next: ornn ${command}${target} ${nextPage}${filters}\n`);
|
|
541
548
|
}
|
|
542
549
|
}
|
package/src/catalog-shell.mjs
CHANGED
|
@@ -818,13 +818,13 @@ function parseCapabilityInput(capability, rawInput) {
|
|
|
818
818
|
});
|
|
819
819
|
}
|
|
820
820
|
|
|
821
|
-
// Commerce
|
|
822
|
-
//
|
|
823
|
-
const
|
|
821
|
+
// Native Commerce and Markets routes authenticate the caller at the gateway.
|
|
822
|
+
// Commerce's /internal/v1 routes additionally require staff.
|
|
823
|
+
const DIRECT_GATEWAY_PREFIXES = ["/commerce", "/internal/v1", "/v1/markets"];
|
|
824
824
|
|
|
825
|
-
function
|
|
825
|
+
function isDirectGatewayPath(path) {
|
|
826
826
|
const pathname = String(path).split("?")[0];
|
|
827
|
-
return
|
|
827
|
+
return DIRECT_GATEWAY_PREFIXES.some(
|
|
828
828
|
(prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`)
|
|
829
829
|
);
|
|
830
830
|
}
|
|
@@ -839,7 +839,7 @@ function adminFetch(io, path, init = {}) {
|
|
|
839
839
|
...(init.headers !== undefined ? { headers: init.headers } : {}),
|
|
840
840
|
...((init.signal ?? io.signal) !== undefined ? { signal: init.signal ?? io.signal } : {}),
|
|
841
841
|
};
|
|
842
|
-
return
|
|
842
|
+
return isDirectGatewayPath(path) || (path === "/v1/staff/invites" && request.method === "POST")
|
|
843
843
|
? cliRequest(request)
|
|
844
844
|
: operatorRequest(request);
|
|
845
845
|
}
|
|
@@ -264,15 +264,13 @@ function reachability(value) {
|
|
|
264
264
|
if (explicit === true) return { state: "reachable", observed_at: null };
|
|
265
265
|
if (explicit === false) return { state: "unreachable", observed_at: null };
|
|
266
266
|
const candidate = record(source.reachability);
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
const observedAt =
|
|
271
|
-
text(candidate.observed_at) ?? text(candidate.checked_at) ?? text(offGrid.last_checked_at);
|
|
267
|
+
const state = stateToken(candidate.state ?? candidate.status);
|
|
268
|
+
const phase = stateToken(candidate.phase);
|
|
269
|
+
const observedAt = text(candidate.observed_at) ?? text(candidate.checked_at);
|
|
272
270
|
if (["reachable", "live", "online"].includes(state) || phase === "ssh_ready")
|
|
273
271
|
return { state: "reachable", observed_at: observedAt };
|
|
274
272
|
if (
|
|
275
|
-
["unreachable", "offline"
|
|
273
|
+
["unreachable", "offline"].includes(state) ||
|
|
276
274
|
["ssh_unreachable", "unreachable"].includes(phase)
|
|
277
275
|
)
|
|
278
276
|
return { state: "unreachable", observed_at: observedAt };
|