maritime-sdk 0.1.0
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 +138 -0
- package/dist/index.cjs +424 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +287 -0
- package/dist/index.d.ts +287 -0
- package/dist/index.js +389 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# maritime-sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript SDK for [Maritime](https://maritime.sh) — provision and drive AI agents on Maritime's serverless infrastructure, straight from your own backend.
|
|
4
|
+
|
|
5
|
+
Build an app where every one of **your** users gets **their own** agent: one call on sign-up spins up an isolated agent on Maritime's fleet; another sends it a message. You never touch a container.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install maritime-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node 18+ (or any runtime with a global `fetch` — Bun, Deno, edge). Zero runtime dependencies.
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Maritime } from 'maritime-sdk'
|
|
17
|
+
|
|
18
|
+
const maritime = new Maritime({ apiKey: process.env.MARITIME_API_KEY })
|
|
19
|
+
|
|
20
|
+
// When YOUR user signs up, give them their own agent. `provision` is
|
|
21
|
+
// idempotent on externalId — safe to call on every login.
|
|
22
|
+
const agent = await maritime.agents.provision({
|
|
23
|
+
externalId: `customer_${user.id}`, // your id for this agent
|
|
24
|
+
name: `assistant-${user.id}`,
|
|
25
|
+
template: 'openclaw',
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Talk to it (sleeping agents auto-wake):
|
|
29
|
+
const { response } = await maritime.agents.chat(agent.id, 'Summarize my unread email.')
|
|
30
|
+
console.log(response)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Authentication
|
|
34
|
+
|
|
35
|
+
Mint an API key (`mk_...`) from the dashboard (**Settings → API keys**) or the CLI (`maritime keys create`), then:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const maritime = new Maritime({ apiKey: 'mk_...' })
|
|
39
|
+
// or set MARITIME_API_KEY and call new Maritime()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Keys carry **scopes** — hand a narrower key to a subsystem that only needs part of the surface:
|
|
43
|
+
|
|
44
|
+
| Scope | Grants |
|
|
45
|
+
|-------|--------|
|
|
46
|
+
| `provision` | create agents |
|
|
47
|
+
| `deploy` | start/stop/restart/sleep/chat |
|
|
48
|
+
| `secrets` | read/write env vars |
|
|
49
|
+
| `manage` | everything, incl. delete + key management (wildcard) |
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const worker = await maritime.keys.create({ name: 'chat-worker', scopes: ['deploy'] })
|
|
53
|
+
// worker.rawKey is shown once — store it now.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Agents
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// Create (kicks off deploy). Prefer `template` — a bare framework yields a broken image.
|
|
60
|
+
const agent = await maritime.agents.create({
|
|
61
|
+
name: 'support-bot',
|
|
62
|
+
template: 'openclaw',
|
|
63
|
+
externalId: 'customer_42',
|
|
64
|
+
instructions: 'You are a friendly support agent for Acme Inc.',
|
|
65
|
+
env: [{ key: 'ACME_API_KEY', value: '...', secret: true }],
|
|
66
|
+
tier: 'smart', // 'smart' | 'extended' | 'always_on'
|
|
67
|
+
idleTtlSeconds: 3600, // 0 = always-on
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// Idempotent get-or-create by externalId (recommended for per-user provisioning)
|
|
71
|
+
const agent = await maritime.agents.provision({ externalId: 'customer_42', name: 'support-bot' })
|
|
72
|
+
|
|
73
|
+
await maritime.agents.get(agent.id)
|
|
74
|
+
await maritime.agents.list({ externalId: 'customer_42' }) // filter by your id
|
|
75
|
+
await maritime.agents.list() // all of your agents
|
|
76
|
+
|
|
77
|
+
// Chat (synchronous; auto-wakes a sleeping agent)
|
|
78
|
+
const { response, error } = await maritime.agents.chat(agent.id, 'Hello')
|
|
79
|
+
|
|
80
|
+
// Lifecycle
|
|
81
|
+
await maritime.agents.start(agent.id)
|
|
82
|
+
await maritime.agents.sleep(agent.id) // cheapest resting state (serverless snapshot)
|
|
83
|
+
await maritime.agents.restart(agent.id)
|
|
84
|
+
await maritime.agents.delete(agent.id) // tears down container + volume + network
|
|
85
|
+
|
|
86
|
+
// Env vars (secrets encrypted at rest; reach a running container after reloadEnv)
|
|
87
|
+
await maritime.agents.setEnv(agent.id, 'STRIPE_KEY', 'sk_live_...', { secret: true })
|
|
88
|
+
await maritime.agents.listEnv(agent.id)
|
|
89
|
+
await maritime.agents.reloadEnv(agent.id)
|
|
90
|
+
|
|
91
|
+
// Logs
|
|
92
|
+
await maritime.agents.logs(agent.id, { limit: 100, level: 'error' })
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Errors
|
|
96
|
+
|
|
97
|
+
Every failure is a subclass of `MaritimeError` — catch the base to catch them all, or narrow by type:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import {
|
|
101
|
+
MaritimeAuthError, // 401 / 403 — bad or under-scoped key
|
|
102
|
+
MaritimePaymentRequiredError,// 402 — wallet needs funding
|
|
103
|
+
MaritimeNotFoundError, // 404 — no such agent (or not yours)
|
|
104
|
+
MaritimeConflictError, // 409 — name already taken
|
|
105
|
+
MaritimeRateLimitError, // 429
|
|
106
|
+
MaritimeAPIError, // any other non-2xx (has .status, .detail)
|
|
107
|
+
MaritimeConnectionError, // never reached Maritime (network/timeout)
|
|
108
|
+
} from 'maritime-sdk'
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await maritime.agents.create({ name: 'dupe', template: 'openclaw' })
|
|
112
|
+
} catch (err) {
|
|
113
|
+
if (err instanceof MaritimeConflictError) {
|
|
114
|
+
// an agent with that name already exists
|
|
115
|
+
} else if (err instanceof MaritimeAPIError) {
|
|
116
|
+
console.error(err.status, err.detail, err.requestId)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
new Maritime({
|
|
125
|
+
apiKey: 'mk_...', // or MARITIME_API_KEY
|
|
126
|
+
baseUrl: 'https://api.maritime.sh', // or MARITIME_API_URL
|
|
127
|
+
timeout: 60_000, // per-request ms
|
|
128
|
+
maxRetries: 2, // network + 5xx/429 (GET/DELETE and 429/503 only)
|
|
129
|
+
fetch: customFetch, // inject a fetch (tests, proxies)
|
|
130
|
+
defaultHeaders: { 'x-team': 'acme' },
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Retries are safe by construction: `GET`/`DELETE` retry on any transient failure; `POST`/`PUT` retry only on network errors and `429`/`503` (never a `5xx` that might have applied a write).
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Maritime: () => Maritime,
|
|
24
|
+
MaritimeAPIError: () => MaritimeAPIError,
|
|
25
|
+
MaritimeAuthError: () => MaritimeAuthError,
|
|
26
|
+
MaritimeConflictError: () => MaritimeConflictError,
|
|
27
|
+
MaritimeConnectionError: () => MaritimeConnectionError,
|
|
28
|
+
MaritimeError: () => MaritimeError,
|
|
29
|
+
MaritimeNotFoundError: () => MaritimeNotFoundError,
|
|
30
|
+
MaritimePaymentRequiredError: () => MaritimePaymentRequiredError,
|
|
31
|
+
MaritimeRateLimitError: () => MaritimeRateLimitError,
|
|
32
|
+
default: () => index_default
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/errors.ts
|
|
37
|
+
var MaritimeError = class extends Error {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "MaritimeError";
|
|
41
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var MaritimeConnectionError = class extends MaritimeError {
|
|
45
|
+
constructor(message, cause) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "MaritimeConnectionError";
|
|
48
|
+
this.cause = cause;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var MaritimeAPIError = class extends MaritimeError {
|
|
52
|
+
constructor(status, detail, requestId) {
|
|
53
|
+
super(`Maritime API error ${status}: ${detail}`);
|
|
54
|
+
this.name = "MaritimeAPIError";
|
|
55
|
+
this.status = status;
|
|
56
|
+
this.detail = detail;
|
|
57
|
+
this.requestId = requestId;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var MaritimeAuthError = class extends MaritimeAPIError {
|
|
61
|
+
constructor(status, detail, requestId) {
|
|
62
|
+
super(status, detail, requestId);
|
|
63
|
+
this.name = "MaritimeAuthError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var MaritimePaymentRequiredError = class extends MaritimeAPIError {
|
|
67
|
+
constructor(status, detail, requestId) {
|
|
68
|
+
super(status, detail, requestId);
|
|
69
|
+
this.name = "MaritimePaymentRequiredError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var MaritimeNotFoundError = class extends MaritimeAPIError {
|
|
73
|
+
constructor(status, detail, requestId) {
|
|
74
|
+
super(status, detail, requestId);
|
|
75
|
+
this.name = "MaritimeNotFoundError";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var MaritimeConflictError = class extends MaritimeAPIError {
|
|
79
|
+
constructor(status, detail, requestId) {
|
|
80
|
+
super(status, detail, requestId);
|
|
81
|
+
this.name = "MaritimeConflictError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var MaritimeRateLimitError = class extends MaritimeAPIError {
|
|
85
|
+
constructor(status, detail, requestId) {
|
|
86
|
+
super(status, detail, requestId);
|
|
87
|
+
this.name = "MaritimeRateLimitError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
function apiErrorFromStatus(status, detail, requestId) {
|
|
91
|
+
switch (status) {
|
|
92
|
+
case 401:
|
|
93
|
+
case 403:
|
|
94
|
+
return new MaritimeAuthError(status, detail, requestId);
|
|
95
|
+
case 402:
|
|
96
|
+
return new MaritimePaymentRequiredError(status, detail, requestId);
|
|
97
|
+
case 404:
|
|
98
|
+
return new MaritimeNotFoundError(status, detail, requestId);
|
|
99
|
+
case 409:
|
|
100
|
+
return new MaritimeConflictError(status, detail, requestId);
|
|
101
|
+
case 429:
|
|
102
|
+
return new MaritimeRateLimitError(status, detail, requestId);
|
|
103
|
+
default:
|
|
104
|
+
return new MaritimeAPIError(status, detail, requestId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/http.ts
|
|
109
|
+
var DEFAULT_BASE_URL = "https://api.maritime.sh";
|
|
110
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
111
|
+
function resolveApiKey(explicit) {
|
|
112
|
+
const key = explicit ?? (typeof process !== "undefined" ? process.env?.MARITIME_API_KEY : void 0);
|
|
113
|
+
if (!key) {
|
|
114
|
+
throw new MaritimeError(
|
|
115
|
+
"Missing Maritime API key. Pass { apiKey } to the client or set MARITIME_API_KEY."
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return key;
|
|
119
|
+
}
|
|
120
|
+
function resolveBaseUrl(explicit) {
|
|
121
|
+
const url = explicit ?? (typeof process !== "undefined" ? process.env?.MARITIME_API_URL : void 0) ?? DEFAULT_BASE_URL;
|
|
122
|
+
return url.replace(/\/+$/, "");
|
|
123
|
+
}
|
|
124
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
125
|
+
var HttpClient = class {
|
|
126
|
+
constructor(options = {}) {
|
|
127
|
+
this.apiKey = resolveApiKey(options.apiKey);
|
|
128
|
+
this.baseUrl = resolveBaseUrl(options.baseUrl);
|
|
129
|
+
this.timeout = options.timeout ?? 6e4;
|
|
130
|
+
this.maxRetries = options.maxRetries ?? 2;
|
|
131
|
+
const f = options.fetch ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
132
|
+
if (!f) {
|
|
133
|
+
throw new MaritimeError(
|
|
134
|
+
"No global fetch available. Use Node 18+, or pass a { fetch } implementation."
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
this.fetchImpl = f.bind(globalThis);
|
|
138
|
+
this.defaultHeaders = options.defaultHeaders ?? {};
|
|
139
|
+
}
|
|
140
|
+
buildUrl(path, query) {
|
|
141
|
+
const url = new URL(this.baseUrl + path);
|
|
142
|
+
if (query) {
|
|
143
|
+
for (const [k, v] of Object.entries(query)) {
|
|
144
|
+
if (v !== void 0 && v !== null) url.searchParams.set(k, String(v));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return url.toString();
|
|
148
|
+
}
|
|
149
|
+
async request(opts) {
|
|
150
|
+
const url = this.buildUrl(opts.path, opts.query);
|
|
151
|
+
const headers = {
|
|
152
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
153
|
+
Accept: "application/json",
|
|
154
|
+
"User-Agent": "maritime-sdk",
|
|
155
|
+
...this.defaultHeaders
|
|
156
|
+
};
|
|
157
|
+
const init = { method: opts.method, headers };
|
|
158
|
+
if (opts.body !== void 0) {
|
|
159
|
+
headers["Content-Type"] = "application/json";
|
|
160
|
+
init.body = JSON.stringify(opts.body);
|
|
161
|
+
}
|
|
162
|
+
const method = opts.method.toUpperCase();
|
|
163
|
+
const retrySafe = opts.idempotent ?? (method === "GET" || method === "DELETE");
|
|
164
|
+
let lastErr;
|
|
165
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
166
|
+
const controller = new AbortController();
|
|
167
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
168
|
+
let res;
|
|
169
|
+
try {
|
|
170
|
+
res = await this.fetchImpl(url, { ...init, signal: controller.signal });
|
|
171
|
+
} catch (err) {
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
lastErr = err;
|
|
174
|
+
if (attempt < this.maxRetries) {
|
|
175
|
+
await sleep(this.backoff(attempt));
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
179
|
+
throw new MaritimeConnectionError(
|
|
180
|
+
`Failed to reach Maritime at ${this.baseUrl}: ${reason}`,
|
|
181
|
+
err
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
if (res.ok) return await this.parseBody(res);
|
|
186
|
+
const detail = await this.safeDetail(res);
|
|
187
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
188
|
+
const retryable = attempt < this.maxRetries && RETRYABLE_STATUS.has(res.status) && (retrySafe || res.status === 429 || res.status === 503);
|
|
189
|
+
if (retryable) {
|
|
190
|
+
lastErr = apiErrorFromStatus(res.status, detail, requestId);
|
|
191
|
+
await sleep(this.backoff(attempt, res));
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
throw apiErrorFromStatus(res.status, detail, requestId);
|
|
195
|
+
}
|
|
196
|
+
if (lastErr instanceof MaritimeError) throw lastErr;
|
|
197
|
+
throw new MaritimeConnectionError(`Request to ${url} failed after retries`, lastErr);
|
|
198
|
+
}
|
|
199
|
+
backoff(attempt, res) {
|
|
200
|
+
const retryAfter = res?.headers.get("retry-after");
|
|
201
|
+
if (retryAfter) {
|
|
202
|
+
const secs = Number(retryAfter);
|
|
203
|
+
if (!Number.isNaN(secs)) return Math.min(secs * 1e3, 2e4);
|
|
204
|
+
}
|
|
205
|
+
return Math.min(500 * 2 ** attempt, 8e3);
|
|
206
|
+
}
|
|
207
|
+
async parseBody(res) {
|
|
208
|
+
if (res.status === 204) return void 0;
|
|
209
|
+
const text = await res.text();
|
|
210
|
+
if (!text) return void 0;
|
|
211
|
+
try {
|
|
212
|
+
return JSON.parse(text);
|
|
213
|
+
} catch {
|
|
214
|
+
return text;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async safeDetail(res) {
|
|
218
|
+
try {
|
|
219
|
+
const body = await this.parseBody(res);
|
|
220
|
+
if (body && typeof body === "object" && "detail" in body) {
|
|
221
|
+
const d = body.detail;
|
|
222
|
+
if (typeof d === "string") return d;
|
|
223
|
+
return JSON.stringify(d);
|
|
224
|
+
}
|
|
225
|
+
if (typeof body === "string" && body) return body;
|
|
226
|
+
} catch {
|
|
227
|
+
}
|
|
228
|
+
return `Request failed with status ${res.status}`;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// src/resources/agents.ts
|
|
233
|
+
var AgentsResource = class {
|
|
234
|
+
constructor(http) {
|
|
235
|
+
this.http = http;
|
|
236
|
+
}
|
|
237
|
+
/** Create a new agent and kick off its deploy. */
|
|
238
|
+
async create(params) {
|
|
239
|
+
return this.http.request({
|
|
240
|
+
method: "POST",
|
|
241
|
+
path: "/api/agents",
|
|
242
|
+
body: toCreateBody(params)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get-or-create an agent by `externalId` — the idempotent entry point for a
|
|
247
|
+
* "one agent per end-customer" flow. If an agent with that external id
|
|
248
|
+
* already exists it is returned; otherwise a new one is created. Safe to call
|
|
249
|
+
* on every sign-in.
|
|
250
|
+
*/
|
|
251
|
+
async provision(params) {
|
|
252
|
+
const existing = await this.list({ externalId: params.externalId });
|
|
253
|
+
if (existing.length > 0) return existing[0];
|
|
254
|
+
const withTemplate = {
|
|
255
|
+
template: "openclaw",
|
|
256
|
+
...params
|
|
257
|
+
};
|
|
258
|
+
try {
|
|
259
|
+
return await this.create(withTemplate);
|
|
260
|
+
} catch (err) {
|
|
261
|
+
const raced = await this.list({ externalId: params.externalId });
|
|
262
|
+
if (raced.length > 0) return raced[0];
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** Fetch a single agent by id. */
|
|
267
|
+
async get(agentId) {
|
|
268
|
+
return this.http.request({ method: "GET", path: `/api/agents/${enc(agentId)}` });
|
|
269
|
+
}
|
|
270
|
+
/** List agents, optionally filtered by `externalId` or `name`. */
|
|
271
|
+
async list(params = {}) {
|
|
272
|
+
return this.http.request({
|
|
273
|
+
method: "GET",
|
|
274
|
+
path: "/api/agents",
|
|
275
|
+
query: { externalId: params.externalId, name: params.name }
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Send a message to an agent and wait for its reply. Sleeping serverless
|
|
280
|
+
* agents auto-wake. Returns `{ response }` (or `{ response: null, error }`
|
|
281
|
+
* if delivery failed — Maritime does not surface that as an HTTP error).
|
|
282
|
+
*/
|
|
283
|
+
async chat(agentId, message, opts = {}) {
|
|
284
|
+
return this.http.request({
|
|
285
|
+
method: "POST",
|
|
286
|
+
path: `/api/agents/${enc(agentId)}/chat`,
|
|
287
|
+
body: { message, conversation_id: opts.conversationId }
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/** Start / wake an agent. */
|
|
291
|
+
async start(agentId) {
|
|
292
|
+
return this.lifecycle(agentId, "start");
|
|
293
|
+
}
|
|
294
|
+
/** Stop an agent (container stopped, state preserved). */
|
|
295
|
+
async stop(agentId) {
|
|
296
|
+
return this.lifecycle(agentId, "stop");
|
|
297
|
+
}
|
|
298
|
+
/** Put an agent to sleep (serverless snapshot; cheapest resting state). */
|
|
299
|
+
async sleep(agentId) {
|
|
300
|
+
return this.lifecycle(agentId, "sleep");
|
|
301
|
+
}
|
|
302
|
+
/** Restart an agent. */
|
|
303
|
+
async restart(agentId) {
|
|
304
|
+
return this.lifecycle(agentId, "restart");
|
|
305
|
+
}
|
|
306
|
+
/** Delete an agent and all its resources (container, volume, network). */
|
|
307
|
+
async delete(agentId) {
|
|
308
|
+
await this.http.request({ method: "DELETE", path: `/api/agents/${enc(agentId)}` });
|
|
309
|
+
}
|
|
310
|
+
/** List an agent's env vars (secret values are masked). */
|
|
311
|
+
async listEnv(agentId) {
|
|
312
|
+
return this.http.request({ method: "GET", path: `/api/agents/${enc(agentId)}/env` });
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Set (upsert) an env var. Secrets are encrypted at rest. Changes reach a
|
|
316
|
+
* running container after {@link reloadEnv} or a restart.
|
|
317
|
+
*/
|
|
318
|
+
async setEnv(agentId, key, value, opts = {}) {
|
|
319
|
+
return this.http.request({
|
|
320
|
+
method: "POST",
|
|
321
|
+
path: `/api/agents/${enc(agentId)}/env`,
|
|
322
|
+
body: { key, value, isSecret: opts.secret ?? true }
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/** Delete an env var. */
|
|
326
|
+
async deleteEnv(agentId, key) {
|
|
327
|
+
await this.http.request({
|
|
328
|
+
method: "DELETE",
|
|
329
|
+
path: `/api/agents/${enc(agentId)}/env/${enc(key)}`
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
/** Hot-reload env vars into the running container (falls back to restart). */
|
|
333
|
+
async reloadEnv(agentId) {
|
|
334
|
+
return this.lifecycle(agentId, "reload-env");
|
|
335
|
+
}
|
|
336
|
+
/** Fetch recent log entries for an agent. */
|
|
337
|
+
async logs(agentId, opts = {}) {
|
|
338
|
+
return this.http.request({
|
|
339
|
+
method: "GET",
|
|
340
|
+
path: `/api/agents/${enc(agentId)}/logs`,
|
|
341
|
+
query: { limit: opts.limit, level: opts.level }
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
lifecycle(agentId, action) {
|
|
345
|
+
return this.http.request({
|
|
346
|
+
method: "POST",
|
|
347
|
+
path: `/api/agents/${enc(agentId)}/${action}`,
|
|
348
|
+
// Lifecycle transitions are effectively idempotent; safe to retry.
|
|
349
|
+
idempotent: true
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
var enc = encodeURIComponent;
|
|
354
|
+
function toCreateBody(p) {
|
|
355
|
+
return {
|
|
356
|
+
name: p.name,
|
|
357
|
+
templateId: p.template,
|
|
358
|
+
externalId: p.externalId,
|
|
359
|
+
description: p.description,
|
|
360
|
+
instructions: p.instructions,
|
|
361
|
+
tier: p.tier,
|
|
362
|
+
memMb: p.memMb,
|
|
363
|
+
vcpus: p.vcpus,
|
|
364
|
+
idleTtlSeconds: p.idleTtlSeconds,
|
|
365
|
+
diskGb: p.diskGb,
|
|
366
|
+
githubRepo: p.githubRepo,
|
|
367
|
+
imageName: p.imageName,
|
|
368
|
+
initialEnvVars: p.env?.map((e) => ({
|
|
369
|
+
key: e.key,
|
|
370
|
+
value: e.value,
|
|
371
|
+
isSecret: e.secret ?? true
|
|
372
|
+
}))
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// src/resources/keys.ts
|
|
377
|
+
var KeysResource = class {
|
|
378
|
+
constructor(http) {
|
|
379
|
+
this.http = http;
|
|
380
|
+
}
|
|
381
|
+
/** Mint a new key. The raw key is returned once — store it immediately. */
|
|
382
|
+
async create(params) {
|
|
383
|
+
return this.http.request({
|
|
384
|
+
method: "POST",
|
|
385
|
+
path: "/api/v1/keys",
|
|
386
|
+
body: {
|
|
387
|
+
name: params.name,
|
|
388
|
+
scopes: params.scopes ?? ["provision", "deploy", "secrets", "manage"],
|
|
389
|
+
expires_in_days: params.expiresInDays
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
/** List the caller's keys (raw values are never returned again). */
|
|
394
|
+
async list() {
|
|
395
|
+
return this.http.request({ method: "GET", path: "/api/v1/keys" });
|
|
396
|
+
}
|
|
397
|
+
/** Revoke a key by id. */
|
|
398
|
+
async revoke(keyId) {
|
|
399
|
+
await this.http.request({ method: "DELETE", path: `/api/v1/keys/${encodeURIComponent(keyId)}` });
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// src/index.ts
|
|
404
|
+
var Maritime = class {
|
|
405
|
+
constructor(options = {}) {
|
|
406
|
+
this.http = new HttpClient(options);
|
|
407
|
+
this.agents = new AgentsResource(this.http);
|
|
408
|
+
this.keys = new KeysResource(this.http);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
var index_default = Maritime;
|
|
412
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
413
|
+
0 && (module.exports = {
|
|
414
|
+
Maritime,
|
|
415
|
+
MaritimeAPIError,
|
|
416
|
+
MaritimeAuthError,
|
|
417
|
+
MaritimeConflictError,
|
|
418
|
+
MaritimeConnectionError,
|
|
419
|
+
MaritimeError,
|
|
420
|
+
MaritimeNotFoundError,
|
|
421
|
+
MaritimePaymentRequiredError,
|
|
422
|
+
MaritimeRateLimitError
|
|
423
|
+
});
|
|
424
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/agents.ts","../src/resources/keys.ts"],"sourcesContent":["import { HttpClient, type MaritimeClientOptions } from './http.js'\nimport { AgentsResource } from './resources/agents.js'\nimport { KeysResource } from './resources/keys.js'\n\nexport type { MaritimeClientOptions } from './http.js'\nexport * from './types.js'\nexport {\n MaritimeError,\n MaritimeConnectionError,\n MaritimeAPIError,\n MaritimeAuthError,\n MaritimePaymentRequiredError,\n MaritimeNotFoundError,\n MaritimeConflictError,\n MaritimeRateLimitError,\n} from './errors.js'\n\n/**\n * The Maritime client. Provision and drive AI agents on Maritime's serverless\n * infrastructure from your own backend.\n *\n * ```ts\n * import { Maritime } from 'maritime-sdk'\n *\n * const maritime = new Maritime({ apiKey: process.env.MARITIME_API_KEY })\n *\n * // When YOUR user signs up, give them their own agent (idempotent):\n * const agent = await maritime.agents.provision({\n * externalId: `customer_${userId}`,\n * name: `assistant-${userId}`,\n * template: 'openclaw',\n * })\n *\n * const { response } = await maritime.agents.chat(agent.id, 'Hello!')\n * ```\n */\nexport class Maritime {\n readonly agents: AgentsResource\n readonly keys: KeysResource\n /** The underlying transport — escape hatch for endpoints not yet wrapped. */\n readonly http: HttpClient\n\n constructor(options: MaritimeClientOptions = {}) {\n this.http = new HttpClient(options)\n this.agents = new AgentsResource(this.http)\n this.keys = new KeysResource(this.http)\n }\n}\n\nexport default Maritime\n","/** Base class for every error the SDK throws. Catch this to catch them all. */\nexport class MaritimeError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MaritimeError'\n // Restore prototype chain when compiled to ES5-ish targets.\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\n/** The request never reached Maritime (DNS, connection refused, timeout, …). */\nexport class MaritimeConnectionError extends MaritimeError {\n readonly cause?: unknown\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = 'MaritimeConnectionError'\n this.cause = cause\n }\n}\n\n/** Maritime returned a non-2xx response. Subclassed by status below. */\nexport class MaritimeAPIError extends MaritimeError {\n readonly status: number\n readonly detail: string\n /** Value of the `x-request-id` response header, when present. */\n readonly requestId?: string\n\n constructor(status: number, detail: string, requestId?: string) {\n super(`Maritime API error ${status}: ${detail}`)\n this.name = 'MaritimeAPIError'\n this.status = status\n this.detail = detail\n this.requestId = requestId\n }\n}\n\n/** 401 / 403 — bad or insufficiently-scoped API key. */\nexport class MaritimeAuthError extends MaritimeAPIError {\n constructor(status: number, detail: string, requestId?: string) {\n super(status, detail, requestId)\n this.name = 'MaritimeAuthError'\n }\n}\n\n/** 402 — the account wallet needs funding before this action can proceed. */\nexport class MaritimePaymentRequiredError extends MaritimeAPIError {\n constructor(status: number, detail: string, requestId?: string) {\n super(status, detail, requestId)\n this.name = 'MaritimePaymentRequiredError'\n }\n}\n\n/** 404 — the agent (or other resource) does not exist or is not yours. */\nexport class MaritimeNotFoundError extends MaritimeAPIError {\n constructor(status: number, detail: string, requestId?: string) {\n super(status, detail, requestId)\n this.name = 'MaritimeNotFoundError'\n }\n}\n\n/** 409 — a uniqueness conflict (e.g. an agent with that name already exists). */\nexport class MaritimeConflictError extends MaritimeAPIError {\n constructor(status: number, detail: string, requestId?: string) {\n super(status, detail, requestId)\n this.name = 'MaritimeConflictError'\n }\n}\n\n/** 429 — rate limited. */\nexport class MaritimeRateLimitError extends MaritimeAPIError {\n constructor(status: number, detail: string, requestId?: string) {\n super(status, detail, requestId)\n this.name = 'MaritimeRateLimitError'\n }\n}\n\n/** Build the most specific error subclass for an HTTP status. */\nexport function apiErrorFromStatus(\n status: number,\n detail: string,\n requestId?: string,\n): MaritimeAPIError {\n switch (status) {\n case 401:\n case 403:\n return new MaritimeAuthError(status, detail, requestId)\n case 402:\n return new MaritimePaymentRequiredError(status, detail, requestId)\n case 404:\n return new MaritimeNotFoundError(status, detail, requestId)\n case 409:\n return new MaritimeConflictError(status, detail, requestId)\n case 429:\n return new MaritimeRateLimitError(status, detail, requestId)\n default:\n return new MaritimeAPIError(status, detail, requestId)\n }\n}\n","import { apiErrorFromStatus, MaritimeConnectionError, MaritimeError } from './errors.js'\n\nexport interface MaritimeClientOptions {\n /**\n * Maritime API key (`mk_...`). Defaults to the `MARITIME_API_KEY` env var.\n * Mint one from the dashboard (Settings → API keys) or `maritime keys create`.\n */\n apiKey?: string\n /** API base URL. Defaults to `MARITIME_API_URL` or `https://api.maritime.sh`. */\n baseUrl?: string\n /** Per-request timeout in ms (default 60_000). */\n timeout?: number\n /** Retries on network errors and 5xx/429 responses (default 2). */\n maxRetries?: number\n /** Inject a custom fetch (tests, proxies, non-global-fetch runtimes). */\n fetch?: typeof fetch\n /** Extra headers sent on every request. */\n defaultHeaders?: Record<string, string>\n}\n\ninterface RequestOptions {\n method: string\n path: string\n query?: Record<string, string | number | boolean | undefined | null>\n body?: unknown\n /** Override retry behaviour for a single call (e.g. non-idempotent POST). */\n idempotent?: boolean\n}\n\nconst DEFAULT_BASE_URL = 'https://api.maritime.sh'\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504])\n\nfunction resolveApiKey(explicit?: string): string {\n const key = explicit ?? (typeof process !== 'undefined' ? process.env?.MARITIME_API_KEY : undefined)\n if (!key) {\n throw new MaritimeError(\n 'Missing Maritime API key. Pass { apiKey } to the client or set MARITIME_API_KEY.',\n )\n }\n return key\n}\n\nfunction resolveBaseUrl(explicit?: string): string {\n const url =\n explicit ??\n (typeof process !== 'undefined' ? process.env?.MARITIME_API_URL : undefined) ??\n DEFAULT_BASE_URL\n return url.replace(/\\/+$/, '')\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))\n\n/**\n * Thin transport: auth header, JSON encode/decode, typed errors, and bounded\n * retry with exponential backoff on transient failures. No dependencies —\n * uses the runtime's global `fetch` (Node 18+, Bun, Deno, browsers, edge).\n */\nexport class HttpClient {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly timeout: number\n private readonly maxRetries: number\n private readonly fetchImpl: typeof fetch\n private readonly defaultHeaders: Record<string, string>\n\n constructor(options: MaritimeClientOptions = {}) {\n this.apiKey = resolveApiKey(options.apiKey)\n this.baseUrl = resolveBaseUrl(options.baseUrl)\n this.timeout = options.timeout ?? 60_000\n this.maxRetries = options.maxRetries ?? 2\n const f = options.fetch ?? (typeof fetch !== 'undefined' ? fetch : undefined)\n if (!f) {\n throw new MaritimeError(\n 'No global fetch available. Use Node 18+, or pass a { fetch } implementation.',\n )\n }\n // Bind so `this` inside native fetch stays correct.\n this.fetchImpl = f.bind(globalThis) as typeof fetch\n this.defaultHeaders = options.defaultHeaders ?? {}\n }\n\n private buildUrl(path: string, query?: RequestOptions['query']): string {\n const url = new URL(this.baseUrl + path)\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined && v !== null) url.searchParams.set(k, String(v))\n }\n }\n return url.toString()\n }\n\n async request<T>(opts: RequestOptions): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query)\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: 'application/json',\n 'User-Agent': 'maritime-sdk',\n ...this.defaultHeaders,\n }\n const init: RequestInit = { method: opts.method, headers }\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json'\n init.body = JSON.stringify(opts.body)\n }\n\n // GET/DELETE are idempotent and safe to retry; POST/PUT retry only on\n // network errors + 429/503 (never on a 5xx that may have applied a write),\n // unless the caller explicitly marks the call idempotent.\n const method = opts.method.toUpperCase()\n const retrySafe = opts.idempotent ?? (method === 'GET' || method === 'DELETE')\n\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), this.timeout)\n\n let res: Response\n try {\n res = await this.fetchImpl(url, { ...init, signal: controller.signal })\n } catch (err) {\n // Transport-level failure (DNS, connection, timeout/abort). Retry.\n clearTimeout(timer)\n lastErr = err\n if (attempt < this.maxRetries) {\n await sleep(this.backoff(attempt))\n continue\n }\n const reason = err instanceof Error ? err.message : String(err)\n throw new MaritimeConnectionError(\n `Failed to reach Maritime at ${this.baseUrl}: ${reason}`,\n err,\n )\n }\n clearTimeout(timer)\n\n if (res.ok) return (await this.parseBody(res)) as T\n\n const detail = await this.safeDetail(res)\n const requestId = res.headers.get('x-request-id') ?? undefined\n const retryable =\n attempt < this.maxRetries &&\n RETRYABLE_STATUS.has(res.status) &&\n (retrySafe || res.status === 429 || res.status === 503)\n if (retryable) {\n lastErr = apiErrorFromStatus(res.status, detail, requestId)\n await sleep(this.backoff(attempt, res))\n continue\n }\n throw apiErrorFromStatus(res.status, detail, requestId)\n }\n\n // Exhausted retries on a retryable HTTP status.\n if (lastErr instanceof MaritimeError) throw lastErr\n throw new MaritimeConnectionError(`Request to ${url} failed after retries`, lastErr)\n }\n\n private backoff(attempt: number, res?: Response): number {\n // Honour Retry-After (seconds) when the server sends it.\n const retryAfter = res?.headers.get('retry-after')\n if (retryAfter) {\n const secs = Number(retryAfter)\n if (!Number.isNaN(secs)) return Math.min(secs * 1000, 20_000)\n }\n return Math.min(500 * 2 ** attempt, 8_000)\n }\n\n private async parseBody(res: Response): Promise<unknown> {\n if (res.status === 204) return undefined\n const text = await res.text()\n if (!text) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n }\n\n private async safeDetail(res: Response): Promise<string> {\n try {\n const body = await this.parseBody(res)\n if (body && typeof body === 'object' && 'detail' in body) {\n const d = (body as { detail: unknown }).detail\n if (typeof d === 'string') return d\n return JSON.stringify(d)\n }\n if (typeof body === 'string' && body) return body\n } catch {\n /* fall through */\n }\n return `Request failed with status ${res.status}`\n }\n}\n","import type { HttpClient } from '../http.js'\nimport type {\n Agent,\n ChatOptions,\n ChatResult,\n CreateAgentParams,\n EnvVar,\n ListAgentsParams,\n LogEntry,\n} from '../types.js'\n\n/** Operations on Maritime agents. Access via `maritime.agents`. */\nexport class AgentsResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Create a new agent and kick off its deploy. */\n async create(params: CreateAgentParams): Promise<Agent> {\n return this.http.request<Agent>({\n method: 'POST',\n path: '/api/agents',\n body: toCreateBody(params),\n })\n }\n\n /**\n * Get-or-create an agent by `externalId` — the idempotent entry point for a\n * \"one agent per end-customer\" flow. If an agent with that external id\n * already exists it is returned; otherwise a new one is created. Safe to call\n * on every sign-in.\n */\n async provision(params: CreateAgentParams & { externalId: string }): Promise<Agent> {\n const existing = await this.list({ externalId: params.externalId })\n if (existing.length > 0) return existing[0] as Agent\n // Default the template so we never create a broken bare-framework agent.\n const withTemplate: CreateAgentParams = {\n template: 'openclaw',\n ...params,\n }\n try {\n return await this.create(withTemplate)\n } catch (err) {\n // Lost a race with a concurrent provisioner (unique-name 409). Re-read.\n const raced = await this.list({ externalId: params.externalId })\n if (raced.length > 0) return raced[0] as Agent\n throw err\n }\n }\n\n /** Fetch a single agent by id. */\n async get(agentId: string): Promise<Agent> {\n return this.http.request<Agent>({ method: 'GET', path: `/api/agents/${enc(agentId)}` })\n }\n\n /** List agents, optionally filtered by `externalId` or `name`. */\n async list(params: ListAgentsParams = {}): Promise<Agent[]> {\n return this.http.request<Agent[]>({\n method: 'GET',\n path: '/api/agents',\n query: { externalId: params.externalId, name: params.name },\n })\n }\n\n /**\n * Send a message to an agent and wait for its reply. Sleeping serverless\n * agents auto-wake. Returns `{ response }` (or `{ response: null, error }`\n * if delivery failed — Maritime does not surface that as an HTTP error).\n */\n async chat(agentId: string, message: string, opts: ChatOptions = {}): Promise<ChatResult> {\n return this.http.request<ChatResult>({\n method: 'POST',\n path: `/api/agents/${enc(agentId)}/chat`,\n body: { message, conversation_id: opts.conversationId },\n })\n }\n\n /** Start / wake an agent. */\n async start(agentId: string): Promise<Agent> {\n return this.lifecycle(agentId, 'start')\n }\n\n /** Stop an agent (container stopped, state preserved). */\n async stop(agentId: string): Promise<Agent> {\n return this.lifecycle(agentId, 'stop')\n }\n\n /** Put an agent to sleep (serverless snapshot; cheapest resting state). */\n async sleep(agentId: string): Promise<Agent> {\n return this.lifecycle(agentId, 'sleep')\n }\n\n /** Restart an agent. */\n async restart(agentId: string): Promise<Agent> {\n return this.lifecycle(agentId, 'restart')\n }\n\n /** Delete an agent and all its resources (container, volume, network). */\n async delete(agentId: string): Promise<void> {\n await this.http.request<void>({ method: 'DELETE', path: `/api/agents/${enc(agentId)}` })\n }\n\n /** List an agent's env vars (secret values are masked). */\n async listEnv(agentId: string): Promise<EnvVar[]> {\n return this.http.request<EnvVar[]>({ method: 'GET', path: `/api/agents/${enc(agentId)}/env` })\n }\n\n /**\n * Set (upsert) an env var. Secrets are encrypted at rest. Changes reach a\n * running container after {@link reloadEnv} or a restart.\n */\n async setEnv(\n agentId: string,\n key: string,\n value: string,\n opts: { secret?: boolean } = {},\n ): Promise<EnvVar> {\n return this.http.request<EnvVar>({\n method: 'POST',\n path: `/api/agents/${enc(agentId)}/env`,\n body: { key, value, isSecret: opts.secret ?? true },\n })\n }\n\n /** Delete an env var. */\n async deleteEnv(agentId: string, key: string): Promise<void> {\n await this.http.request<void>({\n method: 'DELETE',\n path: `/api/agents/${enc(agentId)}/env/${enc(key)}`,\n })\n }\n\n /** Hot-reload env vars into the running container (falls back to restart). */\n async reloadEnv(agentId: string): Promise<Agent> {\n return this.lifecycle(agentId, 'reload-env')\n }\n\n /** Fetch recent log entries for an agent. */\n async logs(\n agentId: string,\n opts: { limit?: number; level?: string } = {},\n ): Promise<LogEntry[]> {\n return this.http.request<LogEntry[]>({\n method: 'GET',\n path: `/api/agents/${enc(agentId)}/logs`,\n query: { limit: opts.limit, level: opts.level },\n })\n }\n\n private lifecycle(agentId: string, action: string): Promise<Agent> {\n return this.http.request<Agent>({\n method: 'POST',\n path: `/api/agents/${enc(agentId)}/${action}`,\n // Lifecycle transitions are effectively idempotent; safe to retry.\n idempotent: true,\n })\n }\n}\n\nconst enc = encodeURIComponent\n\nfunction toCreateBody(p: CreateAgentParams): Record<string, unknown> {\n return {\n name: p.name,\n templateId: p.template,\n externalId: p.externalId,\n description: p.description,\n instructions: p.instructions,\n tier: p.tier,\n memMb: p.memMb,\n vcpus: p.vcpus,\n idleTtlSeconds: p.idleTtlSeconds,\n diskGb: p.diskGb,\n githubRepo: p.githubRepo,\n imageName: p.imageName,\n initialEnvVars: p.env?.map((e) => ({\n key: e.key,\n value: e.value,\n isSecret: e.secret ?? true,\n })),\n }\n}\n","import type { HttpClient } from '../http.js'\nimport type { ApiKey, CreatedApiKey, CreateApiKeyParams } from '../types.js'\n\n/**\n * Manage API keys (`mk_...`) programmatically. Access via `maritime.keys`.\n *\n * Minting a key requires the caller's own key to carry the `manage` scope (or\n * be a dashboard session). Hand a narrower-scoped key to a subsystem that only\n * needs part of the surface — e.g. a `deploy`-scoped key for a worker that only\n * chats to agents.\n */\nexport class KeysResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Mint a new key. The raw key is returned once — store it immediately. */\n async create(params: CreateApiKeyParams): Promise<CreatedApiKey> {\n return this.http.request<CreatedApiKey>({\n method: 'POST',\n path: '/api/v1/keys',\n body: {\n name: params.name,\n scopes: params.scopes ?? ['provision', 'deploy', 'secrets', 'manage'],\n expires_in_days: params.expiresInDays,\n },\n })\n }\n\n /** List the caller's keys (raw values are never returned again). */\n async list(): Promise<ApiKey[]> {\n return this.http.request<ApiKey[]>({ method: 'GET', path: '/api/v1/keys' })\n }\n\n /** Revoke a key by id. */\n async revoke(keyId: string): Promise<void> {\n await this.http.request<void>({ method: 'DELETE', path: `/api/v1/keys/${encodeURIComponent(keyId)}` })\n }\n}\n"],"mappings":"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","names":[]}
|