naystack 1.8.14 → 1.8.16

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.
@@ -159,25 +159,47 @@ function createPublisher(platform) {
159
159
  }
160
160
  return true;
161
161
  };
162
+ const createReady = async (token, params, label, wait, retry) => {
163
+ const attempts = Math.max(1, retry?.attempts ?? 3);
164
+ const backoffMS = retry?.backoffMS ?? 2e3;
165
+ for (let attempt = 1; attempt <= attempts; attempt++) {
166
+ const id = await platform.createContainer(token, params);
167
+ if (id && await isReady(token, id, label, wait)) return id;
168
+ if (attempt < attempts) {
169
+ const delay = backoffMS * 2 ** (attempt - 1);
170
+ console.warn(
171
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
172
+ );
173
+ await sleep(delay);
174
+ }
175
+ }
176
+ return null;
177
+ };
162
178
  return {
163
179
  /** Creates a container, waits for it to finish processing, then publishes it. */
164
- publish: async (token, params, wait) => {
165
- const containerID = await platform.createContainer(token, params);
180
+ publish: async (token, params, wait, retry) => {
181
+ const containerID = await createReady(
182
+ token,
183
+ params,
184
+ "container",
185
+ wait,
186
+ retry
187
+ );
166
188
  if (!containerID) return null;
167
- if (!await isReady(token, containerID, "container", wait)) return null;
168
189
  return platform.publish(token, containerID);
169
190
  },
170
191
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
171
- createChildren: async (token, items, wait) => {
192
+ createChildren: async (token, items, wait, retry) => {
172
193
  const children = [];
173
194
  for (const item of items) {
174
- const childID = await platform.createContainer(token, {
175
- ...item,
176
- is_carousel_item: true
177
- });
195
+ const childID = await createReady(
196
+ token,
197
+ { ...item, is_carousel_item: true },
198
+ "carousel item",
199
+ wait,
200
+ retry
201
+ );
178
202
  if (!childID) return null;
179
- if (!await isReady(token, childID, "carousel item", wait))
180
- return null;
181
203
  children.push(childID);
182
204
  }
183
205
  return children;
@@ -185,6 +207,13 @@ function createPublisher(platform) {
185
207
  };
186
208
  }
187
209
 
210
+ // src/socials/meta/types.ts
211
+ var MetaMediaType = /* @__PURE__ */ ((MetaMediaType2) => {
212
+ MetaMediaType2["Photo"] = "photo";
213
+ MetaMediaType2["Video"] = "video";
214
+ return MetaMediaType2;
215
+ })(MetaMediaType || {});
216
+
188
217
  // src/socials/instagram/setters.ts
189
218
  var publisher = createPublisher({
190
219
  name: "Instagram",
@@ -228,14 +257,16 @@ var createInstagramPost = async (token, input) => {
228
257
  media_type: "STORIES",
229
258
  alt_text: void 0
230
259
  },
231
- input.wait
260
+ input.wait,
261
+ input.retry
232
262
  );
233
263
  }
234
264
  if (media.length > 1) {
235
265
  const children = await publisher.createChildren(
236
266
  token,
237
267
  media.map(mediaParams),
238
- input.wait
268
+ input.wait,
269
+ input.retry
239
270
  );
240
271
  if (!children) return null;
241
272
  return publisher.publish(
@@ -245,7 +276,8 @@ var createInstagramPost = async (token, input) => {
245
276
  children: children.join(","),
246
277
  caption: input.caption
247
278
  },
248
- input.wait
279
+ input.wait,
280
+ input.retry
249
281
  );
250
282
  }
251
283
  if (first.type === "video" /* Video */) {
@@ -261,7 +293,8 @@ var createInstagramPost = async (token, input) => {
261
293
  audio_name: input.audioName,
262
294
  collaborators: input.collaborators && JSON.stringify(input.collaborators)
263
295
  },
264
- input.wait
296
+ input.wait,
297
+ input.retry
265
298
  );
266
299
  }
267
300
  return publisher.publish(
@@ -272,7 +305,8 @@ var createInstagramPost = async (token, input) => {
272
305
  alt_text: first.altText,
273
306
  location_id: input.locationID
274
307
  },
275
- input.wait
308
+ input.wait,
309
+ input.retry
276
310
  );
277
311
  };
278
312
  var sendInstagramMessage = (token, to, text) => {
@@ -377,13 +411,15 @@ var createThreadsPost = async (token, input, replyToID) => {
377
411
  const children = await publisher2.createChildren(
378
412
  token,
379
413
  media.map((item) => mediaParams2(item)),
380
- post.wait
414
+ post.wait,
415
+ post.retry
381
416
  );
382
417
  if (!children) return null;
383
418
  return publisher2.publish(
384
419
  token,
385
420
  { ...shared, media_type: "CAROUSEL", children: children.join(",") },
386
- post.wait
421
+ post.wait,
422
+ post.retry
387
423
  );
388
424
  }
389
425
  return publisher2.publish(
@@ -393,7 +429,8 @@ var createThreadsPost = async (token, input, replyToID) => {
393
429
  ...shared,
394
430
  link_attachment: post.linkAttachment
395
431
  },
396
- post.wait
432
+ post.wait,
433
+ post.retry
397
434
  );
398
435
  };
399
436
  var createThread = async (token, posts) => {
@@ -421,6 +458,7 @@ var setupThreadsWebhook = (options) => {
421
458
  };
422
459
  };
423
460
  export {
461
+ MetaMediaType,
424
462
  canPublishToInstagram,
425
463
  createInstagramPost,
426
464
  createThread,
@@ -99,25 +99,47 @@ function createPublisher(platform) {
99
99
  }
100
100
  return true;
101
101
  };
102
+ const createReady = async (token, params, label, wait, retry) => {
103
+ const attempts = Math.max(1, retry?.attempts ?? 3);
104
+ const backoffMS = retry?.backoffMS ?? 2e3;
105
+ for (let attempt = 1; attempt <= attempts; attempt++) {
106
+ const id = await platform.createContainer(token, params);
107
+ if (id && await isReady(token, id, label, wait)) return id;
108
+ if (attempt < attempts) {
109
+ const delay = backoffMS * 2 ** (attempt - 1);
110
+ console.warn(
111
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
112
+ );
113
+ await sleep(delay);
114
+ }
115
+ }
116
+ return null;
117
+ };
102
118
  return {
103
119
  /** Creates a container, waits for it to finish processing, then publishes it. */
104
- publish: async (token, params, wait) => {
105
- const containerID = await platform.createContainer(token, params);
120
+ publish: async (token, params, wait, retry) => {
121
+ const containerID = await createReady(
122
+ token,
123
+ params,
124
+ "container",
125
+ wait,
126
+ retry
127
+ );
106
128
  if (!containerID) return null;
107
- if (!await isReady(token, containerID, "container", wait)) return null;
108
129
  return platform.publish(token, containerID);
109
130
  },
110
131
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
111
- createChildren: async (token, items, wait) => {
132
+ createChildren: async (token, items, wait, retry) => {
112
133
  const children = [];
113
134
  for (const item of items) {
114
- const childID = await platform.createContainer(token, {
115
- ...item,
116
- is_carousel_item: true
117
- });
135
+ const childID = await createReady(
136
+ token,
137
+ { ...item, is_carousel_item: true },
138
+ "carousel item",
139
+ wait,
140
+ retry
141
+ );
118
142
  if (!childID) return null;
119
- if (!await isReady(token, childID, "carousel item", wait))
120
- return null;
121
143
  children.push(childID);
122
144
  }
123
145
  return children;
@@ -168,14 +190,16 @@ var createInstagramPost = async (token, input) => {
168
190
  media_type: "STORIES",
169
191
  alt_text: void 0
170
192
  },
171
- input.wait
193
+ input.wait,
194
+ input.retry
172
195
  );
173
196
  }
174
197
  if (media.length > 1) {
175
198
  const children = await publisher.createChildren(
176
199
  token,
177
200
  media.map(mediaParams),
178
- input.wait
201
+ input.wait,
202
+ input.retry
179
203
  );
180
204
  if (!children) return null;
181
205
  return publisher.publish(
@@ -185,7 +209,8 @@ var createInstagramPost = async (token, input) => {
185
209
  children: children.join(","),
186
210
  caption: input.caption
187
211
  },
188
- input.wait
212
+ input.wait,
213
+ input.retry
189
214
  );
190
215
  }
191
216
  if (first.type === "video" /* Video */) {
@@ -201,7 +226,8 @@ var createInstagramPost = async (token, input) => {
201
226
  audio_name: input.audioName,
202
227
  collaborators: input.collaborators && JSON.stringify(input.collaborators)
203
228
  },
204
- input.wait
229
+ input.wait,
230
+ input.retry
205
231
  );
206
232
  }
207
233
  return publisher.publish(
@@ -212,7 +238,8 @@ var createInstagramPost = async (token, input) => {
212
238
  alt_text: first.altText,
213
239
  location_id: input.locationID
214
240
  },
215
- input.wait
241
+ input.wait,
242
+ input.retry
216
243
  );
217
244
  };
218
245
  var sendInstagramMessage = (token, to, text) => {
@@ -72,25 +72,47 @@ function createPublisher(platform) {
72
72
  }
73
73
  return true;
74
74
  };
75
+ const createReady = async (token, params, label, wait, retry) => {
76
+ const attempts = Math.max(1, retry?.attempts ?? 3);
77
+ const backoffMS = retry?.backoffMS ?? 2e3;
78
+ for (let attempt = 1; attempt <= attempts; attempt++) {
79
+ const id = await platform.createContainer(token, params);
80
+ if (id && await isReady(token, id, label, wait)) return id;
81
+ if (attempt < attempts) {
82
+ const delay = backoffMS * 2 ** (attempt - 1);
83
+ console.warn(
84
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
85
+ );
86
+ await sleep(delay);
87
+ }
88
+ }
89
+ return null;
90
+ };
75
91
  return {
76
92
  /** Creates a container, waits for it to finish processing, then publishes it. */
77
- publish: async (token, params, wait) => {
78
- const containerID = await platform.createContainer(token, params);
93
+ publish: async (token, params, wait, retry) => {
94
+ const containerID = await createReady(
95
+ token,
96
+ params,
97
+ "container",
98
+ wait,
99
+ retry
100
+ );
79
101
  if (!containerID) return null;
80
- if (!await isReady(token, containerID, "container", wait)) return null;
81
102
  return platform.publish(token, containerID);
82
103
  },
83
104
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
84
- createChildren: async (token, items, wait) => {
105
+ createChildren: async (token, items, wait, retry) => {
85
106
  const children = [];
86
107
  for (const item of items) {
87
- const childID = await platform.createContainer(token, {
88
- ...item,
89
- is_carousel_item: true
90
- });
108
+ const childID = await createReady(
109
+ token,
110
+ { ...item, is_carousel_item: true },
111
+ "carousel item",
112
+ wait,
113
+ retry
114
+ );
91
115
  if (!childID) return null;
92
- if (!await isReady(token, childID, "carousel item", wait))
93
- return null;
94
116
  children.push(childID);
95
117
  }
96
118
  return children;
@@ -141,14 +163,16 @@ var createInstagramPost = async (token, input) => {
141
163
  media_type: "STORIES",
142
164
  alt_text: void 0
143
165
  },
144
- input.wait
166
+ input.wait,
167
+ input.retry
145
168
  );
146
169
  }
147
170
  if (media.length > 1) {
148
171
  const children = await publisher.createChildren(
149
172
  token,
150
173
  media.map(mediaParams),
151
- input.wait
174
+ input.wait,
175
+ input.retry
152
176
  );
153
177
  if (!children) return null;
154
178
  return publisher.publish(
@@ -158,7 +182,8 @@ var createInstagramPost = async (token, input) => {
158
182
  children: children.join(","),
159
183
  caption: input.caption
160
184
  },
161
- input.wait
185
+ input.wait,
186
+ input.retry
162
187
  );
163
188
  }
164
189
  if (first.type === "video" /* Video */) {
@@ -174,7 +199,8 @@ var createInstagramPost = async (token, input) => {
174
199
  audio_name: input.audioName,
175
200
  collaborators: input.collaborators && JSON.stringify(input.collaborators)
176
201
  },
177
- input.wait
202
+ input.wait,
203
+ input.retry
178
204
  );
179
205
  }
180
206
  return publisher.publish(
@@ -185,7 +211,8 @@ var createInstagramPost = async (token, input) => {
185
211
  alt_text: first.altText,
186
212
  location_id: input.locationID
187
213
  },
188
- input.wait
214
+ input.wait,
215
+ input.retry
189
216
  );
190
217
  };
191
218
  var sendInstagramMessage = (token, to, text) => {
@@ -1,4 +1,4 @@
1
- import { WaitForContainerOptions } from '../meta/container.mjs';
1
+ import { WaitForContainerOptions, RetryOptions } from '../meta/container.mjs';
2
2
  import { MetaMediaType } from '../meta/types.mjs';
3
3
 
4
4
  /**
@@ -121,6 +121,7 @@ type InstagramPostMedia = {
121
121
  * @property audioName - Reels: name for the audio track. Can only be set once.
122
122
  * @property collaborators - Reels: up to 3 public usernames to invite as collaborators.
123
123
  * @property wait - Container polling settings.
124
+ * @property retry - Container-creation retry settings. See {@link RetryOptions}.
124
125
  *
125
126
  * @category Socials
126
127
  */
@@ -135,6 +136,7 @@ type InstagramPostInput = {
135
136
  audioName?: string;
136
137
  collaborators?: string[];
137
138
  wait?: WaitForContainerOptions;
139
+ retry?: RetryOptions;
138
140
  };
139
141
 
140
142
  export type { InstagramConversation, InstagramMedia, InstagramMessage, InstagramPostInput, InstagramPostMedia, InstagramUser };
@@ -1,4 +1,4 @@
1
- import { WaitForContainerOptions } from '../meta/container.js';
1
+ import { WaitForContainerOptions, RetryOptions } from '../meta/container.js';
2
2
  import { MetaMediaType } from '../meta/types.js';
3
3
 
4
4
  /**
@@ -121,6 +121,7 @@ type InstagramPostMedia = {
121
121
  * @property audioName - Reels: name for the audio track. Can only be set once.
122
122
  * @property collaborators - Reels: up to 3 public usernames to invite as collaborators.
123
123
  * @property wait - Container polling settings.
124
+ * @property retry - Container-creation retry settings. See {@link RetryOptions}.
124
125
  *
125
126
  * @category Socials
126
127
  */
@@ -135,6 +136,7 @@ type InstagramPostInput = {
135
136
  audioName?: string;
136
137
  collaborators?: string[];
137
138
  wait?: WaitForContainerOptions;
139
+ retry?: RetryOptions;
138
140
  };
139
141
 
140
142
  export type { InstagramConversation, InstagramMedia, InstagramMessage, InstagramPostInput, InstagramPostMedia, InstagramUser };
@@ -51,25 +51,47 @@ function createPublisher(platform) {
51
51
  }
52
52
  return true;
53
53
  };
54
+ const createReady = async (token, params, label, wait, retry) => {
55
+ const attempts = Math.max(1, retry?.attempts ?? 3);
56
+ const backoffMS = retry?.backoffMS ?? 2e3;
57
+ for (let attempt = 1; attempt <= attempts; attempt++) {
58
+ const id = await platform.createContainer(token, params);
59
+ if (id && await isReady(token, id, label, wait)) return id;
60
+ if (attempt < attempts) {
61
+ const delay = backoffMS * 2 ** (attempt - 1);
62
+ console.warn(
63
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
64
+ );
65
+ await sleep(delay);
66
+ }
67
+ }
68
+ return null;
69
+ };
54
70
  return {
55
71
  /** Creates a container, waits for it to finish processing, then publishes it. */
56
- publish: async (token, params, wait) => {
57
- const containerID = await platform.createContainer(token, params);
72
+ publish: async (token, params, wait, retry) => {
73
+ const containerID = await createReady(
74
+ token,
75
+ params,
76
+ "container",
77
+ wait,
78
+ retry
79
+ );
58
80
  if (!containerID) return null;
59
- if (!await isReady(token, containerID, "container", wait)) return null;
60
81
  return platform.publish(token, containerID);
61
82
  },
62
83
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
63
- createChildren: async (token, items, wait) => {
84
+ createChildren: async (token, items, wait, retry) => {
64
85
  const children = [];
65
86
  for (const item of items) {
66
- const childID = await platform.createContainer(token, {
67
- ...item,
68
- is_carousel_item: true
69
- });
87
+ const childID = await createReady(
88
+ token,
89
+ { ...item, is_carousel_item: true },
90
+ "carousel item",
91
+ wait,
92
+ retry
93
+ );
70
94
  if (!childID) return null;
71
- if (!await isReady(token, childID, "carousel item", wait))
72
- return null;
73
95
  children.push(childID);
74
96
  }
75
97
  return children;
@@ -12,6 +12,24 @@ type WaitForContainerOptions = {
12
12
  intervalMS?: number;
13
13
  timeoutMS?: number;
14
14
  };
15
+ /**
16
+ * Retry settings for creating a media container.
17
+ *
18
+ * Meta intermittently rejects a perfectly valid container — most visibly on
19
+ * carousels, where one arbitrary child fails with "Only photo or video can be
20
+ * accepted as media type." and the identical call succeeds moments later. The
21
+ * failure is transient and carries no distinguishing error code, so container
22
+ * creation is simply retried rather than pattern-matched against Meta's copy.
23
+ *
24
+ * @property attempts - Total tries, including the first. Default: `3`.
25
+ * @property backoffMS - Delay before the second try, doubled each time after. Default: `2000`.
26
+ *
27
+ * @category Socials
28
+ */
29
+ type RetryOptions = {
30
+ attempts?: number;
31
+ backoffMS?: number;
32
+ };
15
33
  /**
16
34
  * Wires up the create → wait → publish flow Meta platforms share. Instagram and
17
35
  * Threads differ only in their endpoints, so each builds one publisher and every
@@ -30,9 +48,9 @@ declare function createPublisher(platform: {
30
48
  publish: (token: string, creationID: string) => Promise<string | null>;
31
49
  }): {
32
50
  /** Creates a container, waits for it to finish processing, then publishes it. */
33
- publish: (token: string, params: GraphParams, wait?: WaitForContainerOptions) => Promise<string | null>;
51
+ publish: (token: string, params: GraphParams, wait?: WaitForContainerOptions, retry?: RetryOptions) => Promise<string | null>;
34
52
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
35
- createChildren: (token: string, items: GraphParams[], wait?: WaitForContainerOptions) => Promise<string[] | null>;
53
+ createChildren: (token: string, items: GraphParams[], wait?: WaitForContainerOptions, retry?: RetryOptions) => Promise<string[] | null>;
36
54
  };
37
55
 
38
- export { type WaitForContainerOptions, createPublisher };
56
+ export { type RetryOptions, type WaitForContainerOptions, createPublisher };
@@ -12,6 +12,24 @@ type WaitForContainerOptions = {
12
12
  intervalMS?: number;
13
13
  timeoutMS?: number;
14
14
  };
15
+ /**
16
+ * Retry settings for creating a media container.
17
+ *
18
+ * Meta intermittently rejects a perfectly valid container — most visibly on
19
+ * carousels, where one arbitrary child fails with "Only photo or video can be
20
+ * accepted as media type." and the identical call succeeds moments later. The
21
+ * failure is transient and carries no distinguishing error code, so container
22
+ * creation is simply retried rather than pattern-matched against Meta's copy.
23
+ *
24
+ * @property attempts - Total tries, including the first. Default: `3`.
25
+ * @property backoffMS - Delay before the second try, doubled each time after. Default: `2000`.
26
+ *
27
+ * @category Socials
28
+ */
29
+ type RetryOptions = {
30
+ attempts?: number;
31
+ backoffMS?: number;
32
+ };
15
33
  /**
16
34
  * Wires up the create → wait → publish flow Meta platforms share. Instagram and
17
35
  * Threads differ only in their endpoints, so each builds one publisher and every
@@ -30,9 +48,9 @@ declare function createPublisher(platform: {
30
48
  publish: (token: string, creationID: string) => Promise<string | null>;
31
49
  }): {
32
50
  /** Creates a container, waits for it to finish processing, then publishes it. */
33
- publish: (token: string, params: GraphParams, wait?: WaitForContainerOptions) => Promise<string | null>;
51
+ publish: (token: string, params: GraphParams, wait?: WaitForContainerOptions, retry?: RetryOptions) => Promise<string | null>;
34
52
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
35
- createChildren: (token: string, items: GraphParams[], wait?: WaitForContainerOptions) => Promise<string[] | null>;
53
+ createChildren: (token: string, items: GraphParams[], wait?: WaitForContainerOptions, retry?: RetryOptions) => Promise<string[] | null>;
36
54
  };
37
55
 
38
- export { type WaitForContainerOptions, createPublisher };
56
+ export { type RetryOptions, type WaitForContainerOptions, createPublisher };
@@ -27,25 +27,47 @@ function createPublisher(platform) {
27
27
  }
28
28
  return true;
29
29
  };
30
+ const createReady = async (token, params, label, wait, retry) => {
31
+ const attempts = Math.max(1, retry?.attempts ?? 3);
32
+ const backoffMS = retry?.backoffMS ?? 2e3;
33
+ for (let attempt = 1; attempt <= attempts; attempt++) {
34
+ const id = await platform.createContainer(token, params);
35
+ if (id && await isReady(token, id, label, wait)) return id;
36
+ if (attempt < attempts) {
37
+ const delay = backoffMS * 2 ** (attempt - 1);
38
+ console.warn(
39
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
40
+ );
41
+ await sleep(delay);
42
+ }
43
+ }
44
+ return null;
45
+ };
30
46
  return {
31
47
  /** Creates a container, waits for it to finish processing, then publishes it. */
32
- publish: async (token, params, wait) => {
33
- const containerID = await platform.createContainer(token, params);
48
+ publish: async (token, params, wait, retry) => {
49
+ const containerID = await createReady(
50
+ token,
51
+ params,
52
+ "container",
53
+ wait,
54
+ retry
55
+ );
34
56
  if (!containerID) return null;
35
- if (!await isReady(token, containerID, "container", wait)) return null;
36
57
  return platform.publish(token, containerID);
37
58
  },
38
59
  /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
39
- createChildren: async (token, items, wait) => {
60
+ createChildren: async (token, items, wait, retry) => {
40
61
  const children = [];
41
62
  for (const item of items) {
42
- const childID = await platform.createContainer(token, {
43
- ...item,
44
- is_carousel_item: true
45
- });
63
+ const childID = await createReady(
64
+ token,
65
+ { ...item, is_carousel_item: true },
66
+ "carousel item",
67
+ wait,
68
+ retry
69
+ );
46
70
  if (!childID) return null;
47
- if (!await isReady(token, childID, "carousel item", wait))
48
- return null;
49
71
  children.push(childID);
50
72
  }
51
73
  return children;