@nodetool-ai/deploy 0.7.0-rc.23 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +41 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/admin-client.d.ts +5 -39
  4. package/dist/admin-client.d.ts.map +1 -1
  5. package/dist/admin-client.js +9 -230
  6. package/dist/admin-client.js.map +1 -1
  7. package/dist/api-user-manager.d.ts.map +1 -1
  8. package/dist/api-user-manager.js +5 -2
  9. package/dist/api-user-manager.js.map +1 -1
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +0 -3
  12. package/dist/auth.js.map +1 -1
  13. package/dist/compose.d.ts.map +1 -1
  14. package/dist/compose.js +5 -6
  15. package/dist/compose.js.map +1 -1
  16. package/dist/configure.d.ts +1 -43
  17. package/dist/configure.d.ts.map +1 -1
  18. package/dist/configure.js +2 -43
  19. package/dist/configure.js.map +1 -1
  20. package/dist/deployment-config.d.ts +28 -786
  21. package/dist/deployment-config.d.ts.map +1 -1
  22. package/dist/deployment-config.js +34 -218
  23. package/dist/deployment-config.js.map +1 -1
  24. package/dist/docker-run.d.ts +2 -1
  25. package/dist/docker-run.d.ts.map +1 -1
  26. package/dist/docker-run.js +6 -22
  27. package/dist/docker-run.js.map +1 -1
  28. package/dist/docker.d.ts +6 -21
  29. package/dist/docker.d.ts.map +1 -1
  30. package/dist/docker.js +6 -53
  31. package/dist/docker.js.map +1 -1
  32. package/dist/image-spec.d.ts +1 -1
  33. package/dist/index.d.ts +0 -14
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/manager.d.ts.map +1 -1
  38. package/dist/manager.js +0 -44
  39. package/dist/manager.js.map +1 -1
  40. package/dist/progress.d.ts.map +1 -1
  41. package/dist/progress.js +0 -1
  42. package/dist/progress.js.map +1 -1
  43. package/dist/remote-users.d.ts.map +1 -1
  44. package/dist/remote-users.js +1 -4
  45. package/dist/remote-users.js.map +1 -1
  46. package/dist/runpod-rest.d.ts +114 -0
  47. package/dist/runpod-rest.d.ts.map +1 -0
  48. package/dist/runpod-rest.js +150 -0
  49. package/dist/runpod-rest.js.map +1 -0
  50. package/dist/self-hosted.d.ts +17 -43
  51. package/dist/self-hosted.d.ts.map +1 -1
  52. package/dist/self-hosted.js +50 -124
  53. package/dist/self-hosted.js.map +1 -1
  54. package/dist/ssh.d.ts +9 -0
  55. package/dist/ssh.d.ts.map +1 -1
  56. package/dist/ssh.js +1 -5
  57. package/dist/ssh.js.map +1 -1
  58. package/dist/state.d.ts.map +1 -1
  59. package/dist/state.js +1 -11
  60. package/dist/state.js.map +1 -1
  61. package/dist/workflow-syncer.d.ts +3 -32
  62. package/dist/workflow-syncer.d.ts.map +1 -1
  63. package/dist/workflow-syncer.js +3 -162
  64. package/dist/workflow-syncer.js.map +1 -1
  65. package/package.json +29 -14
  66. package/dist/admin-operations.d.ts +0 -197
  67. package/dist/admin-operations.d.ts.map +0 -1
  68. package/dist/admin-operations.js +0 -433
  69. package/dist/admin-operations.js.map +0 -1
  70. package/dist/admin-routes.d.ts +0 -306
  71. package/dist/admin-routes.d.ts.map +0 -1
  72. package/dist/admin-routes.js +0 -383
  73. package/dist/admin-routes.js.map +0 -1
  74. package/dist/collection-routes.d.ts +0 -37
  75. package/dist/collection-routes.d.ts.map +0 -1
  76. package/dist/collection-routes.js +0 -43
  77. package/dist/collection-routes.js.map +0 -1
  78. package/dist/deploy-to-gcp.d.ts +0 -67
  79. package/dist/deploy-to-gcp.d.ts.map +0 -1
  80. package/dist/deploy-to-gcp.js +0 -268
  81. package/dist/deploy-to-gcp.js.map +0 -1
  82. package/dist/deploy-to-runpod.d.ts +0 -53
  83. package/dist/deploy-to-runpod.d.ts.map +0 -1
  84. package/dist/deploy-to-runpod.js +0 -207
  85. package/dist/deploy-to-runpod.js.map +0 -1
  86. package/dist/fly.d.ts +0 -40
  87. package/dist/fly.d.ts.map +0 -1
  88. package/dist/fly.js +0 -291
  89. package/dist/fly.js.map +0 -1
  90. package/dist/gcp.d.ts +0 -59
  91. package/dist/gcp.d.ts.map +0 -1
  92. package/dist/gcp.js +0 -339
  93. package/dist/gcp.js.map +0 -1
  94. package/dist/google-cloud-run-api.d.ts +0 -134
  95. package/dist/google-cloud-run-api.d.ts.map +0 -1
  96. package/dist/google-cloud-run-api.js +0 -532
  97. package/dist/google-cloud-run-api.js.map +0 -1
  98. package/dist/huggingface.d.ts +0 -69
  99. package/dist/huggingface.d.ts.map +0 -1
  100. package/dist/huggingface.js +0 -346
  101. package/dist/huggingface.js.map +0 -1
  102. package/dist/railway.d.ts +0 -65
  103. package/dist/railway.d.ts.map +0 -1
  104. package/dist/railway.js +0 -284
  105. package/dist/railway.js.map +0 -1
  106. package/dist/runpod-api.d.ts +0 -206
  107. package/dist/runpod-api.d.ts.map +0 -1
  108. package/dist/runpod-api.js +0 -703
  109. package/dist/runpod-api.js.map +0 -1
  110. package/dist/runpod.d.ts +0 -82
  111. package/dist/runpod.d.ts.map +0 -1
  112. package/dist/runpod.js +0 -188
  113. package/dist/runpod.js.map +0 -1
  114. package/dist/storage-routes.d.ts +0 -55
  115. package/dist/storage-routes.d.ts.map +0 -1
  116. package/dist/storage-routes.js +0 -160
  117. package/dist/storage-routes.js.map +0 -1
  118. package/dist/sync.d.ts +0 -38
  119. package/dist/sync.d.ts.map +0 -1
  120. package/dist/sync.js +0 -130
  121. package/dist/sync.js.map +0 -1
@@ -1,703 +0,0 @@
1
- /**
2
- * RunPod API Module
3
- *
4
- * Provides a clean interface to RunPod's REST and GraphQL APIs for managing
5
- * templates and endpoints. Handles authentication, request/response processing,
6
- * and error handling for all RunPod operations.
7
- *
8
- * Key Features:
9
- * - Template management (create, update, delete, get)
10
- * - Endpoint management (create, update, delete)
11
- * - Network volume management
12
- * - GraphQL query support
13
- * - Proper error handling and logging
14
- */
15
- const RUNPOD_REST_BASE_URL = "https://rest.runpod.io/v1";
16
- /** Escape a string for safe interpolation inside a GraphQL quoted string. */
17
- function gqlEscape(s) {
18
- return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
19
- }
20
- const HTTP_STATUS_UNAUTHORIZED = 401;
21
- const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36";
22
- // ---------------------------------------------------------------------------
23
- // Enums
24
- // ---------------------------------------------------------------------------
25
- /** GPU types available in RunPod using their official GPU ID codes. */
26
- export var GPUType;
27
- (function (GPUType) {
28
- // Ada Lovelace Architecture
29
- GPUType["ADA_24"] = "ADA_24";
30
- GPUType["ADA_32_PRO"] = "ADA_32_PRO";
31
- GPUType["ADA_48_PRO"] = "ADA_48_PRO";
32
- GPUType["ADA_80_PRO"] = "ADA_80_PRO";
33
- // Ampere Architecture
34
- GPUType["AMPERE_16"] = "AMPERE_16";
35
- GPUType["AMPERE_24"] = "AMPERE_24";
36
- GPUType["AMPERE_48"] = "AMPERE_48";
37
- GPUType["AMPERE_80"] = "AMPERE_80";
38
- // Hopper Architecture
39
- GPUType["HOPPER_141"] = "HOPPER_141";
40
- })(GPUType || (GPUType = {}));
41
- /** Compute types for RunPod endpoints. */
42
- export var ComputeType;
43
- (function (ComputeType) {
44
- ComputeType["CPU"] = "CPU";
45
- ComputeType["GPU"] = "GPU";
46
- })(ComputeType || (ComputeType = {}));
47
- /** CPU flavor IDs for RunPod endpoints. */
48
- export var CPUFlavor;
49
- (function (CPUFlavor) {
50
- CPUFlavor["CPU_3C"] = "cpu3c";
51
- CPUFlavor["CPU_3G"] = "cpu3g";
52
- CPUFlavor["CPU_5C"] = "cpu5c";
53
- CPUFlavor["CPU_5G"] = "cpu5g";
54
- })(CPUFlavor || (CPUFlavor = {}));
55
- /** Data center locations for RunPod endpoints. */
56
- export var DataCenter;
57
- (function (DataCenter) {
58
- // United States
59
- DataCenter["US_CALIFORNIA_2"] = "US-CA-2";
60
- DataCenter["US_DELAWARE_1"] = "US-DE-1";
61
- DataCenter["US_GEORGIA_1"] = "US-GA-1";
62
- DataCenter["US_GEORGIA_2"] = "US-GA-2";
63
- DataCenter["US_ILLINOIS_1"] = "US-IL-1";
64
- DataCenter["US_KANSAS_2"] = "US-KS-2";
65
- DataCenter["US_KANSAS_3"] = "US-KS-3";
66
- DataCenter["US_NORTH_CAROLINA_1"] = "US-NC-1";
67
- DataCenter["US_TEXAS_1"] = "US-TX-1";
68
- DataCenter["US_TEXAS_3"] = "US-TX-3";
69
- DataCenter["US_TEXAS_4"] = "US-TX-4";
70
- DataCenter["US_WASHINGTON_1"] = "US-WA-1";
71
- // Canada
72
- DataCenter["CA_MONTREAL_1"] = "CA-MTL-1";
73
- DataCenter["CA_MONTREAL_2"] = "CA-MTL-2";
74
- DataCenter["CA_MONTREAL_3"] = "CA-MTL-3";
75
- // Europe
76
- DataCenter["EU_CZECH_REPUBLIC_1"] = "EU-CZ-1";
77
- DataCenter["EU_FRANCE_1"] = "EU-FR-1";
78
- DataCenter["EU_NETHERLANDS_1"] = "EU-NL-1";
79
- DataCenter["EU_ROMANIA_1"] = "EU-RO-1";
80
- DataCenter["EU_SWEDEN_1"] = "EU-SE-1";
81
- // Europe Extended
82
- DataCenter["EUR_ICELAND_1"] = "EUR-IS-1";
83
- DataCenter["EUR_ICELAND_2"] = "EUR-IS-2";
84
- DataCenter["EUR_ICELAND_3"] = "EUR-IS-3";
85
- DataCenter["EUR_NORWAY_1"] = "EUR-NO-1";
86
- // Asia-Pacific
87
- DataCenter["AP_JAPAN_1"] = "AP-JP-1";
88
- // Oceania
89
- DataCenter["OC_AUSTRALIA_1"] = "OC-AU-1";
90
- })(DataCenter || (DataCenter = {}));
91
- /** CUDA versions available in RunPod. */
92
- export var CUDAVersion;
93
- (function (CUDAVersion) {
94
- CUDAVersion["CUDA_11_8"] = "11.8";
95
- CUDAVersion["CUDA_12_0"] = "12.0";
96
- CUDAVersion["CUDA_12_1"] = "12.1";
97
- CUDAVersion["CUDA_12_2"] = "12.2";
98
- CUDAVersion["CUDA_12_3"] = "12.3";
99
- CUDAVersion["CUDA_12_4"] = "12.4";
100
- CUDAVersion["CUDA_12_5"] = "12.5";
101
- CUDAVersion["CUDA_12_6"] = "12.6";
102
- CUDAVersion["CUDA_12_7"] = "12.7";
103
- CUDAVersion["CUDA_12_8"] = "12.8";
104
- })(CUDAVersion || (CUDAVersion = {}));
105
- // ---------------------------------------------------------------------------
106
- // Helpers
107
- // ---------------------------------------------------------------------------
108
- /** Return all values of a string enum. */
109
- export function enumValues(e) {
110
- return Object.values(e);
111
- }
112
- /** Print available options for an enum. */
113
- export function printEnumOptions(enumObj, title) {
114
- console.log(`\n${title}:`);
115
- for (const value of Object.values(enumObj)) {
116
- console.log(` ${value}`);
117
- }
118
- }
119
- // ---------------------------------------------------------------------------
120
- // Shared helpers
121
- // ---------------------------------------------------------------------------
122
- function getApiKey() {
123
- const key = process.env.RUNPOD_API_KEY;
124
- if (!key) {
125
- throw new Error("RUNPOD_API_KEY environment variable is not set");
126
- }
127
- return key;
128
- }
129
- /**
130
- * Run a GraphQL query against the RunPod API.
131
- */
132
- export async function runGraphqlQuery(query) {
133
- const apiUrlBase = process.env.RUNPOD_API_BASE_URL ?? "https://api.runpod.io";
134
- const url = `${apiUrlBase}/graphql`;
135
- const apiKey = getApiKey();
136
- const response = await fetch(url, {
137
- method: "POST",
138
- headers: {
139
- "Content-Type": "application/json",
140
- "User-Agent": USER_AGENT,
141
- Authorization: `Bearer ${apiKey}`
142
- },
143
- body: JSON.stringify({ query }),
144
- signal: AbortSignal.timeout(30_000)
145
- });
146
- if (response.status === HTTP_STATUS_UNAUTHORIZED) {
147
- throw new Error("Unauthorized request, please check your API key.");
148
- }
149
- const json = (await response.json());
150
- if (json.errors && json.errors.length > 0) {
151
- throw new Error(json.errors[0].message);
152
- }
153
- return json;
154
- }
155
- /**
156
- * Make a REST API call to RunPod.
157
- *
158
- * @param endpoint - The API endpoint (e.g., "endpoints", "templates")
159
- * @param method - HTTP method
160
- * @param data - Request body for POST/PUT/PATCH
161
- * @returns API response data, or empty object for DELETE 204 responses
162
- */
163
- export async function makeRunpodApiCall(endpoint, method = "GET", data) {
164
- const url = `${RUNPOD_REST_BASE_URL}/${endpoint}`;
165
- const apiKey = getApiKey();
166
- const headers = {
167
- Authorization: `Bearer ${apiKey}`,
168
- "Content-Type": "application/json",
169
- "User-Agent": USER_AGENT,
170
- Accept: "*/*",
171
- "Accept-Language": "en-US,en;q=0.9"
172
- };
173
- const init = {
174
- method,
175
- headers,
176
- signal: AbortSignal.timeout(60_000)
177
- };
178
- if (data && (method === "POST" || method === "PUT" || method === "PATCH")) {
179
- init.body = JSON.stringify(data);
180
- }
181
- let response;
182
- try {
183
- response = await fetch(url, init);
184
- }
185
- catch (err) {
186
- console.error("RunPod API call failed:", err);
187
- throw err;
188
- }
189
- if (!response.ok) {
190
- const body = await response.text().catch(() => "");
191
- console.error(`RunPod API call failed: ${response.status}`);
192
- if (body) {
193
- console.error("Response body:", body);
194
- }
195
- throw new Error(`RunPod API ${method} ${endpoint} failed with status ${response.status}: ${body}`);
196
- }
197
- // DELETE 204 may have no body
198
- if (method === "DELETE" && response.status === 204) {
199
- return {};
200
- }
201
- const text = await response.text();
202
- if (!text) {
203
- return {};
204
- }
205
- return JSON.parse(text);
206
- }
207
- // ---------------------------------------------------------------------------
208
- // Network Volume Management
209
- // ---------------------------------------------------------------------------
210
- /**
211
- * Create a new network volume.
212
- */
213
- export async function createNetworkVolume(name, size, dataCenterId) {
214
- return makeRunpodApiCall("networkvolumes", "POST", {
215
- dataCenterId,
216
- name,
217
- size
218
- });
219
- }
220
- /**
221
- * List all network volumes.
222
- */
223
- export async function listNetworkVolumes() {
224
- return makeRunpodApiCall("networkvolumes", "GET");
225
- }
226
- /**
227
- * Get details of a specific network volume.
228
- */
229
- export async function getNetworkVolume(volumeId) {
230
- return makeRunpodApiCall(`networkvolumes/${volumeId}`, "GET");
231
- }
232
- /**
233
- * Update a network volume.
234
- */
235
- export async function updateNetworkVolume(volumeId, name, size) {
236
- const data = {};
237
- if (name != null)
238
- data.name = name;
239
- if (size != null)
240
- data.size = size;
241
- return makeRunpodApiCall(`networkvolumes/${volumeId}`, "PATCH", data);
242
- }
243
- // ---------------------------------------------------------------------------
244
- // Template Management
245
- // ---------------------------------------------------------------------------
246
- /**
247
- * Get a RunPod template by name.
248
- */
249
- export async function getRunpodTemplateByName(templateName) {
250
- try {
251
- const result = await makeRunpodApiCall("templates", "GET");
252
- const templates = Array.isArray(result)
253
- ? result
254
- : (result.templates ?? []);
255
- for (const tpl of templates) {
256
- if (tpl.name === templateName) {
257
- return tpl;
258
- }
259
- }
260
- return null;
261
- }
262
- catch (err) {
263
- console.error(`Error fetching template '${templateName}':`, err);
264
- return null;
265
- }
266
- }
267
- /**
268
- * Delete a RunPod template by name.
269
- */
270
- export async function deleteRunpodTemplateByName(templateName) {
271
- try {
272
- const template = await getRunpodTemplateByName(templateName);
273
- if (!template) {
274
- console.log(`Template '${templateName}' not found (may not exist)`);
275
- return true;
276
- }
277
- const templateId = template.id;
278
- await makeRunpodApiCall(`templates/${templateId}`, "DELETE");
279
- console.log(`Template '${templateName}' (ID: ${templateId}) deleted successfully`);
280
- return true;
281
- }
282
- catch (err) {
283
- console.error(`Error deleting template '${templateName}':`, err);
284
- return false;
285
- }
286
- }
287
- /**
288
- * Update an existing RunPod template with a new Docker image.
289
- */
290
- export async function updateRunpodTemplate(templateData, imageName, tag) {
291
- try {
292
- const templateId = templateData.id;
293
- const env = templateData.env ?? {};
294
- env.PORT = "8000";
295
- env.PORT_HEALTH = "8000";
296
- const updateData = {
297
- containerDiskInGb: templateData.containerDiskInGb ?? 20,
298
- imageName: `${imageName}:${tag}`,
299
- name: templateData.name,
300
- ports: templateData.ports ?? ["8000/http"],
301
- volumeInGb: templateData.volumeInGb ?? 0,
302
- volumeMountPath: templateData.volumeMountPath ?? "/workspace",
303
- isPublic: templateData.isPublic ?? false,
304
- env
305
- };
306
- if (templateData.dockerEntrypoint) {
307
- updateData.dockerEntrypoint = templateData.dockerEntrypoint;
308
- }
309
- if (templateData.dockerStartCmd) {
310
- updateData.dockerStartCmd = templateData.dockerStartCmd;
311
- }
312
- if (templateData.readme) {
313
- updateData.readme = templateData.readme;
314
- }
315
- console.log("Updating template with data:");
316
- console.log(JSON.stringify(updateData, null, 2));
317
- await makeRunpodApiCall(`templates/${templateId}`, "PATCH", updateData);
318
- console.log(`Template '${templateData.name}' updated with image: ${imageName}:${tag}`);
319
- return true;
320
- }
321
- catch (err) {
322
- console.error("Error updating template:", err);
323
- return false;
324
- }
325
- }
326
- /**
327
- * Create or update a RunPod template with the latest Docker image.
328
- *
329
- * Checks if a template with the given name exists:
330
- * - If it exists, updates it with the new Docker image
331
- * - If it doesn't exist, creates a new template
332
- *
333
- * @returns The template ID
334
- */
335
- export async function createOrUpdateRunpodTemplate(templateName, imageName, tag, env) {
336
- const envVars = env ?? {};
337
- console.log(`Checking for existing template: ${templateName}`);
338
- const existing = await getRunpodTemplateByName(templateName);
339
- if (existing) {
340
- const templateId = existing.id;
341
- console.log(`Found existing template (ID: ${templateId})`);
342
- console.log(`Current image: ${existing.imageName ?? "unknown"}`);
343
- console.log(`Updating with new image: ${imageName}:${tag}`);
344
- if (await updateRunpodTemplate(existing, imageName, tag)) {
345
- console.log(`Template '${templateName}' updated successfully`);
346
- return templateId;
347
- }
348
- throw new Error(`Failed to update template '${templateName}'`);
349
- }
350
- // Create new template
351
- console.log(`Template not found, creating new template: ${templateName}`);
352
- const templateData = {
353
- containerDiskInGb: 20,
354
- imageName: `${imageName}:${tag}`,
355
- name: templateName,
356
- ports: ["8000/http", "22/ssh"],
357
- volumeInGb: 0,
358
- volumeMountPath: "/workspace",
359
- isPublic: false,
360
- env: envVars
361
- };
362
- console.log("Creating template with data:");
363
- console.log(JSON.stringify(templateData, null, 2));
364
- const result = await makeRunpodApiCall("templates", "POST", templateData);
365
- const templateId = result.id;
366
- if (!templateId) {
367
- console.error("Error: No template ID returned");
368
- console.error(`Response data: ${JSON.stringify(result, null, 2)}`);
369
- throw new Error("No template ID returned from RunPod API");
370
- }
371
- console.log(`Template created successfully: ${templateId}`);
372
- return templateId;
373
- }
374
- // ---------------------------------------------------------------------------
375
- // Endpoint Management
376
- // ---------------------------------------------------------------------------
377
- /**
378
- * Get a RunPod endpoint by name.
379
- */
380
- export async function getRunpodEndpointByName(endpointName, quiet = false) {
381
- const endpointsResponse = await makeRunpodApiCall("endpoints", "GET");
382
- const endpoints = Array.isArray(endpointsResponse)
383
- ? endpointsResponse
384
- : (endpointsResponse.endpoints ?? []);
385
- if (!quiet) {
386
- console.log(`Looking for endpoint: '${endpointName}'`);
387
- console.log(`Found ${endpoints.length} total endpoints`);
388
- }
389
- if (endpoints.length > 0 && !quiet) {
390
- console.log("Available endpoints:");
391
- endpoints.forEach((ep, i) => {
392
- const name = ep.name ?? "<no name>";
393
- const id = ep.id ?? "<no id>";
394
- console.log(` [${i + 1}] Name: '${name}' (ID: ${id})`);
395
- });
396
- }
397
- // Exact match first
398
- const exact = endpoints.find((ep) => ep.name === endpointName);
399
- if (exact) {
400
- if (!quiet) {
401
- console.log(`Found exact match for endpoint: '${endpointName}'`);
402
- }
403
- return exact;
404
- }
405
- // Prefix match fallback
406
- for (const ep of endpoints) {
407
- const name = ep.name ?? "";
408
- if (name.startsWith(endpointName)) {
409
- if (!quiet) {
410
- console.log(`Found prefix match for endpoint: '${endpointName}' -> '${name}'`);
411
- }
412
- return ep;
413
- }
414
- }
415
- if (!quiet) {
416
- console.log(`No endpoint found with name: '${endpointName}'`);
417
- }
418
- return null;
419
- }
420
- /**
421
- * Update an existing RunPod endpoint with a new template.
422
- */
423
- export async function updateRunpodEndpoint(endpointId, templateId, extra) {
424
- try {
425
- const updateData = {
426
- templateId,
427
- ...extra
428
- };
429
- // Remove undefined values
430
- for (const key of Object.keys(updateData)) {
431
- if (updateData[key] === undefined) {
432
- delete updateData[key];
433
- }
434
- }
435
- console.log(`Updating endpoint ${endpointId} with template ${templateId}`);
436
- await makeRunpodApiCall(`endpoints/${endpointId}`, "PATCH", updateData);
437
- console.log(`Endpoint '${endpointId}' updated successfully with template: ${templateId}`);
438
- return true;
439
- }
440
- catch (err) {
441
- console.error(`Error updating endpoint '${endpointId}':`, err);
442
- return false;
443
- }
444
- }
445
- /**
446
- * Delete a RunPod endpoint by name.
447
- */
448
- export async function deleteRunpodEndpointByName(endpointName) {
449
- try {
450
- const result = await makeRunpodApiCall("endpoints", "GET");
451
- const endpoints = result.endpoints ?? [];
452
- let endpointId;
453
- console.log(`Looking for endpoint to delete: '${endpointName}'`);
454
- console.log(`Found ${endpoints.length} total endpoints`);
455
- // Exact match
456
- for (const ep of endpoints) {
457
- if (ep.name === endpointName) {
458
- endpointId = ep.id;
459
- console.log(`Found exact match for deletion: '${endpointName}' (ID: ${endpointId})`);
460
- break;
461
- }
462
- }
463
- // Case-insensitive fallback
464
- if (!endpointId) {
465
- for (const ep of endpoints) {
466
- const name = (ep.name ?? "").toLowerCase();
467
- if (name === endpointName.toLowerCase()) {
468
- endpointId = ep.id;
469
- console.log(`Found case-insensitive match for deletion: '${endpointName}' -> '${ep.name}' (ID: ${endpointId})`);
470
- break;
471
- }
472
- }
473
- }
474
- if (!endpointId) {
475
- console.log(`Endpoint '${endpointName}' not found (may not exist)`);
476
- return true;
477
- }
478
- await makeRunpodApiCall(`endpoints/${endpointId}`, "DELETE");
479
- console.log(`Endpoint '${endpointName}' (ID: ${endpointId}) deleted successfully`);
480
- return true;
481
- }
482
- catch (err) {
483
- console.error(`Error deleting endpoint '${endpointName}':`, err);
484
- return false;
485
- }
486
- }
487
- /**
488
- * Create or update a RunPod serverless endpoint using the REST API.
489
- *
490
- * If an endpoint with the same name already exists, it will be updated
491
- * with the new template. Otherwise a new endpoint is created.
492
- *
493
- * @returns The endpoint ID
494
- */
495
- export async function createOrUpdateRunpodEndpoint(opts) {
496
- const { templateId, name, computeType = ComputeType.GPU, gpuCount, cpuFlavorIds, vcpuCount, workersMin = 0, workersMax = 3, idleTimeout = 5, executionTimeoutMs, flashboot = false, networkVolumeId, allowedCudaVersions } = opts;
497
- let gpuTypeIds = opts.gpuTypeIds;
498
- let dataCenterIds = opts.dataCenterIds ?? undefined;
499
- // Handle network volume and data center coordination
500
- if (networkVolumeId) {
501
- console.log(`Network volume specified: ${networkVolumeId}`);
502
- const volumeInfo = await getNetworkVolume(networkVolumeId);
503
- const volumeDataCenter = volumeInfo.dataCenterId;
504
- if (volumeDataCenter) {
505
- console.log(`Network volume is in data center: ${volumeDataCenter}`);
506
- dataCenterIds = [volumeDataCenter];
507
- console.log(`Endpoint will be deployed to same region: ${volumeDataCenter}`);
508
- }
509
- }
510
- if (gpuTypeIds == null && computeType === ComputeType.GPU) {
511
- gpuTypeIds = ["NVIDIA GeForce RTX 4090"];
512
- }
513
- if (dataCenterIds == null) {
514
- dataCenterIds = [];
515
- }
516
- // Check if endpoint already exists
517
- console.log(`Checking for existing endpoint: ${name}`);
518
- const existingEndpoint = await getRunpodEndpointByName(name);
519
- if (existingEndpoint) {
520
- const endpointId = existingEndpoint.id;
521
- console.log(`Found existing endpoint (ID: ${endpointId})`);
522
- console.log(`Current template: ${existingEndpoint.templateId ?? "unknown"}`);
523
- console.log(`Updating with new template: ${templateId}`);
524
- if (await updateRunpodEndpoint(endpointId, templateId)) {
525
- console.log(`Endpoint '${name}' updated successfully`);
526
- return endpointId;
527
- }
528
- console.log(`Failed to update endpoint '${name}', creating new one...`);
529
- await deleteRunpodEndpointByName(name);
530
- }
531
- console.log(`Creating new endpoint: ${name}`);
532
- console.log(` Compute type: ${computeType}`);
533
- if (computeType === ComputeType.GPU) {
534
- console.log(` GPU types: ${JSON.stringify(gpuTypeIds)}`);
535
- if (gpuCount)
536
- console.log(` GPU count: ${gpuCount}`);
537
- }
538
- else {
539
- console.log(` CPU flavors: ${JSON.stringify(cpuFlavorIds)}`);
540
- if (vcpuCount)
541
- console.log(` vCPU count: ${vcpuCount}`);
542
- }
543
- console.log(` Data centers: ${dataCenterIds.length > 0 ? JSON.stringify(dataCenterIds) : "Auto-selected"}`);
544
- console.log(` Workers: ${workersMin}-${workersMax}`);
545
- const endpointData = {
546
- computeType,
547
- templateId,
548
- name,
549
- workersMin,
550
- workersMax,
551
- scalerType: "REQUEST_COUNT",
552
- scalerValue: 4,
553
- idleTimeout,
554
- flashboot
555
- };
556
- if (computeType === ComputeType.GPU) {
557
- endpointData.gpuTypeIds = gpuTypeIds ?? ["NVIDIA GeForce RTX 4090"];
558
- endpointData.gpuCount = gpuCount ?? 1;
559
- }
560
- else {
561
- endpointData.cpuFlavorIds = cpuFlavorIds ?? ["cpu3c"];
562
- if (vcpuCount)
563
- endpointData.vcpuCount = vcpuCount;
564
- }
565
- if (allowedCudaVersions && allowedCudaVersions.length > 0) {
566
- endpointData.allowedCudaVersions = allowedCudaVersions;
567
- }
568
- if (dataCenterIds.length > 0) {
569
- endpointData.dataCenterIds = dataCenterIds;
570
- }
571
- if (executionTimeoutMs) {
572
- endpointData.executionTimeoutMs = executionTimeoutMs;
573
- }
574
- if (networkVolumeId) {
575
- endpointData.networkVolumeId = networkVolumeId;
576
- }
577
- console.log("\nCreating endpoint with data:");
578
- console.log(JSON.stringify(endpointData, null, 2));
579
- const result = await makeRunpodApiCall("endpoints", "POST", endpointData);
580
- const endpointId = result.id;
581
- if (!endpointId) {
582
- console.error("Error: No endpoint ID returned");
583
- console.error(`Response data: ${JSON.stringify(result, null, 2)}`);
584
- throw new Error("No endpoint ID returned from RunPod API");
585
- }
586
- console.log("\nEndpoint created successfully!");
587
- console.log(` ID: ${endpointId}`);
588
- console.log(` Name: ${result.name ?? name}`);
589
- console.log(` GPU Configuration: ${JSON.stringify(result.gpuTypeIds)}`);
590
- console.log(` Workers: ${result.workersMin}-${result.workersMax}`);
591
- return endpointId;
592
- }
593
- /**
594
- * Create a RunPod serverless endpoint using raw GraphQL queries.
595
- *
596
- * If an endpoint with the same name already exists, it will be deleted first.
597
- *
598
- * @returns The endpoint ID
599
- */
600
- export async function createRunpodEndpointGraphql(opts) {
601
- const { templateId, name, computeType = ComputeType.GPU, gpuTypeIds, gpuCount, vcpuCount, workersMin = 0, workersMax = 3, idleTimeout = 5, executionTimeoutMs, flashboot = false, networkVolumeId } = opts;
602
- const dataCenterIds = opts.dataCenterIds ?? [];
603
- // Ensure API key
604
- getApiKey();
605
- // Delete existing endpoint if it exists
606
- console.log(`Checking for existing endpoint: ${name}`);
607
- if (await deleteRunpodEndpointByName(name)) {
608
- console.log(`Existing endpoint '${name}' deleted successfully`);
609
- }
610
- else {
611
- console.log(`Note: Endpoint '${name}' may not have existed`);
612
- }
613
- console.log(`Creating new endpoint: ${name}`);
614
- console.log(` Compute type: ${computeType}`);
615
- console.log(` GPU types: ${JSON.stringify(gpuTypeIds)}`);
616
- console.log(` GPU count: ${gpuCount}`);
617
- console.log(` Data centers: ${dataCenterIds.length > 0 ? JSON.stringify(dataCenterIds) : "Auto-selected"}`);
618
- console.log(` Workers: ${workersMin}-${workersMax}`);
619
- console.log(` Idle timeout: ${idleTimeout}s`);
620
- console.log(` Execution timeout: ${executionTimeoutMs}ms`);
621
- console.log(` Flashboot: ${flashboot}`);
622
- console.log(` Network volume: ${networkVolumeId}`);
623
- const gpuIdsStr = gpuTypeIds ? gpuTypeIds.join(",") : "AMPERE_24";
624
- // Build mutation parts
625
- const endpointName = flashboot ? `${name}-fb` : name;
626
- const mutationParts = [];
627
- mutationParts.push(`name: "${gqlEscape(endpointName)}"`);
628
- mutationParts.push(`templateId: "${gqlEscape(templateId)}"`);
629
- mutationParts.push('type: "LB"');
630
- mutationParts.push(`workersMin: ${workersMin}`);
631
- mutationParts.push(`workersMax: ${workersMax}`);
632
- mutationParts.push(`idleTimeout: ${idleTimeout}`);
633
- mutationParts.push('scalerType: "REQUEST_COUNT"');
634
- mutationParts.push("scalerValue: 4");
635
- mutationParts.push(`executionTimeoutMs: ${executionTimeoutMs ?? 300000}`);
636
- mutationParts.push(`gpuIds: "${gqlEscape(gpuIdsStr)}"`);
637
- mutationParts.push(`gpuCount: ${gpuCount ?? 1}`);
638
- if (vcpuCount) {
639
- mutationParts.push(`vcpuCount: ${vcpuCount}`);
640
- }
641
- if (dataCenterIds.length > 0) {
642
- mutationParts.push(`locations: ${JSON.stringify(dataCenterIds.map(gqlEscape))}`);
643
- }
644
- else {
645
- mutationParts.push("locations: null");
646
- }
647
- if (networkVolumeId) {
648
- mutationParts.push(`networkVolumeId: "${gqlEscape(networkVolumeId)}"`);
649
- }
650
- else {
651
- mutationParts.push("networkVolumeId: null");
652
- }
653
- const mutation = `
654
- mutation {
655
- saveEndpoint(input: {
656
- ${mutationParts.join(", ")}
657
- }) {
658
- id
659
- name
660
- gpuIds
661
- idleTimeout
662
- locations
663
- type
664
- networkVolumeId
665
- executionTimeoutMs
666
- scalerType
667
- scalerValue
668
- templateId
669
- userId
670
- workersMax
671
- workersMin
672
- gpuCount
673
- __typename
674
- }
675
- }
676
- `;
677
- console.log("\nExecuting GraphQL mutation:");
678
- console.log(mutation);
679
- const result = await runGraphqlQuery(mutation);
680
- if (result.errors) {
681
- const errors = result.errors;
682
- const msg = errors[0]?.message ?? "Unknown error";
683
- console.error(`Error creating endpoint: ${msg}`);
684
- console.error(`Full error response: ${JSON.stringify(result, null, 2)}`);
685
- throw new Error(`Failed to create RunPod endpoint: ${msg}`);
686
- }
687
- const data = result.data ?? {};
688
- const endpointData = data.saveEndpoint ?? {};
689
- const endpointId = endpointData.id;
690
- if (!endpointId) {
691
- console.error("Error: No endpoint ID returned");
692
- console.error(`Response data: ${JSON.stringify(result, null, 2)}`);
693
- throw new Error("No endpoint ID returned from RunPod GraphQL API");
694
- }
695
- console.log("\nEndpoint created successfully!");
696
- console.log(` ID: ${endpointId}`);
697
- console.log(` Name: ${endpointData.name}`);
698
- console.log(` GPU Configuration: ${endpointData.gpuIds}`);
699
- console.log(` Workers: ${endpointData.workersMin}-${endpointData.workersMax}`);
700
- console.log(` Scaler: ${endpointData.scalerType}`);
701
- return endpointId;
702
- }
703
- //# sourceMappingURL=runpod-api.js.map