@ornncompute/cli 1.0.75 → 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 +32 -5
- package/package.json +4 -2
- package/src/admin-capacity-reservations.mjs +4 -1
- package/src/admin-command-handlers.mjs +2 -0
- package/src/admin-node-diagnostics.mjs +1 -5
- package/src/admin-node-lifecycle.mjs +23 -125
- package/src/admin-node-sanitize.mjs +243 -0
- package/src/catalog-shell.mjs +6 -6
- package/src/evidence-commands.mjs +4 -6
- package/src/external-bucket-commands.mjs +71 -23
- package/src/interaction-runtime.mjs +3 -0
- package/src/kubernetes-commands.mjs +16 -83
- package/src/machine-reference.mjs +33 -56
- package/src/slurm-commands.mjs +13 -2
- package/src/vm-commands.mjs +39 -59
- 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 -322
- package/vendor/capabilities/capabilities/admin-node-diagnostics.js +0 -88
- package/vendor/capabilities/capabilities/admin-nodes-lifecycle.js +0 -137
- 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 -83
- package/vendor/capabilities/capabilities/evidence.js +0 -145
- package/vendor/capabilities/capabilities/external-buckets.js +0 -191
- package/vendor/capabilities/capabilities/fleet.js +0 -386
- 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 -253
- 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 -161
- package/vendor/capabilities/capabilities/users.js +0 -157
- 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
|
@@ -1,405 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { nativeTermsInput, nativeTermFields, listingWriteControls } from "./native-listing.js";
|
|
3
|
-
import { defineCapability, preview } from "../capability.js";
|
|
4
|
-
import { consent, idempotencyHeaders, microUsd, microUsdLabel, positionals, query, seg, } from "./market-shared.js";
|
|
5
|
-
// Commerce market verbs: one capability per role-aware `/commerce` route.
|
|
6
|
-
// Commerce decides from the caller's session what each listing or
|
|
7
|
-
// reservation reveals; these verbs return its JSON unchanged.
|
|
8
|
-
function help(command, outcome, human, automation, related, order, acceptedReferences = []) {
|
|
9
|
-
return {
|
|
10
|
-
arguments: "semantic",
|
|
11
|
-
audience: "customer",
|
|
12
|
-
category: "resource",
|
|
13
|
-
command,
|
|
14
|
-
outcome,
|
|
15
|
-
human,
|
|
16
|
-
automation,
|
|
17
|
-
acceptedReferences,
|
|
18
|
-
related,
|
|
19
|
-
order,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
const pageLimit = z.coerce.number().int().min(1).max(200).optional();
|
|
23
|
-
export const listingsListInput = z.object({
|
|
24
|
-
$positionals: positionals,
|
|
25
|
-
kind: z.enum(["primary", "secondary", "on_demand"]).optional(),
|
|
26
|
-
state: z.enum(["draft", "available", "held", "sold", "delisted"]).optional(),
|
|
27
|
-
sourceReservationId: z.string().uuid().optional(),
|
|
28
|
-
sourceListingId: z.string().uuid().optional(),
|
|
29
|
-
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
30
|
-
cursor: z.string().min(1).optional(),
|
|
31
|
-
});
|
|
32
|
-
export const listingsListCapability = defineCapability({
|
|
33
|
-
id: "listings.list",
|
|
34
|
-
domain: "listings",
|
|
35
|
-
roles: ["user"],
|
|
36
|
-
description: "List native capacity listings. Primary listings require organization approval. Returns capacityListingId, hardware, capacity and availability; when nextCursor is present, pass it back as cursor for the next page. Read listings.terms separately for prices and durations.",
|
|
37
|
-
mutation: "read",
|
|
38
|
-
http: { method: "GET", path: "/commerce/v2/listings" },
|
|
39
|
-
input: listingsListInput,
|
|
40
|
-
cli: {
|
|
41
|
-
command: ["capacity-offers", "list"],
|
|
42
|
-
vnext: help(["capacity-offers", "list"], "List capacity parents with bounded pagination; read their financial terms separately.", "ornn capacity-offers list [--kind primary|secondary|on_demand] [--source-reservation-id <id>] [--limit <1-100>] [--cursor <opaque>]", "ornn capacity-offers list --limit 50 --format json", ["capacity-offers show", "capacity-offers terms", "capacity-offers availability"], 20, ["opaque page cursor"]),
|
|
43
|
-
},
|
|
44
|
-
slack: false,
|
|
45
|
-
execute: async (ctx, input) => {
|
|
46
|
-
const parsed = listingsListInput.parse(input ?? {});
|
|
47
|
-
return ctx.fetch(`/commerce/v2/listings${query({
|
|
48
|
-
kind: parsed.kind,
|
|
49
|
-
state: parsed.state,
|
|
50
|
-
sourceReservationId: parsed.sourceReservationId,
|
|
51
|
-
sourceListingId: parsed.sourceListingId,
|
|
52
|
-
limit: parsed.limit,
|
|
53
|
-
cursor: parsed.cursor,
|
|
54
|
-
})}`, { method: "GET" });
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
export const listingShowInput = z.object({
|
|
58
|
-
$positionals: positionals,
|
|
59
|
-
listingId: z.string().uuid(),
|
|
60
|
-
});
|
|
61
|
-
export const listingShowCapability = defineCapability({
|
|
62
|
-
id: "listings.show",
|
|
63
|
-
domain: "listings",
|
|
64
|
-
roles: ["user"],
|
|
65
|
-
description: "Show one native capacity listing. Returns capacityListingId, hardware, capacity and availability; use listings.terms for financial choices.",
|
|
66
|
-
mutation: "read",
|
|
67
|
-
http: { method: "GET", path: "/commerce/v2/listings/{listingId}" },
|
|
68
|
-
input: listingShowInput,
|
|
69
|
-
cli: {
|
|
70
|
-
command: ["capacity-offers", "show"],
|
|
71
|
-
vnext: help(["capacity-offers", "show"], "Inspect one listing's hardware, capacity and availability.", "ornn capacity-offers show --listing-id <id>", "ornn capacity-offers show --listing-id <id> --format json", ["capacity-offers list", "capacity-offers terms", "capacity-offers availability"], 21, ["listing ID"]),
|
|
72
|
-
},
|
|
73
|
-
slack: false,
|
|
74
|
-
execute: async (ctx, input) => {
|
|
75
|
-
const parsed = listingShowInput.parse(input);
|
|
76
|
-
return ctx.fetch(`/commerce/v2/listings/${seg(parsed.listingId)}`, { method: "GET" });
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
export const listingTermsCapability = defineCapability({
|
|
80
|
-
id: "listings.terms",
|
|
81
|
-
domain: "listings",
|
|
82
|
-
roles: ["user"],
|
|
83
|
-
description: "Read a capacity listing's advertised financial terms. Each term returns listingTermsId, capacityListingId, pricePerGpuHourMicroUsd, duration bounds, downPaymentCents and renewable. Use the parent's capacityListingId as listingId. Prices are gross integer micro-USD per GPU-hour, the price reservations.purchase expects.",
|
|
84
|
-
mutation: "read",
|
|
85
|
-
http: { method: "GET", path: "/commerce/v2/listings/{listingId}/terms" },
|
|
86
|
-
input: listingShowInput,
|
|
87
|
-
cli: {
|
|
88
|
-
command: ["capacity-offers", "terms"],
|
|
89
|
-
vnext: help(["capacity-offers", "terms"], "Read the advertised financial terms for a capacity listing.", "ornn capacity-offers terms --listing-id <id>", "ornn capacity-offers terms --listing-id <id> --format json", ["capacity-offers show", "offers post", "reservations buy"], 22, ["capacityListingId from capacity-offers list or show"]),
|
|
90
|
-
},
|
|
91
|
-
slack: false,
|
|
92
|
-
execute: async (ctx, input) => {
|
|
93
|
-
const parsed = listingShowInput.parse(input);
|
|
94
|
-
return ctx.fetch(`/commerce/v2/listings/${seg(parsed.listingId)}/terms`, { method: "GET" });
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
export const listingAvailabilityInput = z.object({
|
|
98
|
-
$positionals: positionals,
|
|
99
|
-
listingId: z.string().uuid(),
|
|
100
|
-
from: z.iso
|
|
101
|
-
.datetime({ offset: true })
|
|
102
|
-
.optional()
|
|
103
|
-
.describe("RFC 3339 start of the range to read. Defaults to now or the listing's start."),
|
|
104
|
-
to: z.iso
|
|
105
|
-
.datetime({ offset: true })
|
|
106
|
-
.optional()
|
|
107
|
-
.describe("RFC 3339 end of the range to read. Defaults to the listing's end."),
|
|
108
|
-
});
|
|
109
|
-
export const listingAvailabilityCapability = defineCapability({
|
|
110
|
-
id: "listings.availability",
|
|
111
|
-
domain: "listings",
|
|
112
|
-
roles: ["user"],
|
|
113
|
-
description: "Read how much of a capacity listing is free to book over time: windows of startsAt, endsAt, gpus and nodes (the nodes with any GPU free) from now until the listing ends (for an open-ended listing, 30 days ahead for a Market listing and far enough for any term of a Reserve listing), optionally narrowed by from and to. Use the parent's capacityListingId as listingId.",
|
|
114
|
-
mutation: "read",
|
|
115
|
-
http: { method: "GET", path: "/v1/markets/listings/{listingId}/availability" },
|
|
116
|
-
input: listingAvailabilityInput,
|
|
117
|
-
cli: {
|
|
118
|
-
command: ["capacity-offers", "availability"],
|
|
119
|
-
vnext: help(["capacity-offers", "availability"], "Show how many of a listing's nodes are free over time.", "ornn capacity-offers availability --listing-id <id> [--from <time>] [--to <time>]", "ornn capacity-offers availability --listing-id <id> --format json", ["capacity-offers terms", "reservations buy", "offers post"], 23, ["capacityListingId from capacity-offers list or show"]),
|
|
120
|
-
},
|
|
121
|
-
slack: false,
|
|
122
|
-
execute: async (ctx, input) => {
|
|
123
|
-
const parsed = listingAvailabilityInput.parse(input);
|
|
124
|
-
return ctx.fetch(`/v1/markets/listings/${seg(parsed.listingId)}/availability${query({
|
|
125
|
-
from: parsed.from,
|
|
126
|
-
to: parsed.to,
|
|
127
|
-
})}`, { method: "GET" });
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
export const listingRelistInput = z.strictObject({
|
|
131
|
-
$positionals: positionals,
|
|
132
|
-
reservationId: z.string().uuid(),
|
|
133
|
-
startsAt: z.iso.datetime({ offset: true }),
|
|
134
|
-
endsAt: z.iso.datetime({ offset: true }),
|
|
135
|
-
nodeCount: z.coerce.number().int().positive(),
|
|
136
|
-
terms: nativeTermsInput,
|
|
137
|
-
idempotencyKey: z.string().min(1).max(200).optional(),
|
|
138
|
-
confirm: z.boolean().optional(),
|
|
139
|
-
yes: z.boolean().optional(),
|
|
140
|
-
});
|
|
141
|
-
export const listingRelistCapability = defineCapability({
|
|
142
|
-
id: "listings.relist",
|
|
143
|
-
domain: "listings",
|
|
144
|
-
roles: ["user"],
|
|
145
|
-
description: "Relist whole nodes of a reservation's capacity using a native availability window, nodeCount and financial terms. Buyers run on nodes Ornn assigns when their rental starts..",
|
|
146
|
-
mutation: "preview-confirm",
|
|
147
|
-
http: { method: "POST", path: "/commerce/reservations/{reservationId}/relist" },
|
|
148
|
-
input: listingRelistInput,
|
|
149
|
-
cli: {
|
|
150
|
-
command: ["capacity-offers", "relist"],
|
|
151
|
-
vnext: help(["capacity-offers", "relist"], "Relist reserved capacity with explicit financial terms.", "ornn capacity-offers relist --reservation-id UUID --node-count COUNT --starts-at TIME --ends-at TIME --terms JSON", "ornn capacity-offers relist --reservation-id UUID --node-count 1 --starts-at TIME --ends-at TIME --terms JSON --idempotency-key KEY --format json", ["capacity-offers terms", "capacity-offers delist"], 24, ["reservation ID"]),
|
|
152
|
-
},
|
|
153
|
-
slack: false,
|
|
154
|
-
execute: async (ctx, input) => {
|
|
155
|
-
const { $positionals: _, reservationId, confirm: _confirm, yes: _yes, idempotencyKey, ...body } = listingRelistInput.parse(input);
|
|
156
|
-
const gate = await consent(ctx, "listings.relist", "Relist capacity", [
|
|
157
|
-
{ label: "Reservation", value: reservationId },
|
|
158
|
-
{ label: "Capacity and financial terms", value: JSON.stringify(body) },
|
|
159
|
-
], { reservationId, ...body });
|
|
160
|
-
if (gate)
|
|
161
|
-
return gate;
|
|
162
|
-
return ctx.fetch(`/commerce/reservations/${seg(reservationId)}/relist`, {
|
|
163
|
-
method: "POST",
|
|
164
|
-
body,
|
|
165
|
-
headers: idempotencyHeaders(ctx, idempotencyKey),
|
|
166
|
-
});
|
|
167
|
-
},
|
|
168
|
-
});
|
|
169
|
-
export const listingUpdateInput = z
|
|
170
|
-
.object({
|
|
171
|
-
$positionals: positionals,
|
|
172
|
-
listingId: z.string().uuid(),
|
|
173
|
-
listingTermsId: z.string().uuid(),
|
|
174
|
-
...nativeTermFields,
|
|
175
|
-
...listingWriteControls,
|
|
176
|
-
})
|
|
177
|
-
.strict();
|
|
178
|
-
export const listingUpdateCapability = defineCapability({
|
|
179
|
-
id: "listings.update",
|
|
180
|
-
domain: "listings",
|
|
181
|
-
roles: ["admin"],
|
|
182
|
-
description: "Staff only: edit one advertised native financial term with its complete financial fields. Reuse idempotencyKey on retries..",
|
|
183
|
-
mutation: "preview-confirm",
|
|
184
|
-
http: { method: "PATCH", path: "/commerce/v2/listings/{listingId}/terms/{listingTermsId}" },
|
|
185
|
-
input: listingUpdateInput,
|
|
186
|
-
cli: {
|
|
187
|
-
command: ["admin", "capacity-offers", "update"],
|
|
188
|
-
vnext: {
|
|
189
|
-
...help(["admin", "capacity-offers", "update"], "Edit one advertised financial term as staff.", "ornn admin capacity-offers update --listing-id UUID --listing-terms-id UUID --min-duration-hours HOURS --max-duration-hours HOURS --price-per-gpu-hour-micro-usd RATE --renewable true|false --idempotency-key KEY [--type reserved|spot|on-demand] [--down-payment-cents CENTS]", "Requires an eligible human terminal; reuse --idempotency-key on retries.", ["capacity-offers terms"], 25),
|
|
190
|
-
audience: "admin",
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
slack: false,
|
|
194
|
-
mcp: false,
|
|
195
|
-
execute: async (ctx, input) => {
|
|
196
|
-
const { $positionals: _, listingId, listingTermsId, confirm: _confirm, idempotencyKey, ...body } = listingUpdateInput.parse(input);
|
|
197
|
-
if (!ctx.confirmed)
|
|
198
|
-
return preview("listings.update", { listingId, listingTermsId, ...body });
|
|
199
|
-
return ctx.fetch(`/commerce/v2/listings/${seg(listingId)}/terms/${seg(listingTermsId)}`, {
|
|
200
|
-
method: "PATCH",
|
|
201
|
-
body,
|
|
202
|
-
headers: idempotencyHeaders(ctx, idempotencyKey),
|
|
203
|
-
});
|
|
204
|
-
},
|
|
205
|
-
});
|
|
206
|
-
export const listingDelistInput = z.object({
|
|
207
|
-
$positionals: positionals,
|
|
208
|
-
listingId: z.string().uuid(),
|
|
209
|
-
confirm: z.boolean().optional(),
|
|
210
|
-
});
|
|
211
|
-
export const listingDelistCapability = defineCapability({
|
|
212
|
-
id: "listings.delist",
|
|
213
|
-
domain: "listings",
|
|
214
|
-
roles: ["user"],
|
|
215
|
-
description: "Delist a listing you own. Its unsold time leaves the market, its spot asks are cancelled and running spot reservations on it end. Windows already bought stay sold..",
|
|
216
|
-
mutation: "preview-confirm",
|
|
217
|
-
http: { method: "POST", path: "/commerce/v2/listings/{listingId}/delist" },
|
|
218
|
-
input: listingDelistInput,
|
|
219
|
-
cli: {
|
|
220
|
-
command: ["capacity-offers", "delist"],
|
|
221
|
-
vnext: help(["capacity-offers", "delist"], "Delist a listing you relisted.", "ornn capacity-offers delist --listing-id <id>", "ornn capacity-offers delist --listing-id <id> --format json", ["capacity-offers relist"], 26, ["listing ID"]),
|
|
222
|
-
},
|
|
223
|
-
slack: false,
|
|
224
|
-
execute: async (ctx, input) => {
|
|
225
|
-
const parsed = listingDelistInput.parse(input);
|
|
226
|
-
const gate = await consent(ctx, "listings.delist", "Delist listing", [
|
|
227
|
-
{ label: "Listing", value: parsed.listingId },
|
|
228
|
-
{
|
|
229
|
-
label: "Consequence",
|
|
230
|
-
value: "Unsold time and spot asks leave the market; running spot reservations on it end.",
|
|
231
|
-
},
|
|
232
|
-
], { listingId: parsed.listingId });
|
|
233
|
-
if (gate)
|
|
234
|
-
return gate;
|
|
235
|
-
return ctx.fetch(`/commerce/v2/listings/${seg(parsed.listingId)}/delist`, { method: "POST" });
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
export const reservationsListInput = z.object({
|
|
239
|
-
$positionals: positionals,
|
|
240
|
-
kind: z.enum(["schedule", "spot"]).optional(),
|
|
241
|
-
status: z
|
|
242
|
-
.enum([
|
|
243
|
-
"awaiting_down_payment",
|
|
244
|
-
"awaiting_payment",
|
|
245
|
-
"confirmed",
|
|
246
|
-
"active",
|
|
247
|
-
"completed",
|
|
248
|
-
"cancelled",
|
|
249
|
-
])
|
|
250
|
-
.optional(),
|
|
251
|
-
listingId: z.string().uuid().optional().describe("Trades on a listing you own."),
|
|
252
|
-
limit: pageLimit,
|
|
253
|
-
cursor: z.string().min(1).optional(),
|
|
254
|
-
});
|
|
255
|
-
export const reservationsListCapability = defineCapability({
|
|
256
|
-
id: "reservations.list",
|
|
257
|
-
domain: "reservations",
|
|
258
|
-
roles: ["user"],
|
|
259
|
-
description: "List this organization's reservations, schedule and spot alike (a running spot reservation has no end time). With listingId, list the trades on a listing you own. When nextCursor is present, pass it back as cursor for the next page.",
|
|
260
|
-
mutation: "read",
|
|
261
|
-
http: { method: "GET", path: "/commerce/reservations" },
|
|
262
|
-
input: reservationsListInput,
|
|
263
|
-
cli: {
|
|
264
|
-
command: ["reservations", "list"],
|
|
265
|
-
vnext: help(["reservations", "list"], "List your organization's schedule and spot reservations.", "ornn reservations list [--kind schedule|spot] [--status <status>] [--listing-id <id>] [--limit <1-200>] [--cursor <opaque>]", "ornn reservations list --format json", ["reservations show", "capacity-offers relist"], 27, ["opaque page cursor"]),
|
|
266
|
-
},
|
|
267
|
-
slack: false,
|
|
268
|
-
execute: async (ctx, input) => {
|
|
269
|
-
const parsed = reservationsListInput.parse(input ?? {});
|
|
270
|
-
return ctx.fetch(`/commerce/reservations${query({
|
|
271
|
-
kind: parsed.kind,
|
|
272
|
-
status: parsed.status,
|
|
273
|
-
listingId: parsed.listingId,
|
|
274
|
-
limit: parsed.limit,
|
|
275
|
-
cursor: parsed.cursor,
|
|
276
|
-
})}`, { method: "GET" });
|
|
277
|
-
},
|
|
278
|
-
});
|
|
279
|
-
export const reservationLookupInput = z.object({
|
|
280
|
-
$positionals: positionals,
|
|
281
|
-
reservationId: z.string().uuid(),
|
|
282
|
-
});
|
|
283
|
-
export const reservationsShowCapability = defineCapability({
|
|
284
|
-
id: "reservations.show",
|
|
285
|
-
domain: "reservations",
|
|
286
|
-
roles: ["user"],
|
|
287
|
-
description: "Show one reservation: kind, status, window, price and node count.",
|
|
288
|
-
mutation: "read",
|
|
289
|
-
http: { method: "GET", path: "/commerce/reservations/{reservationId}" },
|
|
290
|
-
input: reservationLookupInput,
|
|
291
|
-
cli: {
|
|
292
|
-
command: ["reservations", "show"],
|
|
293
|
-
vnext: help(["reservations", "show"], "Inspect one reservation.", "ornn reservations show --reservation-id <id>", "ornn reservations show --reservation-id <id> --format json", ["reservations list", "reservations invoices"], 28, ["reservation ID"]),
|
|
294
|
-
},
|
|
295
|
-
slack: false,
|
|
296
|
-
execute: async (ctx, input) => {
|
|
297
|
-
const parsed = reservationLookupInput.parse(input);
|
|
298
|
-
return ctx.fetch(`/commerce/reservations/${seg(parsed.reservationId)}`, { method: "GET" });
|
|
299
|
-
},
|
|
300
|
-
});
|
|
301
|
-
export const reservationInvoicesCapability = defineCapability({
|
|
302
|
-
id: "reservations.invoices",
|
|
303
|
-
domain: "billing",
|
|
304
|
-
roles: ["user"],
|
|
305
|
-
description: "List a reservation's invoices: the down payment and each billing period, with status and amount in cents.",
|
|
306
|
-
mutation: "read",
|
|
307
|
-
http: { method: "GET", path: "/commerce/reservations/{reservationId}/invoices" },
|
|
308
|
-
input: reservationLookupInput,
|
|
309
|
-
cli: {
|
|
310
|
-
command: ["reservations", "invoices"],
|
|
311
|
-
vnext: help(["reservations", "invoices"], "List one reservation's invoices.", "ornn reservations invoices --reservation-id <id>", "ornn reservations invoices --reservation-id <id> --format json", ["reservations show"], 29, ["reservation ID"]),
|
|
312
|
-
},
|
|
313
|
-
slack: false,
|
|
314
|
-
execute: async (ctx, input) => {
|
|
315
|
-
const parsed = reservationLookupInput.parse(input);
|
|
316
|
-
return ctx.fetch(`/commerce/reservations/${seg(parsed.reservationId)}/invoices`, {
|
|
317
|
-
method: "GET",
|
|
318
|
-
});
|
|
319
|
-
},
|
|
320
|
-
});
|
|
321
|
-
export const reservationPurchaseInput = z.object({
|
|
322
|
-
$positionals: positionals,
|
|
323
|
-
listingId: z
|
|
324
|
-
.string()
|
|
325
|
-
.uuid()
|
|
326
|
-
.describe("The relisted (secondary) listing's capacityListingId, from listings.list."),
|
|
327
|
-
listingTermId: z
|
|
328
|
-
.string()
|
|
329
|
-
.uuid()
|
|
330
|
-
.describe("The listingTermsId of the listing's term, from listings.terms."),
|
|
331
|
-
nodeCount: z.coerce
|
|
332
|
-
.number()
|
|
333
|
-
.int()
|
|
334
|
-
.positive()
|
|
335
|
-
.optional()
|
|
336
|
-
.describe("Whole nodes to book for the window. Defaults to every node the listing sells."),
|
|
337
|
-
startsAt: z.iso
|
|
338
|
-
.datetime({ offset: true })
|
|
339
|
-
.describe("RFC 3339 start of the window, in whole seconds, inside the listing and not in the past."),
|
|
340
|
-
endsAt: z.iso
|
|
341
|
-
.datetime({ offset: true })
|
|
342
|
-
.describe("RFC 3339 end of the window, at least an hour after the start and within the term's duration range, or at the listing's end."),
|
|
343
|
-
pricePerGpuHourMicroUsd: microUsd.describe("The term's price from listings.terms, in micro-USD per GPU-hour. A changed price refuses the purchase."),
|
|
344
|
-
idempotencyKey: z.string().min(1).max(200).optional(),
|
|
345
|
-
confirm: z.boolean().optional(),
|
|
346
|
-
});
|
|
347
|
-
export const reservationPurchaseCapability = defineCapability({
|
|
348
|
-
id: "reservations.purchase",
|
|
349
|
-
domain: "reservations",
|
|
350
|
-
roles: ["user"],
|
|
351
|
-
description: "Book a window of a relisted (secondary) listing on one of its terms at the term's price. The GPUs are held for you until the window starts; then it becomes your reservation, with the booking's ID. Nothing is charged when you book. Primary listings take offers instead (offers.post)..",
|
|
352
|
-
mutation: "preview-confirm",
|
|
353
|
-
http: { method: "POST", path: "/v1/markets/bookings" },
|
|
354
|
-
input: reservationPurchaseInput,
|
|
355
|
-
cli: {
|
|
356
|
-
command: ["reservations", "buy"],
|
|
357
|
-
vnext: help(["reservations", "buy"], "Book a window of relisted capacity at its term's price.", "ornn reservations buy --listing-id <id> --listing-term-id <id> --starts-at <time> --ends-at <time> --price-per-gpu-hour-micro-usd <n> [--node-count <n>]", "ornn reservations buy --listing-id <id> --listing-term-id <id> --starts-at <time> --ends-at <time> --price-per-gpu-hour-micro-usd 4000000 --idempotency-key <key> --format json", ["capacity-offers availability", "capacity-offers terms", "reservations show"], 30, ["listingTermsId from capacity-offers terms"]),
|
|
358
|
-
},
|
|
359
|
-
slack: false,
|
|
360
|
-
execute: async (ctx, input) => {
|
|
361
|
-
const parsed = reservationPurchaseInput.parse(input);
|
|
362
|
-
const body = {
|
|
363
|
-
legs: [
|
|
364
|
-
{
|
|
365
|
-
listingId: parsed.listingId,
|
|
366
|
-
listingTermId: parsed.listingTermId,
|
|
367
|
-
...(parsed.nodeCount !== undefined ? { nodes: parsed.nodeCount } : {}),
|
|
368
|
-
startsAt: parsed.startsAt,
|
|
369
|
-
endsAt: parsed.endsAt,
|
|
370
|
-
pricePerGpuHourMicroUsd: parsed.pricePerGpuHourMicroUsd,
|
|
371
|
-
},
|
|
372
|
-
],
|
|
373
|
-
};
|
|
374
|
-
const gate = await consent(ctx, "reservations.purchase", "Book relisted window", [
|
|
375
|
-
{ label: "Listing term", value: parsed.listingTermId },
|
|
376
|
-
{
|
|
377
|
-
label: "Nodes",
|
|
378
|
-
value: parsed.nodeCount !== undefined ? String(parsed.nodeCount) : "Every node on the listing",
|
|
379
|
-
},
|
|
380
|
-
{ label: "Window", value: `${parsed.startsAt} to ${parsed.endsAt}` },
|
|
381
|
-
{ label: "Price", value: microUsdLabel(parsed.pricePerGpuHourMicroUsd) },
|
|
382
|
-
{ label: "Payment", value: "Nothing is charged when you book." },
|
|
383
|
-
], body);
|
|
384
|
-
if (gate)
|
|
385
|
-
return gate;
|
|
386
|
-
return ctx.fetch("/v1/markets/bookings", {
|
|
387
|
-
method: "POST",
|
|
388
|
-
body,
|
|
389
|
-
headers: idempotencyHeaders(ctx, parsed.idempotencyKey),
|
|
390
|
-
});
|
|
391
|
-
},
|
|
392
|
-
});
|
|
393
|
-
export const commerceMarketCapabilities = [
|
|
394
|
-
listingsListCapability,
|
|
395
|
-
listingShowCapability,
|
|
396
|
-
listingTermsCapability,
|
|
397
|
-
listingAvailabilityCapability,
|
|
398
|
-
listingRelistCapability,
|
|
399
|
-
listingUpdateCapability,
|
|
400
|
-
listingDelistCapability,
|
|
401
|
-
reservationsListCapability,
|
|
402
|
-
reservationsShowCapability,
|
|
403
|
-
reservationInvoicesCapability,
|
|
404
|
-
reservationPurchaseCapability,
|
|
405
|
-
];
|