@transloadit/node 4.1.3
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/LICENSE +21 -0
- package/README.md +701 -0
- package/dist/ApiError.d.ts +22 -0
- package/dist/ApiError.d.ts.map +1 -0
- package/dist/ApiError.js +33 -0
- package/dist/ApiError.js.map +1 -0
- package/dist/InconsistentResponseError.d.ts +4 -0
- package/dist/InconsistentResponseError.d.ts.map +1 -0
- package/dist/InconsistentResponseError.js +4 -0
- package/dist/InconsistentResponseError.js.map +1 -0
- package/dist/PaginationStream.d.ts +14 -0
- package/dist/PaginationStream.d.ts.map +1 -0
- package/dist/PaginationStream.js +36 -0
- package/dist/PaginationStream.js.map +1 -0
- package/dist/PollingTimeoutError.d.ts +5 -0
- package/dist/PollingTimeoutError.d.ts.map +1 -0
- package/dist/PollingTimeoutError.js +5 -0
- package/dist/PollingTimeoutError.js.map +1 -0
- package/dist/Transloadit.d.ts +250 -0
- package/dist/Transloadit.d.ts.map +1 -0
- package/dist/Transloadit.js +661 -0
- package/dist/Transloadit.js.map +1 -0
- package/dist/alphalib/lib/nativeGlobby.d.ts +14 -0
- package/dist/alphalib/lib/nativeGlobby.d.ts.map +1 -0
- package/dist/alphalib/lib/nativeGlobby.js +181 -0
- package/dist/alphalib/lib/nativeGlobby.js.map +1 -0
- package/dist/alphalib/mcache.d.ts +65 -0
- package/dist/alphalib/mcache.d.ts.map +1 -0
- package/dist/alphalib/mcache.js +135 -0
- package/dist/alphalib/mcache.js.map +1 -0
- package/dist/alphalib/tryCatch.d.ts +21 -0
- package/dist/alphalib/tryCatch.d.ts.map +1 -0
- package/dist/alphalib/tryCatch.js +17 -0
- package/dist/alphalib/tryCatch.js.map +1 -0
- package/dist/alphalib/types/assembliesGet.d.ts +62 -0
- package/dist/alphalib/types/assembliesGet.d.ts.map +1 -0
- package/dist/alphalib/types/assembliesGet.js +33 -0
- package/dist/alphalib/types/assembliesGet.js.map +1 -0
- package/dist/alphalib/types/assemblyReplay.d.ts +7858 -0
- package/dist/alphalib/types/assemblyReplay.d.ts.map +1 -0
- package/dist/alphalib/types/assemblyReplay.js +15 -0
- package/dist/alphalib/types/assemblyReplay.js.map +1 -0
- package/dist/alphalib/types/assemblyReplayNotification.d.ts +7849 -0
- package/dist/alphalib/types/assemblyReplayNotification.d.ts.map +1 -0
- package/dist/alphalib/types/assemblyReplayNotification.js +13 -0
- package/dist/alphalib/types/assemblyReplayNotification.js.map +1 -0
- package/dist/alphalib/types/assemblyStatus.d.ts +71084 -0
- package/dist/alphalib/types/assemblyStatus.d.ts.map +1 -0
- package/dist/alphalib/types/assemblyStatus.js +710 -0
- package/dist/alphalib/types/assemblyStatus.js.map +1 -0
- package/dist/alphalib/types/bill.d.ts +44 -0
- package/dist/alphalib/types/bill.d.ts.map +1 -0
- package/dist/alphalib/types/bill.js +8 -0
- package/dist/alphalib/types/bill.js.map +1 -0
- package/dist/alphalib/types/robots/_index.d.ts +76306 -0
- package/dist/alphalib/types/robots/_index.d.ts.map +1 -0
- package/dist/alphalib/types/robots/_index.js +354 -0
- package/dist/alphalib/types/robots/_index.js.map +1 -0
- package/dist/alphalib/types/robots/_instructions-primitives.d.ts +3533 -0
- package/dist/alphalib/types/robots/_instructions-primitives.d.ts.map +1 -0
- package/dist/alphalib/types/robots/_instructions-primitives.js +1491 -0
- package/dist/alphalib/types/robots/_instructions-primitives.js.map +1 -0
- package/dist/alphalib/types/robots/ai-chat.d.ts +2096 -0
- package/dist/alphalib/types/robots/ai-chat.d.ts.map +1 -0
- package/dist/alphalib/types/robots/ai-chat.js +223 -0
- package/dist/alphalib/types/robots/ai-chat.js.map +1 -0
- package/dist/alphalib/types/robots/assembly-savejson.d.ts +52 -0
- package/dist/alphalib/types/robots/assembly-savejson.d.ts.map +1 -0
- package/dist/alphalib/types/robots/assembly-savejson.js +22 -0
- package/dist/alphalib/types/robots/assembly-savejson.js.map +1 -0
- package/dist/alphalib/types/robots/audio-artwork.d.ts +2867 -0
- package/dist/alphalib/types/robots/audio-artwork.d.ts.map +1 -0
- package/dist/alphalib/types/robots/audio-artwork.js +73 -0
- package/dist/alphalib/types/robots/audio-artwork.js.map +1 -0
- package/dist/alphalib/types/robots/audio-concat.d.ts +2916 -0
- package/dist/alphalib/types/robots/audio-concat.d.ts.map +1 -0
- package/dist/alphalib/types/robots/audio-concat.js +106 -0
- package/dist/alphalib/types/robots/audio-concat.js.map +1 -0
- package/dist/alphalib/types/robots/audio-encode.d.ts +2864 -0
- package/dist/alphalib/types/robots/audio-encode.d.ts.map +1 -0
- package/dist/alphalib/types/robots/audio-encode.js +67 -0
- package/dist/alphalib/types/robots/audio-encode.js.map +1 -0
- package/dist/alphalib/types/robots/audio-loop.d.ts +2879 -0
- package/dist/alphalib/types/robots/audio-loop.d.ts.map +1 -0
- package/dist/alphalib/types/robots/audio-loop.js +67 -0
- package/dist/alphalib/types/robots/audio-loop.js.map +1 -0
- package/dist/alphalib/types/robots/audio-merge.d.ts +2931 -0
- package/dist/alphalib/types/robots/audio-merge.d.ts.map +1 -0
- package/dist/alphalib/types/robots/audio-merge.js +101 -0
- package/dist/alphalib/types/robots/audio-merge.js.map +1 -0
- package/dist/alphalib/types/robots/audio-waveform.d.ts +3131 -0
- package/dist/alphalib/types/robots/audio-waveform.d.ts.map +1 -0
- package/dist/alphalib/types/robots/audio-waveform.js +238 -0
- package/dist/alphalib/types/robots/audio-waveform.js.map +1 -0
- package/dist/alphalib/types/robots/azure-import.d.ts +210 -0
- package/dist/alphalib/types/robots/azure-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/azure-import.js +73 -0
- package/dist/alphalib/types/robots/azure-import.js.map +1 -0
- package/dist/alphalib/types/robots/azure-store.d.ts +562 -0
- package/dist/alphalib/types/robots/azure-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/azure-store.js +115 -0
- package/dist/alphalib/types/robots/azure-store.js.map +1 -0
- package/dist/alphalib/types/robots/backblaze-import.d.ts +210 -0
- package/dist/alphalib/types/robots/backblaze-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/backblaze-import.js +81 -0
- package/dist/alphalib/types/robots/backblaze-import.js.map +1 -0
- package/dist/alphalib/types/robots/backblaze-store.d.ts +478 -0
- package/dist/alphalib/types/robots/backblaze-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/backblaze-store.js +76 -0
- package/dist/alphalib/types/robots/backblaze-store.js.map +1 -0
- package/dist/alphalib/types/robots/cloudfiles-import.d.ts +234 -0
- package/dist/alphalib/types/robots/cloudfiles-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/cloudfiles-import.js +80 -0
- package/dist/alphalib/types/robots/cloudfiles-import.js.map +1 -0
- package/dist/alphalib/types/robots/cloudfiles-store.d.ts +490 -0
- package/dist/alphalib/types/robots/cloudfiles-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/cloudfiles-store.js +70 -0
- package/dist/alphalib/types/robots/cloudfiles-store.js.map +1 -0
- package/dist/alphalib/types/robots/cloudflare-import.d.ts +234 -0
- package/dist/alphalib/types/robots/cloudflare-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/cloudflare-import.js +81 -0
- package/dist/alphalib/types/robots/cloudflare-import.js.map +1 -0
- package/dist/alphalib/types/robots/cloudflare-store.d.ts +514 -0
- package/dist/alphalib/types/robots/cloudflare-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/cloudflare-store.js +86 -0
- package/dist/alphalib/types/robots/cloudflare-store.js.map +1 -0
- package/dist/alphalib/types/robots/digitalocean-import.d.ts +234 -0
- package/dist/alphalib/types/robots/digitalocean-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/digitalocean-import.js +78 -0
- package/dist/alphalib/types/robots/digitalocean-import.js.map +1 -0
- package/dist/alphalib/types/robots/digitalocean-store.d.ts +526 -0
- package/dist/alphalib/types/robots/digitalocean-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/digitalocean-store.js +91 -0
- package/dist/alphalib/types/robots/digitalocean-store.js.map +1 -0
- package/dist/alphalib/types/robots/document-autorotate.d.ts +405 -0
- package/dist/alphalib/types/robots/document-autorotate.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-autorotate.js +44 -0
- package/dist/alphalib/types/robots/document-autorotate.js.map +1 -0
- package/dist/alphalib/types/robots/document-convert.d.ts +513 -0
- package/dist/alphalib/types/robots/document-convert.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-convert.js +273 -0
- package/dist/alphalib/types/robots/document-convert.js.map +1 -0
- package/dist/alphalib/types/robots/document-merge.d.ts +429 -0
- package/dist/alphalib/types/robots/document-merge.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-merge.js +86 -0
- package/dist/alphalib/types/robots/document-merge.js.map +1 -0
- package/dist/alphalib/types/robots/document-ocr.d.ts +441 -0
- package/dist/alphalib/types/robots/document-ocr.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-ocr.js +86 -0
- package/dist/alphalib/types/robots/document-ocr.js.map +1 -0
- package/dist/alphalib/types/robots/document-split.d.ts +417 -0
- package/dist/alphalib/types/robots/document-split.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-split.js +48 -0
- package/dist/alphalib/types/robots/document-split.js.map +1 -0
- package/dist/alphalib/types/robots/document-thumbs.d.ts +592 -0
- package/dist/alphalib/types/robots/document-thumbs.d.ts.map +1 -0
- package/dist/alphalib/types/robots/document-thumbs.js +196 -0
- package/dist/alphalib/types/robots/document-thumbs.js.map +1 -0
- package/dist/alphalib/types/robots/dropbox-import.d.ts +144 -0
- package/dist/alphalib/types/robots/dropbox-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/dropbox-import.js +65 -0
- package/dist/alphalib/types/robots/dropbox-import.js.map +1 -0
- package/dist/alphalib/types/robots/dropbox-store.d.ts +449 -0
- package/dist/alphalib/types/robots/dropbox-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/dropbox-store.js +68 -0
- package/dist/alphalib/types/robots/dropbox-store.js.map +1 -0
- package/dist/alphalib/types/robots/edgly-deliver.d.ts +100 -0
- package/dist/alphalib/types/robots/edgly-deliver.d.ts.map +1 -0
- package/dist/alphalib/types/robots/edgly-deliver.js +46 -0
- package/dist/alphalib/types/robots/edgly-deliver.js.map +1 -0
- package/dist/alphalib/types/robots/file-compress.d.ts +477 -0
- package/dist/alphalib/types/robots/file-compress.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-compress.js +139 -0
- package/dist/alphalib/types/robots/file-compress.js.map +1 -0
- package/dist/alphalib/types/robots/file-decompress.d.ts +404 -0
- package/dist/alphalib/types/robots/file-decompress.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-decompress.js +94 -0
- package/dist/alphalib/types/robots/file-decompress.js.map +1 -0
- package/dist/alphalib/types/robots/file-filter.d.ts +465 -0
- package/dist/alphalib/types/robots/file-filter.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-filter.js +136 -0
- package/dist/alphalib/types/robots/file-filter.js.map +1 -0
- package/dist/alphalib/types/robots/file-hash.d.ts +417 -0
- package/dist/alphalib/types/robots/file-hash.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-hash.js +59 -0
- package/dist/alphalib/types/robots/file-hash.js.map +1 -0
- package/dist/alphalib/types/robots/file-preview.d.ts +854 -0
- package/dist/alphalib/types/robots/file-preview.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-preview.js +221 -0
- package/dist/alphalib/types/robots/file-preview.js.map +1 -0
- package/dist/alphalib/types/robots/file-read.d.ts +405 -0
- package/dist/alphalib/types/robots/file-read.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-read.js +44 -0
- package/dist/alphalib/types/robots/file-read.js.map +1 -0
- package/dist/alphalib/types/robots/file-serve.d.ts +418 -0
- package/dist/alphalib/types/robots/file-serve.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-serve.js +99 -0
- package/dist/alphalib/types/robots/file-serve.js.map +1 -0
- package/dist/alphalib/types/robots/file-verify.d.ts +441 -0
- package/dist/alphalib/types/robots/file-verify.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-verify.js +73 -0
- package/dist/alphalib/types/robots/file-verify.js.map +1 -0
- package/dist/alphalib/types/robots/file-virusscan.d.ts +435 -0
- package/dist/alphalib/types/robots/file-virusscan.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-virusscan.js +82 -0
- package/dist/alphalib/types/robots/file-virusscan.js.map +1 -0
- package/dist/alphalib/types/robots/file-watermark.d.ts +417 -0
- package/dist/alphalib/types/robots/file-watermark.d.ts.map +1 -0
- package/dist/alphalib/types/robots/file-watermark.js +28 -0
- package/dist/alphalib/types/robots/file-watermark.js.map +1 -0
- package/dist/alphalib/types/robots/ftp-import.d.ts +198 -0
- package/dist/alphalib/types/robots/ftp-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/ftp-import.js +60 -0
- package/dist/alphalib/types/robots/ftp-import.js.map +1 -0
- package/dist/alphalib/types/robots/ftp-store.d.ts +532 -0
- package/dist/alphalib/types/robots/ftp-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/ftp-store.js +91 -0
- package/dist/alphalib/types/robots/ftp-store.js.map +1 -0
- package/dist/alphalib/types/robots/google-import.d.ts +174 -0
- package/dist/alphalib/types/robots/google-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/google-import.js +77 -0
- package/dist/alphalib/types/robots/google-import.js.map +1 -0
- package/dist/alphalib/types/robots/google-store.d.ts +476 -0
- package/dist/alphalib/types/robots/google-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/google-store.js +111 -0
- package/dist/alphalib/types/robots/google-store.js.map +1 -0
- package/dist/alphalib/types/robots/html-convert.d.ts +531 -0
- package/dist/alphalib/types/robots/html-convert.d.ts.map +1 -0
- package/dist/alphalib/types/robots/html-convert.js +137 -0
- package/dist/alphalib/types/robots/html-convert.js.map +1 -0
- package/dist/alphalib/types/robots/http-import.d.ts +215 -0
- package/dist/alphalib/types/robots/http-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/http-import.js +135 -0
- package/dist/alphalib/types/robots/http-import.js.map +1 -0
- package/dist/alphalib/types/robots/image-bgremove.d.ts +453 -0
- package/dist/alphalib/types/robots/image-bgremove.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-bgremove.js +65 -0
- package/dist/alphalib/types/robots/image-bgremove.js.map +1 -0
- package/dist/alphalib/types/robots/image-describe.d.ts +453 -0
- package/dist/alphalib/types/robots/image-describe.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-describe.js +86 -0
- package/dist/alphalib/types/robots/image-describe.js.map +1 -0
- package/dist/alphalib/types/robots/image-facedetect.d.ts +477 -0
- package/dist/alphalib/types/robots/image-facedetect.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-facedetect.js +151 -0
- package/dist/alphalib/types/robots/image-facedetect.js.map +1 -0
- package/dist/alphalib/types/robots/image-generate.d.ts +522 -0
- package/dist/alphalib/types/robots/image-generate.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-generate.js +64 -0
- package/dist/alphalib/types/robots/image-generate.js.map +1 -0
- package/dist/alphalib/types/robots/image-merge.d.ts +477 -0
- package/dist/alphalib/types/robots/image-merge.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-merge.js +92 -0
- package/dist/alphalib/types/robots/image-merge.js.map +1 -0
- package/dist/alphalib/types/robots/image-ocr.d.ts +441 -0
- package/dist/alphalib/types/robots/image-ocr.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-ocr.js +79 -0
- package/dist/alphalib/types/robots/image-ocr.js.map +1 -0
- package/dist/alphalib/types/robots/image-optimize.d.ts +453 -0
- package/dist/alphalib/types/robots/image-optimize.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-optimize.js +81 -0
- package/dist/alphalib/types/robots/image-optimize.js.map +1 -0
- package/dist/alphalib/types/robots/image-resize.d.ts +1758 -0
- package/dist/alphalib/types/robots/image-resize.d.ts.map +1 -0
- package/dist/alphalib/types/robots/image-resize.js +602 -0
- package/dist/alphalib/types/robots/image-resize.js.map +1 -0
- package/dist/alphalib/types/robots/meta-read.d.ts +98 -0
- package/dist/alphalib/types/robots/meta-read.d.ts.map +1 -0
- package/dist/alphalib/types/robots/meta-read.js +24 -0
- package/dist/alphalib/types/robots/meta-read.js.map +1 -0
- package/dist/alphalib/types/robots/meta-write.d.ts +2842 -0
- package/dist/alphalib/types/robots/meta-write.d.ts.map +1 -0
- package/dist/alphalib/types/robots/meta-write.js +66 -0
- package/dist/alphalib/types/robots/meta-write.js.map +1 -0
- package/dist/alphalib/types/robots/minio-import.d.ts +234 -0
- package/dist/alphalib/types/robots/minio-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/minio-import.js +81 -0
- package/dist/alphalib/types/robots/minio-import.js.map +1 -0
- package/dist/alphalib/types/robots/minio-store.d.ts +514 -0
- package/dist/alphalib/types/robots/minio-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/minio-store.js +87 -0
- package/dist/alphalib/types/robots/minio-store.js.map +1 -0
- package/dist/alphalib/types/robots/progress-simulate.d.ts +229 -0
- package/dist/alphalib/types/robots/progress-simulate.d.ts.map +1 -0
- package/dist/alphalib/types/robots/progress-simulate.js +25 -0
- package/dist/alphalib/types/robots/progress-simulate.js.map +1 -0
- package/dist/alphalib/types/robots/s3-import.d.ts +246 -0
- package/dist/alphalib/types/robots/s3-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/s3-import.js +137 -0
- package/dist/alphalib/types/robots/s3-import.js.map +1 -0
- package/dist/alphalib/types/robots/s3-store.d.ts +593 -0
- package/dist/alphalib/types/robots/s3-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/s3-store.js +169 -0
- package/dist/alphalib/types/robots/s3-store.js.map +1 -0
- package/dist/alphalib/types/robots/script-run.d.ts +423 -0
- package/dist/alphalib/types/robots/script-run.d.ts.map +1 -0
- package/dist/alphalib/types/robots/script-run.js +95 -0
- package/dist/alphalib/types/robots/script-run.js.map +1 -0
- package/dist/alphalib/types/robots/sftp-import.d.ts +192 -0
- package/dist/alphalib/types/robots/sftp-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/sftp-import.js +62 -0
- package/dist/alphalib/types/robots/sftp-import.js.map +1 -0
- package/dist/alphalib/types/robots/sftp-store.d.ts +520 -0
- package/dist/alphalib/types/robots/sftp-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/sftp-store.js +83 -0
- package/dist/alphalib/types/robots/sftp-store.js.map +1 -0
- package/dist/alphalib/types/robots/speech-transcribe.d.ts +465 -0
- package/dist/alphalib/types/robots/speech-transcribe.d.ts.map +1 -0
- package/dist/alphalib/types/robots/speech-transcribe.js +103 -0
- package/dist/alphalib/types/robots/speech-transcribe.js.map +1 -0
- package/dist/alphalib/types/robots/supabase-import.d.ts +246 -0
- package/dist/alphalib/types/robots/supabase-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/supabase-import.js +83 -0
- package/dist/alphalib/types/robots/supabase-import.js.map +1 -0
- package/dist/alphalib/types/robots/supabase-store.d.ts +514 -0
- package/dist/alphalib/types/robots/supabase-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/supabase-store.js +77 -0
- package/dist/alphalib/types/robots/supabase-store.js.map +1 -0
- package/dist/alphalib/types/robots/swift-import.d.ts +246 -0
- package/dist/alphalib/types/robots/swift-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/swift-import.js +81 -0
- package/dist/alphalib/types/robots/swift-import.js.map +1 -0
- package/dist/alphalib/types/robots/swift-store.d.ts +526 -0
- package/dist/alphalib/types/robots/swift-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/swift-store.js +84 -0
- package/dist/alphalib/types/robots/swift-store.js.map +1 -0
- package/dist/alphalib/types/robots/text-speak.d.ts +465 -0
- package/dist/alphalib/types/robots/text-speak.d.ts.map +1 -0
- package/dist/alphalib/types/robots/text-speak.js +119 -0
- package/dist/alphalib/types/robots/text-speak.js.map +1 -0
- package/dist/alphalib/types/robots/text-translate.d.ts +441 -0
- package/dist/alphalib/types/robots/text-translate.d.ts.map +1 -0
- package/dist/alphalib/types/robots/text-translate.js +211 -0
- package/dist/alphalib/types/robots/text-translate.js.map +1 -0
- package/dist/alphalib/types/robots/tigris-import.d.ts +244 -0
- package/dist/alphalib/types/robots/tigris-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/tigris-import.js +85 -0
- package/dist/alphalib/types/robots/tigris-import.js.map +1 -0
- package/dist/alphalib/types/robots/tigris-store.d.ts +524 -0
- package/dist/alphalib/types/robots/tigris-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/tigris-store.js +91 -0
- package/dist/alphalib/types/robots/tigris-store.js.map +1 -0
- package/dist/alphalib/types/robots/tlcdn-deliver.d.ts +100 -0
- package/dist/alphalib/types/robots/tlcdn-deliver.d.ts.map +1 -0
- package/dist/alphalib/types/robots/tlcdn-deliver.js +46 -0
- package/dist/alphalib/types/robots/tlcdn-deliver.js.map +1 -0
- package/dist/alphalib/types/robots/tus-store.d.ts +477 -0
- package/dist/alphalib/types/robots/tus-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/tus-store.js +102 -0
- package/dist/alphalib/types/robots/tus-store.js.map +1 -0
- package/dist/alphalib/types/robots/upload-handle.d.ts +100 -0
- package/dist/alphalib/types/robots/upload-handle.d.ts.map +1 -0
- package/dist/alphalib/types/robots/upload-handle.js +66 -0
- package/dist/alphalib/types/robots/upload-handle.js.map +1 -0
- package/dist/alphalib/types/robots/video-adaptive.d.ts +2915 -0
- package/dist/alphalib/types/robots/video-adaptive.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-adaptive.js +144 -0
- package/dist/alphalib/types/robots/video-adaptive.js.map +1 -0
- package/dist/alphalib/types/robots/video-concat.d.ts +2891 -0
- package/dist/alphalib/types/robots/video-concat.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-concat.js +96 -0
- package/dist/alphalib/types/robots/video-concat.js.map +1 -0
- package/dist/alphalib/types/robots/video-encode.d.ts +3280 -0
- package/dist/alphalib/types/robots/video-encode.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-encode.js +107 -0
- package/dist/alphalib/types/robots/video-encode.js.map +1 -0
- package/dist/alphalib/types/robots/video-merge.d.ts +2987 -0
- package/dist/alphalib/types/robots/video-merge.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-merge.js +102 -0
- package/dist/alphalib/types/robots/video-merge.js.map +1 -0
- package/dist/alphalib/types/robots/video-ondemand.d.ts +4553 -0
- package/dist/alphalib/types/robots/video-ondemand.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-ondemand.js +112 -0
- package/dist/alphalib/types/robots/video-ondemand.js.map +1 -0
- package/dist/alphalib/types/robots/video-subtitle.d.ts +2975 -0
- package/dist/alphalib/types/robots/video-subtitle.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-subtitle.js +122 -0
- package/dist/alphalib/types/robots/video-subtitle.js.map +1 -0
- package/dist/alphalib/types/robots/video-thumbs.d.ts +2938 -0
- package/dist/alphalib/types/robots/video-thumbs.d.ts.map +1 -0
- package/dist/alphalib/types/robots/video-thumbs.js +122 -0
- package/dist/alphalib/types/robots/video-thumbs.js.map +1 -0
- package/dist/alphalib/types/robots/vimeo-import.d.ts +189 -0
- package/dist/alphalib/types/robots/vimeo-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/vimeo-import.js +92 -0
- package/dist/alphalib/types/robots/vimeo-import.js.map +1 -0
- package/dist/alphalib/types/robots/vimeo-store.d.ts +520 -0
- package/dist/alphalib/types/robots/vimeo-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/vimeo-store.js +115 -0
- package/dist/alphalib/types/robots/vimeo-store.js.map +1 -0
- package/dist/alphalib/types/robots/wasabi-import.d.ts +244 -0
- package/dist/alphalib/types/robots/wasabi-import.d.ts.map +1 -0
- package/dist/alphalib/types/robots/wasabi-import.js +85 -0
- package/dist/alphalib/types/robots/wasabi-import.js.map +1 -0
- package/dist/alphalib/types/robots/wasabi-store.d.ts +526 -0
- package/dist/alphalib/types/robots/wasabi-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/wasabi-store.js +85 -0
- package/dist/alphalib/types/robots/wasabi-store.js.map +1 -0
- package/dist/alphalib/types/robots/youtube-store.d.ts +477 -0
- package/dist/alphalib/types/robots/youtube-store.d.ts.map +1 -0
- package/dist/alphalib/types/robots/youtube-store.js +122 -0
- package/dist/alphalib/types/robots/youtube-store.js.map +1 -0
- package/dist/alphalib/types/stackVersions.d.ts +13 -0
- package/dist/alphalib/types/stackVersions.d.ts.map +1 -0
- package/dist/alphalib/types/stackVersions.js +13 -0
- package/dist/alphalib/types/stackVersions.js.map +1 -0
- package/dist/alphalib/types/template.d.ts +131710 -0
- package/dist/alphalib/types/template.d.ts.map +1 -0
- package/dist/alphalib/types/template.js +218 -0
- package/dist/alphalib/types/template.js.map +1 -0
- package/dist/alphalib/types/templateCredential.d.ts +95 -0
- package/dist/alphalib/types/templateCredential.d.ts.map +1 -0
- package/dist/alphalib/types/templateCredential.js +57 -0
- package/dist/alphalib/types/templateCredential.js.map +1 -0
- package/dist/alphalib/zodParseWithContext.d.ts +17 -0
- package/dist/alphalib/zodParseWithContext.d.ts.map +1 -0
- package/dist/alphalib/zodParseWithContext.js +248 -0
- package/dist/alphalib/zodParseWithContext.js.map +1 -0
- package/dist/apiTypes.d.ts +112 -0
- package/dist/apiTypes.d.ts.map +1 -0
- package/dist/apiTypes.js +3 -0
- package/dist/apiTypes.js.map +1 -0
- package/dist/cli/OutputCtl.d.ts +47 -0
- package/dist/cli/OutputCtl.d.ts.map +1 -0
- package/dist/cli/OutputCtl.js +85 -0
- package/dist/cli/OutputCtl.js.map +1 -0
- package/dist/cli/commands/BaseCommand.d.ts +24 -0
- package/dist/cli/commands/BaseCommand.d.ts.map +1 -0
- package/dist/cli/commands/BaseCommand.js +52 -0
- package/dist/cli/commands/BaseCommand.js.map +1 -0
- package/dist/cli/commands/assemblies.d.ts +93 -0
- package/dist/cli/commands/assemblies.d.ts.map +1 -0
- package/dist/cli/commands/assemblies.js +1021 -0
- package/dist/cli/commands/assemblies.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +28 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +280 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/bills.d.ts +14 -0
- package/dist/cli/commands/bills.d.ts.map +1 -0
- package/dist/cli/commands/bills.js +69 -0
- package/dist/cli/commands/bills.js.map +1 -0
- package/dist/cli/commands/index.d.ts +3 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +39 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/notifications.d.ts +9 -0
- package/dist/cli/commands/notifications.d.ts.map +1 -0
- package/dist/cli/commands/notifications.js +44 -0
- package/dist/cli/commands/notifications.js.map +1 -0
- package/dist/cli/commands/templates.d.ts +73 -0
- package/dist/cli/commands/templates.d.ts.map +1 -0
- package/dist/cli/commands/templates.js +428 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/helpers.d.ts +13 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +39 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/template-last-modified.d.ts +10 -0
- package/dist/cli/template-last-modified.d.ts.map +1 -0
- package/dist/cli/template-last-modified.js +134 -0
- package/dist/cli/template-last-modified.js.map +1 -0
- package/dist/cli/types.d.ts +78 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +49 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +41 -0
- package/dist/cli.js.map +1 -0
- package/dist/tus.d.ts +18 -0
- package/dist/tus.d.ts.map +1 -0
- package/dist/tus.js +122 -0
- package/dist/tus.js.map +1 -0
- package/package.json +92 -0
- package/src/ApiError.ts +49 -0
- package/src/InconsistentResponseError.ts +3 -0
- package/src/PaginationStream.ts +54 -0
- package/src/PollingTimeoutError.ts +5 -0
- package/src/Transloadit.ts +980 -0
- package/src/alphalib/lib/nativeGlobby.ts +244 -0
- package/src/alphalib/mcache.ts +184 -0
- package/src/alphalib/tryCatch.ts +30 -0
- package/src/alphalib/types/assembliesGet.ts +42 -0
- package/src/alphalib/types/assemblyReplay.ts +24 -0
- package/src/alphalib/types/assemblyReplayNotification.ts +16 -0
- package/src/alphalib/types/assemblyStatus.ts +794 -0
- package/src/alphalib/types/bill.ts +9 -0
- package/src/alphalib/types/robots/_index.ts +1201 -0
- package/src/alphalib/types/robots/_instructions-primitives.ts +1770 -0
- package/src/alphalib/types/robots/ai-chat.ts +278 -0
- package/src/alphalib/types/robots/assembly-savejson.ts +37 -0
- package/src/alphalib/types/robots/audio-artwork.ts +107 -0
- package/src/alphalib/types/robots/audio-concat.ts +142 -0
- package/src/alphalib/types/robots/audio-encode.ts +103 -0
- package/src/alphalib/types/robots/audio-loop.ts +102 -0
- package/src/alphalib/types/robots/audio-merge.ts +137 -0
- package/src/alphalib/types/robots/audio-waveform.ts +280 -0
- package/src/alphalib/types/robots/azure-import.ts +111 -0
- package/src/alphalib/types/robots/azure-store.ts +143 -0
- package/src/alphalib/types/robots/backblaze-import.ts +119 -0
- package/src/alphalib/types/robots/backblaze-store.ts +104 -0
- package/src/alphalib/types/robots/cloudfiles-import.ts +118 -0
- package/src/alphalib/types/robots/cloudfiles-store.ts +104 -0
- package/src/alphalib/types/robots/cloudflare-import.ts +121 -0
- package/src/alphalib/types/robots/cloudflare-store.ts +120 -0
- package/src/alphalib/types/robots/digitalocean-import.ts +118 -0
- package/src/alphalib/types/robots/digitalocean-store.ts +125 -0
- package/src/alphalib/types/robots/document-autorotate.ts +74 -0
- package/src/alphalib/types/robots/document-convert.ts +302 -0
- package/src/alphalib/types/robots/document-merge.ts +114 -0
- package/src/alphalib/types/robots/document-ocr.ts +120 -0
- package/src/alphalib/types/robots/document-split.ts +78 -0
- package/src/alphalib/types/robots/document-thumbs.ts +231 -0
- package/src/alphalib/types/robots/dropbox-import.ts +100 -0
- package/src/alphalib/types/robots/dropbox-store.ts +97 -0
- package/src/alphalib/types/robots/edgly-deliver.ts +73 -0
- package/src/alphalib/types/robots/file-compress.ts +167 -0
- package/src/alphalib/types/robots/file-decompress.ts +125 -0
- package/src/alphalib/types/robots/file-filter.ts +173 -0
- package/src/alphalib/types/robots/file-hash.ts +86 -0
- package/src/alphalib/types/robots/file-preview.ts +260 -0
- package/src/alphalib/types/robots/file-read.ts +71 -0
- package/src/alphalib/types/robots/file-serve.ts +128 -0
- package/src/alphalib/types/robots/file-verify.ts +102 -0
- package/src/alphalib/types/robots/file-virusscan.ts +113 -0
- package/src/alphalib/types/robots/file-watermark.ts +56 -0
- package/src/alphalib/types/robots/ftp-import.ts +95 -0
- package/src/alphalib/types/robots/ftp-store.ts +119 -0
- package/src/alphalib/types/robots/google-import.ts +115 -0
- package/src/alphalib/types/robots/google-store.ts +139 -0
- package/src/alphalib/types/robots/html-convert.ts +165 -0
- package/src/alphalib/types/robots/http-import.ts +168 -0
- package/src/alphalib/types/robots/image-bgremove.ts +95 -0
- package/src/alphalib/types/robots/image-describe.ts +121 -0
- package/src/alphalib/types/robots/image-facedetect.ts +187 -0
- package/src/alphalib/types/robots/image-generate.ts +92 -0
- package/src/alphalib/types/robots/image-merge.ts +127 -0
- package/src/alphalib/types/robots/image-ocr.ts +112 -0
- package/src/alphalib/types/robots/image-optimize.ts +114 -0
- package/src/alphalib/types/robots/image-resize.ts +653 -0
- package/src/alphalib/types/robots/meta-read.ts +44 -0
- package/src/alphalib/types/robots/meta-write.ts +93 -0
- package/src/alphalib/types/robots/minio-import.ts +120 -0
- package/src/alphalib/types/robots/minio-store.ts +115 -0
- package/src/alphalib/types/robots/progress-simulate.ts +40 -0
- package/src/alphalib/types/robots/s3-import.ts +175 -0
- package/src/alphalib/types/robots/s3-store.ts +198 -0
- package/src/alphalib/types/robots/script-run.ts +122 -0
- package/src/alphalib/types/robots/sftp-import.ts +92 -0
- package/src/alphalib/types/robots/sftp-store.ts +110 -0
- package/src/alphalib/types/robots/speech-transcribe.ts +139 -0
- package/src/alphalib/types/robots/supabase-import.ts +122 -0
- package/src/alphalib/types/robots/supabase-store.ts +105 -0
- package/src/alphalib/types/robots/swift-import.ts +120 -0
- package/src/alphalib/types/robots/swift-store.ts +112 -0
- package/src/alphalib/types/robots/text-speak.ts +152 -0
- package/src/alphalib/types/robots/text-translate.ts +245 -0
- package/src/alphalib/types/robots/tigris-import.ts +124 -0
- package/src/alphalib/types/robots/tigris-store.ts +119 -0
- package/src/alphalib/types/robots/tlcdn-deliver.ts +73 -0
- package/src/alphalib/types/robots/tus-store.ts +129 -0
- package/src/alphalib/types/robots/upload-handle.ts +95 -0
- package/src/alphalib/types/robots/video-adaptive.ts +179 -0
- package/src/alphalib/types/robots/video-concat.ts +130 -0
- package/src/alphalib/types/robots/video-encode.ts +141 -0
- package/src/alphalib/types/robots/video-merge.ts +138 -0
- package/src/alphalib/types/robots/video-ondemand.ts +161 -0
- package/src/alphalib/types/robots/video-subtitle.ts +159 -0
- package/src/alphalib/types/robots/video-thumbs.ts +158 -0
- package/src/alphalib/types/robots/vimeo-import.ts +126 -0
- package/src/alphalib/types/robots/vimeo-store.ts +143 -0
- package/src/alphalib/types/robots/wasabi-import.ts +124 -0
- package/src/alphalib/types/robots/wasabi-store.ts +113 -0
- package/src/alphalib/types/robots/youtube-store.ts +153 -0
- package/src/alphalib/types/stackVersions.ts +12 -0
- package/src/alphalib/types/template.ts +277 -0
- package/src/alphalib/types/templateCredential.ts +61 -0
- package/src/alphalib/zodParseWithContext.ts +306 -0
- package/src/apiTypes.ts +154 -0
- package/src/cli/OutputCtl.ts +115 -0
- package/src/cli/commands/BaseCommand.ts +71 -0
- package/src/cli/commands/assemblies.ts +1373 -0
- package/src/cli/commands/auth.ts +354 -0
- package/src/cli/commands/bills.ts +91 -0
- package/src/cli/commands/index.ts +65 -0
- package/src/cli/commands/notifications.ts +63 -0
- package/src/cli/commands/templates.ts +556 -0
- package/src/cli/helpers.ts +50 -0
- package/src/cli/template-last-modified.ts +156 -0
- package/src/cli/types.ts +70 -0
- package/src/cli.ts +44 -0
- package/src/tus.ts +168 -0
|
@@ -0,0 +1,1373 @@
|
|
|
1
|
+
import EventEmitter from 'node:events'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import fsp from 'node:fs/promises'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
import type { Readable, Writable } from 'node:stream'
|
|
7
|
+
import { pipeline } from 'node:stream/promises'
|
|
8
|
+
import { setTimeout as delay } from 'node:timers/promises'
|
|
9
|
+
import tty from 'node:tty'
|
|
10
|
+
import { promisify } from 'node:util'
|
|
11
|
+
import { Command, Option } from 'clipanion'
|
|
12
|
+
import got from 'got'
|
|
13
|
+
import PQueue from 'p-queue'
|
|
14
|
+
import * as t from 'typanion'
|
|
15
|
+
import { z } from 'zod'
|
|
16
|
+
import { tryCatch } from '../../alphalib/tryCatch.ts'
|
|
17
|
+
import type { Steps, StepsInput } from '../../alphalib/types/template.ts'
|
|
18
|
+
import { stepsSchema } from '../../alphalib/types/template.ts'
|
|
19
|
+
import type { CreateAssemblyParams, ReplayAssemblyParams } from '../../apiTypes.ts'
|
|
20
|
+
import type { CreateAssemblyOptions, Transloadit } from '../../Transloadit.ts'
|
|
21
|
+
import { createReadStream, formatAPIError, streamToBuffer } from '../helpers.ts'
|
|
22
|
+
import type { IOutputCtl } from '../OutputCtl.ts'
|
|
23
|
+
import { ensureError, isErrnoException } from '../types.ts'
|
|
24
|
+
import { AuthenticatedCommand } from './BaseCommand.ts'
|
|
25
|
+
|
|
26
|
+
// --- From assemblies.ts: Schemas and interfaces ---
|
|
27
|
+
export interface AssemblyListOptions {
|
|
28
|
+
before?: string
|
|
29
|
+
after?: string
|
|
30
|
+
fields?: string[]
|
|
31
|
+
keywords?: string[]
|
|
32
|
+
pagesize?: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AssemblyGetOptions {
|
|
36
|
+
assemblies: string[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface AssemblyDeleteOptions {
|
|
40
|
+
assemblies: string[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AssemblyReplayOptions {
|
|
44
|
+
fields?: Record<string, string>
|
|
45
|
+
reparse?: boolean
|
|
46
|
+
steps?: string
|
|
47
|
+
notify_url?: string
|
|
48
|
+
assemblies: string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const AssemblySchema = z.object({
|
|
52
|
+
id: z.string(),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// --- Business logic functions (from assemblies.ts) ---
|
|
56
|
+
|
|
57
|
+
export function list(
|
|
58
|
+
output: IOutputCtl,
|
|
59
|
+
client: Transloadit,
|
|
60
|
+
{ before, after, fields, keywords }: AssemblyListOptions,
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
const assemblies = client.streamAssemblies({
|
|
63
|
+
fromdate: after,
|
|
64
|
+
todate: before,
|
|
65
|
+
keywords,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
assemblies.on('readable', () => {
|
|
69
|
+
const assembly: unknown = assemblies.read()
|
|
70
|
+
if (assembly == null) return
|
|
71
|
+
|
|
72
|
+
const parsed = AssemblySchema.safeParse(assembly)
|
|
73
|
+
if (!parsed.success) return
|
|
74
|
+
|
|
75
|
+
if (fields == null) {
|
|
76
|
+
output.print(parsed.data.id, assembly)
|
|
77
|
+
} else {
|
|
78
|
+
const assemblyRecord = assembly as Record<string, unknown>
|
|
79
|
+
output.print(fields.map((field) => assemblyRecord[field]).join(' '), assembly)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
return new Promise<void>((resolve) => {
|
|
84
|
+
assemblies.on('end', resolve)
|
|
85
|
+
assemblies.on('error', (err: unknown) => {
|
|
86
|
+
output.error(formatAPIError(err))
|
|
87
|
+
resolve()
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function get(
|
|
93
|
+
output: IOutputCtl,
|
|
94
|
+
client: Transloadit,
|
|
95
|
+
{ assemblies }: AssemblyGetOptions,
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
for (const assembly of assemblies) {
|
|
98
|
+
await delay(1000)
|
|
99
|
+
const [err, result] = await tryCatch(client.getAssembly(assembly))
|
|
100
|
+
if (err) {
|
|
101
|
+
output.error(formatAPIError(err))
|
|
102
|
+
throw ensureError(err)
|
|
103
|
+
}
|
|
104
|
+
output.print(result, result)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function deleteAssemblies(
|
|
109
|
+
output: IOutputCtl,
|
|
110
|
+
client: Transloadit,
|
|
111
|
+
{ assemblies }: AssemblyDeleteOptions,
|
|
112
|
+
): Promise<void> {
|
|
113
|
+
const promises = assemblies.map(async (assembly) => {
|
|
114
|
+
const [err] = await tryCatch(client.cancelAssembly(assembly))
|
|
115
|
+
if (err) {
|
|
116
|
+
output.error(formatAPIError(err))
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
await Promise.all(promises)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Export with `delete` alias for tests (can't use `delete` as function name)
|
|
123
|
+
export { deleteAssemblies as delete }
|
|
124
|
+
|
|
125
|
+
export async function replay(
|
|
126
|
+
output: IOutputCtl,
|
|
127
|
+
client: Transloadit,
|
|
128
|
+
{ fields, reparse, steps, notify_url, assemblies }: AssemblyReplayOptions,
|
|
129
|
+
): Promise<void> {
|
|
130
|
+
if (steps) {
|
|
131
|
+
try {
|
|
132
|
+
const buf = await streamToBuffer(createReadStream(steps))
|
|
133
|
+
const parsed: unknown = JSON.parse(buf.toString())
|
|
134
|
+
const validated = stepsSchema.safeParse(parsed)
|
|
135
|
+
if (!validated.success) {
|
|
136
|
+
throw new Error(`Invalid steps format: ${validated.error.message}`)
|
|
137
|
+
}
|
|
138
|
+
await apiCall(validated.data)
|
|
139
|
+
} catch (err) {
|
|
140
|
+
const error = ensureError(err)
|
|
141
|
+
output.error(error.message)
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
await apiCall()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function apiCall(stepsOverride?: Steps): Promise<void> {
|
|
148
|
+
const promises = assemblies.map(async (assembly) => {
|
|
149
|
+
const [err] = await tryCatch(
|
|
150
|
+
client.replayAssembly(assembly, {
|
|
151
|
+
reparse_template: reparse ? 1 : 0,
|
|
152
|
+
fields,
|
|
153
|
+
notify_url,
|
|
154
|
+
// Steps (validated) is assignable to StepsInput at runtime; cast for TS
|
|
155
|
+
steps: stepsOverride as ReplayAssemblyParams['steps'],
|
|
156
|
+
}),
|
|
157
|
+
)
|
|
158
|
+
if (err) {
|
|
159
|
+
output.error(formatAPIError(err))
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
await Promise.all(promises)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// --- From assemblies-create.ts: Helper classes and functions ---
|
|
167
|
+
interface NodeWatcher {
|
|
168
|
+
on(event: 'error', listener: (err: Error) => void): void
|
|
169
|
+
on(event: 'close', listener: () => void): void
|
|
170
|
+
on(event: 'change', listener: (evt: string, filename: string) => void): void
|
|
171
|
+
on(event: string, listener: (...args: unknown[]) => void): void
|
|
172
|
+
close(): void
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
type NodeWatchFn = (path: string, options?: { recursive?: boolean }) => NodeWatcher
|
|
176
|
+
|
|
177
|
+
let nodeWatch: NodeWatchFn | undefined
|
|
178
|
+
|
|
179
|
+
async function getNodeWatch(): Promise<NodeWatchFn> {
|
|
180
|
+
if (!nodeWatch) {
|
|
181
|
+
const mod = (await import('node-watch')) as unknown as { default: NodeWatchFn }
|
|
182
|
+
nodeWatch = mod.default
|
|
183
|
+
}
|
|
184
|
+
return nodeWatch
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// workaround for determining mime-type of stdin
|
|
188
|
+
const stdinWithPath = process.stdin as unknown as { path: string }
|
|
189
|
+
stdinWithPath.path = '/dev/stdin'
|
|
190
|
+
|
|
191
|
+
interface OutStream extends Writable {
|
|
192
|
+
path?: string
|
|
193
|
+
mtime?: Date
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
interface Job {
|
|
197
|
+
in: Readable | null
|
|
198
|
+
out: OutStream | null
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
type OutstreamProvider = (inpath: string | null, indir?: string) => Promise<OutStream | null>
|
|
202
|
+
|
|
203
|
+
interface StreamRegistry {
|
|
204
|
+
[key: string]: OutStream | undefined
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface JobEmitterOptions {
|
|
208
|
+
recursive?: boolean
|
|
209
|
+
outstreamProvider: OutstreamProvider
|
|
210
|
+
streamRegistry: StreamRegistry
|
|
211
|
+
watch?: boolean
|
|
212
|
+
reprocessStale?: boolean
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface ReaddirJobEmitterOptions {
|
|
216
|
+
dir: string
|
|
217
|
+
streamRegistry: StreamRegistry
|
|
218
|
+
recursive?: boolean
|
|
219
|
+
outstreamProvider: OutstreamProvider
|
|
220
|
+
topdir?: string
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
interface SingleJobEmitterOptions {
|
|
224
|
+
file: string
|
|
225
|
+
streamRegistry: StreamRegistry
|
|
226
|
+
outstreamProvider: OutstreamProvider
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface WatchJobEmitterOptions {
|
|
230
|
+
file: string
|
|
231
|
+
streamRegistry: StreamRegistry
|
|
232
|
+
recursive?: boolean
|
|
233
|
+
outstreamProvider: OutstreamProvider
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
interface StatLike {
|
|
237
|
+
isDirectory(): boolean
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const fstatAsync = promisify(fs.fstat)
|
|
241
|
+
|
|
242
|
+
async function myStat(
|
|
243
|
+
stdioStream: NodeJS.ReadStream | NodeJS.WriteStream,
|
|
244
|
+
filepath: string,
|
|
245
|
+
): Promise<fs.Stats> {
|
|
246
|
+
if (filepath === '-') {
|
|
247
|
+
const stream = stdioStream as NodeJS.ReadStream & { fd: number }
|
|
248
|
+
return await fstatAsync(stream.fd)
|
|
249
|
+
}
|
|
250
|
+
return await fsp.stat(filepath)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function dirProvider(output: string): OutstreamProvider {
|
|
254
|
+
return async (inpath, indir = process.cwd()) => {
|
|
255
|
+
if (inpath == null || inpath === '-') {
|
|
256
|
+
throw new Error('You must provide an input to output to a directory')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
let relpath = path.relative(indir, inpath)
|
|
260
|
+
relpath = relpath.replace(/^(\.\.\/)+/, '')
|
|
261
|
+
const outpath = path.join(output, relpath)
|
|
262
|
+
const outdir = path.dirname(outpath)
|
|
263
|
+
|
|
264
|
+
await fsp.mkdir(outdir, { recursive: true })
|
|
265
|
+
const [, stats] = await tryCatch(fsp.stat(outpath))
|
|
266
|
+
const mtime = stats?.mtime ?? new Date(0)
|
|
267
|
+
const outstream = fs.createWriteStream(outpath) as OutStream
|
|
268
|
+
// Attach a no-op error handler to prevent unhandled errors if stream is destroyed
|
|
269
|
+
// before being consumed (e.g., due to output collision detection)
|
|
270
|
+
outstream.on('error', () => {})
|
|
271
|
+
outstream.mtime = mtime
|
|
272
|
+
return outstream
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function fileProvider(output: string): OutstreamProvider {
|
|
277
|
+
const dirExistsP = fsp.mkdir(path.dirname(output), { recursive: true })
|
|
278
|
+
return async (_inpath) => {
|
|
279
|
+
await dirExistsP
|
|
280
|
+
if (output === '-') return process.stdout as OutStream
|
|
281
|
+
|
|
282
|
+
const [, stats] = await tryCatch(fsp.stat(output))
|
|
283
|
+
const mtime = stats?.mtime ?? new Date(0)
|
|
284
|
+
const outstream = fs.createWriteStream(output) as OutStream
|
|
285
|
+
// Attach a no-op error handler to prevent unhandled errors if stream is destroyed
|
|
286
|
+
// before being consumed (e.g., due to output collision detection)
|
|
287
|
+
outstream.on('error', () => {})
|
|
288
|
+
outstream.mtime = mtime
|
|
289
|
+
return outstream
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function nullProvider(): OutstreamProvider {
|
|
294
|
+
return async (_inpath) => null
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
class MyEventEmitter extends EventEmitter {
|
|
298
|
+
protected hasEnded: boolean
|
|
299
|
+
|
|
300
|
+
constructor() {
|
|
301
|
+
super()
|
|
302
|
+
this.hasEnded = false
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
override emit(event: string | symbol, ...args: unknown[]): boolean {
|
|
306
|
+
if (this.hasEnded) return false
|
|
307
|
+
if (event === 'end' || event === 'error') {
|
|
308
|
+
this.hasEnded = true
|
|
309
|
+
return super.emit(event, ...args)
|
|
310
|
+
}
|
|
311
|
+
return super.emit(event, ...args)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
class ReaddirJobEmitter extends MyEventEmitter {
|
|
316
|
+
constructor({
|
|
317
|
+
dir,
|
|
318
|
+
streamRegistry,
|
|
319
|
+
recursive,
|
|
320
|
+
outstreamProvider,
|
|
321
|
+
topdir = dir,
|
|
322
|
+
}: ReaddirJobEmitterOptions) {
|
|
323
|
+
super()
|
|
324
|
+
|
|
325
|
+
process.nextTick(() => {
|
|
326
|
+
this.processDirectory({ dir, streamRegistry, recursive, outstreamProvider, topdir }).catch(
|
|
327
|
+
(err) => {
|
|
328
|
+
this.emit('error', err)
|
|
329
|
+
},
|
|
330
|
+
)
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private async processDirectory({
|
|
335
|
+
dir,
|
|
336
|
+
streamRegistry,
|
|
337
|
+
recursive,
|
|
338
|
+
outstreamProvider,
|
|
339
|
+
topdir,
|
|
340
|
+
}: ReaddirJobEmitterOptions & { topdir: string }): Promise<void> {
|
|
341
|
+
const files = await fsp.readdir(dir)
|
|
342
|
+
|
|
343
|
+
const pendingOperations: Promise<void>[] = []
|
|
344
|
+
|
|
345
|
+
for (const filename of files) {
|
|
346
|
+
const file = path.normalize(path.join(dir, filename))
|
|
347
|
+
pendingOperations.push(
|
|
348
|
+
this.processFile({ file, streamRegistry, recursive, outstreamProvider, topdir }),
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
await Promise.all(pendingOperations)
|
|
353
|
+
this.emit('end')
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private async processFile({
|
|
357
|
+
file,
|
|
358
|
+
streamRegistry,
|
|
359
|
+
recursive = false,
|
|
360
|
+
outstreamProvider,
|
|
361
|
+
topdir,
|
|
362
|
+
}: {
|
|
363
|
+
file: string
|
|
364
|
+
streamRegistry: StreamRegistry
|
|
365
|
+
recursive?: boolean
|
|
366
|
+
outstreamProvider: OutstreamProvider
|
|
367
|
+
topdir: string
|
|
368
|
+
}): Promise<void> {
|
|
369
|
+
const stats = await fsp.stat(file)
|
|
370
|
+
|
|
371
|
+
if (stats.isDirectory()) {
|
|
372
|
+
if (recursive) {
|
|
373
|
+
await new Promise<void>((resolve, reject) => {
|
|
374
|
+
const subdirEmitter = new ReaddirJobEmitter({
|
|
375
|
+
dir: file,
|
|
376
|
+
streamRegistry,
|
|
377
|
+
recursive,
|
|
378
|
+
outstreamProvider,
|
|
379
|
+
topdir,
|
|
380
|
+
})
|
|
381
|
+
subdirEmitter.on('job', (job: Job) => this.emit('job', job))
|
|
382
|
+
subdirEmitter.on('error', (error: Error) => reject(error))
|
|
383
|
+
subdirEmitter.on('end', () => resolve())
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
} else {
|
|
387
|
+
const existing = streamRegistry[file]
|
|
388
|
+
if (existing) existing.end()
|
|
389
|
+
const outstream = await outstreamProvider(file, topdir)
|
|
390
|
+
streamRegistry[file] = outstream ?? undefined
|
|
391
|
+
const instream = fs.createReadStream(file)
|
|
392
|
+
// Attach a no-op error handler to prevent unhandled errors if stream is destroyed
|
|
393
|
+
// before being consumed (e.g., due to output collision detection)
|
|
394
|
+
instream.on('error', () => {})
|
|
395
|
+
this.emit('job', { in: instream, out: outstream })
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
class SingleJobEmitter extends MyEventEmitter {
|
|
401
|
+
constructor({ file, streamRegistry, outstreamProvider }: SingleJobEmitterOptions) {
|
|
402
|
+
super()
|
|
403
|
+
|
|
404
|
+
const normalizedFile = path.normalize(file)
|
|
405
|
+
const existing = streamRegistry[normalizedFile]
|
|
406
|
+
if (existing) existing.end()
|
|
407
|
+
outstreamProvider(normalizedFile).then((outstream) => {
|
|
408
|
+
streamRegistry[normalizedFile] = outstream ?? undefined
|
|
409
|
+
|
|
410
|
+
let instream: Readable | null
|
|
411
|
+
if (normalizedFile === '-') {
|
|
412
|
+
if (tty.isatty(process.stdin.fd)) {
|
|
413
|
+
instream = null
|
|
414
|
+
} else {
|
|
415
|
+
instream = process.stdin
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
instream = fs.createReadStream(normalizedFile)
|
|
419
|
+
// Attach a no-op error handler to prevent unhandled errors if stream is destroyed
|
|
420
|
+
// before being consumed (e.g., due to output collision detection)
|
|
421
|
+
instream.on('error', () => {})
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
process.nextTick(() => {
|
|
425
|
+
this.emit('job', { in: instream, out: outstream })
|
|
426
|
+
this.emit('end')
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
class InputlessJobEmitter extends MyEventEmitter {
|
|
433
|
+
constructor({
|
|
434
|
+
outstreamProvider,
|
|
435
|
+
}: { streamRegistry: StreamRegistry; outstreamProvider: OutstreamProvider }) {
|
|
436
|
+
super()
|
|
437
|
+
|
|
438
|
+
process.nextTick(() => {
|
|
439
|
+
outstreamProvider(null).then((outstream) => {
|
|
440
|
+
try {
|
|
441
|
+
this.emit('job', { in: null, out: outstream })
|
|
442
|
+
} catch (err) {
|
|
443
|
+
this.emit('error', err)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
this.emit('end')
|
|
447
|
+
})
|
|
448
|
+
})
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
class NullJobEmitter extends MyEventEmitter {
|
|
453
|
+
constructor() {
|
|
454
|
+
super()
|
|
455
|
+
process.nextTick(() => this.emit('end'))
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
class WatchJobEmitter extends MyEventEmitter {
|
|
460
|
+
private watcher: NodeWatcher | null = null
|
|
461
|
+
|
|
462
|
+
constructor({ file, streamRegistry, recursive, outstreamProvider }: WatchJobEmitterOptions) {
|
|
463
|
+
super()
|
|
464
|
+
|
|
465
|
+
this.init({ file, streamRegistry, recursive, outstreamProvider }).catch((err) => {
|
|
466
|
+
this.emit('error', err)
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
// Clean up watcher on process exit signals
|
|
470
|
+
const cleanup = () => this.close()
|
|
471
|
+
process.once('SIGINT', cleanup)
|
|
472
|
+
process.once('SIGTERM', cleanup)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** Close the file watcher and release resources */
|
|
476
|
+
close(): void {
|
|
477
|
+
if (this.watcher) {
|
|
478
|
+
this.watcher.close()
|
|
479
|
+
this.watcher = null
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
private async init({
|
|
484
|
+
file,
|
|
485
|
+
streamRegistry,
|
|
486
|
+
recursive,
|
|
487
|
+
outstreamProvider,
|
|
488
|
+
}: WatchJobEmitterOptions): Promise<void> {
|
|
489
|
+
const stats = await fsp.stat(file)
|
|
490
|
+
const topdir = stats.isDirectory() ? file : undefined
|
|
491
|
+
|
|
492
|
+
const watchFn = await getNodeWatch()
|
|
493
|
+
this.watcher = watchFn(file, { recursive })
|
|
494
|
+
|
|
495
|
+
this.watcher.on('error', (err: Error) => {
|
|
496
|
+
this.close()
|
|
497
|
+
this.emit('error', err)
|
|
498
|
+
})
|
|
499
|
+
this.watcher.on('close', () => this.emit('end'))
|
|
500
|
+
this.watcher.on('change', (_evt: string, filename: string) => {
|
|
501
|
+
const normalizedFile = path.normalize(filename)
|
|
502
|
+
this.handleChange(normalizedFile, topdir, streamRegistry, outstreamProvider).catch((err) => {
|
|
503
|
+
this.emit('error', err)
|
|
504
|
+
})
|
|
505
|
+
})
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private async handleChange(
|
|
509
|
+
normalizedFile: string,
|
|
510
|
+
topdir: string | undefined,
|
|
511
|
+
streamRegistry: StreamRegistry,
|
|
512
|
+
outstreamProvider: OutstreamProvider,
|
|
513
|
+
): Promise<void> {
|
|
514
|
+
const stats = await fsp.stat(normalizedFile)
|
|
515
|
+
if (stats.isDirectory()) return
|
|
516
|
+
|
|
517
|
+
const existing = streamRegistry[normalizedFile]
|
|
518
|
+
if (existing) existing.end()
|
|
519
|
+
|
|
520
|
+
const outstream = await outstreamProvider(normalizedFile, topdir)
|
|
521
|
+
streamRegistry[normalizedFile] = outstream ?? undefined
|
|
522
|
+
|
|
523
|
+
const instream = fs.createReadStream(normalizedFile)
|
|
524
|
+
// Attach a no-op error handler to prevent unhandled errors if stream is destroyed
|
|
525
|
+
// before being consumed (e.g., due to output collision detection)
|
|
526
|
+
instream.on('error', () => {})
|
|
527
|
+
this.emit('job', { in: instream, out: outstream })
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
class MergedJobEmitter extends MyEventEmitter {
|
|
532
|
+
constructor(...jobEmitters: MyEventEmitter[]) {
|
|
533
|
+
super()
|
|
534
|
+
|
|
535
|
+
let ncomplete = 0
|
|
536
|
+
|
|
537
|
+
for (const jobEmitter of jobEmitters) {
|
|
538
|
+
jobEmitter.on('error', (err: Error) => this.emit('error', err))
|
|
539
|
+
jobEmitter.on('job', (job: Job) => this.emit('job', job))
|
|
540
|
+
jobEmitter.on('end', () => {
|
|
541
|
+
if (++ncomplete === jobEmitters.length) this.emit('end')
|
|
542
|
+
})
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (jobEmitters.length === 0) {
|
|
546
|
+
this.emit('end')
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
class ConcattedJobEmitter extends MyEventEmitter {
|
|
552
|
+
constructor(emitterFn: () => MyEventEmitter, ...emitterFns: (() => MyEventEmitter)[]) {
|
|
553
|
+
super()
|
|
554
|
+
|
|
555
|
+
const emitter = emitterFn()
|
|
556
|
+
|
|
557
|
+
emitter.on('error', (err: Error) => this.emit('error', err))
|
|
558
|
+
emitter.on('job', (job: Job) => this.emit('job', job))
|
|
559
|
+
|
|
560
|
+
if (emitterFns.length === 0) {
|
|
561
|
+
emitter.on('end', () => this.emit('end'))
|
|
562
|
+
} else {
|
|
563
|
+
emitter.on('end', () => {
|
|
564
|
+
const firstFn = emitterFns[0]
|
|
565
|
+
if (!firstFn) {
|
|
566
|
+
this.emit('end')
|
|
567
|
+
return
|
|
568
|
+
}
|
|
569
|
+
const restEmitter = new ConcattedJobEmitter(firstFn, ...emitterFns.slice(1))
|
|
570
|
+
restEmitter.on('error', (err: Error) => this.emit('error', err))
|
|
571
|
+
restEmitter.on('job', (job: Job) => this.emit('job', job))
|
|
572
|
+
restEmitter.on('end', () => this.emit('end'))
|
|
573
|
+
})
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function detectConflicts(jobEmitter: EventEmitter): MyEventEmitter {
|
|
579
|
+
const emitter = new MyEventEmitter()
|
|
580
|
+
const outfileAssociations: Record<string, string> = {}
|
|
581
|
+
|
|
582
|
+
jobEmitter.on('end', () => emitter.emit('end'))
|
|
583
|
+
jobEmitter.on('error', (err: Error) => emitter.emit('error', err))
|
|
584
|
+
jobEmitter.on('job', (job: Job) => {
|
|
585
|
+
if (job.in == null || job.out == null) {
|
|
586
|
+
emitter.emit('job', job)
|
|
587
|
+
return
|
|
588
|
+
}
|
|
589
|
+
const inPath = (job.in as fs.ReadStream).path as string
|
|
590
|
+
const outPath = job.out.path as string
|
|
591
|
+
if (Object.hasOwn(outfileAssociations, outPath) && outfileAssociations[outPath] !== inPath) {
|
|
592
|
+
emitter.emit(
|
|
593
|
+
'error',
|
|
594
|
+
new Error(`Output collision between '${inPath}' and '${outfileAssociations[outPath]}'`),
|
|
595
|
+
)
|
|
596
|
+
} else {
|
|
597
|
+
outfileAssociations[outPath] = inPath
|
|
598
|
+
emitter.emit('job', job)
|
|
599
|
+
}
|
|
600
|
+
})
|
|
601
|
+
|
|
602
|
+
return emitter
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function dismissStaleJobs(jobEmitter: EventEmitter): MyEventEmitter {
|
|
606
|
+
const emitter = new MyEventEmitter()
|
|
607
|
+
const pendingChecks: Promise<void>[] = []
|
|
608
|
+
|
|
609
|
+
jobEmitter.on('end', () => Promise.all(pendingChecks).then(() => emitter.emit('end')))
|
|
610
|
+
jobEmitter.on('error', (err: Error) => emitter.emit('error', err))
|
|
611
|
+
jobEmitter.on('job', (job: Job) => {
|
|
612
|
+
if (job.in == null || job.out == null) {
|
|
613
|
+
emitter.emit('job', job)
|
|
614
|
+
return
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const inPath = (job.in as fs.ReadStream).path as string
|
|
618
|
+
const checkPromise = fsp
|
|
619
|
+
.stat(inPath)
|
|
620
|
+
.then((stats) => {
|
|
621
|
+
const inM = stats.mtime
|
|
622
|
+
const outM = job.out?.mtime ?? new Date(0)
|
|
623
|
+
|
|
624
|
+
if (outM <= inM) emitter.emit('job', job)
|
|
625
|
+
})
|
|
626
|
+
.catch(() => {
|
|
627
|
+
emitter.emit('job', job)
|
|
628
|
+
})
|
|
629
|
+
pendingChecks.push(checkPromise)
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
return emitter
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function makeJobEmitter(
|
|
636
|
+
inputs: string[],
|
|
637
|
+
{
|
|
638
|
+
recursive,
|
|
639
|
+
outstreamProvider,
|
|
640
|
+
streamRegistry,
|
|
641
|
+
watch: watchOption,
|
|
642
|
+
reprocessStale,
|
|
643
|
+
}: JobEmitterOptions,
|
|
644
|
+
): MyEventEmitter {
|
|
645
|
+
const emitter = new EventEmitter()
|
|
646
|
+
|
|
647
|
+
const emitterFns: (() => MyEventEmitter)[] = []
|
|
648
|
+
const watcherFns: (() => MyEventEmitter)[] = []
|
|
649
|
+
|
|
650
|
+
async function processInputs(): Promise<void> {
|
|
651
|
+
for (const input of inputs) {
|
|
652
|
+
if (input === '-') {
|
|
653
|
+
emitterFns.push(
|
|
654
|
+
() => new SingleJobEmitter({ file: input, outstreamProvider, streamRegistry }),
|
|
655
|
+
)
|
|
656
|
+
watcherFns.push(() => new NullJobEmitter())
|
|
657
|
+
} else {
|
|
658
|
+
const stats = await fsp.stat(input)
|
|
659
|
+
if (stats.isDirectory()) {
|
|
660
|
+
emitterFns.push(
|
|
661
|
+
() =>
|
|
662
|
+
new ReaddirJobEmitter({ dir: input, recursive, outstreamProvider, streamRegistry }),
|
|
663
|
+
)
|
|
664
|
+
watcherFns.push(
|
|
665
|
+
() =>
|
|
666
|
+
new WatchJobEmitter({ file: input, recursive, outstreamProvider, streamRegistry }),
|
|
667
|
+
)
|
|
668
|
+
} else {
|
|
669
|
+
emitterFns.push(
|
|
670
|
+
() => new SingleJobEmitter({ file: input, outstreamProvider, streamRegistry }),
|
|
671
|
+
)
|
|
672
|
+
watcherFns.push(
|
|
673
|
+
() =>
|
|
674
|
+
new WatchJobEmitter({ file: input, recursive, outstreamProvider, streamRegistry }),
|
|
675
|
+
)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (inputs.length === 0) {
|
|
681
|
+
emitterFns.push(() => new InputlessJobEmitter({ outstreamProvider, streamRegistry }))
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
startEmitting()
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function startEmitting(): void {
|
|
688
|
+
let source: MyEventEmitter = new MergedJobEmitter(...emitterFns.map((f) => f()))
|
|
689
|
+
|
|
690
|
+
if (watchOption) {
|
|
691
|
+
source = new ConcattedJobEmitter(
|
|
692
|
+
() => source,
|
|
693
|
+
() => new MergedJobEmitter(...watcherFns.map((f) => f())),
|
|
694
|
+
)
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
source.on('job', (job: Job) => emitter.emit('job', job))
|
|
698
|
+
source.on('error', (err: Error) => emitter.emit('error', err))
|
|
699
|
+
source.on('end', () => emitter.emit('end'))
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
processInputs().catch((err) => {
|
|
703
|
+
emitter.emit('error', err)
|
|
704
|
+
})
|
|
705
|
+
|
|
706
|
+
const stalefilter = reprocessStale ? (x: EventEmitter) => x as MyEventEmitter : dismissStaleJobs
|
|
707
|
+
return stalefilter(detectConflicts(emitter))
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
export interface AssembliesCreateOptions {
|
|
711
|
+
steps?: string
|
|
712
|
+
template?: string
|
|
713
|
+
fields?: Record<string, string>
|
|
714
|
+
watch?: boolean
|
|
715
|
+
recursive?: boolean
|
|
716
|
+
inputs: string[]
|
|
717
|
+
output?: string | null
|
|
718
|
+
del?: boolean
|
|
719
|
+
reprocessStale?: boolean
|
|
720
|
+
singleAssembly?: boolean
|
|
721
|
+
concurrency?: number
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const DEFAULT_CONCURRENCY = 5
|
|
725
|
+
|
|
726
|
+
// --- Main assembly create function ---
|
|
727
|
+
export async function create(
|
|
728
|
+
outputctl: IOutputCtl,
|
|
729
|
+
client: Transloadit,
|
|
730
|
+
{
|
|
731
|
+
steps,
|
|
732
|
+
template,
|
|
733
|
+
fields,
|
|
734
|
+
watch: watchOption,
|
|
735
|
+
recursive,
|
|
736
|
+
inputs,
|
|
737
|
+
output,
|
|
738
|
+
del,
|
|
739
|
+
reprocessStale,
|
|
740
|
+
singleAssembly,
|
|
741
|
+
concurrency = DEFAULT_CONCURRENCY,
|
|
742
|
+
}: AssembliesCreateOptions,
|
|
743
|
+
): Promise<{ results: unknown[]; hasFailures: boolean }> {
|
|
744
|
+
// Quick fix for https://github.com/transloadit/transloadify/issues/13
|
|
745
|
+
// Only default to stdout when output is undefined (not provided), not when explicitly null
|
|
746
|
+
let resolvedOutput = output
|
|
747
|
+
if (resolvedOutput === undefined && !process.stdout.isTTY) resolvedOutput = '-'
|
|
748
|
+
|
|
749
|
+
// Read steps file async before entering the Promise constructor
|
|
750
|
+
// We use StepsInput (the input type) rather than Steps (the transformed output type)
|
|
751
|
+
// to avoid zod adding default values that the API may reject
|
|
752
|
+
let stepsData: StepsInput | undefined
|
|
753
|
+
if (steps) {
|
|
754
|
+
const stepsContent = await fsp.readFile(steps, 'utf8')
|
|
755
|
+
const parsed: unknown = JSON.parse(stepsContent)
|
|
756
|
+
// Basic structural validation: must be an object with step names as keys
|
|
757
|
+
if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
758
|
+
throw new Error('Invalid steps format: expected an object with step names as keys')
|
|
759
|
+
}
|
|
760
|
+
// Validate each step has a robot field
|
|
761
|
+
for (const [stepName, step] of Object.entries(parsed)) {
|
|
762
|
+
if (step == null || typeof step !== 'object' || Array.isArray(step)) {
|
|
763
|
+
throw new Error(`Invalid steps format: step '${stepName}' must be an object`)
|
|
764
|
+
}
|
|
765
|
+
if (!('robot' in step) || typeof (step as Record<string, unknown>).robot !== 'string') {
|
|
766
|
+
throw new Error(
|
|
767
|
+
`Invalid steps format: step '${stepName}' must have a 'robot' string property`,
|
|
768
|
+
)
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
stepsData = parsed as StepsInput
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Determine output stat async before entering the Promise constructor
|
|
775
|
+
let outstat: StatLike | undefined
|
|
776
|
+
if (resolvedOutput != null) {
|
|
777
|
+
const [err, stat] = await tryCatch(myStat(process.stdout, resolvedOutput))
|
|
778
|
+
if (err && (!isErrnoException(err) || err.code !== 'ENOENT')) throw err
|
|
779
|
+
outstat = stat ?? { isDirectory: () => false }
|
|
780
|
+
|
|
781
|
+
if (!outstat.isDirectory() && inputs.length !== 0) {
|
|
782
|
+
const firstInput = inputs[0]
|
|
783
|
+
if (firstInput) {
|
|
784
|
+
const firstInputStat = await myStat(process.stdin, firstInput)
|
|
785
|
+
if (inputs.length > 1 || firstInputStat.isDirectory()) {
|
|
786
|
+
const msg = 'Output must be a directory when specifying multiple inputs'
|
|
787
|
+
outputctl.error(msg)
|
|
788
|
+
throw new Error(msg)
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
return new Promise((resolve, reject) => {
|
|
795
|
+
const params: CreateAssemblyParams = (
|
|
796
|
+
stepsData ? { steps: stepsData as CreateAssemblyParams['steps'] } : { template_id: template }
|
|
797
|
+
) as CreateAssemblyParams
|
|
798
|
+
if (fields) {
|
|
799
|
+
params.fields = fields
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const outstreamProvider: OutstreamProvider =
|
|
803
|
+
resolvedOutput == null
|
|
804
|
+
? nullProvider()
|
|
805
|
+
: outstat?.isDirectory()
|
|
806
|
+
? dirProvider(resolvedOutput)
|
|
807
|
+
: fileProvider(resolvedOutput)
|
|
808
|
+
const streamRegistry: StreamRegistry = {}
|
|
809
|
+
|
|
810
|
+
const emitter = makeJobEmitter(inputs, {
|
|
811
|
+
recursive,
|
|
812
|
+
watch: watchOption,
|
|
813
|
+
outstreamProvider,
|
|
814
|
+
streamRegistry,
|
|
815
|
+
reprocessStale,
|
|
816
|
+
})
|
|
817
|
+
|
|
818
|
+
// Use p-queue for concurrency management
|
|
819
|
+
const queue = new PQueue({ concurrency })
|
|
820
|
+
const results: unknown[] = []
|
|
821
|
+
let hasFailures = false
|
|
822
|
+
// AbortController to cancel all in-flight createAssembly calls when an error occurs
|
|
823
|
+
const abortController = new AbortController()
|
|
824
|
+
|
|
825
|
+
// Helper to process a single assembly job
|
|
826
|
+
async function processAssemblyJob(
|
|
827
|
+
inPath: string | null,
|
|
828
|
+
outPath: string | null,
|
|
829
|
+
outMtime: Date | undefined,
|
|
830
|
+
): Promise<unknown> {
|
|
831
|
+
outputctl.debug(`PROCESSING JOB ${inPath ?? 'null'} ${outPath ?? 'null'}`)
|
|
832
|
+
|
|
833
|
+
// Create fresh streams for this job
|
|
834
|
+
const inStream = inPath ? fs.createReadStream(inPath) : null
|
|
835
|
+
inStream?.on('error', () => {})
|
|
836
|
+
const outStream = outPath ? (fs.createWriteStream(outPath) as OutStream) : null
|
|
837
|
+
outStream?.on('error', () => {})
|
|
838
|
+
if (outStream) outStream.mtime = outMtime
|
|
839
|
+
|
|
840
|
+
let superceded = false
|
|
841
|
+
if (outStream != null) {
|
|
842
|
+
outStream.on('finish', () => {
|
|
843
|
+
superceded = true
|
|
844
|
+
})
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const createOptions: CreateAssemblyOptions = {
|
|
848
|
+
params,
|
|
849
|
+
signal: abortController.signal,
|
|
850
|
+
}
|
|
851
|
+
if (inStream != null) {
|
|
852
|
+
createOptions.uploads = { in: inStream }
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const result = await client.createAssembly(createOptions)
|
|
856
|
+
if (superceded) return undefined
|
|
857
|
+
|
|
858
|
+
const assemblyId = result.assembly_id
|
|
859
|
+
if (!assemblyId) throw new Error('No assembly_id in result')
|
|
860
|
+
|
|
861
|
+
const assembly = await client.awaitAssemblyCompletion(assemblyId, {
|
|
862
|
+
signal: abortController.signal,
|
|
863
|
+
onPoll: () => {
|
|
864
|
+
if (superceded) return false
|
|
865
|
+
return true
|
|
866
|
+
},
|
|
867
|
+
onAssemblyProgress: (status) => {
|
|
868
|
+
outputctl.debug(`Assembly status: ${status.ok}`)
|
|
869
|
+
},
|
|
870
|
+
})
|
|
871
|
+
|
|
872
|
+
if (superceded) return undefined
|
|
873
|
+
|
|
874
|
+
if (assembly.error || (assembly.ok && assembly.ok !== 'ASSEMBLY_COMPLETED')) {
|
|
875
|
+
const msg = `Assembly failed: ${assembly.error || assembly.message} (Status: ${assembly.ok})`
|
|
876
|
+
outputctl.error(msg)
|
|
877
|
+
throw new Error(msg)
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if (!assembly.results) throw new Error('No results in assembly')
|
|
881
|
+
const resultsKeys = Object.keys(assembly.results)
|
|
882
|
+
const firstKey = resultsKeys[0]
|
|
883
|
+
if (!firstKey) throw new Error('No results in assembly')
|
|
884
|
+
const firstResult = assembly.results[firstKey]
|
|
885
|
+
if (!firstResult || !firstResult[0]) throw new Error('No results in assembly')
|
|
886
|
+
const resulturl = firstResult[0].url
|
|
887
|
+
|
|
888
|
+
if (outStream != null && resulturl && !superceded) {
|
|
889
|
+
outputctl.debug('DOWNLOADING')
|
|
890
|
+
const [dlErr] = await tryCatch(
|
|
891
|
+
pipeline(got.stream(resulturl, { signal: abortController.signal }), outStream),
|
|
892
|
+
)
|
|
893
|
+
if (dlErr) {
|
|
894
|
+
if (dlErr.name !== 'AbortError') {
|
|
895
|
+
outputctl.error(dlErr.message)
|
|
896
|
+
throw dlErr
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
outputctl.debug(`COMPLETED ${inPath ?? 'null'} ${outPath ?? 'null'}`)
|
|
902
|
+
|
|
903
|
+
if (del && inPath) {
|
|
904
|
+
await fsp.unlink(inPath)
|
|
905
|
+
}
|
|
906
|
+
return assembly
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
if (singleAssembly) {
|
|
910
|
+
// Single-assembly mode: collect file paths, then create one assembly with all inputs
|
|
911
|
+
// We close streams immediately to avoid exhausting file descriptors with many files
|
|
912
|
+
const collectedPaths: string[] = []
|
|
913
|
+
|
|
914
|
+
emitter.on('job', (job: Job) => {
|
|
915
|
+
if (job.in != null) {
|
|
916
|
+
const inPath = (job.in as fs.ReadStream).path as string
|
|
917
|
+
outputctl.debug(`COLLECTING JOB ${inPath}`)
|
|
918
|
+
collectedPaths.push(inPath)
|
|
919
|
+
// Close the stream immediately to avoid file descriptor exhaustion
|
|
920
|
+
;(job.in as fs.ReadStream).destroy()
|
|
921
|
+
outputctl.debug(`STREAM CLOSED ${inPath}`)
|
|
922
|
+
}
|
|
923
|
+
})
|
|
924
|
+
|
|
925
|
+
emitter.on('error', (err: Error) => {
|
|
926
|
+
abortController.abort()
|
|
927
|
+
queue.clear()
|
|
928
|
+
outputctl.error(err)
|
|
929
|
+
reject(err)
|
|
930
|
+
})
|
|
931
|
+
|
|
932
|
+
emitter.on('end', async () => {
|
|
933
|
+
if (collectedPaths.length === 0) {
|
|
934
|
+
resolve({ results: [], hasFailures: false })
|
|
935
|
+
return
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// Build uploads object, creating fresh streams for each file
|
|
939
|
+
const uploads: Record<string, Readable> = {}
|
|
940
|
+
const inputPaths: string[] = []
|
|
941
|
+
for (const inPath of collectedPaths) {
|
|
942
|
+
const basename = path.basename(inPath)
|
|
943
|
+
let key = basename
|
|
944
|
+
let counter = 1
|
|
945
|
+
while (key in uploads) {
|
|
946
|
+
key = `${path.parse(basename).name}_${counter}${path.parse(basename).ext}`
|
|
947
|
+
counter++
|
|
948
|
+
}
|
|
949
|
+
uploads[key] = fs.createReadStream(inPath)
|
|
950
|
+
inputPaths.push(inPath)
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
outputctl.debug(`Creating single assembly with ${Object.keys(uploads).length} files`)
|
|
954
|
+
|
|
955
|
+
try {
|
|
956
|
+
const assembly = await queue.add(async () => {
|
|
957
|
+
const createOptions: CreateAssemblyOptions = {
|
|
958
|
+
params,
|
|
959
|
+
signal: abortController.signal,
|
|
960
|
+
}
|
|
961
|
+
if (Object.keys(uploads).length > 0) {
|
|
962
|
+
createOptions.uploads = uploads
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const result = await client.createAssembly(createOptions)
|
|
966
|
+
const assemblyId = result.assembly_id
|
|
967
|
+
if (!assemblyId) throw new Error('No assembly_id in result')
|
|
968
|
+
|
|
969
|
+
const asm = await client.awaitAssemblyCompletion(assemblyId, {
|
|
970
|
+
signal: abortController.signal,
|
|
971
|
+
onAssemblyProgress: (status) => {
|
|
972
|
+
outputctl.debug(`Assembly status: ${status.ok}`)
|
|
973
|
+
},
|
|
974
|
+
})
|
|
975
|
+
|
|
976
|
+
if (asm.error || (asm.ok && asm.ok !== 'ASSEMBLY_COMPLETED')) {
|
|
977
|
+
const msg = `Assembly failed: ${asm.error || asm.message} (Status: ${asm.ok})`
|
|
978
|
+
outputctl.error(msg)
|
|
979
|
+
throw new Error(msg)
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Download all results
|
|
983
|
+
if (asm.results && resolvedOutput != null) {
|
|
984
|
+
for (const [stepName, stepResults] of Object.entries(asm.results)) {
|
|
985
|
+
for (const stepResult of stepResults) {
|
|
986
|
+
const resultUrl = stepResult.url
|
|
987
|
+
if (!resultUrl) continue
|
|
988
|
+
|
|
989
|
+
let outPath: string
|
|
990
|
+
if (outstat?.isDirectory()) {
|
|
991
|
+
outPath = path.join(resolvedOutput, stepResult.name || `${stepName}_result`)
|
|
992
|
+
} else {
|
|
993
|
+
outPath = resolvedOutput
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
outputctl.debug(`DOWNLOADING ${stepResult.name} to ${outPath}`)
|
|
997
|
+
const [dlErr] = await tryCatch(
|
|
998
|
+
pipeline(
|
|
999
|
+
got.stream(resultUrl, { signal: abortController.signal }),
|
|
1000
|
+
fs.createWriteStream(outPath),
|
|
1001
|
+
),
|
|
1002
|
+
)
|
|
1003
|
+
if (dlErr) {
|
|
1004
|
+
if (dlErr.name === 'AbortError') continue
|
|
1005
|
+
outputctl.error(dlErr.message)
|
|
1006
|
+
throw dlErr
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// Delete input files if requested
|
|
1013
|
+
if (del) {
|
|
1014
|
+
for (const inPath of inputPaths) {
|
|
1015
|
+
await fsp.unlink(inPath)
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return asm
|
|
1019
|
+
})
|
|
1020
|
+
results.push(assembly)
|
|
1021
|
+
} catch (err) {
|
|
1022
|
+
hasFailures = true
|
|
1023
|
+
outputctl.error(err as Error)
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
resolve({ results, hasFailures })
|
|
1027
|
+
})
|
|
1028
|
+
} else {
|
|
1029
|
+
// Default mode: one assembly per file with p-queue concurrency limiting
|
|
1030
|
+
emitter.on('job', (job: Job) => {
|
|
1031
|
+
const inPath = job.in
|
|
1032
|
+
? (((job.in as fs.ReadStream).path as string | undefined) ?? null)
|
|
1033
|
+
: null
|
|
1034
|
+
const outPath = job.out?.path ?? null
|
|
1035
|
+
const outMtime = job.out?.mtime
|
|
1036
|
+
outputctl.debug(`GOT JOB ${inPath ?? 'null'} ${outPath ?? 'null'}`)
|
|
1037
|
+
|
|
1038
|
+
// Close the original streams immediately - we'll create fresh ones when processing
|
|
1039
|
+
if (job.in != null) {
|
|
1040
|
+
;(job.in as fs.ReadStream).destroy()
|
|
1041
|
+
}
|
|
1042
|
+
if (job.out != null) {
|
|
1043
|
+
job.out.destroy()
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// Add job to queue - p-queue handles concurrency automatically
|
|
1047
|
+
queue
|
|
1048
|
+
.add(async () => {
|
|
1049
|
+
const result = await processAssemblyJob(inPath, outPath, outMtime)
|
|
1050
|
+
if (result !== undefined) {
|
|
1051
|
+
results.push(result)
|
|
1052
|
+
}
|
|
1053
|
+
})
|
|
1054
|
+
.catch((err: unknown) => {
|
|
1055
|
+
hasFailures = true
|
|
1056
|
+
outputctl.error(err as Error)
|
|
1057
|
+
})
|
|
1058
|
+
})
|
|
1059
|
+
|
|
1060
|
+
emitter.on('error', (err: Error) => {
|
|
1061
|
+
abortController.abort()
|
|
1062
|
+
queue.clear()
|
|
1063
|
+
outputctl.error(err)
|
|
1064
|
+
reject(err)
|
|
1065
|
+
})
|
|
1066
|
+
|
|
1067
|
+
emitter.on('end', async () => {
|
|
1068
|
+
// Wait for all queued jobs to complete
|
|
1069
|
+
await queue.onIdle()
|
|
1070
|
+
resolve({ results, hasFailures })
|
|
1071
|
+
})
|
|
1072
|
+
}
|
|
1073
|
+
})
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// --- Command classes ---
|
|
1077
|
+
export class AssembliesCreateCommand extends AuthenticatedCommand {
|
|
1078
|
+
static override paths = [
|
|
1079
|
+
['assemblies', 'create'],
|
|
1080
|
+
['assembly', 'create'],
|
|
1081
|
+
['a', 'create'],
|
|
1082
|
+
['a', 'c'],
|
|
1083
|
+
]
|
|
1084
|
+
|
|
1085
|
+
static override usage = Command.Usage({
|
|
1086
|
+
category: 'Assemblies',
|
|
1087
|
+
description: 'Create assemblies to process media',
|
|
1088
|
+
details: `
|
|
1089
|
+
Create assemblies to process media files using Transloadit.
|
|
1090
|
+
You must specify either --steps or --template.
|
|
1091
|
+
`,
|
|
1092
|
+
examples: [
|
|
1093
|
+
[
|
|
1094
|
+
'Process a file with steps',
|
|
1095
|
+
'transloadit assemblies create --steps steps.json -i input.jpg -o output.jpg',
|
|
1096
|
+
],
|
|
1097
|
+
[
|
|
1098
|
+
'Process with a template',
|
|
1099
|
+
'transloadit assemblies create --template TEMPLATE_ID -i input.jpg -o output/',
|
|
1100
|
+
],
|
|
1101
|
+
[
|
|
1102
|
+
'Watch for changes',
|
|
1103
|
+
'transloadit assemblies create --steps steps.json -i input/ -o output/ --watch',
|
|
1104
|
+
],
|
|
1105
|
+
],
|
|
1106
|
+
})
|
|
1107
|
+
|
|
1108
|
+
steps = Option.String('--steps,-s', {
|
|
1109
|
+
description: 'Specify assembly instructions with a JSON file',
|
|
1110
|
+
})
|
|
1111
|
+
|
|
1112
|
+
template = Option.String('--template,-t', {
|
|
1113
|
+
description: 'Specify a template to use for these assemblies',
|
|
1114
|
+
})
|
|
1115
|
+
|
|
1116
|
+
inputs = Option.Array('--input,-i', {
|
|
1117
|
+
description: 'Provide an input file or a directory',
|
|
1118
|
+
})
|
|
1119
|
+
|
|
1120
|
+
outputPath = Option.String('--output,-o', {
|
|
1121
|
+
description: 'Specify an output file or directory',
|
|
1122
|
+
})
|
|
1123
|
+
|
|
1124
|
+
fields = Option.Array('--field,-f', {
|
|
1125
|
+
description: 'Set a template field (KEY=VAL)',
|
|
1126
|
+
})
|
|
1127
|
+
|
|
1128
|
+
watch = Option.Boolean('--watch,-w', false, {
|
|
1129
|
+
description: 'Watch inputs for changes',
|
|
1130
|
+
})
|
|
1131
|
+
|
|
1132
|
+
recursive = Option.Boolean('--recursive,-r', false, {
|
|
1133
|
+
description: 'Enumerate input directories recursively',
|
|
1134
|
+
})
|
|
1135
|
+
|
|
1136
|
+
deleteAfterProcessing = Option.Boolean('--delete-after-processing,-d', false, {
|
|
1137
|
+
description: 'Delete input files after they are processed',
|
|
1138
|
+
})
|
|
1139
|
+
|
|
1140
|
+
reprocessStale = Option.Boolean('--reprocess-stale', false, {
|
|
1141
|
+
description: 'Process inputs even if output is newer',
|
|
1142
|
+
})
|
|
1143
|
+
|
|
1144
|
+
singleAssembly = Option.Boolean('--single-assembly', false, {
|
|
1145
|
+
description: 'Pass all input files to a single assembly instead of one assembly per file',
|
|
1146
|
+
})
|
|
1147
|
+
|
|
1148
|
+
concurrency = Option.String('--concurrency,-c', {
|
|
1149
|
+
description: 'Maximum number of concurrent assemblies (default: 5)',
|
|
1150
|
+
validator: t.isNumber(),
|
|
1151
|
+
})
|
|
1152
|
+
|
|
1153
|
+
protected async run(): Promise<number | undefined> {
|
|
1154
|
+
if (!this.steps && !this.template) {
|
|
1155
|
+
this.output.error('assemblies create requires exactly one of either --steps or --template')
|
|
1156
|
+
return 1
|
|
1157
|
+
}
|
|
1158
|
+
if (this.steps && this.template) {
|
|
1159
|
+
this.output.error('assemblies create requires exactly one of either --steps or --template')
|
|
1160
|
+
return 1
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
const inputList = this.inputs ?? []
|
|
1164
|
+
if (inputList.length === 0 && this.watch) {
|
|
1165
|
+
this.output.error('assemblies create --watch requires at least one input')
|
|
1166
|
+
return 1
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Default to stdin if no inputs and not a TTY
|
|
1170
|
+
if (inputList.length === 0 && !process.stdin.isTTY) {
|
|
1171
|
+
inputList.push('-')
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
const fieldsMap: Record<string, string> = {}
|
|
1175
|
+
for (const field of this.fields ?? []) {
|
|
1176
|
+
const eqIndex = field.indexOf('=')
|
|
1177
|
+
if (eqIndex === -1) {
|
|
1178
|
+
this.output.error(`invalid argument for --field: '${field}'`)
|
|
1179
|
+
return 1
|
|
1180
|
+
}
|
|
1181
|
+
const key = field.slice(0, eqIndex)
|
|
1182
|
+
const value = field.slice(eqIndex + 1)
|
|
1183
|
+
fieldsMap[key] = value
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
if (this.singleAssembly && this.watch) {
|
|
1187
|
+
this.output.error('--single-assembly cannot be used with --watch')
|
|
1188
|
+
return 1
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
const { hasFailures } = await create(this.output, this.client, {
|
|
1192
|
+
steps: this.steps,
|
|
1193
|
+
template: this.template,
|
|
1194
|
+
fields: fieldsMap,
|
|
1195
|
+
watch: this.watch,
|
|
1196
|
+
recursive: this.recursive,
|
|
1197
|
+
inputs: inputList,
|
|
1198
|
+
output: this.outputPath ?? null,
|
|
1199
|
+
del: this.deleteAfterProcessing,
|
|
1200
|
+
reprocessStale: this.reprocessStale,
|
|
1201
|
+
singleAssembly: this.singleAssembly,
|
|
1202
|
+
concurrency: this.concurrency,
|
|
1203
|
+
})
|
|
1204
|
+
return hasFailures ? 1 : undefined
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
export class AssembliesListCommand extends AuthenticatedCommand {
|
|
1209
|
+
static override paths = [
|
|
1210
|
+
['assemblies', 'list'],
|
|
1211
|
+
['assembly', 'list'],
|
|
1212
|
+
['a', 'list'],
|
|
1213
|
+
['a', 'l'],
|
|
1214
|
+
]
|
|
1215
|
+
|
|
1216
|
+
static override usage = Command.Usage({
|
|
1217
|
+
category: 'Assemblies',
|
|
1218
|
+
description: 'List assemblies matching given criteria',
|
|
1219
|
+
examples: [
|
|
1220
|
+
['List recent assemblies', 'transloadit assemblies list'],
|
|
1221
|
+
['List assemblies after a date', 'transloadit assemblies list --after 2024-01-01'],
|
|
1222
|
+
],
|
|
1223
|
+
})
|
|
1224
|
+
|
|
1225
|
+
before = Option.String('--before,-b', {
|
|
1226
|
+
description: 'Return only assemblies created before specified date',
|
|
1227
|
+
})
|
|
1228
|
+
|
|
1229
|
+
after = Option.String('--after,-a', {
|
|
1230
|
+
description: 'Return only assemblies created after specified date',
|
|
1231
|
+
})
|
|
1232
|
+
|
|
1233
|
+
keywords = Option.String('--keywords', {
|
|
1234
|
+
description: 'Comma-separated list of keywords to match assemblies',
|
|
1235
|
+
})
|
|
1236
|
+
|
|
1237
|
+
fields = Option.String('--fields', {
|
|
1238
|
+
description: 'Comma-separated list of fields to return for each assembly',
|
|
1239
|
+
})
|
|
1240
|
+
|
|
1241
|
+
protected async run(): Promise<number | undefined> {
|
|
1242
|
+
const keywordList = this.keywords ? this.keywords.split(',') : undefined
|
|
1243
|
+
const fieldList = this.fields ? this.fields.split(',') : undefined
|
|
1244
|
+
|
|
1245
|
+
await list(this.output, this.client, {
|
|
1246
|
+
before: this.before,
|
|
1247
|
+
after: this.after,
|
|
1248
|
+
keywords: keywordList,
|
|
1249
|
+
fields: fieldList,
|
|
1250
|
+
})
|
|
1251
|
+
return undefined
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
export class AssembliesGetCommand extends AuthenticatedCommand {
|
|
1256
|
+
static override paths = [
|
|
1257
|
+
['assemblies', 'get'],
|
|
1258
|
+
['assembly', 'get'],
|
|
1259
|
+
['a', 'get'],
|
|
1260
|
+
['a', 'g'],
|
|
1261
|
+
]
|
|
1262
|
+
|
|
1263
|
+
static override usage = Command.Usage({
|
|
1264
|
+
category: 'Assemblies',
|
|
1265
|
+
description: 'Fetch assembly statuses',
|
|
1266
|
+
examples: [['Get assembly status', 'transloadit assemblies get ASSEMBLY_ID']],
|
|
1267
|
+
})
|
|
1268
|
+
|
|
1269
|
+
assemblyIds = Option.Rest({ required: 1 })
|
|
1270
|
+
|
|
1271
|
+
protected async run(): Promise<number | undefined> {
|
|
1272
|
+
await get(this.output, this.client, {
|
|
1273
|
+
assemblies: this.assemblyIds,
|
|
1274
|
+
})
|
|
1275
|
+
return undefined
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
export class AssembliesDeleteCommand extends AuthenticatedCommand {
|
|
1280
|
+
static override paths = [
|
|
1281
|
+
['assemblies', 'delete'],
|
|
1282
|
+
['assembly', 'delete'],
|
|
1283
|
+
['a', 'delete'],
|
|
1284
|
+
['a', 'd'],
|
|
1285
|
+
['assemblies', 'cancel'],
|
|
1286
|
+
['assembly', 'cancel'],
|
|
1287
|
+
]
|
|
1288
|
+
|
|
1289
|
+
static override usage = Command.Usage({
|
|
1290
|
+
category: 'Assemblies',
|
|
1291
|
+
description: 'Cancel assemblies',
|
|
1292
|
+
examples: [['Cancel an assembly', 'transloadit assemblies delete ASSEMBLY_ID']],
|
|
1293
|
+
})
|
|
1294
|
+
|
|
1295
|
+
assemblyIds = Option.Rest({ required: 1 })
|
|
1296
|
+
|
|
1297
|
+
protected async run(): Promise<number | undefined> {
|
|
1298
|
+
await deleteAssemblies(this.output, this.client, {
|
|
1299
|
+
assemblies: this.assemblyIds,
|
|
1300
|
+
})
|
|
1301
|
+
return undefined
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
export class AssembliesReplayCommand extends AuthenticatedCommand {
|
|
1306
|
+
static override paths = [
|
|
1307
|
+
['assemblies', 'replay'],
|
|
1308
|
+
['assembly', 'replay'],
|
|
1309
|
+
['a', 'replay'],
|
|
1310
|
+
['a', 'r'],
|
|
1311
|
+
]
|
|
1312
|
+
|
|
1313
|
+
static override usage = Command.Usage({
|
|
1314
|
+
category: 'Assemblies',
|
|
1315
|
+
description: 'Replay assemblies',
|
|
1316
|
+
details: `
|
|
1317
|
+
Replay one or more assemblies. By default, replays use the original assembly instructions.
|
|
1318
|
+
Use --steps to override the instructions, or --reparse-template to use the latest template version.
|
|
1319
|
+
`,
|
|
1320
|
+
examples: [
|
|
1321
|
+
['Replay an assembly with original steps', 'transloadit assemblies replay ASSEMBLY_ID'],
|
|
1322
|
+
[
|
|
1323
|
+
'Replay with different steps',
|
|
1324
|
+
'transloadit assemblies replay --steps new-steps.json ASSEMBLY_ID',
|
|
1325
|
+
],
|
|
1326
|
+
[
|
|
1327
|
+
'Replay with updated template',
|
|
1328
|
+
'transloadit assemblies replay --reparse-template ASSEMBLY_ID',
|
|
1329
|
+
],
|
|
1330
|
+
],
|
|
1331
|
+
})
|
|
1332
|
+
|
|
1333
|
+
fields = Option.Array('--field,-f', {
|
|
1334
|
+
description: 'Set a template field (KEY=VAL)',
|
|
1335
|
+
})
|
|
1336
|
+
|
|
1337
|
+
steps = Option.String('--steps,-s', {
|
|
1338
|
+
description: 'Optional JSON file to override assembly instructions',
|
|
1339
|
+
})
|
|
1340
|
+
|
|
1341
|
+
notifyUrl = Option.String('--notify-url', {
|
|
1342
|
+
description: 'Specify a new URL for assembly notifications',
|
|
1343
|
+
})
|
|
1344
|
+
|
|
1345
|
+
reparseTemplate = Option.Boolean('--reparse-template', false, {
|
|
1346
|
+
description: 'Use the most up-to-date version of the template',
|
|
1347
|
+
})
|
|
1348
|
+
|
|
1349
|
+
assemblyIds = Option.Rest({ required: 1 })
|
|
1350
|
+
|
|
1351
|
+
protected async run(): Promise<number | undefined> {
|
|
1352
|
+
const fieldsMap: Record<string, string> = {}
|
|
1353
|
+
for (const field of this.fields ?? []) {
|
|
1354
|
+
const eqIndex = field.indexOf('=')
|
|
1355
|
+
if (eqIndex === -1) {
|
|
1356
|
+
this.output.error(`invalid argument for --field: '${field}'`)
|
|
1357
|
+
return 1
|
|
1358
|
+
}
|
|
1359
|
+
const key = field.slice(0, eqIndex)
|
|
1360
|
+
const value = field.slice(eqIndex + 1)
|
|
1361
|
+
fieldsMap[key] = value
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
await replay(this.output, this.client, {
|
|
1365
|
+
fields: fieldsMap,
|
|
1366
|
+
reparse: this.reparseTemplate,
|
|
1367
|
+
steps: this.steps,
|
|
1368
|
+
notify_url: this.notifyUrl,
|
|
1369
|
+
assemblies: this.assemblyIds,
|
|
1370
|
+
})
|
|
1371
|
+
return undefined
|
|
1372
|
+
}
|
|
1373
|
+
}
|