transloadit 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.dockerignore +9 -0
- data/.gitattributes +2 -0
- data/.github/workflows/ci.yml +37 -1
- data/.gitignore +2 -0
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +95 -0
- data/Dockerfile +19 -0
- data/Gemfile +5 -0
- data/README.md +4 -21
- data/chameleon.jpg +0 -0
- data/lib/transloadit/response.rb +1 -0
- data/lib/transloadit/version.rb +1 -1
- data/lib/transloadit.rb +1 -1
- data/scripts/notify-registry.sh +57 -0
- data/scripts/test-in-docker.sh +89 -0
- data/test/integration/test_e2e_upload.rb +97 -0
- data/test/test_helper.rb +54 -1
- data/test/unit/test_transloadit.rb +4 -1
- data/test/unit/transloadit/test_request.rb +85 -0
- data/test/unit/transloadit/test_smart_cdn.rb +10 -21
- data/transloadit.gemspec +2 -2
- metadata +12 -3
- data/test/unit/transloadit/node-smartcdn-sig.ts +0 -89
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c48cbed2048f296ca130e4cbb69790fea92b7a02fab75f4aa9c0e6811b89063e
|
|
4
|
+
data.tar.gz: 2b9752757ce8a2575cb6b3c446a19aec436c4003e715869e835e8906fb768b85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d05074cb025387b2f805c14797ff93b9abd5b28f77b51bc7a6a69811d66deb2dad2260a0ad6f0ad7ea5ff4313e076d1867332528a5b136f6694267d56987eee
|
|
7
|
+
data.tar.gz: e078c99468b14f03ddc1f1c48a7abab1f92492194d8fc17bb6208a696f0a0cfb9a638a4002f7a4905ef9cd714e6ba0159f4f7f6e275693527478d5ea1ff3eae6
|
data/.dockerignore
ADDED
data/.gitattributes
ADDED
data/.github/workflows/ci.yml
CHANGED
|
@@ -31,4 +31,40 @@ jobs:
|
|
|
31
31
|
ruby-version: ${{ matrix.ruby }}
|
|
32
32
|
bundler-cache: true
|
|
33
33
|
- run: bundle exec standardrb
|
|
34
|
-
-
|
|
34
|
+
- name: Run tests
|
|
35
|
+
env:
|
|
36
|
+
COVERAGE: ${{ matrix.ruby == '3.3' && '1' || '0' }}
|
|
37
|
+
TEST_NODE_PARITY: ${{ matrix.ruby == '3.3' && '1' || '0' }}
|
|
38
|
+
run: bundle exec rake test
|
|
39
|
+
- name: Upload coverage to Codecov
|
|
40
|
+
if: matrix.ruby == '3.3'
|
|
41
|
+
uses: codecov/codecov-action@v5
|
|
42
|
+
with:
|
|
43
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
44
|
+
files: ./coverage/coverage.json
|
|
45
|
+
fail_ci_if_error: true
|
|
46
|
+
e2e:
|
|
47
|
+
needs: ci
|
|
48
|
+
if: >
|
|
49
|
+
github.event_name != 'pull_request' ||
|
|
50
|
+
github.event.pull_request.head.repo.full_name == github.repository
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
env:
|
|
53
|
+
TRANSLOADIT_KEY: ${{ secrets.TRANSLOADIT_KEY }}
|
|
54
|
+
TRANSLOADIT_SECRET: ${{ secrets.TRANSLOADIT_SECRET }}
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v3
|
|
57
|
+
- uses: ruby/setup-ruby@v1
|
|
58
|
+
with:
|
|
59
|
+
ruby-version: 3.3
|
|
60
|
+
bundler-cache: true
|
|
61
|
+
- name: Ensure e2e credentials are configured
|
|
62
|
+
if: ${{ env.TRANSLOADIT_KEY == '' || env.TRANSLOADIT_SECRET == '' }}
|
|
63
|
+
run: |
|
|
64
|
+
echo "TRANSLOADIT_KEY and TRANSLOADIT_SECRET must be configured in repository secrets to run the e2e job." >&2
|
|
65
|
+
exit 1
|
|
66
|
+
- name: Run end-to-end upload test
|
|
67
|
+
env:
|
|
68
|
+
RUBY_SDK_E2E: 1
|
|
69
|
+
if: ${{ env.TRANSLOADIT_KEY != '' && env.TRANSLOADIT_SECRET != '' }}
|
|
70
|
+
run: bundle exec ruby -Itest test/integration/test_e2e_upload.rb
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
### 3.1.1 / 2025-10-28
|
|
2
|
+
|
|
3
|
+
- Add optional live end-to-end upload harness and CI job for parity verification, defaulted in Docker tests (kvz)
|
|
4
|
+
- Restore missing `require "uri"` to prevent `NameError` when loading `Transloadit::Request` (kvz)
|
|
5
|
+
|
|
1
6
|
### 3.1.0 / 2024-11-24
|
|
2
7
|
|
|
3
8
|
- Add Smart CDN signature support via `signed_smart_cdn_url` method (kvz)
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve the Transloadit Ruby SDK! This guide covers local development, testing, and publishing new releases.
|
|
4
|
+
|
|
5
|
+
## Local Development
|
|
6
|
+
|
|
7
|
+
After cloning the repository, install dependencies and run the test suite:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bundle install
|
|
11
|
+
bundle exec rake test
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
To exercise the signature parity suite against the Node.js CLI, make sure `npx transloadit` is available and run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
TEST_NODE_PARITY=1 bundle exec rake test
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
You can warm the CLI cache ahead of time:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
TRANSLOADIT_KEY=... TRANSLOADIT_SECRET=... \
|
|
24
|
+
npx --yes transloadit smart_sig --help
|
|
25
|
+
TRANSLOADIT_KEY=... TRANSLOADIT_SECRET=... \
|
|
26
|
+
npx --yes transloadit sig --algorithm sha384 --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Set `COVERAGE=0` to skip coverage instrumentation if desired:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
COVERAGE=0 bundle exec rake test
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Docker Workflow
|
|
36
|
+
|
|
37
|
+
The repository ships with a helper that runs tests inside a reproducible Docker image:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
./scripts/test-in-docker.sh
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Pass a custom command to run alternatives (Bundler still installs first):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
./scripts/test-in-docker.sh bundle exec ruby -Itest test/unit/transloadit/test_request.rb
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The script forwards environment variables such as `TEST_NODE_PARITY` and credentials from `.env`, so you can combine parity checks and integration tests. End-to-end uploads are enabled by default; unset them by running:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
RUBY_SDK_E2E=0 ./scripts/test-in-docker.sh
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Live End-to-End Test
|
|
56
|
+
|
|
57
|
+
To exercise the optional live upload:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
RUBY_SDK_E2E=1 TRANSLOADIT_KEY=... TRANSLOADIT_SECRET=... \
|
|
61
|
+
./scripts/test-in-docker.sh bundle exec ruby -Itest test/integration/test_e2e_upload.rb
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The test uploads `chameleon.jpg`, resizes it, and asserts on a real assembly response.
|
|
65
|
+
|
|
66
|
+
## Releasing to RubyGems
|
|
67
|
+
|
|
68
|
+
1. Update the version and changelog:
|
|
69
|
+
- Bump `lib/transloadit/version.rb`.
|
|
70
|
+
- Add a corresponding entry to `CHANGELOG.md`.
|
|
71
|
+
2. Run the full test suite (including Docker, parity, and e2e checks as needed).
|
|
72
|
+
3. Commit the release changes and tag:
|
|
73
|
+
```bash
|
|
74
|
+
git commit -am "Release X.Y.Z"
|
|
75
|
+
git tag -a vX.Y.Z -m "Release X.Y.Z"
|
|
76
|
+
```
|
|
77
|
+
4. Push the commit and tag:
|
|
78
|
+
```bash
|
|
79
|
+
git push origin main
|
|
80
|
+
git push origin vX.Y.Z
|
|
81
|
+
```
|
|
82
|
+
5. Publish the gem using the helper script:
|
|
83
|
+
```bash
|
|
84
|
+
GEM_HOST_API_KEY=... ./scripts/notify-registry.sh
|
|
85
|
+
```
|
|
86
|
+
6. Draft a GitHub release from the new tag and publish the generated notes.
|
|
87
|
+
|
|
88
|
+
### RubyGems Credentials
|
|
89
|
+
|
|
90
|
+
- You must belong to the `transloadit` organization on RubyGems with permission to push the `transloadit` gem.
|
|
91
|
+
- Generate an API key with **Push Rubygems** permissions at <https://rubygems.org/profile/edit>. Copy the token and keep it secure.
|
|
92
|
+
- Export the token as `GEM_HOST_API_KEY` in your environment before running `./scripts/notify-registry.sh`. The script refuses to run if the variable is missing.
|
|
93
|
+
|
|
94
|
+
That’s it! Thank you for contributing.
|
|
95
|
+
|
data/Dockerfile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
|
|
3
|
+
FROM ruby:3.3 AS base
|
|
4
|
+
|
|
5
|
+
RUN apt-get update \
|
|
6
|
+
&& apt-get install -y --no-install-recommends \
|
|
7
|
+
build-essential \
|
|
8
|
+
git \
|
|
9
|
+
curl \
|
|
10
|
+
ca-certificates \
|
|
11
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
12
|
+
|
|
13
|
+
# Install Node.js for parity checks
|
|
14
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
|
15
|
+
&& apt-get install -y --no-install-recommends nodejs \
|
|
16
|
+
&& npm install -g npm@latest \
|
|
17
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
18
|
+
|
|
19
|
+
WORKDIR /workspace
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[](https://github.com/transloadit/ruby-sdk/actions/workflows/ci.yml)
|
|
2
|
-
[](https://codecov.io/gh/transloadit/ruby-sdk)
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# Transloadit Ruby SDK
|
|
5
5
|
|
|
6
6
|
A **Ruby** Integration for [Transloadit](https://transloadit.com)'s file uploading and encoding service
|
|
7
7
|
|
|
@@ -447,7 +447,7 @@ transloadit.assembly(:tries => 0).create! open('/PATH/TO/FILE.mpg')
|
|
|
447
447
|
|
|
448
448
|
## Example
|
|
449
449
|
|
|
450
|
-
A small sample
|
|
450
|
+
A small sample tutorials of using the Transloadit Ruby SDK to optimize an image, encode MP3 audio, add ID3 tags,
|
|
451
451
|
and more can be found [here](https://github.com/transloadit/ruby-sdk/tree/main/examples).
|
|
452
452
|
|
|
453
453
|
## Documentation
|
|
@@ -467,21 +467,4 @@ If you still need support for Ruby 2.x, 2.0.1 is the last version that supports
|
|
|
467
467
|
|
|
468
468
|
## Contributing
|
|
469
469
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
```bash
|
|
473
|
-
bundle install
|
|
474
|
-
bundle exec rake test
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
To also test parity against the Node.js reference implementation, run:
|
|
478
|
-
|
|
479
|
-
```bash
|
|
480
|
-
TEST_NODE_PARITY=1 bundle exec rake test
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
To disable coverage reporting, run:
|
|
484
|
-
|
|
485
|
-
```bash
|
|
486
|
-
COVERAGE=0 bundle exec rake test
|
|
487
|
-
```
|
|
470
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for local development, testing, and release instructions.
|
data/chameleon.jpg
ADDED
|
Binary file
|
data/lib/transloadit/response.rb
CHANGED
data/lib/transloadit/version.rb
CHANGED
data/lib/transloadit.rb
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
IMAGE_NAME=${IMAGE_NAME:-transloadit-ruby-sdk-dev}
|
|
5
|
+
|
|
6
|
+
err() {
|
|
7
|
+
echo "notify-registry: $*" >&2
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if ! command -v docker >/dev/null 2>&1; then
|
|
11
|
+
err "Docker is required to publish the gem."
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
if [[ -z "${GEM_HOST_API_KEY:-}" ]]; then
|
|
16
|
+
err "GEM_HOST_API_KEY environment variable is not set. Generate a RubyGems API key with push permissions and export it before running this script."
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
|
|
21
|
+
err "Docker image '$IMAGE_NAME' not found. Building it now..."
|
|
22
|
+
docker build -t "$IMAGE_NAME" -f Dockerfile .
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
version=$(
|
|
26
|
+
docker run --rm \
|
|
27
|
+
-v "$PWD":/workspace \
|
|
28
|
+
-w /workspace \
|
|
29
|
+
"$IMAGE_NAME" \
|
|
30
|
+
ruby -Ilib -e 'require "transloadit/version"; puts Transloadit::VERSION'
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
gem_file="transloadit-${version}.gem"
|
|
34
|
+
|
|
35
|
+
err "Building ${gem_file}..."
|
|
36
|
+
docker run --rm \
|
|
37
|
+
--user "$(id -u):$(id -g)" \
|
|
38
|
+
-e HOME=/workspace \
|
|
39
|
+
-v "$PWD":/workspace \
|
|
40
|
+
-w /workspace \
|
|
41
|
+
"$IMAGE_NAME" \
|
|
42
|
+
bash -lc "set -euo pipefail; rm -f ${gem_file}; gem build transloadit.gemspec >/dev/null"
|
|
43
|
+
|
|
44
|
+
err "Pushing ${gem_file} to RubyGems..."
|
|
45
|
+
docker run --rm \
|
|
46
|
+
--user "$(id -u):$(id -g)" \
|
|
47
|
+
-e HOME=/workspace \
|
|
48
|
+
-e GEM_HOST_API_KEY="$GEM_HOST_API_KEY" \
|
|
49
|
+
-v "$PWD":/workspace \
|
|
50
|
+
-w /workspace \
|
|
51
|
+
"$IMAGE_NAME" \
|
|
52
|
+
bash -lc "set -euo pipefail; gem push ${gem_file}"
|
|
53
|
+
|
|
54
|
+
err "Removing local ${gem_file}..."
|
|
55
|
+
rm -f "${gem_file}"
|
|
56
|
+
|
|
57
|
+
echo "notify-registry: Successfully pushed ${gem_file} to RubyGems."
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
IMAGE_NAME=${IMAGE_NAME:-transloadit-ruby-sdk-dev}
|
|
5
|
+
CACHE_DIR=.docker-cache
|
|
6
|
+
|
|
7
|
+
ensure_docker() {
|
|
8
|
+
if ! command -v docker >/dev/null 2>&1; then
|
|
9
|
+
echo "Docker is required to run this script." >&2
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if ! docker info >/dev/null 2>&1; then
|
|
14
|
+
if [[ -z "${DOCKER_HOST:-}" && -S "$HOME/.colima/default/docker.sock" ]]; then
|
|
15
|
+
export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"
|
|
16
|
+
fi
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
if ! docker info >/dev/null 2>&1; then
|
|
20
|
+
echo "Docker daemon is not reachable. Start Docker (or Colima) and retry." >&2
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
configure_platform() {
|
|
26
|
+
if [[ -z "${DOCKER_PLATFORM:-}" ]]; then
|
|
27
|
+
local arch
|
|
28
|
+
arch=$(uname -m)
|
|
29
|
+
if [[ "$arch" == "arm64" || "$arch" == "aarch64" ]]; then
|
|
30
|
+
DOCKER_PLATFORM=linux/amd64
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
ensure_docker
|
|
36
|
+
configure_platform
|
|
37
|
+
|
|
38
|
+
if [[ $# -eq 0 ]]; then
|
|
39
|
+
RUN_CMD='set -e; bundle install --jobs 4 --retry 3; bundle exec rake test'
|
|
40
|
+
else
|
|
41
|
+
printf -v USER_CMD '%q ' "$@"
|
|
42
|
+
RUN_CMD="set -e; bundle install --jobs 4 --retry 3; ${USER_CMD}"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
mkdir -p "$CACHE_DIR/bundle" "$CACHE_DIR/npm-cache"
|
|
46
|
+
|
|
47
|
+
BUILD_ARGS=()
|
|
48
|
+
if [[ -n "${DOCKER_PLATFORM:-}" ]]; then
|
|
49
|
+
BUILD_ARGS+=(--platform "$DOCKER_PLATFORM")
|
|
50
|
+
fi
|
|
51
|
+
BUILD_ARGS+=(-t "$IMAGE_NAME" -f Dockerfile .)
|
|
52
|
+
|
|
53
|
+
docker build "${BUILD_ARGS[@]}"
|
|
54
|
+
|
|
55
|
+
DOCKER_ARGS=(
|
|
56
|
+
--rm
|
|
57
|
+
--user "$(id -u):$(id -g)"
|
|
58
|
+
-e HOME=/workspace
|
|
59
|
+
-e BUNDLE_PATH=/workspace/$CACHE_DIR/bundle
|
|
60
|
+
-e BUNDLE_APP_CONFIG=/workspace/$CACHE_DIR/bundle-config
|
|
61
|
+
-e BUNDLE_CACHE_PATH=/workspace/$CACHE_DIR/bundle-cache
|
|
62
|
+
-e npm_config_cache=/workspace/$CACHE_DIR/npm-cache
|
|
63
|
+
-e TEST_NODE_PARITY="${TEST_NODE_PARITY:-0}"
|
|
64
|
+
-e RUBY_SDK_E2E="${RUBY_SDK_E2E:-1}"
|
|
65
|
+
-v "$PWD":/workspace
|
|
66
|
+
-w /workspace
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if [[ -n "${DOCKER_PLATFORM:-}" ]]; then
|
|
70
|
+
DOCKER_ARGS+=(--platform "$DOCKER_PLATFORM")
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [[ -f .env ]]; then
|
|
74
|
+
DOCKER_ARGS+=(--env-file "$PWD/.env")
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
PASSTHROUGH_ENV_VARS=(
|
|
78
|
+
TRANSLOADIT_KEY
|
|
79
|
+
TRANSLOADIT_SECRET
|
|
80
|
+
TRANSLOADIT_TEMPLATE_ID
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
for var in "${PASSTHROUGH_ENV_VARS[@]}"; do
|
|
84
|
+
if [[ -n "${!var:-}" ]]; then
|
|
85
|
+
DOCKER_ARGS+=(-e "$var=${!var}")
|
|
86
|
+
fi
|
|
87
|
+
done
|
|
88
|
+
|
|
89
|
+
exec docker run "${DOCKER_ARGS[@]}" "$IMAGE_NAME" bash -lc "$RUN_CMD"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "webmock"
|
|
3
|
+
|
|
4
|
+
describe "Transloadit end-to-end upload" do
|
|
5
|
+
before do
|
|
6
|
+
skip "Set RUBY_SDK_E2E=1 to run live upload tests" unless e2e_enabled?
|
|
7
|
+
|
|
8
|
+
@key = ENV["TRANSLOADIT_KEY"]
|
|
9
|
+
@secret = ENV["TRANSLOADIT_SECRET"]
|
|
10
|
+
skip "TRANSLOADIT_KEY and TRANSLOADIT_SECRET must be set to run live upload tests" if blank?(@key) || blank?(@secret)
|
|
11
|
+
|
|
12
|
+
@fixture_path = File.expand_path("../../chameleon.jpg", __dir__)
|
|
13
|
+
skip "chameleon.jpg fixture missing; run tests from the repository root" unless File.file?(@fixture_path)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "uploads and processes the chameleon image" do
|
|
17
|
+
with_live_http do
|
|
18
|
+
transloadit = Transloadit.new(key: @key, secret: @secret)
|
|
19
|
+
|
|
20
|
+
resize_step = transloadit.step(
|
|
21
|
+
"resize",
|
|
22
|
+
"/image/resize",
|
|
23
|
+
use: ":original",
|
|
24
|
+
width: 128,
|
|
25
|
+
height: 128,
|
|
26
|
+
resize_strategy: "fit",
|
|
27
|
+
format: "png"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
response = File.open(@fixture_path, "rb") do |upload|
|
|
31
|
+
transloadit.assembly.create!(
|
|
32
|
+
upload,
|
|
33
|
+
wait: true,
|
|
34
|
+
steps: resize_step
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
response.reload_until_finished!(tries: 120) unless response.finished?
|
|
39
|
+
|
|
40
|
+
_(response.completed?).must_equal true, "Assembly did not complete successfully: #{response.body.inspect}"
|
|
41
|
+
|
|
42
|
+
uploads = response["uploads"] || []
|
|
43
|
+
refute_empty uploads, "Expected uploads in the assembly response"
|
|
44
|
+
|
|
45
|
+
upload_info = uploads.first
|
|
46
|
+
basename = upload_info["basename"]
|
|
47
|
+
_(basename).must_equal File.basename(@fixture_path, ".*") if basename
|
|
48
|
+
|
|
49
|
+
filename = upload_info["name"]
|
|
50
|
+
_(filename).must_equal File.basename(@fixture_path) if filename
|
|
51
|
+
|
|
52
|
+
results = (response["results"] || {})["resize"] || []
|
|
53
|
+
refute_empty results, "Expected resize results in assembly response"
|
|
54
|
+
|
|
55
|
+
first_result = results.first
|
|
56
|
+
ssl_url = first_result["ssl_url"]
|
|
57
|
+
refute_nil ssl_url, "Missing ssl_url in resize result: #{first_result.inspect}"
|
|
58
|
+
_(ssl_url).must_match(/\Ahttps:\/\//)
|
|
59
|
+
|
|
60
|
+
meta = first_result["meta"] || {}
|
|
61
|
+
width = integer_if_present(meta["width"])
|
|
62
|
+
height = integer_if_present(meta["height"])
|
|
63
|
+
refute_nil width, "Missing width metadata: #{meta.inspect}"
|
|
64
|
+
refute_nil height, "Missing height metadata: #{meta.inspect}"
|
|
65
|
+
assert width.positive? && width <= 128, "Unexpected width #{width.inspect}"
|
|
66
|
+
assert height.positive? && height <= 128, "Unexpected height #{height.inspect}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def with_live_http
|
|
73
|
+
VCR.turn_off!(ignore_cassettes: true)
|
|
74
|
+
WebMock.allow_net_connect!
|
|
75
|
+
yield
|
|
76
|
+
ensure
|
|
77
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
|
78
|
+
VCR.turn_on!
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def e2e_enabled?
|
|
82
|
+
flag = ENV["RUBY_SDK_E2E"]
|
|
83
|
+
return false if blank?(flag)
|
|
84
|
+
|
|
85
|
+
%w[1 true yes on].include?(flag.to_s.strip.downcase)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def integer_if_present(value)
|
|
89
|
+
return nil if blank?(value)
|
|
90
|
+
|
|
91
|
+
value.to_i
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def blank?(value)
|
|
95
|
+
value.respond_to?(:empty?) ? value.empty? : !value
|
|
96
|
+
end
|
|
97
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -3,12 +3,20 @@ $:.unshift File.expand_path("../../lib", __FILE__)
|
|
|
3
3
|
|
|
4
4
|
if ENV["COVERAGE"] != "0"
|
|
5
5
|
require "simplecov"
|
|
6
|
-
SimpleCov.start
|
|
6
|
+
SimpleCov.start do
|
|
7
|
+
add_filter "/test/"
|
|
8
|
+
enable_coverage :branch
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
require "simplecov-cobertura"
|
|
12
|
+
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
|
7
13
|
end
|
|
8
14
|
|
|
9
15
|
require "minitest/autorun"
|
|
10
16
|
require "transloadit"
|
|
11
17
|
require "vcr"
|
|
18
|
+
require "open3"
|
|
19
|
+
require "json"
|
|
12
20
|
|
|
13
21
|
VCR.configure do |c|
|
|
14
22
|
c.cassette_library_dir = "test/fixtures/cassettes"
|
|
@@ -19,3 +27,48 @@ end
|
|
|
19
27
|
def values_from_post_body(body)
|
|
20
28
|
Addressable::URI.parse("?" + CGI.unescape(body)).query_values
|
|
21
29
|
end
|
|
30
|
+
|
|
31
|
+
module TransloaditCliHelpers
|
|
32
|
+
TRANSLOADIT_CLI_PACKAGE = ENV.fetch("TRANSLOADIT_CLI_PACKAGE", "transloadit@4.0.5")
|
|
33
|
+
|
|
34
|
+
def run_transloadit_cli(command, payload, key:, secret:, algorithm: nil)
|
|
35
|
+
return nil unless ENV["TEST_NODE_PARITY"] == "1"
|
|
36
|
+
|
|
37
|
+
env = {
|
|
38
|
+
"TRANSLOADIT_KEY" => key,
|
|
39
|
+
"TRANSLOADIT_SECRET" => secret,
|
|
40
|
+
"TRANSLOADIT_AUTH_KEY" => key,
|
|
41
|
+
"TRANSLOADIT_AUTH_SECRET" => secret
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
args = [
|
|
45
|
+
"npm", "exec", "--yes", "--package", TRANSLOADIT_CLI_PACKAGE, "--",
|
|
46
|
+
"transloadit", command
|
|
47
|
+
]
|
|
48
|
+
args += ["--algorithm", algorithm] if algorithm
|
|
49
|
+
|
|
50
|
+
stdout, stderr, status = Open3.capture3(env, *args, stdin_data: JSON.dump(payload))
|
|
51
|
+
raise "transloadit CLI #{command} failed: #{stderr}" unless status.success?
|
|
52
|
+
|
|
53
|
+
stdout.strip
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def run_transloadit_smart_sig(payload, key:, secret:)
|
|
57
|
+
cli_payload = {
|
|
58
|
+
workspace: payload.fetch(:workspace),
|
|
59
|
+
template: payload.fetch(:template),
|
|
60
|
+
input: payload.fetch(:input)
|
|
61
|
+
}
|
|
62
|
+
cli_payload[:url_params] = payload[:url_params] if payload.key?(:url_params)
|
|
63
|
+
cli_payload[:expire_at_ms] = payload[:expire_at_ms] if payload.key?(:expire_at_ms)
|
|
64
|
+
|
|
65
|
+
run_transloadit_cli("smart_sig", cli_payload, key: key, secret: secret)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def run_transloadit_sig(payload, key:, secret:, algorithm: nil)
|
|
69
|
+
output = run_transloadit_cli("sig", payload, key: key, secret: secret, algorithm: algorithm)
|
|
70
|
+
output && JSON.parse(output)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
Minitest::Test.include(TransloaditCliHelpers)
|
|
@@ -108,7 +108,10 @@ describe Transloadit do
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
it "must produce Transloadit-compatible JSON output" do
|
|
111
|
-
|
|
111
|
+
fixed_time = Time.utc(2025, 10, 28, 0, 0, 0)
|
|
112
|
+
Time.stub :now, fixed_time do
|
|
113
|
+
_(@transloadit.to_json).must_equal MultiJson.dump(@transloadit.to_hash)
|
|
114
|
+
end
|
|
112
115
|
end
|
|
113
116
|
end
|
|
114
117
|
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
|
+
require "multi_json"
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
require "tmpdir"
|
|
2
5
|
|
|
3
6
|
describe Transloadit::Request do
|
|
4
7
|
it "must allow initialization" do
|
|
@@ -75,4 +78,86 @@ describe Transloadit::Request do
|
|
|
75
78
|
end
|
|
76
79
|
end
|
|
77
80
|
end
|
|
81
|
+
|
|
82
|
+
it "loads request when URI was not previously required" do
|
|
83
|
+
lib_path = File.expand_path("../../../lib", __dir__)
|
|
84
|
+
|
|
85
|
+
Dir.mktmpdir do |stub_dir|
|
|
86
|
+
File.write(File.join(stub_dir, "rest-client.rb"), <<~RUBY)
|
|
87
|
+
module RestClient
|
|
88
|
+
class Response; end
|
|
89
|
+
|
|
90
|
+
class Resource
|
|
91
|
+
def initialize(*); end
|
|
92
|
+
def [](*); self; end
|
|
93
|
+
def get(*); Response.new; end
|
|
94
|
+
def post(*); Response.new; end
|
|
95
|
+
def put(*); Response.new; end
|
|
96
|
+
def delete(*); Response.new; end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
module Exceptions
|
|
100
|
+
class OpenTimeout < StandardError; end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
RUBY
|
|
104
|
+
|
|
105
|
+
File.write(File.join(stub_dir, "multi_json.rb"), <<~RUBY)
|
|
106
|
+
require "json"
|
|
107
|
+
|
|
108
|
+
module MultiJson
|
|
109
|
+
def self.dump(value)
|
|
110
|
+
JSON.dump(value)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.load(json)
|
|
114
|
+
JSON.parse(json)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
RUBY
|
|
118
|
+
|
|
119
|
+
script = <<~RUBY
|
|
120
|
+
$LOAD_PATH.unshift #{stub_dir.inspect}
|
|
121
|
+
$LOAD_PATH.unshift #{lib_path.inspect}
|
|
122
|
+
|
|
123
|
+
begin
|
|
124
|
+
require "transloadit/request"
|
|
125
|
+
Transloadit::Request.new("/")
|
|
126
|
+
rescue StandardError => e
|
|
127
|
+
warn e.full_message
|
|
128
|
+
exit 1
|
|
129
|
+
end
|
|
130
|
+
RUBY
|
|
131
|
+
|
|
132
|
+
stdout, stderr, status = Open3.capture3(RbConfig.ruby, "-e", script)
|
|
133
|
+
error_output = stderr.empty? ? stdout : stderr
|
|
134
|
+
assert status.success?, "Expected transloadit/request to load without NameError, got: #{error_output}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe "signature parity" do
|
|
140
|
+
it "matches transloadit CLI sig output" do
|
|
141
|
+
skip "Parity testing not enabled" unless ENV["TEST_NODE_PARITY"] == "1"
|
|
142
|
+
|
|
143
|
+
expires = "2025-01-02T00:00:00.000Z"
|
|
144
|
+
params = {
|
|
145
|
+
auth: {key: "cli-key", expires: expires},
|
|
146
|
+
steps: {encode: {robot: "/video/encode"}}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
cli_result = run_transloadit_sig(params, key: "cli-key", secret: "cli-secret", algorithm: "sha384")
|
|
150
|
+
refute_nil cli_result
|
|
151
|
+
|
|
152
|
+
cli_params_json = cli_result["params"]
|
|
153
|
+
request = Transloadit::Request.new("/", "cli-secret")
|
|
154
|
+
ruby_signature = request.send(:signature, cli_params_json)
|
|
155
|
+
|
|
156
|
+
assert_equal cli_result["signature"], ruby_signature
|
|
157
|
+
|
|
158
|
+
cli_params = JSON.parse(cli_params_json)
|
|
159
|
+
assert_equal "cli-key", cli_params.dig("auth", "key")
|
|
160
|
+
assert_equal expires, cli_params.dig("auth", "expires")
|
|
161
|
+
assert_equal "/video/encode", cli_params.dig("steps", "encode", "robot")
|
|
162
|
+
end
|
|
78
163
|
end
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
|
-
require "json"
|
|
3
|
-
require "open3"
|
|
4
2
|
|
|
5
3
|
describe Transloadit do
|
|
6
4
|
before do
|
|
@@ -13,15 +11,6 @@ describe Transloadit do
|
|
|
13
11
|
@expire_at = 1732550672867
|
|
14
12
|
end
|
|
15
13
|
|
|
16
|
-
def run_node_script(params)
|
|
17
|
-
return unless ENV["TEST_NODE_PARITY"] == "1"
|
|
18
|
-
script_path = File.expand_path("./node-smartcdn-sig", __dir__)
|
|
19
|
-
json_input = JSON.dump(params)
|
|
20
|
-
stdout, stderr, status = Open3.capture3("tsx #{script_path}", stdin_data: json_input)
|
|
21
|
-
raise "Node script failed: #{stderr}" unless status.success?
|
|
22
|
-
stdout.strip
|
|
23
|
-
end
|
|
24
|
-
|
|
25
14
|
describe "#signed_smart_cdn_url" do
|
|
26
15
|
it "requires workspace" do
|
|
27
16
|
assert_raises ArgumentError, "workspace is required" do
|
|
@@ -81,8 +70,8 @@ describe Transloadit do
|
|
|
81
70
|
url = @transloadit.signed_smart_cdn_url(**params)
|
|
82
71
|
assert_equal expected_url, url
|
|
83
72
|
|
|
84
|
-
if (
|
|
85
|
-
assert_equal expected_url,
|
|
73
|
+
if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
|
|
74
|
+
assert_equal expected_url, cli_url
|
|
86
75
|
end
|
|
87
76
|
end
|
|
88
77
|
|
|
@@ -98,8 +87,8 @@ describe Transloadit do
|
|
|
98
87
|
url = @transloadit.signed_smart_cdn_url(**params)
|
|
99
88
|
assert_equal expected_url, url
|
|
100
89
|
|
|
101
|
-
if (
|
|
102
|
-
assert_equal expected_url,
|
|
90
|
+
if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
|
|
91
|
+
assert_equal expected_url, cli_url
|
|
103
92
|
end
|
|
104
93
|
end
|
|
105
94
|
|
|
@@ -119,8 +108,8 @@ describe Transloadit do
|
|
|
119
108
|
url = @transloadit.signed_smart_cdn_url(**params)
|
|
120
109
|
assert_equal expected_url, url
|
|
121
110
|
|
|
122
|
-
if (
|
|
123
|
-
assert_equal expected_url,
|
|
111
|
+
if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
|
|
112
|
+
assert_equal expected_url, cli_url
|
|
124
113
|
end
|
|
125
114
|
end
|
|
126
115
|
|
|
@@ -140,8 +129,8 @@ describe Transloadit do
|
|
|
140
129
|
url = @transloadit.signed_smart_cdn_url(**params)
|
|
141
130
|
assert_equal expected_url, url
|
|
142
131
|
|
|
143
|
-
if (
|
|
144
|
-
assert_equal expected_url,
|
|
132
|
+
if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
|
|
133
|
+
assert_equal expected_url, cli_url
|
|
145
134
|
end
|
|
146
135
|
end
|
|
147
136
|
|
|
@@ -161,8 +150,8 @@ describe Transloadit do
|
|
|
161
150
|
url = @transloadit.signed_smart_cdn_url(**params)
|
|
162
151
|
assert_equal expected_url, url
|
|
163
152
|
|
|
164
|
-
if (
|
|
165
|
-
assert_equal expected_url,
|
|
153
|
+
if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
|
|
154
|
+
assert_equal expected_url, cli_url
|
|
166
155
|
end
|
|
167
156
|
end
|
|
168
157
|
end
|
data/transloadit.gemspec
CHANGED
|
@@ -7,8 +7,8 @@ Gem::Specification.new do |gem|
|
|
|
7
7
|
gem.version = Transloadit::VERSION
|
|
8
8
|
gem.platform = Gem::Platform::RUBY
|
|
9
9
|
|
|
10
|
-
gem.authors = ["Stephen Touset", "Robin Mehner"]
|
|
11
|
-
gem.email = %w[stephen@touset.org robin@coding-robin.de]
|
|
10
|
+
gem.authors = ["Stephen Touset", "Robin Mehner", "Kevin van Zonneveld"]
|
|
11
|
+
gem.email = %w[stephen@touset.org robin@coding-robin.de kevin@transloadit.com]
|
|
12
12
|
gem.homepage = "https://github.com/transloadit/ruby-sdk/"
|
|
13
13
|
gem.license = "MIT"
|
|
14
14
|
|
metadata
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: transloadit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.1.
|
|
4
|
+
version: 3.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stephen Touset
|
|
8
8
|
- Robin Mehner
|
|
9
|
+
- Kevin van Zonneveld
|
|
9
10
|
autorequire:
|
|
10
11
|
bindir: bin
|
|
11
12
|
cert_chain: []
|
|
12
|
-
date:
|
|
13
|
+
date: 2025-10-29 00:00:00.000000000 Z
|
|
13
14
|
dependencies:
|
|
14
15
|
- !ruby/object:Gem::Dependency
|
|
15
16
|
name: rest-client
|
|
@@ -170,20 +171,26 @@ description: The transloadit gem allows you to automate uploading files through
|
|
|
170
171
|
email:
|
|
171
172
|
- stephen@touset.org
|
|
172
173
|
- robin@coding-robin.de
|
|
174
|
+
- kevin@transloadit.com
|
|
173
175
|
executables: []
|
|
174
176
|
extensions: []
|
|
175
177
|
extra_rdoc_files: []
|
|
176
178
|
files:
|
|
179
|
+
- ".dockerignore"
|
|
180
|
+
- ".gitattributes"
|
|
177
181
|
- ".github/workflows/ci.yml"
|
|
178
182
|
- ".gitignore"
|
|
179
183
|
- ".standard.yml"
|
|
180
184
|
- ".vscode/ruby-sdk.code-workspace"
|
|
181
185
|
- CHANGELOG.md
|
|
186
|
+
- CONTRIBUTING.md
|
|
187
|
+
- Dockerfile
|
|
182
188
|
- Gemfile
|
|
183
189
|
- LICENSE
|
|
184
190
|
- Makefile
|
|
185
191
|
- README.md
|
|
186
192
|
- Rakefile
|
|
193
|
+
- chameleon.jpg
|
|
187
194
|
- examples/README.md
|
|
188
195
|
- examples/basic/assets/APU_Shutdown.mp3
|
|
189
196
|
- examples/basic/assets/Computers_are_in_Control.flac
|
|
@@ -205,6 +212,8 @@ files:
|
|
|
205
212
|
- lib/transloadit/step.rb
|
|
206
213
|
- lib/transloadit/template.rb
|
|
207
214
|
- lib/transloadit/version.rb
|
|
215
|
+
- scripts/notify-registry.sh
|
|
216
|
+
- scripts/test-in-docker.sh
|
|
208
217
|
- test/fixtures/cassettes/cancel_assembly.yml
|
|
209
218
|
- test/fixtures/cassettes/create_template.yml
|
|
210
219
|
- test/fixtures/cassettes/delete_template.yml
|
|
@@ -226,9 +235,9 @@ files:
|
|
|
226
235
|
- test/fixtures/cassettes/replay_assembly_notification.yml
|
|
227
236
|
- test/fixtures/cassettes/submit_assembly.yml
|
|
228
237
|
- test/fixtures/cassettes/update_template.yml
|
|
238
|
+
- test/integration/test_e2e_upload.rb
|
|
229
239
|
- test/test_helper.rb
|
|
230
240
|
- test/unit/test_transloadit.rb
|
|
231
|
-
- test/unit/transloadit/node-smartcdn-sig.ts
|
|
232
241
|
- test/unit/transloadit/test_api.rb
|
|
233
242
|
- test/unit/transloadit/test_assembly.rb
|
|
234
243
|
- test/unit/transloadit/test_request.rb
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env tsx
|
|
2
|
-
// Reference Smart CDN (https://transloadit.com/services/content-delivery/) Signature implementation
|
|
3
|
-
// And CLI tester to see if our SDK's implementation
|
|
4
|
-
// matches Node's
|
|
5
|
-
|
|
6
|
-
/// <reference types="node" />
|
|
7
|
-
|
|
8
|
-
import { createHash, createHmac } from 'crypto'
|
|
9
|
-
|
|
10
|
-
interface SmartCDNParams {
|
|
11
|
-
workspace: string
|
|
12
|
-
template: string
|
|
13
|
-
input: string
|
|
14
|
-
expire_at_ms?: number
|
|
15
|
-
auth_key?: string
|
|
16
|
-
auth_secret?: string
|
|
17
|
-
url_params?: Record<string, any>
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function signSmartCDNUrl(params: SmartCDNParams): string {
|
|
21
|
-
const {
|
|
22
|
-
workspace,
|
|
23
|
-
template,
|
|
24
|
-
input,
|
|
25
|
-
expire_at_ms,
|
|
26
|
-
auth_key = 'my-key',
|
|
27
|
-
auth_secret = 'my-secret',
|
|
28
|
-
url_params = {},
|
|
29
|
-
} = params
|
|
30
|
-
|
|
31
|
-
if (!workspace) throw new Error('workspace is required')
|
|
32
|
-
if (!template) throw new Error('template is required')
|
|
33
|
-
if (input === null || input === undefined)
|
|
34
|
-
throw new Error('input must be a string')
|
|
35
|
-
|
|
36
|
-
const workspaceSlug = encodeURIComponent(workspace)
|
|
37
|
-
const templateSlug = encodeURIComponent(template)
|
|
38
|
-
const inputField = encodeURIComponent(input)
|
|
39
|
-
|
|
40
|
-
const expireAt = expire_at_ms ?? Date.now() + 60 * 60 * 1000 // 1 hour default
|
|
41
|
-
|
|
42
|
-
const queryParams: Record<string, string[]> = {}
|
|
43
|
-
|
|
44
|
-
// Handle url_params
|
|
45
|
-
Object.entries(url_params).forEach(([key, value]) => {
|
|
46
|
-
if (value === null || value === undefined) return
|
|
47
|
-
if (Array.isArray(value)) {
|
|
48
|
-
value.forEach((val) => {
|
|
49
|
-
if (val === null || val === undefined) return
|
|
50
|
-
;(queryParams[key] ||= []).push(String(val))
|
|
51
|
-
})
|
|
52
|
-
} else {
|
|
53
|
-
queryParams[key] = [String(value)]
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
queryParams.auth_key = [auth_key]
|
|
58
|
-
queryParams.exp = [String(expireAt)]
|
|
59
|
-
|
|
60
|
-
// Sort parameters to ensure consistent ordering
|
|
61
|
-
const sortedParams = Object.entries(queryParams)
|
|
62
|
-
.sort()
|
|
63
|
-
.map(([key, values]) =>
|
|
64
|
-
values.map((v) => `${encodeURIComponent(key)}=${encodeURIComponent(v)}`)
|
|
65
|
-
)
|
|
66
|
-
.flat()
|
|
67
|
-
.join('&')
|
|
68
|
-
|
|
69
|
-
const stringToSign = `${workspaceSlug}/${templateSlug}/${inputField}?${sortedParams}`
|
|
70
|
-
const signature = createHmac('sha256', auth_secret)
|
|
71
|
-
.update(stringToSign)
|
|
72
|
-
.digest('hex')
|
|
73
|
-
|
|
74
|
-
const finalParams = `${sortedParams}&sig=${encodeURIComponent(
|
|
75
|
-
`sha256:${signature}`
|
|
76
|
-
)}`
|
|
77
|
-
return `https://${workspaceSlug}.tlcdn.com/${templateSlug}/${inputField}?${finalParams}`
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Read JSON from stdin
|
|
81
|
-
let jsonInput = ''
|
|
82
|
-
process.stdin.on('data', (chunk) => {
|
|
83
|
-
jsonInput += chunk
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
process.stdin.on('end', () => {
|
|
87
|
-
const params = JSON.parse(jsonInput)
|
|
88
|
-
console.log(signSmartCDNUrl(params))
|
|
89
|
-
})
|