naystack 1.8.11 → 1.8.13

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 (88) hide show
  1. package/README.md +189 -31
  2. package/dist/auth/index.cjs.js +158 -18
  3. package/dist/auth/index.d.mts +3 -1
  4. package/dist/auth/index.d.ts +3 -1
  5. package/dist/auth/index.esm.js +158 -18
  6. package/dist/auth/instagram/index.cjs.js +158 -18
  7. package/dist/auth/instagram/index.d.mts +6 -1
  8. package/dist/auth/instagram/index.d.ts +6 -1
  9. package/dist/auth/instagram/index.esm.js +158 -18
  10. package/dist/auth/instagram/route.cjs.js +158 -18
  11. package/dist/auth/instagram/route.d.mts +3 -1
  12. package/dist/auth/instagram/route.d.ts +3 -1
  13. package/dist/auth/instagram/route.esm.js +158 -18
  14. package/dist/auth/instagram/utils.cjs.js +2 -2
  15. package/dist/auth/instagram/utils.d.mts +13 -2
  16. package/dist/auth/instagram/utils.d.ts +13 -2
  17. package/dist/auth/instagram/utils.esm.js +2 -2
  18. package/dist/file/index.cjs.js +9 -6
  19. package/dist/file/index.d.mts +1 -1
  20. package/dist/file/index.d.ts +1 -1
  21. package/dist/file/index.esm.js +9 -6
  22. package/dist/file/put.cjs.js +6 -4
  23. package/dist/file/put.d.mts +2 -0
  24. package/dist/file/put.d.ts +2 -0
  25. package/dist/file/put.esm.js +6 -4
  26. package/dist/file/setup.cjs.js +6 -4
  27. package/dist/file/setup.d.mts +22 -4
  28. package/dist/file/setup.d.ts +22 -4
  29. package/dist/file/setup.esm.js +6 -4
  30. package/dist/file/utils.cjs.js +6 -4
  31. package/dist/file/utils.d.mts +19 -3
  32. package/dist/file/utils.d.ts +19 -3
  33. package/dist/file/utils.esm.js +6 -4
  34. package/dist/index.d.mts +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/socials/index.cjs.js +298 -72
  37. package/dist/socials/index.d.mts +6 -4
  38. package/dist/socials/index.d.ts +6 -4
  39. package/dist/socials/index.esm.js +296 -72
  40. package/dist/socials/instagram/getters.cjs.js +76 -25
  41. package/dist/socials/instagram/getters.d.mts +56 -6
  42. package/dist/socials/instagram/getters.d.ts +56 -6
  43. package/dist/socials/instagram/getters.esm.js +74 -25
  44. package/dist/socials/instagram/setters.cjs.js +192 -14
  45. package/dist/socials/instagram/setters.d.mts +43 -3
  46. package/dist/socials/instagram/setters.d.ts +43 -3
  47. package/dist/socials/instagram/setters.esm.js +191 -14
  48. package/dist/socials/instagram/types.d.mts +48 -11
  49. package/dist/socials/instagram/types.d.ts +48 -11
  50. package/dist/socials/instagram/utils.cjs.js +28 -15
  51. package/dist/socials/instagram/utils.d.mts +7 -18
  52. package/dist/socials/instagram/utils.d.ts +7 -18
  53. package/dist/socials/instagram/utils.esm.js +26 -14
  54. package/dist/socials/instagram/webhook.cjs.js +1 -1
  55. package/dist/socials/instagram/webhook.esm.js +1 -1
  56. package/dist/socials/meta/container.cjs.js +82 -0
  57. package/dist/socials/meta/container.d.mts +38 -0
  58. package/dist/socials/meta/container.d.ts +38 -0
  59. package/dist/socials/meta/container.esm.js +57 -0
  60. package/dist/socials/meta/request.cjs.js +60 -0
  61. package/dist/socials/meta/request.d.mts +50 -0
  62. package/dist/socials/meta/request.d.ts +50 -0
  63. package/dist/socials/meta/request.esm.js +34 -0
  64. package/dist/socials/meta/types.cjs.js +18 -0
  65. package/dist/socials/meta/types.d.mts +47 -0
  66. package/dist/socials/meta/types.d.ts +47 -0
  67. package/dist/socials/meta/types.esm.js +0 -0
  68. package/dist/socials/{meta-webhook.cjs.js → meta/webhook.cjs.js} +4 -4
  69. package/dist/socials/{meta-webhook.esm.js → meta/webhook.esm.js} +1 -1
  70. package/dist/socials/threads/getters.cjs.js +36 -11
  71. package/dist/socials/threads/getters.d.mts +23 -2
  72. package/dist/socials/threads/getters.d.ts +23 -2
  73. package/dist/socials/threads/getters.esm.js +35 -11
  74. package/dist/socials/threads/setters.cjs.js +150 -44
  75. package/dist/socials/threads/setters.d.mts +25 -34
  76. package/dist/socials/threads/setters.d.ts +25 -34
  77. package/dist/socials/threads/setters.esm.js +149 -41
  78. package/dist/socials/threads/types.d.mts +40 -1
  79. package/dist/socials/threads/types.d.ts +40 -1
  80. package/dist/socials/threads/utils.cjs.js +29 -11
  81. package/dist/socials/threads/utils.d.mts +8 -17
  82. package/dist/socials/threads/utils.d.ts +8 -17
  83. package/dist/socials/threads/utils.esm.js +27 -10
  84. package/dist/socials/threads/webhook.cjs.js +1 -1
  85. package/dist/socials/threads/webhook.esm.js +1 -1
  86. package/package.json +1 -1
  87. /package/dist/socials/{meta-webhook.d.mts → meta/webhook.d.mts} +0 -0
  88. /package/dist/socials/{meta-webhook.d.ts → meta/webhook.d.ts} +0 -0
@@ -125,40 +125,177 @@ async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
125
125
  }
126
126
  }
127
127
  }
128
- var getInstagramAuthorizationURL = (token) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
128
+ var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
129
129
  "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
130
- )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=instagram_business_basic&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
130
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
131
131
 
132
- // src/socials/instagram/utils.ts
133
- function getInstagramURL(token, path, params) {
134
- return `https://graph.instagram.com/v23.0/${path}?${Object.keys(params).map((key) => `${key}=${params[key]}`).join("&")}&access_token=${token}`;
135
- }
136
- function getInstagramData(token, path, params = {}, postData) {
137
- return fetch(getInstagramURL(token, path, params), {
138
- method: postData ? "POST" : "GET",
139
- body: JSON.stringify(postData),
140
- headers: {
141
- Authorization: `Bearer ${token}`,
142
- "Content-Type": "application/json"
132
+ // src/socials/meta/request.ts
133
+ function createGraphClient(baseURL) {
134
+ const buildURL = (token, path, params = {}) => {
135
+ const search = new URLSearchParams();
136
+ for (const [key, value] of Object.entries(params)) {
137
+ if (value !== void 0) search.set(key, String(value));
143
138
  }
144
- }).then((res) => res.json());
139
+ search.set("access_token", token);
140
+ return `${baseURL}/${path}?${search.toString()}`;
141
+ };
142
+ const request = async (token, path, options = {}) => {
143
+ const response = await fetch(buildURL(token, path, options.params), {
144
+ method: options.method || (options.body ? "POST" : "GET"),
145
+ headers: {
146
+ Authorization: `Bearer ${token}`,
147
+ ...options.body ? { "Content-Type": "application/json" } : {}
148
+ },
149
+ ...options.body ? { body: JSON.stringify(options.body) } : {}
150
+ });
151
+ return response.json().catch(() => null);
152
+ };
153
+ return { buildURL, request };
145
154
  }
155
+ function readGraphID(label, result) {
156
+ if (result?.error) {
157
+ console.error(`[naystack] ${label} failed: ${result.error.message}`);
158
+ return null;
159
+ }
160
+ return result?.id || null;
161
+ }
162
+
163
+ // src/socials/instagram/utils.ts
164
+ var client = createGraphClient("https://graph.instagram.com/v23.0");
165
+ var getInstagramData = client.request;
146
166
 
147
167
  // src/socials/instagram/getters.ts
148
168
  var getInstagramUser = (token, id, fields) => {
149
169
  return getInstagramData(token, id || "me", {
150
- fields: fields ? fields.join(",") : "username,followers_count,media_count"
170
+ params: {
171
+ fields: fields ? fields.join(",") : "username,followers_count,media_count"
172
+ }
151
173
  });
152
174
  };
175
+ var getInstagramContainerStatus = async (token, id) => {
176
+ const result = await getInstagramData(token, id, { params: { fields: "status_code,status" } });
177
+ if (!result?.status_code) return null;
178
+ return {
179
+ status: result.status_code,
180
+ error: result.status_code === "ERROR" ? result.status : void 0
181
+ };
182
+ };
153
183
 
154
- // src/socials/meta-webhook.ts
184
+ // src/socials/meta/container.ts
185
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
186
+ async function waitForContainer(getState, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
187
+ const deadline = Date.now() + timeoutMS;
188
+ let state = await getState();
189
+ if (!state) {
190
+ await sleep(2e3);
191
+ return null;
192
+ }
193
+ while (state?.status === "IN_PROGRESS" && Date.now() < deadline) {
194
+ await sleep(intervalMS);
195
+ state = await getState();
196
+ }
197
+ return state;
198
+ }
199
+ function createPublisher(platform) {
200
+ const isReady = async (token, id, label, wait) => {
201
+ const state = await waitForContainer(
202
+ () => platform.getStatus(token, id),
203
+ wait
204
+ );
205
+ if (state && state.status !== "FINISHED" && state.status !== "PUBLISHED") {
206
+ console.error(
207
+ `[naystack] ${platform.name} ${label} ${id} is ${state.status}${state.error ? `: ${state.error}` : ""}`
208
+ );
209
+ return false;
210
+ }
211
+ return true;
212
+ };
213
+ return {
214
+ /** Creates a container, waits for it to finish processing, then publishes it. */
215
+ publish: async (token, params, wait) => {
216
+ const containerID = await platform.createContainer(token, params);
217
+ if (!containerID) return null;
218
+ if (!await isReady(token, containerID, "container", wait)) return null;
219
+ return platform.publish(token, containerID);
220
+ },
221
+ /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
222
+ createChildren: async (token, items, wait) => {
223
+ const children = [];
224
+ for (const item of items) {
225
+ const childID = await platform.createContainer(token, {
226
+ ...item,
227
+ is_carousel_item: true
228
+ });
229
+ if (!childID) return null;
230
+ if (!await isReady(token, childID, "carousel item", wait))
231
+ return null;
232
+ children.push(childID);
233
+ }
234
+ return children;
235
+ }
236
+ };
237
+ }
238
+
239
+ // src/socials/instagram/setters.ts
240
+ var publisher = createPublisher({
241
+ name: "Instagram",
242
+ getStatus: getInstagramContainerStatus,
243
+ createContainer: async (token, params) => readGraphID(
244
+ "Instagram media container",
245
+ await getInstagramData(token, "me/media", {
246
+ params,
247
+ method: "POST"
248
+ })
249
+ ),
250
+ publish: async (token, creationID) => readGraphID(
251
+ "Instagram publish",
252
+ await getInstagramData(token, "me/media_publish", {
253
+ params: { creation_id: creationID },
254
+ method: "POST"
255
+ })
256
+ )
257
+ });
258
+
259
+ // src/socials/meta/webhook.ts
155
260
  var import_server2 = require("next/server");
156
261
 
262
+ // src/socials/threads/utils.ts
263
+ var client2 = createGraphClient("https://graph.threads.net/v1.0");
264
+ var getThreadsData = client2.request;
265
+
266
+ // src/socials/threads/getters.ts
267
+ var getThreadsContainerStatus = async (token, id) => {
268
+ const result = await getThreadsData(token, id, { params: { fields: "status,error_message" } });
269
+ if (!result?.status) return null;
270
+ return { status: result.status, error: result.error_message };
271
+ };
272
+
273
+ // src/socials/threads/setters.ts
274
+ var publisher2 = createPublisher({
275
+ name: "Threads",
276
+ getStatus: getThreadsContainerStatus,
277
+ createContainer: async (token, params) => readGraphID(
278
+ "Threads container",
279
+ await getThreadsData(token, "me/threads", {
280
+ params,
281
+ method: "POST"
282
+ })
283
+ ),
284
+ publish: async (token, creationID) => readGraphID(
285
+ "Threads publish",
286
+ await getThreadsData(token, "me/threads_publish", {
287
+ params: { creation_id: creationID },
288
+ method: "POST"
289
+ })
290
+ )
291
+ });
292
+
157
293
  // src/auth/instagram/route.ts
158
294
  var getInstagramRoute = ({
159
295
  redirectURL,
160
296
  errorRedirectURL,
161
- onUser
297
+ onUser,
298
+ scopes
162
299
  }) => {
163
300
  const handleError = (message) => import_server3.NextResponse.redirect(`${errorRedirectURL}?error=${message}`);
164
301
  return async (req) => {
@@ -168,7 +305,10 @@ var getInstagramRoute = ({
168
305
  if (error) return handleError(error);
169
306
  if (!accessCode) {
170
307
  if (!stateToken) return handleError("Invalid request");
171
- return import_server3.NextResponse.redirect(getInstagramAuthorizationURL(stateToken), 302);
308
+ return import_server3.NextResponse.redirect(
309
+ getInstagramAuthorizationURL(stateToken, scopes),
310
+ 302
311
+ );
172
312
  }
173
313
  if (!stateToken) return handleError("Invalid request");
174
314
  const instagramData = await getLongLivedToken(
@@ -2,12 +2,14 @@ import { NextRequest, NextResponse } from 'next/server';
2
2
  import { SetupInstagramAuthOptions } from './index.mjs';
3
3
  import './utils.mjs';
4
4
  import '../../socials/instagram/types.mjs';
5
+ import '../../socials/meta/container.mjs';
6
+ import '../../socials/meta/types.mjs';
5
7
 
6
8
  /**
7
9
  * Returns the GET route handler for Instagram OAuth callback.
8
10
  * @param options - SetupInstagramAuthOptions (onUser, redirect URLs)
9
11
  * @returns Async route handler for the OAuth callback
10
12
  */
11
- declare const getInstagramRoute: ({ redirectURL, errorRedirectURL, onUser, }: SetupInstagramAuthOptions) => (req: NextRequest) => Promise<NextResponse<unknown>>;
13
+ declare const getInstagramRoute: ({ redirectURL, errorRedirectURL, onUser, scopes, }: SetupInstagramAuthOptions) => (req: NextRequest) => Promise<NextResponse<unknown>>;
12
14
 
13
15
  export { getInstagramRoute };
@@ -2,12 +2,14 @@ import { NextRequest, NextResponse } from 'next/server';
2
2
  import { SetupInstagramAuthOptions } from './index.js';
3
3
  import './utils.js';
4
4
  import '../../socials/instagram/types.js';
5
+ import '../../socials/meta/container.js';
6
+ import '../../socials/meta/types.js';
5
7
 
6
8
  /**
7
9
  * Returns the GET route handler for Instagram OAuth callback.
8
10
  * @param options - SetupInstagramAuthOptions (onUser, redirect URLs)
9
11
  * @returns Async route handler for the OAuth callback
10
12
  */
11
- declare const getInstagramRoute: ({ redirectURL, errorRedirectURL, onUser, }: SetupInstagramAuthOptions) => (req: NextRequest) => Promise<NextResponse<unknown>>;
13
+ declare const getInstagramRoute: ({ redirectURL, errorRedirectURL, onUser, scopes, }: SetupInstagramAuthOptions) => (req: NextRequest) => Promise<NextResponse<unknown>>;
12
14
 
13
15
  export { getInstagramRoute };
@@ -101,40 +101,177 @@ async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
101
101
  }
102
102
  }
103
103
  }
104
- var getInstagramAuthorizationURL = (token) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
104
+ var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
105
105
  "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
106
- )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=instagram_business_basic&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
106
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
107
107
 
108
- // src/socials/instagram/utils.ts
109
- function getInstagramURL(token, path, params) {
110
- return `https://graph.instagram.com/v23.0/${path}?${Object.keys(params).map((key) => `${key}=${params[key]}`).join("&")}&access_token=${token}`;
111
- }
112
- function getInstagramData(token, path, params = {}, postData) {
113
- return fetch(getInstagramURL(token, path, params), {
114
- method: postData ? "POST" : "GET",
115
- body: JSON.stringify(postData),
116
- headers: {
117
- Authorization: `Bearer ${token}`,
118
- "Content-Type": "application/json"
108
+ // src/socials/meta/request.ts
109
+ function createGraphClient(baseURL) {
110
+ const buildURL = (token, path, params = {}) => {
111
+ const search = new URLSearchParams();
112
+ for (const [key, value] of Object.entries(params)) {
113
+ if (value !== void 0) search.set(key, String(value));
119
114
  }
120
- }).then((res) => res.json());
115
+ search.set("access_token", token);
116
+ return `${baseURL}/${path}?${search.toString()}`;
117
+ };
118
+ const request = async (token, path, options = {}) => {
119
+ const response = await fetch(buildURL(token, path, options.params), {
120
+ method: options.method || (options.body ? "POST" : "GET"),
121
+ headers: {
122
+ Authorization: `Bearer ${token}`,
123
+ ...options.body ? { "Content-Type": "application/json" } : {}
124
+ },
125
+ ...options.body ? { body: JSON.stringify(options.body) } : {}
126
+ });
127
+ return response.json().catch(() => null);
128
+ };
129
+ return { buildURL, request };
121
130
  }
131
+ function readGraphID(label, result) {
132
+ if (result?.error) {
133
+ console.error(`[naystack] ${label} failed: ${result.error.message}`);
134
+ return null;
135
+ }
136
+ return result?.id || null;
137
+ }
138
+
139
+ // src/socials/instagram/utils.ts
140
+ var client = createGraphClient("https://graph.instagram.com/v23.0");
141
+ var getInstagramData = client.request;
122
142
 
123
143
  // src/socials/instagram/getters.ts
124
144
  var getInstagramUser = (token, id, fields) => {
125
145
  return getInstagramData(token, id || "me", {
126
- fields: fields ? fields.join(",") : "username,followers_count,media_count"
146
+ params: {
147
+ fields: fields ? fields.join(",") : "username,followers_count,media_count"
148
+ }
127
149
  });
128
150
  };
151
+ var getInstagramContainerStatus = async (token, id) => {
152
+ const result = await getInstagramData(token, id, { params: { fields: "status_code,status" } });
153
+ if (!result?.status_code) return null;
154
+ return {
155
+ status: result.status_code,
156
+ error: result.status_code === "ERROR" ? result.status : void 0
157
+ };
158
+ };
129
159
 
130
- // src/socials/meta-webhook.ts
160
+ // src/socials/meta/container.ts
161
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
162
+ async function waitForContainer(getState, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
163
+ const deadline = Date.now() + timeoutMS;
164
+ let state = await getState();
165
+ if (!state) {
166
+ await sleep(2e3);
167
+ return null;
168
+ }
169
+ while (state?.status === "IN_PROGRESS" && Date.now() < deadline) {
170
+ await sleep(intervalMS);
171
+ state = await getState();
172
+ }
173
+ return state;
174
+ }
175
+ function createPublisher(platform) {
176
+ const isReady = async (token, id, label, wait) => {
177
+ const state = await waitForContainer(
178
+ () => platform.getStatus(token, id),
179
+ wait
180
+ );
181
+ if (state && state.status !== "FINISHED" && state.status !== "PUBLISHED") {
182
+ console.error(
183
+ `[naystack] ${platform.name} ${label} ${id} is ${state.status}${state.error ? `: ${state.error}` : ""}`
184
+ );
185
+ return false;
186
+ }
187
+ return true;
188
+ };
189
+ return {
190
+ /** Creates a container, waits for it to finish processing, then publishes it. */
191
+ publish: async (token, params, wait) => {
192
+ const containerID = await platform.createContainer(token, params);
193
+ if (!containerID) return null;
194
+ if (!await isReady(token, containerID, "container", wait)) return null;
195
+ return platform.publish(token, containerID);
196
+ },
197
+ /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
198
+ createChildren: async (token, items, wait) => {
199
+ const children = [];
200
+ for (const item of items) {
201
+ const childID = await platform.createContainer(token, {
202
+ ...item,
203
+ is_carousel_item: true
204
+ });
205
+ if (!childID) return null;
206
+ if (!await isReady(token, childID, "carousel item", wait))
207
+ return null;
208
+ children.push(childID);
209
+ }
210
+ return children;
211
+ }
212
+ };
213
+ }
214
+
215
+ // src/socials/instagram/setters.ts
216
+ var publisher = createPublisher({
217
+ name: "Instagram",
218
+ getStatus: getInstagramContainerStatus,
219
+ createContainer: async (token, params) => readGraphID(
220
+ "Instagram media container",
221
+ await getInstagramData(token, "me/media", {
222
+ params,
223
+ method: "POST"
224
+ })
225
+ ),
226
+ publish: async (token, creationID) => readGraphID(
227
+ "Instagram publish",
228
+ await getInstagramData(token, "me/media_publish", {
229
+ params: { creation_id: creationID },
230
+ method: "POST"
231
+ })
232
+ )
233
+ });
234
+
235
+ // src/socials/meta/webhook.ts
131
236
  import { NextResponse as NextResponse2 } from "next/server";
132
237
 
238
+ // src/socials/threads/utils.ts
239
+ var client2 = createGraphClient("https://graph.threads.net/v1.0");
240
+ var getThreadsData = client2.request;
241
+
242
+ // src/socials/threads/getters.ts
243
+ var getThreadsContainerStatus = async (token, id) => {
244
+ const result = await getThreadsData(token, id, { params: { fields: "status,error_message" } });
245
+ if (!result?.status) return null;
246
+ return { status: result.status, error: result.error_message };
247
+ };
248
+
249
+ // src/socials/threads/setters.ts
250
+ var publisher2 = createPublisher({
251
+ name: "Threads",
252
+ getStatus: getThreadsContainerStatus,
253
+ createContainer: async (token, params) => readGraphID(
254
+ "Threads container",
255
+ await getThreadsData(token, "me/threads", {
256
+ params,
257
+ method: "POST"
258
+ })
259
+ ),
260
+ publish: async (token, creationID) => readGraphID(
261
+ "Threads publish",
262
+ await getThreadsData(token, "me/threads_publish", {
263
+ params: { creation_id: creationID },
264
+ method: "POST"
265
+ })
266
+ )
267
+ });
268
+
133
269
  // src/auth/instagram/route.ts
134
270
  var getInstagramRoute = ({
135
271
  redirectURL,
136
272
  errorRedirectURL,
137
- onUser
273
+ onUser,
274
+ scopes
138
275
  }) => {
139
276
  const handleError = (message) => NextResponse3.redirect(`${errorRedirectURL}?error=${message}`);
140
277
  return async (req) => {
@@ -144,7 +281,10 @@ var getInstagramRoute = ({
144
281
  if (error) return handleError(error);
145
282
  if (!accessCode) {
146
283
  if (!stateToken) return handleError("Invalid request");
147
- return NextResponse3.redirect(getInstagramAuthorizationURL(stateToken), 302);
284
+ return NextResponse3.redirect(
285
+ getInstagramAuthorizationURL(stateToken, scopes),
286
+ 302
287
+ );
148
288
  }
149
289
  if (!stateToken) return handleError("Invalid request");
150
290
  const instagramData = await getLongLivedToken(
@@ -112,9 +112,9 @@ async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
112
112
  }
113
113
  }
114
114
  }
115
- var getInstagramAuthorizationURL = (token) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
115
+ var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
116
116
  "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
117
- )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=instagram_business_basic&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
117
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
118
118
  // Annotate the CommonJS export names for ESM import in node:
119
119
  0 && (module.exports = {
120
120
  getInstagramAuthorizationURL,
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Permissions requestable during Instagram Login OAuth. `instagram_business_basic`
3
+ * is enough to read a profile; publishing needs `instagram_business_content_publish`.
4
+ *
5
+ * Widening the scopes only affects users who authorize afterwards — tokens already
6
+ * stored keep the permissions they were granted, so existing users must reconnect.
7
+ *
8
+ * @category Auth
9
+ */
10
+ type InstagramScope = "instagram_business_basic" | "instagram_business_content_publish" | "instagram_business_manage_messages" | "instagram_business_manage_comments" | "instagram_business_manage_insights";
1
11
  /**
2
12
  * Exchanges a long-lived Instagram token for a refreshed token.
3
13
  * @param token - Current long-lived access token
@@ -29,6 +39,7 @@ declare function getLongLivedToken(code: string, redirectURL: string, clientId:
29
39
  * simply built on the server instead of shipped in the client bundle.
30
40
  *
31
41
  * @param token - The state token to embed in the authorization URL (typically the user's session or access token).
42
+ * @param scopes - Permissions to request. Default: `["instagram_business_basic"]`.
32
43
  * @returns The full Instagram OAuth authorization URL.
33
44
  *
34
45
  * @example
@@ -41,6 +52,6 @@ declare function getLongLivedToken(code: string, redirectURL: string, clientId:
41
52
  *
42
53
  * @category Auth
43
54
  */
44
- declare const getInstagramAuthorizationURL: (token: string) => string;
55
+ declare const getInstagramAuthorizationURL: (token: string, scopes?: InstagramScope[]) => string;
45
56
 
46
- export { getInstagramAuthorizationURL, getLongLivedToken, getRefreshedInstagramAccessToken };
57
+ export { type InstagramScope, getInstagramAuthorizationURL, getLongLivedToken, getRefreshedInstagramAccessToken };
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Permissions requestable during Instagram Login OAuth. `instagram_business_basic`
3
+ * is enough to read a profile; publishing needs `instagram_business_content_publish`.
4
+ *
5
+ * Widening the scopes only affects users who authorize afterwards — tokens already
6
+ * stored keep the permissions they were granted, so existing users must reconnect.
7
+ *
8
+ * @category Auth
9
+ */
10
+ type InstagramScope = "instagram_business_basic" | "instagram_business_content_publish" | "instagram_business_manage_messages" | "instagram_business_manage_comments" | "instagram_business_manage_insights";
1
11
  /**
2
12
  * Exchanges a long-lived Instagram token for a refreshed token.
3
13
  * @param token - Current long-lived access token
@@ -29,6 +39,7 @@ declare function getLongLivedToken(code: string, redirectURL: string, clientId:
29
39
  * simply built on the server instead of shipped in the client bundle.
30
40
  *
31
41
  * @param token - The state token to embed in the authorization URL (typically the user's session or access token).
42
+ * @param scopes - Permissions to request. Default: `["instagram_business_basic"]`.
32
43
  * @returns The full Instagram OAuth authorization URL.
33
44
  *
34
45
  * @example
@@ -41,6 +52,6 @@ declare function getLongLivedToken(code: string, redirectURL: string, clientId:
41
52
  *
42
53
  * @category Auth
43
54
  */
44
- declare const getInstagramAuthorizationURL: (token: string) => string;
55
+ declare const getInstagramAuthorizationURL: (token: string, scopes?: InstagramScope[]) => string;
45
56
 
46
- export { getInstagramAuthorizationURL, getLongLivedToken, getRefreshedInstagramAccessToken };
57
+ export { type InstagramScope, getInstagramAuthorizationURL, getLongLivedToken, getRefreshedInstagramAccessToken };
@@ -84,9 +84,9 @@ async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
84
84
  }
85
85
  }
86
86
  }
87
- var getInstagramAuthorizationURL = (token) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
87
+ var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
88
88
  "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
89
- )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=instagram_business_basic&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
89
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${token}&redirect_uri=${getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */)}#weblink`;
90
90
  export {
91
91
  getInstagramAuthorizationURL,
92
92
  getLongLivedToken,
@@ -165,14 +165,15 @@ var getDownloadURL = (keys) => {
165
165
  };
166
166
  var uploadFile = async (keys, {
167
167
  url,
168
- blob
168
+ blob,
169
+ put
169
170
  }) => {
170
171
  if (!checkClient(client)) return;
171
172
  if (!blob && !url) return null;
172
173
  const fileBlob = blob || await fetch(url).then((file) => file.blob());
173
174
  if (fileBlob) {
174
175
  const key = getKey(keys);
175
- await uploadBlob(fileBlob, key);
176
+ await uploadBlob(fileBlob, key, put);
176
177
  return getDownloadURL(key);
177
178
  }
178
179
  return null;
@@ -199,7 +200,7 @@ function checkClient(client2) {
199
200
  if (!client2) throw new Error("Client does not exist");
200
201
  return true;
201
202
  }
202
- var uploadBlob = async (file, key) => {
203
+ var uploadBlob = async (file, key, overrides) => {
203
204
  if (!checkClient(client)) return;
204
205
  const fileBuffer = await file.arrayBuffer();
205
206
  return client.send(
@@ -209,7 +210,8 @@ var uploadBlob = async (file, key) => {
209
210
  ACL: "public-read",
210
211
  Body: Buffer.from(fileBuffer),
211
212
  ContentType: file.type,
212
- ContentLength: file.size
213
+ ContentLength: file.size,
214
+ ...overrides
213
215
  })
214
216
  );
215
217
  };
@@ -232,8 +234,9 @@ var getFileUploadPutRoute = (options) => async (req) => {
232
234
  const fileKey = options.getKey ? await options.getKey(inputData) : (0, import_uuid.v4)();
233
235
  const url = getDownloadURL(fileKey);
234
236
  const blob = options.processFile ? await options.processFile(file, inputData) : file;
235
- if (async) (0, import_functions.waitUntil)(uploadBlob(blob, fileKey));
236
- else await uploadBlob(blob, fileKey);
237
+ const put = options.putOptions?.(inputData);
238
+ if (async) (0, import_functions.waitUntil)(uploadBlob(blob, fileKey, put));
239
+ else await uploadBlob(blob, fileKey, put);
237
240
  const onUploadResponse = await options.onUpload({
238
241
  ...inputData,
239
242
  url
@@ -1,4 +1,4 @@
1
1
  export { setupFileUpload } from './setup.mjs';
2
- export { deleteFile, getDownloadURL, getUploadURL, uploadFile } from './utils.mjs';
2
+ export { PutOverrides, deleteFile, getDownloadURL, getUploadURL, uploadFile } from './utils.mjs';
3
3
  import 'next/server';
4
4
  import '@aws-sdk/client-s3';
@@ -1,4 +1,4 @@
1
1
  export { setupFileUpload } from './setup.js';
2
- export { deleteFile, getDownloadURL, getUploadURL, uploadFile } from './utils.js';
2
+ export { PutOverrides, deleteFile, getDownloadURL, getUploadURL, uploadFile } from './utils.js';
3
3
  import 'next/server';
4
4
  import '@aws-sdk/client-s3';
@@ -139,14 +139,15 @@ var getDownloadURL = (keys) => {
139
139
  };
140
140
  var uploadFile = async (keys, {
141
141
  url,
142
- blob
142
+ blob,
143
+ put
143
144
  }) => {
144
145
  if (!checkClient(client)) return;
145
146
  if (!blob && !url) return null;
146
147
  const fileBlob = blob || await fetch(url).then((file) => file.blob());
147
148
  if (fileBlob) {
148
149
  const key = getKey(keys);
149
- await uploadBlob(fileBlob, key);
150
+ await uploadBlob(fileBlob, key, put);
150
151
  return getDownloadURL(key);
151
152
  }
152
153
  return null;
@@ -173,7 +174,7 @@ function checkClient(client2) {
173
174
  if (!client2) throw new Error("Client does not exist");
174
175
  return true;
175
176
  }
176
- var uploadBlob = async (file, key) => {
177
+ var uploadBlob = async (file, key, overrides) => {
177
178
  if (!checkClient(client)) return;
178
179
  const fileBuffer = await file.arrayBuffer();
179
180
  return client.send(
@@ -183,7 +184,8 @@ var uploadBlob = async (file, key) => {
183
184
  ACL: "public-read",
184
185
  Body: Buffer.from(fileBuffer),
185
186
  ContentType: file.type,
186
- ContentLength: file.size
187
+ ContentLength: file.size,
188
+ ...overrides
187
189
  })
188
190
  );
189
191
  };
@@ -206,8 +208,9 @@ var getFileUploadPutRoute = (options) => async (req) => {
206
208
  const fileKey = options.getKey ? await options.getKey(inputData) : v4();
207
209
  const url = getDownloadURL(fileKey);
208
210
  const blob = options.processFile ? await options.processFile(file, inputData) : file;
209
- if (async) waitUntil(uploadBlob(blob, fileKey));
210
- else await uploadBlob(blob, fileKey);
211
+ const put = options.putOptions?.(inputData);
212
+ if (async) waitUntil(uploadBlob(blob, fileKey, put));
213
+ else await uploadBlob(blob, fileKey, put);
211
214
  const onUploadResponse = await options.onUpload({
212
215
  ...inputData,
213
216
  url