sound-tank 1.3.0 โ†’ 1.3.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +665 -21
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # sound-tank
2
2
 
3
+ ## 1.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - ec5975d: update readme
8
+
3
9
  ## 1.3.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -1,37 +1,681 @@
1
- <h1 align="center">
2
- Sound Tank
3
- </h1>
1
+ <h1 align="center">๐ŸŽธ Sound Tank</h1>
4
2
 
5
3
  <p align="center">
6
- A library to interface with <a href="https://www.reverb.com/" target="_blank">Reverb's</a> API programmatically.
4
+ <strong>TypeScript SDK for the <a href="https://reverb.com">Reverb Marketplace</a> API</strong>
7
5
  </p>
8
6
 
9
7
  <p align="center">
10
- To get started, just run <code>npm install sound-tank</code> in your project's directory, or <code>yarn add sound-tank</code> if you prefer Yarn.
8
+ A modern, type-safe interface for buying, selling, and managing musical instruments and gear on Reverb
11
9
  </p>
12
10
 
13
- <h2>
14
- Example Usage
15
- </h2>
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/sound-tank"><img src="https://img.shields.io/npm/v/sound-tank.svg" alt="npm version"></a>
13
+ <a href="https://www.npmjs.com/package/sound-tank"><img src="https://img.shields.io/npm/dm/sound-tank.svg" alt="npm downloads"></a>
14
+ <a href="https://github.com/ZacharyEggert/sound-tank/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
15
+ <a href="https://github.com/ZacharyEggert/sound-tank/actions"><img src="https://github.com/ZacharyEggert/sound-tank/workflows/CI/badge.svg" alt="Build Status"></a>
16
+ <img src="https://img.shields.io/badge/TypeScript-5.8-blue" alt="TypeScript">
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## Quick Start
22
+
23
+ ```bash
24
+ npm install sound-tank
25
+ # or
26
+ yarn add sound-tank
27
+ # or
28
+ pnpm add sound-tank
29
+ ```
16
30
 
17
31
  ```typescript
18
32
  import Reverb from 'sound-tank';
19
33
 
20
- const { REVERB_API_KEY } = process.env;
34
+ const reverb = new Reverb({ apiKey: process.env.REVERB_API_KEY });
35
+ const { data } = await reverb.getMyListings({ perPage: 10, state: 'live' });
36
+
37
+ data.listings.forEach(listing => {
38
+ console.log(`${listing.title}: ${listing.price.display}`);
39
+ });
40
+ ```
41
+
42
+ ## Features
43
+
44
+ - โœ… **Full TypeScript Support** - Complete type definitions for all API entities
45
+ - โœ… **Automatic Pagination** - Built-in helpers to fetch all results seamlessly
46
+ - โœ… **Configuration Management** - Easy setup for currency, locale, and shipping preferences
47
+ - โœ… **Comprehensive Coverage** - Listings, orders, and arbitrary endpoint access
48
+ - โœ… **HTTP Client Abstraction** - Clean architecture with testable mock implementations
49
+ - โœ… **Dual Module Support** - Both CommonJS and ESM builds included
50
+ - โœ… **Well Tested** - Extensive unit and integration test coverage
51
+ - โœ… **Minimal Dependencies** - Only requires axios
52
+
53
+ ## Table of Contents
54
+
55
+ - [Installation](#installation)
56
+ - [Getting Started](#getting-started)
57
+ - [Configuration](#configuration)
58
+ - [API Methods](#api-methods)
59
+ - [getMyListings](#getmylistingsoptions)
60
+ - [getAllMyListings](#getallmylistingsoptions)
61
+ - [getOneListing](#getonelistingoptions)
62
+ - [getMyOrders](#getmyordersoptions)
63
+ - [getArbitraryEndpoint](#getarbitraryendpointoptions)
64
+ - [TypeScript Usage](#typescript-usage)
65
+ - [Advanced Features](#advanced-features)
66
+ - [Examples](#examples)
67
+ - [Development](#development)
68
+ - [Testing](#testing)
69
+ - [Contributing](#contributing)
70
+ - [License](#license)
71
+
72
+ ## Installation
73
+
74
+ Install via your preferred package manager:
75
+
76
+ ```bash
77
+ npm install sound-tank
78
+ # or
79
+ yarn add sound-tank
80
+ # or
81
+ pnpm add sound-tank
82
+ ```
83
+
84
+ ### Getting a Reverb API Key
85
+
86
+ 1. Visit [Reverb API Settings](https://reverb.com/my/api)
87
+ 2. Generate a new API token
88
+ 3. Set the appropriate scopes for your use case
89
+ 4. Store securely in environment variables
90
+
91
+ ```bash
92
+ # .env
93
+ REVERB_API_KEY=your_api_key_here
94
+ ```
95
+
96
+ You can use the provided `.env.example` file as a template:
97
+
98
+ ```bash
99
+ cp .env.example .env
100
+ # Edit .env and add your REVERB_API_KEY
101
+ ```
102
+
103
+ ## Getting Started
104
+
105
+ ### Initialize the Client
106
+
107
+ ```typescript
108
+ import Reverb from 'sound-tank';
109
+
110
+ const reverb = new Reverb({
111
+ apiKey: process.env.REVERB_API_KEY,
112
+ displayCurrency: 'USD', // optional
113
+ locale: 'en', // optional
114
+ version: '3.0', // optional
115
+ });
116
+ ```
117
+
118
+ ### Fetch Your Listings
119
+
120
+ ```typescript
121
+ const response = await reverb.getMyListings({
122
+ perPage: 25,
123
+ page: 1,
124
+ state: 'live',
125
+ query: 'Gibson Les Paul'
126
+ });
127
+
128
+ console.log(response.data.listings);
129
+ ```
130
+
131
+ ### Error Handling
132
+
133
+ ```typescript
134
+ try {
135
+ const response = await reverb.getMyListings({ state: 'live' });
136
+ console.log(`Found ${response.data.listings.length} listings`);
137
+ } catch (error) {
138
+ console.error('Failed to fetch listings:', error.message);
139
+ }
140
+ ```
141
+
142
+ ## Configuration
143
+
144
+ ### Constructor Options
145
+
146
+ | Option | Type | Required | Default | Description |
147
+ |--------|------|----------|---------|-------------|
148
+ | `apiKey` | `string` | โœ… Yes | - | Your Reverb API key |
149
+ | `version` | `string` | No | `'3.0'` | API version to use |
150
+ | `rootEndpoint` | `string` | No | `'https://api.reverb.com/api'` | API base URL |
151
+ | `displayCurrency` | `string` | No | `'USD'` | Currency for price display |
152
+ | `locale` | `string` | No | `'en'` | Language locale (e.g., 'en', 'fr', 'de') |
153
+ | `shippingRegion` | `string` | No | `undefined` | Shipping region code (e.g., 'US', 'EU') |
154
+
155
+ ### Runtime Configuration
156
+
157
+ You can update configuration after initialization using setters:
158
+
159
+ ```typescript
160
+ reverb.displayCurrency = 'EUR';
161
+ reverb.locale = 'fr';
162
+ reverb.shippingRegion = 'FR';
163
+ reverb.version = '3.0';
164
+ ```
165
+
166
+ These changes automatically update the internal headers and configuration for subsequent API requests.
167
+
168
+ ## API Methods
169
+
170
+ ### getMyListings(options?)
171
+
172
+ Fetch a paginated list of your listings.
173
+
174
+ **Parameters:**
175
+ - `perPage?: number` - Items per page
176
+ - `page?: number` - Page number (starts at 1)
177
+ - `query?: string` - Search query to filter listings
178
+ - `state?: string` - Filter by state: `'live'`, `'sold'`, `'draft'`, or `'all'`
179
+
180
+ **Returns:** `Promise<AxiosResponse<PaginatedReverbResponse<{ listings: Listing[] }>>>`
181
+
182
+ **Example:**
183
+ ```typescript
184
+ const response = await reverb.getMyListings({
185
+ perPage: 50,
186
+ page: 1,
187
+ state: 'live',
188
+ query: 'Fender Stratocaster'
189
+ });
190
+
191
+ const { listings } = response.data;
192
+ console.log(`Page 1: ${listings.length} listings`);
193
+ ```
194
+
195
+ ---
196
+
197
+ ### getAllMyListings(options?)
198
+
199
+ Automatically fetches **all** listings across all pages using automatic pagination.
200
+
201
+ **Parameters:**
202
+ - `query?: string` - Search query to filter listings
203
+ - `state?: ListingStates` - Filter by state: `ListingStates.LIVE`, `ListingStates.SOLD`, or `ListingStates.DRAFT`
204
+
205
+ **Returns:** `Promise<AxiosResponse<Listing[]>>`
206
+
207
+ **Example:**
208
+ ```typescript
209
+ const response = await reverb.getAllMyListings({ state: 'live' });
210
+ const allListings = response.data; // All listings from all pages
211
+
212
+ console.log(`Total listings: ${allListings.length}`);
213
+ ```
214
+
215
+ > **Note:** This method automatically handles pagination by fetching all pages sequentially until all results are retrieved.
216
+
217
+ ---
218
+
219
+ ### getOneListing(options)
220
+
221
+ Fetch a single listing by ID.
222
+
223
+ **Parameters:**
224
+ - `id: string` - Listing ID (required)
225
+
226
+ **Returns:** `Promise<AxiosResponse<Listing>>`
227
+
228
+ **Example:**
229
+ ```typescript
230
+ const response = await reverb.getOneListing({ id: '12345' });
231
+ const listing = response.data;
232
+
233
+ console.log(`${listing.title} - ${listing.price.display}`);
234
+ console.log(`Condition: ${listing.condition.displayName}`);
235
+ ```
236
+
237
+ ---
238
+
239
+ ### getMyOrders(options?)
240
+
241
+ Fetch your orders with pagination.
242
+
243
+ **Parameters:**
244
+ - `page?: number` - Page number (starts at 1)
245
+ - `perPage?: number` - Items per page
246
+
247
+ **Returns:** `Promise<AxiosResponse<PaginatedReverbResponse<{ orders: Order[] }>>>`
248
+
249
+ **Example:**
250
+ ```typescript
251
+ const response = await reverb.getMyOrders({
252
+ page: 1,
253
+ perPage: 25
254
+ });
255
+
256
+ const { orders } = response.data;
257
+ orders.forEach(order => {
258
+ console.log(`Order ${order.order_number}: ${order.status}`);
259
+ });
260
+ ```
261
+
262
+ ---
263
+
264
+ ### getArbitraryEndpoint(options)
265
+
266
+ Make requests to any Reverb API endpoint not explicitly covered by other methods.
267
+
268
+ **Parameters:**
269
+ - `url: string` - Endpoint URL (absolute or relative to root endpoint)
270
+ - `params?: object` - Query parameters
271
+
272
+ **Returns:** `Promise<AxiosResponse<unknown>>`
273
+
274
+ **Example:**
275
+ ```typescript
276
+ // Fetch categories
277
+ const categories = await reverb.getArbitraryEndpoint({
278
+ url: '/categories/flat'
279
+ });
280
+
281
+ // Fetch listing conditions
282
+ const conditions = await reverb.getArbitraryEndpoint({
283
+ url: '/listing_conditions'
284
+ });
285
+
286
+ console.log(categories.data);
287
+ ```
288
+
289
+ ## TypeScript Usage
290
+
291
+ Sound Tank is written in TypeScript and provides comprehensive type definitions for the entire Reverb API.
292
+
293
+ ### Importing Types
294
+
295
+ ```typescript
296
+ import Reverb, {
297
+ Listing,
298
+ Order,
299
+ Price,
300
+ ListingStates,
301
+ ListingCondition,
302
+ ShippingRate,
303
+ Category,
304
+ ReverbOptions
305
+ } from 'sound-tank';
306
+ ```
307
+
308
+ ### Working with Typed Responses
309
+
310
+ ```typescript
311
+ const response = await reverb.getMyListings();
312
+ const listings: Listing[] = response.data.listings;
313
+
314
+ listings.forEach((listing: Listing) => {
315
+ const price: Price = listing.price;
316
+ const condition: ListingCondition = listing.condition;
317
+
318
+ console.log(`${listing.title}`);
319
+ console.log(` Price: ${price.display} (${price.currency})`);
320
+ console.log(` Condition: ${condition.displayName}`);
321
+ console.log(` Year: ${listing.year}`);
322
+ });
323
+ ```
324
+
325
+ ### Available Types
326
+
327
+ The SDK exports comprehensive TypeScript types including:
328
+
329
+ **Listing Types:**
330
+ - `Listing` - Complete listing data with make, model, price, condition, shipping, etc.
331
+ - `ListingState` - Listing status information
332
+ - `ListingStates` - Enum for state values (LIVE, SOLD, DRAFT)
333
+ - `ListingCondition` - Item condition with UUID and display name
334
+ - `ListingShipping` - Shipping information and rates
335
+ - `ListingStats` - View and watch counts
21
336
 
22
- (async () => {
23
- const reverb = new Reverb({ apiKey: REVERB_API_KEY });
337
+ **Order Types:**
338
+ - `Order` - Complete order information with buyer, seller, shipping, pricing details
339
+ - `OrderStatus` - Order status information
340
+ - `ShippingAddress` - Complete address information
24
341
 
25
- const response = await reverb.getMyListings({
26
- perPage: 10,
27
- page: 1,
28
- state: 'all',
29
- });
342
+ **Pricing Types:**
343
+ - `Price` - Currency-aware price with amount, currency, symbol, and formatted display
344
+ - `ShippingRate` - Regional shipping costs
30
345
 
31
- const { listings } = response.data;
346
+ **Other Types:**
347
+ - `Category` - Product categorization
348
+ - `Link` - HATEOAS navigation links
349
+ - `ReverbOptions` - SDK configuration options
350
+
351
+ ## Advanced Features
352
+
353
+ ### Automatic Pagination
354
+
355
+ The `getAllMyListings` method demonstrates automatic pagination, fetching all results across multiple API pages:
356
+
357
+ ```typescript
358
+ // Manually paginate
359
+ let page = 1;
360
+ let allListings = [];
361
+ let response;
362
+
363
+ do {
364
+ response = await reverb.getMyListings({ page, perPage: 50 });
365
+ allListings = allListings.concat(response.data.listings);
366
+ page++;
367
+ } while (response.data.listings.length === 50);
368
+
369
+ // Or use the built-in helper
370
+ const autoResponse = await reverb.getAllMyListings();
371
+ const listings = autoResponse.data; // Same result, simpler code
372
+ ```
373
+
374
+ ### HTTP Client Abstraction
375
+
376
+ Sound Tank uses an HTTP client abstraction for testability:
377
+
378
+ ```typescript
379
+ import { MockHttpClient } from 'sound-tank/http';
380
+
381
+ // Use mock client for testing
382
+ const mockClient = new MockHttpClient();
383
+ // Your tests here
384
+ ```
385
+
386
+ ### Configuration Access
387
+
388
+ Access the internal configuration and headers:
389
+
390
+ ```typescript
391
+ const config = reverb.config;
392
+ console.log(config.rootEndpoint); // 'https://api.reverb.com/api'
393
+ console.log(config.displayCurrency); // 'USD'
394
+ console.log(config.locale); // 'en'
395
+
396
+ const headers = reverb.headers;
397
+ console.log(headers['Authorization']); // 'Bearer your_api_key'
398
+ console.log(headers['X-Display-Currency']); // 'USD'
399
+ ```
400
+
401
+ ## Examples
402
+
403
+ ### Find All Guitars Under $1000
404
+
405
+ ```typescript
406
+ const reverb = new Reverb({ apiKey: process.env.REVERB_API_KEY });
407
+
408
+ const response = await reverb.getAllMyListings({ query: 'guitar' });
409
+ const affordable = response.data.filter(listing =>
410
+ listing.price.amount_cents < 100000 // $1000 = 100,000 cents
411
+ );
412
+
413
+ console.log(`Found ${affordable.length} guitars under $1000`);
414
+ affordable.forEach(listing => {
415
+ console.log(` ${listing.title}: ${listing.price.display}`);
416
+ });
417
+ ```
418
+
419
+ ### Multi-Currency Price Display
420
+
421
+ ```typescript
422
+ const reverb = new Reverb({ apiKey: process.env.REVERB_API_KEY });
423
+
424
+ // Get prices in USD
425
+ reverb.displayCurrency = 'USD';
426
+ const usdResponse = await reverb.getMyListings({ perPage: 5 });
427
+ console.log('USD Prices:');
428
+ usdResponse.data.listings.forEach(l =>
429
+ console.log(` ${l.title}: ${l.price.display}`)
430
+ );
431
+
432
+ // Switch to EUR
433
+ reverb.displayCurrency = 'EUR';
434
+ const eurResponse = await reverb.getMyListings({ perPage: 5 });
435
+ console.log('\nEUR Prices:');
436
+ eurResponse.data.listings.forEach(l =>
437
+ console.log(` ${l.title}: ${l.price.display}`)
438
+ );
439
+ ```
440
+
441
+ ### Export Listings to CSV
442
+
443
+ ```typescript
444
+ const response = await reverb.getAllMyListings({ state: 'live' });
445
+
446
+ const csvHeader = 'ID,Title,Price,Currency,Condition,Year,State\n';
447
+ const csvRows = response.data.map(listing =>
448
+ `${listing.id},"${listing.title}",${listing.price.amount},${listing.price.currency},${listing.condition.displayName},${listing.year},${listing.state.slug}`
449
+ ).join('\n');
450
+
451
+ const csv = csvHeader + csvRows;
452
+ console.log(csv);
453
+ // Save to file or send via API
454
+ ```
455
+
456
+ ### Search and Filter
457
+
458
+ ```typescript
459
+ // Search for specific items
460
+ const response = await reverb.getMyListings({
461
+ query: 'Les Paul',
462
+ state: 'live',
463
+ perPage: 100
464
+ });
465
+
466
+ // Filter by condition
467
+ const excellent = response.data.listings.filter(
468
+ listing => listing.condition.displayName === 'Excellent'
469
+ );
470
+
471
+ // Filter by year
472
+ const vintage = response.data.listings.filter(
473
+ listing => parseInt(listing.year) < 1980
474
+ );
475
+
476
+ console.log(`Found ${excellent.length} in excellent condition`);
477
+ console.log(`Found ${vintage.length} vintage items`);
478
+ ```
479
+
480
+ ## Development
481
+
482
+ ### Prerequisites
483
+
484
+ - **Node.js** 18 or higher
485
+ - **Yarn** package manager
486
+
487
+ ### Setup
488
+
489
+ ```bash
490
+ # Clone the repository
491
+ git clone https://github.com/ZacharyEggert/sound-tank.git
492
+ cd sound-tank
493
+
494
+ # Install dependencies
495
+ yarn install
496
+
497
+ # Copy environment template
498
+ cp .env.example .env
499
+ # Edit .env and add your REVERB_API_KEY
500
+ ```
501
+
502
+ ### Project Structure
32
503
 
33
- listings.forEach((listing) => {
34
- console.log(listing.title);
35
- });
36
- })();
37
504
  ```
505
+ sound-tank/
506
+ โ”œโ”€โ”€ src/
507
+ โ”‚ โ”œโ”€โ”€ Reverb.ts # Main SDK class
508
+ โ”‚ โ”œโ”€โ”€ index.ts # Entry point
509
+ โ”‚ โ”œโ”€โ”€ types.ts # TypeScript type definitions
510
+ โ”‚ โ”œโ”€โ”€ config/
511
+ โ”‚ โ”‚ โ””โ”€โ”€ ReverbConfig.ts # Configuration management
512
+ โ”‚ โ”œโ”€โ”€ http/
513
+ โ”‚ โ”‚ โ”œโ”€โ”€ HttpClient.ts # HTTP client interface
514
+ โ”‚ โ”‚ โ”œโ”€โ”€ AxiosHttpClient.ts # Axios implementation
515
+ โ”‚ โ”‚ โ””โ”€โ”€ MockHttpClient.ts # Mock for testing
516
+ โ”‚ โ”œโ”€โ”€ methods/
517
+ โ”‚ โ”‚ โ”œโ”€โ”€ listings/ # Listing operations
518
+ โ”‚ โ”‚ โ””โ”€โ”€ orders/ # Order operations
519
+ โ”‚ โ””โ”€โ”€ utils/ # Helper utilities
520
+ โ”œโ”€โ”€ tests/ # Test files
521
+ โ”œโ”€โ”€ dist/ # Build output (git-ignored)
522
+ โ”œโ”€โ”€ package.json
523
+ โ”œโ”€โ”€ tsconfig.json # TypeScript configuration
524
+ โ”œโ”€โ”€ tsup.config.ts # Build configuration
525
+ โ””โ”€โ”€ vite.config.mts # Test configuration
526
+ ```
527
+
528
+ ### Available Scripts
529
+
530
+ | Command | Description |
531
+ |---------|-------------|
532
+ | `yarn dev` | Run tests in watch mode during development |
533
+ | `yarn test` | Run all tests once |
534
+ | `yarn build` | Build production bundles (CJS + ESM + declarations) |
535
+ | `yarn lint` | Type-check code with TypeScript compiler |
536
+ | `yarn ci` | Run full CI pipeline (install, lint, test, build) |
537
+ | `yarn release` | Build and publish to npm (uses changesets) |
538
+
539
+ ### Build System
540
+
541
+ Sound Tank uses [tsup](https://tsup.egoist.dev/) for building:
542
+
543
+ - **Dual Output**: CommonJS (`dist/index.js`) and ESM (`dist/index.mjs`)
544
+ - **Type Declarations**: Full TypeScript `.d.ts` files
545
+ - **Source Maps**: Included for debugging
546
+ - **Tree-shaking**: Optimized bundles
547
+ - **External Dependencies**: `axios` marked as external (not bundled)
548
+
549
+ Build outputs:
550
+ ```
551
+ dist/
552
+ โ”œโ”€โ”€ index.js # CommonJS
553
+ โ”œโ”€โ”€ index.mjs # ES Modules
554
+ โ”œโ”€โ”€ index.d.ts # TypeScript declarations
555
+ โ””โ”€โ”€ *.map # Source maps
556
+ ```
557
+
558
+ ## Testing
559
+
560
+ Sound Tank uses [Vitest](https://vitest.dev/) for testing with comprehensive coverage.
561
+
562
+ ### Run Tests
563
+
564
+ ```bash
565
+ # Run all tests once
566
+ yarn test
567
+
568
+ # Run tests in watch mode (for development)
569
+ yarn dev
570
+
571
+ # Run tests with coverage report
572
+ yarn test --coverage
573
+ ```
574
+
575
+ ### Test Structure
576
+
577
+ - **Unit Tests**: Test individual functions in isolation
578
+ - **Integration Tests**: Test real API interactions (require `REVERB_API_KEY` in `.env`)
579
+
580
+ ### Writing Tests
581
+
582
+ Integration tests require a valid API key:
583
+
584
+ ```typescript
585
+ import { config } from 'dotenv';
586
+ config(); // Load .env
587
+
588
+ const reverb = new Reverb({ apiKey: process.env.REVERB_API_KEY });
589
+
590
+ // Your tests here
591
+ ```
592
+
593
+ Tests are located in the `tests/` directory and mirror the `src/` structure.
594
+
595
+ ## Contributing
596
+
597
+ Contributions are welcome! Here's how to get started:
598
+
599
+ ### Process
600
+
601
+ 1. **Fork** the repository on GitHub
602
+ 2. **Clone** your fork locally
603
+ 3. **Create** a feature branch: `git checkout -b feature/amazing-feature`
604
+ 4. **Make** your changes with clear, focused commits
605
+ 5. **Test** thoroughly: `yarn test`
606
+ 6. **Lint** your code: `yarn lint`
607
+ 7. **Commit** with descriptive messages
608
+ 8. **Push** to your fork: `git push origin feature/amazing-feature`
609
+ 9. **Open** a Pull Request
610
+
611
+ ### Guidelines
612
+
613
+ - Write **TypeScript** with strict types
614
+ - Add **tests** for new features
615
+ - Update **documentation** as needed
616
+ - Follow **existing code style** (Prettier configured)
617
+ - Ensure all **tests pass** (`yarn test`)
618
+ - Keep commits **atomic** and well-described
619
+ - Run **full CI** locally before pushing: `yarn ci`
620
+
621
+ ### Code Style
622
+
623
+ This project uses:
624
+ - **TypeScript** strict mode
625
+ - **Prettier** for formatting (run automatically)
626
+ - **ESLint** for linting
627
+ - 2-space indentation
628
+ - Single quotes for strings
629
+ - Trailing commas
630
+
631
+ ### Changesets
632
+
633
+ This project uses [Changesets](https://github.com/changesets/changesets) for version management:
634
+
635
+ ```bash
636
+ # After making changes, create a changeset
637
+ npx changeset
638
+
639
+ # Follow prompts to describe your changes
640
+ # Commit the generated changeset file
641
+ ```
642
+
643
+ ### Release Process
644
+
645
+ Releases are automated via GitHub Actions:
646
+
647
+ 1. Create and commit a changeset for your changes
648
+ 2. Push to `main` branch (after PR approval)
649
+ 3. Changesets GitHub Action creates a "Version Packages" PR
650
+ 4. Review and merge the Version Packages PR
651
+ 5. Package automatically publishes to npm with provenance
652
+
653
+ The project uses **OIDC trusted publishing** for npm, so no `NPM_TOKEN` is needed.
654
+
655
+ ## Links & Resources
656
+
657
+ - **npm Package**: [sound-tank on npm](https://www.npmjs.com/package/sound-tank)
658
+ - **GitHub Repository**: [ZacharyEggert/sound-tank](https://github.com/ZacharyEggert/sound-tank)
659
+ - **Report Issues**: [GitHub Issues](https://github.com/ZacharyEggert/sound-tank/issues)
660
+ - **Reverb API Docs**: [reverb.com/page/api](https://reverb.com/page/api)
661
+ - **Reverb Marketplace**: [reverb.com](https://reverb.com)
662
+
663
+ ## License
664
+
665
+ MIT ยฉ [Zachary Eggert](https://github.com/ZacharyEggert)
666
+
667
+ See [LICENSE](./LICENSE) for details.
668
+
669
+ ---
670
+
671
+ <p align="center">
672
+ Made with โ™ฅ by <a href="https://github.com/ZacharyEggert">Zachary Eggert</a>
673
+ </p>
674
+
675
+ <p align="center">
676
+ <a href="https://github.com/ZacharyEggert/sound-tank/issues">Report Bug</a>
677
+ ยท
678
+ <a href="https://github.com/ZacharyEggert/sound-tank/issues">Request Feature</a>
679
+ ยท
680
+ <a href="https://reverb.com">Reverb.com</a>
681
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sound-tank",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "A library for interacting with the Reverb Marketplace API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",