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
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/socials/instagram/adapter.ts
21
+ var adapter_exports = {};
22
+ __export(adapter_exports, {
23
+ InstagramProvider: () => InstagramProvider
24
+ });
25
+ module.exports = __toCommonJS(adapter_exports);
26
+
27
+ // src/env.ts
28
+ var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
29
+ var getEnvValue = (key) => {
30
+ switch (key) {
31
+ case "NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */:
32
+ return process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || EXTRA_ENV.GRAPHQL_ENDPOINT;
33
+ case "NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */:
34
+ return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
35
+ case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
36
+ return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
37
+ case "NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT" /* NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT */:
38
+ return process.env.NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT || EXTRA_ENV.SOCIAL_AUTH_ENDPOINT;
39
+ case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
40
+ return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
41
+ case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
42
+ return process.env.NEXT_PUBLIC_BASE_URL || EXTRA_ENV.BASE_URL;
43
+ case "REFRESH_KEY" /* REFRESH_KEY */:
44
+ return process.env.REFRESH_KEY;
45
+ case "SIGNING_KEY" /* SIGNING_KEY */:
46
+ return process.env.SIGNING_KEY;
47
+ case "INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */:
48
+ return process.env.INSTAGRAM_CLIENT_SECRET;
49
+ case "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */:
50
+ return process.env.INSTAGRAM_CLIENT_ID;
51
+ case "GOOGLE_CLIENT_SECRET" /* GOOGLE_CLIENT_SECRET */:
52
+ return process.env.GOOGLE_CLIENT_SECRET;
53
+ case "GOOGLE_CLIENT_ID" /* GOOGLE_CLIENT_ID */:
54
+ return process.env.GOOGLE_CLIENT_ID;
55
+ case "TURNSTILE_KEY" /* TURNSTILE_KEY */:
56
+ return process.env.TURNSTILE_KEY;
57
+ case "S3_ACCESS_KEY_ID" /* S3_ACCESS_KEY_ID */:
58
+ return process.env.S3_ACCESS_KEY_ID;
59
+ case "S3_ACCESS_KEY_SECRET" /* S3_ACCESS_KEY_SECRET */:
60
+ return process.env.S3_ACCESS_KEY_SECRET;
61
+ case "S3_REGION" /* S3_REGION */:
62
+ return process.env.S3_REGION;
63
+ case "S3_BUCKET" /* S3_BUCKET */:
64
+ return process.env.S3_BUCKET;
65
+ case "NODE_ENV" /* NODE_ENV */:
66
+ return process.env.NODE_ENV;
67
+ default:
68
+ return process.env[key];
69
+ }
70
+ };
71
+ function getEnv(key, skipCheck) {
72
+ const value = getEnvValue(key);
73
+ if (!skipCheck && !value) throw new Error(`${key} is not defined`);
74
+ return value;
75
+ }
76
+
77
+ // src/socials/instagram/auth.ts
78
+ var getInstagramAuthorizationURL = (state, redirectURI, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
79
+ "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
80
+ )}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${state}&redirect_uri=${redirectURI}#weblink`;
81
+ async function getLongLivedInstagramToken(code, redirectURI) {
82
+ const formData = new FormData();
83
+ formData.set("client_id", getEnv("INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */));
84
+ formData.set("client_secret", getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */));
85
+ formData.set("grant_type", "authorization_code");
86
+ formData.set("redirect_uri", redirectURI);
87
+ formData.set("code", code);
88
+ const shortRes = await fetch("https://api.instagram.com/oauth/access_token", {
89
+ method: "POST",
90
+ body: formData
91
+ });
92
+ if (!shortRes.ok) return void 0;
93
+ const shortResData = await shortRes.json();
94
+ if (!shortResData.access_token) return void 0;
95
+ const longRes = await fetch(
96
+ `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 */)}`
97
+ );
98
+ if (!longRes.ok) return void 0;
99
+ const longResData = await longRes.json();
100
+ return {
101
+ accessToken: longResData.access_token,
102
+ userId: shortResData.user_id,
103
+ expiresIn: longResData.expires_in,
104
+ permissions: shortResData.permissions
105
+ };
106
+ }
107
+ async function refreshInstagramAccessToken(token) {
108
+ const request = await fetch(
109
+ `https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
110
+ );
111
+ const response = await request.json();
112
+ if (!response.access_token) return void 0;
113
+ return {
114
+ accessToken: response.access_token,
115
+ expiresIn: response.expires_in
116
+ };
117
+ }
118
+
119
+ // src/socials/meta/request.ts
120
+ function createGraphClient(baseURL) {
121
+ const buildURL = (token, path, params = {}) => {
122
+ const search = new URLSearchParams();
123
+ for (const [key, value] of Object.entries(params)) {
124
+ if (value !== void 0) search.set(key, String(value));
125
+ }
126
+ search.set("access_token", token);
127
+ return `${baseURL}/${path}?${search.toString()}`;
128
+ };
129
+ const request = async (token, path, options = {}) => {
130
+ const response = await fetch(buildURL(token, path, options.params), {
131
+ method: options.method || (options.body ? "POST" : "GET"),
132
+ headers: {
133
+ Authorization: `Bearer ${token}`,
134
+ ...options.body ? { "Content-Type": "application/json" } : {}
135
+ },
136
+ ...options.body ? { body: JSON.stringify(options.body) } : {}
137
+ });
138
+ return response.json().catch(() => null);
139
+ };
140
+ return { buildURL, request };
141
+ }
142
+
143
+ // src/socials/instagram/utils.ts
144
+ var client = createGraphClient("https://graph.instagram.com/v23.0");
145
+ var getInstagramData = client.request;
146
+
147
+ // src/socials/instagram/getters.ts
148
+ var getInstagramUser = (token, id, fields) => {
149
+ return getInstagramData(token, id || "me", {
150
+ params: {
151
+ fields: fields ? fields.join(",") : "username,followers_count,media_count"
152
+ }
153
+ });
154
+ };
155
+ var getInstagramMedia = (token, fields, limit = 12) => {
156
+ return getInstagramData(token, "me/media", {
157
+ params: {
158
+ fields: fields ? fields.join(",") : "like_count,comments_count,permalink",
159
+ limit
160
+ }
161
+ });
162
+ };
163
+
164
+ // src/socials/instagram/adapter.ts
165
+ var PROFILE_FIELDS = [
166
+ "id",
167
+ "user_id",
168
+ "username",
169
+ "name",
170
+ "profile_picture_url",
171
+ "followers_count",
172
+ "media_count"
173
+ ];
174
+ var MEDIA_FIELDS = [
175
+ "id",
176
+ "caption",
177
+ "media_type",
178
+ "media_url",
179
+ "permalink",
180
+ "thumbnail_url",
181
+ "timestamp",
182
+ "like_count",
183
+ "comments_count"
184
+ ];
185
+ var expiresAt = (seconds) => seconds ? new Date(Date.now() + seconds * 1e3) : void 0;
186
+ function toKind(mediaType) {
187
+ if (mediaType === "VIDEO") return "video" /* Video */;
188
+ if (mediaType === "CAROUSEL_ALBUM") return "carousel" /* Carousel */;
189
+ return "image" /* Image */;
190
+ }
191
+ function toPost(media) {
192
+ const kind = toKind(media.media_type);
193
+ return {
194
+ platform: "instagram" /* Instagram */,
195
+ platformMediaId: media.id,
196
+ permalink: media.permalink,
197
+ // A video's `media_url` is the .mp4 itself, so it is never a stand-in for a
198
+ // missing poster frame — better no thumbnail than one that can't render.
199
+ thumbnail: media.thumbnail_url ?? (kind === "video" /* Video */ ? null : media.media_url ?? null),
200
+ mediaURL: media.media_url ?? null,
201
+ caption: media.caption ?? null,
202
+ kind,
203
+ publishedAt: media.timestamp,
204
+ likes: media.like_count ?? null,
205
+ comments: media.comments_count ?? null,
206
+ // Both need the Insights API; the basic media fields carry neither.
207
+ views: null,
208
+ shares: null,
209
+ metadata: {}
210
+ };
211
+ }
212
+ var InstagramProvider = {
213
+ platform: "instagram" /* Instagram */,
214
+ auth: {
215
+ authorizationURL: ({ state, redirectURI, scopes }) => getInstagramAuthorizationURL(
216
+ state,
217
+ redirectURI,
218
+ scopes
219
+ ),
220
+ exchangeCode: async ({ code, redirectURI }) => {
221
+ const result = await getLongLivedInstagramToken(code, redirectURI);
222
+ if (!result) {
223
+ console.error("[naystack] Instagram code exchange returned no token");
224
+ return null;
225
+ }
226
+ return {
227
+ accessToken: result.accessToken,
228
+ platformUserId: result.userId || null,
229
+ expiresAt: expiresAt(result.expiresIn),
230
+ scopes: result.permissions
231
+ };
232
+ },
233
+ refresh: async ({ accessToken }) => {
234
+ const refreshed = await refreshInstagramAccessToken(accessToken);
235
+ if (!refreshed) return null;
236
+ return {
237
+ accessToken: refreshed.accessToken,
238
+ expiresAt: expiresAt(refreshed.expiresIn)
239
+ };
240
+ }
241
+ },
242
+ fetchProfile: async (accessToken) => {
243
+ const user = await getInstagramUser(
244
+ accessToken,
245
+ void 0,
246
+ PROFILE_FIELDS
247
+ );
248
+ if (!user?.username) return null;
249
+ return {
250
+ platform: "instagram" /* Instagram */,
251
+ // `user_id` is what the OAuth exchange hands back, so preferring it keeps
252
+ // one account's id identical however it was read.
253
+ platformUserId: user.user_id || user.id || null,
254
+ username: user.username,
255
+ displayName: user.name ?? null,
256
+ avatar: user.profile_picture_url ?? null,
257
+ followers: user.followers_count ?? 0,
258
+ contentCount: user.media_count ?? 0,
259
+ metadata: {}
260
+ };
261
+ },
262
+ fetchMedia: async (accessToken, options) => {
263
+ const result = await getInstagramMedia(
264
+ accessToken,
265
+ MEDIA_FIELDS,
266
+ options?.limit
267
+ );
268
+ if (!result?.data) return [];
269
+ return result.data.map(toPost);
270
+ }
271
+ };
272
+ // Annotate the CommonJS export names for ESM import in node:
273
+ 0 && (module.exports = {
274
+ InstagramProvider
275
+ });
@@ -0,0 +1,30 @@
1
+ import { SocialProvider } from '../provider.mjs';
2
+ import '../types.mjs';
3
+
4
+ /**
5
+ * Instagram as a normalized {@link SocialProvider}.
6
+ *
7
+ * A ready-made singleton — import and call it, there is nothing to construct.
8
+ * Credentials are read from the environment inside the `auth` methods, so
9
+ * `fetchProfile` and `fetchMedia` need only a token and work in a process that
10
+ * has no Instagram OAuth configuration at all.
11
+ *
12
+ * Wraps the platform-specific helpers rather than replacing them:
13
+ * {@link getInstagramUser} and {@link getInstagramMedia} remain the way to reach
14
+ * fields this normalization drops.
15
+ *
16
+ * Requires env vars for `auth` only: `INSTAGRAM_CLIENT_ID`, `INSTAGRAM_CLIENT_SECRET`.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { InstagramProvider } from "naystack/socials";
21
+ *
22
+ * const profile = await InstagramProvider.fetchProfile(accessToken);
23
+ * const posts = await InstagramProvider.fetchMedia?.(accessToken, { limit: 6 });
24
+ * ```
25
+ *
26
+ * @category Socials
27
+ */
28
+ declare const InstagramProvider: SocialProvider;
29
+
30
+ export { InstagramProvider };
@@ -0,0 +1,30 @@
1
+ import { SocialProvider } from '../provider.js';
2
+ import '../types.js';
3
+
4
+ /**
5
+ * Instagram as a normalized {@link SocialProvider}.
6
+ *
7
+ * A ready-made singleton — import and call it, there is nothing to construct.
8
+ * Credentials are read from the environment inside the `auth` methods, so
9
+ * `fetchProfile` and `fetchMedia` need only a token and work in a process that
10
+ * has no Instagram OAuth configuration at all.
11
+ *
12
+ * Wraps the platform-specific helpers rather than replacing them:
13
+ * {@link getInstagramUser} and {@link getInstagramMedia} remain the way to reach
14
+ * fields this normalization drops.
15
+ *
16
+ * Requires env vars for `auth` only: `INSTAGRAM_CLIENT_ID`, `INSTAGRAM_CLIENT_SECRET`.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { InstagramProvider } from "naystack/socials";
21
+ *
22
+ * const profile = await InstagramProvider.fetchProfile(accessToken);
23
+ * const posts = await InstagramProvider.fetchMedia?.(accessToken, { limit: 6 });
24
+ * ```
25
+ *
26
+ * @category Socials
27
+ */
28
+ declare const InstagramProvider: SocialProvider;
29
+
30
+ export { InstagramProvider };
@@ -0,0 +1,248 @@
1
+ // src/env.ts
2
+ var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
3
+ var getEnvValue = (key) => {
4
+ switch (key) {
5
+ case "NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */:
6
+ return process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || EXTRA_ENV.GRAPHQL_ENDPOINT;
7
+ case "NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */:
8
+ return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
9
+ case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
10
+ return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_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
+ case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
14
+ return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
15
+ case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
16
+ return process.env.NEXT_PUBLIC_BASE_URL || EXTRA_ENV.BASE_URL;
17
+ case "REFRESH_KEY" /* REFRESH_KEY */:
18
+ return process.env.REFRESH_KEY;
19
+ case "SIGNING_KEY" /* SIGNING_KEY */:
20
+ return process.env.SIGNING_KEY;
21
+ case "INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */:
22
+ return process.env.INSTAGRAM_CLIENT_SECRET;
23
+ case "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */:
24
+ return process.env.INSTAGRAM_CLIENT_ID;
25
+ case "GOOGLE_CLIENT_SECRET" /* GOOGLE_CLIENT_SECRET */:
26
+ return process.env.GOOGLE_CLIENT_SECRET;
27
+ case "GOOGLE_CLIENT_ID" /* GOOGLE_CLIENT_ID */:
28
+ return process.env.GOOGLE_CLIENT_ID;
29
+ case "TURNSTILE_KEY" /* TURNSTILE_KEY */:
30
+ return process.env.TURNSTILE_KEY;
31
+ case "S3_ACCESS_KEY_ID" /* S3_ACCESS_KEY_ID */:
32
+ return process.env.S3_ACCESS_KEY_ID;
33
+ case "S3_ACCESS_KEY_SECRET" /* S3_ACCESS_KEY_SECRET */:
34
+ return process.env.S3_ACCESS_KEY_SECRET;
35
+ case "S3_REGION" /* S3_REGION */:
36
+ return process.env.S3_REGION;
37
+ case "S3_BUCKET" /* S3_BUCKET */:
38
+ return process.env.S3_BUCKET;
39
+ case "NODE_ENV" /* NODE_ENV */:
40
+ return process.env.NODE_ENV;
41
+ default:
42
+ return process.env[key];
43
+ }
44
+ };
45
+ function getEnv(key, skipCheck) {
46
+ const value = getEnvValue(key);
47
+ if (!skipCheck && !value) throw new Error(`${key} is not defined`);
48
+ return value;
49
+ }
50
+
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) {
56
+ const formData = new FormData();
57
+ formData.set("client_id", getEnv("INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */));
58
+ formData.set("client_secret", getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */));
59
+ formData.set("grant_type", "authorization_code");
60
+ formData.set("redirect_uri", redirectURI);
61
+ formData.set("code", code);
62
+ const shortRes = await fetch("https://api.instagram.com/oauth/access_token", {
63
+ method: "POST",
64
+ body: formData
65
+ });
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
+ };
91
+ }
92
+
93
+ // src/socials/meta/request.ts
94
+ function createGraphClient(baseURL) {
95
+ const buildURL = (token, path, params = {}) => {
96
+ const search = new URLSearchParams();
97
+ for (const [key, value] of Object.entries(params)) {
98
+ if (value !== void 0) search.set(key, String(value));
99
+ }
100
+ search.set("access_token", token);
101
+ return `${baseURL}/${path}?${search.toString()}`;
102
+ };
103
+ const request = async (token, path, options = {}) => {
104
+ const response = await fetch(buildURL(token, path, options.params), {
105
+ method: options.method || (options.body ? "POST" : "GET"),
106
+ headers: {
107
+ Authorization: `Bearer ${token}`,
108
+ ...options.body ? { "Content-Type": "application/json" } : {}
109
+ },
110
+ ...options.body ? { body: JSON.stringify(options.body) } : {}
111
+ });
112
+ return response.json().catch(() => null);
113
+ };
114
+ return { buildURL, request };
115
+ }
116
+
117
+ // src/socials/instagram/utils.ts
118
+ var client = createGraphClient("https://graph.instagram.com/v23.0");
119
+ var getInstagramData = client.request;
120
+
121
+ // src/socials/instagram/getters.ts
122
+ var getInstagramUser = (token, id, fields) => {
123
+ return getInstagramData(token, id || "me", {
124
+ params: {
125
+ fields: fields ? fields.join(",") : "username,followers_count,media_count"
126
+ }
127
+ });
128
+ };
129
+ var getInstagramMedia = (token, fields, limit = 12) => {
130
+ return getInstagramData(token, "me/media", {
131
+ params: {
132
+ fields: fields ? fields.join(",") : "like_count,comments_count,permalink",
133
+ limit
134
+ }
135
+ });
136
+ };
137
+
138
+ // src/socials/instagram/adapter.ts
139
+ var PROFILE_FIELDS = [
140
+ "id",
141
+ "user_id",
142
+ "username",
143
+ "name",
144
+ "profile_picture_url",
145
+ "followers_count",
146
+ "media_count"
147
+ ];
148
+ var MEDIA_FIELDS = [
149
+ "id",
150
+ "caption",
151
+ "media_type",
152
+ "media_url",
153
+ "permalink",
154
+ "thumbnail_url",
155
+ "timestamp",
156
+ "like_count",
157
+ "comments_count"
158
+ ];
159
+ var expiresAt = (seconds) => seconds ? new Date(Date.now() + seconds * 1e3) : void 0;
160
+ function toKind(mediaType) {
161
+ if (mediaType === "VIDEO") return "video" /* Video */;
162
+ if (mediaType === "CAROUSEL_ALBUM") return "carousel" /* Carousel */;
163
+ return "image" /* Image */;
164
+ }
165
+ function toPost(media) {
166
+ const kind = toKind(media.media_type);
167
+ return {
168
+ platform: "instagram" /* Instagram */,
169
+ platformMediaId: media.id,
170
+ permalink: media.permalink,
171
+ // A video's `media_url` is the .mp4 itself, so it is never a stand-in for a
172
+ // missing poster frame — better no thumbnail than one that can't render.
173
+ thumbnail: media.thumbnail_url ?? (kind === "video" /* Video */ ? null : media.media_url ?? null),
174
+ mediaURL: media.media_url ?? null,
175
+ caption: media.caption ?? null,
176
+ kind,
177
+ publishedAt: media.timestamp,
178
+ likes: media.like_count ?? null,
179
+ comments: media.comments_count ?? null,
180
+ // Both need the Insights API; the basic media fields carry neither.
181
+ views: null,
182
+ shares: null,
183
+ metadata: {}
184
+ };
185
+ }
186
+ var InstagramProvider = {
187
+ platform: "instagram" /* Instagram */,
188
+ auth: {
189
+ authorizationURL: ({ state, redirectURI, scopes }) => getInstagramAuthorizationURL(
190
+ state,
191
+ redirectURI,
192
+ scopes
193
+ ),
194
+ exchangeCode: async ({ code, redirectURI }) => {
195
+ const result = await getLongLivedInstagramToken(code, redirectURI);
196
+ if (!result) {
197
+ console.error("[naystack] Instagram code exchange returned no token");
198
+ return null;
199
+ }
200
+ return {
201
+ accessToken: result.accessToken,
202
+ platformUserId: result.userId || null,
203
+ expiresAt: expiresAt(result.expiresIn),
204
+ scopes: result.permissions
205
+ };
206
+ },
207
+ refresh: async ({ accessToken }) => {
208
+ const refreshed = await refreshInstagramAccessToken(accessToken);
209
+ if (!refreshed) return null;
210
+ return {
211
+ accessToken: refreshed.accessToken,
212
+ expiresAt: expiresAt(refreshed.expiresIn)
213
+ };
214
+ }
215
+ },
216
+ fetchProfile: async (accessToken) => {
217
+ const user = await getInstagramUser(
218
+ accessToken,
219
+ void 0,
220
+ PROFILE_FIELDS
221
+ );
222
+ if (!user?.username) return null;
223
+ return {
224
+ platform: "instagram" /* Instagram */,
225
+ // `user_id` is what the OAuth exchange hands back, so preferring it keeps
226
+ // one account's id identical however it was read.
227
+ platformUserId: user.user_id || user.id || null,
228
+ username: user.username,
229
+ displayName: user.name ?? null,
230
+ avatar: user.profile_picture_url ?? null,
231
+ followers: user.followers_count ?? 0,
232
+ contentCount: user.media_count ?? 0,
233
+ metadata: {}
234
+ };
235
+ },
236
+ fetchMedia: async (accessToken, options) => {
237
+ const result = await getInstagramMedia(
238
+ accessToken,
239
+ MEDIA_FIELDS,
240
+ options?.limit
241
+ );
242
+ if (!result?.data) return [];
243
+ return result.data.map(toPost);
244
+ }
245
+ };
246
+ export {
247
+ InstagramProvider
248
+ };