@swarm-agent/sdk 0.1.47

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 (74) hide show
  1. package/APPLICATIONS.md +133 -0
  2. package/HEADLESS_UI.md +97 -0
  3. package/LICENSE +201 -0
  4. package/README.md +473 -0
  5. package/dist/app-results.d.ts +24 -0
  6. package/dist/app-results.js +167 -0
  7. package/dist/apps.d.ts +82 -0
  8. package/dist/apps.js +89 -0
  9. package/dist/auth.d.ts +45 -0
  10. package/dist/auth.js +89 -0
  11. package/dist/automations.d.ts +74 -0
  12. package/dist/automations.js +159 -0
  13. package/dist/client.d.ts +61 -0
  14. package/dist/client.js +103 -0
  15. package/dist/deliverables.d.ts +42 -0
  16. package/dist/deliverables.js +83 -0
  17. package/dist/deploy/dockerfile.d.ts +14 -0
  18. package/dist/deploy/dockerfile.js +14 -0
  19. package/dist/deploy/index.d.ts +67 -0
  20. package/dist/deploy/index.js +226 -0
  21. package/dist/deploy/manifest.d.ts +17 -0
  22. package/dist/deploy/manifest.js +220 -0
  23. package/dist/deploy/providers/gcp-cloud-run.d.ts +9 -0
  24. package/dist/deploy/providers/gcp-cloud-run.js +12 -0
  25. package/dist/deploy/providers/gcp-compute.d.ts +9 -0
  26. package/dist/deploy/providers/gcp-compute.js +12 -0
  27. package/dist/deploy/types.d.ts +211 -0
  28. package/dist/deploy/types.js +4 -0
  29. package/dist/deploy/worker-cloud-deployer.d.ts +33 -0
  30. package/dist/deploy/worker-cloud-deployer.js +14 -0
  31. package/dist/errors.d.ts +36 -0
  32. package/dist/errors.js +68 -0
  33. package/dist/index.d.ts +23 -0
  34. package/dist/index.js +20 -0
  35. package/dist/notifications.d.ts +28 -0
  36. package/dist/notifications.js +65 -0
  37. package/dist/projects.d.ts +147 -0
  38. package/dist/projects.js +513 -0
  39. package/dist/provider-auth.d.ts +160 -0
  40. package/dist/provider-auth.js +54 -0
  41. package/dist/realtime.d.ts +240 -0
  42. package/dist/realtime.js +312 -0
  43. package/dist/sessions.d.ts +60 -0
  44. package/dist/sessions.js +194 -0
  45. package/dist/settings.d.ts +85 -0
  46. package/dist/settings.js +26 -0
  47. package/dist/storage/adapters/memory.d.ts +13 -0
  48. package/dist/storage/adapters/memory.js +35 -0
  49. package/dist/storage/adapters/s3.d.ts +31 -0
  50. package/dist/storage/adapters/s3.js +171 -0
  51. package/dist/storage/client.d.ts +174 -0
  52. package/dist/storage/client.js +121 -0
  53. package/dist/storage/hub.d.ts +30 -0
  54. package/dist/storage/hub.js +372 -0
  55. package/dist/storage/index.d.ts +6 -0
  56. package/dist/storage/index.js +6 -0
  57. package/dist/storage/runner.d.ts +48 -0
  58. package/dist/storage/runner.js +233 -0
  59. package/dist/storage/types.d.ts +198 -0
  60. package/dist/storage/types.js +1 -0
  61. package/dist/system.d.ts +14 -0
  62. package/dist/system.js +52 -0
  63. package/dist/transport.d.ts +17 -0
  64. package/dist/transport.js +243 -0
  65. package/dist/types.d.ts +1137 -0
  66. package/dist/types.js +1 -0
  67. package/dist/usage.d.ts +106 -0
  68. package/dist/usage.js +82 -0
  69. package/dist/workers.d.ts +146 -0
  70. package/dist/workers.js +822 -0
  71. package/dist/workspaces.d.ts +81 -0
  72. package/dist/workspaces.js +58 -0
  73. package/examples/headless-session.ts +85 -0
  74. package/package.json +56 -0
@@ -0,0 +1,243 @@
1
+ import { SwarmApiError, SwarmAuthError, SwarmConflictError, SwarmForbiddenError, SwarmNotFoundError, SwarmTimeoutError, } from './errors.js';
2
+ export class SwarmTransport {
3
+ config;
4
+ constructor(config) {
5
+ this.config = { ...config };
6
+ }
7
+ setConfig(partial) {
8
+ this.config = { ...this.config, ...partial };
9
+ }
10
+ getConfig() {
11
+ return { ...this.config };
12
+ }
13
+ async request(path, options = {}) {
14
+ if (options.signal?.aborted)
15
+ throw new SwarmApiError('Request aborted by caller', { status: 0 });
16
+ const timeoutMs = options.timeoutMs ?? this.config.timeoutMs;
17
+ const method = (options.method ?? 'GET').toUpperCase();
18
+ // Prepare headers
19
+ const headers = {
20
+ ...this.config.defaultHeaders,
21
+ ...options.headers,
22
+ };
23
+ if (this.config.token && !headers['Authorization'] && !headers['authorization']) {
24
+ headers['Authorization'] = `Bearer ${this.config.token}`;
25
+ }
26
+ let bodyStr;
27
+ if (options.body !== undefined && options.body !== null) {
28
+ if (typeof options.body === 'string') {
29
+ bodyStr = options.body;
30
+ }
31
+ else {
32
+ bodyStr = JSON.stringify(options.body);
33
+ if (!headers['Content-Type'] && !headers['content-type']) {
34
+ headers['Content-Type'] = 'application/json';
35
+ }
36
+ }
37
+ }
38
+ // If socketPath is configured, route via Node.js Unix domain socket
39
+ if (this.config.socketPath) {
40
+ return this.requestSocket(path, method, headers, bodyStr, timeoutMs, options.signal);
41
+ }
42
+ // Standard HTTP/HTTPS via fetch
43
+ return this.requestFetch(path, method, headers, bodyStr, timeoutMs, options.signal);
44
+ }
45
+ async requestFetch(path, method, headers, bodyStr, timeoutMs, externalSignal) {
46
+ const url = `${this.config.baseUrl.replace(/\/+$/, '')}${path.startsWith('/') ? path : `/${path}`}`;
47
+ const controller = new AbortController();
48
+ let timeoutId;
49
+ if (timeoutMs > 0) {
50
+ timeoutId = setTimeout(() => {
51
+ controller.abort(new SwarmTimeoutError(`Request timed out after ${timeoutMs}ms`, timeoutMs));
52
+ }, timeoutMs);
53
+ }
54
+ const abortHandler = () => controller.abort(externalSignal?.reason);
55
+ if (externalSignal) {
56
+ externalSignal.addEventListener('abort', abortHandler, { once: true });
57
+ if (externalSignal.aborted)
58
+ abortHandler();
59
+ }
60
+ try {
61
+ const res = await fetch(url, {
62
+ method,
63
+ headers,
64
+ body: bodyStr,
65
+ signal: controller.signal,
66
+ // Never forward SDK credentials or mutation bodies through redirects.
67
+ redirect: 'error',
68
+ });
69
+ const rawText = await res.text();
70
+ const responseHeaders = {};
71
+ res.headers.forEach((v, k) => {
72
+ responseHeaders[k.toLowerCase()] = v;
73
+ });
74
+ let data;
75
+ try {
76
+ data = (rawText.length > 0 ? JSON.parse(rawText) : null);
77
+ }
78
+ catch {
79
+ data = rawText;
80
+ }
81
+ if (!res.ok) {
82
+ this.handleErrorResponse(res.status, data, rawText);
83
+ }
84
+ return {
85
+ status: res.status,
86
+ headers: responseHeaders,
87
+ data,
88
+ rawText,
89
+ };
90
+ }
91
+ catch (err) {
92
+ if (err instanceof SwarmTimeoutError) {
93
+ throw err;
94
+ }
95
+ if (err instanceof Error && err.name === 'AbortError') {
96
+ if (externalSignal?.aborted) {
97
+ throw new SwarmApiError('Request aborted by caller', { status: 0 });
98
+ }
99
+ throw new SwarmTimeoutError(`Request timed out after ${timeoutMs}ms`, timeoutMs);
100
+ }
101
+ if (err instanceof SwarmApiError) {
102
+ throw err;
103
+ }
104
+ throw new SwarmApiError(err instanceof Error ? err.message : String(err), {
105
+ status: 0,
106
+ details: err,
107
+ });
108
+ }
109
+ finally {
110
+ if (timeoutId)
111
+ clearTimeout(timeoutId);
112
+ if (externalSignal)
113
+ externalSignal.removeEventListener('abort', abortHandler);
114
+ }
115
+ }
116
+ async requestSocket(path, method, headers, bodyStr, timeoutMs, externalSignal) {
117
+ let httpModule;
118
+ try {
119
+ // Dynamic import using variable to avoid static compile-time module resolution
120
+ const mod = 'node:http';
121
+ httpModule = await import(mod);
122
+ }
123
+ catch {
124
+ throw new SwarmApiError('Unix domain socket transport requires Node.js runtime', { status: 0 });
125
+ }
126
+ return new Promise((resolve, reject) => {
127
+ const formattedPath = path.startsWith('/') ? path : `/${path}`;
128
+ const reqHeaders = { ...headers };
129
+ if (bodyStr !== undefined) {
130
+ const byteLength = typeof Buffer !== 'undefined'
131
+ ? Buffer.byteLength(bodyStr)
132
+ : new TextEncoder().encode(bodyStr).length;
133
+ reqHeaders['Content-Length'] = byteLength.toString();
134
+ }
135
+ const req = httpModule.request({
136
+ socketPath: this.config.socketPath,
137
+ path: formattedPath,
138
+ method,
139
+ headers: reqHeaders,
140
+ timeout: timeoutMs > 0 ? timeoutMs : undefined,
141
+ }, (res) => {
142
+ const chunks = [];
143
+ res.on('data', (chunk) => chunks.push(chunk));
144
+ res.on('end', () => {
145
+ let rawText = '';
146
+ if (typeof Buffer !== 'undefined') {
147
+ rawText = Buffer.concat(chunks).toString('utf8');
148
+ }
149
+ else {
150
+ rawText = chunks.map((c) => String(c)).join('');
151
+ }
152
+ const responseHeaders = {};
153
+ for (const [k, v] of Object.entries(res.headers || {})) {
154
+ if (v)
155
+ responseHeaders[k.toLowerCase()] = Array.isArray(v) ? v.join(', ') : String(v);
156
+ }
157
+ let data;
158
+ try {
159
+ data = (rawText.length > 0 ? JSON.parse(rawText) : null);
160
+ }
161
+ catch {
162
+ data = rawText;
163
+ }
164
+ const status = res.statusCode || 200;
165
+ if (status >= 400) {
166
+ try {
167
+ this.handleErrorResponse(status, data, rawText);
168
+ }
169
+ catch (apiErr) {
170
+ return reject(apiErr);
171
+ }
172
+ }
173
+ resolve({
174
+ status,
175
+ headers: responseHeaders,
176
+ data,
177
+ rawText,
178
+ });
179
+ });
180
+ });
181
+ if (timeoutMs > 0) {
182
+ req.on('timeout', () => {
183
+ req.destroy(new SwarmTimeoutError(`Socket request timed out after ${timeoutMs}ms`, timeoutMs));
184
+ });
185
+ }
186
+ req.on('error', (err) => {
187
+ if (err instanceof SwarmTimeoutError) {
188
+ return reject(err);
189
+ }
190
+ reject(new SwarmApiError(`Socket error: ${err?.message || String(err)}`, { status: 0, details: err }));
191
+ });
192
+ const abort = () => req.destroy(new SwarmApiError('Request aborted by caller', { status: 0 }));
193
+ externalSignal?.addEventListener('abort', abort, { once: true });
194
+ req.on('close', () => externalSignal?.removeEventListener('abort', abort));
195
+ if (externalSignal?.aborted) {
196
+ abort();
197
+ return;
198
+ }
199
+ if (bodyStr !== undefined) {
200
+ req.write(bodyStr);
201
+ }
202
+ req.end();
203
+ });
204
+ }
205
+ handleErrorResponse(status, data, rawText) {
206
+ let message = `API request failed with status ${status}`;
207
+ let code;
208
+ let details = undefined;
209
+ if (data && typeof data === 'object') {
210
+ const obj = data;
211
+ if (typeof obj.error === 'string' && obj.error) {
212
+ message = obj.error;
213
+ }
214
+ else if (typeof obj.message === 'string' && obj.message) {
215
+ message = obj.message;
216
+ }
217
+ if (typeof obj.code === 'string') {
218
+ code = obj.code;
219
+ }
220
+ details = obj.details ?? obj;
221
+ }
222
+ else if (rawText && rawText.length < 200) {
223
+ message = rawText;
224
+ }
225
+ const options = {
226
+ code,
227
+ details,
228
+ responseBody: rawText,
229
+ };
230
+ switch (status) {
231
+ case 401:
232
+ throw new SwarmAuthError(message, options);
233
+ case 403:
234
+ throw new SwarmForbiddenError(message, options);
235
+ case 404:
236
+ throw new SwarmNotFoundError(message, options);
237
+ case 409:
238
+ throw new SwarmConflictError(message, options);
239
+ default:
240
+ throw new SwarmApiError(message, { ...options, status });
241
+ }
242
+ }
243
+ }