libretto 0.5.3-experimental.0 → 0.5.3-experimental.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,149 @@
1
+ import { z } from "zod";
2
+ import { buildHostedDeployTarball } from "../core/deploy-artifact.js";
3
+ import { SimpleCLI } from "../framework/simple-cli.js";
4
+ function getConfig() {
5
+ const apiUrl = process.env.LIBRETTO_API_URL;
6
+ const apiKey = process.env.LIBRETTO_API_KEY;
7
+ if (!apiUrl) {
8
+ throw new Error(
9
+ "LIBRETTO_API_URL environment variable is required."
10
+ );
11
+ }
12
+ if (!apiKey) {
13
+ throw new Error(
14
+ "LIBRETTO_API_KEY environment variable is required."
15
+ );
16
+ }
17
+ return { apiUrl: apiUrl.replace(/\/$/, ""), apiKey };
18
+ }
19
+ async function postJson(apiUrl, apiKey, path, input = {}) {
20
+ return fetch(`${apiUrl}${path}`, {
21
+ method: "POST",
22
+ headers: {
23
+ "x-api-key": apiKey,
24
+ "Content-Type": "application/json"
25
+ },
26
+ body: JSON.stringify({ json: input })
27
+ });
28
+ }
29
+ async function pollDeployment(apiUrl, apiKey, deploymentId, pollIntervalMs, maxWaitMs) {
30
+ const start = Date.now();
31
+ let status = "building";
32
+ let deployment;
33
+ while (status === "building" && Date.now() - start < maxWaitMs) {
34
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
35
+ const res = await postJson(apiUrl, apiKey, "/v1/deployments/get", {
36
+ id: deploymentId
37
+ });
38
+ const body = await res.json();
39
+ if (res.status !== 200) {
40
+ throw new Error(
41
+ `Failed to get deployment status (${res.status}): ${JSON.stringify(body)}`
42
+ );
43
+ }
44
+ status = body.json.status;
45
+ deployment = body.json;
46
+ process.stdout.write(".");
47
+ }
48
+ console.log();
49
+ if (!deployment) {
50
+ throw new Error("Deployment timed out before receiving a status update.");
51
+ }
52
+ return deployment;
53
+ }
54
+ const deployInput = SimpleCLI.input({
55
+ positionals: [
56
+ SimpleCLI.positional("sourceDir", z.string().default("."), {
57
+ help: "Path to source directory (default: current directory)"
58
+ })
59
+ ],
60
+ named: {
61
+ name: SimpleCLI.option(z.string(), {
62
+ help: "Deployment name"
63
+ }),
64
+ description: SimpleCLI.option(z.string().optional(), {
65
+ help: "Deployment description"
66
+ }),
67
+ entryPoint: SimpleCLI.option(z.string().optional(), {
68
+ name: "entry-point",
69
+ help: "Entry point file (default: index.ts)"
70
+ }),
71
+ external: SimpleCLI.option(
72
+ z.string().optional().transform(
73
+ (value) => value?.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0) ?? []
74
+ ),
75
+ {
76
+ help: "Comma-separated packages to externalize and install at runtime"
77
+ }
78
+ )
79
+ }
80
+ });
81
+ const deployCommand = SimpleCLI.command({
82
+ description: "[experimental] Deploy workflows to the hosted platform",
83
+ experimental: true
84
+ }).input(deployInput).handle(async ({ input }) => {
85
+ const { apiUrl, apiKey } = getConfig();
86
+ console.log("Bundling hosted deployment artifact...");
87
+ const { entryPoint, source } = await buildHostedDeployTarball({
88
+ additionalExternals: input.external,
89
+ deploymentName: input.name,
90
+ entryPoint: input.entryPoint,
91
+ sourceDir: input.sourceDir
92
+ });
93
+ const createPayload = {
94
+ name: input.name,
95
+ source,
96
+ entry_point: entryPoint
97
+ };
98
+ if (input.description) createPayload.description = input.description;
99
+ console.log("Uploading deployment...");
100
+ const res = await postJson(
101
+ apiUrl,
102
+ apiKey,
103
+ "/v1/deployments/create",
104
+ createPayload
105
+ );
106
+ const body = await res.json();
107
+ if (res.status !== 200) {
108
+ throw new Error(
109
+ `Failed to create deployment (${res.status}): ${JSON.stringify(body)}`
110
+ );
111
+ }
112
+ const { deployment_id, name, version, status } = body.json;
113
+ console.log(
114
+ `Deployment created: ${name} v${version} (${deployment_id})`
115
+ );
116
+ console.log(`Status: ${status}`);
117
+ if (status === "building") {
118
+ process.stdout.write("Waiting for build");
119
+ const deployment = await pollDeployment(
120
+ apiUrl,
121
+ apiKey,
122
+ deployment_id,
123
+ 1e4,
124
+ 5 * 60 * 1e3
125
+ );
126
+ if (deployment.status === "failed") {
127
+ throw new Error(
128
+ `Build failed: ${deployment.build_error ?? "unknown error"}`
129
+ );
130
+ }
131
+ if (deployment.status === "ready") {
132
+ console.log(`Build complete.`);
133
+ if (deployment.workflows?.length) {
134
+ console.log(
135
+ `Workflows: ${deployment.workflows.join(", ")}`
136
+ );
137
+ }
138
+ } else {
139
+ console.log(
140
+ `Build still in progress (timed out waiting). Check status with deployment ID: ${deployment_id}`
141
+ );
142
+ }
143
+ }
144
+ return deployment_id;
145
+ });
146
+ export {
147
+ deployCommand,
148
+ deployInput
149
+ };