@transloadit/node 4.7.7 → 4.8.1

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.
Files changed (57) hide show
  1. package/README.md +97 -22
  2. package/dist/bearerToken.d.ts +1 -0
  3. package/dist/bearerToken.d.ts.map +1 -1
  4. package/dist/bearerToken.js +5 -3
  5. package/dist/bearerToken.js.map +1 -1
  6. package/dist/cli/commands/BaseCommand.d.ts +0 -1
  7. package/dist/cli/commands/BaseCommand.d.ts.map +1 -1
  8. package/dist/cli/commands/BaseCommand.js +7 -9
  9. package/dist/cli/commands/BaseCommand.js.map +1 -1
  10. package/dist/cli/commands/auth.d.ts.map +1 -1
  11. package/dist/cli/commands/auth.js +49 -29
  12. package/dist/cli/commands/auth.js.map +1 -1
  13. package/dist/cli/generateIntentDocs.d.ts +5 -1
  14. package/dist/cli/generateIntentDocs.d.ts.map +1 -1
  15. package/dist/cli/generateIntentDocs.js +27 -9
  16. package/dist/cli/generateIntentDocs.js.map +1 -1
  17. package/dist/cli/helpers.d.ts +19 -4
  18. package/dist/cli/helpers.d.ts.map +1 -1
  19. package/dist/cli/helpers.js +232 -10
  20. package/dist/cli/helpers.js.map +1 -1
  21. package/dist/cli/intentCommandSpecs.d.ts.map +1 -1
  22. package/dist/cli/intentCommandSpecs.js +4 -6
  23. package/dist/cli/intentCommandSpecs.js.map +1 -1
  24. package/dist/cli/intentRuntime.d.ts.map +1 -1
  25. package/dist/cli/intentRuntime.js +4 -4
  26. package/dist/cli/intentRuntime.js.map +1 -1
  27. package/dist/cli/semanticIntents/imageDescribe.d.ts +3 -1
  28. package/dist/cli/semanticIntents/imageDescribe.d.ts.map +1 -1
  29. package/dist/cli/semanticIntents/imageDescribe.js +1 -1
  30. package/dist/cli/semanticIntents/imageDescribe.js.map +1 -1
  31. package/dist/cli/semanticIntents/imageGenerate.d.ts +94 -0
  32. package/dist/cli/semanticIntents/imageGenerate.d.ts.map +1 -0
  33. package/dist/cli/semanticIntents/imageGenerate.js +215 -0
  34. package/dist/cli/semanticIntents/imageGenerate.js.map +1 -0
  35. package/dist/cli/semanticIntents/index.d.ts +3 -1
  36. package/dist/cli/semanticIntents/index.d.ts.map +1 -1
  37. package/dist/cli/semanticIntents/index.js +2 -0
  38. package/dist/cli/semanticIntents/index.js.map +1 -1
  39. package/dist/cli/semanticIntents/markdownPdf.js +1 -1
  40. package/dist/cli/semanticIntents/markdownPdf.js.map +1 -1
  41. package/dist/cli.d.ts +0 -1
  42. package/dist/cli.d.ts.map +1 -1
  43. package/dist/cli.js +3 -2
  44. package/dist/cli.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/bearerToken.ts +14 -3
  47. package/src/cli/commands/BaseCommand.ts +7 -9
  48. package/src/cli/commands/auth.ts +66 -32
  49. package/src/cli/generateIntentDocs.ts +30 -9
  50. package/src/cli/helpers.ts +278 -13
  51. package/src/cli/intentCommandSpecs.ts +4 -9
  52. package/src/cli/intentRuntime.ts +8 -3
  53. package/src/cli/semanticIntents/imageDescribe.ts +4 -1
  54. package/src/cli/semanticIntents/imageGenerate.ts +254 -0
  55. package/src/cli/semanticIntents/index.ts +6 -1
  56. package/src/cli/semanticIntents/markdownPdf.ts +1 -1
  57. package/src/cli.ts +3 -2
@@ -0,0 +1,254 @@
1
+ import { basename } from 'node:path'
2
+ import type { IntentOptionDefinition, PreparedIntentInputs } from '../intentRuntime.ts'
3
+ import type { SemanticIntentDescriptor, SemanticIntentPresentation } from './index.ts'
4
+ import { parseOptionalEnumValue } from './parsing.ts'
5
+
6
+ const defaultImageGenerateModel = 'google/nano-banana-2'
7
+ const imageGenerateFormats = ['jpeg', 'jpg', 'png', 'gif', 'webp', 'svg'] as const
8
+
9
+ const imageGenerateOptionDefinitions = [
10
+ {
11
+ name: 'prompt',
12
+ kind: 'string',
13
+ propertyName: 'prompt',
14
+ optionFlags: '--prompt',
15
+ description: 'The prompt describing the desired image content.',
16
+ required: true,
17
+ exampleValue: JSON.stringify('A red bicycle in a studio'),
18
+ },
19
+ {
20
+ name: 'model',
21
+ kind: 'string',
22
+ propertyName: 'model',
23
+ optionFlags: '--model',
24
+ description: `The AI model to use for image generation. Defaults to ${defaultImageGenerateModel}.`,
25
+ required: false,
26
+ exampleValue: defaultImageGenerateModel,
27
+ },
28
+ {
29
+ name: 'format',
30
+ kind: 'string',
31
+ propertyName: 'format',
32
+ optionFlags: '--format',
33
+ description: 'Format of the generated image.',
34
+ required: false,
35
+ exampleValue: 'jpg',
36
+ },
37
+ {
38
+ name: 'seed',
39
+ kind: 'number',
40
+ propertyName: 'seed',
41
+ optionFlags: '--seed',
42
+ description: 'Seed for the random number generator.',
43
+ required: false,
44
+ },
45
+ {
46
+ name: 'aspectRatio',
47
+ kind: 'string',
48
+ propertyName: 'aspectRatio',
49
+ optionFlags: '--aspect-ratio',
50
+ description: 'Aspect ratio of the generated image.',
51
+ required: false,
52
+ },
53
+ {
54
+ name: 'height',
55
+ kind: 'number',
56
+ propertyName: 'height',
57
+ optionFlags: '--height',
58
+ description: 'Height of the generated image.',
59
+ required: false,
60
+ },
61
+ {
62
+ name: 'width',
63
+ kind: 'number',
64
+ propertyName: 'width',
65
+ optionFlags: '--width',
66
+ description: 'Width of the generated image.',
67
+ required: false,
68
+ },
69
+ {
70
+ name: 'style',
71
+ kind: 'string',
72
+ propertyName: 'style',
73
+ optionFlags: '--style',
74
+ description: 'Style of the generated image.',
75
+ required: false,
76
+ },
77
+ {
78
+ name: 'numOutputs',
79
+ kind: 'number',
80
+ propertyName: 'numOutputs',
81
+ optionFlags: '--num-outputs',
82
+ description: 'Number of image variants to generate.',
83
+ required: false,
84
+ },
85
+ ] as const satisfies readonly IntentOptionDefinition[]
86
+
87
+ const imageGenerateCommandPresentation = {
88
+ description: 'Generate images from text prompts',
89
+ details:
90
+ 'Runs `/image/generate`. Without inputs, this is text-to-image. With one or more `--input` files, the inputs are bundled into a single assembly so the prompt can refer to them by filename.',
91
+ examples: [
92
+ [
93
+ 'Generate an image from text',
94
+ 'transloadit image generate --prompt "A red bicycle in a studio" --out output.png',
95
+ ],
96
+ [
97
+ 'Guide generation with one input image',
98
+ 'transloadit image generate --input subject.jpg --prompt "Place subject.jpg on a magazine cover" --out output.png',
99
+ ],
100
+ [
101
+ 'Guide generation with multiple input images',
102
+ 'transloadit image generate --input person1.jpg --input person2.jpg --input background.jpg --prompt "Place person1.jpg feeding person2.jpg in front of background.jpg" --out output.png',
103
+ ],
104
+ ] as Array<[string, string]>,
105
+ } as const satisfies SemanticIntentPresentation
106
+
107
+ function parseOptionalFormat(value: unknown): (typeof imageGenerateFormats)[number] | null {
108
+ return parseOptionalEnumValue({
109
+ flagName: '--format',
110
+ supportedValues: imageGenerateFormats,
111
+ value,
112
+ })
113
+ }
114
+
115
+ function parseRequiredPrompt(value: unknown): string {
116
+ if (typeof value !== 'string' || value.trim() === '') {
117
+ throw new Error('image generate requires --prompt')
118
+ }
119
+
120
+ return value
121
+ }
122
+
123
+ function parseOptionalNumber(flagName: string, value: unknown): number | undefined {
124
+ if (value == null || value === '') {
125
+ return undefined
126
+ }
127
+
128
+ const numericValue = typeof value === 'number' ? value : Number(String(value).trim())
129
+ if (Number.isNaN(numericValue)) {
130
+ throw new Error(`${flagName} must be a number`)
131
+ }
132
+
133
+ return numericValue
134
+ }
135
+
136
+ function parseOptionalIntegerRange(
137
+ flagName: string,
138
+ value: unknown,
139
+ { max, min }: { max: number; min: number },
140
+ ): number | undefined {
141
+ const numericValue = parseOptionalNumber(flagName, value)
142
+ if (numericValue == null) {
143
+ return undefined
144
+ }
145
+
146
+ if (!Number.isInteger(numericValue) || numericValue < min || numericValue > max) {
147
+ throw new Error(`${flagName} must be an integer between ${min} and ${max}`)
148
+ }
149
+
150
+ return numericValue
151
+ }
152
+
153
+ function createImageGenerateStep(
154
+ rawValues: Record<string, unknown>,
155
+ context: { hasInputs: boolean },
156
+ ): Record<string, unknown> {
157
+ const step: Record<string, unknown> = {
158
+ robot: '/image/generate',
159
+ result: true,
160
+ model: defaultImageGenerateModel,
161
+ prompt: parseRequiredPrompt(rawValues.prompt),
162
+ }
163
+
164
+ if (context.hasInputs) {
165
+ step.use = {
166
+ steps: [':original'],
167
+ bundle_steps: true,
168
+ }
169
+ }
170
+
171
+ const model = rawValues.model
172
+ if (typeof model === 'string' && model.trim() !== '') {
173
+ step.model = model
174
+ }
175
+
176
+ const format = parseOptionalFormat(rawValues.format)
177
+ if (format != null) {
178
+ step.format = format
179
+ }
180
+
181
+ const seed = parseOptionalNumber('--seed', rawValues.seed)
182
+ if (seed != null) {
183
+ step.seed = seed
184
+ }
185
+
186
+ const aspectRatio = rawValues.aspectRatio
187
+ if (typeof aspectRatio === 'string' && aspectRatio.trim() !== '') {
188
+ step.aspect_ratio = aspectRatio
189
+ }
190
+
191
+ const height = parseOptionalNumber('--height', rawValues.height)
192
+ if (height != null) {
193
+ step.height = height
194
+ }
195
+
196
+ const width = parseOptionalNumber('--width', rawValues.width)
197
+ if (width != null) {
198
+ step.width = width
199
+ }
200
+
201
+ const style = rawValues.style
202
+ if (typeof style === 'string' && style.trim() !== '') {
203
+ step.style = style
204
+ }
205
+
206
+ const numOutputs = parseOptionalIntegerRange('--num-outputs', rawValues.numOutputs, {
207
+ min: 1,
208
+ max: 10,
209
+ })
210
+ if (numOutputs != null) {
211
+ step.num_outputs = numOutputs
212
+ }
213
+
214
+ return step
215
+ }
216
+
217
+ function ensureUniqueInputBasenames(preparedInputs: PreparedIntentInputs): PreparedIntentInputs {
218
+ const seenBasenames = new Map<string, string>()
219
+
220
+ for (const input of preparedInputs.inputs) {
221
+ const inputBasename = basename(input)
222
+ const previousInput = seenBasenames.get(inputBasename)
223
+ if (previousInput != null) {
224
+ throw new Error(
225
+ `image generate requires unique input basenames when prompts refer to files; found duplicate ${inputBasename} in ${previousInput} and ${input}`,
226
+ )
227
+ }
228
+
229
+ seenBasenames.set(inputBasename, input)
230
+ }
231
+
232
+ return preparedInputs
233
+ }
234
+
235
+ export const imageGenerateSemanticIntentDescriptor = {
236
+ createStep: createImageGenerateStep,
237
+ execution: {
238
+ kind: 'dynamic-step',
239
+ handler: 'image-generate',
240
+ resultStepName: 'generate',
241
+ fields: imageGenerateOptionDefinitions,
242
+ },
243
+ inputPolicy: {
244
+ kind: 'optional',
245
+ field: 'prompt',
246
+ attachUseWhenInputsProvided: false,
247
+ },
248
+ outputDescription: 'Write the result to this path',
249
+ async prepareInputs(preparedInputs) {
250
+ return await Promise.resolve(ensureUniqueInputBasenames(preparedInputs))
251
+ },
252
+ presentation: imageGenerateCommandPresentation,
253
+ runnerKind: 'bundled',
254
+ } as const satisfies SemanticIntentDescriptor
@@ -5,6 +5,7 @@ import type {
5
5
  PreparedIntentInputs,
6
6
  } from '../intentRuntime.ts'
7
7
  import { imageDescribeSemanticIntentDescriptor } from './imageDescribe.ts'
8
+ import { imageGenerateSemanticIntentDescriptor } from './imageGenerate.ts'
8
9
  import {
9
10
  markdownDocxSemanticIntentDescriptor,
10
11
  markdownPdfSemanticIntentDescriptor,
@@ -17,7 +18,10 @@ export interface SemanticIntentPresentation {
17
18
  }
18
19
 
19
20
  export interface SemanticIntentDescriptor {
20
- createStep: (rawValues: Record<string, unknown>) => Record<string, unknown>
21
+ createStep: (
22
+ rawValues: Record<string, unknown>,
23
+ context: { hasInputs: boolean },
24
+ ) => Record<string, unknown>
21
25
  execution: IntentDynamicStepExecutionDefinition
22
26
  inputPolicy: IntentInputPolicy
23
27
  outputDescription: string
@@ -31,6 +35,7 @@ export interface SemanticIntentDescriptor {
31
35
 
32
36
  const semanticIntentDescriptors: Record<string, SemanticIntentDescriptor> = {
33
37
  'image-describe': imageDescribeSemanticIntentDescriptor,
38
+ 'image-generate': imageGenerateSemanticIntentDescriptor,
34
39
  'markdown-pdf': {
35
40
  ...markdownPdfSemanticIntentDescriptor,
36
41
  },
@@ -76,7 +76,7 @@ function createMarkdownConvertSemanticIntent({
76
76
  } satisfies SemanticIntentPresentation
77
77
 
78
78
  return {
79
- createStep(rawValues) {
79
+ createStep(rawValues, _context) {
80
80
  return {
81
81
  robot: '/document/convert',
82
82
  use: ':original',
package/src/cli.ts CHANGED
@@ -4,8 +4,7 @@ import { realpathSync } from 'node:fs'
4
4
  import path from 'node:path'
5
5
  import process from 'node:process'
6
6
  import { fileURLToPath } from 'node:url'
7
- import 'dotenv/config'
8
- import { createCli } from './cli/commands/index.ts'
7
+ import { loadProjectDotenvIntoProcessEnv } from './cli/helpers.ts'
9
8
  import { ensureError } from './cli/types.ts'
10
9
 
11
10
  const currentFile = realpathSync(fileURLToPath(import.meta.url))
@@ -26,6 +25,8 @@ export function shouldRunCli(invoked?: string): boolean {
26
25
  }
27
26
 
28
27
  export async function main(args = process.argv.slice(2)): Promise<void> {
28
+ loadProjectDotenvIntoProcessEnv()
29
+ const { createCli } = await import('./cli/commands/index.ts')
29
30
  const cli = createCli()
30
31
  const exitCode = await cli.run(args)
31
32
  if (exitCode !== 0) {