npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

parse-aws-s3-presigned-url-tool

v1.1.2

Published

Interactive CLI tool that parses an AWS S3 pre-signed URL and exports it as a Bruno collection, a Postman collection, or a cURL command

Readme

parse-aws-s3-presigned-url-tool

An interactive Node.js CLI tool that parses an AWS S3 pre-signed URL and exports it as a Bruno collection, a Postman collection, or a cURL command you can run directly.

Features

  • Interactive prompts – no flags to memorise
  • Non-interactive mode – supply all arguments via flags for scripting and CI use
  • --parse mode – dumps a structured JSON object of all presigned-URL fields to stdout for direct use in calling code
  • --stdout mode – outputs the result as JSON for consumption by other Node.js apps
  • GET mode – keeps all query parameters as URL parameters
  • POST mode – converts every query parameter into a multipart form field (HTML entities in values are decoded automatically)
  • Bruno output – generates a Bruno collection JSON (output/bruno-collection.json)
  • Postman output – generates a Postman Collection v2.1 JSON (output/postman-collection.json)
  • cURL output – generates a ready-to-run cURL command (output/request.sh)

Requirements

  • Node.js ≥ 18

Installation

npm install

Usage

Interactive mode

npm start

The CLI will ask you three questions:

  1. URL – paste your AWS S3 pre-signed URL
  2. MethodGET (query params) or POST (multipart form fields)
  3. FormatBruno, Postman, or cURL

The generated file is written to the output/ directory in the current working directory.

Non-interactive mode (flags)

Pass all three arguments directly to skip every prompt:

# Using npx (no global install required)
npx parse-aws-s3-presigned-url-tool \
  --url "https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=..." \
  --method GET \
  --format bruno
# Or with the short alias
npx parse-s3-url \
  --url "https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=..." \
  --method POST \
  --format curl

You can also supply only some flags – the tool will prompt for the rest:

npx parse-s3-url --url "https://..." --method GET
# Only the format prompt is shown

Programmatic / machine-readable output (--stdout)

Add the --stdout flag to have the tool write a JSON object to stdout instead of a human-readable message. This is ideal when calling the tool from another Node.js application.

--stdout requires --url, --method, and --format to all be provided.

npx parse-s3-url \
  --url "https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=..." \
  --method GET \
  --format postman \
  --stdout

Output shape

Every --stdout run emits exactly one JSON line to stdout:

{
  "filePath": "/absolute/path/to/output/<filename>",
  "content": "<generated file content as a string>"
}

| Field | Description | |-------|-------------| | filePath | Absolute path of the file that was written to disk. Use this when you need to pass the file to another tool that expects a path. | | content | The full text of the generated file. For bruno and postman formats this is a JSON string (parse it with JSON.parse). For curl it is a plain shell script string. |

Status and error messages are always written to stderr, keeping stdout clean for the JSON payload.


Synchronous usage (execFileSync)

The simplest approach — blocks until the tool exits, then parses the output.

Postman format

import { execFileSync } from 'child_process';

const raw = execFileSync(
  'npx',
  [
    'parse-s3-url',
    '--url', 'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...',
    '--method', 'GET',
    '--format', 'postman',
    '--stdout',
  ],
  { encoding: 'utf-8' }
);

const { filePath, content } = JSON.parse(raw);
const collection = JSON.parse(content);          // Postman Collection v2.1 object
console.log('Written to:', filePath);
console.log('Collection name:', collection.info.name);
console.log('First request:', collection.item[0].name);

Bruno format

import { execFileSync } from 'child_process';

const raw = execFileSync(
  'npx',
  [
    'parse-s3-url',
    '--url', 'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...',
    '--method', 'GET',
    '--format', 'bruno',
    '--stdout',
  ],
  { encoding: 'utf-8' }
);

const { filePath, content } = JSON.parse(raw);
const collection = JSON.parse(content);          // Bruno collection object
console.log('Written to:', filePath);
console.log('Collection name:', collection.name);
console.log('First item:', collection.items[0].name);

cURL format

import { execFileSync } from 'child_process';

const raw = execFileSync(
  'npx',
  [
    'parse-s3-url',
    '--url', 'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...',
    '--method', 'GET',
    '--format', 'curl',
    '--stdout',
  ],
  { encoding: 'utf-8' }
);

const { filePath, content } = JSON.parse(raw);
// `content` is a plain shell script string — no further parsing needed
console.log('Written to:', filePath);
console.log('cURL command:\n', content);

Error handling

execFileSync throws when the process exits with a non-zero code. Wrap the call in a try/catch and read err.stderr for the human-readable error message:

import { execFileSync } from 'child_process';

try {
  const raw = execFileSync(
    'npx',
    [
      'parse-s3-url',
      '--url', 'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...',
      '--method', 'GET',
      '--format', 'postman',
      '--stdout',
    ],
    { encoding: 'utf-8' }
  );

  const { filePath, content } = JSON.parse(raw);
  const collection = JSON.parse(content);
  console.log('Done:', filePath);
} catch (err) {
  // err.stderr contains the human-readable error written by the tool
  console.error('Tool failed:', err.stderr || err.message);
}

Asynchronous usage (execFile)

Use execFile when you do not want to block the event loop:

import { execFile } from 'child_process';

execFile(
  'npx',
  [
    'parse-s3-url',
    '--url', 'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...',
    '--method', 'GET',
    '--format', 'postman',
    '--stdout',
  ],
  { encoding: 'utf-8' },
  (err, stdout, stderr) => {
    if (err) {
      console.error('Tool failed:', stderr || err.message);
      return;
    }

    const { filePath, content } = JSON.parse(stdout);
    const collection = JSON.parse(content);
    console.log('Done:', filePath);
    console.log('Collection name:', collection.info.name);
  }
);

Or with util.promisify for promise-based / async–await code:

import { execFile } from 'child_process';
import { promisify } from 'util';

const execFileAsync = promisify(execFile);

async function generatePostmanCollection(presignedUrl) {
  const { stdout, stderr } = await execFileAsync(
    'npx',
    [
      'parse-s3-url',
      '--url', presignedUrl,
      '--method', 'GET',
      '--format', 'postman',
      '--stdout',
    ],
    { encoding: 'utf-8' }
  );

  const { filePath, content } = JSON.parse(stdout);
  return { filePath, collection: JSON.parse(content) };
}

// Usage
const { filePath, collection } = await generatePostmanCollection(
  'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...'
);
console.log('Written to:', filePath);
console.log('Collection name:', collection.info.name);

CLI flags reference

| Flag | Values | Description | |------|--------|-------------| | --url <url> | Any valid URL | AWS S3 pre-signed URL to parse | | --method <method> | GET, POST | HTTP method for the generated request | | --format <format> | bruno, postman, curl | Output format | | --stdout | (boolean) | Print { filePath, content } JSON to stdout instead of a human-readable message. Requires --url, --method, and --format. | | --parse | (boolean) | Parse the URL and print the structured JSON object to stdout, then exit. Only --url is required; --method and --format are ignored. |


JSON utility (--parse)

Use --parse when you want a structured JSON object of all presigned-URL fields without generating any collection file. Only --url is required.

npx parse-s3-url \
  --url "https://my-bucket.s3.us-east-1.amazonaws.com/uploads/photo.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20230101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230101T000000Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=abcdef1234567890" \
  --parse

Output written to stdout:

{
  "url": "<original URL>",
  "baseUrl": "https://my-bucket.s3.us-east-1.amazonaws.com/uploads/photo.jpg",
  "protocol": "https",
  "host": "my-bucket.s3.us-east-1.amazonaws.com",
  "bucket": "my-bucket",
  "key": "uploads/photo.jpg",
  "pathname": "/uploads/photo.jpg",
  "region": "us-east-1",
  "algorithm": "AWS4-HMAC-SHA256",
  "credential": "AKIAIOSFODNN7EXAMPLE/20230101/us-east-1/s3/aws4_request",
  "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
  "credentialDate": "20230101",
  "date": "20230101T000000Z",
  "expires": "3600",
  "signedHeaders": "host",
  "signature": "abcdef1234567890",
  "securityToken": null,
  "params": {
    "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
    "X-Amz-Credential": "AKIAIOSFODNN7EXAMPLE/20230101/us-east-1/s3/aws4_request",
    "X-Amz-Date": "20230101T000000Z",
    "X-Amz-Expires": "3600",
    "X-Amz-SignedHeaders": "host",
    "X-Amz-Signature": "abcdef1234567890"
  }
}

| Field | Description | |-------|-------------| | url | The original URL string passed in | | baseUrl | URL without the query string | | protocol | https or http | | host | Full hostname (e.g. my-bucket.s3.us-east-1.amazonaws.com) | | bucket | Bucket name extracted from a virtual-hosted-style hostname; null for path-style URLs | | key | S3 object key (pathname without the leading /) | | pathname | URL pathname with the leading / | | region | AWS region from the hostname or, as a fallback, from the credential scope; null if not determinable | | algorithm | Value of X-Amz-Algorithm; null if absent | | credential | Full value of X-Amz-Credential; null if absent | | accessKeyId | First segment of the credential (<keyId>/…); null if credential absent | | credentialDate | Second segment of the credential (…/<date>/…); null if credential absent | | date | Value of X-Amz-Date; null if absent | | expires | Value of X-Amz-Expires (seconds as a string); null if absent | | signedHeaders | Value of X-Amz-SignedHeaders; null if absent | | signature | Value of X-Amz-Signature; null if absent | | securityToken | Value of X-Amz-Security-Token; null if absent | | params | All query parameters as a flat { name: value } map (includes non-standard params) |

Programmatic import

You can also use parsePresignedUrlToJson directly in your own code without spawning a child process:

import { parsePresignedUrlToJson } from 'parse-aws-s3-presigned-url-tool/src/parser.js';

const presignedUrl = 'https://my-bucket.s3.us-east-1.amazonaws.com/uploads/photo.jpg?X-Amz-Algorithm=...';

const {
  bucket,
  key,
  region,
  accessKeyId,
  expires,
  signature,
  params,
} = parsePresignedUrlToJson(presignedUrl);

console.log(`Bucket: ${bucket}, Key: ${key}, Region: ${region}`);
console.log(`Expires in: ${expires}s`);

Calling from a Node.js app via the CLI

import { execFileSync } from 'child_process';

const raw = execFileSync(
  'npx',
  [
    'parse-s3-url',
    '--url', 'https://my-bucket.s3.amazonaws.com/file.jpg?X-Amz-Algorithm=...',
    '--parse',
  ],
  { encoding: 'utf-8' }
);

const { bucket, key, region, expires, signature } = JSON.parse(raw);
console.log(`Bucket: ${bucket}, Key: ${key}, Region: ${region}`);

Running Tests

npm test

Project Structure

src/
  index.js               # CLI entry point (interactive & non-interactive)
  parser.js              # URL parsing and HTML-entity decoding
  generators/
    bruno.js             # Bruno collection generator
    postman.js           # Postman Collection v2.1 generator
    curl.js              # cURL command generator
tests/
  parser.test.js
  generators/
    bruno.test.js
    postman.test.js
    curl.test.js