transloadit 4.7.3 → 4.7.6
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 +897 -5
- package/dist/Transloadit.d.ts +13 -3
- package/dist/Transloadit.d.ts.map +1 -1
- package/dist/Transloadit.js +22 -2
- package/dist/Transloadit.js.map +1 -1
- package/dist/alphalib/types/assembliesGet.d.ts +5 -0
- package/dist/alphalib/types/assembliesGet.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyReplay.d.ts +5 -0
- package/dist/alphalib/types/assemblyReplay.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyReplayNotification.d.ts +5 -0
- package/dist/alphalib/types/assemblyReplayNotification.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyStatus.d.ts +25 -25
- package/dist/alphalib/types/assemblyStatus.d.ts.map +1 -1
- package/dist/alphalib/types/assemblyStatus.js +4 -1
- package/dist/alphalib/types/assemblyStatus.js.map +1 -1
- package/dist/alphalib/types/bill.d.ts +5 -0
- package/dist/alphalib/types/bill.d.ts.map +1 -1
- package/dist/alphalib/types/builtinTemplates.d.ts +83 -0
- package/dist/alphalib/types/builtinTemplates.d.ts.map +1 -0
- package/dist/alphalib/types/builtinTemplates.js +19 -0
- package/dist/alphalib/types/builtinTemplates.js.map +1 -0
- package/dist/alphalib/types/robots/ai-chat.d.ts.map +1 -1
- package/dist/alphalib/types/robots/ai-chat.js +1 -0
- package/dist/alphalib/types/robots/ai-chat.js.map +1 -1
- package/dist/alphalib/types/skillFrontmatter.d.ts +29 -0
- package/dist/alphalib/types/skillFrontmatter.d.ts.map +1 -0
- package/dist/alphalib/types/skillFrontmatter.js +19 -0
- package/dist/alphalib/types/skillFrontmatter.js.map +1 -0
- package/dist/alphalib/types/template.d.ts +36 -0
- package/dist/alphalib/types/template.d.ts.map +1 -1
- package/dist/alphalib/types/template.js +10 -0
- package/dist/alphalib/types/template.js.map +1 -1
- package/dist/alphalib/types/templateCredential.d.ts +10 -0
- package/dist/alphalib/types/templateCredential.d.ts.map +1 -1
- package/dist/bearerToken.d.ts +31 -0
- package/dist/bearerToken.d.ts.map +1 -0
- package/dist/bearerToken.js +158 -0
- package/dist/bearerToken.js.map +1 -0
- package/dist/cli/commands/assemblies.d.ts +8 -2
- package/dist/cli/commands/assemblies.d.ts.map +1 -1
- package/dist/cli/commands/assemblies.js +566 -411
- package/dist/cli/commands/assemblies.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -4
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +7 -123
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +5 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/templates.d.ts.map +1 -1
- package/dist/cli/commands/templates.js +4 -14
- package/dist/cli/commands/templates.js.map +1 -1
- package/dist/cli/fileProcessingOptions.d.ts +35 -0
- package/dist/cli/fileProcessingOptions.d.ts.map +1 -0
- package/dist/cli/fileProcessingOptions.js +182 -0
- package/dist/cli/fileProcessingOptions.js.map +1 -0
- package/dist/cli/generateIntentDocs.d.ts +2 -0
- package/dist/cli/generateIntentDocs.d.ts.map +1 -0
- package/dist/cli/generateIntentDocs.js +321 -0
- package/dist/cli/generateIntentDocs.js.map +1 -0
- package/dist/cli/intentCommandSpecs.d.ts +36 -0
- package/dist/cli/intentCommandSpecs.d.ts.map +1 -0
- package/dist/cli/intentCommandSpecs.js +181 -0
- package/dist/cli/intentCommandSpecs.js.map +1 -0
- package/dist/cli/intentCommands.d.ts +13 -0
- package/dist/cli/intentCommands.d.ts.map +1 -0
- package/dist/cli/intentCommands.js +368 -0
- package/dist/cli/intentCommands.js.map +1 -0
- package/dist/cli/intentFields.d.ts +25 -0
- package/dist/cli/intentFields.d.ts.map +1 -0
- package/dist/cli/intentFields.js +298 -0
- package/dist/cli/intentFields.js.map +1 -0
- package/dist/cli/intentInputPolicy.d.ts +10 -0
- package/dist/cli/intentInputPolicy.d.ts.map +1 -0
- package/dist/cli/intentInputPolicy.js +2 -0
- package/dist/cli/intentInputPolicy.js.map +1 -0
- package/dist/cli/intentRuntime.d.ts +114 -0
- package/dist/cli/intentRuntime.d.ts.map +1 -0
- package/dist/cli/intentRuntime.js +464 -0
- package/dist/cli/intentRuntime.js.map +1 -0
- package/dist/cli/resultFiles.d.ts +19 -0
- package/dist/cli/resultFiles.d.ts.map +1 -0
- package/dist/cli/resultFiles.js +66 -0
- package/dist/cli/resultFiles.js.map +1 -0
- package/dist/cli/resultUrls.d.ts +19 -0
- package/dist/cli/resultUrls.d.ts.map +1 -0
- package/dist/cli/resultUrls.js +36 -0
- package/dist/cli/resultUrls.js.map +1 -0
- package/dist/cli/semanticIntents/imageDescribe.d.ts +43 -0
- package/dist/cli/semanticIntents/imageDescribe.d.ts.map +1 -0
- package/dist/cli/semanticIntents/imageDescribe.js +188 -0
- package/dist/cli/semanticIntents/imageDescribe.js.map +1 -0
- package/dist/cli/semanticIntents/index.d.ts +18 -0
- package/dist/cli/semanticIntents/index.d.ts.map +1 -0
- package/dist/cli/semanticIntents/index.js +18 -0
- package/dist/cli/semanticIntents/index.js.map +1 -0
- package/dist/cli/semanticIntents/markdownPdf.d.ts +4 -0
- package/dist/cli/semanticIntents/markdownPdf.d.ts.map +1 -0
- package/dist/cli/semanticIntents/markdownPdf.js +93 -0
- package/dist/cli/semanticIntents/markdownPdf.js.map +1 -0
- package/dist/cli/semanticIntents/parsing.d.ts +11 -0
- package/dist/cli/semanticIntents/parsing.d.ts.map +1 -0
- package/dist/cli/semanticIntents/parsing.js +29 -0
- package/dist/cli/semanticIntents/parsing.js.map +1 -0
- package/dist/cli/stepsInput.d.ts +4 -0
- package/dist/cli/stepsInput.d.ts.map +1 -0
- package/dist/cli/stepsInput.js +23 -0
- package/dist/cli/stepsInput.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -4
- package/dist/cli.js.map +1 -1
- package/dist/ensureUniqueCounter.d.ts +8 -0
- package/dist/ensureUniqueCounter.d.ts.map +1 -0
- package/dist/ensureUniqueCounter.js +48 -0
- package/dist/ensureUniqueCounter.js.map +1 -0
- package/dist/inputFiles.d.ts +9 -0
- package/dist/inputFiles.d.ts.map +1 -1
- package/dist/inputFiles.js +177 -26
- package/dist/inputFiles.js.map +1 -1
- package/dist/robots.js +1 -1
- package/dist/robots.js.map +1 -1
- package/package.json +9 -7
- package/src/Transloadit.ts +35 -3
- package/src/alphalib/types/assemblyStatus.ts +4 -1
- package/src/alphalib/types/builtinTemplates.ts +24 -0
- package/src/alphalib/types/robots/ai-chat.ts +1 -0
- package/src/alphalib/types/skillFrontmatter.ts +24 -0
- package/src/alphalib/types/template.ts +14 -0
- package/src/bearerToken.ts +208 -0
- package/src/cli/commands/assemblies.ts +825 -505
- package/src/cli/commands/auth.ts +9 -151
- package/src/cli/commands/index.ts +6 -3
- package/src/cli/commands/templates.ts +6 -17
- package/src/cli/fileProcessingOptions.ts +294 -0
- package/src/cli/generateIntentDocs.ts +419 -0
- package/src/cli/intentCommandSpecs.ts +282 -0
- package/src/cli/intentCommands.ts +525 -0
- package/src/cli/intentFields.ts +403 -0
- package/src/cli/intentInputPolicy.ts +11 -0
- package/src/cli/intentRuntime.ts +734 -0
- package/src/cli/resultFiles.ts +105 -0
- package/src/cli/resultUrls.ts +72 -0
- package/src/cli/semanticIntents/imageDescribe.ts +254 -0
- package/src/cli/semanticIntents/index.ts +48 -0
- package/src/cli/semanticIntents/markdownPdf.ts +120 -0
- package/src/cli/semanticIntents/parsing.ts +56 -0
- package/src/cli/stepsInput.ts +32 -0
- package/src/cli.ts +5 -4
- package/src/ensureUniqueCounter.ts +75 -0
- package/src/inputFiles.ts +277 -26
- package/src/robots.ts +1 -1
package/src/cli/commands/auth.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
assemblyInstructionsSchema,
|
|
8
8
|
} from '../../alphalib/types/template.ts'
|
|
9
9
|
import type { OptionalAuthParams } from '../../apiTypes.ts'
|
|
10
|
+
import { mintBearerTokenWithCredentials } from '../../bearerToken.ts'
|
|
10
11
|
import { Transloadit } from '../../Transloadit.ts'
|
|
11
12
|
import { readCliInput, requireEnvCredentials } from '../helpers.ts'
|
|
12
13
|
import { UnauthenticatedCommand } from './BaseCommand.ts'
|
|
@@ -194,155 +195,6 @@ export interface RunSmartSigOptions {
|
|
|
194
195
|
providedInput?: string
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
export interface RequestTokenOptions {
|
|
198
|
-
endpoint?: string
|
|
199
|
-
aud?: string
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const tokenErrorSchema = z
|
|
203
|
-
.object({
|
|
204
|
-
error: z.string(),
|
|
205
|
-
message: z.string().optional(),
|
|
206
|
-
})
|
|
207
|
-
.passthrough()
|
|
208
|
-
|
|
209
|
-
const tokenSuccessSchema = z
|
|
210
|
-
.object({
|
|
211
|
-
access_token: z.string().min(1),
|
|
212
|
-
})
|
|
213
|
-
.passthrough()
|
|
214
|
-
|
|
215
|
-
const buildBasicAuthHeaderValue = (credentials: { authKey: string; authSecret: string }): string =>
|
|
216
|
-
`Basic ${Buffer.from(`${credentials.authKey}:${credentials.authSecret}`, 'utf8').toString('base64')}`
|
|
217
|
-
|
|
218
|
-
const isLoopbackHost = (hostname: string): boolean =>
|
|
219
|
-
hostname === 'localhost' || hostname === '::1' || hostname.startsWith('127.')
|
|
220
|
-
|
|
221
|
-
type TokenBaseResult = { ok: true; baseUrl: URL } | { ok: false; error: string }
|
|
222
|
-
|
|
223
|
-
const normalizeTokenBaseEndpoint = (raw?: string): TokenBaseResult => {
|
|
224
|
-
const baseRaw = (raw || process.env.TRANSLOADIT_ENDPOINT || 'https://api2.transloadit.com').trim()
|
|
225
|
-
|
|
226
|
-
let url: URL
|
|
227
|
-
try {
|
|
228
|
-
url = new URL(baseRaw)
|
|
229
|
-
} catch {
|
|
230
|
-
return {
|
|
231
|
-
ok: false,
|
|
232
|
-
error:
|
|
233
|
-
'Invalid endpoint URL. Use --endpoint https://api2.transloadit.com (or set TRANSLOADIT_ENDPOINT).',
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (url.username || url.password) {
|
|
238
|
-
return { ok: false, error: 'Endpoint must not include username/password.' }
|
|
239
|
-
}
|
|
240
|
-
if (url.search || url.hash) {
|
|
241
|
-
return { ok: false, error: 'Endpoint must not include query string or hash.' }
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (url.protocol !== 'https:') {
|
|
245
|
-
if (url.protocol === 'http:' && isLoopbackHost(url.hostname)) {
|
|
246
|
-
// Allowed for local development only.
|
|
247
|
-
} else {
|
|
248
|
-
return {
|
|
249
|
-
ok: false,
|
|
250
|
-
error:
|
|
251
|
-
'Refusing to send credentials to a non-HTTPS endpoint. Use https://... (or http://localhost for local development).',
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// If someone pasted the token URL, normalize it back to the API base to avoid /token/token.
|
|
257
|
-
const pathLower = url.pathname.toLowerCase()
|
|
258
|
-
if (pathLower === '/token' || pathLower === '/token/') {
|
|
259
|
-
url.pathname = '/'
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (!url.pathname.endsWith('/')) {
|
|
263
|
-
url.pathname = `${url.pathname}/`
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return { ok: true, baseUrl: url }
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
async function requestTokenWithCredentials(
|
|
270
|
-
credentials: { authKey: string; authSecret: string },
|
|
271
|
-
options: RequestTokenOptions = {},
|
|
272
|
-
): Promise<OutputResult> {
|
|
273
|
-
const endpointResult = normalizeTokenBaseEndpoint(options.endpoint)
|
|
274
|
-
if (!endpointResult.ok) {
|
|
275
|
-
return { ok: false, error: endpointResult.error }
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const url = new URL('token', endpointResult.baseUrl).toString()
|
|
279
|
-
const aud = (options.aud ?? 'mcp').trim() || 'mcp'
|
|
280
|
-
|
|
281
|
-
const body = new URLSearchParams({ grant_type: 'client_credentials', aud }).toString()
|
|
282
|
-
|
|
283
|
-
let res: Response
|
|
284
|
-
const controller = new AbortController()
|
|
285
|
-
const timeout = setTimeout(() => controller.abort(), 15_000)
|
|
286
|
-
try {
|
|
287
|
-
res = await fetch(url, {
|
|
288
|
-
method: 'POST',
|
|
289
|
-
// Never follow redirects with Basic Auth credentials.
|
|
290
|
-
redirect: 'error',
|
|
291
|
-
signal: controller.signal,
|
|
292
|
-
headers: {
|
|
293
|
-
Authorization: buildBasicAuthHeaderValue(credentials),
|
|
294
|
-
Accept: 'application/json',
|
|
295
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
296
|
-
},
|
|
297
|
-
body,
|
|
298
|
-
})
|
|
299
|
-
} catch (err) {
|
|
300
|
-
clearTimeout(timeout)
|
|
301
|
-
if (err instanceof Error && err.name === 'AbortError') {
|
|
302
|
-
return { ok: false, error: 'Failed to mint bearer token: request timed out after 15s.' }
|
|
303
|
-
}
|
|
304
|
-
const message = err instanceof Error ? err.message : String(err)
|
|
305
|
-
return { ok: false, error: `Failed to mint bearer token: ${message}` }
|
|
306
|
-
} finally {
|
|
307
|
-
clearTimeout(timeout)
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const text = await res.text()
|
|
311
|
-
const trimmed = text.trim()
|
|
312
|
-
let parsedJson: unknown = null
|
|
313
|
-
try {
|
|
314
|
-
parsedJson = trimmed ? JSON.parse(trimmed) : null
|
|
315
|
-
} catch {
|
|
316
|
-
parsedJson = null
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (res.ok) {
|
|
320
|
-
if (parsedJson == null) {
|
|
321
|
-
return { ok: false, error: 'Token response was not valid JSON.' }
|
|
322
|
-
}
|
|
323
|
-
const parsed = tokenSuccessSchema.safeParse(parsedJson)
|
|
324
|
-
if (!parsed.success) {
|
|
325
|
-
return { ok: false, error: 'Token response did not include an access_token.' }
|
|
326
|
-
}
|
|
327
|
-
return { ok: true, output: trimmed }
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const parsedError = tokenErrorSchema.safeParse(parsedJson)
|
|
331
|
-
if (parsedError.success) {
|
|
332
|
-
return {
|
|
333
|
-
ok: false,
|
|
334
|
-
error: parsedError.data.message
|
|
335
|
-
? `${parsedError.data.error}: ${parsedError.data.message}`
|
|
336
|
-
: parsedError.data.error,
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return {
|
|
341
|
-
ok: false,
|
|
342
|
-
error: `Token request failed (${res.status}): ${trimmed || res.statusText}`,
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
198
|
export async function runSig(options: RunSigOptions = {}): Promise<void> {
|
|
347
199
|
const credentialsResult = requireEnvCredentials()
|
|
348
200
|
if (!credentialsResult.ok) {
|
|
@@ -520,6 +372,11 @@ export class TokenCommand extends UnauthenticatedCommand {
|
|
|
520
372
|
description: 'Token audience (default: mcp).',
|
|
521
373
|
})
|
|
522
374
|
|
|
375
|
+
scope = Option.String('--scope', {
|
|
376
|
+
description:
|
|
377
|
+
'Comma-separated list of scopes to request (defaults to auth key scopes). Example: assemblies:write,templates:read',
|
|
378
|
+
})
|
|
379
|
+
|
|
523
380
|
protected override async run(): Promise<number | undefined> {
|
|
524
381
|
const credentialsResult = requireEnvCredentials()
|
|
525
382
|
if (!credentialsResult.ok) {
|
|
@@ -527,13 +384,14 @@ export class TokenCommand extends UnauthenticatedCommand {
|
|
|
527
384
|
return 1
|
|
528
385
|
}
|
|
529
386
|
|
|
530
|
-
const result = await
|
|
387
|
+
const result = await mintBearerTokenWithCredentials(credentialsResult.credentials, {
|
|
531
388
|
endpoint: this.endpoint,
|
|
532
389
|
aud: this.aud,
|
|
390
|
+
scope: this.scope,
|
|
533
391
|
})
|
|
534
392
|
|
|
535
393
|
if (result.ok) {
|
|
536
|
-
process.stdout.write(`${result.
|
|
394
|
+
process.stdout.write(`${result.raw}\n`)
|
|
537
395
|
return undefined
|
|
538
396
|
}
|
|
539
397
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Builtins, Cli } from 'clipanion'
|
|
2
2
|
|
|
3
3
|
import packageJson from '../../../package.json' with { type: 'json' }
|
|
4
|
-
|
|
4
|
+
import { intentCommands } from '../intentCommands.ts'
|
|
5
5
|
import {
|
|
6
6
|
AssembliesCreateCommand,
|
|
7
7
|
AssembliesDeleteCommand,
|
|
@@ -10,9 +10,7 @@ import {
|
|
|
10
10
|
AssembliesListCommand,
|
|
11
11
|
AssembliesReplayCommand,
|
|
12
12
|
} from './assemblies.ts'
|
|
13
|
-
|
|
14
13
|
import { SignatureCommand, SmartCdnSignatureCommand, TokenCommand } from './auth.ts'
|
|
15
|
-
|
|
16
14
|
import { BillsGetCommand } from './bills.ts'
|
|
17
15
|
import { DocsRobotsGetCommand, DocsRobotsListCommand } from './docs.ts'
|
|
18
16
|
import { NotificationsReplayCommand } from './notifications.ts'
|
|
@@ -71,5 +69,10 @@ export function createCli(): Cli {
|
|
|
71
69
|
cli.register(DocsRobotsListCommand)
|
|
72
70
|
cli.register(DocsRobotsGetCommand)
|
|
73
71
|
|
|
72
|
+
// Intent-first commands
|
|
73
|
+
for (const command of intentCommands) {
|
|
74
|
+
cli.register(command)
|
|
75
|
+
}
|
|
76
|
+
|
|
74
77
|
return cli
|
|
75
78
|
}
|
|
@@ -5,12 +5,11 @@ import { Command, Option } from 'clipanion'
|
|
|
5
5
|
import rreaddir from 'recursive-readdir'
|
|
6
6
|
import { z } from 'zod'
|
|
7
7
|
import { tryCatch } from '../../alphalib/tryCatch.ts'
|
|
8
|
-
import type { Steps } from '../../alphalib/types/template.ts'
|
|
9
|
-
import { stepsSchema } from '../../alphalib/types/template.ts'
|
|
10
8
|
import type { TemplateContent } from '../../apiTypes.ts'
|
|
11
9
|
import type { Transloadit } from '../../Transloadit.ts'
|
|
12
10
|
import { createReadStream, formatAPIError, streamToBuffer } from '../helpers.ts'
|
|
13
11
|
import type { IOutputCtl } from '../OutputCtl.ts'
|
|
12
|
+
import { parseStepsInputJson } from '../stepsInput.ts'
|
|
14
13
|
import ModifiedLookup from '../template-last-modified.ts'
|
|
15
14
|
import type { TemplateFile } from '../types.ts'
|
|
16
15
|
import { ensureError, isTransloaditAPIError, TemplateFileDataSchema } from '../types.ts'
|
|
@@ -60,16 +59,11 @@ export async function create(
|
|
|
60
59
|
try {
|
|
61
60
|
const buf = await streamToBuffer(createReadStream(file))
|
|
62
61
|
|
|
63
|
-
const
|
|
64
|
-
const validated = stepsSchema.safeParse(parsed)
|
|
65
|
-
if (!validated.success) {
|
|
66
|
-
throw new Error(`Invalid template steps format: ${validated.error.message}`)
|
|
67
|
-
}
|
|
62
|
+
const steps = parseStepsInputJson(buf.toString())
|
|
68
63
|
|
|
69
64
|
const result = await client.createTemplate({
|
|
70
65
|
name,
|
|
71
|
-
|
|
72
|
-
template: { steps: validated.data } as TemplateContent,
|
|
66
|
+
template: { steps } as TemplateContent,
|
|
73
67
|
})
|
|
74
68
|
output.print(result.id, result)
|
|
75
69
|
return result
|
|
@@ -106,23 +100,18 @@ export async function modify(
|
|
|
106
100
|
try {
|
|
107
101
|
const buf = await streamToBuffer(createReadStream(file))
|
|
108
102
|
|
|
109
|
-
let steps:
|
|
103
|
+
let steps: TemplateContent['steps'] | null = null
|
|
110
104
|
let newName = name
|
|
111
105
|
|
|
112
106
|
if (buf.length > 0) {
|
|
113
|
-
|
|
114
|
-
const validated = stepsSchema.safeParse(parsed)
|
|
115
|
-
if (!validated.success) {
|
|
116
|
-
throw new Error(`Invalid template steps format: ${validated.error.message}`)
|
|
117
|
-
}
|
|
118
|
-
steps = validated.data
|
|
107
|
+
steps = parseStepsInputJson(buf.toString()) as TemplateContent['steps']
|
|
119
108
|
}
|
|
120
109
|
|
|
121
110
|
if (!name || buf.length === 0) {
|
|
122
111
|
const tpl = await client.getTemplate(template)
|
|
123
112
|
if (!name) newName = tpl.name
|
|
124
113
|
if (buf.length === 0 && tpl.content.steps) {
|
|
125
|
-
steps = tpl.content.steps
|
|
114
|
+
steps = tpl.content.steps as TemplateContent['steps']
|
|
126
115
|
}
|
|
127
116
|
}
|
|
128
117
|
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { Option } from 'clipanion'
|
|
2
|
+
import * as t from 'typanion'
|
|
3
|
+
|
|
4
|
+
export interface SharedCliOptionDocumentation {
|
|
5
|
+
description: string
|
|
6
|
+
example: string
|
|
7
|
+
flags: string
|
|
8
|
+
required: string
|
|
9
|
+
type: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SharedCliOptionDefinition {
|
|
13
|
+
docs: SharedCliOptionDocumentation
|
|
14
|
+
optionFlags: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface SharedCliOptionExports<T> {
|
|
18
|
+
docs: (description?: string) => SharedCliOptionDocumentation
|
|
19
|
+
option: (description?: string) => T
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SharedFileProcessingValidationInput {
|
|
23
|
+
explicitInputCount: number
|
|
24
|
+
singleAssembly: boolean
|
|
25
|
+
watch: boolean
|
|
26
|
+
watchRequiresInputsMessage: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const inputPathsOptionDefinition = {
|
|
30
|
+
docs: {
|
|
31
|
+
flags: '--input, -i',
|
|
32
|
+
type: 'path | dir | url | -',
|
|
33
|
+
required: 'varies',
|
|
34
|
+
example: 'input.file',
|
|
35
|
+
description: 'Provide an input path, directory, URL, or - for stdin',
|
|
36
|
+
},
|
|
37
|
+
optionFlags: '--input,-i',
|
|
38
|
+
} as const satisfies SharedCliOptionDefinition
|
|
39
|
+
|
|
40
|
+
const recursiveOptionDefinition = {
|
|
41
|
+
docs: {
|
|
42
|
+
flags: '--recursive, -r',
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
required: 'no',
|
|
45
|
+
example: 'false',
|
|
46
|
+
description: 'Enumerate input directories recursively',
|
|
47
|
+
},
|
|
48
|
+
optionFlags: '--recursive,-r',
|
|
49
|
+
} as const satisfies SharedCliOptionDefinition
|
|
50
|
+
|
|
51
|
+
const deleteAfterProcessingOptionDefinition = {
|
|
52
|
+
docs: {
|
|
53
|
+
flags: '--delete-after-processing, -d',
|
|
54
|
+
type: 'boolean',
|
|
55
|
+
required: 'no',
|
|
56
|
+
example: 'false',
|
|
57
|
+
description: 'Delete input files after they are processed',
|
|
58
|
+
},
|
|
59
|
+
optionFlags: '--delete-after-processing,-d',
|
|
60
|
+
} as const satisfies SharedCliOptionDefinition
|
|
61
|
+
|
|
62
|
+
const reprocessStaleOptionDefinition = {
|
|
63
|
+
docs: {
|
|
64
|
+
flags: '--reprocess-stale',
|
|
65
|
+
type: 'boolean',
|
|
66
|
+
required: 'no',
|
|
67
|
+
example: 'false',
|
|
68
|
+
description: 'Process inputs even if output is newer',
|
|
69
|
+
},
|
|
70
|
+
optionFlags: '--reprocess-stale',
|
|
71
|
+
} as const satisfies SharedCliOptionDefinition
|
|
72
|
+
|
|
73
|
+
const watchOptionDefinition = {
|
|
74
|
+
docs: {
|
|
75
|
+
flags: '--watch, -w',
|
|
76
|
+
type: 'boolean',
|
|
77
|
+
required: 'no',
|
|
78
|
+
example: 'false',
|
|
79
|
+
description: 'Watch inputs for changes',
|
|
80
|
+
},
|
|
81
|
+
optionFlags: '--watch,-w',
|
|
82
|
+
} as const satisfies SharedCliOptionDefinition
|
|
83
|
+
|
|
84
|
+
const singleAssemblyOptionDefinition = {
|
|
85
|
+
docs: {
|
|
86
|
+
flags: '--single-assembly',
|
|
87
|
+
type: 'boolean',
|
|
88
|
+
required: 'no',
|
|
89
|
+
example: 'false',
|
|
90
|
+
description: 'Pass all input files to a single assembly instead of one assembly per file',
|
|
91
|
+
},
|
|
92
|
+
optionFlags: '--single-assembly',
|
|
93
|
+
} as const satisfies SharedCliOptionDefinition
|
|
94
|
+
|
|
95
|
+
const concurrencyOptionDefinition = {
|
|
96
|
+
docs: {
|
|
97
|
+
flags: '--concurrency, -c',
|
|
98
|
+
type: 'number',
|
|
99
|
+
required: 'no',
|
|
100
|
+
example: '5',
|
|
101
|
+
description: 'Maximum number of concurrent assemblies (default: 5)',
|
|
102
|
+
},
|
|
103
|
+
optionFlags: '--concurrency,-c',
|
|
104
|
+
} as const satisfies SharedCliOptionDefinition
|
|
105
|
+
|
|
106
|
+
const printUrlsOptionDefinition = {
|
|
107
|
+
docs: {
|
|
108
|
+
flags: '--print-urls',
|
|
109
|
+
type: 'boolean',
|
|
110
|
+
required: 'no',
|
|
111
|
+
example: 'false',
|
|
112
|
+
description: 'Print temporary result URLs after completion',
|
|
113
|
+
},
|
|
114
|
+
optionFlags: '--print-urls',
|
|
115
|
+
} as const satisfies SharedCliOptionDefinition
|
|
116
|
+
|
|
117
|
+
function getSharedCliOptionDocumentation(
|
|
118
|
+
definition: SharedCliOptionDefinition,
|
|
119
|
+
description = definition.docs.description,
|
|
120
|
+
): SharedCliOptionDocumentation {
|
|
121
|
+
return {
|
|
122
|
+
...definition.docs,
|
|
123
|
+
description,
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function arrayOption(
|
|
128
|
+
definition: SharedCliOptionDefinition,
|
|
129
|
+
description = definition.docs.description,
|
|
130
|
+
): string[] {
|
|
131
|
+
return Option.Array(definition.optionFlags, {
|
|
132
|
+
description,
|
|
133
|
+
}) as unknown as string[]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function booleanOption(
|
|
137
|
+
definition: SharedCliOptionDefinition,
|
|
138
|
+
description = definition.docs.description,
|
|
139
|
+
): boolean {
|
|
140
|
+
return Option.Boolean(definition.optionFlags, false, {
|
|
141
|
+
description,
|
|
142
|
+
}) as unknown as boolean
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function createArrayOptionExports(
|
|
146
|
+
definition: SharedCliOptionDefinition,
|
|
147
|
+
): SharedCliOptionExports<string[]> {
|
|
148
|
+
return {
|
|
149
|
+
docs: (description = definition.docs.description) =>
|
|
150
|
+
getSharedCliOptionDocumentation(definition, description),
|
|
151
|
+
option: (description = definition.docs.description) => arrayOption(definition, description),
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function createBooleanOptionExports(
|
|
156
|
+
definition: SharedCliOptionDefinition,
|
|
157
|
+
): SharedCliOptionExports<boolean> {
|
|
158
|
+
return {
|
|
159
|
+
docs: (description = definition.docs.description) =>
|
|
160
|
+
getSharedCliOptionDocumentation(definition, description),
|
|
161
|
+
option: (description = definition.docs.description) => booleanOption(definition, description),
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const inputPathsOptionExports = createArrayOptionExports(inputPathsOptionDefinition)
|
|
166
|
+
const recursiveOptionExports = createBooleanOptionExports(recursiveOptionDefinition)
|
|
167
|
+
const deleteAfterProcessingOptionExports = createBooleanOptionExports(
|
|
168
|
+
deleteAfterProcessingOptionDefinition,
|
|
169
|
+
)
|
|
170
|
+
const reprocessStaleOptionExports = createBooleanOptionExports(reprocessStaleOptionDefinition)
|
|
171
|
+
const watchOptionExports = createBooleanOptionExports(watchOptionDefinition)
|
|
172
|
+
const singleAssemblyOptionExports = createBooleanOptionExports(singleAssemblyOptionDefinition)
|
|
173
|
+
|
|
174
|
+
export function getInputPathsOptionDocumentation(
|
|
175
|
+
description = inputPathsOptionDefinition.docs.description,
|
|
176
|
+
): SharedCliOptionDocumentation {
|
|
177
|
+
return inputPathsOptionExports.docs(description)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function inputPathsOption(
|
|
181
|
+
description = inputPathsOptionDefinition.docs.description,
|
|
182
|
+
): string[] {
|
|
183
|
+
return inputPathsOptionExports.option(description)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function getRecursiveOptionDocumentation(
|
|
187
|
+
description = recursiveOptionDefinition.docs.description,
|
|
188
|
+
): SharedCliOptionDocumentation {
|
|
189
|
+
return recursiveOptionExports.docs(description)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function recursiveOption(description = recursiveOptionDefinition.docs.description): boolean {
|
|
193
|
+
return recursiveOptionExports.option(description)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function getDeleteAfterProcessingOptionDocumentation(
|
|
197
|
+
description = deleteAfterProcessingOptionDefinition.docs.description,
|
|
198
|
+
): SharedCliOptionDocumentation {
|
|
199
|
+
return deleteAfterProcessingOptionExports.docs(description)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function deleteAfterProcessingOption(
|
|
203
|
+
description = deleteAfterProcessingOptionDefinition.docs.description,
|
|
204
|
+
): boolean {
|
|
205
|
+
return deleteAfterProcessingOptionExports.option(description)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function getReprocessStaleOptionDocumentation(
|
|
209
|
+
description = reprocessStaleOptionDefinition.docs.description,
|
|
210
|
+
): SharedCliOptionDocumentation {
|
|
211
|
+
return reprocessStaleOptionExports.docs(description)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function reprocessStaleOption(
|
|
215
|
+
description = reprocessStaleOptionDefinition.docs.description,
|
|
216
|
+
): boolean {
|
|
217
|
+
return reprocessStaleOptionExports.option(description)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function getWatchOptionDocumentation(
|
|
221
|
+
description = watchOptionDefinition.docs.description,
|
|
222
|
+
): SharedCliOptionDocumentation {
|
|
223
|
+
return watchOptionExports.docs(description)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function watchOption(description = watchOptionDefinition.docs.description): boolean {
|
|
227
|
+
return watchOptionExports.option(description)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function getSingleAssemblyOptionDocumentation(
|
|
231
|
+
description = singleAssemblyOptionDefinition.docs.description,
|
|
232
|
+
): SharedCliOptionDocumentation {
|
|
233
|
+
return singleAssemblyOptionExports.docs(description)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function singleAssemblyOption(
|
|
237
|
+
description = singleAssemblyOptionDefinition.docs.description,
|
|
238
|
+
): boolean {
|
|
239
|
+
return singleAssemblyOptionExports.option(description)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function getConcurrencyOptionDocumentation(
|
|
243
|
+
description = concurrencyOptionDefinition.docs.description,
|
|
244
|
+
): SharedCliOptionDocumentation {
|
|
245
|
+
return getSharedCliOptionDocumentation(concurrencyOptionDefinition, description)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function concurrencyOption(
|
|
249
|
+
description = concurrencyOptionDefinition.docs.description,
|
|
250
|
+
): number | undefined {
|
|
251
|
+
return Option.String(concurrencyOptionDefinition.optionFlags, {
|
|
252
|
+
description,
|
|
253
|
+
validator: t.applyCascade(t.isNumber(), [t.isAtLeast(1)]),
|
|
254
|
+
}) as unknown as number | undefined
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function getPrintUrlsOptionDocumentation(
|
|
258
|
+
description = printUrlsOptionDefinition.docs.description,
|
|
259
|
+
): SharedCliOptionDocumentation {
|
|
260
|
+
return getSharedCliOptionDocumentation(printUrlsOptionDefinition, description)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function printUrlsOption(description = printUrlsOptionDefinition.docs.description): boolean {
|
|
264
|
+
return Option.Boolean(printUrlsOptionDefinition.optionFlags, {
|
|
265
|
+
description,
|
|
266
|
+
}) as unknown as boolean
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function countProvidedInputs({
|
|
270
|
+
inputBase64,
|
|
271
|
+
inputs,
|
|
272
|
+
}: {
|
|
273
|
+
inputBase64?: string[]
|
|
274
|
+
inputs?: string[]
|
|
275
|
+
}): number {
|
|
276
|
+
return (inputs ?? []).length + (inputBase64 ?? []).length
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function validateSharedFileProcessingOptions({
|
|
280
|
+
explicitInputCount,
|
|
281
|
+
singleAssembly,
|
|
282
|
+
watch,
|
|
283
|
+
watchRequiresInputsMessage,
|
|
284
|
+
}: SharedFileProcessingValidationInput): string | undefined {
|
|
285
|
+
if (watch && explicitInputCount === 0) {
|
|
286
|
+
return watchRequiresInputsMessage
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (watch && singleAssembly) {
|
|
290
|
+
return '--single-assembly cannot be used with --watch'
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return undefined
|
|
294
|
+
}
|