naystack 1.8.19 → 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.
- package/README.md +94 -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 +344 -21
- package/dist/socials/index.d.mts +8 -2
- package/dist/socials/index.d.ts +8 -2
- package/dist/socials/index.esm.js +334 -20
- package/dist/socials/instagram/adapter.cjs.js +275 -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 +248 -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 +52 -0
- package/dist/socials/provider.d.ts +52 -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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waiting and retrying, with no platform in them. Meta's media containers were
|
|
3
|
+
* the first caller; any API that hands back a job id and a status endpoint wants
|
|
4
|
+
* the same two helpers.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Polling settings for {@link pollUntilReady}.
|
|
10
|
+
*
|
|
11
|
+
* @property intervalMS - Delay between reads. Default: `5000`.
|
|
12
|
+
* @property timeoutMS - Stop polling after this long. Default: `300000`.
|
|
13
|
+
*
|
|
14
|
+
* @category Socials
|
|
15
|
+
*/
|
|
16
|
+
type PollOptions = {
|
|
17
|
+
intervalMS?: number;
|
|
18
|
+
timeoutMS?: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Retry settings for {@link withRetry}.
|
|
22
|
+
*
|
|
23
|
+
* @property attempts - Total tries, including the first. Default: `3`.
|
|
24
|
+
* @property backoffMS - Delay before the second try, doubled each time after. Default: `2000`.
|
|
25
|
+
*
|
|
26
|
+
* @category Socials
|
|
27
|
+
*/
|
|
28
|
+
type RetryOptions = {
|
|
29
|
+
attempts?: number;
|
|
30
|
+
backoffMS?: number;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Reads a job's state until it stops being pending.
|
|
34
|
+
*
|
|
35
|
+
* Resolves `null` when the first read returns nothing. That is "unknown", not
|
|
36
|
+
* "failed": some jobs are complete the moment they exist and never publish a
|
|
37
|
+
* readable status, so treating `null` as an error would reject work that already
|
|
38
|
+
* succeeded. A short pause before returning gives such a job a beat to settle.
|
|
39
|
+
*
|
|
40
|
+
* @param read - `null` means no state was readable.
|
|
41
|
+
* @param isPending - `true` while the state means "still working".
|
|
42
|
+
* @returns The last state read, or `null` if the state was never readable.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { pollUntilReady } from "naystack/socials";
|
|
47
|
+
*
|
|
48
|
+
* const state = await pollUntilReady(
|
|
49
|
+
* () => getInstagramContainerStatus(token, containerID),
|
|
50
|
+
* (s) => s.status === "IN_PROGRESS",
|
|
51
|
+
* );
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @category Socials
|
|
55
|
+
*/
|
|
56
|
+
declare function pollUntilReady<T>(read: () => Promise<T | null>, isPending: (state: T) => boolean, { intervalMS, timeoutMS }?: PollOptions): Promise<T | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Runs an operation until it produces a result, backing off between tries.
|
|
59
|
+
*
|
|
60
|
+
* `run` signals failure by resolving `null` rather than throwing — the socials
|
|
61
|
+
* helpers log the API's message and resolve `null`, so a loop that only caught
|
|
62
|
+
* exceptions would never retry.
|
|
63
|
+
*
|
|
64
|
+
* @param run - Receives the 1-based attempt number; resolve `null` to retry.
|
|
65
|
+
* @param options - {@link RetryOptions}, plus `onRetry` for logging before each delay.
|
|
66
|
+
* @returns The first non-`null` result, or `null` once every attempt is spent.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { withRetry } from "naystack/socials";
|
|
71
|
+
*
|
|
72
|
+
* const id = await withRetry(() => createContainer(token, params), {
|
|
73
|
+
* attempts: 3,
|
|
74
|
+
* onRetry: (attempt, attempts, delayMS) =>
|
|
75
|
+
* console.warn(`attempt ${attempt}/${attempts} failed — retrying in ${delayMS}ms`),
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @category Socials
|
|
80
|
+
*/
|
|
81
|
+
declare function withRetry<T>(run: (attempt: number) => Promise<T | null>, options?: RetryOptions & {
|
|
82
|
+
onRetry?: (attempt: number, attempts: number, delayMS: number) => void;
|
|
83
|
+
}): Promise<T | null>;
|
|
84
|
+
|
|
85
|
+
export { type PollOptions, type RetryOptions, pollUntilReady, withRetry };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/socials/utils/poll.ts
|
|
2
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
async function pollUntilReady(read, isPending, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
|
|
4
|
+
const deadline = Date.now() + timeoutMS;
|
|
5
|
+
let state = await read();
|
|
6
|
+
if (!state) {
|
|
7
|
+
await sleep(2e3);
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
while (state && isPending(state) && Date.now() < deadline) {
|
|
11
|
+
await sleep(intervalMS);
|
|
12
|
+
state = await read();
|
|
13
|
+
}
|
|
14
|
+
return state;
|
|
15
|
+
}
|
|
16
|
+
async function withRetry(run, options = {}) {
|
|
17
|
+
const attempts = Math.max(1, options.attempts ?? 3);
|
|
18
|
+
const backoffMS = options.backoffMS ?? 2e3;
|
|
19
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
20
|
+
const result = await run(attempt);
|
|
21
|
+
if (result) return result;
|
|
22
|
+
if (attempt < attempts) {
|
|
23
|
+
const delayMS = backoffMS * 2 ** (attempt - 1);
|
|
24
|
+
options.onRetry?.(attempt, attempts, delayMS);
|
|
25
|
+
await sleep(delayMS);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
pollUntilReady,
|
|
32
|
+
withRetry
|
|
33
|
+
};
|
|
@@ -81,8 +81,8 @@ var getEnvValue = (key) => {
|
|
|
81
81
|
return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
|
|
82
82
|
case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
|
|
83
83
|
return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
|
|
84
|
-
case "
|
|
85
|
-
return process.env.
|
|
84
|
+
case "NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT" /* NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT */:
|
|
85
|
+
return process.env.NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT || EXTRA_ENV.SOCIAL_AUTH_ENDPOINT;
|
|
86
86
|
case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
|
|
87
87
|
return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
|
|
88
88
|
case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
|
|
@@ -53,8 +53,8 @@ var getEnvValue = (key) => {
|
|
|
53
53
|
return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
|
|
54
54
|
case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
|
|
55
55
|
return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
|
|
56
|
-
case "
|
|
57
|
-
return process.env.
|
|
56
|
+
case "NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT" /* NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT */:
|
|
57
|
+
return process.env.NEXT_PUBLIC_SOCIAL_AUTH_ENDPOINT || EXTRA_ENV.SOCIAL_AUTH_ENDPOINT;
|
|
58
58
|
case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
|
|
59
59
|
return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
|
|
60
60
|
case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
|
|
@@ -34,8 +34,8 @@ var getEnvValue = (key) => {
|
|
|
34
34
|
return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
|
|
35
35
|
case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
|
|
36
36
|
return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
|
|
37
|
-
case "
|
|
38
|
-
return process.env.
|
|
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
39
|
case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
|
|
40
40
|
return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
|
|
41
41
|
case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
|
|
@@ -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 "
|
|
12
|
-
return process.env.
|
|
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 */:
|
package/package.json
CHANGED
|
@@ -1,388 +0,0 @@
|
|
|
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/auth/instagram/index.ts
|
|
21
|
-
var instagram_exports = {};
|
|
22
|
-
__export(instagram_exports, {
|
|
23
|
-
getInstagramAuthorizationURL: () => getInstagramAuthorizationURL,
|
|
24
|
-
getRefreshedInstagramAccessToken: () => getRefreshedInstagramAccessToken,
|
|
25
|
-
setupInstagramAuth: () => setupInstagramAuth
|
|
26
|
-
});
|
|
27
|
-
module.exports = __toCommonJS(instagram_exports);
|
|
28
|
-
|
|
29
|
-
// src/auth/instagram/route.ts
|
|
30
|
-
var import_server3 = require("next/server");
|
|
31
|
-
|
|
32
|
-
// src/auth/email/token.ts
|
|
33
|
-
var import_bcryptjs = require("bcryptjs");
|
|
34
|
-
var import_jsonwebtoken = require("jsonwebtoken");
|
|
35
|
-
var import_headers = require("next/headers");
|
|
36
|
-
var import_navigation = require("next/navigation");
|
|
37
|
-
var import_server = require("next/server");
|
|
38
|
-
|
|
39
|
-
// src/env.ts
|
|
40
|
-
var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
|
|
41
|
-
var getEnvValue = (key) => {
|
|
42
|
-
switch (key) {
|
|
43
|
-
case "NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */:
|
|
44
|
-
return process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || EXTRA_ENV.GRAPHQL_ENDPOINT;
|
|
45
|
-
case "NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */:
|
|
46
|
-
return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
|
|
47
|
-
case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
|
|
48
|
-
return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
|
|
49
|
-
case "NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */:
|
|
50
|
-
return process.env.NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT || EXTRA_ENV.INSTAGRAM_AUTH_ENDPOINT;
|
|
51
|
-
case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
|
|
52
|
-
return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
|
|
53
|
-
case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
|
|
54
|
-
return process.env.NEXT_PUBLIC_BASE_URL || EXTRA_ENV.BASE_URL;
|
|
55
|
-
case "REFRESH_KEY" /* REFRESH_KEY */:
|
|
56
|
-
return process.env.REFRESH_KEY;
|
|
57
|
-
case "SIGNING_KEY" /* SIGNING_KEY */:
|
|
58
|
-
return process.env.SIGNING_KEY;
|
|
59
|
-
case "INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */:
|
|
60
|
-
return process.env.INSTAGRAM_CLIENT_SECRET;
|
|
61
|
-
case "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */:
|
|
62
|
-
return process.env.INSTAGRAM_CLIENT_ID;
|
|
63
|
-
case "GOOGLE_CLIENT_SECRET" /* GOOGLE_CLIENT_SECRET */:
|
|
64
|
-
return process.env.GOOGLE_CLIENT_SECRET;
|
|
65
|
-
case "GOOGLE_CLIENT_ID" /* GOOGLE_CLIENT_ID */:
|
|
66
|
-
return process.env.GOOGLE_CLIENT_ID;
|
|
67
|
-
case "TURNSTILE_KEY" /* TURNSTILE_KEY */:
|
|
68
|
-
return process.env.TURNSTILE_KEY;
|
|
69
|
-
case "S3_ACCESS_KEY_ID" /* S3_ACCESS_KEY_ID */:
|
|
70
|
-
return process.env.S3_ACCESS_KEY_ID;
|
|
71
|
-
case "S3_ACCESS_KEY_SECRET" /* S3_ACCESS_KEY_SECRET */:
|
|
72
|
-
return process.env.S3_ACCESS_KEY_SECRET;
|
|
73
|
-
case "S3_REGION" /* S3_REGION */:
|
|
74
|
-
return process.env.S3_REGION;
|
|
75
|
-
case "S3_BUCKET" /* S3_BUCKET */:
|
|
76
|
-
return process.env.S3_BUCKET;
|
|
77
|
-
case "NODE_ENV" /* NODE_ENV */:
|
|
78
|
-
return process.env.NODE_ENV;
|
|
79
|
-
default:
|
|
80
|
-
return process.env[key];
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
function getEnv(key, skipCheck) {
|
|
84
|
-
const value = getEnvValue(key);
|
|
85
|
-
if (!skipCheck && !value) throw new Error(`${key} is not defined`);
|
|
86
|
-
return value;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// src/auth/email/token.ts
|
|
90
|
-
function getUserIdFromAccessToken(accessToken) {
|
|
91
|
-
if (accessToken)
|
|
92
|
-
try {
|
|
93
|
-
const decoded = (0, import_jsonwebtoken.verify)(accessToken, getEnv("SIGNING_KEY" /* SIGNING_KEY */));
|
|
94
|
-
if (typeof decoded !== "string" && typeof decoded.id === "number")
|
|
95
|
-
return decoded.id;
|
|
96
|
-
} catch (e) {
|
|
97
|
-
if (!(e instanceof import_jsonwebtoken.JsonWebTokenError)) console.error(e, "errors");
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// src/auth/instagram/utils.ts
|
|
104
|
-
async function getRefreshedInstagramAccessToken(token) {
|
|
105
|
-
const request = await fetch(
|
|
106
|
-
`https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=${token}`
|
|
107
|
-
);
|
|
108
|
-
const response = await request.json();
|
|
109
|
-
return response.access_token;
|
|
110
|
-
}
|
|
111
|
-
async function getLongLivedToken(code, redirectURL, clientId, clientSecret) {
|
|
112
|
-
const formData = new FormData();
|
|
113
|
-
formData.set("client_id", clientId);
|
|
114
|
-
formData.set("client_secret", clientSecret);
|
|
115
|
-
formData.set("grant_type", "authorization_code");
|
|
116
|
-
formData.set("redirect_uri", redirectURL);
|
|
117
|
-
formData.set("code", code);
|
|
118
|
-
const shortRes = await fetch("https://api.instagram.com/oauth/access_token", {
|
|
119
|
-
method: "POST",
|
|
120
|
-
body: formData
|
|
121
|
-
});
|
|
122
|
-
if (shortRes.ok) {
|
|
123
|
-
const shortResData = await shortRes.json();
|
|
124
|
-
if (shortResData.access_token) {
|
|
125
|
-
const shortLivedToken = shortResData.access_token;
|
|
126
|
-
const longRes = await fetch(
|
|
127
|
-
`https://graph.instagram.com/access_token?grant_type=ig_exchange_token&access_token=${shortLivedToken}&client_secret=${getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */)}`
|
|
128
|
-
);
|
|
129
|
-
if (longRes.ok) {
|
|
130
|
-
const longResData = await longRes.json();
|
|
131
|
-
return {
|
|
132
|
-
accessToken: longResData.access_token,
|
|
133
|
-
userId: shortResData.user_id
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
var getInstagramAuthorizationURL = (token, scopes = ["instagram_business_basic"]) => `https://www.instagram.com/oauth/authorize/?client_id=${getEnv(
|
|
140
|
-
"INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */
|
|
141
|
-
)}&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`;
|
|
142
|
-
|
|
143
|
-
// src/socials/meta/request.ts
|
|
144
|
-
function createGraphClient(baseURL) {
|
|
145
|
-
const buildURL = (token, path, params = {}) => {
|
|
146
|
-
const search = new URLSearchParams();
|
|
147
|
-
for (const [key, value] of Object.entries(params)) {
|
|
148
|
-
if (value !== void 0) search.set(key, String(value));
|
|
149
|
-
}
|
|
150
|
-
search.set("access_token", token);
|
|
151
|
-
return `${baseURL}/${path}?${search.toString()}`;
|
|
152
|
-
};
|
|
153
|
-
const request = async (token, path, options = {}) => {
|
|
154
|
-
const response = await fetch(buildURL(token, path, options.params), {
|
|
155
|
-
method: options.method || (options.body ? "POST" : "GET"),
|
|
156
|
-
headers: {
|
|
157
|
-
Authorization: `Bearer ${token}`,
|
|
158
|
-
...options.body ? { "Content-Type": "application/json" } : {}
|
|
159
|
-
},
|
|
160
|
-
...options.body ? { body: JSON.stringify(options.body) } : {}
|
|
161
|
-
});
|
|
162
|
-
return response.json().catch(() => null);
|
|
163
|
-
};
|
|
164
|
-
return { buildURL, request };
|
|
165
|
-
}
|
|
166
|
-
function readGraphID(label, result) {
|
|
167
|
-
if (result?.error) {
|
|
168
|
-
console.error(`[naystack] ${label} failed: ${result.error.message}`);
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
return result?.id || null;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/socials/instagram/utils.ts
|
|
175
|
-
var client = createGraphClient("https://graph.instagram.com/v23.0");
|
|
176
|
-
var getInstagramData = client.request;
|
|
177
|
-
|
|
178
|
-
// src/socials/instagram/getters.ts
|
|
179
|
-
var getInstagramUser = (token, id, fields) => {
|
|
180
|
-
return getInstagramData(token, id || "me", {
|
|
181
|
-
params: {
|
|
182
|
-
fields: fields ? fields.join(",") : "username,followers_count,media_count"
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
};
|
|
186
|
-
var getInstagramContainerStatus = async (token, id) => {
|
|
187
|
-
const result = await getInstagramData(token, id, { params: { fields: "status_code,status" } });
|
|
188
|
-
if (!result?.status_code) return null;
|
|
189
|
-
return {
|
|
190
|
-
status: result.status_code,
|
|
191
|
-
error: result.status_code === "ERROR" ? result.status : void 0
|
|
192
|
-
};
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
// src/socials/meta/container.ts
|
|
196
|
-
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
197
|
-
async function waitForContainer(getState, { intervalMS = 5e3, timeoutMS = 3e5 } = {}) {
|
|
198
|
-
const deadline = Date.now() + timeoutMS;
|
|
199
|
-
let state = await getState();
|
|
200
|
-
if (!state) {
|
|
201
|
-
await sleep(2e3);
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
while (state?.status === "IN_PROGRESS" && Date.now() < deadline) {
|
|
205
|
-
await sleep(intervalMS);
|
|
206
|
-
state = await getState();
|
|
207
|
-
}
|
|
208
|
-
return state;
|
|
209
|
-
}
|
|
210
|
-
function createPublisher(platform) {
|
|
211
|
-
const isReady = async (token, id, label, wait) => {
|
|
212
|
-
const state = await waitForContainer(
|
|
213
|
-
() => platform.getStatus(token, id),
|
|
214
|
-
wait
|
|
215
|
-
);
|
|
216
|
-
if (state && state.status !== "FINISHED" && state.status !== "PUBLISHED") {
|
|
217
|
-
console.error(
|
|
218
|
-
`[naystack] ${platform.name} ${label} ${id} is ${state.status}${state.error ? `: ${state.error}` : ""}`
|
|
219
|
-
);
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
return true;
|
|
223
|
-
};
|
|
224
|
-
const createReady = async (token, params, label, wait, retry) => {
|
|
225
|
-
const attempts = Math.max(1, retry?.attempts ?? 3);
|
|
226
|
-
const backoffMS = retry?.backoffMS ?? 2e3;
|
|
227
|
-
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
228
|
-
const id = await platform.createContainer(token, params);
|
|
229
|
-
if (id && await isReady(token, id, label, wait)) return id;
|
|
230
|
-
if (attempt < attempts) {
|
|
231
|
-
const delay = backoffMS * 2 ** (attempt - 1);
|
|
232
|
-
console.warn(
|
|
233
|
-
`[naystack] ${platform.name} ${label} attempt ${attempt}/${attempts} failed \u2014 retrying in ${delay}ms`
|
|
234
|
-
);
|
|
235
|
-
await sleep(delay);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return null;
|
|
239
|
-
};
|
|
240
|
-
return {
|
|
241
|
-
/** Creates a container, waits for it to finish processing, then publishes it. */
|
|
242
|
-
publish: async (token, params, wait, retry) => {
|
|
243
|
-
const containerID = await createReady(
|
|
244
|
-
token,
|
|
245
|
-
params,
|
|
246
|
-
"container",
|
|
247
|
-
wait,
|
|
248
|
-
retry
|
|
249
|
-
);
|
|
250
|
-
if (!containerID) return null;
|
|
251
|
-
return platform.publish(token, containerID);
|
|
252
|
-
},
|
|
253
|
-
/**
|
|
254
|
-
* Creates and awaits every carousel child **in parallel**, resolving to
|
|
255
|
-
* their ids in input order — or `null` if any failed.
|
|
256
|
-
*
|
|
257
|
-
* Parallel because each child is an independent create-then-poll and Meta
|
|
258
|
-
* spends ~5s accepting a single container, so ten sequential children cost
|
|
259
|
-
* ~50s of mostly waiting — past what a serverless caller can fit in its
|
|
260
|
-
* timeout. `Promise.all` preserves input order, which the carousel's slide
|
|
261
|
-
* order depends on.
|
|
262
|
-
*/
|
|
263
|
-
createChildren: async (token, items, wait, retry) => {
|
|
264
|
-
const children = await Promise.all(
|
|
265
|
-
items.map(
|
|
266
|
-
(item) => createReady(
|
|
267
|
-
token,
|
|
268
|
-
{ ...item, is_carousel_item: true },
|
|
269
|
-
"carousel item",
|
|
270
|
-
wait,
|
|
271
|
-
retry
|
|
272
|
-
)
|
|
273
|
-
)
|
|
274
|
-
);
|
|
275
|
-
const created = children.filter((childID) => childID !== null);
|
|
276
|
-
return created.length === children.length ? created : null;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// src/socials/instagram/setters.ts
|
|
282
|
-
var publisher = createPublisher({
|
|
283
|
-
name: "Instagram",
|
|
284
|
-
getStatus: getInstagramContainerStatus,
|
|
285
|
-
createContainer: async (token, params) => readGraphID(
|
|
286
|
-
"Instagram media container",
|
|
287
|
-
await getInstagramData(token, "me/media", {
|
|
288
|
-
params,
|
|
289
|
-
method: "POST"
|
|
290
|
-
})
|
|
291
|
-
),
|
|
292
|
-
publish: async (token, creationID) => readGraphID(
|
|
293
|
-
"Instagram publish",
|
|
294
|
-
await getInstagramData(token, "me/media_publish", {
|
|
295
|
-
params: { creation_id: creationID },
|
|
296
|
-
method: "POST"
|
|
297
|
-
})
|
|
298
|
-
)
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// src/socials/meta/webhook.ts
|
|
302
|
-
var import_server2 = require("next/server");
|
|
303
|
-
|
|
304
|
-
// src/socials/threads/utils.ts
|
|
305
|
-
var client2 = createGraphClient("https://graph.threads.net/v1.0");
|
|
306
|
-
var getThreadsData = client2.request;
|
|
307
|
-
|
|
308
|
-
// src/socials/threads/getters.ts
|
|
309
|
-
var getThreadsContainerStatus = async (token, id) => {
|
|
310
|
-
const result = await getThreadsData(token, id, { params: { fields: "status,error_message" } });
|
|
311
|
-
if (!result?.status) return null;
|
|
312
|
-
return { status: result.status, error: result.error_message };
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
// src/socials/threads/setters.ts
|
|
316
|
-
var publisher2 = createPublisher({
|
|
317
|
-
name: "Threads",
|
|
318
|
-
getStatus: getThreadsContainerStatus,
|
|
319
|
-
createContainer: async (token, params) => readGraphID(
|
|
320
|
-
"Threads container",
|
|
321
|
-
await getThreadsData(token, "me/threads", {
|
|
322
|
-
params,
|
|
323
|
-
method: "POST"
|
|
324
|
-
})
|
|
325
|
-
),
|
|
326
|
-
publish: async (token, creationID) => readGraphID(
|
|
327
|
-
"Threads publish",
|
|
328
|
-
await getThreadsData(token, "me/threads_publish", {
|
|
329
|
-
params: { creation_id: creationID },
|
|
330
|
-
method: "POST"
|
|
331
|
-
})
|
|
332
|
-
)
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
// src/auth/instagram/route.ts
|
|
336
|
-
var getInstagramRoute = ({
|
|
337
|
-
redirectURL,
|
|
338
|
-
errorRedirectURL,
|
|
339
|
-
onUser,
|
|
340
|
-
scopes
|
|
341
|
-
}) => {
|
|
342
|
-
const handleError = (message) => import_server3.NextResponse.redirect(`${errorRedirectURL}?error=${message}`);
|
|
343
|
-
return async (req) => {
|
|
344
|
-
const accessCode = req.nextUrl.searchParams.get("code");
|
|
345
|
-
const error = req.nextUrl.searchParams.get("error");
|
|
346
|
-
const stateToken = req.nextUrl.searchParams.get("state");
|
|
347
|
-
if (error) return handleError(error);
|
|
348
|
-
if (!accessCode) {
|
|
349
|
-
if (!stateToken) return handleError("Invalid request");
|
|
350
|
-
return import_server3.NextResponse.redirect(
|
|
351
|
-
getInstagramAuthorizationURL(stateToken, scopes),
|
|
352
|
-
302
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
if (!stateToken) return handleError("Invalid request");
|
|
356
|
-
const instagramData = await getLongLivedToken(
|
|
357
|
-
accessCode,
|
|
358
|
-
getEnv("NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */),
|
|
359
|
-
getEnv("INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */),
|
|
360
|
-
getEnv("INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */)
|
|
361
|
-
);
|
|
362
|
-
if (!instagramData?.accessToken)
|
|
363
|
-
return handleError("Unable to reach Instagram");
|
|
364
|
-
const personalInfo = await getInstagramUser(instagramData.accessToken);
|
|
365
|
-
if (!personalInfo?.username) return handleError("You are not logged in");
|
|
366
|
-
const loggedInUserID = getUserIdFromAccessToken(stateToken);
|
|
367
|
-
const errorMessage = await onUser(
|
|
368
|
-
personalInfo,
|
|
369
|
-
loggedInUserID,
|
|
370
|
-
instagramData.accessToken
|
|
371
|
-
);
|
|
372
|
-
if (errorMessage) return handleError(errorMessage);
|
|
373
|
-
return import_server3.NextResponse.redirect(redirectURL);
|
|
374
|
-
};
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// src/auth/instagram/index.ts
|
|
378
|
-
function setupInstagramAuth(props) {
|
|
379
|
-
return {
|
|
380
|
-
GET: getInstagramRoute(props)
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
384
|
-
0 && (module.exports = {
|
|
385
|
-
getInstagramAuthorizationURL,
|
|
386
|
-
getRefreshedInstagramAccessToken,
|
|
387
|
-
setupInstagramAuth
|
|
388
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as next_server from 'next/server';
|
|
2
|
-
import { InstagramScope } from './utils.mjs';
|
|
3
|
-
export { getInstagramAuthorizationURL, getRefreshedInstagramAccessToken } from './utils.mjs';
|
|
4
|
-
import { InstagramUser } from '../../socials/instagram/types.mjs';
|
|
5
|
-
import '../../socials/meta/container.mjs';
|
|
6
|
-
import '../../socials/meta/types.mjs';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Options for initializing Instagram OAuth via {@link setupInstagramAuth}.
|
|
10
|
-
*
|
|
11
|
-
* @property onUser - Called with `(instagramUser, appUserId, accessToken)` after successful OAuth. Return a string to show as error (redirects to `errorRedirectURL`); return `void` on success.
|
|
12
|
-
* @property redirectURL - Where to redirect after successful Instagram auth.
|
|
13
|
-
* @property errorRedirectURL - Where to redirect on error (with `?error=` query param).
|
|
14
|
-
* @property scopes - Permissions to request. Default: `["instagram_business_basic"]`. Add `"instagram_business_content_publish"` to publish on the user's behalf.
|
|
15
|
-
*
|
|
16
|
-
* @category Auth
|
|
17
|
-
*/
|
|
18
|
-
interface SetupInstagramAuthOptions {
|
|
19
|
-
onUser: (data: InstagramUser, id: number | null, accessToken: string) => Promise<string | void>;
|
|
20
|
-
redirectURL: string;
|
|
21
|
-
errorRedirectURL: string;
|
|
22
|
-
scopes?: InstagramScope[];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Initializes Instagram OAuth. Returns a GET handler for the OAuth callback and a helper to refresh long-lived tokens.
|
|
26
|
-
*
|
|
27
|
-
* Mount the GET handler on your Instagram auth route (e.g. `app/api/(auth)/instagram/route.ts`).
|
|
28
|
-
*
|
|
29
|
-
* The single GET handler serves both the OAuth callback (`?code`) and the connect
|
|
30
|
-
* entry point (`?state` with no code → 302 to Instagram's authorize URL; see
|
|
31
|
-
* {@link getInstagramAuthorizationURL} for why that URL is spelled the way it is).
|
|
32
|
-
*
|
|
33
|
-
* Requires env vars: `INSTAGRAM_CLIENT_ID` (server-only), `INSTAGRAM_CLIENT_SECRET`, `NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT`.
|
|
34
|
-
*
|
|
35
|
-
* @param props - Options. See {@link SetupInstagramAuthOptions}.
|
|
36
|
-
* @returns Object with `GET` (route handler) and `getRefreshedAccessToken` (refreshes a long-lived token).
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* // app/api/(auth)/instagram/route.ts
|
|
41
|
-
* import { setupInstagramAuth } from "naystack/auth";
|
|
42
|
-
*
|
|
43
|
-
* export const { GET } = setupInstagramAuth({
|
|
44
|
-
* onUser: async (igUser, appUserId, accessToken) => {
|
|
45
|
-
* await saveInstagramUser(appUserId, igUser, accessToken);
|
|
46
|
-
* },
|
|
47
|
-
* redirectURL: "/dashboard",
|
|
48
|
-
* errorRedirectURL: "/login",
|
|
49
|
-
* });
|
|
50
|
-
* ```
|
|
51
|
-
*
|
|
52
|
-
* @category Auth
|
|
53
|
-
*/
|
|
54
|
-
declare function setupInstagramAuth(props: SetupInstagramAuthOptions): {
|
|
55
|
-
GET: (req: next_server.NextRequest) => Promise<next_server.NextResponse<unknown>>;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export { InstagramScope, type SetupInstagramAuthOptions, setupInstagramAuth };
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as next_server from 'next/server';
|
|
2
|
-
import { InstagramScope } from './utils.js';
|
|
3
|
-
export { getInstagramAuthorizationURL, getRefreshedInstagramAccessToken } from './utils.js';
|
|
4
|
-
import { InstagramUser } from '../../socials/instagram/types.js';
|
|
5
|
-
import '../../socials/meta/container.js';
|
|
6
|
-
import '../../socials/meta/types.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Options for initializing Instagram OAuth via {@link setupInstagramAuth}.
|
|
10
|
-
*
|
|
11
|
-
* @property onUser - Called with `(instagramUser, appUserId, accessToken)` after successful OAuth. Return a string to show as error (redirects to `errorRedirectURL`); return `void` on success.
|
|
12
|
-
* @property redirectURL - Where to redirect after successful Instagram auth.
|
|
13
|
-
* @property errorRedirectURL - Where to redirect on error (with `?error=` query param).
|
|
14
|
-
* @property scopes - Permissions to request. Default: `["instagram_business_basic"]`. Add `"instagram_business_content_publish"` to publish on the user's behalf.
|
|
15
|
-
*
|
|
16
|
-
* @category Auth
|
|
17
|
-
*/
|
|
18
|
-
interface SetupInstagramAuthOptions {
|
|
19
|
-
onUser: (data: InstagramUser, id: number | null, accessToken: string) => Promise<string | void>;
|
|
20
|
-
redirectURL: string;
|
|
21
|
-
errorRedirectURL: string;
|
|
22
|
-
scopes?: InstagramScope[];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Initializes Instagram OAuth. Returns a GET handler for the OAuth callback and a helper to refresh long-lived tokens.
|
|
26
|
-
*
|
|
27
|
-
* Mount the GET handler on your Instagram auth route (e.g. `app/api/(auth)/instagram/route.ts`).
|
|
28
|
-
*
|
|
29
|
-
* The single GET handler serves both the OAuth callback (`?code`) and the connect
|
|
30
|
-
* entry point (`?state` with no code → 302 to Instagram's authorize URL; see
|
|
31
|
-
* {@link getInstagramAuthorizationURL} for why that URL is spelled the way it is).
|
|
32
|
-
*
|
|
33
|
-
* Requires env vars: `INSTAGRAM_CLIENT_ID` (server-only), `INSTAGRAM_CLIENT_SECRET`, `NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT`.
|
|
34
|
-
*
|
|
35
|
-
* @param props - Options. See {@link SetupInstagramAuthOptions}.
|
|
36
|
-
* @returns Object with `GET` (route handler) and `getRefreshedAccessToken` (refreshes a long-lived token).
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* // app/api/(auth)/instagram/route.ts
|
|
41
|
-
* import { setupInstagramAuth } from "naystack/auth";
|
|
42
|
-
*
|
|
43
|
-
* export const { GET } = setupInstagramAuth({
|
|
44
|
-
* onUser: async (igUser, appUserId, accessToken) => {
|
|
45
|
-
* await saveInstagramUser(appUserId, igUser, accessToken);
|
|
46
|
-
* },
|
|
47
|
-
* redirectURL: "/dashboard",
|
|
48
|
-
* errorRedirectURL: "/login",
|
|
49
|
-
* });
|
|
50
|
-
* ```
|
|
51
|
-
*
|
|
52
|
-
* @category Auth
|
|
53
|
-
*/
|
|
54
|
-
declare function setupInstagramAuth(props: SetupInstagramAuthOptions): {
|
|
55
|
-
GET: (req: next_server.NextRequest) => Promise<next_server.NextResponse<unknown>>;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export { InstagramScope, type SetupInstagramAuthOptions, setupInstagramAuth };
|