naystack 1.8.19 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -34
- package/dist/auth/client.cjs.js +2 -2
- package/dist/auth/client.esm.js +2 -2
- package/dist/auth/email/client.cjs.js +2 -2
- package/dist/auth/email/client.esm.js +2 -2
- package/dist/auth/email/index.cjs.js +2 -2
- package/dist/auth/email/index.esm.js +2 -2
- package/dist/auth/email/next.cjs.js +2 -2
- package/dist/auth/email/next.esm.js +2 -2
- package/dist/auth/email/routes/delete.cjs.js +2 -2
- package/dist/auth/email/routes/delete.esm.js +2 -2
- package/dist/auth/email/routes/get.cjs.js +2 -2
- package/dist/auth/email/routes/get.esm.js +2 -2
- package/dist/auth/email/routes/post.cjs.js +2 -2
- package/dist/auth/email/routes/post.esm.js +2 -2
- package/dist/auth/email/routes/put.cjs.js +2 -2
- package/dist/auth/email/routes/put.esm.js +2 -2
- package/dist/auth/email/token.cjs.js +2 -2
- package/dist/auth/email/token.esm.js +2 -2
- package/dist/auth/email/utils.cjs.js +2 -2
- package/dist/auth/email/utils.esm.js +2 -2
- package/dist/auth/google/get.cjs.js +2 -2
- package/dist/auth/google/get.esm.js +2 -2
- package/dist/auth/google/index.cjs.js +2 -2
- package/dist/auth/google/index.esm.js +2 -2
- package/dist/auth/index.cjs.js +4 -306
- package/dist/auth/index.d.mts +0 -5
- package/dist/auth/index.d.ts +0 -5
- package/dist/auth/index.esm.js +3 -302
- package/dist/auth/token-store.cjs.js +2 -2
- package/dist/auth/token-store.esm.js +2 -2
- package/dist/env.cjs.js +3 -3
- package/dist/env.d.mts +3 -2
- package/dist/env.d.ts +3 -2
- package/dist/env.esm.js +3 -3
- package/dist/file/client.cjs.js +2 -2
- package/dist/file/client.esm.js +2 -2
- package/dist/file/index.cjs.js +2 -2
- package/dist/file/index.esm.js +2 -2
- package/dist/file/put.cjs.js +2 -2
- package/dist/file/put.esm.js +2 -2
- package/dist/file/setup.cjs.js +2 -2
- package/dist/file/setup.esm.js +2 -2
- package/dist/file/utils.cjs.js +2 -2
- package/dist/file/utils.esm.js +2 -2
- package/dist/graphql/client.cjs.js +2 -2
- package/dist/graphql/client.esm.js +2 -2
- package/dist/graphql/index.cjs.js +2 -2
- package/dist/graphql/index.esm.js +2 -2
- package/dist/graphql/init.cjs.js +2 -2
- package/dist/graphql/init.esm.js +2 -2
- package/dist/graphql/links.cjs.js +2 -2
- package/dist/graphql/links.esm.js +2 -2
- package/dist/graphql/next.cjs.js +2 -2
- package/dist/graphql/next.esm.js +2 -2
- package/dist/graphql/server.cjs.js +2 -2
- package/dist/graphql/server.esm.js +2 -2
- package/dist/graphql/utils.cjs.js +2 -2
- package/dist/graphql/utils.esm.js +2 -2
- package/dist/socials/connect.cjs.js +151 -0
- package/dist/socials/connect.d.mts +70 -0
- package/dist/socials/connect.d.ts +70 -0
- package/dist/socials/connect.esm.js +126 -0
- package/dist/socials/index.cjs.js +345 -21
- package/dist/socials/index.d.mts +8 -2
- package/dist/socials/index.d.ts +8 -2
- package/dist/socials/index.esm.js +335 -20
- package/dist/socials/instagram/adapter.cjs.js +276 -0
- package/dist/socials/instagram/adapter.d.mts +30 -0
- package/dist/socials/instagram/adapter.d.ts +30 -0
- package/dist/socials/instagram/adapter.esm.js +249 -0
- package/dist/{auth/instagram/utils.cjs.js → socials/instagram/auth.cjs.js} +43 -41
- package/dist/socials/instagram/auth.d.mts +52 -0
- package/dist/socials/instagram/auth.d.ts +52 -0
- package/dist/{auth/instagram/utils.esm.js → socials/instagram/auth.esm.js} +37 -35
- package/dist/socials/instagram/getters.d.mts +1 -0
- package/dist/socials/instagram/getters.d.ts +1 -0
- package/dist/socials/instagram/setters.cjs.js +33 -17
- package/dist/socials/instagram/setters.d.mts +1 -0
- package/dist/socials/instagram/setters.d.ts +1 -0
- package/dist/socials/instagram/setters.esm.js +33 -17
- package/dist/socials/instagram/types.d.mts +2 -1
- package/dist/socials/instagram/types.d.ts +2 -1
- package/dist/socials/meta/container.cjs.js +34 -16
- package/dist/socials/meta/container.d.mts +5 -27
- package/dist/socials/meta/container.d.ts +5 -27
- package/dist/socials/meta/container.esm.js +33 -17
- package/dist/socials/provider.cjs.js +18 -0
- package/dist/socials/provider.d.mts +54 -0
- package/dist/socials/provider.d.ts +54 -0
- package/dist/socials/provider.esm.js +0 -0
- package/dist/socials/threads/getters.d.mts +1 -0
- package/dist/socials/threads/getters.d.ts +1 -0
- package/dist/socials/threads/setters.cjs.js +33 -17
- package/dist/socials/threads/setters.d.mts +1 -0
- package/dist/socials/threads/setters.d.ts +1 -0
- package/dist/socials/threads/setters.esm.js +33 -17
- package/dist/socials/threads/types.d.mts +2 -1
- package/dist/socials/threads/types.d.ts +2 -1
- package/dist/socials/types.cjs.js +43 -0
- package/dist/socials/types.d.mts +99 -0
- package/dist/socials/types.d.ts +99 -0
- package/dist/socials/types.esm.js +17 -0
- package/dist/socials/utils/poll.cjs.js +59 -0
- package/dist/socials/utils/poll.d.mts +85 -0
- package/dist/socials/utils/poll.d.ts +85 -0
- package/dist/socials/utils/poll.esm.js +33 -0
- package/dist/utils/client/index.cjs.js +2 -2
- package/dist/utils/client/index.esm.js +2 -2
- package/dist/utils/client/seo.cjs.js +2 -2
- package/dist/utils/client/seo.esm.js +2 -2
- package/package.json +1 -1
- package/dist/auth/instagram/index.cjs.js +0 -388
- package/dist/auth/instagram/index.d.mts +0 -58
- package/dist/auth/instagram/index.d.ts +0 -58
- package/dist/auth/instagram/index.esm.js +0 -359
- package/dist/auth/instagram/route.cjs.js +0 -368
- package/dist/auth/instagram/route.d.mts +0 -15
- package/dist/auth/instagram/route.d.ts +0 -15
- package/dist/auth/instagram/route.esm.js +0 -343
- package/dist/auth/instagram/utils.d.mts +0 -57
- package/dist/auth/instagram/utils.d.ts +0 -57
|
@@ -20,11 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/socials/index.ts
|
|
21
21
|
var socials_exports = {};
|
|
22
22
|
__export(socials_exports, {
|
|
23
|
+
InstagramProvider: () => InstagramProvider,
|
|
23
24
|
MetaMediaType: () => MetaMediaType,
|
|
25
|
+
SocialMediaKind: () => SocialMediaKind,
|
|
26
|
+
SocialPlatform: () => SocialPlatform,
|
|
24
27
|
canPublishToInstagram: () => canPublishToInstagram,
|
|
25
28
|
createInstagramPost: () => createInstagramPost,
|
|
26
29
|
createThread: () => createThread,
|
|
27
30
|
createThreadsPost: () => createThreadsPost,
|
|
31
|
+
getInstagramAuthorizationURL: () => getInstagramAuthorizationURL,
|
|
28
32
|
getInstagramConversation: () => getInstagramConversation,
|
|
29
33
|
getInstagramConversationByUser: () => getInstagramConversationByUser,
|
|
30
34
|
getInstagramConversations: () => getInstagramConversations,
|
|
@@ -33,18 +37,203 @@ __export(socials_exports, {
|
|
|
33
37
|
getInstagramMedia: () => getInstagramMedia,
|
|
34
38
|
getInstagramMessage: () => getInstagramMessage,
|
|
35
39
|
getInstagramUser: () => getInstagramUser,
|
|
40
|
+
getLongLivedInstagramToken: () => getLongLivedInstagramToken,
|
|
36
41
|
getThread: () => getThread,
|
|
37
42
|
getThreads: () => getThreads,
|
|
38
43
|
getThreadsData: () => getThreadsData,
|
|
39
44
|
getThreadsReplies: () => getThreadsReplies,
|
|
45
|
+
pollUntilReady: () => pollUntilReady,
|
|
40
46
|
readGraphID: () => readGraphID,
|
|
47
|
+
refreshInstagramAccessToken: () => refreshInstagramAccessToken,
|
|
41
48
|
replyToInstagramComment: () => replyToInstagramComment,
|
|
42
49
|
sendInstagramMessage: () => sendInstagramMessage,
|
|
43
50
|
setupInstagramWebhook: () => setupInstagramWebhook,
|
|
44
|
-
|
|
51
|
+
setupSocialAuth: () => setupSocialAuth,
|
|
52
|
+
setupThreadsWebhook: () => setupThreadsWebhook,
|
|
53
|
+
withRetry: () => withRetry
|
|
45
54
|
});
|
|
46
55
|
module.exports = __toCommonJS(socials_exports);
|
|
47
56
|
|
|
57
|
+
// src/socials/connect.ts
|
|
58
|
+
var import_server2 = require("next/server");
|
|
59
|
+
|
|
60
|
+
// src/auth/email/token.ts
|
|
61
|
+
var import_bcryptjs = require("bcryptjs");
|
|
62
|
+
var import_jsonwebtoken = require("jsonwebtoken");
|
|
63
|
+
var import_headers = require("next/headers");
|
|
64
|
+
var import_navigation = require("next/navigation");
|
|
65
|
+
var import_server = require("next/server");
|
|
66
|
+
|
|
67
|
+
// src/env.ts
|
|
68
|
+
var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
|
|
69
|
+
var getEnvValue = (key) => {
|
|
70
|
+
switch (key) {
|
|
71
|
+
case "NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */:
|
|
72
|
+
return process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || EXTRA_ENV.GRAPHQL_ENDPOINT;
|
|
73
|
+
case "NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */:
|
|
74
|
+
return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
|
|
75
|
+
case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
|
|
76
|
+
return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
|
|
77
|
+
case "NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT" /* NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT */:
|
|
78
|
+
return process.env.NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT || EXTRA_ENV.SOCIAL_AUTH_ENDPOINT;
|
|
79
|
+
case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
|
|
80
|
+
return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
|
|
81
|
+
case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
|
|
82
|
+
return process.env.NEXT_PUBLIC_BASE_URL || EXTRA_ENV.BASE_URL;
|
|
83
|
+
case "REFRESH_KEY" /* REFRESH_KEY */:
|
|
84
|
+
return process.env.REFRESH_KEY;
|
|
85
|
+
case "SIGNING_KEY" /* SIGNING_KEY */:
|
|
86
|
+
return process.env.SIGNING_KEY;
|
|
87
|
+
case "INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */:
|
|
88
|
+
return process.env.INSTAGRAM_CLIENT_SECRET;
|
|
89
|
+
case "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */:
|
|
90
|
+
return process.env.INSTAGRAM_CLIENT_ID;
|
|
91
|
+
case "GOOGLE_CLIENT_SECRET" /* GOOGLE_CLIENT_SECRET */:
|
|
92
|
+
return process.env.GOOGLE_CLIENT_SECRET;
|
|
93
|
+
case "GOOGLE_CLIENT_ID" /* GOOGLE_CLIENT_ID */:
|
|
94
|
+
return process.env.GOOGLE_CLIENT_ID;
|
|
95
|
+
case "TURNSTILE_KEY" /* TURNSTILE_KEY */:
|
|
96
|
+
return process.env.TURNSTILE_KEY;
|
|
97
|
+
case "S3_ACCESS_KEY_ID" /* S3_ACCESS_KEY_ID */:
|
|
98
|
+
return process.env.S3_ACCESS_KEY_ID;
|
|
99
|
+
case "S3_ACCESS_KEY_SECRET" /* S3_ACCESS_KEY_SECRET */:
|
|
100
|
+
return process.env.S3_ACCESS_KEY_SECRET;
|
|
101
|
+
case "S3_REGION" /* S3_REGION */:
|
|
102
|
+
return process.env.S3_REGION;
|
|
103
|
+
case "S3_BUCKET" /* S3_BUCKET */:
|
|
104
|
+
return process.env.S3_BUCKET;
|
|
105
|
+
case "NODE_ENV" /* NODE_ENV */:
|
|
106
|
+
return process.env.NODE_ENV;
|
|
107
|
+
default:
|
|
108
|
+
return process.env[key];
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
function getEnv(key, skipCheck) {
|
|
112
|
+
const value = getEnvValue(key);
|
|
113
|
+
if (!skipCheck && !value) throw new Error(`${key} is not defined`);
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/auth/email/token.ts
|
|
118
|
+
function getUserIdFromAccessToken(accessToken) {
|
|
119
|
+
if (accessToken)
|
|
120
|
+
try {
|
|
121
|
+
const decoded = (0, import_jsonwebtoken.verify)(accessToken, getEnv("SIGNING_KEY" /* SIGNING_KEY */));
|
|
122
|
+
if (typeof decoded !== "string" && typeof decoded.id === "number")
|
|
123
|
+
return decoded.id;
|
|
124
|
+
} catch (e) {
|
|
125
|
+
if (!(e instanceof import_jsonwebtoken.JsonWebTokenError)) console.error(e, "errors");
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/socials/connect.ts
|
|
132
|
+
function setupSocialAuth({
|
|
133
|
+
providers,
|
|
134
|
+
endpoint,
|
|
135
|
+
onConnect,
|
|
136
|
+
redirectURL,
|
|
137
|
+
errorRedirectURL,
|
|
138
|
+
scopes
|
|
139
|
+
}) {
|
|
140
|
+
const handleError = (message) => import_server2.NextResponse.redirect(`${errorRedirectURL}?error=${message}`);
|
|
141
|
+
const GET = async (req, ctx) => {
|
|
142
|
+
const { platform } = await ctx.params;
|
|
143
|
+
const provider = providers.find((p) => p.platform === platform);
|
|
144
|
+
if (!provider) return handleError("Unsupported platform");
|
|
145
|
+
const code = req.nextUrl.searchParams.get("code");
|
|
146
|
+
const error = req.nextUrl.searchParams.get("error");
|
|
147
|
+
const state = req.nextUrl.searchParams.get("state");
|
|
148
|
+
if (error) return handleError(error);
|
|
149
|
+
if (!state) return handleError("Invalid request");
|
|
150
|
+
const redirectURI = `${endpoint}/${provider.platform}`;
|
|
151
|
+
if (!code) {
|
|
152
|
+
return import_server2.NextResponse.redirect(
|
|
153
|
+
provider.auth.authorizationURL({
|
|
154
|
+
state,
|
|
155
|
+
redirectURI,
|
|
156
|
+
scopes: scopes?.[provider.platform]
|
|
157
|
+
}),
|
|
158
|
+
302
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const exchanged = await provider.auth.exchangeCode({ code, redirectURI });
|
|
162
|
+
if (!exchanged) return handleError("Couldn't connect your account");
|
|
163
|
+
const { platformUserId, ...tokens } = exchanged;
|
|
164
|
+
const profile = await provider.fetchProfile(tokens.accessToken);
|
|
165
|
+
if (!profile) return handleError("Couldn't read your profile");
|
|
166
|
+
const errorMessage = await onConnect({
|
|
167
|
+
platform: provider.platform,
|
|
168
|
+
profile: {
|
|
169
|
+
...profile,
|
|
170
|
+
platformUserId: profile.platformUserId ?? platformUserId
|
|
171
|
+
},
|
|
172
|
+
tokens,
|
|
173
|
+
userId: getUserIdFromAccessToken(state)
|
|
174
|
+
});
|
|
175
|
+
if (errorMessage) return handleError(errorMessage);
|
|
176
|
+
return import_server2.NextResponse.redirect(redirectURL);
|
|
177
|
+
};
|
|
178
|
+
return { GET };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/socials/types.ts
|
|
182
|
+
var SocialPlatform = /* @__PURE__ */ ((SocialPlatform2) => {
|
|
183
|
+
SocialPlatform2["Instagram"] = "instagram";
|
|
184
|
+
SocialPlatform2["YouTube"] = "youtube";
|
|
185
|
+
SocialPlatform2["TikTok"] = "tiktok";
|
|
186
|
+
return SocialPlatform2;
|
|
187
|
+
})(SocialPlatform || {});
|
|
188
|
+
var SocialMediaKind = /* @__PURE__ */ ((SocialMediaKind2) => {
|
|
189
|
+
SocialMediaKind2["Image"] = "image";
|
|
190
|
+
SocialMediaKind2["Video"] = "video";
|
|
191
|
+
SocialMediaKind2["Carousel"] = "carousel";
|
|
192
|
+
return SocialMediaKind2;
|
|
193
|
+
})(SocialMediaKind || {});
|
|
194
|
+
|
|
195
|
+
// src/socials/instagram/auth.ts
|
|
196
|
+
var getInstagramAuthorizationURL = (state, redirectURI, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
|
|
197
|
+
"INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
|
|
198
|
+
)}&response_type=code&enable_fb_login=0&force_authentication=1&scope=${scopes.join(",")}&state=${state}&redirect_uri=${redirectURI}#weblink`;
|
|
199
|
+
async function getLongLivedInstagramToken(code, redirectURI) {
|
|
200
|
+
const formData = new FormData();
|
|
201
|
+
formData.set("client_id", getEnv("INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */));
|
|
202
|
+
formData.set("client_secret", getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */));
|
|
203
|
+
formData.set("grant_type", "authorization_code");
|
|
204
|
+
formData.set("redirect_uri", redirectURI);
|
|
205
|
+
formData.set("code", code);
|
|
206
|
+
const shortRes = await fetch("https://api.instagram.com/oauth/access_token", {
|
|
207
|
+
method: "POST",
|
|
208
|
+
body: formData
|
|
209
|
+
});
|
|
210
|
+
if (!shortRes.ok) return void 0;
|
|
211
|
+
const shortResData = await shortRes.json();
|
|
212
|
+
if (!shortResData.access_token) return void 0;
|
|
213
|
+
const longRes = await fetch(
|
|
214
|
+
`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 */)}`
|
|
215
|
+
);
|
|
216
|
+
if (!longRes.ok) return void 0;
|
|
217
|
+
const longResData = await longRes.json();
|
|
218
|
+
return {
|
|
219
|
+
accessToken: longResData.access_token,
|
|
220
|
+
userId: shortResData.user_id,
|
|
221
|
+
expiresIn: longResData.expires_in,
|
|
222
|
+
permissions: shortResData.permissions
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async function refreshInstagramAccessToken(token) {
|
|
226
|
+
const request = await fetch(
|
|
227
|
+
`https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
|
|
228
|
+
);
|
|
229
|
+
const response = await request.json();
|
|
230
|
+
if (!response.access_token) return void 0;
|
|
231
|
+
return {
|
|
232
|
+
accessToken: response.access_token,
|
|
233
|
+
expiresIn: response.expires_in
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
48
237
|
// src/socials/meta/request.ts
|
|
49
238
|
function createGraphClient(baseURL) {
|
|
50
239
|
const buildURL = (token, path, params = {}) => {
|
|
@@ -177,25 +366,152 @@ var canPublishToInstagram = async (token) => {
|
|
|
177
366
|
return true;
|
|
178
367
|
};
|
|
179
368
|
|
|
180
|
-
// src/socials/
|
|
369
|
+
// src/socials/instagram/adapter.ts
|
|
370
|
+
var PROFILE_FIELDS = [
|
|
371
|
+
"id",
|
|
372
|
+
"user_id",
|
|
373
|
+
"username",
|
|
374
|
+
"name",
|
|
375
|
+
"profile_picture_url",
|
|
376
|
+
"followers_count",
|
|
377
|
+
"media_count"
|
|
378
|
+
];
|
|
379
|
+
var MEDIA_FIELDS = [
|
|
380
|
+
"id",
|
|
381
|
+
"caption",
|
|
382
|
+
"media_type",
|
|
383
|
+
"media_url",
|
|
384
|
+
"permalink",
|
|
385
|
+
"thumbnail_url",
|
|
386
|
+
"timestamp",
|
|
387
|
+
"like_count",
|
|
388
|
+
"comments_count"
|
|
389
|
+
];
|
|
390
|
+
var expiresAt = (seconds) => seconds ? new Date(Date.now() + seconds * 1e3) : void 0;
|
|
391
|
+
function toKind(mediaType) {
|
|
392
|
+
if (mediaType === "VIDEO") return "video" /* Video */;
|
|
393
|
+
if (mediaType === "CAROUSEL_ALBUM") return "carousel" /* Carousel */;
|
|
394
|
+
return "image" /* Image */;
|
|
395
|
+
}
|
|
396
|
+
function toPost(media) {
|
|
397
|
+
const kind = toKind(media.media_type);
|
|
398
|
+
return {
|
|
399
|
+
platform: "instagram" /* Instagram */,
|
|
400
|
+
platformMediaId: media.id,
|
|
401
|
+
permalink: media.permalink,
|
|
402
|
+
// A video's `media_url` is the .mp4 itself, so it is never a stand-in for a
|
|
403
|
+
// missing poster frame — better no thumbnail than one that can't render.
|
|
404
|
+
thumbnail: media.thumbnail_url ?? (kind === "video" /* Video */ ? null : media.media_url ?? null),
|
|
405
|
+
mediaURL: media.media_url ?? null,
|
|
406
|
+
caption: media.caption ?? null,
|
|
407
|
+
kind,
|
|
408
|
+
publishedAt: media.timestamp,
|
|
409
|
+
likes: media.like_count ?? null,
|
|
410
|
+
comments: media.comments_count ?? null,
|
|
411
|
+
// Both need the Insights API; the basic media fields carry neither.
|
|
412
|
+
views: null,
|
|
413
|
+
shares: null,
|
|
414
|
+
metadata: {}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
var InstagramProvider = {
|
|
418
|
+
platform: "instagram" /* Instagram */,
|
|
419
|
+
auth: {
|
|
420
|
+
authorizationURL: ({ state, redirectURI, scopes }) => getInstagramAuthorizationURL(
|
|
421
|
+
state,
|
|
422
|
+
redirectURI,
|
|
423
|
+
scopes
|
|
424
|
+
),
|
|
425
|
+
exchangeCode: async ({ code, redirectURI }) => {
|
|
426
|
+
const result = await getLongLivedInstagramToken(code, redirectURI);
|
|
427
|
+
if (!result) {
|
|
428
|
+
console.error("[naystack] Instagram code exchange returned no token");
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
accessToken: result.accessToken,
|
|
433
|
+
platformUserId: result.userId || null,
|
|
434
|
+
expiresAt: expiresAt(result.expiresIn),
|
|
435
|
+
scopes: result.permissions
|
|
436
|
+
};
|
|
437
|
+
},
|
|
438
|
+
refresh: async ({ accessToken }) => {
|
|
439
|
+
const refreshed = await refreshInstagramAccessToken(accessToken);
|
|
440
|
+
if (!refreshed) return null;
|
|
441
|
+
return {
|
|
442
|
+
accessToken: refreshed.accessToken,
|
|
443
|
+
expiresAt: expiresAt(refreshed.expiresIn)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
profileURL: (username) => `https://instagram.com/${username}`,
|
|
448
|
+
fetchProfile: async (accessToken) => {
|
|
449
|
+
const user = await getInstagramUser(
|
|
450
|
+
accessToken,
|
|
451
|
+
void 0,
|
|
452
|
+
PROFILE_FIELDS
|
|
453
|
+
);
|
|
454
|
+
if (!user?.username) return null;
|
|
455
|
+
return {
|
|
456
|
+
platform: "instagram" /* Instagram */,
|
|
457
|
+
// `user_id` is what the OAuth exchange hands back, so preferring it keeps
|
|
458
|
+
// one account's id identical however it was read.
|
|
459
|
+
platformUserId: user.user_id || user.id || null,
|
|
460
|
+
username: user.username,
|
|
461
|
+
displayName: user.name ?? null,
|
|
462
|
+
avatar: user.profile_picture_url ?? null,
|
|
463
|
+
followers: user.followers_count ?? 0,
|
|
464
|
+
contentCount: user.media_count ?? 0,
|
|
465
|
+
metadata: {}
|
|
466
|
+
};
|
|
467
|
+
},
|
|
468
|
+
fetchMedia: async (accessToken, options) => {
|
|
469
|
+
const result = await getInstagramMedia(
|
|
470
|
+
accessToken,
|
|
471
|
+
MEDIA_FIELDS,
|
|
472
|
+
options?.limit
|
|
473
|
+
);
|
|
474
|
+
if (!result?.data) return [];
|
|
475
|
+
return result.data.map(toPost);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
// src/socials/utils/poll.ts
|
|
181
480
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
182
|
-
async function
|
|
481
|
+
async function pollUntilReady(read, isPending, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
|
|
183
482
|
const deadline = Date.now() + timeoutMS;
|
|
184
|
-
let state = await
|
|
483
|
+
let state = await read();
|
|
185
484
|
if (!state) {
|
|
186
485
|
await sleep(2e3);
|
|
187
486
|
return null;
|
|
188
487
|
}
|
|
189
|
-
while (state
|
|
488
|
+
while (state && isPending(state) && Date.now() < deadline) {
|
|
190
489
|
await sleep(intervalMS);
|
|
191
|
-
state = await
|
|
490
|
+
state = await read();
|
|
192
491
|
}
|
|
193
492
|
return state;
|
|
194
493
|
}
|
|
494
|
+
async function withRetry(run, options = {}) {
|
|
495
|
+
const attempts = Math.max(1, options.attempts ?? 3);
|
|
496
|
+
const backoffMS = options.backoffMS ?? 2e3;
|
|
497
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
498
|
+
const result = await run(attempt);
|
|
499
|
+
if (result) return result;
|
|
500
|
+
if (attempt < attempts) {
|
|
501
|
+
const delayMS = backoffMS * 2 ** (attempt - 1);
|
|
502
|
+
options.onRetry?.(attempt, attempts, delayMS);
|
|
503
|
+
await sleep(delayMS);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/socials/meta/container.ts
|
|
195
510
|
function createPublisher(platform) {
|
|
196
511
|
const isReady = async (token, id, label, wait) => {
|
|
197
|
-
const state = await
|
|
512
|
+
const state = await pollUntilReady(
|
|
198
513
|
() => platform.getStatus(token, id),
|
|
514
|
+
(current) => current.status === "IN_PROGRESS",
|
|
199
515
|
wait
|
|
200
516
|
);
|
|
201
517
|
if (state && state.status !== "FINISHED" && state.status !== "PUBLISHED") {
|
|
@@ -206,22 +522,21 @@ function createPublisher(platform) {
|
|
|
206
522
|
}
|
|
207
523
|
return true;
|
|
208
524
|
};
|
|
209
|
-
const createReady =
|
|
210
|
-
|
|
211
|
-
const backoffMS = retry?.backoffMS ?? 2e3;
|
|
212
|
-
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
525
|
+
const createReady = (token, params, label, wait, retry) => withRetry(
|
|
526
|
+
async () => {
|
|
213
527
|
const id = await platform.createContainer(token, params);
|
|
214
|
-
if (id
|
|
215
|
-
|
|
216
|
-
|
|
528
|
+
if (!id || !await isReady(token, id, label, wait)) return null;
|
|
529
|
+
return id;
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
...retry,
|
|
533
|
+
onRetry: (attempt, attempts, delayMS) => {
|
|
217
534
|
console.warn(
|
|
218
|
-
`[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${
|
|
535
|
+
`[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delayMS}ms`
|
|
219
536
|
);
|
|
220
|
-
await sleep(delay);
|
|
221
537
|
}
|
|
222
538
|
}
|
|
223
|
-
|
|
224
|
-
};
|
|
539
|
+
);
|
|
225
540
|
return {
|
|
226
541
|
/** Creates a container, waits for it to finish processing, then publishes it. */
|
|
227
542
|
publish: async (token, params, wait, retry) => {
|
|
@@ -384,11 +699,11 @@ var sendInstagramMessage = (token, to, text) => {
|
|
|
384
699
|
};
|
|
385
700
|
|
|
386
701
|
// src/socials/meta/webhook.ts
|
|
387
|
-
var
|
|
702
|
+
var import_server3 = require("next/server");
|
|
388
703
|
var verifyWebhook = (secret) => (req) => {
|
|
389
704
|
const params = req.nextUrl.searchParams;
|
|
390
705
|
if (params.get("hub.verify_token") === secret) {
|
|
391
|
-
return new
|
|
706
|
+
return new import_server3.NextResponse(params.get("hub.challenge"));
|
|
392
707
|
}
|
|
393
708
|
};
|
|
394
709
|
|
|
@@ -522,11 +837,15 @@ var setupThreadsWebhook = (options) => {
|
|
|
522
837
|
};
|
|
523
838
|
// Annotate the CommonJS export names for ESM import in node:
|
|
524
839
|
0 && (module.exports = {
|
|
840
|
+
InstagramProvider,
|
|
525
841
|
MetaMediaType,
|
|
842
|
+
SocialMediaKind,
|
|
843
|
+
SocialPlatform,
|
|
526
844
|
canPublishToInstagram,
|
|
527
845
|
createInstagramPost,
|
|
528
846
|
createThread,
|
|
529
847
|
createThreadsPost,
|
|
848
|
+
getInstagramAuthorizationURL,
|
|
530
849
|
getInstagramConversation,
|
|
531
850
|
getInstagramConversationByUser,
|
|
532
851
|
getInstagramConversations,
|
|
@@ -535,13 +854,18 @@ var setupThreadsWebhook = (options) => {
|
|
|
535
854
|
getInstagramMedia,
|
|
536
855
|
getInstagramMessage,
|
|
537
856
|
getInstagramUser,
|
|
857
|
+
getLongLivedInstagramToken,
|
|
538
858
|
getThread,
|
|
539
859
|
getThreads,
|
|
540
860
|
getThreadsData,
|
|
541
861
|
getThreadsReplies,
|
|
862
|
+
pollUntilReady,
|
|
542
863
|
readGraphID,
|
|
864
|
+
refreshInstagramAccessToken,
|
|
543
865
|
replyToInstagramComment,
|
|
544
866
|
sendInstagramMessage,
|
|
545
867
|
setupInstagramWebhook,
|
|
546
|
-
|
|
868
|
+
setupSocialAuth,
|
|
869
|
+
setupThreadsWebhook,
|
|
870
|
+
withRetry
|
|
547
871
|
});
|
package/dist/socials/index.d.mts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
export { SetupSocialAuthOptions, SocialConnection, setupSocialAuth } from './connect.mjs';
|
|
2
|
+
export { InstagramProvider } from './instagram/adapter.mjs';
|
|
3
|
+
export { InstagramScope, getInstagramAuthorizationURL, getLongLivedInstagramToken, refreshInstagramAccessToken } from './instagram/auth.mjs';
|
|
1
4
|
export { canPublishToInstagram, getInstagramConversation, getInstagramConversationByUser, getInstagramConversations, getInstagramConversationsByUser, getInstagramMedia, getInstagramMessage, getInstagramUser } from './instagram/getters.mjs';
|
|
2
5
|
export { createInstagramPost, replyToInstagramComment, sendInstagramMessage } from './instagram/setters.mjs';
|
|
3
6
|
export { InstagramConversation, InstagramMedia, InstagramMessage, InstagramPostInput, InstagramPostMedia, InstagramUser } from './instagram/types.mjs';
|
|
4
7
|
export { getInstagramData } from './instagram/utils.mjs';
|
|
5
8
|
export { setupInstagramWebhook } from './instagram/webhook.mjs';
|
|
6
|
-
export {
|
|
9
|
+
export { WaitForContainerOptions } from './meta/container.mjs';
|
|
7
10
|
export { GraphClient, GraphRequestOptions, readGraphID } from './meta/request.mjs';
|
|
8
11
|
export { GraphError, GraphParams, MetaMediaType } from './meta/types.mjs';
|
|
12
|
+
export { SocialProvider } from './provider.mjs';
|
|
9
13
|
export { getThread, getThreads, getThreadsReplies } from './threads/getters.mjs';
|
|
10
14
|
export { createThread, createThreadsPost } from './threads/setters.mjs';
|
|
11
|
-
export { getThreadsData } from './threads/utils.mjs';
|
|
12
15
|
export { ThreadsPost, ThreadsPostInput, ThreadsPostMedia } from './threads/types.mjs';
|
|
16
|
+
export { getThreadsData } from './threads/utils.mjs';
|
|
13
17
|
export { setupThreadsWebhook } from './threads/webhook.mjs';
|
|
18
|
+
export { SocialMediaKind, SocialPlatform, SocialPost, SocialProfile, SocialTokens } from './types.mjs';
|
|
19
|
+
export { PollOptions, RetryOptions, pollUntilReady, withRetry } from './utils/poll.mjs';
|
|
14
20
|
import 'next/server';
|
package/dist/socials/index.d.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
export { SetupSocialAuthOptions, SocialConnection, setupSocialAuth } from './connect.js';
|
|
2
|
+
export { InstagramProvider } from './instagram/adapter.js';
|
|
3
|
+
export { InstagramScope, getInstagramAuthorizationURL, getLongLivedInstagramToken, refreshInstagramAccessToken } from './instagram/auth.js';
|
|
1
4
|
export { canPublishToInstagram, getInstagramConversation, getInstagramConversationByUser, getInstagramConversations, getInstagramConversationsByUser, getInstagramMedia, getInstagramMessage, getInstagramUser } from './instagram/getters.js';
|
|
2
5
|
export { createInstagramPost, replyToInstagramComment, sendInstagramMessage } from './instagram/setters.js';
|
|
3
6
|
export { InstagramConversation, InstagramMedia, InstagramMessage, InstagramPostInput, InstagramPostMedia, InstagramUser } from './instagram/types.js';
|
|
4
7
|
export { getInstagramData } from './instagram/utils.js';
|
|
5
8
|
export { setupInstagramWebhook } from './instagram/webhook.js';
|
|
6
|
-
export {
|
|
9
|
+
export { WaitForContainerOptions } from './meta/container.js';
|
|
7
10
|
export { GraphClient, GraphRequestOptions, readGraphID } from './meta/request.js';
|
|
8
11
|
export { GraphError, GraphParams, MetaMediaType } from './meta/types.js';
|
|
12
|
+
export { SocialProvider } from './provider.js';
|
|
9
13
|
export { getThread, getThreads, getThreadsReplies } from './threads/getters.js';
|
|
10
14
|
export { createThread, createThreadsPost } from './threads/setters.js';
|
|
11
|
-
export { getThreadsData } from './threads/utils.js';
|
|
12
15
|
export { ThreadsPost, ThreadsPostInput, ThreadsPostMedia } from './threads/types.js';
|
|
16
|
+
export { getThreadsData } from './threads/utils.js';
|
|
13
17
|
export { setupThreadsWebhook } from './threads/webhook.js';
|
|
18
|
+
export { SocialMediaKind, SocialPlatform, SocialPost, SocialProfile, SocialTokens } from './types.js';
|
|
19
|
+
export { PollOptions, RetryOptions, pollUntilReady, withRetry } from './utils/poll.js';
|
|
14
20
|
import 'next/server';
|