Skip to content

Commit 6fdd4bc

Browse files
authored
Sync alphalib 2025 04 03 (#221)
* w * Update .gitignore
1 parent 9e0fe1d commit 6fdd4bc

8 files changed

Lines changed: 144 additions & 24 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ env.sh
1717
!.yarn/sdks
1818
!.yarn/versions
1919
.aider*
20+
.DS_Store

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"is-stream": "^2.0.1",
2626
"p-map": "^4.0.0",
2727
"tus-js-client": "^4.3.1",
28+
"type-fest": "^4.39.1",
2829
"zod": "^3.24.2"
2930
},
3031
"devDependencies": {

src/alphalib/types/robots/_index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ const robotStepsInstructionsWithHiddenFields = [
325325
/**
326326
* Public robot instructions
327327
*/
328+
export type RobotsSchema = z.infer<typeof robotsSchema>
328329
export const robotsSchema = z.discriminatedUnion('robot', [...robotStepsInstructions])
329330
export const robotsWithHiddenFieldsSchema = z.discriminatedUnion('robot', [
330331
...robotStepsInstructionsWithHiddenFields,

src/alphalib/types/robots/_instructions-primitives.ts

Lines changed: 127 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Replace } from 'type-fest'
12
import { z } from 'zod'
23

34
import { stackVersions } from '../stackVersions.ts'
@@ -315,11 +316,72 @@ Selects the FFmpeg stack version to use for encoding. These versions reflect rea
315316
`),
316317
})
317318

318-
function preprocessPreset(preset: unknown) {
319-
return typeof preset === 'string' ? preset.replaceAll('_', '-') : preset
319+
/**
320+
* Replace all underscores with hyphens.
321+
*
322+
* @param preset
323+
* The input preset which may contain underscores.
324+
* @returns
325+
* The hyphenated preset.
326+
*/
327+
function transformPreset<T extends string>(preset: T): Replace<T, '_', '-', { all: true }> {
328+
return preset.replaceAll('_', '-') as Replace<T, '_', '-', { all: true }>
329+
}
330+
331+
/**
332+
* Convert a preset with hyphens to any underscore/hyphen combination.
333+
*
334+
* @template T
335+
* The preset to process.
336+
*/
337+
type ReplacePreset<T extends string> = T extends `${infer T0}-${infer Tail}`
338+
? T | `${T0}-${ReplacePreset<Tail>}` | `${T0}_${ReplacePreset<Tail>}`
339+
: T
340+
341+
/**
342+
* Generate all possible underscore/hyphen combinations of a preset.
343+
*
344+
* @param chunks
345+
* A normalized preset split on hyphens.
346+
* @returns
347+
* An iterable that yields all possible combinations.
348+
*/
349+
function* generateCombinations(chunks: string[]): Iterable<string> {
350+
if (chunks.length === 0) {
351+
return
352+
}
353+
354+
if (chunks.length === 1) {
355+
yield chunks[0]
356+
}
357+
358+
const [head, ...remaining] = chunks
359+
for (const result of generateCombinations(remaining)) {
360+
yield `${head}-${result}`
361+
yield `${head}_${result}`
362+
}
363+
}
364+
365+
/**
366+
* Create all possible preset combinations from a list of normalized presets.
367+
*
368+
* @param inputs
369+
* The hyphenated presets.
370+
* @returns
371+
* An array of all possible combinations.
372+
*/
373+
function createPresets<T extends string>(
374+
inputs: T[],
375+
): readonly [ReplacePreset<T>, ...ReplacePreset<T>[]] {
376+
const results: string[] = []
377+
for (const input of inputs) {
378+
results.push(...generateCombinations(input.split('-')))
379+
}
380+
381+
return [...results].sort() as [ReplacePreset<T>, ...ReplacePreset<T>[]]
320382
}
321383

322-
const audioPresets = [
384+
const audioPresets = createPresets([
323385
'aac',
324386
'alac',
325387
'audio/aac',
@@ -344,15 +406,15 @@ const audioPresets = [
344406
'opus',
345407
'speech',
346408
'wav',
347-
] as const
409+
])
348410

349411
/**
350412
* A robot that uses FFmpeg to **output** audio.
351413
*/
352414
export type FFmpegAudio = z.infer<typeof robotFFmpegAudio>
353415
export const robotFFmpegAudio = robotFFmpeg
354416
.extend({
355-
preset: z.preprocess(preprocessPreset, z.enum(audioPresets)).optional().describe(`
417+
preset: z.enum(audioPresets).transform(transformPreset).optional().describe(`
356418
Performs conversion using pre-configured settings.
357419
358420
If you specify your own FFmpeg parameters using the <dfn>Robot</dfn>'s \`ffmpeg\` parameter and you have not specified a preset, then the default \`mp3\` preset is not applied. This is to prevent you from having to override each of the MP3 preset's values manually.
@@ -379,9 +441,8 @@ Height of the new video, in pixels.
379441
If the value is not specified and the \`preset\` parameter is available, the \`preset\`'s [supplied height](/docs/transcoding/video-encoding/video-presets/) will be implemented.
380442
`),
381443
preset: z
382-
.preprocess(
383-
preprocessPreset,
384-
z.enum([
444+
.enum([
445+
...createPresets([
385446
'android-high',
386447
'android-low',
387448
'android',
@@ -461,9 +522,10 @@ If the value is not specified and the \`preset\` parameter is available, the \`p
461522
'webm-1080p',
462523
'webm',
463524
'wmv',
464-
...audioPresets,
465525
]),
466-
)
526+
...audioPresets,
527+
])
528+
.transform(transformPreset)
467529
.optional().describe(`
468530
Converts a video according to [pre-configured settings](/docs/transcoding/video-encoding/video-presets/).
469531
@@ -834,3 +896,58 @@ While we recommend to use <dfn>Template Credentials</dfn> at all times, some use
834896
secret: z.string().optional(),
835897
})
836898
.strict()
899+
900+
export type FilterExpression = z.infer<typeof filterExpression>
901+
export const filterExpression = z.union([
902+
z.string(),
903+
z.number(),
904+
z.array(z.union([z.string(), z.number()])),
905+
])
906+
907+
export type FilterCondition = z.infer<typeof filterCondition>
908+
export const filterCondition = z
909+
.array(
910+
z.union([
911+
z.tuple([
912+
filterExpression,
913+
z.union([
914+
z.literal('==').describe('Equals without type check'),
915+
z.literal('===').describe('Strict equals with type check'),
916+
z.literal('<').describe('Less than'),
917+
z.literal('>').describe('Greater than'),
918+
z.literal('<=').describe('Less or equal'),
919+
z.literal('>=').describe('Greater or equal'),
920+
z.literal('!=').describe('Simple inequality check without type check'),
921+
z.literal('!==').describe('Strict inequality check with type check'),
922+
z
923+
.literal('regex')
924+
.describe(
925+
'Case-insensitive regular expression based on [RE2](https://github.com/google/re2) `.match()`',
926+
),
927+
z
928+
.literal('!regex')
929+
.describe(
930+
'Case-insensitive regular expression based on [RE2](https://github.com/google/re2) `!.match()`',
931+
),
932+
z
933+
.literal('includes')
934+
.describe(
935+
'Check if the right element is included in the array, which is represented by the left element',
936+
),
937+
z
938+
.literal('empty')
939+
.describe(
940+
'Check if the left element is an empty array, an object without properties, an empty string, the number zero or the boolean false. Leave the third element of the array to be an empty string. It won’t be evaluated.',
941+
),
942+
z
943+
.literal('!empty')
944+
.describe(
945+
'Check if the left element is an array with members, an object with at least one property, a non-empty string, a number that does not equal zero or the boolean true. Leave the third element of the array to be an empty string. It won’t be evaluated.',
946+
),
947+
]),
948+
filterExpression,
949+
]),
950+
z.string(),
951+
]),
952+
)
953+
.default([])

src/alphalib/types/robots/file-filter.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { z } from 'zod'
22

3-
import { robotBase, robotUse } from './_instructions-primitives.ts'
3+
import { filterCondition, robotBase, robotUse } from './_instructions-primitives.ts'
44
import type { RobotMeta } from './_instructions-primitives.ts'
55

66
export const meta: RobotMeta = {
@@ -13,7 +13,7 @@ export const meta: RobotMeta = {
1313
filtered: {
1414
robot: '/file/filter',
1515
use: ':original',
16-
declines: [['${file.size}', '&gt;', '20971520']],
16+
declines: [['${file.size}', '>', '20971520']],
1717
error_on_decline: true,
1818
error_msg: 'File size must not exceed 20 MB',
1919
},
@@ -77,22 +77,14 @@ Examples:
7777
7878
As indicated, we charge for this via [🤖/script/run](/docs/transcoding/code-evaluation/script-run/). See also [Dynamic Evaluation](/docs/topics/dynamic-evaluation/) for more details on allowed syntax and behavior.
7979
`),
80-
accepts: z
81-
.array(
82-
z.union([z.string(), z.tuple([z.string(), z.string(), z.union([z.string(), z.number()])])]),
83-
)
84-
.default([]).describe(`
80+
accepts: filterCondition.describe(`
8581
Files that match at least one requirement will be accepted, or declined otherwise. If the array is empty, all files will be accepted. Example:
8682
8783
\`[["\${file.mime}", "==", "image/gif"]]\`.
8884
8985
If the \`condition_type\` parameter is set to \`"and"\`, then all requirements must match for the file to be accepted.
9086
`),
91-
declines: z
92-
.array(
93-
z.union([z.string(), z.tuple([z.string(), z.string(), z.union([z.string(), z.number()])])]),
94-
)
95-
.default([]).describe(`
87+
declines: filterCondition.describe(`
9688
Files that match at least one requirement will be declined, or accepted otherwise. Example:
9789
9890
\`[["\${file.size}",">","1024"]]\`.

src/alphalib/types/robots/image-generate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const robotImageGenerateInstructionsSchema = robotBase
1313
.optional()
1414
.describe('Format of the generated image.'),
1515
seed: z.number().optional().describe('Seed for the random number generator.'),
16-
aspectRatio: z.string().optional().describe('Aspect ratio of the generated image.'),
16+
aspect_ratio: z.string().optional().describe('Aspect ratio of the generated image.'),
1717
height: z.number().optional().describe('Height of the generated image.'),
1818
width: z.number().optional().describe('Width of the generated image.'),
1919
style: z.string().optional().describe('Style of the generated image.'),

tsconfig.build.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"include": ["src"],
3-
"exclude": ["coverage"],
3+
"exclude": ["coverage", "dist"],
44
"compilerOptions": {
55
"composite": true,
66
"declaration": true,

yarn.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6786,6 +6786,7 @@ __metadata:
67866786
prettier: "npm:^3.3.3"
67876787
temp: "npm:^0.9.4"
67886788
tus-js-client: "npm:^4.3.1"
6789+
type-fest: "npm:^4.39.1"
67896790
typescript: "npm:^5.7.2"
67906791
vitest: "npm:^2.1.3"
67916792
zod: "npm:^3.24.2"
@@ -6851,6 +6852,13 @@ __metadata:
68516852
languageName: node
68526853
linkType: hard
68536854

6855+
"type-fest@npm:^4.39.1":
6856+
version: 4.39.1
6857+
resolution: "type-fest@npm:4.39.1"
6858+
checksum: 10c0/f5bf302eb2e2f70658be1757aa578f4a09da3f65699b0b12b7ae5502ccea76e5124521a6e6b69540f442c3dc924c394202a2ab58718d0582725c7ac23c072594
6859+
languageName: node
6860+
linkType: hard
6861+
68546862
"typed-array-buffer@npm:^1.0.2":
68556863
version: 1.0.2
68566864
resolution: "typed-array-buffer@npm:1.0.2"

0 commit comments

Comments
 (0)