Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ jobs:
- run: corepack yarn
- run: corepack yarn lint:js

knip:
name: Knip
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: corepack yarn
- run: corepack yarn knip

typescript:
name: Lint (TypeScript)
runs-on: ubuntu-latest
Expand Down
42 changes: 42 additions & 0 deletions knip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { KnipConfig } from 'knip'

// Note: `yarn check` runs knip with --fix --allow-remove-files. This is safe because
// lint:ts and tests run immediately after - they'll fail if knip removes something needed.
const config: KnipConfig = {
entry: ['src/Transloadit.ts', 'src/cli.ts', 'test/**/*.{ts,tsx,js,jsx}', 'vitest.config.ts'],
project: ['{src,test}/**/*.{ts,tsx,js,jsx}'],
ignore: [
'dist/**',
'coverage/**',
'static-build/**',
'node_modules/**',
// alphalib is a shared utility library. Exclude it so knip does not remove
// files that may only be used in other repos.
'src/alphalib/**',
],
ignoreDependencies: [
// Used in src/alphalib/** which is excluded from knip
'@aws-sdk/client-s3',
'@aws-sdk/s3-request-presigner',
'@transloadit/sev-logger',
'type-fest',
'zod',
// Repo-specific ignores
'@types/minimist',
'minimatch',
'tsx',
],
ignoreExportsUsedInFile: {
type: true,
interface: true,
},
rules: {
exports: 'warn',
types: 'warn',
nsExports: 'warn',
nsTypes: 'warn',
duplicates: 'warn',
},
}

export default config
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,22 @@
"p-queue": "^9.0.1",
"recursive-readdir": "^2.2.3",
"tus-js-client": "^4.3.1",
"typanion": "^3.14.0",
Copy link
Collaborator

@mifi mifi Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ironically, this seems unused. and shouldn't that have been caught by knip?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typanion is a peer dependency of clipanion. node_modules/clipanion/package.json lists "typanion": "*" in peerDependencies and also lists it in its own dependencies. That’s why it should remain in node-sdk/package.json even without direct imports.
Knip doesn’t flag it because it treats peer‑required deps as needed (or because clipanion’s peer requirement effectively justifies it).

"type-fest": "^4.41.0",
"zod": "3.25.76"
},
"devDependencies": {
"@biomejs/biome": "^2.2.4",
"@types/debug": "^4.1.12",
"@types/minimist": "^1.2.5",
"@types/node": "^24.10.3",
"@types/recursive-readdir": "^2.2.4",
"@types/temp": "^0.9.4",
"@vitest/coverage-v8": "^3.2.4",
"badge-maker": "^5.0.2",
"execa": "9.6.0",
"image-size": "^2.0.2",
"knip": "^5.73.3",
"minimatch": "^10.1.1",
"nock": "^14.0.10",
"npm-run-all": "^4.1.5",
Expand All @@ -62,13 +66,16 @@
"src": "./src"
},
"scripts": {
"check": "yarn lint:ts && yarn fix && yarn test:unit",
"check": "yarn knip --fix --allow-remove-files --no-config-hints && yarn lint:ts && yarn fix && yarn test:unit",
"fix:js": "biome check --write .",
"lint:ts": "tsc --build",
"fix:js:unsafe": "biome check --write . --unsafe",
"lint:js": "biome check .",
"lint": "npm-run-all --parallel 'lint:js'",
"fix": "npm-run-all --serial 'fix:js'",
"lint:deps": "knip --dependencies --no-progress",
"fix:deps": "knip --dependencies --no-progress --fix",
"knip": "knip --no-config-hints --no-progress",
"prepack": "rm -f tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo && tsc --build tsconfig.build.json",
"test:unit": "vitest run --coverage ./test/unit",
"test:e2e": "vitest run ./test/e2e",
Expand Down
2 changes: 1 addition & 1 deletion src/cli/OutputCtl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Log levels following syslog severity (https://en.wikipedia.org/wiki/Syslog#Severity_level)
* Lower numbers = more severe, higher numbers = more verbose
*/
export const LOG_LEVEL = {
const LOG_LEVEL = {
ERR: 3, // Error conditions
WARN: 4, // Warning conditions
NOTICE: 5, // Normal but significant (default)
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/BaseCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getEnvCredentials } from '../helpers.ts'
import type { IOutputCtl } from '../OutputCtl.ts'
import OutputCtl, { LOG_LEVEL_DEFAULT, LOG_LEVEL_NAMES, parseLogLevel } from '../OutputCtl.ts'

export abstract class BaseCommand extends Command {
abstract class BaseCommand extends Command {
logLevelOption = Option.String('-l,--log-level', {
description: `Log level: ${LOG_LEVEL_NAMES.join(', ')} or 3-8 (default: notice)`,
})
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/assemblies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface AssemblyGetOptions {
assemblies: string[]
}

export interface AssemblyDeleteOptions {
interface AssemblyDeleteOptions {
assemblies: string[]
}

Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { AuthenticatedCommand } from './BaseCommand.ts'

// --- Types and business logic ---

export interface NotificationsReplayOptions {
interface NotificationsReplayOptions {
notify_url?: string
assemblies: string[]
}

export async function replay(
async function replay(
output: IOutputCtl,
client: Transloadit,
{ notify_url, assemblies }: NotificationsReplayOptions,
Expand Down
6 changes: 3 additions & 3 deletions src/cli/commands/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ export interface TemplateModifyOptions {
file: string
}

export interface TemplateDeleteOptions {
interface TemplateDeleteOptions {
templates: string[]
}

export interface TemplateListOptions {
interface TemplateListOptions {
before?: string
after?: string
order?: 'asc' | 'desc'
Expand Down Expand Up @@ -162,7 +162,7 @@ const TemplateIdSchema = z.object({
id: z.string(),
})

export function list(
function list(
output: IOutputCtl,
client: Transloadit,
{ before, after, order, sort, fields }: TemplateListOptions,
Expand Down
6 changes: 3 additions & 3 deletions src/cli/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import fs from 'node:fs'
import type { Readable } from 'node:stream'
import type { APIError } from './types.ts'
import { isAPIError } from './types.ts'

export function getEnvCredentials(): { authKey: string; authSecret: string } | null {
Expand Down Expand Up @@ -35,8 +34,9 @@ export function formatAPIError(err: unknown): string {
return String(err)
}

// Re-export APIError type for convenience
export type { APIError }
// Re-export APIError type for CLI consumers relying on deep imports.
/** @public */
export type { APIError } from './types.ts'

export function zip<A, B>(listA: A[], listB: B[]): [A, B][]
export function zip<T>(...lists: T[][]): T[][]
Expand Down
117 changes: 2 additions & 115 deletions src/cli/types.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { z } from 'zod'
import type { Steps } from '../alphalib/types/template.ts'
import { optionalStepsSchema } from '../alphalib/types/template.ts'
import type { BillResponse, ListedTemplate, TemplateResponse } from '../apiTypes.ts'
import type { AssemblyStatus, Transloadit } from '../Transloadit.ts'
import type { IOutputCtl } from './OutputCtl.ts'

// Re-export transloadit types for CLI use
export type { AssemblyStatus, BillResponse, ListedTemplate, TemplateResponse }
export type { Transloadit }
export type { CreateAssemblyOptions } from '../Transloadit.ts'

// Zod schemas for runtime validation
export const APIErrorSchema = z.object({
const APIErrorSchema = z.object({
error: z.string(),
message: z.string(),
})
export type APIError = z.infer<typeof APIErrorSchema>

export const TransloaditAPIErrorSchema = z.object({
const TransloaditAPIErrorSchema = z.object({
error: z.string().optional(),
message: z.string(),
code: z.string().optional(),
Expand Down Expand Up @@ -54,98 +46,6 @@ export interface TemplateFile {
data: TemplateFileData
}

// Template list item (from API)
export interface TemplateListItem {
id: string
modified: string
name?: string
}

// CLI Invocation types
export interface BaseInvocation {
error?: boolean
message?: string
mode: string
action?: string
logLevel?: number
jsonMode?: boolean
}

export interface AssemblyInvocation extends BaseInvocation {
mode: 'assemblies'
action?: 'create' | 'get' | 'list' | 'delete' | 'replay'
inputs: string[]
output?: string
recursive?: boolean
watch?: boolean
del?: boolean
reprocessStale?: boolean
steps?: string
template?: string
fields?: Record<string, string>
assemblies?: string[]
before?: string
after?: string
keywords?: string[]
notify_url?: string
reparse?: boolean
}

export interface TemplateInvocation extends BaseInvocation {
mode: 'templates'
action?: 'create' | 'get' | 'list' | 'delete' | 'modify' | 'sync'
templates?: string[]
template?: string
name?: string
file?: string
files?: string[]
before?: string
after?: string
order?: 'asc' | 'desc'
sort?: string
fields?: string[]
recursive?: boolean
}

export interface BillInvocation extends BaseInvocation {
mode: 'bills'
action?: 'get'
months: string[]
}

export interface NotificationInvocation extends BaseInvocation {
mode: 'assembly-notifications'
action?: 'list' | 'replay'
assemblies?: string[]
notify_url?: string
type?: string
assembly_id?: string
pagesize?: number
}

export interface HelpInvocation extends BaseInvocation {
mode: 'help' | 'version' | 'register'
}

export type Invocation =
| AssemblyInvocation
| TemplateInvocation
| BillInvocation
| NotificationInvocation
| HelpInvocation

// Command handler type
export type CommandHandler<T extends BaseInvocation = BaseInvocation> = (
output: IOutputCtl,
client: Transloadit | undefined,
invocation: T,
) => void | Promise<void>

// Type guard for Error
export function isError(value: unknown): value is Error {
return value instanceof Error
}

// Helper to ensure error is Error type
export function ensureError(value: unknown): Error {
if (value instanceof Error) {
Expand All @@ -168,16 +68,3 @@ export function isTransloaditAPIError(value: unknown): value is TransloaditAPIEr
export function isErrnoException(value: unknown): value is NodeJS.ErrnoException {
return value instanceof Error && 'code' in value
}

// Safe array access helper
export function safeGet<T>(arr: T[], index: number): T | undefined {
return arr[index]
}

// Assert defined helper
export function assertDefined<T>(value: T | undefined | null, message: string): T {
if (value === undefined || value === null) {
throw new Error(message)
}
return value
}
Loading