@teralabs/shipstack 1.2.0

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.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,418 @@
1
+ # Shipstack
2
+
3
+ Shipstack is a high-performance, type-safe, framework-agnostic shipping SDK for USPS, FedEx, and UPS.
4
+ It provides unified rates, address validation, tracking, and shipment creation through a consistent, predictable API.
5
+
6
+ Shipstack is designed for:
7
+
8
+ - Storefronts (Nuxt, Next.js, SvelteKit, Remix)
9
+ - Serverless functions (Cloudflare, Vercel, Netlify)
10
+ - Node.js backends
11
+ - Edge runtimes
12
+ - Open-source projects that need reliable logistics tooling
13
+
14
+ Shipstack does not assume a backend, database, or dashboard.
15
+ You choose the workflow. Shipstack provides the building blocks.
16
+
17
+ ---
18
+
19
+ ## Features
20
+
21
+ ### Unified Orchestration
22
+ A single SDK surface for USPS, FedEx, and UPS.
23
+
24
+ ### Multi-Carrier Rates
25
+ Fetch normalized rates from any carrier and rank them for checkout.
26
+
27
+ ### Address Validation
28
+ Standardized address verification across all carriers.
29
+
30
+ ### Tracking Aggregator
31
+ Batch tracking with automatic carrier-specific chunking and concurrency limits.
32
+
33
+ ### Staged Shipments (Safe Mode)
34
+ Generate carrier-specific shipment payloads without purchasing a label.
35
+
36
+ ### Actual Label Creation (Advanced Mode)
37
+ Backend-only workflow for purchasing real labels.
38
+
39
+ ### Type-Safe
40
+ Strict TypeScript definitions for public request, response, and normalized models.
41
+
42
+ ### Runtime Agnostic
43
+ Works in Node.js, Bun, Deno, Cloudflare Workers, and other modern JavaScript runtimes.
44
+
45
+ ---
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ npm install @teralabs/shipstack
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Quick Start
56
+
57
+ ### 1. Create your config and clients
58
+
59
+ ```ts
60
+ import { ShippingClient, ShippingManager } from "@teralabs/shipstack";
61
+
62
+ const config = {
63
+ environment: "sandbox",
64
+ usps: {
65
+ enabled: true,
66
+ clientId: "YOUR_USPS_CLIENT_ID",
67
+ clientSecret: "YOUR_USPS_CLIENT_SECRET",
68
+ baseUrl: "https://sandbox.api.usps.com"
69
+ },
70
+ fedex: {
71
+ enabled: true,
72
+ clientId: "YOUR_FEDEX_CLIENT_ID",
73
+ clientSecret: "YOUR_FEDEX_CLIENT_SECRET",
74
+ accountNumber: "YOUR_FEDEX_ACCOUNT_NUMBER"
75
+ },
76
+ ups: {
77
+ enabled: true,
78
+ clientId: "YOUR_UPS_CLIENT_ID",
79
+ clientSecret: "YOUR_UPS_CLIENT_SECRET",
80
+ accountNumber: "YOUR_UPS_ACCOUNT_NUMBER"
81
+ }
82
+ };
83
+
84
+ const client = new ShippingClient(config);
85
+ const manager = new ShippingManager(config);
86
+ ```
87
+
88
+ Use `ShippingClient` for direct per-carrier operations. Use `ShippingManager` for multi-carrier checkout ranking.
89
+
90
+ ### 2. Compare carriers with `ShippingManager`
91
+
92
+ ```ts
93
+ const rankedRates = await manager.getRankedRates(
94
+ {
95
+ originZip: "90210",
96
+ destZip: "10001",
97
+ weightOz: 16,
98
+ lengthInches: 10,
99
+ widthInches: 5,
100
+ heightInches: 5
101
+ },
102
+ ["usps", "fedex", "ups"]
103
+ );
104
+
105
+ const cheapest = rankedRates.find(rate => rate.isCheapest);
106
+ const fastest = rankedRates.find(rate => rate.isFastest);
107
+
108
+ if (cheapest) {
109
+ console.log("Cheapest:", cheapest.serviceName, cheapest.cost.amount);
110
+ }
111
+
112
+ if (fastest) {
113
+ console.log("Fastest:", fastest.serviceName, fastest.deliveryDays);
114
+ }
115
+ ```
116
+
117
+ ### 3. Track with `ShippingClient`
118
+
119
+ ```ts
120
+ const tracking = await client.track(
121
+ ["9400100000000000000000", "9400100000000000000001"],
122
+ "usps"
123
+ );
124
+
125
+ tracking.forEach(pkg => {
126
+ console.log("Status of " + pkg.trackingNumber + ": " + pkg.status);
127
+ });
128
+ ```
129
+
130
+ ### Best Value (Functional API)
131
+
132
+ ```ts
133
+ import { getBestValueRate } from "@teralabs/shipstack";
134
+
135
+ const best = await getBestValueRate(
136
+ {
137
+ carrier: "usps",
138
+ originZip: "90210",
139
+ destZip: "10001",
140
+ weightOz: 16,
141
+ lengthInches: 10,
142
+ widthInches: 5,
143
+ heightInches: 5
144
+ },
145
+ config
146
+ );
147
+ ```
148
+
149
+ ### Fastest Service (Functional API)
150
+
151
+ ```ts
152
+ import { getFastestService } from "@teralabs/shipstack";
153
+
154
+ const fastest = await getFastestService(
155
+ {
156
+ carrier: "fedex",
157
+ originZip: "90210",
158
+ destZip: "10001",
159
+ weightOz: 16,
160
+ lengthInches: 10,
161
+ widthInches: 5,
162
+ heightInches: 5
163
+ },
164
+ config
165
+ );
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Validate an Address
171
+
172
+ ```ts
173
+ const result = await client.validateAddress({
174
+ carrier: "fedex",
175
+ address: {
176
+ streetLines: ["123 Main St"],
177
+ city: "New York",
178
+ stateOrProvinceCode: "NY",
179
+ postalCode: "10001",
180
+ countryCode: "US"
181
+ }
182
+ });
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Track Shipments
188
+
189
+ ```ts
190
+ import { trackShipment } from "@teralabs/shipstack";
191
+
192
+ const tracking = await trackShipment(
193
+ ["9400100000000000000000", "9400100000000000000001"],
194
+ "usps",
195
+ config
196
+ );
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Staged Shipments (Safe Mode)
202
+
203
+ Generate a carrier-specific shipment payload without purchasing a label.
204
+
205
+ This is recommended for:
206
+
207
+ - Storefronts
208
+ - Email workflows
209
+ - Serverless environments
210
+ - Custom dashboards
211
+ - Manual label creation
212
+
213
+ ```ts
214
+ import { buildShipment } from "@teralabs/shipstack";
215
+
216
+ const staged = await buildShipment(
217
+ {
218
+ carrier: "fedex",
219
+ serviceCode: "FEDEX_GROUND",
220
+ fromAddress: {
221
+ name: "Sender Name",
222
+ streetLines: ["123 Warehouse Rd"],
223
+ city: "Los Angeles",
224
+ stateOrProvinceCode: "CA",
225
+ postalCode: "90001",
226
+ countryCode: "US"
227
+ },
228
+ toAddress: {
229
+ name: "Customer Name",
230
+ streetLines: ["55 W 46th St"],
231
+ city: "New York",
232
+ stateOrProvinceCode: "NY",
233
+ postalCode: "10036",
234
+ countryCode: "US"
235
+ },
236
+ package: {
237
+ weightOz: 32,
238
+ lengthInches: 12,
239
+ widthInches: 8,
240
+ heightInches: 4
241
+ }
242
+ },
243
+ config
244
+ );
245
+
246
+ console.log(staged.payload);
247
+ ```
248
+
249
+ This does not call the carrier API.
250
+ This does not purchase postage.
251
+
252
+ ---
253
+
254
+ ## Actual Label Creation (Advanced Mode)
255
+
256
+ This method purchases a real label and must only be used in secure backend environments.
257
+
258
+ ```ts
259
+ import { createShipment } from "@teralabs/shipstack";
260
+
261
+ const shipment = await createShipment(
262
+ {
263
+ carrier: "ups",
264
+ serviceCode: "UPS_GROUND",
265
+ fromAddress: {
266
+ name: "Sender Name",
267
+ streetLines: ["123 Warehouse Rd"],
268
+ city: "Los Angeles",
269
+ stateOrProvinceCode: "CA",
270
+ postalCode: "90001",
271
+ countryCode: "US"
272
+ },
273
+ toAddress: {
274
+ name: "Customer Name",
275
+ streetLines: ["55 W 46th St"],
276
+ city: "New York",
277
+ stateOrProvinceCode: "NY",
278
+ postalCode: "10036",
279
+ countryCode: "US"
280
+ },
281
+ package: {
282
+ weightOz: 48,
283
+ lengthInches: 14,
284
+ widthInches: 10,
285
+ heightInches: 6
286
+ }
287
+ },
288
+ config
289
+ );
290
+
291
+ console.log(shipment.label.base64);
292
+ console.log(shipment.trackingNumber);
293
+ ```
294
+
295
+ Warning:
296
+ Do not call this from the frontend.
297
+ This charges the merchant's carrier account.
298
+
299
+ ---
300
+
301
+ ## Safe vs Advanced Usage
302
+
303
+ | Feature | buildShipment() | createShipment() |
304
+ |--------|-----------------|------------------|
305
+ | Generates carrier payload | Yes | Yes |
306
+ | Purchases a label | No | Yes |
307
+ | Safe for frontend | Yes | No |
308
+ | Requires secure backend | No | Yes |
309
+ | Good for email workflows | Yes | Limited |
310
+ | Good for automation | Limited | Yes |
311
+
312
+ ---
313
+
314
+ ## Functional API (Stateless)
315
+
316
+ ```ts
317
+ import {
318
+ getRates,
319
+ getBestValueRate,
320
+ getFastestService,
321
+ predictCarrier,
322
+ validateAddress,
323
+ trackShipment
324
+ } from "@teralabs/shipstack";
325
+
326
+ const rates = await getRates(
327
+ {
328
+ carrier: "usps",
329
+ originZip: "90210",
330
+ destZip: "10001",
331
+ weightOz: 16,
332
+ lengthInches: 10,
333
+ widthInches: 5,
334
+ heightInches: 5
335
+ },
336
+ config
337
+ );
338
+ const carrier = predictCarrier("1Z9999999999999999");
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Direct Carrier Access
344
+
345
+ Only the low-level rate clients are exported directly from the package entrypoint.
346
+
347
+ ```ts
348
+ import { createUspsRatesClient } from "@teralabs/shipstack";
349
+
350
+ const usps = createUspsRatesClient(config.usps);
351
+ const rawResponse = await usps.getRates({ /* USPS request payload */ });
352
+ ```
353
+
354
+ ---
355
+
356
+ ## Error Handling
357
+
358
+ ```ts
359
+ import { ShipstackError } from "@teralabs/shipstack";
360
+
361
+ const request = {
362
+ carrier: "usps",
363
+ originZip: "90210",
364
+ destZip: "10001",
365
+ weightOz: 16,
366
+ lengthInches: 10,
367
+ widthInches: 5,
368
+ heightInches: 5
369
+ };
370
+
371
+ try {
372
+ await client.getRates(request);
373
+ } catch (error) {
374
+ if (error instanceof ShipstackError) {
375
+ console.error(error.message);
376
+ console.error(error.carrier);
377
+ console.error(error.cause);
378
+ }
379
+ }
380
+ ```
381
+
382
+ ---
383
+
384
+ ## Development
385
+
386
+ **npm run generate:usps** (sync USPS v3 specs)
387
+
388
+ **npm run generate:fedex** (sync local FedEx specs)
389
+
390
+ **npm run generate:ups** (sync local UPS specs)
391
+
392
+ **npm run generate:all** (sync all carriers)
393
+
394
+ ```bash
395
+ npm run generate:usps
396
+ npm run generate:fedex
397
+ npm run generate:ups
398
+ npm run generate:all
399
+ ```
400
+
401
+ ---
402
+
403
+ ## Documentation
404
+
405
+ - docs/index.md
406
+ - docs/API.md
407
+ - docs/config.example.ts
408
+ - CHANGELOG.md
409
+ - CONTRIBUTING.md
410
+
411
+ ---
412
+
413
+ ## License
414
+
415
+ ISC License
416
+ Copyright (c) 2026
417
+
418
+ ---