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
6 changes: 6 additions & 0 deletions .changeset/bright-vans-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@transloadit/notify-url-relay': minor
---

Add a new `@transloadit/notify-url-relay` package for running a local Transloadit
`notify_url` relay with fetch-based forwarding, assembly polling, retry logic, and a CLI/TUI.
12 changes: 8 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ jobs:
github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
env:
NODE_OPTIONS: --trace-deprecation --trace-warnings
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -181,18 +183,20 @@ jobs:

- run: corepack yarn test
env:
TRANSLOADIT_KEY: ${{ secrets.TRANSLOADIT_KEY }}
TRANSLOADIT_SECRET: ${{ secrets.TRANSLOADIT_SECRET }}
NODE_OPTIONS: --trace-deprecation --trace-warnings
CLOUDFLARED_PATH: ${{ github.workspace }}/cloudflared-linux-amd64
DEBUG: 'transloadit:*'
TRANSLOADIT_KEY: ${{ secrets.TRANSLOADIT_KEY }}
TRANSLOADIT_SECRET: ${{ secrets.TRANSLOADIT_SECRET }}

- name: Run MCP server e2e tests
run: corepack yarn workspace @transloadit/mcp-server test:e2e

- name: Run notify-url-relay real e2e test
run: corepack yarn workspace @transloadit/notify-url-relay test:real
env:
TRANSLOADIT_KEY: ${{ secrets.TRANSLOADIT_KEY }}
TRANSLOADIT_SECRET: ${{ secrets.TRANSLOADIT_SECRET }}
NODE_OPTIONS: --trace-deprecation --trace-warnings
TRANSLOADIT_ENDPOINT: ${{ secrets.TRANSLOADIT_ENDPOINT }}

- name: Generate the badge from the json-summary
run: node --experimental-strip-types packages/node/test/generate-coverage-badge.ts packages/node/coverage/coverage-summary.json
Expand Down
20 changes: 10 additions & 10 deletions docs/fingerprint/transloadit-baseline.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"packageDir": "/home/kvz/code/node-sdk/packages/transloadit",
"tarball": {
"filename": "transloadit-4.7.4.tgz",
"sizeBytes": 1247606,
"sha256": "48a0c23cb4652d91594b7ff5a7e16af1397e8da663245f241de49f1057c4330e"
"filename": "transloadit-4.7.5.tgz",
"sizeBytes": 1247607,
"sha256": "8ece4cbf0df04422d189035abb22a80c0565f95e5b10488d0e9226277702e363"
},
"packageJson": {
"name": "transloadit",
"version": "4.7.4",
"version": "4.7.5",
"main": "./dist/Transloadit.js",
"exports": {
".": "./dist/Transloadit.js",
Expand Down Expand Up @@ -473,8 +473,8 @@
},
{
"path": "dist/robots.js",
"sizeBytes": 8373,
"sha256": "de7fd519fcf36cbae2d1a3a316dadf331a61e933bcb666a92358502fb3e90433"
"sizeBytes": 8374,
"sha256": "740d92236f9b0319b73f38c9827074747b80f36694906df916039bec8cd421d2"
},
{
"path": "dist/alphalib/types/robots/s3-import.js",
Expand Down Expand Up @@ -689,7 +689,7 @@
{
"path": "package.json",
"sizeBytes": 2730,
"sha256": "0cf46ccf180fd122bfa412623700b21b34b3cd962aad90102ca8ab14256de1c6"
"sha256": "313dd2ac13d3e4857b71bd889b2c9fa7f2458cf2bf5be2dd5a1996eb3d23199d"
},
{
"path": "dist/alphalib/types/robots/_index.d.ts.map",
Expand Down Expand Up @@ -1599,7 +1599,7 @@
{
"path": "dist/robots.js.map",
"sizeBytes": 9412,
"sha256": "79c6c465ced5d07c7d7a3b5124c4486584d43aa86468caafe886f3b291304b13"
"sha256": "72d51dbe2ba7017ec5700bd72f5247142fa2f4cc3cda60c822a92fef0becf841"
},
{
"path": "dist/alphalib/types/robots/s3-import.d.ts.map",
Expand Down Expand Up @@ -2938,8 +2938,8 @@
},
{
"path": "src/robots.ts",
"sizeBytes": 9642,
"sha256": "fa774b4f6f8b30eb18a94bf2a117bae924d0b80f05e9bb16d7e85a8298e19543"
"sizeBytes": 9643,
"sha256": "7afa1b895f1b28c6eb63b496450e3236e5e20fc649484ba878fd0f6179899499"
},
{
"path": "dist/alphalib/types/robots/s3-import.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion docs/fingerprint/transloadit-baseline.package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "transloadit",
"version": "4.7.4",
"version": "4.7.5",
"description": "Node.js SDK for Transloadit",
"homepage": "https://github.com/transloadit/node-sdk/tree/main/packages/node",
"bugs": {
Expand Down
17 changes: 17 additions & 0 deletions docs/prompts/2026-03-04-notify-url-relay-refactors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Notify URL Relay Refactor Follow-ups (2026-03-04)

Tracking refactors requested after council ideas. Items are completed in order and checked off as they land.

- [x] 1. Consolidate repeated integration test harness helpers into shared test utilities.
- [x] 2. Unify CLI option definition/validation/help generation with one declarative schema.
- [x] 3. Replace cross-package source import in real E2E with workspace package import, fixing Vitest resolution the right way.
- [x] 4. Remove redundant null guard in `observeTiming`.
- [x] 5. Simplify timeout signal plumbing using Node native Abort APIs while preserving timeout error semantics.
- [x] 6. Deduplicate repeated E2E workflow environment variables at job-level.

## Council Refactor Run #2 (2026-03-04)

- [x] 1. Stabilize and DRY test harness setup; remove `getFreePort()` TOCTOU race by binding proxy to port `0`.
- [x] 2. Deduplicate `observeTiming` emission path to a single payload construction.
- [x] 3. Use named export for the relay class (align with repo style guidance).
- [x] 4. Replace avoidable `as` casts with stronger typing/narrowing where practical.
6 changes: 6 additions & 0 deletions knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ const config: KnipConfig = {
ignore: [...sharedIgnore],
ignoreDependencies: ['@types/express', '@types/node', 'vitest', 'vitest/config'],
},
'packages/notify-url-relay': {
entry: ['src/**/*.ts', 'test/**/*.ts', 'vitest.config.ts'],
project: ['{src,test}/**/*.ts'],
ignore: [...sharedIgnore],
ignoreDependencies: ['@types/node', 'vitest', 'vitest/config'],
},
'packages/transloadit': {
entry: [
'src/Transloadit.ts',
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"verify": "yarn lint:changesets && yarn lint:publish && yarn lint:deps && yarn lint:js && yarn lint:ts && yarn test:unit",
"verify:full": "yarn verify && yarn knip && yarn parity:transloadit && yarn test:types",
"lint:js": "biome check .",
"lint:ts": "yarn tsc:types && yarn tsc:node && yarn tsc:zod",
"lint:ts": "yarn tsc:types && yarn tsc:node && yarn tsc:zod && yarn workspace @transloadit/notify-url-relay lint:ts",
"lint:changesets": "node scripts/guard-changesets.ts",
"lint": "yarn lint:js",
"fix": "yarn fix:js",
Expand All @@ -23,7 +23,7 @@
"knip": "yarn run --binaries-only knip --exclude binaries --no-config-hints --no-progress",
"pack": "node scripts/pack-transloadit.ts",
"parity:transloadit": "node scripts/prepare-transloadit.ts && node scripts/fingerprint-pack.ts packages/transloadit --ignore-scripts --quiet --out /tmp/transloadit-after.json && node scripts/verify-fingerprint.ts --current /tmp/transloadit-after.json --diff",
"test:unit": "yarn workspace @transloadit/node test:unit && yarn workspace @transloadit/mcp-server test:unit && yarn workspace @transloadit/types test:unit && yarn workspace @transloadit/zod test:unit",
"test:unit": "yarn workspace @transloadit/node test:unit && yarn workspace @transloadit/mcp-server test:unit && yarn workspace @transloadit/types test:unit && yarn workspace @transloadit/zod test:unit && yarn workspace @transloadit/notify-url-relay test:unit",
"test:types": "yarn workspace @transloadit/zod test:types",
"test:e2e": "yarn workspace @transloadit/node test:e2e",
"test": "yarn workspace @transloadit/node test",
Expand Down
6 changes: 6 additions & 0 deletions packages/notify-url-relay/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TRANSLOADIT_KEY=your-key
TRANSLOADIT_SECRET=your-secret
# Optional (defaults to https://api2.transloadit.com)
TRANSLOADIT_ENDPOINT=https://api2.transloadit.com
# Optional (0-8 or emerg/alert/crit/err/warn/notice/info/debug/trace)
TRANSLOADIT_LOG_LEVEL=info
7 changes: 7 additions & 0 deletions packages/notify-url-relay/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @transloadit/notify-url-relay

## 0.1.0

### Minor Changes

- Initial release of the notify_url proxy package.
122 changes: 122 additions & 0 deletions packages/notify-url-relay/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# @transloadit/notify-url-relay

Local `notify_url` relay for Transloadit Assemblies. This tool polls the status of Assemblies until they complete, then pushes the status to a pingback URL of your choosing. This is useful while on a development machine, which is inaccessible from the public internet and hence can't be notified by Transloadit.

You can alternatively use a tunnel like ngrok or [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/) for this, this is just one more way.

This version is modernized for:

- Node.js 24+
- Native TypeScript execution (type stripping)
- ESM
- Yarn 4
- Biome + Vitest + GitHub Actions + Changesets

Notify payloads are signed via `@transloadit/utils` using prefixed `sha384` signatures.
Forwarding uses native `fetch`, polling retries use `p-retry`, and logs are emitted via `@transloadit/sev-logger`.
Metrics hooks are available for counters, gauges, and timings.

## Install

```bash
npm install @transloadit/notify-url-relay
```

## CLI usage

```bash
export TRANSLOADIT_SECRET="your-secret"

notify-url-relay \
--notifyUrl "http://127.0.0.1:3000/transloadit" \
--port 8888 \
--notifyOnTerminalError \
--log-level info
```

Run `notify-url-relay --help` for all options.

Log level accepts `0-8` or names:
`emerg`, `alert`, `crit`, `err`, `warn`, `notice`, `info`, `debug`, `trace`.
You can also set `TRANSLOADIT_LOG_LEVEL`.

### Reactive TUI Mode

```bash
notify-url-relay --ui --log-level info
```

This opens a live terminal dashboard with:

- throughput and retry counters
- in-flight queue gauges
- latency sparklines
- streaming logs

## Programmatic usage

```ts
import { TransloaditNotifyUrlProxy } from '@transloadit/notify-url-relay'

const proxy = new TransloaditNotifyUrlProxy(
process.env.TRANSLOADIT_SECRET ?? '',
'http://127.0.0.1:3000/transloadit'
)

proxy.run({
port: 8888,
target: 'https://api2.transloadit.com',
forwardTimeoutMs: 15000,
pollIntervalMs: 2000,
pollMaxIntervalMs: 30000,
pollBackoffFactor: 2,
pollRequestTimeoutMs: 15000,
maxPollAttempts: 10,
maxInFlightPolls: 4,
notifyOnTerminalError: false,
notifyTimeoutMs: 15000,
notifyMaxAttempts: 3,
notifyIntervalMs: 500,
notifyMaxIntervalMs: 5000,
notifyBackoffFactor: 2
})
```

## Development

```bash
corepack yarn
corepack yarn workspace @transloadit/notify-url-relay check
corepack yarn workspace @transloadit/notify-url-relay test:real
```

## Real API E2E

Run an opt-in test against the real Transloadit API (default `yarn test` excludes this test):

```bash
# set locally (for example in .env)
export TRANSLOADIT_KEY="your-key"
export TRANSLOADIT_SECRET="your-secret"
# optional
export TRANSLOADIT_ENDPOINT="https://api2.transloadit.com"

corepack yarn workspace @transloadit/notify-url-relay test:real
```

For CI, configure repository secrets:

- `TRANSLOADIT_KEY`
- `TRANSLOADIT_SECRET`
- `TRANSLOADIT_ENDPOINT` (optional)

## Releases

Changesets drives releases for this package:

```bash
corepack yarn changeset
corepack yarn changeset:version
```

On pushes to `main`, `.github/workflows/release.yml` runs `changesets/action` to publish.
52 changes: 52 additions & 0 deletions packages/notify-url-relay/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@transloadit/notify-url-relay",
"version": "0.1.0",
"description": "Local notify_url relay for Transloadit assemblies.",
"type": "module",
"license": "MIT",
"packageManager": "yarn@4.12.0",
"engines": {
"node": ">= 24"
},
"repository": {
"type": "git",
"url": "https://github.com/transloadit/node-sdk",
"directory": "packages/notify-url-relay"
},
"files": [
"dist",
"README.md"
],
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"bin": "./dist/cli.js",
"scripts": {
"lint:ts": "../../node_modules/.bin/tsc --build tsconfig.build.json",
"build": "yarn lint:ts && chmod +x dist/cli.js",
"test:unit": "yarn --cwd ../.. tsc:zod && ../../node_modules/.bin/vitest run",
"test:real": "yarn --cwd ../.. tsc:zod && RUN_REAL_E2E=1 ../../node_modules/.bin/vitest run test/real.e2e.test.ts",
"check": "yarn lint:ts && yarn test:unit",
"prepack": "yarn build"
},
"dependencies": {
"@transloadit/sev-logger": "^0.1.9",
"@transloadit/utils": "^4.3.0",
"@transloadit/zod": "^4.3.0",
"dotenv": "^17.2.3",
"p-retry": "^7.1.1"
},
"devDependencies": {
"@types/node": "^24.10.3",
"transloadit": "^4.7.4"
},
"publishConfig": {
"tag": "experimental"
}
}
Loading