@spooled/sdk 1.0.31 → 1.0.32

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/README.md CHANGED
@@ -157,7 +157,7 @@ Run jobs on a cron schedule:
157
157
  ```typescript
158
158
  const schedule = await client.schedules.create({
159
159
  name: 'Daily Report',
160
- cronExpression: '0 0 9 * * *', // 6-field cron
160
+ cronExpression: '0 9 * * *', // 9 AM daily; 5-field (min hour dom mon dow) or 6-field (leading seconds) both work
161
161
  timezone: 'America/New_York',
162
162
  queueName: 'reports',
163
163
  payloadTemplate: { type: 'daily' },
@@ -320,22 +320,25 @@ All operations automatically enforce tier-based limits:
320
320
  - ✅ Queue creation
321
321
  - ✅ Webhook creation
322
322
 
323
- When limits are exceeded, you'll receive a `403 Forbidden` response with details:
323
+ When a plan quota or limit is exceeded, you'll receive an `HTTP 429` response with
324
+ `code: "QUOTA_EXCEEDED"` and a body describing the `resource`, `current`, `limit`, and `plan`:
324
325
 
325
326
  ```typescript
326
- import { AuthorizationError } from '@spooled/sdk';
327
+ import { RateLimitError } from '@spooled/sdk';
327
328
 
328
329
  try {
329
330
  await client.jobs.create({ /* ... */ });
330
331
  } catch (error) {
331
- if (error instanceof AuthorizationError) {
332
- // Plan limit reached (HTTP 403); the message describes the limit
332
+ if (error instanceof RateLimitError && error.code === 'QUOTA_EXCEEDED') {
333
+ // Plan quota reached (HTTP 429); details carry resource/current/limit/plan
333
334
  console.log(`Plan limit: ${error.message}`);
334
335
  console.log('Details:', error.details);
335
336
  }
336
337
  }
337
338
  ```
338
339
 
340
+ (Per-second rate limiting also returns `429`, as a `RateLimitError` with the default `RATE_LIMIT_EXCEEDED` code.)
341
+
339
342
  ## Error Handling
340
343
 
341
344
  All errors extend `SpooledError` with specific subclasses:
@@ -355,8 +358,9 @@ try {
355
358
  if (error instanceof NotFoundError) {
356
359
  console.log('Job not found');
357
360
  } else if (error instanceof AuthorizationError) {
358
- console.log(`Forbidden (e.g. plan limit): ${error.message}`);
361
+ console.log(`Forbidden: ${error.message}`);
359
362
  } else if (error instanceof RateLimitError) {
363
+ // 429: either a plan quota (code "QUOTA_EXCEEDED") or per-second rate limiting
360
364
  console.log(`Retry after ${error.getRetryAfter()} seconds`);
361
365
  } else if (isSpooledError(error)) {
362
366
  console.log(`API error: ${error.code} - ${error.message}`);
package/dist/index.cjs CHANGED
@@ -55,6 +55,13 @@ var DEFAULT_CONFIG = {
55
55
  var SDK_VERSION = "1.0.31";
56
56
  var API_VERSION = "v1";
57
57
  var API_BASE_PATH = `/api/${API_VERSION}`;
58
+ function normalizeCredential(value) {
59
+ if (value === void 0) {
60
+ return void 0;
61
+ }
62
+ const trimmed = value.trim();
63
+ return trimmed === "" ? void 0 : trimmed;
64
+ }
58
65
  function resolveConfig(options) {
59
66
  let debugFn = null;
60
67
  if (options.debug === true) {
@@ -84,10 +91,10 @@ function resolveConfig(options) {
84
91
  const derivedWsUrl = baseUrl.replace(/^http/, "ws");
85
92
  const wsUrl = options.wsUrl ?? derivedWsUrl;
86
93
  return {
87
- apiKey: options.apiKey,
88
- accessToken: options.accessToken,
89
- refreshToken: options.refreshToken,
90
- adminKey: options.adminKey,
94
+ apiKey: normalizeCredential(options.apiKey),
95
+ accessToken: normalizeCredential(options.accessToken),
96
+ refreshToken: normalizeCredential(options.refreshToken),
97
+ adminKey: normalizeCredential(options.adminKey),
91
98
  baseUrl,
92
99
  wsUrl,
93
100
  grpcAddress: options.grpcAddress ?? DEFAULT_CONFIG.grpcAddress,