@rendobar/sdk 3.4.0 → 4.0.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/dist/index.cjs CHANGED
@@ -646,22 +646,6 @@ function createOrgsResource(request) {
646
646
  };
647
647
  }
648
648
  //#endregion
649
- //#region src/resources/batches.ts
650
- function createBatchesResource(request) {
651
- return {
652
- async create(params, options) {
653
- return request("/batches", {
654
- method: "POST",
655
- body: params,
656
- signal: options?.signal
657
- });
658
- },
659
- async get(id, options) {
660
- return request(`/batches/${id}`, { signal: options?.signal });
661
- }
662
- };
663
- }
664
- //#endregion
665
649
  //#region src/resources/assets.ts
666
650
  function createAssetsResource(request) {
667
651
  return {
@@ -879,7 +863,6 @@ function createClient(config = {}) {
879
863
  webhooks: createWebhooksResource(request),
880
864
  apiKeys: createApiKeysResource(request),
881
865
  orgs: createOrgsResource(request),
882
- batches: createBatchesResource(request),
883
866
  assets: createAssetsResource(request),
884
867
  team: createTeamResource(request),
885
868
  realtime: createRealtimeClient(baseUrl, {
package/dist/index.d.cts CHANGED
@@ -2245,7 +2245,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2245
2245
  type: ZodString;
2246
2246
  source: ZodString;
2247
2247
  client: ZodNullable<ZodString>;
2248
- batchId: ZodNullable<ZodString>;
2249
2248
  retryCount: ZodNumber;
2250
2249
  idempotencyKey: ZodNullable<ZodString>;
2251
2250
  mediaType: ZodNullable<ZodString>;
@@ -2282,6 +2281,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2282
2281
  startedAt: ZodNullable<ZodNumber>;
2283
2282
  completedAt: ZodNullable<ZodNumber>;
2284
2283
  settledAt: ZodNullable<ZodNumber>;
2284
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2285
2285
  status: ZodLiteral<"waiting">;
2286
2286
  }, $strip>, ZodObject<{
2287
2287
  id: ZodString;
@@ -2289,7 +2289,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2289
2289
  type: ZodString;
2290
2290
  source: ZodString;
2291
2291
  client: ZodNullable<ZodString>;
2292
- batchId: ZodNullable<ZodString>;
2293
2292
  retryCount: ZodNumber;
2294
2293
  idempotencyKey: ZodNullable<ZodString>;
2295
2294
  mediaType: ZodNullable<ZodString>;
@@ -2326,6 +2325,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2326
2325
  startedAt: ZodNullable<ZodNumber>;
2327
2326
  completedAt: ZodNullable<ZodNumber>;
2328
2327
  settledAt: ZodNullable<ZodNumber>;
2328
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2329
2329
  status: ZodLiteral<"dispatched">;
2330
2330
  progress: ZodOptional<ZodNumber>;
2331
2331
  eta: ZodOptional<ZodNullable<ZodNumber>>;
@@ -2335,7 +2335,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2335
2335
  type: ZodString;
2336
2336
  source: ZodString;
2337
2337
  client: ZodNullable<ZodString>;
2338
- batchId: ZodNullable<ZodString>;
2339
2338
  retryCount: ZodNumber;
2340
2339
  idempotencyKey: ZodNullable<ZodString>;
2341
2340
  mediaType: ZodNullable<ZodString>;
@@ -2372,6 +2371,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2372
2371
  startedAt: ZodNullable<ZodNumber>;
2373
2372
  completedAt: ZodNullable<ZodNumber>;
2374
2373
  settledAt: ZodNullable<ZodNumber>;
2374
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2375
2375
  status: ZodLiteral<"running">;
2376
2376
  progress: ZodNumber;
2377
2377
  eta: ZodNullable<ZodNumber>;
@@ -2381,7 +2381,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2381
2381
  type: ZodString;
2382
2382
  source: ZodString;
2383
2383
  client: ZodNullable<ZodString>;
2384
- batchId: ZodNullable<ZodString>;
2385
2384
  retryCount: ZodNumber;
2386
2385
  idempotencyKey: ZodNullable<ZodString>;
2387
2386
  mediaType: ZodNullable<ZodString>;
@@ -2418,6 +2417,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2418
2417
  startedAt: ZodNullable<ZodNumber>;
2419
2418
  completedAt: ZodNullable<ZodNumber>;
2420
2419
  settledAt: ZodNullable<ZodNumber>;
2420
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2421
2421
  status: ZodLiteral<"complete">;
2422
2422
  output: ZodObject<{
2423
2423
  data: ZodUnknown;
@@ -2469,7 +2469,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2469
2469
  type: ZodString;
2470
2470
  source: ZodString;
2471
2471
  client: ZodNullable<ZodString>;
2472
- batchId: ZodNullable<ZodString>;
2473
2472
  retryCount: ZodNumber;
2474
2473
  idempotencyKey: ZodNullable<ZodString>;
2475
2474
  mediaType: ZodNullable<ZodString>;
@@ -2506,6 +2505,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2506
2505
  startedAt: ZodNullable<ZodNumber>;
2507
2506
  completedAt: ZodNullable<ZodNumber>;
2508
2507
  settledAt: ZodNullable<ZodNumber>;
2508
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2509
2509
  status: ZodLiteral<"failed">;
2510
2510
  error: ZodObject<{
2511
2511
  code: ZodString;
@@ -2519,7 +2519,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2519
2519
  type: ZodString;
2520
2520
  source: ZodString;
2521
2521
  client: ZodNullable<ZodString>;
2522
- batchId: ZodNullable<ZodString>;
2523
2522
  retryCount: ZodNumber;
2524
2523
  idempotencyKey: ZodNullable<ZodString>;
2525
2524
  mediaType: ZodNullable<ZodString>;
@@ -2556,6 +2555,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2556
2555
  startedAt: ZodNullable<ZodNumber>;
2557
2556
  completedAt: ZodNullable<ZodNumber>;
2558
2557
  settledAt: ZodNullable<ZodNumber>;
2558
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2559
2559
  status: ZodLiteral<"cancelled">;
2560
2560
  }, $strip>], "status">;
2561
2561
  declare const jobCreatedResponseSchema: ZodObject<{
@@ -2594,14 +2594,7 @@ declare const jobTypeSchema: ZodObject<{
2594
2594
  type: ZodString;
2595
2595
  tag: ZodString;
2596
2596
  summary: ZodString;
2597
- needs: ZodArray<ZodString>;
2598
- pattern: ZodNullable<ZodString>;
2599
- runner: ZodOptional<ZodObject<{
2600
- id: ZodString;
2601
- resource: ZodString;
2602
- }, $strip>>;
2603
2597
  acceptsMedia: ZodArray<ZodString>;
2604
- mediaOverrides: ZodOptional<ZodRecord<ZodString, ZodUnknown>>;
2605
2598
  }, $strip>;
2606
2599
  declare const billingStateSchema: ZodObject<{
2607
2600
  balance: ZodObject<{
@@ -2616,7 +2609,6 @@ declare const billingStateSchema: ZodObject<{
2616
2609
  apiRequestsPerMinute: ZodNumber;
2617
2610
  maxJobTimeout: ZodNumber;
2618
2611
  maxInputFileSize: ZodNumber;
2619
- maxBatchSize: ZodNumber;
2620
2612
  }, $strip>;
2621
2613
  }, $strip>;
2622
2614
  subscription: ZodNullable<ZodObject<{
@@ -2640,7 +2632,6 @@ declare const billingStateSchema: ZodObject<{
2640
2632
  apiRequestsPerMinute: ZodNumber;
2641
2633
  maxJobTimeout: ZodNumber;
2642
2634
  maxInputFileSize: ZodNumber;
2643
- maxBatchSize: ZodNumber;
2644
2635
  }, $strip>;
2645
2636
  }, $strip>>;
2646
2637
  }, $strip>;
@@ -2698,11 +2689,15 @@ declare const webhookDeliverySchema: ZodObject<{
2698
2689
  id: ZodString;
2699
2690
  endpointId: ZodString;
2700
2691
  endpointName: ZodNullable<ZodString>;
2701
- jobId: ZodString;
2702
- batchId: ZodNullable<ZodString>;
2692
+ jobId: ZodNullable<ZodString>;
2703
2693
  event: ZodString;
2704
2694
  payload: ZodString;
2705
- status: ZodString;
2695
+ status: ZodEnum<{
2696
+ failed: "failed";
2697
+ cancelled: "cancelled";
2698
+ pending: "pending";
2699
+ delivered: "delivered";
2700
+ }>;
2706
2701
  statusCode: ZodNullable<ZodNumber>;
2707
2702
  responseBody: ZodNullable<ZodString>;
2708
2703
  attempts: ZodNumber;
@@ -3025,6 +3020,130 @@ interface LogEntryData {
3025
3020
  meta?: Record<string, unknown>;
3026
3021
  }
3027
3022
  //#endregion
3023
+ //#region ../shared/src/constants/webhook-events.d.ts
3024
+ declare const WEBHOOK_EVENT_TYPES: readonly ["job.created", "job.started", "job.completed", "job.failed", "job.cancelled", "balance.low", "balance.depleted"];
3025
+ type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
3026
+ //#endregion
3027
+ //#region ../shared/src/types/webhook.d.ts
3028
+ interface JobCreatedData {
3029
+ jobId: string;
3030
+ jobType: string;
3031
+ status: "waiting";
3032
+ timing: {
3033
+ createdAt: number;
3034
+ };
3035
+ }
3036
+ interface JobStartedData {
3037
+ jobId: string;
3038
+ jobType: string;
3039
+ status: "running";
3040
+ timing: {
3041
+ createdAt: number;
3042
+ dispatchedAt?: number;
3043
+ startedAt: number;
3044
+ };
3045
+ }
3046
+ interface JobCompletedData {
3047
+ jobId: string;
3048
+ jobType: string;
3049
+ status: "complete";
3050
+ output: Output;
3051
+ cost?: {
3052
+ amount: number;
3053
+ currency: "USD";
3054
+ formatted: string;
3055
+ breakdown: string;
3056
+ };
3057
+ timing: {
3058
+ createdAt: number;
3059
+ dispatchedAt?: number;
3060
+ startedAt?: number;
3061
+ completedAt: number;
3062
+ };
3063
+ steps?: Array<{
3064
+ id: string;
3065
+ name: string;
3066
+ status: string;
3067
+ durationMs?: number;
3068
+ error?: string;
3069
+ }>;
3070
+ outputCategory?: string;
3071
+ mediaType?: string;
3072
+ }
3073
+ interface JobFailedData {
3074
+ jobId: string;
3075
+ jobType: string;
3076
+ status: "failed";
3077
+ error: JobError;
3078
+ timing: {
3079
+ createdAt: number;
3080
+ dispatchedAt?: number;
3081
+ startedAt?: number;
3082
+ failedAt: number;
3083
+ };
3084
+ steps?: Array<{
3085
+ id: string;
3086
+ name: string;
3087
+ status: string;
3088
+ durationMs?: number;
3089
+ error?: string;
3090
+ }>;
3091
+ }
3092
+ interface JobCancelledData {
3093
+ jobId: string;
3094
+ jobType: string;
3095
+ status: "cancelled";
3096
+ timing: {
3097
+ createdAt: number;
3098
+ cancelledAt: number;
3099
+ };
3100
+ }
3101
+ interface BalanceLowData {
3102
+ balance: number;
3103
+ balanceFormatted: string;
3104
+ threshold: number;
3105
+ thresholdFormatted: string;
3106
+ triggeredByJobId: string;
3107
+ triggeredByJobType: string;
3108
+ }
3109
+ interface BalanceDepletedData {
3110
+ balance: number;
3111
+ balanceFormatted: string;
3112
+ triggeredByJobId: string;
3113
+ triggeredByJobType: string;
3114
+ }
3115
+ interface TestEventData {
3116
+ message: string;
3117
+ endpointId: string;
3118
+ }
3119
+ /**
3120
+ * Maps each event to its `data` shape. The `WebhookPayload` mapped type below
3121
+ * fails to compile if WEBHOOK_EVENT_TYPES gains an event that is missing here,
3122
+ * so this map is the enforced single source of truth for payload shapes.
3123
+ */
3124
+ interface WebhookEventDataMap {
3125
+ "job.created": JobCreatedData;
3126
+ "job.started": JobStartedData;
3127
+ "job.completed": JobCompletedData;
3128
+ "job.failed": JobFailedData;
3129
+ "job.cancelled": JobCancelledData;
3130
+ "balance.low": BalanceLowData;
3131
+ "balance.depleted": BalanceDepletedData;
3132
+ }
3133
+ interface Envelope<E extends string, D> {
3134
+ version: "1";
3135
+ event: E;
3136
+ deliveryId: string;
3137
+ timestamp: number;
3138
+ orgId: string;
3139
+ data: D;
3140
+ }
3141
+ /**
3142
+ * The exact JSON body Rendobar POSTs to your endpoint, discriminated by `event`.
3143
+ * Switch on `payload.event` and `payload.data` narrows to the matching shape.
3144
+ */
3145
+ type WebhookPayload = { [E in WebhookEventType]: Envelope<E, WebhookEventDataMap[E]> }[WebhookEventType] | Envelope<"test", TestEventData>;
3146
+ //#endregion
3028
3147
  //#region src/types.d.ts
3029
3148
  /**
3030
3149
  * Primary playable/download URL for a completed job, or `undefined`.
@@ -3209,7 +3328,7 @@ declare function createClient(config?: ClientConfig): {
3209
3328
  signal?: AbortSignal;
3210
3329
  }): Promise<WebhookEndpoint>;
3211
3330
  update(id: string, params: UpdateWebhookParams, options?: {
3212
- signal /** Default org ID (sent as X-Org-Id header). */? /** Default org ID (sent as X-Org-Id header). */: AbortSignal;
3331
+ signal?: AbortSignal;
3213
3332
  }): Promise<WebhookEndpoint>;
3214
3333
  delete(id: string, options?: {
3215
3334
  signal?: AbortSignal;
@@ -3232,7 +3351,7 @@ declare function createClient(config?: ClientConfig): {
3232
3351
  }>;
3233
3352
  retryDelivery(id: string, options?: {
3234
3353
  signal?: AbortSignal;
3235
- }): Promise<WebhookDelivery>;
3354
+ }): Promise<RetryDeliveryResult>;
3236
3355
  };
3237
3356
  apiKeys: {
3238
3357
  create(params: {
@@ -3282,28 +3401,12 @@ declare function createClient(config?: ClientConfig): {
3282
3401
  signal?: AbortSignal;
3283
3402
  }): Promise<void>;
3284
3403
  getSettings(options?: {
3285
- signal?: AbortSignal;
3404
+ signal? /** Custom fetch function for testing or special runtimes. */: AbortSignal;
3286
3405
  }): Promise<OrgSettings>;
3287
3406
  updateSettings(body: Partial<Pick<OrgSettings, "billingEmailsEnabled" | "defaultRegion" | "regionPinned">>, options?: {
3288
3407
  signal?: AbortSignal;
3289
3408
  }): Promise<OrgSettings>;
3290
3409
  };
3291
- batches: {
3292
- create(params: {
3293
- jobs: CreateJobParams[];
3294
- }, options?: {
3295
- signal?: AbortSignal;
3296
- }): Promise<BatchResult>;
3297
- get(id: string, options?: {
3298
- signal?: AbortSignal;
3299
- }): Promise<{
3300
- id: string;
3301
- orgId: string;
3302
- jobCount: number;
3303
- completedCount: number;
3304
- createdAt: number;
3305
- }>;
3306
- };
3307
3410
  assets: {
3308
3411
  list(params?: ListAssetsParams, options?: {
3309
3412
  signal?: AbortSignal;
@@ -3509,22 +3612,29 @@ type TransactionListParams = {
3509
3612
  type CreateWebhookParams = {
3510
3613
  name: string;
3511
3614
  url: string;
3512
- subscribedEvents: string[];
3615
+ subscribedEvents: WebhookEventType[];
3513
3616
  };
3514
3617
  type UpdateWebhookParams = {
3515
3618
  name?: string;
3516
3619
  url?: string;
3517
- subscribedEvents?: string[];
3620
+ subscribedEvents?: WebhookEventType[];
3518
3621
  active?: boolean;
3519
3622
  };
3520
3623
  type ListDeliveriesParams = {
3521
3624
  endpointId?: string;
3522
- event?: string;
3625
+ event?: WebhookEventType;
3523
3626
  status?: string;
3524
3627
  jobId?: string;
3525
3628
  limit?: number;
3526
3629
  offset?: number;
3527
3630
  };
3631
+ /** The retry route echoes only these fields — not a full delivery record. */
3632
+ type RetryDeliveryResult = {
3633
+ id: string;
3634
+ status: string;
3635
+ event: string;
3636
+ endpointId: string;
3637
+ };
3528
3638
  //#endregion
3529
3639
  //#region src/resources/orgs.d.ts
3530
3640
  type OrgCurrentResponse = {
@@ -3551,14 +3661,6 @@ type OrgCurrentResponse = {
3551
3661
  };
3552
3662
  };
3553
3663
  //#endregion
3554
- //#region src/resources/batches.d.ts
3555
- type BatchResult = {
3556
- batchId: string;
3557
- jobCount: number;
3558
- jobIds: string[];
3559
- status: string;
3560
- };
3561
- //#endregion
3562
3664
  //#region src/resources/uploads.d.ts
3563
3665
  type UploadProgress = {
3564
3666
  loaded: number;
@@ -3588,4 +3690,4 @@ type AssetListPage = {
3588
3690
  meta: AssetListMeta;
3589
3691
  };
3590
3692
  //#endregion
3591
- export { ApiError, type ApiKey, type AssetResponse as Asset, type AssetDownloadResponse, type AssetInitResponse, type AssetListMeta, type AssetListPage, type BatchResult, type BillingInvoice, type BillingState, type ClientConfig, type Cost, type CreateJobParams, type CreateUploadOptions, type CreateWebhookParams, type FfmpegParams, type FileType, type JobResponse as Job, type JobCreatedResponse, type JobError, JobFailedError, type JobListPage, type JobStats, type JobStep, type JobSubscribeOptions, type JobSubscription, type JobTimings, type JobType, type ListAssetsParams, type ListDeliveriesParams, type ListJobsParams, type LogEntryData, type OrgCurrentResponse, type OrgEvent, type OrgSettings, type Organization, type Output, type OutputFile, type PaginationMeta, type PaymentMethod, type RealtimeConnectOptions, type RealtimeConnection, type RendobarClient, type StatsParams, type Transaction, type TransactionListParams, type UpdateWebhookParams, type UploadProgress, type UsageParams, type UsageSummary, type WaitOptions, WaitTimeoutError, type WebhookDelivery, type WebhookEndpoint, createClient, isApiError, jobData, outputUrl };
3693
+ export { ApiError, type ApiKey, type AssetResponse as Asset, type AssetDownloadResponse, type AssetInitResponse, type AssetListMeta, type AssetListPage, type BalanceDepletedData, type BalanceLowData, type BillingInvoice, type BillingState, type ClientConfig, type Cost, type CreateJobParams, type CreateUploadOptions, type CreateWebhookParams, type FfmpegParams, type FileType, type JobResponse as Job, type JobCancelledData, type JobCompletedData, type JobCreatedData, type JobCreatedResponse, type JobError, type JobFailedData, JobFailedError, type JobListPage, type JobStartedData, type JobStats, type JobStep, type JobSubscribeOptions, type JobSubscription, type JobTimings, type JobType, type ListAssetsParams, type ListDeliveriesParams, type ListJobsParams, type LogEntryData, type OrgCurrentResponse, type OrgEvent, type OrgSettings, type Organization, type Output, type OutputFile, type PaginationMeta, type PaymentMethod, type RealtimeConnectOptions, type RealtimeConnection, type RendobarClient, type RetryDeliveryResult, type StatsParams, type TestEventData, type Transaction, type TransactionListParams, type UpdateWebhookParams, type UploadProgress, type UsageParams, type UsageSummary, type WaitOptions, WaitTimeoutError, type WebhookDelivery, type WebhookEndpoint, type WebhookEventDataMap, type WebhookPayload, createClient, isApiError, jobData, outputUrl };
package/dist/index.d.mts CHANGED
@@ -2245,7 +2245,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2245
2245
  type: ZodString;
2246
2246
  source: ZodString;
2247
2247
  client: ZodNullable<ZodString>;
2248
- batchId: ZodNullable<ZodString>;
2249
2248
  retryCount: ZodNumber;
2250
2249
  idempotencyKey: ZodNullable<ZodString>;
2251
2250
  mediaType: ZodNullable<ZodString>;
@@ -2282,6 +2281,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2282
2281
  startedAt: ZodNullable<ZodNumber>;
2283
2282
  completedAt: ZodNullable<ZodNumber>;
2284
2283
  settledAt: ZodNullable<ZodNumber>;
2284
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2285
2285
  status: ZodLiteral<"waiting">;
2286
2286
  }, $strip>, ZodObject<{
2287
2287
  id: ZodString;
@@ -2289,7 +2289,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2289
2289
  type: ZodString;
2290
2290
  source: ZodString;
2291
2291
  client: ZodNullable<ZodString>;
2292
- batchId: ZodNullable<ZodString>;
2293
2292
  retryCount: ZodNumber;
2294
2293
  idempotencyKey: ZodNullable<ZodString>;
2295
2294
  mediaType: ZodNullable<ZodString>;
@@ -2326,6 +2325,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2326
2325
  startedAt: ZodNullable<ZodNumber>;
2327
2326
  completedAt: ZodNullable<ZodNumber>;
2328
2327
  settledAt: ZodNullable<ZodNumber>;
2328
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2329
2329
  status: ZodLiteral<"dispatched">;
2330
2330
  progress: ZodOptional<ZodNumber>;
2331
2331
  eta: ZodOptional<ZodNullable<ZodNumber>>;
@@ -2335,7 +2335,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2335
2335
  type: ZodString;
2336
2336
  source: ZodString;
2337
2337
  client: ZodNullable<ZodString>;
2338
- batchId: ZodNullable<ZodString>;
2339
2338
  retryCount: ZodNumber;
2340
2339
  idempotencyKey: ZodNullable<ZodString>;
2341
2340
  mediaType: ZodNullable<ZodString>;
@@ -2372,6 +2371,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2372
2371
  startedAt: ZodNullable<ZodNumber>;
2373
2372
  completedAt: ZodNullable<ZodNumber>;
2374
2373
  settledAt: ZodNullable<ZodNumber>;
2374
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2375
2375
  status: ZodLiteral<"running">;
2376
2376
  progress: ZodNumber;
2377
2377
  eta: ZodNullable<ZodNumber>;
@@ -2381,7 +2381,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2381
2381
  type: ZodString;
2382
2382
  source: ZodString;
2383
2383
  client: ZodNullable<ZodString>;
2384
- batchId: ZodNullable<ZodString>;
2385
2384
  retryCount: ZodNumber;
2386
2385
  idempotencyKey: ZodNullable<ZodString>;
2387
2386
  mediaType: ZodNullable<ZodString>;
@@ -2418,6 +2417,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2418
2417
  startedAt: ZodNullable<ZodNumber>;
2419
2418
  completedAt: ZodNullable<ZodNumber>;
2420
2419
  settledAt: ZodNullable<ZodNumber>;
2420
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2421
2421
  status: ZodLiteral<"complete">;
2422
2422
  output: ZodObject<{
2423
2423
  data: ZodUnknown;
@@ -2469,7 +2469,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2469
2469
  type: ZodString;
2470
2470
  source: ZodString;
2471
2471
  client: ZodNullable<ZodString>;
2472
- batchId: ZodNullable<ZodString>;
2473
2472
  retryCount: ZodNumber;
2474
2473
  idempotencyKey: ZodNullable<ZodString>;
2475
2474
  mediaType: ZodNullable<ZodString>;
@@ -2506,6 +2505,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2506
2505
  startedAt: ZodNullable<ZodNumber>;
2507
2506
  completedAt: ZodNullable<ZodNumber>;
2508
2507
  settledAt: ZodNullable<ZodNumber>;
2508
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2509
2509
  status: ZodLiteral<"failed">;
2510
2510
  error: ZodObject<{
2511
2511
  code: ZodString;
@@ -2519,7 +2519,6 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2519
2519
  type: ZodString;
2520
2520
  source: ZodString;
2521
2521
  client: ZodNullable<ZodString>;
2522
- batchId: ZodNullable<ZodString>;
2523
2522
  retryCount: ZodNumber;
2524
2523
  idempotencyKey: ZodNullable<ZodString>;
2525
2524
  mediaType: ZodNullable<ZodString>;
@@ -2556,6 +2555,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
2556
2555
  startedAt: ZodNullable<ZodNumber>;
2557
2556
  completedAt: ZodNullable<ZodNumber>;
2558
2557
  settledAt: ZodNullable<ZodNumber>;
2558
+ retentionExpiresAt: ZodNullable<ZodNumber>;
2559
2559
  status: ZodLiteral<"cancelled">;
2560
2560
  }, $strip>], "status">;
2561
2561
  declare const jobCreatedResponseSchema: ZodObject<{
@@ -2594,14 +2594,7 @@ declare const jobTypeSchema: ZodObject<{
2594
2594
  type: ZodString;
2595
2595
  tag: ZodString;
2596
2596
  summary: ZodString;
2597
- needs: ZodArray<ZodString>;
2598
- pattern: ZodNullable<ZodString>;
2599
- runner: ZodOptional<ZodObject<{
2600
- id: ZodString;
2601
- resource: ZodString;
2602
- }, $strip>>;
2603
2597
  acceptsMedia: ZodArray<ZodString>;
2604
- mediaOverrides: ZodOptional<ZodRecord<ZodString, ZodUnknown>>;
2605
2598
  }, $strip>;
2606
2599
  declare const billingStateSchema: ZodObject<{
2607
2600
  balance: ZodObject<{
@@ -2616,7 +2609,6 @@ declare const billingStateSchema: ZodObject<{
2616
2609
  apiRequestsPerMinute: ZodNumber;
2617
2610
  maxJobTimeout: ZodNumber;
2618
2611
  maxInputFileSize: ZodNumber;
2619
- maxBatchSize: ZodNumber;
2620
2612
  }, $strip>;
2621
2613
  }, $strip>;
2622
2614
  subscription: ZodNullable<ZodObject<{
@@ -2640,7 +2632,6 @@ declare const billingStateSchema: ZodObject<{
2640
2632
  apiRequestsPerMinute: ZodNumber;
2641
2633
  maxJobTimeout: ZodNumber;
2642
2634
  maxInputFileSize: ZodNumber;
2643
- maxBatchSize: ZodNumber;
2644
2635
  }, $strip>;
2645
2636
  }, $strip>>;
2646
2637
  }, $strip>;
@@ -2698,11 +2689,15 @@ declare const webhookDeliverySchema: ZodObject<{
2698
2689
  id: ZodString;
2699
2690
  endpointId: ZodString;
2700
2691
  endpointName: ZodNullable<ZodString>;
2701
- jobId: ZodString;
2702
- batchId: ZodNullable<ZodString>;
2692
+ jobId: ZodNullable<ZodString>;
2703
2693
  event: ZodString;
2704
2694
  payload: ZodString;
2705
- status: ZodString;
2695
+ status: ZodEnum<{
2696
+ failed: "failed";
2697
+ cancelled: "cancelled";
2698
+ pending: "pending";
2699
+ delivered: "delivered";
2700
+ }>;
2706
2701
  statusCode: ZodNullable<ZodNumber>;
2707
2702
  responseBody: ZodNullable<ZodString>;
2708
2703
  attempts: ZodNumber;
@@ -3025,6 +3020,130 @@ interface LogEntryData {
3025
3020
  meta?: Record<string, unknown>;
3026
3021
  }
3027
3022
  //#endregion
3023
+ //#region ../shared/src/constants/webhook-events.d.ts
3024
+ declare const WEBHOOK_EVENT_TYPES: readonly ["job.created", "job.started", "job.completed", "job.failed", "job.cancelled", "balance.low", "balance.depleted"];
3025
+ type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
3026
+ //#endregion
3027
+ //#region ../shared/src/types/webhook.d.ts
3028
+ interface JobCreatedData {
3029
+ jobId: string;
3030
+ jobType: string;
3031
+ status: "waiting";
3032
+ timing: {
3033
+ createdAt: number;
3034
+ };
3035
+ }
3036
+ interface JobStartedData {
3037
+ jobId: string;
3038
+ jobType: string;
3039
+ status: "running";
3040
+ timing: {
3041
+ createdAt: number;
3042
+ dispatchedAt?: number;
3043
+ startedAt: number;
3044
+ };
3045
+ }
3046
+ interface JobCompletedData {
3047
+ jobId: string;
3048
+ jobType: string;
3049
+ status: "complete";
3050
+ output: Output;
3051
+ cost?: {
3052
+ amount: number;
3053
+ currency: "USD";
3054
+ formatted: string;
3055
+ breakdown: string;
3056
+ };
3057
+ timing: {
3058
+ createdAt: number;
3059
+ dispatchedAt?: number;
3060
+ startedAt?: number;
3061
+ completedAt: number;
3062
+ };
3063
+ steps?: Array<{
3064
+ id: string;
3065
+ name: string;
3066
+ status: string;
3067
+ durationMs?: number;
3068
+ error?: string;
3069
+ }>;
3070
+ outputCategory?: string;
3071
+ mediaType?: string;
3072
+ }
3073
+ interface JobFailedData {
3074
+ jobId: string;
3075
+ jobType: string;
3076
+ status: "failed";
3077
+ error: JobError;
3078
+ timing: {
3079
+ createdAt: number;
3080
+ dispatchedAt?: number;
3081
+ startedAt?: number;
3082
+ failedAt: number;
3083
+ };
3084
+ steps?: Array<{
3085
+ id: string;
3086
+ name: string;
3087
+ status: string;
3088
+ durationMs?: number;
3089
+ error?: string;
3090
+ }>;
3091
+ }
3092
+ interface JobCancelledData {
3093
+ jobId: string;
3094
+ jobType: string;
3095
+ status: "cancelled";
3096
+ timing: {
3097
+ createdAt: number;
3098
+ cancelledAt: number;
3099
+ };
3100
+ }
3101
+ interface BalanceLowData {
3102
+ balance: number;
3103
+ balanceFormatted: string;
3104
+ threshold: number;
3105
+ thresholdFormatted: string;
3106
+ triggeredByJobId: string;
3107
+ triggeredByJobType: string;
3108
+ }
3109
+ interface BalanceDepletedData {
3110
+ balance: number;
3111
+ balanceFormatted: string;
3112
+ triggeredByJobId: string;
3113
+ triggeredByJobType: string;
3114
+ }
3115
+ interface TestEventData {
3116
+ message: string;
3117
+ endpointId: string;
3118
+ }
3119
+ /**
3120
+ * Maps each event to its `data` shape. The `WebhookPayload` mapped type below
3121
+ * fails to compile if WEBHOOK_EVENT_TYPES gains an event that is missing here,
3122
+ * so this map is the enforced single source of truth for payload shapes.
3123
+ */
3124
+ interface WebhookEventDataMap {
3125
+ "job.created": JobCreatedData;
3126
+ "job.started": JobStartedData;
3127
+ "job.completed": JobCompletedData;
3128
+ "job.failed": JobFailedData;
3129
+ "job.cancelled": JobCancelledData;
3130
+ "balance.low": BalanceLowData;
3131
+ "balance.depleted": BalanceDepletedData;
3132
+ }
3133
+ interface Envelope<E extends string, D> {
3134
+ version: "1";
3135
+ event: E;
3136
+ deliveryId: string;
3137
+ timestamp: number;
3138
+ orgId: string;
3139
+ data: D;
3140
+ }
3141
+ /**
3142
+ * The exact JSON body Rendobar POSTs to your endpoint, discriminated by `event`.
3143
+ * Switch on `payload.event` and `payload.data` narrows to the matching shape.
3144
+ */
3145
+ type WebhookPayload = { [E in WebhookEventType]: Envelope<E, WebhookEventDataMap[E]> }[WebhookEventType] | Envelope<"test", TestEventData>;
3146
+ //#endregion
3028
3147
  //#region src/types.d.ts
3029
3148
  /**
3030
3149
  * Primary playable/download URL for a completed job, or `undefined`.
@@ -3209,7 +3328,7 @@ declare function createClient(config?: ClientConfig): {
3209
3328
  signal?: AbortSignal;
3210
3329
  }): Promise<WebhookEndpoint>;
3211
3330
  update(id: string, params: UpdateWebhookParams, options?: {
3212
- signal /** Default org ID (sent as X-Org-Id header). */? /** Default org ID (sent as X-Org-Id header). */: AbortSignal;
3331
+ signal?: AbortSignal;
3213
3332
  }): Promise<WebhookEndpoint>;
3214
3333
  delete(id: string, options?: {
3215
3334
  signal?: AbortSignal;
@@ -3232,7 +3351,7 @@ declare function createClient(config?: ClientConfig): {
3232
3351
  }>;
3233
3352
  retryDelivery(id: string, options?: {
3234
3353
  signal?: AbortSignal;
3235
- }): Promise<WebhookDelivery>;
3354
+ }): Promise<RetryDeliveryResult>;
3236
3355
  };
3237
3356
  apiKeys: {
3238
3357
  create(params: {
@@ -3282,28 +3401,12 @@ declare function createClient(config?: ClientConfig): {
3282
3401
  signal?: AbortSignal;
3283
3402
  }): Promise<void>;
3284
3403
  getSettings(options?: {
3285
- signal?: AbortSignal;
3404
+ signal? /** Custom fetch function for testing or special runtimes. */: AbortSignal;
3286
3405
  }): Promise<OrgSettings>;
3287
3406
  updateSettings(body: Partial<Pick<OrgSettings, "billingEmailsEnabled" | "defaultRegion" | "regionPinned">>, options?: {
3288
3407
  signal?: AbortSignal;
3289
3408
  }): Promise<OrgSettings>;
3290
3409
  };
3291
- batches: {
3292
- create(params: {
3293
- jobs: CreateJobParams[];
3294
- }, options?: {
3295
- signal?: AbortSignal;
3296
- }): Promise<BatchResult>;
3297
- get(id: string, options?: {
3298
- signal?: AbortSignal;
3299
- }): Promise<{
3300
- id: string;
3301
- orgId: string;
3302
- jobCount: number;
3303
- completedCount: number;
3304
- createdAt: number;
3305
- }>;
3306
- };
3307
3410
  assets: {
3308
3411
  list(params?: ListAssetsParams, options?: {
3309
3412
  signal?: AbortSignal;
@@ -3509,22 +3612,29 @@ type TransactionListParams = {
3509
3612
  type CreateWebhookParams = {
3510
3613
  name: string;
3511
3614
  url: string;
3512
- subscribedEvents: string[];
3615
+ subscribedEvents: WebhookEventType[];
3513
3616
  };
3514
3617
  type UpdateWebhookParams = {
3515
3618
  name?: string;
3516
3619
  url?: string;
3517
- subscribedEvents?: string[];
3620
+ subscribedEvents?: WebhookEventType[];
3518
3621
  active?: boolean;
3519
3622
  };
3520
3623
  type ListDeliveriesParams = {
3521
3624
  endpointId?: string;
3522
- event?: string;
3625
+ event?: WebhookEventType;
3523
3626
  status?: string;
3524
3627
  jobId?: string;
3525
3628
  limit?: number;
3526
3629
  offset?: number;
3527
3630
  };
3631
+ /** The retry route echoes only these fields — not a full delivery record. */
3632
+ type RetryDeliveryResult = {
3633
+ id: string;
3634
+ status: string;
3635
+ event: string;
3636
+ endpointId: string;
3637
+ };
3528
3638
  //#endregion
3529
3639
  //#region src/resources/orgs.d.ts
3530
3640
  type OrgCurrentResponse = {
@@ -3551,14 +3661,6 @@ type OrgCurrentResponse = {
3551
3661
  };
3552
3662
  };
3553
3663
  //#endregion
3554
- //#region src/resources/batches.d.ts
3555
- type BatchResult = {
3556
- batchId: string;
3557
- jobCount: number;
3558
- jobIds: string[];
3559
- status: string;
3560
- };
3561
- //#endregion
3562
3664
  //#region src/resources/uploads.d.ts
3563
3665
  type UploadProgress = {
3564
3666
  loaded: number;
@@ -3588,4 +3690,4 @@ type AssetListPage = {
3588
3690
  meta: AssetListMeta;
3589
3691
  };
3590
3692
  //#endregion
3591
- export { ApiError, type ApiKey, type AssetResponse as Asset, type AssetDownloadResponse, type AssetInitResponse, type AssetListMeta, type AssetListPage, type BatchResult, type BillingInvoice, type BillingState, type ClientConfig, type Cost, type CreateJobParams, type CreateUploadOptions, type CreateWebhookParams, type FfmpegParams, type FileType, type JobResponse as Job, type JobCreatedResponse, type JobError, JobFailedError, type JobListPage, type JobStats, type JobStep, type JobSubscribeOptions, type JobSubscription, type JobTimings, type JobType, type ListAssetsParams, type ListDeliveriesParams, type ListJobsParams, type LogEntryData, type OrgCurrentResponse, type OrgEvent, type OrgSettings, type Organization, type Output, type OutputFile, type PaginationMeta, type PaymentMethod, type RealtimeConnectOptions, type RealtimeConnection, type RendobarClient, type StatsParams, type Transaction, type TransactionListParams, type UpdateWebhookParams, type UploadProgress, type UsageParams, type UsageSummary, type WaitOptions, WaitTimeoutError, type WebhookDelivery, type WebhookEndpoint, createClient, isApiError, jobData, outputUrl };
3693
+ export { ApiError, type ApiKey, type AssetResponse as Asset, type AssetDownloadResponse, type AssetInitResponse, type AssetListMeta, type AssetListPage, type BalanceDepletedData, type BalanceLowData, type BillingInvoice, type BillingState, type ClientConfig, type Cost, type CreateJobParams, type CreateUploadOptions, type CreateWebhookParams, type FfmpegParams, type FileType, type JobResponse as Job, type JobCancelledData, type JobCompletedData, type JobCreatedData, type JobCreatedResponse, type JobError, type JobFailedData, JobFailedError, type JobListPage, type JobStartedData, type JobStats, type JobStep, type JobSubscribeOptions, type JobSubscription, type JobTimings, type JobType, type ListAssetsParams, type ListDeliveriesParams, type ListJobsParams, type LogEntryData, type OrgCurrentResponse, type OrgEvent, type OrgSettings, type Organization, type Output, type OutputFile, type PaginationMeta, type PaymentMethod, type RealtimeConnectOptions, type RealtimeConnection, type RendobarClient, type RetryDeliveryResult, type StatsParams, type TestEventData, type Transaction, type TransactionListParams, type UpdateWebhookParams, type UploadProgress, type UsageParams, type UsageSummary, type WaitOptions, WaitTimeoutError, type WebhookDelivery, type WebhookEndpoint, type WebhookEventDataMap, type WebhookPayload, createClient, isApiError, jobData, outputUrl };
package/dist/index.mjs CHANGED
@@ -645,22 +645,6 @@ function createOrgsResource(request) {
645
645
  };
646
646
  }
647
647
  //#endregion
648
- //#region src/resources/batches.ts
649
- function createBatchesResource(request) {
650
- return {
651
- async create(params, options) {
652
- return request("/batches", {
653
- method: "POST",
654
- body: params,
655
- signal: options?.signal
656
- });
657
- },
658
- async get(id, options) {
659
- return request(`/batches/${id}`, { signal: options?.signal });
660
- }
661
- };
662
- }
663
- //#endregion
664
648
  //#region src/resources/assets.ts
665
649
  function createAssetsResource(request) {
666
650
  return {
@@ -878,7 +862,6 @@ function createClient(config = {}) {
878
862
  webhooks: createWebhooksResource(request),
879
863
  apiKeys: createApiKeysResource(request),
880
864
  orgs: createOrgsResource(request),
881
- batches: createBatchesResource(request),
882
865
  assets: createAssetsResource(request),
883
866
  team: createTeamResource(request),
884
867
  realtime: createRealtimeClient(baseUrl, {
package/dist/webhooks.cjs CHANGED
@@ -1,12 +1,67 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/lib/webhook-verify.ts
3
3
  /**
4
- * Verify a Rendobar webhook signature using HMAC-SHA256.
5
- * Works in any runtime with Web Crypto API (Node 18+, Deno, CF Workers, browser).
4
+ * Verify Rendobar webhook signatures. Zero runtime deps — works in any runtime
5
+ * with the Web Crypto API (Node 18+, Deno, CF Workers, browser).
6
6
  *
7
- * Usage in a webhook handler:
8
- * import { verifyWebhookSignature } from "@rendobar/sdk/webhooks";
9
- * const valid = await verifyWebhookSignature(body, signature, secret);
7
+ * Prefer `verifyWebhook(body, headers, secret)` — it reads the signature +
8
+ * timestamp headers, rebuilds the signed string, checks freshness (replay
9
+ * protection), and handles the secret-rotation window for you:
10
+ *
11
+ * import { verifyWebhook } from "@rendobar/sdk/webhooks";
12
+ * const ok = await verifyWebhook(rawBody, req.headers, process.env.WEBHOOK_SECRET);
13
+ * if (!ok) return res.status(401).send("Invalid signature");
14
+ *
15
+ * `verifyWebhookSignature` is the low-level HMAC primitive. It signs exactly the
16
+ * string you pass, so you must build `${timestamp}.${body}` yourself — the raw
17
+ * body alone will NOT match, because Rendobar signs the timestamped form.
18
+ */
19
+ const SIG_HEADER = "x-rendobar-signature";
20
+ const SIG_PREVIOUS_HEADER = "x-rendobar-signature-previous";
21
+ const TIMESTAMP_HEADER = "x-rendobar-timestamp";
22
+ const DEFAULT_TOLERANCE_SEC = 300;
23
+ function getHeader(headers, name) {
24
+ if (headers instanceof Headers) return headers.get(name) ?? void 0;
25
+ const lower = name.toLowerCase();
26
+ for (const key of Object.keys(headers)) if (key.toLowerCase() === lower) {
27
+ const v = headers[key];
28
+ return Array.isArray(v) ? v[0] : v ?? void 0;
29
+ }
30
+ }
31
+ /**
32
+ * Verify a webhook request end to end: signature + timestamp freshness + secret
33
+ * rotation. Returns `true` only if the body is authentic and recent.
34
+ *
35
+ * @param body Raw request body string (NOT parsed JSON — bytes as received).
36
+ * @param headers The incoming request headers (Web `Headers` or a plain record).
37
+ * @param secret Your endpoint's signing secret (`whsec_...`).
38
+ * @param opts.toleranceSec Max clock skew in seconds (default 300). Pass
39
+ * `Infinity` to disable the replay/freshness check.
40
+ */
41
+ async function verifyWebhook(body, headers, secret, opts = {}) {
42
+ const toleranceSec = opts.toleranceSec ?? DEFAULT_TOLERANCE_SEC;
43
+ const signature = getHeader(headers, SIG_HEADER);
44
+ const timestamp = getHeader(headers, TIMESTAMP_HEADER);
45
+ if (!signature || !timestamp) return false;
46
+ const tsSec = Number(timestamp);
47
+ if (!Number.isFinite(tsSec)) return false;
48
+ if (Number.isFinite(toleranceSec)) {
49
+ const nowSec = Math.floor(Date.now() / 1e3);
50
+ if (Math.abs(nowSec - tsSec) > toleranceSec) return false;
51
+ }
52
+ const signed = `${timestamp}.${body}`;
53
+ if (await verifyWebhookSignature(signed, signature, secret)) return true;
54
+ const previous = getHeader(headers, SIG_PREVIOUS_HEADER);
55
+ if (previous && await verifyWebhookSignature(signed, previous, secret)) return true;
56
+ return false;
57
+ }
58
+ /**
59
+ * Low-level HMAC-SHA256 check. Signs `payload` verbatim and compares (constant
60
+ * time) against `signature` (`sha256=<hex>` or bare hex).
61
+ *
62
+ * NOTE: Rendobar signs `${timestamp}.${body}`, so pass that exact string as
63
+ * `payload` — the raw body alone will not match. Most callers should use
64
+ * `verifyWebhook` instead, which builds the string and checks freshness.
10
65
  */
11
66
  async function verifyWebhookSignature(payload, signature, secret) {
12
67
  const expected = signature.startsWith("sha256=") ? signature.slice(7) : signature;
@@ -22,4 +77,5 @@ async function verifyWebhookSignature(payload, signature, secret) {
22
77
  return mismatch === 0;
23
78
  }
24
79
  //#endregion
80
+ exports.verifyWebhook = verifyWebhook;
25
81
  exports.verifyWebhookSignature = verifyWebhookSignature;
@@ -1,12 +1,43 @@
1
1
  //#region src/lib/webhook-verify.d.ts
2
2
  /**
3
- * Verify a Rendobar webhook signature using HMAC-SHA256.
4
- * Works in any runtime with Web Crypto API (Node 18+, Deno, CF Workers, browser).
3
+ * Verify Rendobar webhook signatures. Zero runtime deps — works in any runtime
4
+ * with the Web Crypto API (Node 18+, Deno, CF Workers, browser).
5
5
  *
6
- * Usage in a webhook handler:
7
- * import { verifyWebhookSignature } from "@rendobar/sdk/webhooks";
8
- * const valid = await verifyWebhookSignature(body, signature, secret);
6
+ * Prefer `verifyWebhook(body, headers, secret)` — it reads the signature +
7
+ * timestamp headers, rebuilds the signed string, checks freshness (replay
8
+ * protection), and handles the secret-rotation window for you:
9
+ *
10
+ * import { verifyWebhook } from "@rendobar/sdk/webhooks";
11
+ * const ok = await verifyWebhook(rawBody, req.headers, process.env.WEBHOOK_SECRET);
12
+ * if (!ok) return res.status(401).send("Invalid signature");
13
+ *
14
+ * `verifyWebhookSignature` is the low-level HMAC primitive. It signs exactly the
15
+ * string you pass, so you must build `${timestamp}.${body}` yourself — the raw
16
+ * body alone will NOT match, because Rendobar signs the timestamped form.
17
+ */
18
+ /** Accepts a Web `Headers` object or a plain header record (e.g. Node `req.headers`). */
19
+ type WebhookHeaders = Headers | Record<string, string | string[] | undefined>;
20
+ /**
21
+ * Verify a webhook request end to end: signature + timestamp freshness + secret
22
+ * rotation. Returns `true` only if the body is authentic and recent.
23
+ *
24
+ * @param body Raw request body string (NOT parsed JSON — bytes as received).
25
+ * @param headers The incoming request headers (Web `Headers` or a plain record).
26
+ * @param secret Your endpoint's signing secret (`whsec_...`).
27
+ * @param opts.toleranceSec Max clock skew in seconds (default 300). Pass
28
+ * `Infinity` to disable the replay/freshness check.
29
+ */
30
+ declare function verifyWebhook(body: string, headers: WebhookHeaders, secret: string, opts?: {
31
+ toleranceSec?: number;
32
+ }): Promise<boolean>;
33
+ /**
34
+ * Low-level HMAC-SHA256 check. Signs `payload` verbatim and compares (constant
35
+ * time) against `signature` (`sha256=<hex>` or bare hex).
36
+ *
37
+ * NOTE: Rendobar signs `${timestamp}.${body}`, so pass that exact string as
38
+ * `payload` — the raw body alone will not match. Most callers should use
39
+ * `verifyWebhook` instead, which builds the string and checks freshness.
9
40
  */
10
41
  declare function verifyWebhookSignature(payload: string, signature: string, secret: string): Promise<boolean>;
11
42
  //#endregion
12
- export { verifyWebhookSignature };
43
+ export { type WebhookHeaders, verifyWebhook, verifyWebhookSignature };
@@ -1,12 +1,43 @@
1
1
  //#region src/lib/webhook-verify.d.ts
2
2
  /**
3
- * Verify a Rendobar webhook signature using HMAC-SHA256.
4
- * Works in any runtime with Web Crypto API (Node 18+, Deno, CF Workers, browser).
3
+ * Verify Rendobar webhook signatures. Zero runtime deps — works in any runtime
4
+ * with the Web Crypto API (Node 18+, Deno, CF Workers, browser).
5
5
  *
6
- * Usage in a webhook handler:
7
- * import { verifyWebhookSignature } from "@rendobar/sdk/webhooks";
8
- * const valid = await verifyWebhookSignature(body, signature, secret);
6
+ * Prefer `verifyWebhook(body, headers, secret)` — it reads the signature +
7
+ * timestamp headers, rebuilds the signed string, checks freshness (replay
8
+ * protection), and handles the secret-rotation window for you:
9
+ *
10
+ * import { verifyWebhook } from "@rendobar/sdk/webhooks";
11
+ * const ok = await verifyWebhook(rawBody, req.headers, process.env.WEBHOOK_SECRET);
12
+ * if (!ok) return res.status(401).send("Invalid signature");
13
+ *
14
+ * `verifyWebhookSignature` is the low-level HMAC primitive. It signs exactly the
15
+ * string you pass, so you must build `${timestamp}.${body}` yourself — the raw
16
+ * body alone will NOT match, because Rendobar signs the timestamped form.
17
+ */
18
+ /** Accepts a Web `Headers` object or a plain header record (e.g. Node `req.headers`). */
19
+ type WebhookHeaders = Headers | Record<string, string | string[] | undefined>;
20
+ /**
21
+ * Verify a webhook request end to end: signature + timestamp freshness + secret
22
+ * rotation. Returns `true` only if the body is authentic and recent.
23
+ *
24
+ * @param body Raw request body string (NOT parsed JSON — bytes as received).
25
+ * @param headers The incoming request headers (Web `Headers` or a plain record).
26
+ * @param secret Your endpoint's signing secret (`whsec_...`).
27
+ * @param opts.toleranceSec Max clock skew in seconds (default 300). Pass
28
+ * `Infinity` to disable the replay/freshness check.
29
+ */
30
+ declare function verifyWebhook(body: string, headers: WebhookHeaders, secret: string, opts?: {
31
+ toleranceSec?: number;
32
+ }): Promise<boolean>;
33
+ /**
34
+ * Low-level HMAC-SHA256 check. Signs `payload` verbatim and compares (constant
35
+ * time) against `signature` (`sha256=<hex>` or bare hex).
36
+ *
37
+ * NOTE: Rendobar signs `${timestamp}.${body}`, so pass that exact string as
38
+ * `payload` — the raw body alone will not match. Most callers should use
39
+ * `verifyWebhook` instead, which builds the string and checks freshness.
9
40
  */
10
41
  declare function verifyWebhookSignature(payload: string, signature: string, secret: string): Promise<boolean>;
11
42
  //#endregion
12
- export { verifyWebhookSignature };
43
+ export { type WebhookHeaders, verifyWebhook, verifyWebhookSignature };
package/dist/webhooks.mjs CHANGED
@@ -1,11 +1,66 @@
1
1
  //#region src/lib/webhook-verify.ts
2
2
  /**
3
- * Verify a Rendobar webhook signature using HMAC-SHA256.
4
- * Works in any runtime with Web Crypto API (Node 18+, Deno, CF Workers, browser).
3
+ * Verify Rendobar webhook signatures. Zero runtime deps — works in any runtime
4
+ * with the Web Crypto API (Node 18+, Deno, CF Workers, browser).
5
5
  *
6
- * Usage in a webhook handler:
7
- * import { verifyWebhookSignature } from "@rendobar/sdk/webhooks";
8
- * const valid = await verifyWebhookSignature(body, signature, secret);
6
+ * Prefer `verifyWebhook(body, headers, secret)` — it reads the signature +
7
+ * timestamp headers, rebuilds the signed string, checks freshness (replay
8
+ * protection), and handles the secret-rotation window for you:
9
+ *
10
+ * import { verifyWebhook } from "@rendobar/sdk/webhooks";
11
+ * const ok = await verifyWebhook(rawBody, req.headers, process.env.WEBHOOK_SECRET);
12
+ * if (!ok) return res.status(401).send("Invalid signature");
13
+ *
14
+ * `verifyWebhookSignature` is the low-level HMAC primitive. It signs exactly the
15
+ * string you pass, so you must build `${timestamp}.${body}` yourself — the raw
16
+ * body alone will NOT match, because Rendobar signs the timestamped form.
17
+ */
18
+ const SIG_HEADER = "x-rendobar-signature";
19
+ const SIG_PREVIOUS_HEADER = "x-rendobar-signature-previous";
20
+ const TIMESTAMP_HEADER = "x-rendobar-timestamp";
21
+ const DEFAULT_TOLERANCE_SEC = 300;
22
+ function getHeader(headers, name) {
23
+ if (headers instanceof Headers) return headers.get(name) ?? void 0;
24
+ const lower = name.toLowerCase();
25
+ for (const key of Object.keys(headers)) if (key.toLowerCase() === lower) {
26
+ const v = headers[key];
27
+ return Array.isArray(v) ? v[0] : v ?? void 0;
28
+ }
29
+ }
30
+ /**
31
+ * Verify a webhook request end to end: signature + timestamp freshness + secret
32
+ * rotation. Returns `true` only if the body is authentic and recent.
33
+ *
34
+ * @param body Raw request body string (NOT parsed JSON — bytes as received).
35
+ * @param headers The incoming request headers (Web `Headers` or a plain record).
36
+ * @param secret Your endpoint's signing secret (`whsec_...`).
37
+ * @param opts.toleranceSec Max clock skew in seconds (default 300). Pass
38
+ * `Infinity` to disable the replay/freshness check.
39
+ */
40
+ async function verifyWebhook(body, headers, secret, opts = {}) {
41
+ const toleranceSec = opts.toleranceSec ?? DEFAULT_TOLERANCE_SEC;
42
+ const signature = getHeader(headers, SIG_HEADER);
43
+ const timestamp = getHeader(headers, TIMESTAMP_HEADER);
44
+ if (!signature || !timestamp) return false;
45
+ const tsSec = Number(timestamp);
46
+ if (!Number.isFinite(tsSec)) return false;
47
+ if (Number.isFinite(toleranceSec)) {
48
+ const nowSec = Math.floor(Date.now() / 1e3);
49
+ if (Math.abs(nowSec - tsSec) > toleranceSec) return false;
50
+ }
51
+ const signed = `${timestamp}.${body}`;
52
+ if (await verifyWebhookSignature(signed, signature, secret)) return true;
53
+ const previous = getHeader(headers, SIG_PREVIOUS_HEADER);
54
+ if (previous && await verifyWebhookSignature(signed, previous, secret)) return true;
55
+ return false;
56
+ }
57
+ /**
58
+ * Low-level HMAC-SHA256 check. Signs `payload` verbatim and compares (constant
59
+ * time) against `signature` (`sha256=<hex>` or bare hex).
60
+ *
61
+ * NOTE: Rendobar signs `${timestamp}.${body}`, so pass that exact string as
62
+ * `payload` — the raw body alone will not match. Most callers should use
63
+ * `verifyWebhook` instead, which builds the string and checks freshness.
9
64
  */
10
65
  async function verifyWebhookSignature(payload, signature, secret) {
11
66
  const expected = signature.startsWith("sha256=") ? signature.slice(7) : signature;
@@ -21,4 +76,4 @@ async function verifyWebhookSignature(payload, signature, secret) {
21
76
  return mismatch === 0;
22
77
  }
23
78
  //#endregion
24
- export { verifyWebhookSignature };
79
+ export { verifyWebhook, verifyWebhookSignature };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rendobar/sdk",
3
- "version": "3.4.0",
3
+ "version": "4.0.0",
4
4
  "type": "module",
5
5
  "description": "TypeScript client for the Rendobar media processing API",
6
6
  "main": "./dist/index.cjs",