@postrun/js 2.16.0 → 2.17.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
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var z = require('zod');
4
- var axios = require('axios');
5
- var pRetry = require('p-retry');
4
+ var Uppy = require('@uppy/core');
5
+ var AwsS3 = require('@uppy/aws-s3');
6
6
 
7
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
8
 
@@ -25,8 +25,8 @@ function _interopNamespace(e) {
25
25
  }
26
26
 
27
27
  var z__namespace = /*#__PURE__*/_interopNamespace(z);
28
- var axios__default = /*#__PURE__*/_interopDefault(axios);
29
- var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
28
+ var Uppy__default = /*#__PURE__*/_interopDefault(Uppy);
29
+ var AwsS3__default = /*#__PURE__*/_interopDefault(AwsS3);
30
30
 
31
31
  // src/client/core/bodySerializer.gen.ts
32
32
  var jsonBodySerializer = {
@@ -821,6 +821,8 @@ var zErrorCode = z__namespace.enum([
821
821
  "connection_discovery_failed",
822
822
  "tiktok_creator_info_unavailable",
823
823
  "media_processing",
824
+ "media_upload_init_failed",
825
+ "media_upload_incomplete",
824
826
  "not_publishable",
825
827
  "invalid_connection",
826
828
  "invalid_media",
@@ -885,11 +887,16 @@ var zErrorCode = z__namespace.enum([
885
887
  "instagram_container_expired",
886
888
  "instagram_container_failed",
887
889
  "instagram_rate_limited",
890
+ "instagram_daily_limit_reached",
891
+ "instagram_aspect_ratio_unsupported",
892
+ "instagram_media_unsupported",
888
893
  "instagram_not_authorized",
889
894
  "instagram_publish_failed",
890
895
  "facebook_reel_processing",
891
896
  "facebook_reel_failed",
892
897
  "facebook_rate_limited",
898
+ "facebook_duplicate_content",
899
+ "facebook_temporarily_blocked",
893
900
  "facebook_not_authorized",
894
901
  "facebook_publish_failed",
895
902
  "tiktok_privacy_not_allowed",
@@ -1974,9 +1981,9 @@ z__namespace.object({
1974
1981
  created_at: z__namespace.string(),
1975
1982
  updated_at: z__namespace.string(),
1976
1983
  upload: z__namespace.object({
1977
- url: z__namespace.url(),
1978
- method: z__namespace.literal("PUT"),
1979
- headers: z__namespace.record(z__namespace.string(), z__namespace.string()),
1984
+ upload_id: z__namespace.string(),
1985
+ key: z__namespace.string(),
1986
+ part_size: z__namespace.int().gt(0).lte(9007199254740991),
1980
1987
  expires_at: z__namespace.string()
1981
1988
  }).nullable()
1982
1989
  });
@@ -2011,6 +2018,37 @@ z__namespace.object({
2011
2018
  z__namespace.object({
2012
2019
  id: z__namespace.string()
2013
2020
  });
2021
+ z__namespace.object({
2022
+ part_number: z__namespace.int().gte(1).lte(1e4)
2023
+ });
2024
+ z__namespace.object({
2025
+ id: z__namespace.string()
2026
+ });
2027
+ z__namespace.object({
2028
+ url: z__namespace.url()
2029
+ });
2030
+ z__namespace.object({
2031
+ id: z__namespace.string()
2032
+ });
2033
+ z__namespace.object({
2034
+ parts: z__namespace.array(z__namespace.object({
2035
+ part_number: z__namespace.int().gte(1).lte(9007199254740991),
2036
+ etag: z__namespace.string(),
2037
+ size: z__namespace.int().gte(0).lte(9007199254740991)
2038
+ }))
2039
+ });
2040
+ z__namespace.object({
2041
+ parts: z__namespace.array(z__namespace.object({
2042
+ part_number: z__namespace.int().gte(1).lte(1e4),
2043
+ etag: z__namespace.string().min(1)
2044
+ })).min(1)
2045
+ });
2046
+ z__namespace.object({
2047
+ id: z__namespace.string()
2048
+ });
2049
+ z__namespace.object({
2050
+ id: z__namespace.string()
2051
+ });
2014
2052
  z__namespace.object({
2015
2053
  limit: z__namespace.int().gte(1).lte(100).optional().default(20),
2016
2054
  offset: z__namespace.int().gte(0).lte(9007199254740991).optional().default(0),
@@ -2146,6 +2184,8 @@ z__namespace.object({
2146
2184
  "connection_discovery_failed",
2147
2185
  "tiktok_creator_info_unavailable",
2148
2186
  "media_processing",
2187
+ "media_upload_init_failed",
2188
+ "media_upload_incomplete",
2149
2189
  "not_publishable",
2150
2190
  "invalid_connection",
2151
2191
  "invalid_media",
@@ -2210,11 +2250,16 @@ z__namespace.object({
2210
2250
  "instagram_container_expired",
2211
2251
  "instagram_container_failed",
2212
2252
  "instagram_rate_limited",
2253
+ "instagram_daily_limit_reached",
2254
+ "instagram_aspect_ratio_unsupported",
2255
+ "instagram_media_unsupported",
2213
2256
  "instagram_not_authorized",
2214
2257
  "instagram_publish_failed",
2215
2258
  "facebook_reel_processing",
2216
2259
  "facebook_reel_failed",
2217
2260
  "facebook_rate_limited",
2261
+ "facebook_duplicate_content",
2262
+ "facebook_temporarily_blocked",
2218
2263
  "facebook_not_authorized",
2219
2264
  "facebook_publish_failed",
2220
2265
  "tiktok_privacy_not_allowed",
@@ -4336,6 +4381,66 @@ var mediaUpdate = (options) => (options.client ?? client).patch({
4336
4381
  ...options.headers
4337
4382
  }
4338
4383
  });
4384
+ var mediaSignPart = (options) => (options.client ?? client).post({
4385
+ security: [{
4386
+ key: "secretKey",
4387
+ scheme: "bearer",
4388
+ type: "http"
4389
+ }, {
4390
+ key: "frontendToken",
4391
+ scheme: "bearer",
4392
+ type: "http"
4393
+ }],
4394
+ url: "/media/{id}/multipart/sign",
4395
+ ...options,
4396
+ headers: {
4397
+ "Content-Type": "application/json",
4398
+ ...options.headers
4399
+ }
4400
+ });
4401
+ var mediaListParts = (options) => (options.client ?? client).get({
4402
+ security: [{
4403
+ key: "secretKey",
4404
+ scheme: "bearer",
4405
+ type: "http"
4406
+ }, {
4407
+ key: "frontendToken",
4408
+ scheme: "bearer",
4409
+ type: "http"
4410
+ }],
4411
+ url: "/media/{id}/multipart/parts",
4412
+ ...options
4413
+ });
4414
+ var mediaComplete = (options) => (options.client ?? client).post({
4415
+ security: [{
4416
+ key: "secretKey",
4417
+ scheme: "bearer",
4418
+ type: "http"
4419
+ }, {
4420
+ key: "frontendToken",
4421
+ scheme: "bearer",
4422
+ type: "http"
4423
+ }],
4424
+ url: "/media/{id}/multipart/complete",
4425
+ ...options,
4426
+ headers: {
4427
+ "Content-Type": "application/json",
4428
+ ...options.headers
4429
+ }
4430
+ });
4431
+ var mediaAbort = (options) => (options.client ?? client).post({
4432
+ security: [{
4433
+ key: "secretKey",
4434
+ scheme: "bearer",
4435
+ type: "http"
4436
+ }, {
4437
+ key: "frontendToken",
4438
+ scheme: "bearer",
4439
+ type: "http"
4440
+ }],
4441
+ url: "/media/{id}/multipart/abort",
4442
+ ...options
4443
+ });
4339
4444
  var postsList = (options) => (options?.client ?? client).get({
4340
4445
  security: [{
4341
4446
  key: "secretKey",
@@ -5312,61 +5417,111 @@ var tokensMint = (options) => (options.client ?? client).post({
5312
5417
  // src/resources.ts
5313
5418
  var isPublished = (post) => post.status === "published";
5314
5419
  var failedVariants = (post) => post.variants.filter((variant) => variant.status === "failed");
5420
+
5421
+ // src/upload/casing.ts
5422
+ function listedPartsToS3(parts) {
5423
+ return parts.map((part) => ({
5424
+ PartNumber: part.part_number,
5425
+ ETag: part.etag,
5426
+ Size: part.size
5427
+ }));
5428
+ }
5429
+ function s3PartsToComplete(parts) {
5430
+ return parts.map((part) => {
5431
+ if (part.PartNumber === void 0 || part.ETag === void 0) {
5432
+ throw new Error(
5433
+ "Multipart complete received a part without PartNumber/ETag."
5434
+ );
5435
+ }
5436
+ return { part_number: part.PartNumber, etag: part.ETag };
5437
+ });
5438
+ }
5439
+
5440
+ // src/upload/upload-error.ts
5315
5441
  var UploadError = class extends Error {
5316
- status;
5317
- constructor(status, message) {
5318
- super(message);
5442
+ constructor(message, options) {
5443
+ super(message, options);
5319
5444
  this.name = "UploadError";
5320
- this.status = status;
5321
5445
  }
5322
5446
  };
5323
- function isTerminal(status) {
5324
- return status >= 400 && status < 500 && status !== 429;
5325
- }
5326
- async function uploadToTarget(file, target, opts = {}) {
5327
- const { onProgress, signal } = opts;
5328
- async function putOnce() {
5329
- try {
5330
- await axios__default.default.request({
5331
- method: target.method,
5332
- url: target.url,
5333
- data: file,
5334
- headers: target.headers,
5335
- signal,
5336
- onUploadProgress: (event) => {
5337
- if (event.total) {
5338
- onProgress?.(event.loaded / event.total);
5339
- }
5340
- }
5447
+
5448
+ // src/upload/upload-file.ts
5449
+ async function uploadFile(file, options) {
5450
+ const { mediaId, session, client: client2, onProgress, signal } = options;
5451
+ if (signal?.aborted) {
5452
+ throw new DOMException("Upload aborted", "AbortError");
5453
+ }
5454
+ const uppy = new Uppy__default.default({ autoProceed: false }).use(AwsS3__default.default, {
5455
+ // Every file is one resumable multipart upload — no size-threshold split, so
5456
+ // the path is uniform and a tiny file is just a 1-part upload (PLAN §2). The
5457
+ // literal `true` (not a `() => true`) selects Uppy's always-multipart variant.
5458
+ shouldUseMultipart: true,
5459
+ // Pin Uppy's chunk size to the server's part size — every part except the
5460
+ // last MUST be exactly this (an R2 requirement the session encodes).
5461
+ getChunkSize: () => session.part_size,
5462
+ // Start: hand back the cached session from the create response — NO HTTP.
5463
+ createMultipartUpload: () => ({
5464
+ uploadId: session.upload_id,
5465
+ key: session.key
5466
+ }),
5467
+ // Sign one part → POST /media/{id}/multipart/sign. The sub-endpoint reads the
5468
+ // upload id from the asset row, so the body carries only the part number.
5469
+ signPart: async (_file, { partNumber }) => {
5470
+ const { data } = await mediaSignPart({
5471
+ client: client2,
5472
+ path: { id: mediaId },
5473
+ body: { part_number: partNumber }
5474
+ });
5475
+ return { url: data.url };
5476
+ },
5477
+ // Resume: GET /media/{id}/multipart/parts → map snake_case → S3 PascalCase so
5478
+ // Uppy skips the parts R2 already holds after a dropped connection.
5479
+ listParts: async () => {
5480
+ const { data } = await mediaListParts({
5481
+ client: client2,
5482
+ path: { id: mediaId }
5483
+ });
5484
+ return listedPartsToS3(data.parts);
5485
+ },
5486
+ // Finish: map Uppy's S3 parts → snake_case → POST /media/{id}/multipart/complete.
5487
+ completeMultipartUpload: async (_file, { parts }) => {
5488
+ await mediaComplete({
5489
+ client: client2,
5490
+ path: { id: mediaId },
5491
+ body: { parts: s3PartsToComplete(parts) }
5492
+ });
5493
+ return {};
5494
+ },
5495
+ // Cancel: POST /media/{id}/multipart/abort (idempotent server-side).
5496
+ abortMultipartUpload: async () => {
5497
+ await mediaAbort({ client: client2, path: { id: mediaId } });
5498
+ }
5499
+ });
5500
+ uppy.on("progress", (percent) => onProgress?.(percent / 100));
5501
+ const onAbort = () => {
5502
+ uppy.cancelAll();
5503
+ };
5504
+ signal?.addEventListener("abort", onAbort, { once: true });
5505
+ try {
5506
+ uppy.addFile({ name: fileName(file), type: file.type, data: file });
5507
+ const result = await uppy.upload();
5508
+ if (signal?.aborted) {
5509
+ throw new DOMException("Upload aborted", "AbortError");
5510
+ }
5511
+ const failed = result?.failed ?? [];
5512
+ if (failed.length > 0) {
5513
+ throw new UploadError("Multipart upload failed.", {
5514
+ cause: failed[0]?.error
5341
5515
  });
5342
- onProgress?.(1);
5343
- } catch (error) {
5344
- if (signal?.aborted) {
5345
- throw error;
5346
- }
5347
- if (axios.isAxiosError(error)) {
5348
- const status = error.response?.status ?? 0;
5349
- throw new UploadError(
5350
- status,
5351
- status ? `Upload failed (HTTP ${status}).` : "Upload failed: network error."
5352
- );
5353
- }
5354
- throw error;
5355
5516
  }
5517
+ onProgress?.(1);
5518
+ } finally {
5519
+ signal?.removeEventListener("abort", onAbort);
5520
+ uppy.destroy();
5356
5521
  }
5357
- await pRetry__default.default(
5358
- async () => {
5359
- try {
5360
- await putOnce();
5361
- } catch (error) {
5362
- if (error instanceof UploadError && isTerminal(error.status)) {
5363
- throw new pRetry.AbortError(error);
5364
- }
5365
- throw error;
5366
- }
5367
- },
5368
- { retries: opts.retries ?? 3, signal }
5369
- );
5522
+ }
5523
+ function fileName(file) {
5524
+ return file instanceof File ? file.name : "upload";
5370
5525
  }
5371
5526
 
5372
5527
  // src/tiktok.ts
@@ -5797,10 +5952,14 @@ exports.isPublished = isPublished;
5797
5952
  exports.linkedinPollDurationLabel = linkedinPollDurationLabel;
5798
5953
  exports.logsGet = logsGet;
5799
5954
  exports.logsList = logsList;
5955
+ exports.mediaAbort = mediaAbort;
5956
+ exports.mediaComplete = mediaComplete;
5800
5957
  exports.mediaCreate = mediaCreate;
5801
5958
  exports.mediaDelete = mediaDelete;
5802
5959
  exports.mediaGet = mediaGet;
5803
5960
  exports.mediaList = mediaList;
5961
+ exports.mediaListParts = mediaListParts;
5962
+ exports.mediaSignPart = mediaSignPart;
5804
5963
  exports.mediaUpdate = mediaUpdate;
5805
5964
  exports.metaAccount = metaAccount;
5806
5965
  exports.metaAd = metaAd;
@@ -5831,7 +5990,7 @@ exports.tiktokPrivacyLabel = tiktokPrivacyLabel;
5831
5990
  exports.tiktokSettings = tiktokSettings;
5832
5991
  exports.toggleInteraction = toggleInteraction;
5833
5992
  exports.tokensMint = tokensMint;
5834
- exports.uploadToTarget = uploadToTarget;
5993
+ exports.uploadFile = uploadFile;
5835
5994
  exports.webhooksCreateEndpoint = webhooksCreateEndpoint;
5836
5995
  exports.webhooksCreatePortal = webhooksCreatePortal;
5837
5996
  exports.webhooksDeleteEndpoint = webhooksDeleteEndpoint;