naystack 1.8.18 → 1.9.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.
Files changed (122) hide show
  1. package/README.md +94 -34
  2. package/dist/auth/client.cjs.js +2 -2
  3. package/dist/auth/client.esm.js +2 -2
  4. package/dist/auth/email/client.cjs.js +2 -2
  5. package/dist/auth/email/client.esm.js +2 -2
  6. package/dist/auth/email/index.cjs.js +2 -2
  7. package/dist/auth/email/index.esm.js +2 -2
  8. package/dist/auth/email/next.cjs.js +2 -2
  9. package/dist/auth/email/next.esm.js +2 -2
  10. package/dist/auth/email/routes/delete.cjs.js +2 -2
  11. package/dist/auth/email/routes/delete.esm.js +2 -2
  12. package/dist/auth/email/routes/get.cjs.js +2 -2
  13. package/dist/auth/email/routes/get.esm.js +2 -2
  14. package/dist/auth/email/routes/post.cjs.js +2 -2
  15. package/dist/auth/email/routes/post.esm.js +2 -2
  16. package/dist/auth/email/routes/put.cjs.js +2 -2
  17. package/dist/auth/email/routes/put.esm.js +2 -2
  18. package/dist/auth/email/token.cjs.js +2 -2
  19. package/dist/auth/email/token.esm.js +2 -2
  20. package/dist/auth/email/utils.cjs.js +2 -2
  21. package/dist/auth/email/utils.esm.js +2 -2
  22. package/dist/auth/google/get.cjs.js +2 -2
  23. package/dist/auth/google/get.esm.js +2 -2
  24. package/dist/auth/google/index.cjs.js +2 -2
  25. package/dist/auth/google/index.esm.js +2 -2
  26. package/dist/auth/index.cjs.js +4 -297
  27. package/dist/auth/index.d.mts +0 -5
  28. package/dist/auth/index.d.ts +0 -5
  29. package/dist/auth/index.esm.js +3 -293
  30. package/dist/auth/token-store.cjs.js +2 -2
  31. package/dist/auth/token-store.esm.js +2 -2
  32. package/dist/env.cjs.js +3 -3
  33. package/dist/env.d.mts +3 -2
  34. package/dist/env.d.ts +3 -2
  35. package/dist/env.esm.js +3 -3
  36. package/dist/file/client.cjs.js +2 -2
  37. package/dist/file/client.esm.js +2 -2
  38. package/dist/file/index.cjs.js +2 -2
  39. package/dist/file/index.esm.js +2 -2
  40. package/dist/file/put.cjs.js +2 -2
  41. package/dist/file/put.esm.js +2 -2
  42. package/dist/file/setup.cjs.js +2 -2
  43. package/dist/file/setup.esm.js +2 -2
  44. package/dist/file/utils.cjs.js +2 -2
  45. package/dist/file/utils.esm.js +2 -2
  46. package/dist/graphql/client.cjs.js +2 -2
  47. package/dist/graphql/client.esm.js +2 -2
  48. package/dist/graphql/index.cjs.js +2 -2
  49. package/dist/graphql/index.esm.js +2 -2
  50. package/dist/graphql/init.cjs.js +2 -2
  51. package/dist/graphql/init.esm.js +2 -2
  52. package/dist/graphql/links.cjs.js +2 -2
  53. package/dist/graphql/links.esm.js +2 -2
  54. package/dist/graphql/next.cjs.js +2 -2
  55. package/dist/graphql/next.esm.js +2 -2
  56. package/dist/graphql/server.cjs.js +2 -2
  57. package/dist/graphql/server.esm.js +2 -2
  58. package/dist/graphql/utils.cjs.js +2 -2
  59. package/dist/graphql/utils.esm.js +2 -2
  60. package/dist/socials/connect.cjs.js +151 -0
  61. package/dist/socials/connect.d.mts +70 -0
  62. package/dist/socials/connect.d.ts +70 -0
  63. package/dist/socials/connect.esm.js +126 -0
  64. package/dist/socials/index.cjs.js +367 -35
  65. package/dist/socials/index.d.mts +8 -2
  66. package/dist/socials/index.d.ts +8 -2
  67. package/dist/socials/index.esm.js +357 -34
  68. package/dist/socials/instagram/adapter.cjs.js +275 -0
  69. package/dist/socials/instagram/adapter.d.mts +30 -0
  70. package/dist/socials/instagram/adapter.d.ts +30 -0
  71. package/dist/socials/instagram/adapter.esm.js +248 -0
  72. package/dist/{auth/instagram/utils.cjs.js → socials/instagram/auth.cjs.js} +43 -41
  73. package/dist/socials/instagram/auth.d.mts +52 -0
  74. package/dist/socials/instagram/auth.d.ts +52 -0
  75. package/dist/{auth/instagram/utils.esm.js → socials/instagram/auth.esm.js} +37 -35
  76. package/dist/socials/instagram/getters.d.mts +1 -0
  77. package/dist/socials/instagram/getters.d.ts +1 -0
  78. package/dist/socials/instagram/setters.cjs.js +56 -31
  79. package/dist/socials/instagram/setters.d.mts +1 -0
  80. package/dist/socials/instagram/setters.d.ts +1 -0
  81. package/dist/socials/instagram/setters.esm.js +56 -31
  82. package/dist/socials/instagram/types.d.mts +2 -1
  83. package/dist/socials/instagram/types.d.ts +2 -1
  84. package/dist/socials/meta/container.cjs.js +57 -30
  85. package/dist/socials/meta/container.d.mts +15 -28
  86. package/dist/socials/meta/container.d.ts +15 -28
  87. package/dist/socials/meta/container.esm.js +56 -31
  88. package/dist/socials/provider.cjs.js +18 -0
  89. package/dist/socials/provider.d.mts +52 -0
  90. package/dist/socials/provider.d.ts +52 -0
  91. package/dist/socials/provider.esm.js +0 -0
  92. package/dist/socials/threads/getters.d.mts +1 -0
  93. package/dist/socials/threads/getters.d.ts +1 -0
  94. package/dist/socials/threads/setters.cjs.js +56 -31
  95. package/dist/socials/threads/setters.d.mts +1 -0
  96. package/dist/socials/threads/setters.d.ts +1 -0
  97. package/dist/socials/threads/setters.esm.js +56 -31
  98. package/dist/socials/threads/types.d.mts +2 -1
  99. package/dist/socials/threads/types.d.ts +2 -1
  100. package/dist/socials/types.cjs.js +43 -0
  101. package/dist/socials/types.d.mts +99 -0
  102. package/dist/socials/types.d.ts +99 -0
  103. package/dist/socials/types.esm.js +17 -0
  104. package/dist/socials/utils/poll.cjs.js +59 -0
  105. package/dist/socials/utils/poll.d.mts +85 -0
  106. package/dist/socials/utils/poll.d.ts +85 -0
  107. package/dist/socials/utils/poll.esm.js +33 -0
  108. package/dist/utils/client/index.cjs.js +2 -2
  109. package/dist/utils/client/index.esm.js +2 -2
  110. package/dist/utils/client/seo.cjs.js +2 -2
  111. package/dist/utils/client/seo.esm.js +2 -2
  112. package/package.json +1 -1
  113. package/dist/auth/instagram/index.cjs.js +0 -379
  114. package/dist/auth/instagram/index.d.mts +0 -58
  115. package/dist/auth/instagram/index.d.ts +0 -58
  116. package/dist/auth/instagram/index.esm.js +0 -350
  117. package/dist/auth/instagram/route.cjs.js +0 -359
  118. package/dist/auth/instagram/route.d.mts +0 -15
  119. package/dist/auth/instagram/route.d.ts +0 -15
  120. package/dist/auth/instagram/route.esm.js +0 -334
  121. package/dist/auth/instagram/utils.d.mts +0 -57
  122. package/dist/auth/instagram/utils.d.ts +0 -57
@@ -17,14 +17,14 @@ var __copyProps = (to, from, except, desc) => {
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
- // src/auth/instagram/utils.ts
21
- var utils_exports = {};
22
- __export(utils_exports, {
20
+ // src/socials/instagram/auth.ts
21
+ var auth_exports = {};
22
+ __export(auth_exports, {
23
23
  getInstagramAuthorizationURL: () => getInstagramAuthorizationURL,
24
- getLongLivedToken: () => getLongLivedToken,
25
- getRefreshedInstagramAccessToken: () => getRefreshedInstagramAccessToken
24
+ getLongLivedInstagramToken: () => getLongLivedInstagramToken,
25
+ refreshInstagramAccessToken: () => refreshInstagramAccessToken
26
26
  });
27
- module.exports = __toCommonJS(utils_exports);
27
+ module.exports = __toCommonJS(auth_exports);
28
28
 
29
29
  // src/env.ts
30
30
  var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
@@ -36,8 +36,8 @@ var getEnvValue = (key) => {
36
36
  return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
37
37
  case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
38
38
  return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
39
- case "NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */:
40
- return process.env.NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT || EXTRA_ENV.INSTAGRAM_AUTH_ENDPOINT;
39
+ case "NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT" /* NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT */:
40
+ return process.env.NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT || EXTRA_ENV.SOCIAL_AUTH_ENDPOINT;
41
41
  case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
42
42
  return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
43
43
  case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
@@ -76,48 +76,50 @@ function getEnv(key, skipCheck) {
76
76
  return value;
77
77
  }
78
78
 
79
- // src/auth/instagram/utils.ts
80
- async function getRefreshedInstagramAccessToken(token) {
81
- const request = await fetch(
82
- `https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
83
- );
84
- const response = await request.json();
85
- return response.access_token;
86
- }
87
- async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
79
+ // src/socials/instagram/auth.ts
80
+ var getInstagramAuthorizationURL = (state, redirectURI, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
81
+ "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
82
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${state}&redirect_uri=${redirectURI}#weblink`;
83
+ async function getLongLivedInstagramToken(code, redirectURI) {
88
84
  const formData = new FormData();
89
- formData.set("client_id", clientId);
90
- formData.set("client_secret", clientSecret);
85
+ formData.set("client_id", getEnv("INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */));
86
+ formData.set("client_secret", getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */));
91
87
  formData.set("grant_type", "authorization_code");
92
- formData.set("redirect_uri", redirectURL);
88
+ formData.set("redirect_uri", redirectURI);
93
89
  formData.set("code", code);
94
90
  const shortRes = await fetch("https://api.instagram.com/oauth/access_token", {
95
91
  method: "POST",
96
92
  body: formData
97
93
  });
98
- if (shortRes.ok) {
99
- const shortResData = await shortRes.json();
100
- if (shortResData.access_token) {
101
- const shortLivedToken = shortResData.access_token;
102
- const longRes = await fetch(
103
- `https://graph.instagram.com/access_token?grant_type=ig_exchange_token&access_token=${shortLivedToken}&client_secret=${getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */)}`
104
- );
105
- if (longRes.ok) {
106
- const longResData = await longRes.json();
107
- return {
108
- accessToken: longResData.access_token,
109
- userId: shortResData.user_id
110
- };
111
- }
112
- }
113
- }
94
+ if (!shortRes.ok) return void 0;
95
+ const shortResData = await shortRes.json();
96
+ if (!shortResData.access_token) return void 0;
97
+ const longRes = await fetch(
98
+ `https://graph.instagram.com/access_token?grant_type=ig_exchange_token&access_token=${shortResData.access_token}&client_secret=${getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */)}`
99
+ );
100
+ if (!longRes.ok) return void 0;
101
+ const longResData = await longRes.json();
102
+ return {
103
+ accessToken: longResData.access_token,
104
+ userId: shortResData.user_id,
105
+ expiresIn: longResData.expires_in,
106
+ permissions: shortResData.permissions
107
+ };
108
+ }
109
+ async function refreshInstagramAccessToken(token) {
110
+ const request = await fetch(
111
+ `https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
112
+ );
113
+ const response = await request.json();
114
+ if (!response.access_token) return void 0;
115
+ return {
116
+ accessToken: response.access_token,
117
+ expiresIn: response.expires_in
118
+ };
114
119
  }
115
- var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
116
- "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
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
120
  // Annotate the CommonJS export names for ESM import in node:
119
121
  0 && (module.exports = {
120
122
  getInstagramAuthorizationURL,
121
- getLongLivedToken,
122
- getRefreshedInstagramAccessToken
123
+ getLongLivedInstagramToken,
124
+ refreshInstagramAccessToken
123
125
  });
@@ -0,0 +1,52 @@
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 Socials
9
+ */
10
+ type InstagramScope = "instagram_business_basic" | "instagram_business_content_publish" | "instagram_business_manage_messages" | "instagram_business_manage_comments" | "instagram_business_manage_insights";
11
+ /**
12
+ * Builds the Instagram OAuth authorization URL.
13
+ *
14
+ * **Server-only** — reads the non-public `INSTAGRAM_CLIENT_ID`. The client id still
15
+ * ends up in the URL the browser follows; it is simply built here rather than
16
+ * shipped in the client bundle.
17
+ *
18
+ * @param state - Passed back by Instagram on the callback; typically the logged-in user's access token.
19
+ * @param redirectURI - Where Instagram sends the user back. Must match a URI registered with Meta verbatim.
20
+ * @param scopes - Default: `["instagram_business_basic"]`.
21
+ *
22
+ * @category Socials
23
+ */
24
+ declare const getInstagramAuthorizationURL: (state: string, redirectURI: string, scopes?: InstagramScope[]) => string;
25
+ /**
26
+ * Exchanges an OAuth code for a long-lived Instagram access token.
27
+ *
28
+ * @param code - Authorization code from the callback.
29
+ * @param redirectURI - The same URI used to obtain the code.
30
+ * @returns `{ accessToken, userId, expiresIn, permissions }`, or `undefined` if either exchange failed.
31
+ *
32
+ * @category Socials
33
+ */
34
+ declare function getLongLivedInstagramToken(code: string, redirectURI: string): Promise<{
35
+ accessToken: string;
36
+ userId: string | undefined;
37
+ expiresIn: number;
38
+ permissions: string[] | undefined;
39
+ } | undefined>;
40
+ /**
41
+ * Refreshes a long-lived Instagram token.
42
+ *
43
+ * @returns `{ accessToken, expiresIn }` (seconds), or `undefined` if the refresh failed.
44
+ *
45
+ * @category Socials
46
+ */
47
+ declare function refreshInstagramAccessToken(token: string): Promise<{
48
+ accessToken: string;
49
+ expiresIn: number | undefined;
50
+ } | undefined>;
51
+
52
+ export { type InstagramScope, getInstagramAuthorizationURL, getLongLivedInstagramToken, refreshInstagramAccessToken };
@@ -0,0 +1,52 @@
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 Socials
9
+ */
10
+ type InstagramScope = "instagram_business_basic" | "instagram_business_content_publish" | "instagram_business_manage_messages" | "instagram_business_manage_comments" | "instagram_business_manage_insights";
11
+ /**
12
+ * Builds the Instagram OAuth authorization URL.
13
+ *
14
+ * **Server-only** — reads the non-public `INSTAGRAM_CLIENT_ID`. The client id still
15
+ * ends up in the URL the browser follows; it is simply built here rather than
16
+ * shipped in the client bundle.
17
+ *
18
+ * @param state - Passed back by Instagram on the callback; typically the logged-in user's access token.
19
+ * @param redirectURI - Where Instagram sends the user back. Must match a URI registered with Meta verbatim.
20
+ * @param scopes - Default: `["instagram_business_basic"]`.
21
+ *
22
+ * @category Socials
23
+ */
24
+ declare const getInstagramAuthorizationURL: (state: string, redirectURI: string, scopes?: InstagramScope[]) => string;
25
+ /**
26
+ * Exchanges an OAuth code for a long-lived Instagram access token.
27
+ *
28
+ * @param code - Authorization code from the callback.
29
+ * @param redirectURI - The same URI used to obtain the code.
30
+ * @returns `{ accessToken, userId, expiresIn, permissions }`, or `undefined` if either exchange failed.
31
+ *
32
+ * @category Socials
33
+ */
34
+ declare function getLongLivedInstagramToken(code: string, redirectURI: string): Promise<{
35
+ accessToken: string;
36
+ userId: string | undefined;
37
+ expiresIn: number;
38
+ permissions: string[] | undefined;
39
+ } | undefined>;
40
+ /**
41
+ * Refreshes a long-lived Instagram token.
42
+ *
43
+ * @returns `{ accessToken, expiresIn }` (seconds), or `undefined` if the refresh failed.
44
+ *
45
+ * @category Socials
46
+ */
47
+ declare function refreshInstagramAccessToken(token: string): Promise<{
48
+ accessToken: string;
49
+ expiresIn: number | undefined;
50
+ } | undefined>;
51
+
52
+ export { type InstagramScope, getInstagramAuthorizationURL, getLongLivedInstagramToken, refreshInstagramAccessToken };
@@ -8,8 +8,8 @@ var getEnvValue = (key) => {
8
8
  return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
9
9
  case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
10
10
  return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
11
- case "NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */:
12
- return process.env.NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT || EXTRA_ENV.INSTAGRAM_AUTH_ENDPOINT;
11
+ case "NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT" /* NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT */:
12
+ return process.env.NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT || EXTRA_ENV.SOCIAL_AUTH_ENDPOINT;
13
13
  case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
14
14
  return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
15
15
  case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
@@ -48,47 +48,49 @@ function getEnv(key, skipCheck) {
48
48
  return value;
49
49
  }
50
50
 
51
- // src/auth/instagram/utils.ts
52
- async function getRefreshedInstagramAccessToken(token) {
53
- const request = await fetch(
54
- `https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
55
- );
56
- const response = await request.json();
57
- return response.access_token;
58
- }
59
- async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
51
+ // src/socials/instagram/auth.ts
52
+ var getInstagramAuthorizationURL = (state, redirectURI, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
53
+ "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
54
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${state}&redirect_uri=${redirectURI}#weblink`;
55
+ async function getLongLivedInstagramToken(code, redirectURI) {
60
56
  const formData = new FormData();
61
- formData.set("client_id", clientId);
62
- formData.set("client_secret", clientSecret);
57
+ formData.set("client_id", getEnv("INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */));
58
+ formData.set("client_secret", getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */));
63
59
  formData.set("grant_type", "authorization_code");
64
- formData.set("redirect_uri", redirectURL);
60
+ formData.set("redirect_uri", redirectURI);
65
61
  formData.set("code", code);
66
62
  const shortRes = await fetch("https://api.instagram.com/oauth/access_token", {
67
63
  method: "POST",
68
64
  body: formData
69
65
  });
70
- if (shortRes.ok) {
71
- const shortResData = await shortRes.json();
72
- if (shortResData.access_token) {
73
- const shortLivedToken = shortResData.access_token;
74
- const longRes = await fetch(
75
- `https://graph.instagram.com/access_token?grant_type=ig_exchange_token&access_token=${shortLivedToken}&client_secret=${getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */)}`
76
- );
77
- if (longRes.ok) {
78
- const longResData = await longRes.json();
79
- return {
80
- accessToken: longResData.access_token,
81
- userId: shortResData.user_id
82
- };
83
- }
84
- }
85
- }
66
+ if (!shortRes.ok) return void 0;
67
+ const shortResData = await shortRes.json();
68
+ if (!shortResData.access_token) return void 0;
69
+ const longRes = await fetch(
70
+ `https://graph.instagram.com/access_token?grant_type=ig_exchange_token&access_token=${shortResData.access_token}&client_secret=${getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */)}`
71
+ );
72
+ if (!longRes.ok) return void 0;
73
+ const longResData = await longRes.json();
74
+ return {
75
+ accessToken: longResData.access_token,
76
+ userId: shortResData.user_id,
77
+ expiresIn: longResData.expires_in,
78
+ permissions: shortResData.permissions
79
+ };
80
+ }
81
+ async function refreshInstagramAccessToken(token) {
82
+ const request = await fetch(
83
+ `https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
84
+ );
85
+ const response = await request.json();
86
+ if (!response.access_token) return void 0;
87
+ return {
88
+ accessToken: response.access_token,
89
+ expiresIn: response.expires_in
90
+ };
86
91
  }
87
- var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
88
- "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
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
92
  export {
91
93
  getInstagramAuthorizationURL,
92
- getLongLivedToken,
93
- getRefreshedInstagramAccessToken
94
+ getLongLivedInstagramToken,
95
+ refreshInstagramAccessToken
94
96
  };
@@ -1,6 +1,7 @@
1
1
  import { GraphError, ContainerState } from '../meta/types.mjs';
2
2
  import { InstagramConversation, InstagramMedia, InstagramMessage, InstagramUser } from './types.mjs';
3
3
  import '../meta/container.mjs';
4
+ import '../utils/poll.mjs';
4
5
 
5
6
  /**
6
7
  * Fetches an Instagram user's profile. Defaults to the authenticated user (`"me"`).
@@ -1,6 +1,7 @@
1
1
  import { GraphError, ContainerState } from '../meta/types.js';
2
2
  import { InstagramConversation, InstagramMedia, InstagramMessage, InstagramUser } from './types.js';
3
3
  import '../meta/container.js';
4
+ import '../utils/poll.js';
4
5
 
5
6
  /**
6
7
  * Fetches an Instagram user's profile. Defaults to the authenticated user (`"me"`).
@@ -71,25 +71,42 @@ var getInstagramContainerStatus = async (token, id) => {
71
71
  };
72
72
  };
73
73
 
74
- // src/socials/meta/container.ts
74
+ // src/socials/utils/poll.ts
75
75
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
76
- async function waitForContainer(getState, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
76
+ async function pollUntilReady(read, isPending, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
77
77
  const deadline = Date.now() + timeoutMS;
78
- let state = await getState();
78
+ let state = await read();
79
79
  if (!state) {
80
80
  await sleep(2e3);
81
81
  return null;
82
82
  }
83
- while (state?.status === "IN_PROGRESS" && Date.now() < deadline) {
83
+ while (state && isPending(state) && Date.now() < deadline) {
84
84
  await sleep(intervalMS);
85
- state = await getState();
85
+ state = await read();
86
86
  }
87
87
  return state;
88
88
  }
89
+ async function withRetry(run, options = {}) {
90
+ const attempts = Math.max(1, options.attempts ?? 3);
91
+ const backoffMS = options.backoffMS ?? 2e3;
92
+ for (let attempt = 1; attempt <= attempts; attempt++) {
93
+ const result = await run(attempt);
94
+ if (result) return result;
95
+ if (attempt < attempts) {
96
+ const delayMS = backoffMS * 2 ** (attempt - 1);
97
+ options.onRetry?.(attempt, attempts, delayMS);
98
+ await sleep(delayMS);
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+
104
+ // src/socials/meta/container.ts
89
105
  function createPublisher(platform) {
90
106
  const isReady = async (token, id, label, wait) => {
91
- const state = await waitForContainer(
107
+ const state = await pollUntilReady(
92
108
  () => platform.getStatus(token, id),
109
+ (current) => current.status === "IN_PROGRESS",
93
110
  wait
94
111
  );
95
112
  if (state && state.status !== "FINISHED" && state.status !== "PUBLISHED") {
@@ -100,22 +117,21 @@ function createPublisher(platform) {
100
117
  }
101
118
  return true;
102
119
  };
103
- const createReady = async (token, params, label, wait, retry) => {
104
- const attempts = Math.max(1, retry?.attempts ?? 3);
105
- const backoffMS = retry?.backoffMS ?? 2e3;
106
- for (let attempt = 1; attempt <= attempts; attempt++) {
120
+ const createReady = (token, params, label, wait, retry) => withRetry(
121
+ async () => {
107
122
  const id = await platform.createContainer(token, params);
108
- if (id && await isReady(token, id, label, wait)) return id;
109
- if (attempt < attempts) {
110
- const delay = backoffMS * 2 ** (attempt - 1);
123
+ if (!id || !await isReady(token, id, label, wait)) return null;
124
+ return id;
125
+ },
126
+ {
127
+ ...retry,
128
+ onRetry: (attempt, attempts, delayMS) => {
111
129
  console.warn(
112
- `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
130
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delayMS}ms`
113
131
  );
114
- await sleep(delay);
115
132
  }
116
133
  }
117
- return null;
118
- };
134
+ );
119
135
  return {
120
136
  /** Creates a container, waits for it to finish processing, then publishes it. */
121
137
  publish: async (token, params, wait, retry) => {
@@ -129,21 +145,30 @@ function createPublisher(platform) {
129
145
  if (!containerID) return null;
130
146
  return platform.publish(token, containerID);
131
147
  },
132
- /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
148
+ /**
149
+ * Creates and awaits every carousel child **in parallel**, resolving to
150
+ * their ids in input order — or `null` if any failed.
151
+ *
152
+ * Parallel because each child is an independent create-then-poll and Meta
153
+ * spends ~5s accepting a single container, so ten sequential children cost
154
+ * ~50s of mostly waiting — past what a serverless caller can fit in its
155
+ * timeout. `Promise.all` preserves input order, which the carousel's slide
156
+ * order depends on.
157
+ */
133
158
  createChildren: async (token, items, wait, retry) => {
134
- const children = [];
135
- for (const item of items) {
136
- const childID = await createReady(
137
- token,
138
- { ...item, is_carousel_item: true },
139
- "carousel item",
140
- wait,
141
- retry
142
- );
143
- if (!childID) return null;
144
- children.push(childID);
145
- }
146
- return children;
159
+ const children = await Promise.all(
160
+ items.map(
161
+ (item) => createReady(
162
+ token,
163
+ { ...item, is_carousel_item: true },
164
+ "carousel item",
165
+ wait,
166
+ retry
167
+ )
168
+ )
169
+ );
170
+ const created = children.filter((childID) => childID !== null);
171
+ return created.length === children.length ? created : null;
147
172
  }
148
173
  };
149
174
  }
@@ -1,6 +1,7 @@
1
1
  import { GraphError } from '../meta/types.mjs';
2
2
  import { InstagramPostInput } from './types.mjs';
3
3
  import '../meta/container.mjs';
4
+ import '../utils/poll.mjs';
4
5
 
5
6
  /**
6
7
  * Publishes to Instagram — feed image, reel, story or carousel, chosen from the
@@ -1,6 +1,7 @@
1
1
  import { GraphError } from '../meta/types.js';
2
2
  import { InstagramPostInput } from './types.js';
3
3
  import '../meta/container.js';
4
+ import '../utils/poll.js';
4
5
 
5
6
  /**
6
7
  * Publishes to Instagram — feed image, reel, story or carousel, chosen from the
@@ -43,25 +43,42 @@ var getInstagramContainerStatus = async (token, id) => {
43
43
  };
44
44
  };
45
45
 
46
- // src/socials/meta/container.ts
46
+ // src/socials/utils/poll.ts
47
47
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
48
- async function waitForContainer(getState, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
48
+ async function pollUntilReady(read, isPending, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
49
49
  const deadline = Date.now() + timeoutMS;
50
- let state = await getState();
50
+ let state = await read();
51
51
  if (!state) {
52
52
  await sleep(2e3);
53
53
  return null;
54
54
  }
55
- while (state?.status === "IN_PROGRESS" && Date.now() < deadline) {
55
+ while (state && isPending(state) && Date.now() < deadline) {
56
56
  await sleep(intervalMS);
57
- state = await getState();
57
+ state = await read();
58
58
  }
59
59
  return state;
60
60
  }
61
+ async function withRetry(run, options = {}) {
62
+ const attempts = Math.max(1, options.attempts ?? 3);
63
+ const backoffMS = options.backoffMS ?? 2e3;
64
+ for (let attempt = 1; attempt <= attempts; attempt++) {
65
+ const result = await run(attempt);
66
+ if (result) return result;
67
+ if (attempt < attempts) {
68
+ const delayMS = backoffMS * 2 ** (attempt - 1);
69
+ options.onRetry?.(attempt, attempts, delayMS);
70
+ await sleep(delayMS);
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+
76
+ // src/socials/meta/container.ts
61
77
  function createPublisher(platform) {
62
78
  const isReady = async (token, id, label, wait) => {
63
- const state = await waitForContainer(
79
+ const state = await pollUntilReady(
64
80
  () => platform.getStatus(token, id),
81
+ (current) => current.status === "IN_PROGRESS",
65
82
  wait
66
83
  );
67
84
  if (state && state.status !== "FINISHED" && state.status !== "PUBLISHED") {
@@ -72,22 +89,21 @@ function createPublisher(platform) {
72
89
  }
73
90
  return true;
74
91
  };
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++) {
92
+ const createReady = (token, params, label, wait, retry) => withRetry(
93
+ async () => {
79
94
  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);
95
+ if (!id || !await isReady(token, id, label, wait)) return null;
96
+ return id;
97
+ },
98
+ {
99
+ ...retry,
100
+ onRetry: (attempt, attempts, delayMS) => {
83
101
  console.warn(
84
- `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
102
+ `[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delayMS}ms`
85
103
  );
86
- await sleep(delay);
87
104
  }
88
105
  }
89
- return null;
90
- };
106
+ );
91
107
  return {
92
108
  /** Creates a container, waits for it to finish processing, then publishes it. */
93
109
  publish: async (token, params, wait, retry) => {
@@ -101,21 +117,30 @@ function createPublisher(platform) {
101
117
  if (!containerID) return null;
102
118
  return platform.publish(token, containerID);
103
119
  },
104
- /** Creates and awaits every carousel child, resolving to their ids — or `null` if any failed. */
120
+ /**
121
+ * Creates and awaits every carousel child **in parallel**, resolving to
122
+ * their ids in input order — or `null` if any failed.
123
+ *
124
+ * Parallel because each child is an independent create-then-poll and Meta
125
+ * spends ~5s accepting a single container, so ten sequential children cost
126
+ * ~50s of mostly waiting — past what a serverless caller can fit in its
127
+ * timeout. `Promise.all` preserves input order, which the carousel's slide
128
+ * order depends on.
129
+ */
105
130
  createChildren: async (token, items, wait, retry) => {
106
- const children = [];
107
- for (const item of items) {
108
- const childID = await createReady(
109
- token,
110
- { ...item, is_carousel_item: true },
111
- "carousel item",
112
- wait,
113
- retry
114
- );
115
- if (!childID) return null;
116
- children.push(childID);
117
- }
118
- return children;
131
+ const children = await Promise.all(
132
+ items.map(
133
+ (item) => createReady(
134
+ token,
135
+ { ...item, is_carousel_item: true },
136
+ "carousel item",
137
+ wait,
138
+ retry
139
+ )
140
+ )
141
+ );
142
+ const created = children.filter((childID) => childID !== null);
143
+ return created.length === children.length ? created : null;
119
144
  }
120
145
  };
121
146
  }
@@ -1,5 +1,6 @@
1
- import { WaitForContainerOptions, RetryOptions } from '../meta/container.mjs';
1
+ import { WaitForContainerOptions } from '../meta/container.mjs';
2
2
  import { MetaMediaType } from '../meta/types.mjs';
3
+ import { RetryOptions } from '../utils/poll.mjs';
3
4
 
4
5
  /**
5
6
  * Instagram Messaging API message shape.
@@ -1,5 +1,6 @@
1
- import { WaitForContainerOptions, RetryOptions } from '../meta/container.js';
1
+ import { WaitForContainerOptions } from '../meta/container.js';
2
2
  import { MetaMediaType } from '../meta/types.js';
3
+ import { RetryOptions } from '../utils/poll.js';
3
4
 
4
5
  /**
5
6
  * Instagram Messaging API message shape.