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

@aftership/carrier-account-sdk

v0.1.0

Published

This SDK enables your application to open an AfterShip-hosted popup window for carrier account creation or editing.

Readme

@aftership/carrier-account-sdk

This SDK enables your application to open an AfterShip-hosted popup window for carrier account creation or editing.

It is intended for customer integration. This document focuses on the integration contract, implementation responsibilities, and SDK usage, while keeping internal implementation details to a minimum.

1. Overview

This integration allows your application to start an AfterShip-hosted carrier account flow without redirecting the user away from your page.

The typical flow is:

  1. Your backend prepares a Signed URL for the requested action.
  2. Your frontend passes that Signed URL into sdk.open(...).
  3. The SDK opens the popup window and manages the browser-side flow.
  4. Your frontend receives the final result through callbacks such as onSuccess, onError, or onClose.

This SDK is designed to keep the frontend integration simple. Your application does not need to implement popup lifecycle management or cross-window message handling by itself.

2. Glossary

| Term | Description | | --- | --- | | Signed URL | A temporary absolute URL used to open the AfterShip-hosted popup flow. | | request_id | A request identifier used to correlate a specific create flow. | | shipper_account_id | The final carrier account identifier returned after a successful flow. | | Popup Window | A separate browser window opened by the SDK to host the AfterShip UI. | | Host Application | Your frontend application that integrates this SDK. | | AfterShip Hosted UI | The popup page hosted by AfterShip where the user completes the flow. |

3. Integration Flow Design

3.1 Flowchart and Interaction Description

The integration flow is shown below:

flowchart TD
    A["User initiates Create or Edit"] --> B["Host frontend requests Signed URL from backend"]
    B --> C["Backend returns Signed URL"]
    C --> D["Frontend calls sdk.open({ url: signedUrl, ... })"]
    D --> E["SDK opens AfterShip Hosted UI in a popup window"]
    E --> F["User completes the carrier account flow"]
    F --> G{"Final popup result"}
    G -->|Success| H["onSuccess({ request_id?, shipper_account_id, action })"]
    G -->|Runtime error| I["onError({ request_id?, code, message })"]
    G -->|Closed| J["onClose({ request_id?, reason })"]

Typical user interaction:

  1. The user clicks a button or toggles a control in your application.
  2. Your frontend asks your backend for a Signed URL.
  3. Your frontend calls the SDK with that Signed URL.
  4. The SDK opens the popup window and waits for the hosted flow to finish.
  5. Your page updates its state according to the returned callback result.

3.2 How the Signed URL and Popup Flow Work

This SDK assumes that your frontend receives a Signed URL from your backend or another trusted integration layer.

Why this design:

  • The popup is opened with a request-specific URL instead of static credentials.
  • The frontend only needs to pass the URL into the SDK.
  • The SDK isolates popup lifecycle handling from your application code.

What the SDK handles on your behalf:

  1. Validating the Signed URL format and protocol.
  2. Opening and closing the popup window.
  3. Listening for messages returned from the popup window.
  4. Matching messages by request_id when available.
  5. Normalizing the final browser-side result into onSuccess, onError, or onClose.

What remains outside the SDK scope:

  • generating the Signed URL
  • deciding when to start Create or Edit
  • updating your own business state after the callback returns
  • persisting any mapping between your entities and shipper_account_id

4. What the Client Needs to Implement

The integration normally involves both frontend and backend work. The sections below outline the responsibilities for each side.

4.1 Backend Responsibilities

Your backend should:

  1. Prepare a Signed URL for the requested action.
  2. Return that Signed URL to the frontend.
  3. Provide the frontend with the correct business context for Create or Edit.

Common patterns:

  • Create flow: prepare a Signed URL associated with a new connection attempt, often including a new request_id.
  • Edit flow: prepare a Signed URL associated with an existing shipper_account_id.

4.2 Frontend Responsibilities

Your frontend should:

  1. Initialize the SDK on the page where the user starts the carrier account flow.
  2. Request a Signed URL before calling sdk.open(...).
  3. Call the SDK from a user-triggered action whenever possible.
  4. Update the page state according to the callback result.
  5. Call sdk.destroy() when the page or integration surface is unloaded.

4.3 Suggested Create and Edit Sequences

Create flow:

sequenceDiagram
    participant Frontend as Host Frontend
    participant Backend as Host Backend
    participant SDK as AfterShip SDK
    participant AfterShip as AfterShip Hosted UI

    Frontend->>Backend: Request Signed URL for create
    Backend-->>Frontend: Return Signed URL
    Frontend->>SDK: sdk.open({ url: signedUrl, ... })
    SDK->>AfterShip: Open popup with Signed URL
    AfterShip-->>SDK: Return success / error / close result
    SDK-->>Frontend: Trigger callback
    Frontend->>Frontend: Update UI state

Edit flow:

sequenceDiagram
    participant Frontend as Host Frontend
    participant Backend as Host Backend
    participant SDK as AfterShip SDK
    participant AfterShip as AfterShip Hosted UI

    Frontend->>Backend: Request Signed URL for edit
    Backend-->>Frontend: Return Signed URL
    Frontend->>SDK: sdk.open({ url: signedUrl, ... })
    SDK->>AfterShip: Open popup with Signed URL
    AfterShip-->>SDK: Return success / error / close result
    SDK-->>Frontend: Trigger callback
    Frontend->>Frontend: Update UI state

5. SDK Reference

5.1 Installation

pnpm add @aftership/carrier-account-sdk

5.2 Initialization

import { init } from "@aftership/carrier-account-sdk";

const sdk = init();

5.3 sdk.open(...)

sdk.open({
  url,
  onSuccess(payload) {},
  onError(payload) {},
  onClose(payload) {},
});

Parameter reference:

| Field | Type | Description | | --- | --- | --- | | url | string | A Signed URL. It must be a valid absolute URL. | | onSuccess | (payload) => void | Called when the user completes the flow successfully. | | onError | (payload) => void | Called when the flow cannot continue because of invalid URLs or runtime errors. | | onClose | (payload) => void | Called when a popup that was opened is later closed. |

5.4 Minimal Integration Example

import { init } from "@aftership/carrier-account-sdk";

const sdk = init();

async function connectCarrier() {
  const signedUrl = await getSignedUrlFromBackend();

  sdk.open({
    url: signedUrl,
    onSuccess(payload) {
      console.log("connect success", payload);
    },
    onError(payload) {
      console.error("connect error", payload);
    },
    onClose(payload) {
      console.log("popup closed", payload);
    },
  });
}

window.addEventListener("beforeunload", () => {
  sdk.destroy();
});

5.5 Callback Payloads

onSuccess

Called when the user completes the flow successfully.

{
  request_id?: string;
  shipper_account_id: string;
  action: "create" | "edit";
}

Field reference:

| Field | Type | Description | | --- | --- | --- | | request_id | string \| undefined | The request identifier when available. | | shipper_account_id | string | The resulting carrier account identifier. | | action | "create" \| "edit" | The final completed action. |

onError

Called when the flow cannot continue before completion.

{
  request_id?: string;
  code: string;
  message: string;
}

Field reference:

| Field | Type | Description | | --- | --- | --- | | request_id | string \| undefined | The request identifier when available. | | code | string | A normalized error code. | | message | string | A normalized human-readable error message. |

Common error codes:

  • INVALID_URL: the Signed URL is not a valid absolute URL
  • INVALID_PROTOCOL: the Signed URL does not use an allowed protocol

onClose

Called when the popup window is closed.

{
  request_id?: string;
  reason: "user_closed" | "unknown";
}

Field reference:

| Field | Type | Description | | --- | --- | --- | | request_id | string \| undefined | The request identifier when available. | | reason | "user_closed" \| "unknown" | The normalized close reason. |

Close reasons:

  • user_closed: the user closed the popup manually
  • unknown: the popup closed without a more specific reason

5.6 URL Requirements

The SDK requires the url passed to sdk.open(...) to be a valid Signed URL.

Allowed protocols:

Production:
  https://

Local development:
  http://localhost
  http://127.0.0.1
  http://[::1]
  http://::1

If the URL is invalid, the SDK will trigger onError immediately.

Validation behavior:

  • invalid absolute URL -> INVALID_URL
  • unsupported protocol -> INVALID_PROTOCOL

6. Troubleshooting and FAQ

6.1 Why did I not receive onSuccess?

Check in this order:

  1. Confirm the Signed URL is valid.
  2. Confirm the popup flow actually reached a successful end state.
  3. Confirm the request_id still matches the current request when applicable.
  4. Confirm your page did not destroy the SDK instance too early.

6.2 What should I do if the popup does not open?

Recommended practice:

  • call sdk.open(...) directly from a user click or similar user-triggered action
  • use request_id from the payload when it is available

6.3 What should I do when the page is unloaded?

Call:

sdk.destroy();

This closes the popup if it is still open and removes related listeners.

6.4 What is the simplest mental model for this SDK?

flowchart LR
    A["Prepare Signed URL"] --> B["Call sdk.open(...)"]
    B --> C["Handle callback result"]

In most integrations, you only need to do these three things:

  1. Prepare the Signed URL.
  2. Call sdk.open(...).
  3. Update your business state according to the callback result.

7. Debugging Tips

If you want to verify the flow quickly, you can refer to the example in the repository:

apps/example

Please note:

  • the example is mainly used to verify popup behavior and callback handling
  • you should not treat the example integration as your production implementation directly