@pipelex/sdk 0.32.0 → 0.34.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 +40 -5
- package/dist/artifacts.js +23 -9
- package/dist/artifacts.js.map +1 -1
- package/dist/cli/args.d.ts +41 -0
- package/dist/cli/args.js +96 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bundle.d.ts +45 -0
- package/dist/cli/bundle.js +148 -0
- package/dist/cli/bundle.js.map +1 -0
- package/dist/cli/environment.d.ts +36 -0
- package/dist/cli/environment.js +72 -0
- package/dist/cli/environment.js.map +1 -0
- package/dist/cli/help.d.ts +4 -0
- package/dist/cli/help.js +56 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/inputs.d.ts +13 -0
- package/dist/cli/inputs.js +70 -0
- package/dist/cli/inputs.js.map +1 -0
- package/dist/cli/io.d.ts +79 -0
- package/dist/cli/io.js +96 -0
- package/dist/cli/io.js.map +1 -0
- package/dist/cli/main.d.ts +18 -0
- package/dist/cli/main.js +58 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/method.d.ts +56 -0
- package/dist/cli/method.js +108 -0
- package/dist/cli/method.js.map +1 -0
- package/dist/cli/present.d.ts +43 -0
- package/dist/cli/present.js +191 -0
- package/dist/cli/present.js.map +1 -0
- package/dist/cli/run.d.ts +17 -0
- package/dist/cli/run.js +290 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/script.d.ts +23 -0
- package/dist/cli/script.js +212 -0
- package/dist/cli/script.js.map +1 -0
- package/dist/cli/source.d.ts +49 -0
- package/dist/cli/source.js +71 -0
- package/dist/cli/source.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +125 -17
- package/dist/client.js +383 -109
- package/dist/client.js.map +1 -1
- package/dist/codegen-check.d.ts +9 -0
- package/dist/codegen-check.js +12 -6
- package/dist/codegen-check.js.map +1 -1
- package/dist/error-models.d.ts +60 -2
- package/dist/error-models.js +169 -3
- package/dist/error-models.js.map +1 -1
- package/dist/error-verdicts.d.ts +34 -0
- package/dist/error-verdicts.js +69 -0
- package/dist/error-verdicts.js.map +1 -0
- package/dist/errors.d.ts +250 -48
- package/dist/errors.js +330 -64
- package/dist/errors.js.map +1 -1
- package/dist/hooks/validate-client.d.ts +3 -3
- package/dist/hooks/validate-client.js +3 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/prepare-inputs.d.ts +6 -0
- package/dist/prepare-inputs.js +46 -14
- package/dist/prepare-inputs.js.map +1 -1
- package/dist/runs.d.ts +28 -1
- package/dist/runs.js +2 -1
- package/dist/runs.js.map +1 -1
- package/dist/upload-grant.d.ts +15 -10
- package/dist/upload-grant.js +36 -17
- package/dist/upload-grant.js.map +1 -1
- package/dist/upload.d.ts +6 -0
- package/dist/upload.js +25 -7
- package/dist/upload.js.map +1 -1
- package/dist/user-agent.d.ts +3 -2
- package/dist/user-agent.js +3 -2
- package/dist/user-agent.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/architecture.md +15 -9
- package/docs/artifact-download.md +3 -3
- package/docs/cli.md +123 -0
- package/docs/client-identification.md +1 -1
- package/docs/errors.md +96 -11
- package/docs/input-preparation.md +16 -8
- package/docs/run-results.md +20 -0
- package/package.json +5 -1
package/dist/cli/run.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pipelex-sdk run`: run one method and print its main output.
|
|
3
|
+
*
|
|
4
|
+
* Every check that needs no request comes first, in this order, so that a mistake costs nothing:
|
|
5
|
+
* the flags, `--pipe`'s form, the method (a path is read from disk), the inputs, the poll interval
|
|
6
|
+
* and the key. Then the inputs are prepared, which uploads each local file at a file input; the
|
|
7
|
+
* run is started through the SDK's start-and-wait, whose `onStarted` gives the run id to stderr
|
|
8
|
+
* as soon as the run exists; and the main output reaches stdout once the run completes, however
|
|
9
|
+
* long that takes.
|
|
10
|
+
*/
|
|
11
|
+
import { ApiResponseError, ApiUnreachableError, MissingMainStuffError, PipelineExecuteTimeoutError, RunFailedError, isGatewayCutOff, renderInputsTemplate, } from "../index.js";
|
|
12
|
+
import { parseFlags } from "./args.js";
|
|
13
|
+
import { readBundle } from "./bundle.js";
|
|
14
|
+
import { makeClient, readPollInterval } from "./environment.js";
|
|
15
|
+
import { RUN_HELP } from "./help.js";
|
|
16
|
+
import { readInputs } from "./inputs.js";
|
|
17
|
+
import { CommandError, EXIT_INTERRUPTED, EXIT_OK, Interrupted, untilInterrupted, usageError, writeLines, } from "./io.js";
|
|
18
|
+
import { checkPipeRef, classifyMethod } from "./method.js";
|
|
19
|
+
import { presentError, printResult } from "./present.js";
|
|
20
|
+
import { crateSelector, describePipe, runSelector } from "./source.js";
|
|
21
|
+
const RUN_FLAGS = {
|
|
22
|
+
method: { type: "string" },
|
|
23
|
+
pipe: { type: "string" },
|
|
24
|
+
inputs: { type: "string" },
|
|
25
|
+
"inputs-template": { type: "boolean" },
|
|
26
|
+
};
|
|
27
|
+
/** Run `pipelex-sdk run` and return its exit code. */
|
|
28
|
+
export async function runCommandRun(args, io) {
|
|
29
|
+
const flags = parseFlags("run", args, RUN_FLAGS);
|
|
30
|
+
if (flags.help) {
|
|
31
|
+
io.writeStdout(RUN_HELP);
|
|
32
|
+
return EXIT_OK;
|
|
33
|
+
}
|
|
34
|
+
const method = flags.strings.get("method");
|
|
35
|
+
if (method === undefined) {
|
|
36
|
+
throw usageError("--method is required.", ["Run 'pipelex-sdk run --help' to see its flags."]);
|
|
37
|
+
}
|
|
38
|
+
const inputsSource = flags.strings.get("inputs");
|
|
39
|
+
const templateOnly = flags.booleans.has("inputs-template");
|
|
40
|
+
if (templateOnly && inputsSource !== undefined) {
|
|
41
|
+
throw usageError("--inputs-template prints the inputs a run takes, so it takes no --inputs.");
|
|
42
|
+
}
|
|
43
|
+
const pipe = flags.strings.get("pipe");
|
|
44
|
+
if (pipe !== undefined)
|
|
45
|
+
checkPipeRef(pipe);
|
|
46
|
+
let stage = { kind: "local" };
|
|
47
|
+
try {
|
|
48
|
+
// Raced like the inputs read: a bundle on a stalled mount must not hold the command.
|
|
49
|
+
const source = await untilInterrupted(() => methodSource(method), io.interrupt);
|
|
50
|
+
const inputs = inputsSource === undefined ? undefined : await readInputs(inputsSource, io);
|
|
51
|
+
const intervalMs = readPollInterval(io);
|
|
52
|
+
const client = makeClient(io);
|
|
53
|
+
if (templateOnly) {
|
|
54
|
+
const described = await describePipe(client, source, pipe, io.interrupt);
|
|
55
|
+
const template = renderInputsTemplate(described.descriptor, {
|
|
56
|
+
explicit: false,
|
|
57
|
+
format: "json",
|
|
58
|
+
});
|
|
59
|
+
io.writeStdout(`${template}\n`);
|
|
60
|
+
return EXIT_OK;
|
|
61
|
+
}
|
|
62
|
+
const prepared = await prepare(client, source, pipe, inputs, io);
|
|
63
|
+
const results = await untilInterrupted(() => {
|
|
64
|
+
return client.startAndWaitForResult({
|
|
65
|
+
...runSelector(source),
|
|
66
|
+
...(pipe === undefined ? {} : { pipe_code: pipe }),
|
|
67
|
+
...(prepared === undefined ? {} : { inputs: prepared }),
|
|
68
|
+
}, {
|
|
69
|
+
// A run takes as long as it takes: the command waits for it until it ends or the
|
|
70
|
+
// person interrupts.
|
|
71
|
+
timeoutMs: Number.POSITIVE_INFINITY,
|
|
72
|
+
...(intervalMs === undefined ? {} : { intervalMs }),
|
|
73
|
+
signal: io.interrupt,
|
|
74
|
+
artifacts: ["main_stuff"],
|
|
75
|
+
onStarting: () => {
|
|
76
|
+
// Only once a request that may create a run is about to leave: an interrupt before
|
|
77
|
+
// it, during the version handshake included, starts nothing, and the command says so.
|
|
78
|
+
stage = { kind: "starting", since: performance.now() };
|
|
79
|
+
},
|
|
80
|
+
onStarted: (ack) => {
|
|
81
|
+
if (io.interrupt.aborted)
|
|
82
|
+
return;
|
|
83
|
+
stage = { kind: "started", runId: ack.pipeline_run_id };
|
|
84
|
+
io.writeStderr(`Run started: ${ack.pipeline_run_id}\n`);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}, io.interrupt);
|
|
88
|
+
printResult(results.main_stuff, io);
|
|
89
|
+
return EXIT_OK;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (!(error instanceof Interrupted)) {
|
|
93
|
+
const runId = waitedOnRun(stage, error);
|
|
94
|
+
const warning = runId !== undefined
|
|
95
|
+
? runStillGoingLine(runId)
|
|
96
|
+
: mayHaveStarted(stage, error)
|
|
97
|
+
? RUN_MAY_HAVE_STARTED_LINE
|
|
98
|
+
: undefined;
|
|
99
|
+
if (warning === undefined)
|
|
100
|
+
throw error;
|
|
101
|
+
// A failure that says nothing of a run that exists, or may: a wrapper must not read it as a
|
|
102
|
+
// failed run and pay for another.
|
|
103
|
+
const presented = presentError(error);
|
|
104
|
+
writeLines(io, [...presented.lines, warning]);
|
|
105
|
+
return presented.exitCode;
|
|
106
|
+
}
|
|
107
|
+
throw new CommandError(interruptMessage(stage, templateOnly), {
|
|
108
|
+
exitCode: EXIT_INTERRUPTED,
|
|
109
|
+
bare: true,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The run a failure leaves going on the server: the run that exists when the failure is not its
|
|
115
|
+
* own outcome, a failed run or a completed one without its output, but an unreachable API or a
|
|
116
|
+
* refused poll.
|
|
117
|
+
*/
|
|
118
|
+
function waitedOnRun(stage, error) {
|
|
119
|
+
if (stage.kind !== "started")
|
|
120
|
+
return undefined;
|
|
121
|
+
if (error instanceof RunFailedError || error instanceof MissingMainStuffError)
|
|
122
|
+
return undefined;
|
|
123
|
+
return stage.runId;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Whether a transport failure proves the request never left, so that no run was created by it: it
|
|
127
|
+
* names a step of the connection's set-up, which no request follows. That is the name lookup or
|
|
128
|
+
* the connection itself failing (the system calls `getaddrinfo` and `connect`: an unknown host, a
|
|
129
|
+
* refused connection, no route to the host or the network, the system's connect time limit),
|
|
130
|
+
* undici's own connect time limit, which covers the TLS handshake, and a server certificate the
|
|
131
|
+
* TLS handshake refused. Several addresses each failing so, which Node reports together as an
|
|
132
|
+
* `AggregateError`, prove it too. A host that drops packets is a connection that never comes:
|
|
133
|
+
* undici gives it up after ten seconds (`UND_ERR_CONNECT_TIMEOUT`), before the time limit of any
|
|
134
|
+
* request the command sends, as the Python command meets httpx's connect timeout first and reads
|
|
135
|
+
* it the same way.
|
|
136
|
+
*
|
|
137
|
+
* Anything else may have come once the request had left, the Python command reading the same
|
|
138
|
+
* failures the same way. A reset (`ECONNRESET`) comes from a `read` whether the connection dropped
|
|
139
|
+
* during the TLS handshake or after the request, and so does an `EHOSTUNREACH` met once connected,
|
|
140
|
+
* so neither proves anything; nor does another TLS failure, which may come after the handshake;
|
|
141
|
+
* nor does the SDK's own time limit (`ABORT_TIMEOUT`), which fetch cannot place before or after
|
|
142
|
+
* the connection was made. Every request the command sends has a limit longer than undici's
|
|
143
|
+
* connect limit, so with Node's own dispatcher it runs out only once the request has left.
|
|
144
|
+
*/
|
|
145
|
+
function provesNothingSent(error) {
|
|
146
|
+
// The SDK keeps fetch's own failure as `cause`, and undici gives the transport's under it.
|
|
147
|
+
const fetchFailure = error.cause;
|
|
148
|
+
return fetchFailure instanceof Error && isConnectionSetupFailure(fetchFailure.cause);
|
|
149
|
+
}
|
|
150
|
+
function isConnectionSetupFailure(failure) {
|
|
151
|
+
if (failure instanceof AggregateError) {
|
|
152
|
+
return failure.errors.length > 0 && failure.errors.every(isConnectionSetupFailure);
|
|
153
|
+
}
|
|
154
|
+
if (typeof failure !== "object" || failure === null)
|
|
155
|
+
return false;
|
|
156
|
+
const { code, syscall } = failure;
|
|
157
|
+
if (typeof code === "string" && CONNECTION_SETUP_CODES.has(code))
|
|
158
|
+
return true;
|
|
159
|
+
return typeof syscall === "string" && CONNECTION_SETUP_CALLS.has(syscall);
|
|
160
|
+
}
|
|
161
|
+
/** The system calls that resolve the host's name and open the connection. */
|
|
162
|
+
const CONNECTION_SETUP_CALLS = new Set(["getaddrinfo", "connect"]);
|
|
163
|
+
/**
|
|
164
|
+
* The codes only a step of the connection's set-up gives: the name lookup's and the connect call's
|
|
165
|
+
* own (set even where Node reports several addresses together, without a system call), undici's
|
|
166
|
+
* connect time limit, Node's limit on one attempt among several addresses, Node's own check of the
|
|
167
|
+
* host's name, and every code Node gives a server certificate the TLS handshake refused.
|
|
168
|
+
*/
|
|
169
|
+
const CONNECTION_SETUP_CODES = new Set([
|
|
170
|
+
"ECONNREFUSED",
|
|
171
|
+
"ENOTFOUND",
|
|
172
|
+
"EAI_AGAIN",
|
|
173
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
174
|
+
"ERR_SOCKET_CONNECTION_TIMEOUT",
|
|
175
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
176
|
+
"ERR_TLS_CERT_ALTNAME_FORMAT",
|
|
177
|
+
// Node names the verdicts of OpenSSL's certificate check from a fixed table, the "X509 certificate
|
|
178
|
+
// error codes" of its `tls` docs, and gives every other verdict, such as an unhandled critical
|
|
179
|
+
// extension or a CA certificate that may not sign certificates, the code `UNSPECIFIED`. The
|
|
180
|
+
// error carries nothing else that marks it, so these codes are the mark: the table as Node 24
|
|
181
|
+
// compiles it, in its order, then its default. The Python command reads every
|
|
182
|
+
// `ssl.SSLCertVerificationError` the same way.
|
|
183
|
+
"UNABLE_TO_GET_ISSUER_CERT",
|
|
184
|
+
"UNABLE_TO_GET_CRL",
|
|
185
|
+
"UNABLE_TO_DECRYPT_CERT_SIGNATURE",
|
|
186
|
+
"UNABLE_TO_DECRYPT_CRL_SIGNATURE",
|
|
187
|
+
"UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY",
|
|
188
|
+
"CERT_SIGNATURE_FAILURE",
|
|
189
|
+
"CRL_SIGNATURE_FAILURE",
|
|
190
|
+
"CERT_NOT_YET_VALID",
|
|
191
|
+
"CERT_HAS_EXPIRED",
|
|
192
|
+
"CRL_NOT_YET_VALID",
|
|
193
|
+
"CRL_HAS_EXPIRED",
|
|
194
|
+
"ERROR_IN_CERT_NOT_BEFORE_FIELD",
|
|
195
|
+
"ERROR_IN_CERT_NOT_AFTER_FIELD",
|
|
196
|
+
"ERROR_IN_CRL_LAST_UPDATE_FIELD",
|
|
197
|
+
"ERROR_IN_CRL_NEXT_UPDATE_FIELD",
|
|
198
|
+
"OUT_OF_MEM",
|
|
199
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
200
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
201
|
+
"UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
202
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
203
|
+
"CERT_CHAIN_TOO_LONG",
|
|
204
|
+
"CERT_REVOKED",
|
|
205
|
+
"INVALID_CA",
|
|
206
|
+
"PATH_LENGTH_EXCEEDED",
|
|
207
|
+
"INVALID_PURPOSE",
|
|
208
|
+
"CERT_UNTRUSTED",
|
|
209
|
+
"CERT_REJECTED",
|
|
210
|
+
"HOSTNAME_MISMATCH",
|
|
211
|
+
"UNSPECIFIED",
|
|
212
|
+
]);
|
|
213
|
+
/**
|
|
214
|
+
* Whether a failure met once a request that may create a run was sent, and before the API named
|
|
215
|
+
* the run, leaves it unknown whether one was created: its answer was lost to a time limit, a
|
|
216
|
+
* connection that closed once the request had left or a gateway that cut the request off, or it
|
|
217
|
+
* came back unreadable, or a gateway answered that it lost or never got the server's answer
|
|
218
|
+
* (`502`, `504`, RFC 9110). A gateway cuts a request off at ~30 seconds, whether a blocking
|
|
219
|
+
* execute or a start the server is still handling, such as one fetching a `method_ref`'s package:
|
|
220
|
+
* the SDK's `isGatewayCutOff` tells it, past its threshold, from the time since `onStarting`. Any
|
|
221
|
+
* other answer from the API, a `503` that came back before that saying the request was not handled
|
|
222
|
+
* included, and a failure that proves nothing was sent, say no run was created.
|
|
223
|
+
*/
|
|
224
|
+
function mayHaveStarted(stage, error) {
|
|
225
|
+
if (stage.kind !== "starting")
|
|
226
|
+
return false;
|
|
227
|
+
if (error instanceof PipelineExecuteTimeoutError)
|
|
228
|
+
return true;
|
|
229
|
+
if (error instanceof ApiUnreachableError)
|
|
230
|
+
return !provesNothingSent(error);
|
|
231
|
+
if (!(error instanceof ApiResponseError))
|
|
232
|
+
return false;
|
|
233
|
+
if (error.status >= 200 && error.status < 300)
|
|
234
|
+
return true;
|
|
235
|
+
return (GATEWAY_LOST_ANSWER.has(error.status) || isGatewayCutOff(error, performance.now() - stage.since));
|
|
236
|
+
}
|
|
237
|
+
/** The gateway statuses that say the server's answer was lost or never came (RFC 9110). */
|
|
238
|
+
const GATEWAY_LOST_ANSWER = new Set([502, 504]);
|
|
239
|
+
/** The line under a failure that leaves it unknown whether a run was created. */
|
|
240
|
+
export const RUN_MAY_HAVE_STARTED_LINE = "A run may have started on the server without the command learning of it, so check before starting it again.";
|
|
241
|
+
/** The line under a failure met while waiting on a run that exists. */
|
|
242
|
+
export function runStillGoingLine(runId) {
|
|
243
|
+
return `Run ${runId} may still be going on the server, so do not start it again.`;
|
|
244
|
+
}
|
|
245
|
+
/** The method `--method` names, a path being read from disk. */
|
|
246
|
+
async function methodSource(method) {
|
|
247
|
+
const selector = classifyMethod(method);
|
|
248
|
+
switch (selector.kind) {
|
|
249
|
+
case "address":
|
|
250
|
+
return { kind: "address", methodRef: selector.methodRef };
|
|
251
|
+
case "catalog":
|
|
252
|
+
return { kind: "catalog", methodId: selector.methodId };
|
|
253
|
+
case "path":
|
|
254
|
+
return { kind: "bundle", files: await readBundle(selector.path) };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Upload the local files the inputs name at the method's file inputs, through the SDK's input
|
|
259
|
+
* preparation, and report each upload on stderr. Inputs that are absent or empty are sent as they
|
|
260
|
+
* are, with no request: there is nothing to upload.
|
|
261
|
+
*/
|
|
262
|
+
async function prepare(client, source, pipe, inputs, io) {
|
|
263
|
+
if (inputs === undefined || Object.keys(inputs).length === 0)
|
|
264
|
+
return inputs;
|
|
265
|
+
const prepared = await untilInterrupted(() => client.prepareInputs({
|
|
266
|
+
...crateSelector(source),
|
|
267
|
+
...(pipe === undefined ? {} : { pipe_ref: pipe }),
|
|
268
|
+
inputs,
|
|
269
|
+
// Once interrupted, no upload starts after the pipe I/O answer arrives.
|
|
270
|
+
signal: io.interrupt,
|
|
271
|
+
}), io.interrupt);
|
|
272
|
+
for (const upload of prepared.uploads) {
|
|
273
|
+
io.writeStderr(`Uploaded ${upload.filename} as ${upload.uri}\n`);
|
|
274
|
+
}
|
|
275
|
+
return prepared.inputs;
|
|
276
|
+
}
|
|
277
|
+
/** What an interrupt says, by where the run stood. */
|
|
278
|
+
function interruptMessage(stage, templateOnly) {
|
|
279
|
+
if (templateOnly)
|
|
280
|
+
return "Interrupted.";
|
|
281
|
+
switch (stage.kind) {
|
|
282
|
+
case "local":
|
|
283
|
+
return "Interrupted. No run was started.";
|
|
284
|
+
case "starting":
|
|
285
|
+
return "Interrupted before the API answered with a run id. A run may or may not have started on the server.";
|
|
286
|
+
case "started":
|
|
287
|
+
return `Interrupted. Run ${stage.runId} keeps going on the server.`;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pipelex-sdk script`: write the per-method command, a short shell script that runs one method
|
|
3
|
+
* through this SDK's `run`, its version pinned.
|
|
4
|
+
*
|
|
5
|
+
* The checks that need no request come first, in this order: the flags, `--pipe`'s form, a
|
|
6
|
+
* control character in any value the script would carry, the method's form (a local bundle is
|
|
7
|
+
* refused), `--name`, `--dir`, the target file when its name is already known, and the key. Then
|
|
8
|
+
* one pipe I/O call checks the method and the pipe, which spends no inference; a catalog id with
|
|
9
|
+
* no `--name` is named from its catalog entry; and the file is written, never over an existing
|
|
10
|
+
* one, with the permissions of an executable, an interrupt meanwhile waiting until it is whole.
|
|
11
|
+
*/
|
|
12
|
+
import type { CommandIO } from "./io.js";
|
|
13
|
+
/** The package a written script runs, and what its runner needs. */
|
|
14
|
+
export declare const SCRIPT_RUNNER = "npx --yes @pipelex/sdk@0.34.0";
|
|
15
|
+
export declare const SCRIPT_WRITER = "@pipelex/sdk";
|
|
16
|
+
export declare const SCRIPT_NEEDS = "Node 22.12 or later";
|
|
17
|
+
/** Run `pipelex-sdk script` and return its exit code. */
|
|
18
|
+
export declare function runCommandScript(args: readonly string[], io: CommandIO): Promise<number>;
|
|
19
|
+
/**
|
|
20
|
+
* The script's text: the shebang, a header saying what it runs, which SDK wrote it, what it needs
|
|
21
|
+
* and how to use it, and the one line that runs it, every value single-quoted.
|
|
22
|
+
*/
|
|
23
|
+
export declare function scriptBody(name: string, method: string, pipe: string | undefined): string;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pipelex-sdk script`: write the per-method command, a short shell script that runs one method
|
|
3
|
+
* through this SDK's `run`, its version pinned.
|
|
4
|
+
*
|
|
5
|
+
* The checks that need no request come first, in this order: the flags, `--pipe`'s form, a
|
|
6
|
+
* control character in any value the script would carry, the method's form (a local bundle is
|
|
7
|
+
* refused), `--name`, `--dir`, the target file when its name is already known, and the key. Then
|
|
8
|
+
* one pipe I/O call checks the method and the pipe, which spends no inference; a catalog id with
|
|
9
|
+
* no `--name` is named from its catalog entry; and the file is written, never over an existing
|
|
10
|
+
* one, with the permissions of an executable, an interrupt meanwhile waiting until it is whole.
|
|
11
|
+
*/
|
|
12
|
+
import { lstat, open, stat, unlink } from "node:fs/promises";
|
|
13
|
+
import { resolve } from "node:path";
|
|
14
|
+
import { SDK_VERSION } from "../index.js";
|
|
15
|
+
import { parseFlags } from "./args.js";
|
|
16
|
+
import { systemReason } from "./bundle.js";
|
|
17
|
+
import { makeClient } from "./environment.js";
|
|
18
|
+
import { SCRIPT_HELP } from "./help.js";
|
|
19
|
+
import { CommandError, EXIT_INTERRUPTED, EXIT_OK, Interrupted, untilInterrupted, usageError, } from "./io.js";
|
|
20
|
+
import { addressName, addressTag, checkPipeRef, classifyMethod, hasControlCharacter, kebabCase, scriptNameProblem, shellQuote, } from "./method.js";
|
|
21
|
+
import { describePipe } from "./source.js";
|
|
22
|
+
const SCRIPT_FLAGS = {
|
|
23
|
+
method: { type: "string" },
|
|
24
|
+
pipe: { type: "string" },
|
|
25
|
+
name: { type: "string" },
|
|
26
|
+
dir: { type: "string" },
|
|
27
|
+
};
|
|
28
|
+
/** The package a written script runs, and what its runner needs. */
|
|
29
|
+
export const SCRIPT_RUNNER = `npx --yes @pipelex/sdk@${SDK_VERSION}`;
|
|
30
|
+
export const SCRIPT_WRITER = "@pipelex/sdk";
|
|
31
|
+
export const SCRIPT_NEEDS = "Node 22.12 or later";
|
|
32
|
+
/** Run `pipelex-sdk script` and return its exit code. */
|
|
33
|
+
export async function runCommandScript(args, io) {
|
|
34
|
+
const flags = parseFlags("script", args, SCRIPT_FLAGS);
|
|
35
|
+
if (flags.help) {
|
|
36
|
+
io.writeStdout(SCRIPT_HELP);
|
|
37
|
+
return EXIT_OK;
|
|
38
|
+
}
|
|
39
|
+
const method = flags.strings.get("method");
|
|
40
|
+
if (method === undefined) {
|
|
41
|
+
throw usageError("--method is required.", [
|
|
42
|
+
"Run 'pipelex-sdk script --help' to see its flags.",
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
const pipe = flags.strings.get("pipe");
|
|
46
|
+
if (pipe !== undefined)
|
|
47
|
+
checkPipeRef(pipe);
|
|
48
|
+
const givenName = flags.strings.get("name");
|
|
49
|
+
for (const [flag, value] of [
|
|
50
|
+
["--method", method],
|
|
51
|
+
["--pipe", pipe],
|
|
52
|
+
["--name", givenName],
|
|
53
|
+
]) {
|
|
54
|
+
if (value !== undefined && hasControlCharacter(value)) {
|
|
55
|
+
throw usageError(`${flag} holds a control character, which no line of a script may carry.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const selector = classifyMethod(method);
|
|
59
|
+
if (selector.kind === "path") {
|
|
60
|
+
throw usageError(`script takes a method address or a catalog id, and "${method}" is neither: a script naming a local bundle breaks as soon as the script or the bundle moves.`, [
|
|
61
|
+
"Publish the method in a git repository and pass its address: github.com/<owner>/<repo>[/<package>]@<tag>",
|
|
62
|
+
"Or save it to your organization's catalog and pass its id: mt_...",
|
|
63
|
+
"To run a local bundle, use: pipelex-sdk run --method <path>",
|
|
64
|
+
]);
|
|
65
|
+
}
|
|
66
|
+
const source = selector.kind === "address"
|
|
67
|
+
? { kind: "address", methodRef: selector.methodRef }
|
|
68
|
+
: { kind: "catalog", methodId: selector.methodId };
|
|
69
|
+
if (givenName !== undefined) {
|
|
70
|
+
const problem = scriptNameProblem(givenName);
|
|
71
|
+
if (problem !== undefined)
|
|
72
|
+
throw usageError(`--name ${problem}.`);
|
|
73
|
+
}
|
|
74
|
+
const dir = flags.strings.get("dir");
|
|
75
|
+
const shownDir = dir === undefined ? "." : dir.replace(/\/+$/, "");
|
|
76
|
+
await checkDirectory(dir ?? ".");
|
|
77
|
+
let name = givenName;
|
|
78
|
+
if (name === undefined && source.kind === "address") {
|
|
79
|
+
name = defaultName(addressName(source.methodRef), method);
|
|
80
|
+
}
|
|
81
|
+
if (name !== undefined)
|
|
82
|
+
await checkFree(shownDir, name);
|
|
83
|
+
const client = makeClient(io);
|
|
84
|
+
try {
|
|
85
|
+
await describePipe(client, source, pipe, io.interrupt);
|
|
86
|
+
if (name === undefined && source.kind === "catalog") {
|
|
87
|
+
name = defaultName(await catalogName(client, source.methodId, io), method);
|
|
88
|
+
await checkFree(shownDir, name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (!(error instanceof Interrupted))
|
|
93
|
+
throw error;
|
|
94
|
+
throw new CommandError("Interrupted. Nothing was written.", {
|
|
95
|
+
exitCode: EXIT_INTERRUPTED,
|
|
96
|
+
bare: true,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (name === undefined)
|
|
100
|
+
throw new Error("a script's name is known once the method is checked");
|
|
101
|
+
if (source.kind === "address" && addressTag(source.methodRef) === undefined) {
|
|
102
|
+
io.writeStderr(`Warning: ${source.methodRef} has no tag, so the script runs whatever its repository's default branch holds each time it runs. Add @<tag> to pin a release.\n`);
|
|
103
|
+
}
|
|
104
|
+
const target = `${shownDir}/${name}`;
|
|
105
|
+
// The last check before the file exists: an interrupt that landed during the checks above
|
|
106
|
+
// writes nothing.
|
|
107
|
+
if (io.interrupt.aborted) {
|
|
108
|
+
throw new CommandError("Interrupted. Nothing was written.", {
|
|
109
|
+
exitCode: EXIT_INTERRUPTED,
|
|
110
|
+
bare: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// The write is not raced with the interrupt: one that lands meanwhile waits for the file to be
|
|
114
|
+
// whole, then says it was written, so that the message is true wherever it lands.
|
|
115
|
+
await writeScript(target, scriptBody(name, method, pipe));
|
|
116
|
+
if (io.interrupt.aborted) {
|
|
117
|
+
throw new CommandError(`Interrupted. ${target} was written.`, {
|
|
118
|
+
exitCode: EXIT_INTERRUPTED,
|
|
119
|
+
bare: true,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
io.writeStdout(`${target}\n`);
|
|
123
|
+
io.writeStderr(`Wrote ${target}. Run it with: ${target} --inputs inputs.json\n`);
|
|
124
|
+
return EXIT_OK;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Create the file, executable, refusing one that exists, a dangling link included (`wx`). A write
|
|
128
|
+
* that fails once the file exists removes it, so that a script is either whole or absent: a
|
|
129
|
+
* truncated one would run half a command, and would make the next attempt say it already exists.
|
|
130
|
+
* The one exception is a second Ctrl-C, which ends the process at once (`cli.ts`): landing between
|
|
131
|
+
* the file's creation and the end of its write, it leaves that file behind, empty or partial, as
|
|
132
|
+
* `docs/cli.md` says. On a local disk that takes no time, but a write can block on a stalled mount.
|
|
133
|
+
*/
|
|
134
|
+
async function writeScript(target, body) {
|
|
135
|
+
const path = resolve(target);
|
|
136
|
+
let handle;
|
|
137
|
+
try {
|
|
138
|
+
handle = await open(path, "wx", 0o755);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (error.code === "EEXIST")
|
|
142
|
+
throw alreadyThere(target);
|
|
143
|
+
throw usageError(`cannot write "${target}".`, [`Reason: ${systemReason(error)}`]);
|
|
144
|
+
}
|
|
145
|
+
// The write's own failure is the one reported, a failed close the next.
|
|
146
|
+
const failures = [];
|
|
147
|
+
await handle.writeFile(body).catch((error) => failures.push(error));
|
|
148
|
+
await handle.close().catch((error) => failures.push(error));
|
|
149
|
+
if (failures.length > 0) {
|
|
150
|
+
await unlink(path).catch(() => undefined);
|
|
151
|
+
throw usageError(`cannot write "${target}".`, [`Reason: ${systemReason(failures[0])}`]);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The script's text: the shebang, a header saying what it runs, which SDK wrote it, what it needs
|
|
156
|
+
* and how to use it, and the one line that runs it, every value single-quoted.
|
|
157
|
+
*/
|
|
158
|
+
export function scriptBody(name, method, pipe) {
|
|
159
|
+
const pipeArgument = pipe === undefined ? "" : ` --pipe ${shellQuote(pipe)}`;
|
|
160
|
+
return [
|
|
161
|
+
"#!/bin/sh",
|
|
162
|
+
`# ${name}: runs ${method} on the Pipelex API.`,
|
|
163
|
+
`# Written by ${SCRIPT_WRITER} ${SDK_VERSION}. Needs ${SCRIPT_NEEDS}, and PIPELEX_API_KEY in the environment.`,
|
|
164
|
+
`# Usage: ./${name} --inputs inputs.json, or ./${name} --inputs-template to see what to fill in.`,
|
|
165
|
+
`exec ${SCRIPT_RUNNER} run --method ${shellQuote(method)}${pipeArgument} "$@"`,
|
|
166
|
+
"",
|
|
167
|
+
].join("\n");
|
|
168
|
+
}
|
|
169
|
+
/** A default name, held to the rules of a file name, or the usage error asking for `--name`. */
|
|
170
|
+
function defaultName(candidate, method) {
|
|
171
|
+
if (scriptNameProblem(candidate) !== undefined) {
|
|
172
|
+
throw usageError(`no script name can be made from "${method}"; give one with --name.`);
|
|
173
|
+
}
|
|
174
|
+
return candidate;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* A catalog method's name, kebab-cased, read from its catalog entry. An entry whose name is
|
|
178
|
+
* missing or not a string gives an empty one, which asks for `--name` as an unusable name does.
|
|
179
|
+
*/
|
|
180
|
+
async function catalogName(client, methodId, io) {
|
|
181
|
+
const entry = await untilInterrupted(() => client.getMethod(methodId), io.interrupt);
|
|
182
|
+
const name = entry.name;
|
|
183
|
+
return typeof name === "string" ? kebabCase(name) : "";
|
|
184
|
+
}
|
|
185
|
+
async function checkDirectory(dir) {
|
|
186
|
+
let found;
|
|
187
|
+
try {
|
|
188
|
+
found = await stat(resolve(dir));
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
throw usageError(`--dir "${dir}" does not exist.`, [`Reason: ${systemReason(error)}`]);
|
|
192
|
+
}
|
|
193
|
+
if (!found.isDirectory())
|
|
194
|
+
throw usageError(`--dir "${dir}" is not a directory.`);
|
|
195
|
+
}
|
|
196
|
+
/** Refuse a target that exists, whatever it is, a link that leads nowhere included. */
|
|
197
|
+
async function checkFree(shownDir, name) {
|
|
198
|
+
const target = `${shownDir}/${name}`;
|
|
199
|
+
try {
|
|
200
|
+
await lstat(resolve(target));
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
throw alreadyThere(target);
|
|
206
|
+
}
|
|
207
|
+
function alreadyThere(target) {
|
|
208
|
+
return usageError(`"${target}" already exists, and script never overwrites a file.`, [
|
|
209
|
+
"Remove it, or choose another name with --name or another directory with --dir.",
|
|
210
|
+
]);
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.js","sourceRoot":"","sources":["../../src/cli/script.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The method as each route names it, and the one pipe I/O call that checks it.
|
|
3
|
+
*
|
|
4
|
+
* A bundle read from disk travels to the pipe I/O route as `files`, each file under its name in the
|
|
5
|
+
* bundle, and to the run as `mthds_contents`, in the same order. An address travels as
|
|
6
|
+
* `method_ref` and a catalog id as `method_id`, both resolved by the server.
|
|
7
|
+
*/
|
|
8
|
+
import type { PipeInputFormDescriptor, PipelexApiClient, PipeIOValidReport, PipelexStartOptions } from "../index.js";
|
|
9
|
+
import type { BundleFile } from "./bundle.js";
|
|
10
|
+
/** A method the command can send: a bundle read from disk, an address or a catalog id. */
|
|
11
|
+
export type MethodSource = {
|
|
12
|
+
readonly kind: "bundle";
|
|
13
|
+
readonly files: readonly BundleFile[];
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "address";
|
|
16
|
+
readonly methodRef: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: "catalog";
|
|
19
|
+
readonly methodId: string;
|
|
20
|
+
};
|
|
21
|
+
/** The method as the crate routes and the input preparation name it. */
|
|
22
|
+
export type CrateSelector = {
|
|
23
|
+
files: Array<{
|
|
24
|
+
content: string;
|
|
25
|
+
source: string;
|
|
26
|
+
}>;
|
|
27
|
+
} | {
|
|
28
|
+
method_ref: string;
|
|
29
|
+
} | {
|
|
30
|
+
method_id: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function crateSelector(source: MethodSource): CrateSelector;
|
|
33
|
+
/** The method as the run routes name it. */
|
|
34
|
+
export declare function runSelector(source: MethodSource): PipelexStartOptions;
|
|
35
|
+
/** A pipe I/O answer's valid arm, and the input form of the pipe it selected. */
|
|
36
|
+
export interface DescribedPipe {
|
|
37
|
+
readonly report: PipeIOValidReport;
|
|
38
|
+
readonly pipeRef: string;
|
|
39
|
+
readonly descriptor: PipeInputFormDescriptor;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Ask `POST /v1/pipe-io` for the pipe the method and `--pipe` select, which spends no inference:
|
|
43
|
+
* the same selection the run's input preparation makes.
|
|
44
|
+
*
|
|
45
|
+
* @throws {CommandError} When the method does not load, or the answer does not describe the pipe
|
|
46
|
+
* it selected. A refusal of the request itself propagates as the SDK's `ApiResponseError`.
|
|
47
|
+
* @throws {Interrupted} When the person interrupts the wait.
|
|
48
|
+
*/
|
|
49
|
+
export declare function describePipe(client: PipelexApiClient, source: MethodSource, pipe: string | undefined, interrupt: AbortSignal): Promise<DescribedPipe>;
|