@miosa/sdk 1.2.4 → 1.2.5
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 +63 -39
- package/dist/index.d.ts +201 -182
- package/dist/index.js +429 -343
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +5 -5
- package/src/index.ts +16 -11
- package/src/resources/admin.ts +0 -11
- package/src/resources/api-keys.ts +0 -16
- package/src/resources/custom_domains.ts +1 -1
- package/src/resources/deployments.test.ts +117 -114
- package/src/resources/deployments.ts +314 -166
- package/src/resources/devices.test.ts +92 -0
- package/src/resources/devices.ts +291 -0
- package/src/resources/sandboxes.test.ts +2 -0
- package/src/resources/sandboxes.ts +4 -0
- package/src/resources/tenant.ts +19 -101
- package/src/resources/webhooks.ts +54 -39
- package/src/types.ts +5 -5
- package/src/resources/docker-deploy.test.ts +0 -102
- package/src/resources/docker-deploy.ts +0 -183
- package/src/resources/governance.test.ts +0 -355
- package/src/resources/governance.ts +0 -528
- package/src/resources/phase1.test.ts +0 -187
- package/src/resources/quotas.ts +0 -77
- package/src/resources/sandbox-processes.ts +0 -112
- package/src/resources/sandbox-shares.ts +0 -83
- package/src/resources/tenant-events.ts +0 -32
- package/src/resources/workspaces.ts +0 -285
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { CronJobs } from "./resources/cron-jobs.js";
|
|
|
15
15
|
import { Dashboard } from "./resources/dashboard.js";
|
|
16
16
|
import { Databases } from "./resources/databases.js";
|
|
17
17
|
import { Deployments } from "./resources/deployments.js";
|
|
18
|
-
import {
|
|
18
|
+
import { Devices } from "./resources/devices.js";
|
|
19
19
|
import { EgressAudit } from "./resources/egressAudit.js";
|
|
20
20
|
import { EgressNetwork } from "./resources/egressNetwork.js";
|
|
21
21
|
import { EgressSecrets } from "./resources/egressSecrets.js";
|
|
@@ -125,15 +125,15 @@ export class Miosa {
|
|
|
125
125
|
/** Sandboxes — native code-execution environments under `/sandboxes`. */
|
|
126
126
|
readonly sandboxes: Sandboxes;
|
|
127
127
|
|
|
128
|
+
/** Agent device facade — route work across Sandboxes, Computers, and deploy hosts. */
|
|
129
|
+
readonly devices: Devices;
|
|
130
|
+
|
|
128
131
|
/**
|
|
129
132
|
* Deployments — publish from a sandbox to a stable production URL.
|
|
130
133
|
* Versions, releases, rollback, custom domains.
|
|
131
134
|
*/
|
|
132
135
|
readonly deployments: Deployments;
|
|
133
136
|
|
|
134
|
-
/** Docker Deploy appliance hosts — one always-on workspace host, many apps. */
|
|
135
|
-
readonly dockerDeploy: DockerDeploy;
|
|
136
|
-
|
|
137
137
|
/** Credit balance and usage. */
|
|
138
138
|
readonly credits: Credits;
|
|
139
139
|
|
|
@@ -260,8 +260,8 @@ export class Miosa {
|
|
|
260
260
|
this.mcp = new Mcp(this.http);
|
|
261
261
|
this.computers = new Computers(this.http);
|
|
262
262
|
this.sandboxes = new Sandboxes(this.http);
|
|
263
|
+
this.devices = new Devices(this.http);
|
|
263
264
|
this.deployments = new Deployments(this.http);
|
|
264
|
-
this.dockerDeploy = new DockerDeploy(this.http);
|
|
265
265
|
this.credits = new Credits(this.http);
|
|
266
266
|
this.admin = new Admin(this.http);
|
|
267
267
|
this.openComputers = new OpenComputers(this.http);
|
package/src/index.ts
CHANGED
|
@@ -67,6 +67,16 @@ export type {
|
|
|
67
67
|
// Resource classes (useful for isinstance checks and extension)
|
|
68
68
|
export { Computer, ScopedFs } from "./resources/computer.js";
|
|
69
69
|
export { Computers } from "./resources/computers.js";
|
|
70
|
+
export { Devices } from "./resources/devices.js";
|
|
71
|
+
export type {
|
|
72
|
+
DeviceCatalogEntry,
|
|
73
|
+
DeviceKind,
|
|
74
|
+
DeviceListError,
|
|
75
|
+
DeviceListParams,
|
|
76
|
+
DeviceListResponse,
|
|
77
|
+
DeviceRecord,
|
|
78
|
+
DeviceSource,
|
|
79
|
+
} from "./resources/devices.js";
|
|
70
80
|
export { Desktop } from "./resources/desktop.js";
|
|
71
81
|
export { Exec } from "./resources/exec.js";
|
|
72
82
|
export { Files } from "./resources/files.js";
|
|
@@ -135,11 +145,17 @@ export type {
|
|
|
135
145
|
DeploymentVersionId,
|
|
136
146
|
DeploymentVersionKind,
|
|
137
147
|
DeploymentVersionState,
|
|
148
|
+
DockerDeployDesignReferencePreset,
|
|
138
149
|
DockerDeployCreateParams,
|
|
139
150
|
DockerDeployDoctorCheck,
|
|
140
151
|
DockerDeployDoctorParams,
|
|
141
152
|
DockerDeployDoctorProbe,
|
|
142
153
|
DockerDeployDoctorResult,
|
|
154
|
+
DockerDeployTemplateData,
|
|
155
|
+
DockerDeployTemplateListParams,
|
|
156
|
+
DockerDeployHostData,
|
|
157
|
+
DockerDeployHostEnsureParams,
|
|
158
|
+
DockerDeployHostListParams,
|
|
143
159
|
ExternalAttribution,
|
|
144
160
|
PublishFromSandboxParams,
|
|
145
161
|
PublishParams,
|
|
@@ -151,17 +167,6 @@ export type {
|
|
|
151
167
|
RuntimeLogsResult,
|
|
152
168
|
VersionListParams,
|
|
153
169
|
} from "./resources/deployments.js";
|
|
154
|
-
export { DockerDeploy } from "./resources/docker-deploy.js";
|
|
155
|
-
export type {
|
|
156
|
-
DockerDeployApplianceStatus,
|
|
157
|
-
DockerDeployHostData,
|
|
158
|
-
DockerDeployHostEnsureParams,
|
|
159
|
-
DockerDeployHostId,
|
|
160
|
-
DockerDeployHostListParams,
|
|
161
|
-
DockerDeployHostListResponse,
|
|
162
|
-
DockerDeployHostResponse,
|
|
163
|
-
DockerDeployHostStatus,
|
|
164
|
-
} from "./resources/docker-deploy.js";
|
|
165
170
|
export type {
|
|
166
171
|
SnapshotData,
|
|
167
172
|
SnapshotStatus,
|
package/src/resources/admin.ts
CHANGED
|
@@ -345,15 +345,4 @@ export class Admin {
|
|
|
345
345
|
model_id: modelId,
|
|
346
346
|
});
|
|
347
347
|
}
|
|
348
|
-
|
|
349
|
-
/** POST /api/v1/admin/impersonate — returns {token, expires_at}. */
|
|
350
|
-
impersonate(
|
|
351
|
-
externalUserId: string,
|
|
352
|
-
options: { ttlSec?: number } = {},
|
|
353
|
-
): Promise<{ token: string; expires_at: string }> {
|
|
354
|
-
return this.http.post("/admin/impersonate", {
|
|
355
|
-
external_user_id: externalUserId,
|
|
356
|
-
ttl_sec: options.ttlSec ?? 3600,
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
348
|
}
|
|
@@ -113,22 +113,6 @@ export class ApiKeys {
|
|
|
113
113
|
return unwrap<ApiKeyCreateResult>(data);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
/** POST /api/v1/api-keys/scoped — L2 delegation token bound to one external user. */
|
|
117
|
-
async createScoped(params: {
|
|
118
|
-
externalUserId: string;
|
|
119
|
-
scopes: string[];
|
|
120
|
-
expiresAt?: string;
|
|
121
|
-
}): Promise<ApiKeyCreateResult> {
|
|
122
|
-
const body = stripUndefined({
|
|
123
|
-
external_user_id: params.externalUserId,
|
|
124
|
-
scopes: params.scopes,
|
|
125
|
-
expires_at: params.expiresAt,
|
|
126
|
-
});
|
|
127
|
-
return unwrap<ApiKeyCreateResult>(
|
|
128
|
-
await this.http.post<unknown>("/api-keys/scoped", body),
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
116
|
async delete(keyId: string): Promise<void> {
|
|
133
117
|
await this.http.delete<unknown>(`/api-keys/${keyId}`);
|
|
134
118
|
}
|
|
@@ -41,7 +41,7 @@ export interface CustomDomainRegisterParams {
|
|
|
41
41
|
* // 1. Register the domain
|
|
42
42
|
* const domain = await computer.domains.register("app.example.com");
|
|
43
43
|
* console.log(domain.instructions);
|
|
44
|
-
* // => "Add a CNAME record: app.example.com → <slug>.sandbox
|
|
44
|
+
* // => "Add a CNAME record: app.example.com → <slug>.sandbox.<tenant-domain>"
|
|
45
45
|
*
|
|
46
46
|
* // 2. Add the CNAME in your DNS registrar, then...
|
|
47
47
|
*
|
|
@@ -14,7 +14,6 @@ function makeHttp(): HttpClient {
|
|
|
14
14
|
|
|
15
15
|
beforeEach(() => {
|
|
16
16
|
vi.clearAllMocks();
|
|
17
|
-
vi.unstubAllGlobals();
|
|
18
17
|
});
|
|
19
18
|
|
|
20
19
|
describe("Deployments", () => {
|
|
@@ -56,139 +55,143 @@ describe("Deployments", () => {
|
|
|
56
55
|
expect(deployment.docker_deploy_host_id).toBe("ddh_123");
|
|
57
56
|
});
|
|
58
57
|
|
|
59
|
-
it("
|
|
60
|
-
mockGet.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
id: "
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
docker_deploy: {
|
|
76
|
-
app_id: "miosa-clinic-intake",
|
|
77
|
-
container_id: "container_123",
|
|
78
|
-
status: "running",
|
|
79
|
-
url: "http://127.0.0.1:23906",
|
|
58
|
+
it("lists Docker Deploy templates", async () => {
|
|
59
|
+
mockGet.mockResolvedValue({
|
|
60
|
+
data: {
|
|
61
|
+
templates: [
|
|
62
|
+
{
|
|
63
|
+
id: "nextjs-app",
|
|
64
|
+
name: "Next.js App",
|
|
65
|
+
runtime: "node",
|
|
66
|
+
framework: "nextjs",
|
|
67
|
+
design_md: "# Design",
|
|
68
|
+
design_reference_presets: [
|
|
69
|
+
{
|
|
70
|
+
id: "fintech-control",
|
|
71
|
+
name: "Fintech Control",
|
|
72
|
+
summary: "Metrics-heavy finance app.",
|
|
73
|
+
best_for: ["billing portals"],
|
|
80
74
|
},
|
|
81
|
-
|
|
75
|
+
],
|
|
82
76
|
},
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
size: "medium",
|
|
94
|
-
region: "us",
|
|
95
|
-
appliance_status: "healthy",
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
}
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const templates = await new Deployments(
|
|
82
|
+
makeHttp(),
|
|
83
|
+
).listDockerDeployTemplates({
|
|
84
|
+
framework: "nextjs",
|
|
85
|
+
includePreview: true,
|
|
86
|
+
});
|
|
99
87
|
|
|
100
|
-
|
|
88
|
+
expect(mockGet).toHaveBeenCalledWith("/docker-deploy/templates", {
|
|
89
|
+
framework: "nextjs",
|
|
90
|
+
include_preview: true,
|
|
101
91
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
expect(templates[0]?.id).toBe("nextjs-app");
|
|
93
|
+
expect(templates[0]?.design_reference_presets?.[0]?.id).toBe(
|
|
94
|
+
"fintech-control",
|
|
105
95
|
);
|
|
96
|
+
});
|
|
106
97
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
98
|
+
it("gets one Docker Deploy template", async () => {
|
|
99
|
+
mockGet.mockResolvedValue({
|
|
100
|
+
data: {
|
|
101
|
+
id: "compose-full-stack",
|
|
102
|
+
name: "Compose Full Stack",
|
|
103
|
+
runtime: "docker-compose",
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const template = await new Deployments(makeHttp()).getDockerDeployTemplate(
|
|
108
|
+
"compose-full-stack",
|
|
110
109
|
);
|
|
111
110
|
|
|
112
|
-
expect(
|
|
113
|
-
|
|
114
|
-
expect(mockGet).toHaveBeenCalledWith("/docker-deploy/hosts/ddh_123");
|
|
115
|
-
expect(fetch).toHaveBeenCalledWith(
|
|
116
|
-
"https://clinic-intake.osa.miosa.app/health",
|
|
117
|
-
expect.objectContaining({ method: "GET" }),
|
|
111
|
+
expect(mockGet).toHaveBeenCalledWith(
|
|
112
|
+
"/docker-deploy/templates/compose-full-stack",
|
|
118
113
|
);
|
|
119
|
-
expect(
|
|
120
|
-
"deployment_product",
|
|
121
|
-
"docker_deploy_host_id",
|
|
122
|
-
"docker_deploy_host_health",
|
|
123
|
-
"docker_deploy_app",
|
|
124
|
-
"runtime_route",
|
|
125
|
-
"public_url_probe",
|
|
126
|
-
]);
|
|
114
|
+
expect(template.runtime).toBe("docker-compose");
|
|
127
115
|
});
|
|
128
116
|
|
|
129
|
-
it("doctorDockerDeploy
|
|
130
|
-
mockGet
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
117
|
+
it("doctorDockerDeploy() proves appliance metadata and public URL", async () => {
|
|
118
|
+
mockGet
|
|
119
|
+
.mockResolvedValueOnce({
|
|
120
|
+
data: {
|
|
121
|
+
id: "dep_123",
|
|
122
|
+
tenant_id: "ten_123",
|
|
123
|
+
name: "Clinic Intake",
|
|
124
|
+
slug: "clinic-intake",
|
|
125
|
+
state: "running",
|
|
126
|
+
deployment_product: "docker_deploy",
|
|
127
|
+
docker_deploy_host_id: "ddh_123",
|
|
128
|
+
public_url: "https://clinic.osa.miosa.app",
|
|
129
|
+
metadata: {
|
|
139
130
|
deployment_product: "docker_deploy",
|
|
140
|
-
|
|
141
|
-
public_url: "https://clinic-intake.osa.miosa.app",
|
|
142
|
-
metadata: {
|
|
143
|
-
deployment_product: "docker_deploy",
|
|
144
|
-
runtime: { ip: "172.16.74.246", port: 8080 },
|
|
145
|
-
docker_deploy: {
|
|
146
|
-
app_id: "miosa-clinic-intake",
|
|
147
|
-
container_id: "container_123",
|
|
148
|
-
status: "running",
|
|
149
|
-
url: "http://127.0.0.1:23906",
|
|
150
|
-
},
|
|
151
|
-
},
|
|
131
|
+
runtime: { ip: "172.16.74.246", port: 23906 },
|
|
152
132
|
},
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
throw new Error(`unexpected path ${path}`);
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
.mockResolvedValueOnce({
|
|
136
|
+
data: {
|
|
137
|
+
id: "ddh_123",
|
|
138
|
+
status: "active",
|
|
139
|
+
appliance_status: "healthy",
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
const fetchImpl = vi.fn().mockResolvedValue({
|
|
143
|
+
ok: true,
|
|
144
|
+
status: 200,
|
|
145
|
+
text: async () => JSON.stringify({ ok: true, product: "clinic" }),
|
|
171
146
|
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
147
|
+
|
|
148
|
+
const result = await new Deployments(makeHttp()).doctorDockerDeploy(
|
|
149
|
+
"dep_123",
|
|
150
|
+
{ probePath: "/health", fetchImpl },
|
|
175
151
|
);
|
|
176
152
|
|
|
153
|
+
expect(mockGet).toHaveBeenNthCalledWith(1, "/deployments/dep_123");
|
|
154
|
+
expect(mockGet).toHaveBeenNthCalledWith(2, "/docker-deploy/hosts/ddh_123");
|
|
155
|
+
expect(fetchImpl).toHaveBeenCalledWith(
|
|
156
|
+
"https://clinic.osa.miosa.app/health",
|
|
157
|
+
expect.objectContaining({ headers: { Accept: "*/*" } }),
|
|
158
|
+
);
|
|
159
|
+
expect(result.ok).toBe(true);
|
|
160
|
+
expect(result.host?.id).toBe("ddh_123");
|
|
161
|
+
expect(result.probe?.status).toBe(200);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("doctorDockerDeploy() flags gateway JSON as not the user app", async () => {
|
|
165
|
+
mockGet
|
|
166
|
+
.mockResolvedValueOnce({
|
|
167
|
+
data: {
|
|
168
|
+
id: "dep_123",
|
|
169
|
+
tenant_id: "ten_123",
|
|
170
|
+
name: "Clinic Intake",
|
|
171
|
+
slug: "clinic-intake",
|
|
172
|
+
state: "running",
|
|
173
|
+
deployment_product: "docker_deploy",
|
|
174
|
+
docker_deploy_host_id: "ddh_123",
|
|
175
|
+
public_url: "https://clinic.osa.miosa.app",
|
|
176
|
+
metadata: { runtime: { ip: "172.16.74.246", port: 23906 } },
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
.mockResolvedValueOnce({ data: { id: "ddh_123", status: "active" } });
|
|
180
|
+
const fetchImpl = vi.fn().mockResolvedValue({
|
|
181
|
+
ok: true,
|
|
182
|
+
status: 200,
|
|
183
|
+
text: async () => JSON.stringify({ ok: true, run_id: "ciq-123" }),
|
|
184
|
+
});
|
|
185
|
+
|
|
177
186
|
const result = await new Deployments(makeHttp()).doctorDockerDeploy(
|
|
178
187
|
"dep_123",
|
|
179
|
-
{
|
|
188
|
+
{ fetchImpl },
|
|
180
189
|
);
|
|
181
190
|
|
|
182
191
|
expect(result.ok).toBe(false);
|
|
183
|
-
expect(result.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
ok: false,
|
|
188
|
-
message:
|
|
189
|
-
"Deployment route port 8080 does not match Docker container host port 23906.",
|
|
190
|
-
}),
|
|
191
|
-
]),
|
|
192
|
-
);
|
|
192
|
+
expect(result.probe?.gatewayJson).toBe(true);
|
|
193
|
+
expect(
|
|
194
|
+
result.checks.find((check) => check.name === "public_url_probe")?.message,
|
|
195
|
+
).toContain("gateway JSON");
|
|
193
196
|
});
|
|
194
197
|
});
|