@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
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
|
|
15
15
|
import type { HttpClient } from "../http.js";
|
|
16
|
-
import type { DockerDeployHostData } from "./docker-deploy.js";
|
|
17
16
|
|
|
18
17
|
// ── Branded IDs ─────────────────────────────────────────────────────────────
|
|
19
18
|
|
|
@@ -121,35 +120,6 @@ export interface DeploymentData {
|
|
|
121
120
|
updated_at?: string;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
export interface DockerDeployDoctorCheck {
|
|
125
|
-
name: string;
|
|
126
|
-
ok: boolean;
|
|
127
|
-
message: string;
|
|
128
|
-
details?: Record<string, unknown>;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export interface DockerDeployDoctorProbe {
|
|
132
|
-
url: string;
|
|
133
|
-
ok: boolean;
|
|
134
|
-
status?: number;
|
|
135
|
-
error?: string;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export interface DockerDeployDoctorResult {
|
|
139
|
-
ok: boolean;
|
|
140
|
-
deployment: DeploymentData;
|
|
141
|
-
host?: DockerDeployHostData;
|
|
142
|
-
checks: DockerDeployDoctorCheck[];
|
|
143
|
-
probe?: DockerDeployDoctorProbe;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface DockerDeployDoctorParams {
|
|
147
|
-
probePath?: string;
|
|
148
|
-
probe_path?: string;
|
|
149
|
-
timeoutMs?: number;
|
|
150
|
-
timeout_ms?: number;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
123
|
export type DeploymentDatabaseRequest =
|
|
154
124
|
| boolean
|
|
155
125
|
| {
|
|
@@ -311,12 +281,118 @@ export interface DeploymentCreateParams extends ExternalAttribution {
|
|
|
311
281
|
auto_deploy?: boolean;
|
|
312
282
|
autoDeploy?: boolean;
|
|
313
283
|
database?: DeploymentDatabaseRequest;
|
|
284
|
+
docker_deploy_template_id?: string;
|
|
285
|
+
dockerDeployTemplateId?: string;
|
|
314
286
|
metadata?: Record<string, unknown>;
|
|
315
287
|
idempotencyKey?: string;
|
|
316
288
|
}
|
|
317
289
|
|
|
318
290
|
export interface DockerDeployCreateParams extends DeploymentCreateParams {}
|
|
319
291
|
|
|
292
|
+
export interface DockerDeployHostData {
|
|
293
|
+
id: string;
|
|
294
|
+
tenant_id?: string;
|
|
295
|
+
workspace_id?: string | null;
|
|
296
|
+
computer_id?: string | null;
|
|
297
|
+
fleet_node_id?: string | null;
|
|
298
|
+
runtime_base_url?: string | null;
|
|
299
|
+
status?: string;
|
|
300
|
+
appliance_status?: string | null;
|
|
301
|
+
appliance_version?: string | null;
|
|
302
|
+
appliance_image?: string | null;
|
|
303
|
+
agent_configured?: boolean;
|
|
304
|
+
last_health_check_at?: string | null;
|
|
305
|
+
created_at?: string;
|
|
306
|
+
updated_at?: string;
|
|
307
|
+
metadata?: Record<string, unknown>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface DockerDeployHostListParams {
|
|
311
|
+
workspace_id?: string;
|
|
312
|
+
workspaceId?: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface DockerDeployHostEnsureParams {
|
|
316
|
+
workspace_id: string;
|
|
317
|
+
workspaceId?: string;
|
|
318
|
+
region?: string;
|
|
319
|
+
size?: string;
|
|
320
|
+
appliance_image?: string;
|
|
321
|
+
applianceImage?: string;
|
|
322
|
+
metadata?: Record<string, unknown>;
|
|
323
|
+
idempotencyKey?: string;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface DockerDeployTemplateData {
|
|
327
|
+
id: string;
|
|
328
|
+
name: string;
|
|
329
|
+
summary?: string;
|
|
330
|
+
description?: string;
|
|
331
|
+
category?: string;
|
|
332
|
+
runtime?: string;
|
|
333
|
+
framework?: string;
|
|
334
|
+
build_command?: string | null;
|
|
335
|
+
run_command?: string | null;
|
|
336
|
+
ports?: number[];
|
|
337
|
+
env?: Record<string, string>;
|
|
338
|
+
files?: Record<string, string>;
|
|
339
|
+
design_md?: string | null;
|
|
340
|
+
design_source_url?: string | null;
|
|
341
|
+
design_sources?: string[];
|
|
342
|
+
design_reference_presets?: DockerDeployDesignReferencePreset[];
|
|
343
|
+
metadata?: Record<string, unknown>;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface DockerDeployDesignReferencePreset {
|
|
347
|
+
id: string;
|
|
348
|
+
name: string;
|
|
349
|
+
summary: string;
|
|
350
|
+
best_for?: string[];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export interface DockerDeployTemplateListParams {
|
|
354
|
+
category?: string;
|
|
355
|
+
runtime?: string;
|
|
356
|
+
framework?: string;
|
|
357
|
+
includePreview?: boolean;
|
|
358
|
+
include_preview?: boolean;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export interface DockerDeployDoctorParams {
|
|
362
|
+
/** Probe the deployment public URL after checking control-plane metadata. Default: true. */
|
|
363
|
+
probe?: boolean;
|
|
364
|
+
/** Path to request on the public URL. Default: "/". */
|
|
365
|
+
probePath?: string;
|
|
366
|
+
/** Public URL probe timeout in milliseconds. Default: 20_000. */
|
|
367
|
+
timeoutMs?: number;
|
|
368
|
+
/** Test hook or custom runtime fetch implementation. */
|
|
369
|
+
fetchImpl?: typeof fetch;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface DockerDeployDoctorCheck {
|
|
373
|
+
name: string;
|
|
374
|
+
ok: boolean;
|
|
375
|
+
message: string;
|
|
376
|
+
data?: Record<string, unknown>;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export interface DockerDeployDoctorProbe {
|
|
380
|
+
url: string;
|
|
381
|
+
status: number | null;
|
|
382
|
+
ok: boolean;
|
|
383
|
+
responseSnippet: string;
|
|
384
|
+
gatewayJson?: boolean;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export interface DockerDeployDoctorResult {
|
|
388
|
+
ok: boolean;
|
|
389
|
+
deployment: DeploymentData;
|
|
390
|
+
host?: DockerDeployHostData;
|
|
391
|
+
publicUrl?: string | null;
|
|
392
|
+
checks: DockerDeployDoctorCheck[];
|
|
393
|
+
probe?: DockerDeployDoctorProbe;
|
|
394
|
+
}
|
|
395
|
+
|
|
320
396
|
export interface DeploymentUpdateParams {
|
|
321
397
|
name?: string;
|
|
322
398
|
branch?: string;
|
|
@@ -363,6 +439,10 @@ export interface PublishParams extends ExternalAttribution {
|
|
|
363
439
|
healthCheckPath?: string;
|
|
364
440
|
/** @deprecated Reserved for dynamic runtime publish. */
|
|
365
441
|
health_check_path?: string;
|
|
442
|
+
deploymentType?: DeploymentProduct | string;
|
|
443
|
+
deployment_type?: DeploymentProduct | string;
|
|
444
|
+
dockerDeployTemplateId?: string;
|
|
445
|
+
docker_deploy_template_id?: string;
|
|
366
446
|
/** @deprecated Reserved for managed data-service binding. */
|
|
367
447
|
dataServices?: string[];
|
|
368
448
|
/** @deprecated Reserved for managed data-service binding. */
|
|
@@ -459,44 +539,48 @@ function stripUndefined(
|
|
|
459
539
|
|
|
460
540
|
function dockerDeployMetadata(
|
|
461
541
|
metadata: Record<string, unknown> | undefined,
|
|
542
|
+
templateId?: string,
|
|
462
543
|
): Record<string, unknown> {
|
|
463
|
-
return {
|
|
544
|
+
return stripUndefined({
|
|
464
545
|
...(metadata ?? {}),
|
|
465
546
|
deployment_product: "docker_deploy",
|
|
466
|
-
|
|
547
|
+
docker_deploy_template_id: templateId,
|
|
548
|
+
});
|
|
467
549
|
}
|
|
468
550
|
|
|
469
|
-
function
|
|
470
|
-
return (
|
|
471
|
-
deployment.deployment_product ??
|
|
472
|
-
deployment.metadata?.["deployment_product"]
|
|
473
|
-
);
|
|
551
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
552
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
474
553
|
}
|
|
475
554
|
|
|
476
|
-
function
|
|
477
|
-
|
|
478
|
-
return (
|
|
479
|
-
deployment.docker_deploy_host_id ??
|
|
480
|
-
(typeof metadataHost === "string" ? metadataHost : null)
|
|
481
|
-
);
|
|
555
|
+
function stringValue(value: unknown): string | undefined {
|
|
556
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
482
557
|
}
|
|
483
558
|
|
|
484
|
-
function
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
559
|
+
function runtimeMetadata(
|
|
560
|
+
metadata: Record<string, unknown>,
|
|
561
|
+
): Record<string, unknown> | undefined {
|
|
562
|
+
const runtime = metadata.runtime;
|
|
563
|
+
return isRecord(runtime) ? runtime : undefined;
|
|
488
564
|
}
|
|
489
565
|
|
|
490
|
-
function
|
|
491
|
-
const url =
|
|
492
|
-
|
|
566
|
+
function publicProbeUrl(publicUrl: string, probePath: string): string {
|
|
567
|
+
const url = new URL(publicUrl);
|
|
568
|
+
const normalizedPath = probePath.startsWith("/") ? probePath : `/${probePath}`;
|
|
569
|
+
url.pathname = normalizedPath;
|
|
570
|
+
return url.toString();
|
|
571
|
+
}
|
|
493
572
|
|
|
573
|
+
function looksLikeMiosaGatewayJson(body: string): boolean {
|
|
494
574
|
try {
|
|
495
|
-
const parsed =
|
|
496
|
-
|
|
497
|
-
|
|
575
|
+
const parsed = JSON.parse(body) as unknown;
|
|
576
|
+
return (
|
|
577
|
+
isRecord(parsed) &&
|
|
578
|
+
parsed.ok === true &&
|
|
579
|
+
typeof parsed.run_id === "string" &&
|
|
580
|
+
Object.keys(parsed).every((key) => ["ok", "run_id"].includes(key))
|
|
581
|
+
);
|
|
498
582
|
} catch {
|
|
499
|
-
return
|
|
583
|
+
return false;
|
|
500
584
|
}
|
|
501
585
|
}
|
|
502
586
|
|
|
@@ -505,21 +589,11 @@ function addDoctorCheck(
|
|
|
505
589
|
name: string,
|
|
506
590
|
ok: boolean,
|
|
507
591
|
message: string,
|
|
508
|
-
|
|
592
|
+
data?: Record<string, unknown>,
|
|
509
593
|
): void {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
function hostHealthy(host: DockerDeployHostData | undefined): boolean {
|
|
514
|
-
return Boolean(
|
|
515
|
-
host && host.status === "active" && host.appliance_status === "healthy",
|
|
516
|
-
);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
function probeUrl(publicUrl: string, probePath: string): string {
|
|
520
|
-
const url = new URL(publicUrl);
|
|
521
|
-
url.pathname = probePath.startsWith("/") ? probePath : `/${probePath}`;
|
|
522
|
-
return url.toString();
|
|
594
|
+
const check: DockerDeployDoctorCheck = { name, ok, message };
|
|
595
|
+
if (data !== undefined) check.data = data;
|
|
596
|
+
checks.push(check);
|
|
523
597
|
}
|
|
524
598
|
|
|
525
599
|
// ── Sub-resources ──────────────────────────────────────────────────────────
|
|
@@ -717,6 +791,8 @@ export class Deployments {
|
|
|
717
791
|
run_command: params.runCommand ?? params.run_command,
|
|
718
792
|
auto_deploy: params.autoDeploy ?? params.auto_deploy,
|
|
719
793
|
database: params.database,
|
|
794
|
+
docker_deploy_template_id:
|
|
795
|
+
params.dockerDeployTemplateId ?? params.docker_deploy_template_id,
|
|
720
796
|
metadata: params.metadata,
|
|
721
797
|
...attributionBody(params),
|
|
722
798
|
});
|
|
@@ -736,16 +812,55 @@ export class Deployments {
|
|
|
736
812
|
async createDockerDeploy(
|
|
737
813
|
params: DockerDeployCreateParams,
|
|
738
814
|
): Promise<DeploymentData> {
|
|
815
|
+
const templateId =
|
|
816
|
+
params.dockerDeployTemplateId ?? params.docker_deploy_template_id;
|
|
739
817
|
return this.create({
|
|
740
818
|
...params,
|
|
741
|
-
metadata: dockerDeployMetadata(params.metadata),
|
|
819
|
+
metadata: dockerDeployMetadata(params.metadata, templateId),
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
async listDockerDeployHosts(
|
|
824
|
+
params: DockerDeployHostListParams = {},
|
|
825
|
+
): Promise<DockerDeployHostData[]> {
|
|
826
|
+
const data = await this.http.get<unknown>(
|
|
827
|
+
"/docker-deploy/hosts",
|
|
828
|
+
stripUndefined({
|
|
829
|
+
workspace_id: params.workspaceId ?? params.workspace_id,
|
|
830
|
+
}) as Record<string, string | number | boolean | undefined>,
|
|
831
|
+
);
|
|
832
|
+
return listItems<DockerDeployHostData>(data, ["hosts", "items"]);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
async ensureDockerDeployHost(
|
|
836
|
+
params: DockerDeployHostEnsureParams,
|
|
837
|
+
): Promise<DockerDeployHostData> {
|
|
838
|
+
const data = await this.http.request<unknown>("/docker-deploy/hosts/ensure", {
|
|
839
|
+
method: "POST",
|
|
840
|
+
body: stripUndefined({
|
|
841
|
+
workspace_id: params.workspaceId ?? params.workspace_id,
|
|
842
|
+
region: params.region,
|
|
843
|
+
size: params.size,
|
|
844
|
+
appliance_image: params.applianceImage ?? params.appliance_image,
|
|
845
|
+
metadata: params.metadata,
|
|
846
|
+
}),
|
|
847
|
+
headers: { "Idempotency-Key": idempotencyKey(params.idempotencyKey) },
|
|
742
848
|
});
|
|
849
|
+
return unwrap(data) as DockerDeployHostData;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
async getDockerDeployHost(hostId: string): Promise<DockerDeployHostData> {
|
|
853
|
+
const data = await this.http.get<unknown>(`/docker-deploy/hosts/${hostId}`);
|
|
854
|
+
return unwrap(data) as DockerDeployHostData;
|
|
743
855
|
}
|
|
744
856
|
|
|
745
857
|
/**
|
|
746
|
-
* Verify a Docker Deploy deployment
|
|
747
|
-
*
|
|
748
|
-
*
|
|
858
|
+
* Verify a Docker Deploy deployment end-to-end.
|
|
859
|
+
*
|
|
860
|
+
* This checks the deployment product marker, Docker Deploy host linkage,
|
|
861
|
+
* appliance health, route runtime metadata, and optionally the public URL.
|
|
862
|
+
* It is intentionally agent-friendly: use this after sandbox.deployDocker()
|
|
863
|
+
* or createDockerDeploy() before telling a user the app is live.
|
|
749
864
|
*/
|
|
750
865
|
async doctorDockerDeploy(
|
|
751
866
|
deploymentId: string,
|
|
@@ -753,161 +868,176 @@ export class Deployments {
|
|
|
753
868
|
): Promise<DockerDeployDoctorResult> {
|
|
754
869
|
const checks: DockerDeployDoctorCheck[] = [];
|
|
755
870
|
const deployment = await this.get(deploymentId);
|
|
756
|
-
const metadata = deployment.metadata
|
|
757
|
-
const product =
|
|
758
|
-
|
|
871
|
+
const metadata = isRecord(deployment.metadata) ? deployment.metadata : {};
|
|
872
|
+
const product =
|
|
873
|
+
stringValue(deployment.deployment_product) ??
|
|
874
|
+
stringValue(metadata.deployment_product);
|
|
875
|
+
const hostId =
|
|
876
|
+
stringValue(deployment.docker_deploy_host_id) ??
|
|
877
|
+
stringValue(metadata.docker_deploy_host_id);
|
|
759
878
|
|
|
760
879
|
addDoctorCheck(
|
|
761
880
|
checks,
|
|
762
881
|
"deployment_product",
|
|
763
882
|
product === "docker_deploy",
|
|
764
883
|
product === "docker_deploy"
|
|
765
|
-
? "Deployment is marked
|
|
766
|
-
: `Expected deployment_product=docker_deploy, got ${
|
|
767
|
-
{
|
|
884
|
+
? "Deployment is marked as Docker Deploy."
|
|
885
|
+
: `Expected deployment_product=docker_deploy, got ${product ?? "missing"}.`,
|
|
886
|
+
{ product: product ?? null },
|
|
768
887
|
);
|
|
769
888
|
|
|
770
889
|
addDoctorCheck(
|
|
771
890
|
checks,
|
|
772
891
|
"docker_deploy_host_id",
|
|
773
|
-
|
|
892
|
+
!!hostId,
|
|
774
893
|
hostId
|
|
775
|
-
? "Deployment
|
|
894
|
+
? "Deployment is linked to a Docker Deploy appliance host."
|
|
776
895
|
: "Deployment has no docker_deploy_host_id.",
|
|
777
|
-
{ docker_deploy_host_id: hostId },
|
|
896
|
+
{ docker_deploy_host_id: hostId ?? null },
|
|
778
897
|
);
|
|
779
898
|
|
|
780
899
|
let host: DockerDeployHostData | undefined;
|
|
781
900
|
if (hostId) {
|
|
782
901
|
try {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
902
|
+
host = await this.getDockerDeployHost(hostId);
|
|
903
|
+
const status = host.status ?? null;
|
|
904
|
+
const applianceStatus = host.appliance_status ?? null;
|
|
905
|
+
const badHostStates = new Set(["failed", "error", "destroyed"]);
|
|
906
|
+
const badApplianceStates = new Set(["failed", "error", "unhealthy"]);
|
|
907
|
+
const ok =
|
|
908
|
+
!badHostStates.has(String(status)) &&
|
|
909
|
+
!badApplianceStates.has(String(applianceStatus));
|
|
787
910
|
addDoctorCheck(
|
|
788
911
|
checks,
|
|
789
912
|
"docker_deploy_host_health",
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
? "Docker Deploy host is
|
|
793
|
-
: `Docker Deploy host status=${
|
|
794
|
-
{
|
|
795
|
-
status: host.status,
|
|
796
|
-
appliance_status: host.appliance_status,
|
|
797
|
-
},
|
|
913
|
+
ok,
|
|
914
|
+
ok
|
|
915
|
+
? "Docker Deploy host is not reporting a failed state."
|
|
916
|
+
: `Docker Deploy host is unhealthy: status=${status}, appliance_status=${applianceStatus}.`,
|
|
917
|
+
{ status, appliance_status: applianceStatus },
|
|
798
918
|
);
|
|
799
|
-
} catch (
|
|
919
|
+
} catch (err) {
|
|
800
920
|
addDoctorCheck(
|
|
801
921
|
checks,
|
|
802
922
|
"docker_deploy_host_health",
|
|
803
923
|
false,
|
|
804
|
-
|
|
924
|
+
`Could not fetch Docker Deploy host ${hostId}: ${
|
|
925
|
+
err instanceof Error ? err.message : String(err)
|
|
926
|
+
}`,
|
|
805
927
|
);
|
|
806
928
|
}
|
|
807
929
|
}
|
|
808
930
|
|
|
809
|
-
const
|
|
810
|
-
const
|
|
811
|
-
|
|
931
|
+
const runtime = runtimeMetadata(metadata);
|
|
932
|
+
const runtimeIp = runtime
|
|
933
|
+
? stringValue(runtime.ip) ?? stringValue(runtime.ip_address)
|
|
934
|
+
: undefined;
|
|
935
|
+
const runtimePort = runtime?.port;
|
|
812
936
|
addDoctorCheck(
|
|
813
937
|
checks,
|
|
814
|
-
"
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
? "
|
|
818
|
-
: "Deployment
|
|
819
|
-
|
|
820
|
-
? {
|
|
821
|
-
app_id: app["app_id"],
|
|
822
|
-
container_id: app["container_id"],
|
|
823
|
-
status: app["status"],
|
|
824
|
-
url: app["url"],
|
|
825
|
-
expected_port: appPort,
|
|
826
|
-
}
|
|
827
|
-
: undefined,
|
|
938
|
+
"route_runtime",
|
|
939
|
+
!!runtimeIp && runtimePort !== undefined && runtimePort !== null,
|
|
940
|
+
runtimeIp && runtimePort !== undefined && runtimePort !== null
|
|
941
|
+
? "Deployment route metadata points at a runtime target."
|
|
942
|
+
: "Deployment metadata has no runtime ip/port target.",
|
|
943
|
+
{ ip: runtimeIp ?? null, port: runtimePort ?? null },
|
|
828
944
|
);
|
|
829
945
|
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
typeof runtime === "object" &&
|
|
833
|
-
runtime !== null &&
|
|
834
|
-
typeof (runtime as Record<string, unknown>)["ip"] === "string" &&
|
|
835
|
-
typeof (runtime as Record<string, unknown>)["port"] === "number";
|
|
836
|
-
const runtimeRecord =
|
|
837
|
-
hasRuntimeRoute && typeof runtime === "object"
|
|
838
|
-
? (runtime as Record<string, unknown>)
|
|
839
|
-
: undefined;
|
|
840
|
-
const routeMatchesContainerPort =
|
|
841
|
-
hasRuntimeRoute &&
|
|
842
|
-
(appPort === null || runtimeRecord?.["port"] === appPort);
|
|
946
|
+
const publicUrl =
|
|
947
|
+
stringValue(deployment.public_url) ?? stringValue(metadata.public_url);
|
|
843
948
|
addDoctorCheck(
|
|
844
949
|
checks,
|
|
845
|
-
"
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
? "Deployment
|
|
849
|
-
:
|
|
850
|
-
|
|
851
|
-
: "Deployment is missing appliance runtime route metadata.",
|
|
852
|
-
runtimeRecord
|
|
853
|
-
? {
|
|
854
|
-
...runtimeRecord,
|
|
855
|
-
expected_port: appPort,
|
|
856
|
-
docker_deploy_url: app?.["url"],
|
|
857
|
-
}
|
|
858
|
-
: undefined,
|
|
950
|
+
"public_url",
|
|
951
|
+
!!publicUrl,
|
|
952
|
+
publicUrl
|
|
953
|
+
? "Deployment has a public URL."
|
|
954
|
+
: "Deployment has no public URL to probe.",
|
|
955
|
+
{ public_url: publicUrl ?? null },
|
|
859
956
|
);
|
|
860
957
|
|
|
861
958
|
let probe: DockerDeployDoctorProbe | undefined;
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
const url = probeUrl(publicUrl, path);
|
|
959
|
+
if (params.probe !== false && publicUrl) {
|
|
960
|
+
const fetchImpl = params.fetchImpl ?? fetch;
|
|
961
|
+
const url = publicProbeUrl(publicUrl, params.probePath ?? "/");
|
|
866
962
|
const controller = new AbortController();
|
|
867
|
-
const
|
|
868
|
-
() => controller.abort(),
|
|
869
|
-
params.timeoutMs ?? params.timeout_ms ?? 10_000,
|
|
870
|
-
);
|
|
963
|
+
const timer = setTimeout(() => controller.abort(), params.timeoutMs ?? 20_000);
|
|
871
964
|
try {
|
|
872
|
-
const response = await
|
|
873
|
-
|
|
965
|
+
const response = await fetchImpl(url, {
|
|
966
|
+
headers: { Accept: "*/*" },
|
|
874
967
|
signal: controller.signal,
|
|
875
968
|
});
|
|
876
|
-
|
|
969
|
+
const text = await response.text();
|
|
970
|
+
const gatewayJson = looksLikeMiosaGatewayJson(text);
|
|
971
|
+
const ok = response.ok && !gatewayJson;
|
|
972
|
+
probe = {
|
|
973
|
+
url,
|
|
974
|
+
status: response.status,
|
|
975
|
+
ok,
|
|
976
|
+
responseSnippet: text.slice(0, 500),
|
|
977
|
+
};
|
|
978
|
+
if (gatewayJson) probe.gatewayJson = true;
|
|
877
979
|
addDoctorCheck(
|
|
878
980
|
checks,
|
|
879
981
|
"public_url_probe",
|
|
880
|
-
|
|
881
|
-
|
|
982
|
+
ok,
|
|
983
|
+
ok
|
|
882
984
|
? `Public URL returned HTTP ${response.status}.`
|
|
883
|
-
:
|
|
884
|
-
|
|
985
|
+
: gatewayJson
|
|
986
|
+
? "Public URL returned MIOSA gateway JSON instead of the app."
|
|
987
|
+
: `Public URL returned HTTP ${response.status}.`,
|
|
988
|
+
{ status: response.status, gateway_json: gatewayJson },
|
|
885
989
|
);
|
|
886
|
-
} catch (
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
ok: false,
|
|
890
|
-
error: error instanceof Error ? error.message : String(error),
|
|
891
|
-
};
|
|
990
|
+
} catch (err) {
|
|
991
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
992
|
+
probe = { url, status: null, ok: false, responseSnippet: message };
|
|
892
993
|
addDoctorCheck(
|
|
893
994
|
checks,
|
|
894
995
|
"public_url_probe",
|
|
895
996
|
false,
|
|
896
|
-
|
|
897
|
-
{ url },
|
|
997
|
+
`Public URL probe failed: ${message}`,
|
|
898
998
|
);
|
|
899
999
|
} finally {
|
|
900
|
-
clearTimeout(
|
|
1000
|
+
clearTimeout(timer);
|
|
901
1001
|
}
|
|
902
1002
|
}
|
|
903
1003
|
|
|
904
|
-
|
|
1004
|
+
const result: DockerDeployDoctorResult = {
|
|
905
1005
|
ok: checks.every((check) => check.ok),
|
|
906
1006
|
deployment,
|
|
907
|
-
...(host ? { host } : {}),
|
|
908
1007
|
checks,
|
|
909
|
-
...(probe ? { probe } : {}),
|
|
910
1008
|
};
|
|
1009
|
+
if (host) result.host = host;
|
|
1010
|
+
if (publicUrl !== undefined) result.publicUrl = publicUrl;
|
|
1011
|
+
if (probe) result.probe = probe;
|
|
1012
|
+
return result;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
async listDockerDeployTemplates(
|
|
1016
|
+
params: DockerDeployTemplateListParams = {},
|
|
1017
|
+
): Promise<DockerDeployTemplateData[]> {
|
|
1018
|
+
const query: Record<string, string | number | boolean | undefined> = {
|
|
1019
|
+
category: params.category,
|
|
1020
|
+
runtime: params.runtime,
|
|
1021
|
+
framework: params.framework,
|
|
1022
|
+
include_preview: params.includePreview ?? params.include_preview,
|
|
1023
|
+
};
|
|
1024
|
+
const data = await this.http.get<unknown>(
|
|
1025
|
+
"/docker-deploy/templates",
|
|
1026
|
+
stripUndefined(query) as Record<string, string | number | boolean | undefined>,
|
|
1027
|
+
);
|
|
1028
|
+
const templates = unwrap<any>(data);
|
|
1029
|
+
if (Array.isArray(templates)) return templates as DockerDeployTemplateData[];
|
|
1030
|
+
return ((templates?.templates ?? templates?.items ?? templates?.data ?? []) ||
|
|
1031
|
+
[]) as DockerDeployTemplateData[];
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
async getDockerDeployTemplate(
|
|
1035
|
+
templateId: string,
|
|
1036
|
+
): Promise<DockerDeployTemplateData> {
|
|
1037
|
+
const data = await this.http.get<unknown>(
|
|
1038
|
+
`/docker-deploy/templates/${templateId}`,
|
|
1039
|
+
);
|
|
1040
|
+
return unwrap(data) as DockerDeployTemplateData;
|
|
911
1041
|
}
|
|
912
1042
|
|
|
913
1043
|
async update(
|
|
@@ -941,6 +1071,15 @@ export class Deployments {
|
|
|
941
1071
|
output_path: params.outputPath ?? params.output_path,
|
|
942
1072
|
entrypoint: params.entrypoint,
|
|
943
1073
|
promote: params.promote,
|
|
1074
|
+
build_command: params.buildCommand ?? params.build_command,
|
|
1075
|
+
run_command: params.runCommand ?? params.run_command,
|
|
1076
|
+
port: params.port,
|
|
1077
|
+
health_check_path: params.healthCheckPath ?? params.health_check_path,
|
|
1078
|
+
deployment_type: params.deploymentType ?? params.deployment_type,
|
|
1079
|
+
docker_deploy_template_id:
|
|
1080
|
+
params.dockerDeployTemplateId ?? params.docker_deploy_template_id,
|
|
1081
|
+
data_services: params.dataServices ?? params.data_services,
|
|
1082
|
+
...attributionBody(params),
|
|
944
1083
|
});
|
|
945
1084
|
const data = await this.http.request<unknown>(
|
|
946
1085
|
`/deployments/${deploymentId}/publish`,
|
|
@@ -971,6 +1110,15 @@ export class Deployments {
|
|
|
971
1110
|
entrypoint: params.entrypoint,
|
|
972
1111
|
domain: params.domain,
|
|
973
1112
|
custom_domain: params.customDomain ?? params.custom_domain,
|
|
1113
|
+
build_command: params.buildCommand ?? params.build_command,
|
|
1114
|
+
run_command: params.runCommand ?? params.run_command,
|
|
1115
|
+
port: params.port,
|
|
1116
|
+
health_check_path: params.healthCheckPath ?? params.health_check_path,
|
|
1117
|
+
deployment_type: params.deploymentType ?? params.deployment_type,
|
|
1118
|
+
docker_deploy_template_id:
|
|
1119
|
+
params.dockerDeployTemplateId ?? params.docker_deploy_template_id,
|
|
1120
|
+
data_services: params.dataServices ?? params.data_services,
|
|
1121
|
+
...attributionBody(params),
|
|
974
1122
|
});
|
|
975
1123
|
const data = await this.http.request<unknown>(
|
|
976
1124
|
`/sandboxes/${sandboxId}/deploy`,
|