@ornncompute/cli 1.0.112 → 1.0.114

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornncompute/cli",
3
- "version": "1.0.112",
3
+ "version": "1.0.114",
4
4
  "description": "Command-line interface for Ornn compute access workflows.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,3 +1,4 @@
1
+ import { getCliSession } from "../vendor/api-client/authorization.js";
1
2
  import { readFileSync } from "node:fs";
2
3
 
3
4
  import {
@@ -1009,7 +1010,9 @@ async function executeCapability(
1009
1010
  }
1010
1011
  if (capability.domain === "listings" && ownOrganizationId === undefined) {
1011
1012
  // Verify listing owner IDs before the request, never after a committed mutation.
1012
- const session = await customerCapabilityFetch(io, "/v1/cli/session", {}, authSnapshot);
1013
+ const session = await getCliSession((path, init) =>
1014
+ customerCapabilityFetch(io, path, init, authSnapshot)
1015
+ );
1013
1016
  ownOrganizationId = session.selectedOrganization?.id ?? null;
1014
1017
  }
1015
1018
  return customerCapabilityFetch(io, path, init, authSnapshot);
@@ -1,3 +1,7 @@
1
+ import {
2
+ startCliDeviceAuthorization,
3
+ pollCliDeviceAuthorization,
4
+ } from "../vendor/api-client/authorization.js";
1
5
  import { spawn } from "node:child_process";
2
6
 
3
7
  import { configuredAuthBaseUrl } from "./auth-store.mjs";
@@ -90,7 +94,7 @@ export async function openBrowser(url, { platform = process.platform, spawnImpl
90
94
 
91
95
  export async function startDeviceFlow({ apiBaseUrl, authBaseUrl, fetchImpl = fetch } = {}) {
92
96
  const requestBaseUrl = apiBaseUrl || authBaseUrl;
93
- const data = await postJson(fetchImpl, `${requestBaseUrl}/v1/cli/device/start`, {});
97
+ const data = await startCliDeviceAuthorization(deviceRequest(fetchImpl, requestBaseUrl));
94
98
 
95
99
  const deviceCode = pickString(data, "deviceCode", "device_code");
96
100
  const userCode = pickString(data, "userCode", "user_code");
@@ -126,11 +130,10 @@ export async function pollDeviceFlow({
126
130
  signal,
127
131
  } = {}) {
128
132
  const requestBaseUrl = apiBaseUrl || authBaseUrl;
129
- return postJson(
130
- fetchImpl,
131
- `${requestBaseUrl}/v1/cli/device/poll`,
133
+ return pollCliDeviceAuthorization(
134
+ deviceRequest(fetchImpl, requestBaseUrl),
132
135
  { device_code: deviceCode },
133
- { signal }
136
+ signal
134
137
  );
135
138
  }
136
139
 
@@ -258,28 +261,31 @@ export async function waitForDeviceApproval({
258
261
  }
259
262
  }
260
263
 
261
- async function postJson(fetchImpl, url, body, { signal } = {}) {
262
- const response = await fetchImpl(url, {
263
- body: JSON.stringify(body),
264
- headers: {
265
- Accept: "application/json",
266
- "Content-Type": "application/json",
267
- },
268
- method: "POST",
269
- ...(signal ? { signal } : {}),
270
- });
271
- const text = await response.text();
272
- const data = text ? parseJson(text, url) : {};
273
-
274
- if (!response.ok) {
275
- const detail = data.detail || data.error || response.statusText;
276
- throw new DeviceAuthError(`Auth request failed: ${detail}`, {
277
- detail: data,
278
- status: response.status,
264
+ function deviceRequest(fetchImpl, baseUrl) {
265
+ return async (path, { body, method, signal } = {}) => {
266
+ const url = `${baseUrl}${path}`;
267
+ const response = await fetchImpl(url, {
268
+ body: JSON.stringify(body),
269
+ headers: {
270
+ Accept: "application/json",
271
+ "Content-Type": "application/json",
272
+ },
273
+ method,
274
+ ...(signal ? { signal } : {}),
279
275
  });
280
- }
276
+ const text = await response.text();
277
+ const data = text ? parseJson(text, url) : {};
281
278
 
282
- return data;
279
+ if (!response.ok) {
280
+ const detail = data.detail || data.error || response.statusText;
281
+ throw new DeviceAuthError(`Auth request failed: ${detail}`, {
282
+ detail: data,
283
+ status: response.status,
284
+ });
285
+ }
286
+
287
+ return data;
288
+ };
283
289
  }
284
290
 
285
291
  function parseJson(text, url) {
@@ -1,3 +1,4 @@
1
+ import { getCliSession } from "../vendor/api-client/authorization.js";
1
2
  import { listAllReservations } from "../vendor/api-client/commerce.js";
2
3
  import { gpuLabeler } from "./gpu-catalog.mjs";
3
4
 
@@ -114,7 +115,7 @@ function invalidGateway(interaction, message) {
114
115
  export async function listActiveReservations(context, interaction) {
115
116
  const session = context.cli?.session
116
117
  ? (await context.cli.session("context", {})).data
117
- : await context.fetch("/v1/cli/session");
118
+ : await getCliSession(context.fetch);
118
119
  const customerId = text((session.selectedOrganization ?? session.selected_organization)?.id);
119
120
  if (!customerId) {
120
121
  interaction.usage("Select an organization before choosing a reservation.", {
@@ -1,3 +1,9 @@
1
+ import {
2
+ listApiKeys,
3
+ createApiKey,
4
+ revokeApiKey,
5
+ getCliSession,
6
+ } from "../vendor/api-client/authorization.js";
1
7
  import { spawn as spawnProcessDefault } from "node:child_process";
2
8
  import os from "node:os";
3
9
 
@@ -18,7 +24,7 @@ async function login({
18
24
  hostname = os.hostname(),
19
25
  }) {
20
26
  const registry = await fetch("/v1/orchestrator/registry");
21
- const session = await fetch("/v1/cli/session");
27
+ const session = await getCliSession(fetch);
22
28
  const organizationId = (session?.selectedOrganization ?? session?.selected_organization)?.id;
23
29
  if (typeof organizationId !== "string" || !organizationId) {
24
30
  interaction.usage("Join an organization before logging in to its registry.", {
@@ -26,25 +32,21 @@ async function login({
26
32
  field: "organization",
27
33
  });
28
34
  }
29
- const keysPath = `/v1/organizations/${encodeURIComponent(organizationId)}/api-keys`;
30
35
  const name = `${KEY_NAME_PREFIX}${hostname}`.slice(0, 100);
31
36
 
32
- const existing = await fetch(keysPath);
37
+ const existing = await listApiKeys(fetch, organizationId);
33
38
  for (const key of existing?.api_keys ?? []) {
34
39
  if (key?.name === name && typeof key.id === "string") {
35
- await fetch(`${keysPath}/${encodeURIComponent(key.id)}`, { method: "DELETE" });
40
+ await revokeApiKey(fetch, organizationId, key.id);
36
41
  }
37
42
  }
38
- const created = await fetch(keysPath, {
39
- method: "POST",
40
- body: { name, access: "read_write" },
41
- });
43
+ const created = await createApiKey(fetch, organizationId, { name, access: "read_write" });
42
44
 
43
45
  let exit;
44
46
  try {
45
47
  exit = await dockerLogin(spawnProcess, registry.host, created.token);
46
48
  } catch (error) {
47
- await fetch(`${keysPath}/${encodeURIComponent(created.id)}`, { method: "DELETE" });
49
+ await revokeApiKey(fetch, organizationId, created.id);
48
50
  const missing = error?.code === "ENOENT";
49
51
  interaction.error(
50
52
  missing
@@ -54,7 +56,7 @@ async function login({
54
56
  );
55
57
  }
56
58
  if (exit.code !== 0) {
57
- await fetch(`${keysPath}/${encodeURIComponent(created.id)}`, { method: "DELETE" });
59
+ await revokeApiKey(fetch, organizationId, created.id);
58
60
  interaction.error(`docker login ${registry.host} failed; no key was kept.`, {
59
61
  code: "docker_login_failed",
60
62
  exitCode: 1,
@@ -1,3 +1,4 @@
1
+ import { getCliSession, revokeCliSession } from "../vendor/api-client/authorization.js";
1
2
  import { CliApiError, cliRequest, resolveApiBaseUrl } from "./api-client.mjs";
2
3
  import {
3
4
  bindAuthUser,
@@ -143,13 +144,15 @@ async function context({ env, fetchImpl, sessionSnapshot }) {
143
144
  sessionSnapshot.current = localSession;
144
145
  }
145
146
  const data = sessionContext(
146
- await cliRequest({
147
- endpoint: "/v1/cli/session",
148
- env,
149
- fetchImpl,
150
- method: "GET",
151
- session: localSession,
152
- })
147
+ await getCliSession((endpoint, init) =>
148
+ cliRequest({
149
+ ...init,
150
+ endpoint,
151
+ env,
152
+ fetchImpl,
153
+ session: localSession,
154
+ })
155
+ )
153
156
  );
154
157
  await bindAuthUser(data.user, {
155
158
  env,
@@ -291,14 +294,16 @@ async function logout(runtime) {
291
294
  try {
292
295
  if (!revocationError && session?.accessToken) {
293
296
  attempted = true;
294
- await cliRequest({
295
- endpoint: "/v1/cli/session",
296
- env: runtime.env,
297
- fetchImpl: runtime.fetchImpl,
298
- method: "DELETE",
299
- raw: true,
300
- session,
301
- });
297
+ await revokeCliSession((endpoint, init) =>
298
+ cliRequest({
299
+ ...init,
300
+ endpoint,
301
+ env: runtime.env,
302
+ fetchImpl: runtime.fetchImpl,
303
+ raw: true,
304
+ session,
305
+ })
306
+ );
302
307
  }
303
308
  } catch (error) {
304
309
  revocationError = error;
@@ -0,0 +1,491 @@
1
+ // ../../packages/api-client/dist/authorization/paths.js
2
+ var organizationPath = (id) => `/v1/organizations/${encodeURIComponent(id)}`;
3
+ var personPath = (id) => `/v1/people/${encodeURIComponent(id)}`;
4
+ function withQuery(path, values) {
5
+ const query = new URLSearchParams();
6
+ for (const [key, value] of Object.entries(values)) {
7
+ if (value !== void 0 && value !== null && value !== "")
8
+ query.set(key, Array.isArray(value) ? value.join(",") : String(value));
9
+ }
10
+ return query.size ? `${path}?${query}` : path;
11
+ }
12
+
13
+ // ../../packages/api-client/dist/authorization/organizations.js
14
+ function listOrganizations(request, query = {}, signal) {
15
+ return request(withQuery("/v1/organizations", query), { method: "GET", signal });
16
+ }
17
+ async function listSupplierOrganizations(request, signal) {
18
+ const rows = [];
19
+ for (let offset = 0; offset < 5e4; offset += 1e3) {
20
+ const page = await listOrganizations(request, { role: "supplier", limit: 1e3, offset, sort: "created_at", direction: "asc" }, signal);
21
+ if (!Array.isArray(page))
22
+ throw new Error("Invalid supplier directory response.");
23
+ rows.push(...page);
24
+ if (page.length < 1e3)
25
+ return rows;
26
+ }
27
+ throw new Error("The supplier directory is too large to load completely.");
28
+ }
29
+ async function listOrganizationsByIds(request, ids, signal) {
30
+ const unique = [
31
+ ...new Set(ids.map((id) => id?.trim()).filter((id) => Boolean(id)))
32
+ ];
33
+ const chunks = [];
34
+ for (let start = 0; start < unique.length; start += 100)
35
+ chunks.push(unique.slice(start, start + 100));
36
+ const pages = await Promise.all(chunks.map(async (chunk, index) => {
37
+ if (index > 0)
38
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 40));
39
+ return listOrganizations(request, { ids: chunk, limit: chunk.length }, signal);
40
+ }));
41
+ return pages.flat();
42
+ }
43
+ function countOrganizations(request, query = {}, signal) {
44
+ return request(withQuery("/v1/staff/v1/organizations/count", query), {
45
+ method: "GET",
46
+ signal
47
+ });
48
+ }
49
+ function getOrganization(request, id, signal) {
50
+ return request(organizationPath(id), { method: "GET", signal });
51
+ }
52
+ function listOrganizationsForUser(request, query, signal) {
53
+ return request(withQuery("/v1/organizations/by-user", query), {
54
+ method: "GET",
55
+ signal
56
+ });
57
+ }
58
+ function createOrganization(request, body, signal) {
59
+ return request("/v1/organizations", { method: "POST", body, signal });
60
+ }
61
+ function updateOrganization(request, id, body) {
62
+ return request(organizationPath(id), { method: "PATCH", body });
63
+ }
64
+ function listOrganizationMembers(request, id, signal) {
65
+ return request(`${organizationPath(id)}/members`, { method: "GET", signal });
66
+ }
67
+ function getOrganizationMembership(request, id, email) {
68
+ return request(`${organizationPath(id)}/members/${encodeURIComponent(email)}`, {
69
+ method: "GET"
70
+ });
71
+ }
72
+ function removeOrganizationMember(request, id, email) {
73
+ return request(`${organizationPath(id)}/members/${encodeURIComponent(email)}`, {
74
+ method: "DELETE"
75
+ });
76
+ }
77
+
78
+ // ../../packages/api-client/dist/authorization/account.js
79
+ function getUserProfile(request, id, signal) {
80
+ return request(`${personPath(id)}/profile`, {
81
+ method: "GET",
82
+ signal
83
+ });
84
+ }
85
+ function updateUserProfile(request, id, body) {
86
+ return request(`${personPath(id)}/profile`, {
87
+ method: "PATCH",
88
+ body
89
+ });
90
+ }
91
+ function getUserPreferences(request, id, signal) {
92
+ return request(`${personPath(id)}/preferences`, {
93
+ method: "GET",
94
+ signal
95
+ });
96
+ }
97
+ function updateUserPreferences(request, id, body) {
98
+ return request(`${personPath(id)}/preferences`, {
99
+ method: "PATCH",
100
+ body
101
+ });
102
+ }
103
+ function getNotificationPreferences(request, id, signal) {
104
+ return request(`${organizationPath(id)}/notification-preferences`, {
105
+ method: "GET",
106
+ signal
107
+ });
108
+ }
109
+ function updateNotificationPreferences(request, id, body) {
110
+ return request(`${organizationPath(id)}/notification-preferences`, {
111
+ method: "PATCH",
112
+ body
113
+ });
114
+ }
115
+ function listApiKeys(request, id, signal) {
116
+ return request(`${organizationPath(id)}/api-keys`, {
117
+ method: "GET",
118
+ signal
119
+ });
120
+ }
121
+ function createApiKey(request, id, body) {
122
+ return request(`${organizationPath(id)}/api-keys`, {
123
+ method: "POST",
124
+ body
125
+ });
126
+ }
127
+ function revokeApiKey(request, id, keyId) {
128
+ return request(`${organizationPath(id)}/api-keys/${encodeURIComponent(keyId)}`, {
129
+ method: "DELETE"
130
+ });
131
+ }
132
+ function listAvailabilityAlerts(request, id, signal) {
133
+ return request(`${personPath(id)}/availability-alerts`, { method: "GET", signal });
134
+ }
135
+ function setAvailabilityAlert(request, id, alert) {
136
+ return request(`${personPath(id)}/availability-alerts/${encodeURIComponent(alert.gpu_slug)}/${encodeURIComponent(alert.sale_type)}`, { method: "PUT", body: { enabled: alert.enabled } });
137
+ }
138
+ var personAvatarPath = (id) => `${personPath(id)}/avatar`;
139
+ var organizationAvatarPath = (id) => `${organizationPath(id)}/avatar`;
140
+ function getPersonAvatar(fetcher, id) {
141
+ return fetcher(personAvatarPath(id), { method: "GET" });
142
+ }
143
+
144
+ // ../../packages/api-client/dist/authorization/invites.js
145
+ var invitePath = (id) => `/v1/invites/${encodeURIComponent(id)}`;
146
+ function listInvites(request, organizationId, signal) {
147
+ return request(withQuery("/v1/invites", { organization_id: organizationId }), {
148
+ method: "GET",
149
+ signal
150
+ });
151
+ }
152
+ function getInvite(request, id) {
153
+ return request(invitePath(id), { method: "GET" });
154
+ }
155
+ function createInvite(request, body) {
156
+ return request("/v1/invites", { method: "POST", body });
157
+ }
158
+ function revokeInvite(request, organizationId, id) {
159
+ return request(withQuery(invitePath(id), { organization_id: organizationId }), {
160
+ method: "DELETE"
161
+ });
162
+ }
163
+ function acceptInvite(request, id, body = {}) {
164
+ return request(`${invitePath(id)}/accept`, { method: "POST", body });
165
+ }
166
+
167
+ // ../../packages/api-client/dist/authorization/ssh-keys.js
168
+ function listSshKeys(request, id, query = {}, signal) {
169
+ return request(withQuery(`${organizationPath(id)}/ssh-keys`, query), {
170
+ method: "GET",
171
+ signal
172
+ });
173
+ }
174
+ async function listAllSshKeys(request, id, signal) {
175
+ const ssh_keys = [];
176
+ const seen = /* @__PURE__ */ new Set();
177
+ let cursor = null;
178
+ let has_revoked = false;
179
+ do {
180
+ const page = await listSshKeys(request, id, { status: "all", limit: 500, cursor }, signal);
181
+ ssh_keys.push(...page.ssh_keys);
182
+ has_revoked ||= page.has_revoked === true;
183
+ cursor = page.next_cursor ?? null;
184
+ if (cursor && seen.has(cursor))
185
+ throw new Error("SSH key pagination did not advance.");
186
+ if (cursor)
187
+ seen.add(cursor);
188
+ } while (cursor);
189
+ return { ssh_keys, next_cursor: null, has_revoked };
190
+ }
191
+ function createSshKey(request, id, body, query = {}) {
192
+ return request(withQuery(`${organizationPath(id)}/ssh-keys`, query), {
193
+ method: "POST",
194
+ body
195
+ });
196
+ }
197
+ function revokeSshKey(request, id, keyId, query = {}) {
198
+ return request(withQuery(`${organizationPath(id)}/ssh-keys/${encodeURIComponent(keyId)}`, query), { method: "DELETE" });
199
+ }
200
+
201
+ // ../../packages/api-client/dist/authorization/staff.js
202
+ var staffOrganizationPath = (id) => `/v1/staff/organizations/${encodeURIComponent(id)}`;
203
+ function searchStaffPeople(request, query, signal) {
204
+ return request(withQuery("/v1/staff/people", query), { method: "GET", signal });
205
+ }
206
+ function searchStaffOrganizations(request, query, signal) {
207
+ return request(withQuery("/v1/staff/organizations", query), {
208
+ method: "GET",
209
+ signal
210
+ });
211
+ }
212
+ function getStaffOrganization(request, id, signal) {
213
+ return request(staffOrganizationPath(id), {
214
+ method: "GET",
215
+ signal
216
+ });
217
+ }
218
+ function createStaffOrganization(request, body) {
219
+ return request("/v1/staff/organizations", {
220
+ method: "POST",
221
+ body
222
+ });
223
+ }
224
+ function listStaffOrganizationMembers(request, id, signal) {
225
+ return request(`${staffOrganizationPath(id)}/members`, { method: "GET", signal });
226
+ }
227
+ function addStaffOrganizationMember(request, id, body) {
228
+ return request(`${staffOrganizationPath(id)}/members`, {
229
+ method: "POST",
230
+ body
231
+ });
232
+ }
233
+ function removeStaffOrganizationMember(request, id, email) {
234
+ return request(`${staffOrganizationPath(id)}/members/${encodeURIComponent(email)}`, {
235
+ method: "DELETE"
236
+ });
237
+ }
238
+ function listStaffOrganizationInvites(request, id, signal) {
239
+ return request(`${staffOrganizationPath(id)}/invites`, { method: "GET", signal });
240
+ }
241
+ function revokeStaffOrganizationInvite(request, id, inviteId) {
242
+ return request(`${staffOrganizationPath(id)}/invites/${encodeURIComponent(inviteId)}`, {
243
+ method: "DELETE"
244
+ });
245
+ }
246
+ function createStaffInvite(request, body) {
247
+ return request("/v1/staff/invites", { method: "POST", body });
248
+ }
249
+ function updateOrganizationApproval(request, id, body) {
250
+ return request(`${organizationPath(id)}/approval`, { method: "POST", body });
251
+ }
252
+ function cancelOrganizationFollowUp(request, id) {
253
+ return request(`${organizationPath(id)}/follow-up/cancel`, {
254
+ method: "POST",
255
+ body: {}
256
+ });
257
+ }
258
+ function listSupplierApplications(request, query = {}, signal) {
259
+ return request(withQuery("/v1/supplier-applications", query), {
260
+ method: "GET",
261
+ signal
262
+ });
263
+ }
264
+ function updateSupplierApplication(request, id, body) {
265
+ return request(`/v1/supplier-applications/${encodeURIComponent(id)}`, {
266
+ method: "PATCH",
267
+ body
268
+ });
269
+ }
270
+ function approveSupplierApplicationFromSlack(fetcher, id, actorEmail) {
271
+ return fetcher(`/v1/staff/v1/supplier-applications/${encodeURIComponent(id)}`, {
272
+ method: "PATCH",
273
+ headers: { "Content-Type": "application/json" },
274
+ body: JSON.stringify({ approve_pending: true, actor_email: actorEmail })
275
+ });
276
+ }
277
+
278
+ // ../../packages/api-client/dist/authorization/onboarding.js
279
+ function submitOnboardingIntake(fetcher, body) {
280
+ return fetcher("/v1/onboarding/intake", {
281
+ method: "POST",
282
+ headers: { "Content-Type": "application/json" },
283
+ body: JSON.stringify(body)
284
+ });
285
+ }
286
+ function listOnboardingSlots(fetcher, id, query) {
287
+ return fetcher(withQuery(`${organizationPath(id)}/onboarding-booking/slots`, query), {
288
+ method: "GET"
289
+ });
290
+ }
291
+ function bookOnboardingCall(fetcher, id, body) {
292
+ return fetcher(`${organizationPath(id)}/onboarding-booking`, {
293
+ method: "POST",
294
+ headers: { "Content-Type": "application/json" },
295
+ body: JSON.stringify(body)
296
+ });
297
+ }
298
+ function cancelOnboardingCall(fetcher, id) {
299
+ return fetcher(`${organizationPath(id)}/onboarding-booking`, { method: "DELETE" });
300
+ }
301
+ function createSupplierApplication(fetcher, body, query = {}) {
302
+ return fetcher(withQuery("/v1/supplier-applications", query), {
303
+ method: "POST",
304
+ headers: { "Content-Type": "application/json" },
305
+ body: JSON.stringify(body)
306
+ });
307
+ }
308
+
309
+ // ../../packages/api-client/dist/authorization/sessions.js
310
+ var browserSessionPath = "/v1/auth/session";
311
+ var signInPath = "/v1/auth/sign-in";
312
+ var inviteRedeemPath = "/v1/auth/invites/redeem";
313
+ var unsubscribePath = "/v1/auth/unsubscribe";
314
+ var post = (body, signal) => ({
315
+ method: "POST",
316
+ headers: { "Content-Type": "application/json" },
317
+ body: JSON.stringify(body),
318
+ ...signal ? { signal } : {}
319
+ });
320
+ function getBrowserSession(fetcher, query = {}, options = {}) {
321
+ return fetcher(withQuery(browserSessionPath, query), { ...options, method: "GET" });
322
+ }
323
+ function signOutBrowserSession(fetcher, next) {
324
+ return fetcher(withQuery("/v1/auth/sign-out", { next }), post({}));
325
+ }
326
+ function changeEmail(fetcher, body) {
327
+ return fetcher("/v1/auth/change-email", post(body));
328
+ }
329
+ function authorizeStaff(fetcher, body, signal) {
330
+ return fetcher("/v1/authorize", post(body, signal));
331
+ }
332
+ function createSlackSession(fetcher, body, signal) {
333
+ return fetcher("/v1/slack/session", post(body, signal));
334
+ }
335
+ function startCliDeviceAuthorization(request) {
336
+ return request("/v1/cli/device/start", {
337
+ method: "POST",
338
+ body: {}
339
+ });
340
+ }
341
+ function pollCliDeviceAuthorization(request, body, signal) {
342
+ return request("/v1/cli/device/poll", { method: "POST", body, signal });
343
+ }
344
+ function approveCliDeviceAuthorization(fetcher, body) {
345
+ return fetcher("/v1/cli/device/approve", post(body));
346
+ }
347
+ function getCliSession(request) {
348
+ return request("/v1/cli/session", { method: "GET" });
349
+ }
350
+ function revokeCliSession(request) {
351
+ return request("/v1/cli/session", { method: "DELETE" });
352
+ }
353
+
354
+ // ../../packages/api-client/dist/authorization/mcp.js
355
+ function getMcpApplication(fetcher, clientId) {
356
+ return fetcher(`/v1/mcp/applications/${encodeURIComponent(clientId)}`, { method: "GET" });
357
+ }
358
+ function listMcpConnections(fetcher, userId) {
359
+ return fetcher(withQuery("/v1/mcp/connections", { user_id: userId }), { method: "GET" });
360
+ }
361
+ function revokeMcpConnection(fetcher, userId, clientId) {
362
+ return fetcher(withQuery(`/v1/mcp/connections/${encodeURIComponent(clientId)}`, { user_id: userId }), { method: "DELETE" });
363
+ }
364
+ function resolveMcpSession(fetcher, token) {
365
+ return fetcher("/v1/mcp/session", {
366
+ method: "POST",
367
+ headers: { "Content-Type": "application/json" },
368
+ body: JSON.stringify({ token })
369
+ });
370
+ }
371
+ function authorizeMcp(fetcher, body, signal) {
372
+ return fetcher("/v1/auth/mcp/authorize", {
373
+ method: "POST",
374
+ headers: { "Content-Type": "application/json" },
375
+ body: JSON.stringify(body),
376
+ signal
377
+ });
378
+ }
379
+ function consentMcp(fetcher, body, signal) {
380
+ return fetcher("/v1/auth/mcp/consent", {
381
+ method: "POST",
382
+ headers: { "Content-Type": "application/json" },
383
+ body: JSON.stringify(body),
384
+ signal
385
+ });
386
+ }
387
+
388
+ // ../../packages/api-client/dist/authorization/impersonation.js
389
+ function getActiveImpersonationGrant(fetcher, staffUserId) {
390
+ return fetcher(`/v1/impersonation/active/${encodeURIComponent(staffUserId)}`, { method: "GET" });
391
+ }
392
+ function deleteImpersonationGrant(fetcher, staffUserId) {
393
+ return fetcher(`/v1/impersonation/${encodeURIComponent(staffUserId)}`, { method: "DELETE" });
394
+ }
395
+ function listImpersonationCustomers(request, query = {}, signal) {
396
+ return request(withQuery("/v1/staff/impersonation/customers", query), {
397
+ method: "GET",
398
+ signal
399
+ });
400
+ }
401
+ function startStaffImpersonation(fetcher, body) {
402
+ return fetcher("/v1/staff/impersonation/start", {
403
+ method: "POST",
404
+ headers: { "Content-Type": "application/json" },
405
+ body: JSON.stringify(body)
406
+ });
407
+ }
408
+ function stopStaffImpersonation(fetcher) {
409
+ return fetcher("/v1/staff/impersonation/stop", { method: "POST" });
410
+ }
411
+ export {
412
+ acceptInvite,
413
+ addStaffOrganizationMember,
414
+ approveCliDeviceAuthorization,
415
+ approveSupplierApplicationFromSlack,
416
+ authorizeMcp,
417
+ authorizeStaff,
418
+ bookOnboardingCall,
419
+ browserSessionPath,
420
+ cancelOnboardingCall,
421
+ cancelOrganizationFollowUp,
422
+ changeEmail,
423
+ consentMcp,
424
+ countOrganizations,
425
+ createApiKey,
426
+ createInvite,
427
+ createOrganization,
428
+ createSlackSession,
429
+ createSshKey,
430
+ createStaffInvite,
431
+ createStaffOrganization,
432
+ createSupplierApplication,
433
+ deleteImpersonationGrant,
434
+ getActiveImpersonationGrant,
435
+ getBrowserSession,
436
+ getCliSession,
437
+ getInvite,
438
+ getMcpApplication,
439
+ getNotificationPreferences,
440
+ getOrganization,
441
+ getOrganizationMembership,
442
+ getPersonAvatar,
443
+ getStaffOrganization,
444
+ getUserPreferences,
445
+ getUserProfile,
446
+ inviteRedeemPath,
447
+ listAllSshKeys,
448
+ listApiKeys,
449
+ listAvailabilityAlerts,
450
+ listImpersonationCustomers,
451
+ listInvites,
452
+ listMcpConnections,
453
+ listOnboardingSlots,
454
+ listOrganizationMembers,
455
+ listOrganizations,
456
+ listOrganizationsByIds,
457
+ listOrganizationsForUser,
458
+ listSshKeys,
459
+ listStaffOrganizationInvites,
460
+ listStaffOrganizationMembers,
461
+ listSupplierApplications,
462
+ listSupplierOrganizations,
463
+ organizationAvatarPath,
464
+ personAvatarPath,
465
+ pollCliDeviceAuthorization,
466
+ removeOrganizationMember,
467
+ removeStaffOrganizationMember,
468
+ resolveMcpSession,
469
+ revokeApiKey,
470
+ revokeCliSession,
471
+ revokeInvite,
472
+ revokeMcpConnection,
473
+ revokeSshKey,
474
+ revokeStaffOrganizationInvite,
475
+ searchStaffOrganizations,
476
+ searchStaffPeople,
477
+ setAvailabilityAlert,
478
+ signInPath,
479
+ signOutBrowserSession,
480
+ startCliDeviceAuthorization,
481
+ startStaffImpersonation,
482
+ stopStaffImpersonation,
483
+ submitOnboardingIntake,
484
+ unsubscribePath,
485
+ updateNotificationPreferences,
486
+ updateOrganization,
487
+ updateOrganizationApproval,
488
+ updateSupplierApplication,
489
+ updateUserPreferences,
490
+ updateUserProfile
491
+ };
@@ -236,25 +236,55 @@ function ensureFacility(request, body2) {
236
236
  });
237
237
  }
238
238
 
239
- // ../../packages/capabilities/dist/supplier-directory.js
240
- async function listSupplierOrganizationPage(fetch, input) {
241
- const params = `role=supplier&limit=${input.limit}&offset=${input.offset}&sort=created_at&direction=asc` + (input.q?.trim() ? `&q=${encodeURIComponent(input.q.trim())}` : "");
242
- const page2 = await fetch(`/v1/organizations?${params}`, { method: "GET" });
243
- if (!Array.isArray(page2))
244
- throw new Error("Invalid supplier directory response.");
245
- return page2;
246
- }
247
- async function listSupplierOrganizations(fetch) {
239
+ // ../../packages/api-client/dist/authorization/paths.js
240
+ function withQuery(path, values) {
241
+ const query2 = new URLSearchParams();
242
+ for (const [key, value] of Object.entries(values)) {
243
+ if (value !== void 0 && value !== null && value !== "")
244
+ query2.set(key, Array.isArray(value) ? value.join(",") : String(value));
245
+ }
246
+ return query2.size ? `${path}?${query2}` : path;
247
+ }
248
+
249
+ // ../../packages/api-client/dist/authorization/organizations.js
250
+ function listOrganizations(request, query2 = {}, signal) {
251
+ return request(withQuery("/v1/organizations", query2), { method: "GET", signal });
252
+ }
253
+ async function listSupplierOrganizations(request, signal) {
248
254
  const rows = [];
249
255
  for (let offset = 0; offset < 5e4; offset += 1e3) {
250
- const page2 = await listSupplierOrganizationPage(fetch, { limit: 1e3, offset });
256
+ const page2 = await listOrganizations(request, { role: "supplier", limit: 1e3, offset, sort: "created_at", direction: "asc" }, signal);
257
+ if (!Array.isArray(page2))
258
+ throw new Error("Invalid supplier directory response.");
251
259
  rows.push(...page2);
252
260
  if (page2.length < 1e3)
253
261
  return rows;
254
262
  }
255
- throw new Error("Supplier directory exceeded 50 pages; refusing a partial catalog.");
263
+ throw new Error("The supplier directory is too large to load completely.");
264
+ }
265
+
266
+ // ../../packages/api-client/dist/authorization/staff.js
267
+ function createStaffInvite(request, body2) {
268
+ return request("/v1/staff/invites", { method: "POST", body: body2 });
256
269
  }
257
270
 
271
+ // ../../packages/api-client/dist/authorization/sessions.js
272
+ function getCliSession(request) {
273
+ return request("/v1/cli/session", { method: "GET" });
274
+ }
275
+
276
+ // ../../packages/capabilities/dist/supplier-directory.js
277
+ function listSupplierOrganizationPage(fetch, input) {
278
+ return listOrganizations(fetch, {
279
+ role: "supplier",
280
+ ...input,
281
+ q: input.q?.trim() || void 0,
282
+ sort: "created_at",
283
+ direction: "asc"
284
+ });
285
+ }
286
+ var listSupplierOrganizations2 = listSupplierOrganizations;
287
+
258
288
  // ../../packages/capabilities/dist/capabilities/fleet.js
259
289
  import { z as z2 } from "zod";
260
290
  function queryPath(path, params) {
@@ -311,7 +341,6 @@ var listSuppliersCapability = defineCapability({
311
341
  roles: ["admin"],
312
342
  description: "List supplier organizations (id, name). Resolve supplier names to organization_id with this before nodes.list or facilities.list. When next_offset is present, pass it back as offset for the next page.",
313
343
  mutation: "read",
314
- http: { method: "GET", path: "/v1/organizations" },
315
344
  slack: {
316
345
  parameters: {
317
346
  type: "object",
@@ -328,7 +357,7 @@ var listSuppliersCapability = defineCapability({
328
357
  const paged = parsed.limit !== void 0 || parsed.offset !== void 0 || parsed.q !== void 0;
329
358
  const limit = parsed.limit ?? 25;
330
359
  const offset = parsed.offset ?? 0;
331
- const rows = paged ? await listSupplierOrganizationPage(ctx.fetch, { ...parsed, limit, offset }) : await listSupplierOrganizations(ctx.fetch);
360
+ const rows = paged ? await listSupplierOrganizationPage(ctx.fetch, { ...parsed, limit, offset }) : await listSupplierOrganizations2(ctx.fetch);
332
361
  return {
333
362
  suppliers: rows.map((org) => ({ id: org.id, name: org.name })),
334
363
  ...paged && rows.length === limit ? { next_offset: offset + rows.length } : {}
@@ -997,19 +1026,6 @@ var usersListInput = z5.object({
997
1026
  limit: directoryLimit,
998
1027
  offset: directoryOffset
999
1028
  });
1000
- function directoryPath(input) {
1001
- const params = [`limit=${input.limit}`, `offset=${input.offset}`, "sort=name", "direction=asc"];
1002
- if (input.q)
1003
- params.push(`q=${encodeURIComponent(input.q)}`);
1004
- if (input.role)
1005
- params.push(`role=${encodeURIComponent(input.role)}`);
1006
- if (input.approved !== void 0) {
1007
- params.push(`approved=${input.approved}`);
1008
- }
1009
- if (input.ids)
1010
- params.push(`ids=${encodeURIComponent(input.ids.join(","))}`);
1011
- return `/v1/organizations?${params.join("&")}`;
1012
- }
1013
1029
  function directoryMembers(organization) {
1014
1030
  return organization.members ?? [];
1015
1031
  }
@@ -1027,7 +1043,6 @@ var organizationListCapability = defineCapability({
1027
1043
  roles: ["admin"],
1028
1044
  description: "List organizations from the Authorization directory. Search by company name, contact/member name, or email; filter by role, approval, or UUIDs. When next_offset is present, pass it back as offset for the next page. Use the organization id as organizationId when recording downtime, and ask the user to choose if matches are ambiguous.",
1029
1045
  mutation: "read",
1030
- http: { method: "GET", path: "/v1/organizations" },
1031
1046
  slack: {
1032
1047
  parameters: {
1033
1048
  type: "object",
@@ -1054,8 +1069,12 @@ var organizationListCapability = defineCapability({
1054
1069
  const parsed = organizationListInput.parse(input);
1055
1070
  const limit = parsed.limit;
1056
1071
  const offset = parsed.offset ?? 0;
1057
- const rows = await ctx.fetch(directoryPath({ ...parsed, limit, offset }), {
1058
- method: "GET"
1072
+ const rows = await listOrganizations(ctx.fetch, {
1073
+ ...parsed,
1074
+ limit,
1075
+ offset,
1076
+ sort: "name",
1077
+ direction: "asc"
1059
1078
  });
1060
1079
  return {
1061
1080
  organizations: rows.map((organization) => ({
@@ -1079,7 +1098,6 @@ var usersListCapability = defineCapability({
1079
1098
  roles: ["admin"],
1080
1099
  description: "List users who belong to an organization, from the Authorization directory. Search by person name, email, or company name; use organization_id to restrict results to one organization. When next_offset is present, pass it back as offset for the next page.",
1081
1100
  mutation: "read",
1082
- http: { method: "GET", path: "/v1/organizations" },
1083
1101
  slack: {
1084
1102
  parameters: {
1085
1103
  type: "object",
@@ -1102,12 +1120,14 @@ var usersListCapability = defineCapability({
1102
1120
  const parsed = usersListInput.parse(input);
1103
1121
  const limit = parsed.limit;
1104
1122
  const offset = parsed.offset ?? 0;
1105
- const rows = await ctx.fetch(directoryPath({
1123
+ const rows = await listOrganizations(ctx.fetch, {
1106
1124
  limit,
1107
1125
  offset,
1108
1126
  q: parsed.q,
1109
- ids: parsed.organization_id ? [parsed.organization_id] : void 0
1110
- }), { method: "GET" });
1127
+ ids: parsed.organization_id ? [parsed.organization_id] : void 0,
1128
+ sort: "name",
1129
+ direction: "asc"
1130
+ });
1111
1131
  const q = parsed.q?.toLowerCase();
1112
1132
  const users = rows.flatMap((organization) => {
1113
1133
  const members = directoryMembers(organization);
@@ -5094,7 +5114,7 @@ var whoamiCapability = defineCapability({
5094
5114
  mutation: "read",
5095
5115
  http: { method: "GET", path: "/v1/cli/session" },
5096
5116
  input: emptyInput3,
5097
- execute: async (ctx) => ctx.fetch("/v1/cli/session", { method: "GET" })
5117
+ execute: async (ctx) => getCliSession(ctx.fetch)
5098
5118
  });
5099
5119
  var statusCapability = defineCapability({
5100
5120
  id: "identity.status",
@@ -5349,7 +5369,7 @@ var createListingCapability = defineCapability({
5349
5369
  const supplierQuery = (parsed.site_supplier ?? "").trim().toLowerCase();
5350
5370
  const place = (parsed.site_nickname ?? parsed.site ?? "").trim();
5351
5371
  if (!organizationId && supplierQuery) {
5352
- const matches = (await listSupplierOrganizations(ctx.fetch)).filter((org) => org.id.toLowerCase() === supplierQuery || org.name.toLowerCase() === supplierQuery);
5372
+ const matches = (await listSupplierOrganizations2(ctx.fetch)).filter((org) => org.id.toLowerCase() === supplierQuery || org.name.toLowerCase() === supplierQuery);
5353
5373
  if (matches.length !== 1) {
5354
5374
  return { ok: false, error: matches.length ? "ambiguous_supplier" : "supplier_not_found" };
5355
5375
  }
@@ -5493,7 +5513,6 @@ var organizationInviteCapability = defineCapability({
5493
5513
  roles: ["admin"],
5494
5514
  description: "Invite a person to an existing organization (emails by default; send_email=false returns a join link), or omit organization_id to create a signup link with organization_role=consumer or supplier. Resolve organization UUIDs first; ask if ambiguous. Executes immediately. Keep invitation links secret.",
5495
5515
  mutation: "immediate",
5496
- http: { method: "POST", path: "/v1/staff/invites" },
5497
5516
  cli: {
5498
5517
  command: ["admin", "organizations", "invite"],
5499
5518
  vnext: {
@@ -5528,9 +5547,9 @@ var organizationInviteCapability = defineCapability({
5528
5547
  input: organizationInviteInput,
5529
5548
  execute: async (ctx, input) => {
5530
5549
  const parsed = organizationInviteInput.parse(input);
5531
- return ctx.fetch("/v1/staff/invites", {
5532
- method: "POST",
5533
- body: { ...parsed, send_email: parsed.send_email ?? parsed.organization_id !== void 0 }
5550
+ return createStaffInvite(ctx.fetch, {
5551
+ ...parsed,
5552
+ send_email: parsed.send_email ?? parsed.organization_id !== void 0
5534
5553
  });
5535
5554
  }
5536
5555
  });