@classytic/social 0.1.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/CHANGELOG.md +65 -0
- package/LICENSE +21 -0
- package/README.md +368 -0
- package/dist/base-Bw7e52V8.mjs +246 -0
- package/dist/base-Bw7e52V8.mjs.map +1 -0
- package/dist/base-DBtKFiSX.d.mts +226 -0
- package/dist/base-DBtKFiSX.d.mts.map +1 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/client/index.d.mts +44 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +154 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/common/index.d.mts +3 -0
- package/dist/common/index.mjs +7 -0
- package/dist/contracts-Cdwa4zlg.d.mts +121 -0
- package/dist/contracts-Cdwa4zlg.d.mts.map +1 -0
- package/dist/contracts-lCa069IK.mjs +221 -0
- package/dist/contracts-lCa069IK.mjs.map +1 -0
- package/dist/env-Bl0cwwjC.mjs +955 -0
- package/dist/env-Bl0cwwjC.mjs.map +1 -0
- package/dist/env-DxOZHf0p.d.mts +394 -0
- package/dist/env-DxOZHf0p.d.mts.map +1 -0
- package/dist/errors-Cm6LeKf7.mjs +32 -0
- package/dist/errors-Cm6LeKf7.mjs.map +1 -0
- package/dist/facebook-l_4CghaA.mjs +95 -0
- package/dist/facebook-l_4CghaA.mjs.map +1 -0
- package/dist/http-DpcLSR1M.mjs +197 -0
- package/dist/http-DpcLSR1M.mjs.map +1 -0
- package/dist/index.d.mts +42 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +71 -0
- package/dist/index.mjs.map +1 -0
- package/dist/instagram-BGaeUFU2.mjs +90 -0
- package/dist/instagram-BGaeUFU2.mjs.map +1 -0
- package/dist/linkedin-70whtVKa.mjs +101 -0
- package/dist/linkedin-70whtVKa.mjs.map +1 -0
- package/dist/meta-D3vcJU1c.mjs +126 -0
- package/dist/meta-D3vcJU1c.mjs.map +1 -0
- package/dist/pkce-jq5II68b.mjs +72 -0
- package/dist/pkce-jq5II68b.mjs.map +1 -0
- package/dist/polling-DZ1apXtA.mjs +25 -0
- package/dist/polling-DZ1apXtA.mjs.map +1 -0
- package/dist/providers/facebook.d.mts +135 -0
- package/dist/providers/facebook.d.mts.map +1 -0
- package/dist/providers/facebook.mjs +450 -0
- package/dist/providers/facebook.mjs.map +1 -0
- package/dist/providers/instagram.d.mts +122 -0
- package/dist/providers/instagram.d.mts.map +1 -0
- package/dist/providers/instagram.mjs +496 -0
- package/dist/providers/instagram.mjs.map +1 -0
- package/dist/providers/linkedin.d.mts +145 -0
- package/dist/providers/linkedin.d.mts.map +1 -0
- package/dist/providers/linkedin.mjs +574 -0
- package/dist/providers/linkedin.mjs.map +1 -0
- package/dist/providers/reddit.d.mts +102 -0
- package/dist/providers/reddit.d.mts.map +1 -0
- package/dist/providers/reddit.mjs +657 -0
- package/dist/providers/reddit.mjs.map +1 -0
- package/dist/providers/telegram.d.mts +139 -0
- package/dist/providers/telegram.d.mts.map +1 -0
- package/dist/providers/telegram.mjs +517 -0
- package/dist/providers/telegram.mjs.map +1 -0
- package/dist/providers/tiktok.d.mts +116 -0
- package/dist/providers/tiktok.d.mts.map +1 -0
- package/dist/providers/tiktok.mjs +676 -0
- package/dist/providers/tiktok.mjs.map +1 -0
- package/dist/providers/twitter.d.mts +150 -0
- package/dist/providers/twitter.d.mts.map +1 -0
- package/dist/providers/twitter.mjs +628 -0
- package/dist/providers/twitter.mjs.map +1 -0
- package/dist/providers/whatsapp.d.mts +79 -0
- package/dist/providers/whatsapp.d.mts.map +1 -0
- package/dist/providers/whatsapp.mjs +376 -0
- package/dist/providers/whatsapp.mjs.map +1 -0
- package/dist/providers/youtube.d.mts +153 -0
- package/dist/providers/youtube.d.mts.map +1 -0
- package/dist/providers/youtube.mjs +902 -0
- package/dist/providers/youtube.mjs.map +1 -0
- package/dist/reddit-B10kS4Se.mjs +126 -0
- package/dist/reddit-B10kS4Se.mjs.map +1 -0
- package/dist/schemas/index.d.mts +819 -0
- package/dist/schemas/index.d.mts.map +1 -0
- package/dist/schemas/index.mjs +31 -0
- package/dist/schemas/index.mjs.map +1 -0
- package/dist/security-BXhfebWm.d.mts +338 -0
- package/dist/security-BXhfebWm.d.mts.map +1 -0
- package/dist/shared-Fvc6xQku.mjs +100 -0
- package/dist/shared-Fvc6xQku.mjs.map +1 -0
- package/dist/telegram-FaUHpZgB.mjs +107 -0
- package/dist/telegram-FaUHpZgB.mjs.map +1 -0
- package/dist/tiktok-B_bMk4G-.mjs +94 -0
- package/dist/tiktok-B_bMk4G-.mjs.map +1 -0
- package/dist/twitter-BC22zfuc.mjs +98 -0
- package/dist/twitter-BC22zfuc.mjs.map +1 -0
- package/dist/types-BFE4psYI.d.mts +102 -0
- package/dist/types-BFE4psYI.d.mts.map +1 -0
- package/dist/types-Bv27tcT0.d.mts +230 -0
- package/dist/types-Bv27tcT0.d.mts.map +1 -0
- package/dist/types-BwkKyqpi.d.mts +253 -0
- package/dist/types-BwkKyqpi.d.mts.map +1 -0
- package/dist/types-CJrHMDV9.mjs +27 -0
- package/dist/types-CJrHMDV9.mjs.map +1 -0
- package/dist/types-ClbVc2rc.d.mts +117 -0
- package/dist/types-ClbVc2rc.d.mts.map +1 -0
- package/dist/types-D91N16Ym.d.mts +242 -0
- package/dist/types-D91N16Ym.d.mts.map +1 -0
- package/dist/types-DfLp_ibQ.d.mts +178 -0
- package/dist/types-DfLp_ibQ.d.mts.map +1 -0
- package/dist/types-DfjDgEoJ.d.mts +88 -0
- package/dist/types-DfjDgEoJ.d.mts.map +1 -0
- package/dist/types-Dp5Z9VBr.mjs +23 -0
- package/dist/types-Dp5Z9VBr.mjs.map +1 -0
- package/dist/types-hriBJTsU.d.mts +129 -0
- package/dist/types-hriBJTsU.d.mts.map +1 -0
- package/dist/types-rn6UuLL8.d.mts +184 -0
- package/dist/types-rn6UuLL8.d.mts.map +1 -0
- package/dist/whatsapp-CFp7ryR4.mjs +101 -0
- package/dist/whatsapp-CFp7ryR4.mjs.map +1 -0
- package/dist/youtube-Bs0fdY7H.mjs +98 -0
- package/dist/youtube-Bs0fdY7H.mjs.map +1 -0
- package/package.json +148 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-DQk6qfdC.mjs";
|
|
2
|
+
import { i as OAuthTokensSchema, r as NonEmptyString } from "./shared-Fvc6xQku.mjs";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
//#region src/schemas/facebook.ts
|
|
6
|
+
/**
|
|
7
|
+
* Facebook Pages zod v4 schemas.
|
|
8
|
+
*/
|
|
9
|
+
var facebook_exports = /* @__PURE__ */ __exportAll({
|
|
10
|
+
FacebookCreateLinkPostSchema: () => FacebookCreateLinkPostSchema,
|
|
11
|
+
FacebookCreatePhotoPostSchema: () => FacebookCreatePhotoPostSchema,
|
|
12
|
+
FacebookCreatePostSchema: () => FacebookCreatePostSchema,
|
|
13
|
+
FacebookCredentialDataSchema: () => FacebookCredentialDataSchema,
|
|
14
|
+
FacebookCredentialsSchema: () => FacebookCredentialsSchema,
|
|
15
|
+
FacebookFeedSchema: () => FacebookFeedSchema,
|
|
16
|
+
FacebookInsightsPeriod: () => FacebookInsightsPeriod,
|
|
17
|
+
FacebookVideoUploadSchema: () => FacebookVideoUploadSchema,
|
|
18
|
+
facebookCapabilities: () => facebookCapabilities,
|
|
19
|
+
facebookInfo: () => facebookInfo
|
|
20
|
+
});
|
|
21
|
+
const FacebookCredentialsSchema = z.object({
|
|
22
|
+
appId: NonEmptyString.describe("Facebook app ID"),
|
|
23
|
+
appSecret: NonEmptyString.describe("Facebook app secret"),
|
|
24
|
+
redirectUri: z.url().optional()
|
|
25
|
+
});
|
|
26
|
+
const FacebookCredentialDataSchema = FacebookCredentialsSchema.extend({ oauthTokenData: z.union([z.string(), OAuthTokensSchema]).optional() });
|
|
27
|
+
const ScheduledAt = z.union([z.iso.datetime(), z.date()]).optional().describe("Schedule publication time (10 minutes – 6 months in the future)");
|
|
28
|
+
const FacebookCreatePostSchema = z.object({
|
|
29
|
+
message: z.string().min(1).max(63206),
|
|
30
|
+
scheduledAt: ScheduledAt
|
|
31
|
+
});
|
|
32
|
+
const FacebookCreateLinkPostSchema = z.object({
|
|
33
|
+
link: z.url(),
|
|
34
|
+
message: z.string().max(63206).optional(),
|
|
35
|
+
scheduledAt: ScheduledAt
|
|
36
|
+
});
|
|
37
|
+
const FacebookCreatePhotoPostSchema = z.object({
|
|
38
|
+
photoUrl: z.url(),
|
|
39
|
+
caption: z.string().max(63206).optional(),
|
|
40
|
+
scheduledAt: ScheduledAt
|
|
41
|
+
});
|
|
42
|
+
const FacebookVideoUploadSchema = z.object({
|
|
43
|
+
videoUrl: z.url(),
|
|
44
|
+
title: z.string().max(255).optional(),
|
|
45
|
+
description: z.string().max(63206).optional(),
|
|
46
|
+
scheduledAt: ScheduledAt
|
|
47
|
+
});
|
|
48
|
+
const FacebookFeedSchema = z.object({
|
|
49
|
+
limit: z.number().int().min(1).max(100).optional().default(25),
|
|
50
|
+
cursor: z.string().optional()
|
|
51
|
+
});
|
|
52
|
+
const FacebookInsightsPeriod = z.enum([
|
|
53
|
+
"day",
|
|
54
|
+
"week",
|
|
55
|
+
"days_28"
|
|
56
|
+
]);
|
|
57
|
+
const facebookCapabilities = {
|
|
58
|
+
auth: "oauth2",
|
|
59
|
+
posting: true,
|
|
60
|
+
upload: true,
|
|
61
|
+
messaging: false,
|
|
62
|
+
scheduling: true,
|
|
63
|
+
deletion: true,
|
|
64
|
+
listing: true,
|
|
65
|
+
analytics: true,
|
|
66
|
+
environments: false,
|
|
67
|
+
pkce: false
|
|
68
|
+
};
|
|
69
|
+
const facebookInfo = {
|
|
70
|
+
name: "facebook",
|
|
71
|
+
displayName: "Facebook Pages",
|
|
72
|
+
scopes: [
|
|
73
|
+
"business_management",
|
|
74
|
+
"pages_show_list",
|
|
75
|
+
"pages_read_engagement",
|
|
76
|
+
"pages_manage_posts",
|
|
77
|
+
"pages_read_user_content"
|
|
78
|
+
],
|
|
79
|
+
fileLimits: {
|
|
80
|
+
photo: { maxSizeBytes: 4 * 1024 * 1024 * 1024 },
|
|
81
|
+
video: {
|
|
82
|
+
maxSizeBytes: 10 * 1024 ** 3,
|
|
83
|
+
maxDurationSec: 4 * 3600
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
scheduling: {
|
|
87
|
+
minMinutes: 10,
|
|
88
|
+
maxDays: 180
|
|
89
|
+
},
|
|
90
|
+
docsUrl: "https://developers.facebook.com/docs/pages-api"
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
//#endregion
|
|
94
|
+
export { facebook_exports as i, facebookCapabilities as n, facebookInfo as r, FacebookCredentialsSchema as t };
|
|
95
|
+
//# sourceMappingURL=facebook-l_4CghaA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facebook-l_4CghaA.mjs","names":[],"sources":["../src/schemas/facebook.ts"],"sourcesContent":["/**\n * Facebook Pages zod v4 schemas.\n */\n\nimport { z } from 'zod';\nimport type { ProviderCapabilities } from '../common/contracts.js';\nimport { NonEmptyString, OAuthTokensSchema } from './shared.js';\n\n// ─── Credentials ────────────────────────────────────────────────────────────\n\nexport const FacebookCredentialsSchema = z.object({\n appId: NonEmptyString.describe('Facebook app ID'),\n appSecret: NonEmptyString.describe('Facebook app secret'),\n redirectUri: z.url().optional(),\n});\nexport type FacebookCredentialsInput = z.infer<typeof FacebookCredentialsSchema>;\n\nexport const FacebookCredentialDataSchema = FacebookCredentialsSchema.extend({\n oauthTokenData: z.union([z.string(), OAuthTokensSchema]).optional(),\n});\n\n// ─── Post creation ──────────────────────────────────────────────────────────\n\nconst ScheduledAt = z.union([z.iso.datetime(), z.date()]).optional()\n .describe('Schedule publication time (10 minutes – 6 months in the future)');\n\nexport const FacebookCreatePostSchema = z.object({\n message: z.string().min(1).max(63206),\n scheduledAt: ScheduledAt,\n});\n\nexport const FacebookCreateLinkPostSchema = z.object({\n link: z.url(),\n message: z.string().max(63206).optional(),\n scheduledAt: ScheduledAt,\n});\n\nexport const FacebookCreatePhotoPostSchema = z.object({\n photoUrl: z.url(),\n caption: z.string().max(63206).optional(),\n scheduledAt: ScheduledAt,\n});\n\nexport const FacebookVideoUploadSchema = z.object({\n videoUrl: z.url(),\n title: z.string().max(255).optional(),\n description: z.string().max(63206).optional(),\n scheduledAt: ScheduledAt,\n});\n\n// ─── List / read ────────────────────────────────────────────────────────────\n\nexport const FacebookFeedSchema = z.object({\n limit: z.number().int().min(1).max(100).optional().default(25),\n cursor: z.string().optional(),\n});\n\nexport const FacebookInsightsPeriod = z.enum(['day', 'week', 'days_28']);\n\n// ─── Capabilities ───────────────────────────────────────────────────────────\n\nexport const facebookCapabilities: ProviderCapabilities = {\n auth: 'oauth2',\n posting: true,\n upload: true,\n messaging: false,\n scheduling: true,\n deletion: true,\n listing: true,\n analytics: true,\n environments: false,\n pkce: false,\n};\n\nexport const facebookInfo = {\n name: 'facebook' as const,\n displayName: 'Facebook Pages',\n scopes: [\n 'business_management',\n 'pages_show_list',\n 'pages_read_engagement',\n 'pages_manage_posts',\n 'pages_read_user_content',\n ],\n fileLimits: {\n photo: { maxSizeBytes: 4 * 1024 * 1024 * 1024 },\n video: { maxSizeBytes: 10 * 1024 ** 3, maxDurationSec: 4 * 3600 },\n },\n scheduling: { minMinutes: 10, maxDays: 6 * 30 },\n docsUrl: 'https://developers.facebook.com/docs/pages-api',\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAUA,MAAa,4BAA4B,EAAE,OAAO;CAChD,OAAO,eAAe,SAAS,kBAAkB;CACjD,WAAW,eAAe,SAAS,sBAAsB;CACzD,aAAa,EAAE,KAAK,CAAC,UAAU;CAChC,CAAC;AAGF,MAAa,+BAA+B,0BAA0B,OAAO,EAC3E,gBAAgB,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC,UAAU,EACpE,CAAC;AAIF,MAAM,cAAc,EAAE,MAAM,CAAC,EAAE,IAAI,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CACjE,SAAS,kEAAkE;AAE9E,MAAa,2BAA2B,EAAE,OAAO;CAC/C,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM;CACrC,aAAa;CACd,CAAC;AAEF,MAAa,+BAA+B,EAAE,OAAO;CACnD,MAAM,EAAE,KAAK;CACb,SAAS,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,UAAU;CACzC,aAAa;CACd,CAAC;AAEF,MAAa,gCAAgC,EAAE,OAAO;CACpD,UAAU,EAAE,KAAK;CACjB,SAAS,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,UAAU;CACzC,aAAa;CACd,CAAC;AAEF,MAAa,4BAA4B,EAAE,OAAO;CAChD,UAAU,EAAE,KAAK;CACjB,OAAO,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU;CACrC,aAAa,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,UAAU;CAC7C,aAAa;CACd,CAAC;AAIF,MAAa,qBAAqB,EAAE,OAAO;CACzC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;CAC9D,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC9B,CAAC;AAEF,MAAa,yBAAyB,EAAE,KAAK;CAAC;CAAO;CAAQ;CAAU,CAAC;AAIxE,MAAa,uBAA6C;CACxD,MAAM;CACN,SAAS;CACT,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,UAAU;CACV,SAAS;CACT,WAAW;CACX,cAAc;CACd,MAAM;CACP;AAED,MAAa,eAAe;CAC1B,MAAM;CACN,aAAa;CACb,QAAQ;EACN;EACA;EACA;EACA;EACA;EACD;CACD,YAAY;EACV,OAAO,EAAE,cAAc,IAAI,OAAO,OAAO,MAAM;EAC/C,OAAO;GAAE,cAAc,KAAK,QAAQ;GAAG,gBAAgB,IAAI;GAAM;EAClE;CACD,YAAY;EAAE,YAAY;EAAI,SAAS;EAAQ;CAC/C,SAAS;CACV"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { t as SocialError } from "./errors-Cm6LeKf7.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/common/http.ts
|
|
4
|
+
/**
|
|
5
|
+
* Shared HTTP client for all providers.
|
|
6
|
+
*
|
|
7
|
+
* Centralizes:
|
|
8
|
+
* - Timeouts (AbortController)
|
|
9
|
+
* - Retry with exponential backoff and Retry-After honoring
|
|
10
|
+
* - 429 / 5xx detection
|
|
11
|
+
* - JSON / form-urlencoded / multipart bodies
|
|
12
|
+
* - Structured errors via SocialError
|
|
13
|
+
*
|
|
14
|
+
* All provider _api helpers should delegate to this module.
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_TIMEOUT = 3e4;
|
|
17
|
+
const DEFAULT_RETRY_STATUSES = [
|
|
18
|
+
429,
|
|
19
|
+
502,
|
|
20
|
+
503,
|
|
21
|
+
504
|
|
22
|
+
];
|
|
23
|
+
function buildUrl(url, query) {
|
|
24
|
+
if (!query) return url;
|
|
25
|
+
const params = new URLSearchParams();
|
|
26
|
+
for (const [k, v] of Object.entries(query)) {
|
|
27
|
+
if (v === void 0 || v === null) continue;
|
|
28
|
+
params.append(k, String(v));
|
|
29
|
+
}
|
|
30
|
+
const qs = params.toString();
|
|
31
|
+
if (!qs) return url;
|
|
32
|
+
return url + (url.includes("?") ? "&" : "?") + qs;
|
|
33
|
+
}
|
|
34
|
+
function parseRetryAfter(headers) {
|
|
35
|
+
const ra = headers?.get?.("retry-after");
|
|
36
|
+
if (!ra) return null;
|
|
37
|
+
const seconds = Number(ra);
|
|
38
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds);
|
|
39
|
+
const dateMs = Date.parse(ra);
|
|
40
|
+
if (!Number.isNaN(dateMs)) return Math.max(0, Math.ceil((dateMs - Date.now()) / 1e3));
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function backoffDelay(attempt, base, max, retryAfter) {
|
|
44
|
+
if (retryAfter !== null) return Math.min(max, retryAfter * 1e3);
|
|
45
|
+
const exp = Math.min(max, base * 2 ** attempt);
|
|
46
|
+
return Math.floor(Math.random() * exp);
|
|
47
|
+
}
|
|
48
|
+
async function readResponseBody(response) {
|
|
49
|
+
const contentType = response.headers?.get?.("content-type") || "";
|
|
50
|
+
if (response.status === 204) return null;
|
|
51
|
+
if (!contentType || contentType.includes("application/json")) try {
|
|
52
|
+
if (typeof response.json === "function") return await response.json();
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if (typeof response.text !== "function") return null;
|
|
57
|
+
const text = await response.text();
|
|
58
|
+
if (!text) return null;
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(text);
|
|
61
|
+
} catch {
|
|
62
|
+
return text;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function buildBody(opts) {
|
|
66
|
+
const headers = {};
|
|
67
|
+
if (opts.json !== void 0) {
|
|
68
|
+
headers["Content-Type"] = "application/json";
|
|
69
|
+
return {
|
|
70
|
+
body: JSON.stringify(opts.json),
|
|
71
|
+
headers
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (opts.form !== void 0) return {
|
|
75
|
+
body: opts.form,
|
|
76
|
+
headers
|
|
77
|
+
};
|
|
78
|
+
if (opts.urlencoded !== void 0) {
|
|
79
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
80
|
+
return {
|
|
81
|
+
body: opts.urlencoded instanceof URLSearchParams ? opts.urlencoded.toString() : new URLSearchParams(opts.urlencoded).toString(),
|
|
82
|
+
headers
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (opts.binary !== void 0) return {
|
|
86
|
+
body: opts.binary instanceof Uint8Array ? opts.binary : opts.binary instanceof ArrayBuffer ? new Uint8Array(opts.binary) : new Uint8Array(opts.binary),
|
|
87
|
+
headers
|
|
88
|
+
};
|
|
89
|
+
if (opts.text !== void 0) {
|
|
90
|
+
headers["Content-Type"] = "text/plain";
|
|
91
|
+
return {
|
|
92
|
+
body: opts.text,
|
|
93
|
+
headers
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
body: void 0,
|
|
98
|
+
headers
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Core request function. Throws SocialError on failure. Returns parsed body on success.
|
|
103
|
+
*
|
|
104
|
+
* @param provider — provider name used for error attribution
|
|
105
|
+
* @param opts — request options
|
|
106
|
+
*/
|
|
107
|
+
async function httpRequest(provider, opts) {
|
|
108
|
+
const method = opts.method ?? "GET";
|
|
109
|
+
const url = buildUrl(opts.url, opts.query);
|
|
110
|
+
const timeout = opts.timeout ?? DEFAULT_TIMEOUT;
|
|
111
|
+
const retry = opts.retry ?? { attempts: 0 };
|
|
112
|
+
const retryStatuses = retry.on ?? DEFAULT_RETRY_STATUSES;
|
|
113
|
+
const baseDelay = retry.baseDelayMs ?? 500;
|
|
114
|
+
const maxDelay = retry.maxDelayMs ?? 3e4;
|
|
115
|
+
const { body, headers: bodyHeaders } = buildBody(opts);
|
|
116
|
+
const headers = {
|
|
117
|
+
Accept: "application/json",
|
|
118
|
+
...bodyHeaders,
|
|
119
|
+
...opts.headers ?? {}
|
|
120
|
+
};
|
|
121
|
+
if (opts.bearer) headers.Authorization = `Bearer ${opts.bearer}`;
|
|
122
|
+
let lastError = null;
|
|
123
|
+
const totalAttempts = retry.attempts + 1;
|
|
124
|
+
for (let attempt = 0; attempt < totalAttempts; attempt++) {
|
|
125
|
+
const controller = new AbortController();
|
|
126
|
+
const timer = timeout > 0 ? setTimeout(() => controller.abort(), timeout) : null;
|
|
127
|
+
const callerAbort = () => controller.abort();
|
|
128
|
+
if (opts.signal) if (opts.signal.aborted) controller.abort();
|
|
129
|
+
else opts.signal.addEventListener("abort", callerAbort, { once: true });
|
|
130
|
+
let response;
|
|
131
|
+
try {
|
|
132
|
+
response = await fetch(url, {
|
|
133
|
+
method,
|
|
134
|
+
headers,
|
|
135
|
+
body,
|
|
136
|
+
signal: controller.signal
|
|
137
|
+
});
|
|
138
|
+
} catch (err) {
|
|
139
|
+
if (timer) clearTimeout(timer);
|
|
140
|
+
opts.signal?.removeEventListener("abort", callerAbort);
|
|
141
|
+
const isTimeout = err.name === "AbortError" && !opts.signal?.aborted;
|
|
142
|
+
lastError = new SocialError(provider, isTimeout ? `Request timed out after ${timeout}ms` : `Network error: ${err.message}`, {
|
|
143
|
+
statusCode: isTimeout ? 504 : 502,
|
|
144
|
+
retryable: true,
|
|
145
|
+
originalError: err
|
|
146
|
+
});
|
|
147
|
+
if (attempt < totalAttempts - 1) {
|
|
148
|
+
await sleep(backoffDelay(attempt, baseDelay, maxDelay, null));
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
throw lastError;
|
|
152
|
+
} finally {
|
|
153
|
+
if (timer) clearTimeout(timer);
|
|
154
|
+
opts.signal?.removeEventListener("abort", callerAbort);
|
|
155
|
+
}
|
|
156
|
+
const status = response.status ?? 200;
|
|
157
|
+
const responseHeaders = response.headers ?? new Headers();
|
|
158
|
+
if (response.ok ?? (status >= 200 && status < 300)) return {
|
|
159
|
+
data: await readResponseBody(response),
|
|
160
|
+
status,
|
|
161
|
+
headers: responseHeaders
|
|
162
|
+
};
|
|
163
|
+
const raw = await readResponseBody(response);
|
|
164
|
+
const retryAfter = parseRetryAfter(responseHeaders);
|
|
165
|
+
if (retryStatuses.includes(status) && attempt < totalAttempts - 1) {
|
|
166
|
+
await sleep(backoffDelay(attempt, baseDelay, maxDelay, retryAfter));
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const parsed = opts.parseError?.(raw, status, responseHeaders);
|
|
170
|
+
const isRetryable = status === 429 || status >= 500;
|
|
171
|
+
throw new SocialError(provider, parsed?.message ?? defaultErrorMessage(status, raw), {
|
|
172
|
+
statusCode: status >= 400 && status < 500 ? status : 502,
|
|
173
|
+
errorCode: parsed?.errorCode ?? null,
|
|
174
|
+
hint: parsed?.hint ?? null,
|
|
175
|
+
retryable: parsed?.retryable ?? isRetryable,
|
|
176
|
+
retryAfter: parsed?.retryAfter ?? retryAfter,
|
|
177
|
+
...parsed?.extras ?? {}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
throw lastError ?? new SocialError(provider, "Unknown HTTP error");
|
|
181
|
+
}
|
|
182
|
+
function defaultErrorMessage(status, raw) {
|
|
183
|
+
if (raw && typeof raw === "object") {
|
|
184
|
+
const r = raw;
|
|
185
|
+
const msg = r.message ?? r.error_description ?? r.detail ?? r.error;
|
|
186
|
+
if (typeof msg === "string") return msg;
|
|
187
|
+
}
|
|
188
|
+
if (typeof raw === "string" && raw.trim()) return raw;
|
|
189
|
+
return `HTTP ${status}`;
|
|
190
|
+
}
|
|
191
|
+
function sleep(ms) {
|
|
192
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//#endregion
|
|
196
|
+
export { httpRequest as t };
|
|
197
|
+
//# sourceMappingURL=http-DpcLSR1M.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-DpcLSR1M.mjs","names":[],"sources":["../src/common/http.ts"],"sourcesContent":["/**\n * Shared HTTP client for all providers.\n *\n * Centralizes:\n * - Timeouts (AbortController)\n * - Retry with exponential backoff and Retry-After honoring\n * - 429 / 5xx detection\n * - JSON / form-urlencoded / multipart bodies\n * - Structured errors via SocialError\n *\n * All provider _api helpers should delegate to this module.\n */\n\nimport { SocialError } from '../errors.js';\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\nexport type ParseError<E> = (raw: unknown, status: number, headers: Headers) => {\n message: string;\n errorCode?: string | number | null;\n hint?: string | null;\n retryable?: boolean | null;\n retryAfter?: number | null;\n extras?: Record<string, unknown>;\n} | null;\n\nexport interface RetryConfig {\n /** Max retry attempts (in addition to the initial request). Default 0. */\n attempts: number;\n /** HTTP status codes that should trigger a retry. Default [429, 502, 503, 504]. */\n on?: number[];\n /** Base delay in ms before exponential backoff. Default 500. */\n baseDelayMs?: number;\n /** Cap on backoff delay. Default 30_000. */\n maxDelayMs?: number;\n}\n\nexport interface HttpRequestOptions<E = unknown> {\n method?: HttpMethod;\n url: string;\n query?: Record<string, string | number | boolean | undefined | null>;\n /** JSON body. Mutually exclusive with `form`, `urlencoded`, `binary`, `text`. */\n json?: unknown;\n /** multipart/form-data body. */\n form?: FormData;\n /** application/x-www-form-urlencoded body. */\n urlencoded?: URLSearchParams | Record<string, string>;\n /** Raw binary body. */\n binary?: ArrayBuffer | Uint8Array | Buffer;\n /** Raw text body. */\n text?: string;\n headers?: Record<string, string>;\n /** Convenience: sets `Authorization: Bearer <token>`. */\n bearer?: string;\n /** Request timeout in ms. Default 30_000. Use 0 to disable. */\n timeout?: number;\n /** Retry policy. Default no retries. */\n retry?: RetryConfig;\n /** Provider-specific error parser invoked when the response is not OK. */\n parseError?: ParseError<E>;\n /** AbortSignal for caller-driven cancellation. */\n signal?: AbortSignal;\n}\n\nexport interface HttpResponse<T> {\n data: T;\n status: number;\n headers: Headers;\n}\n\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_RETRY_STATUSES = [429, 502, 503, 504];\n\nfunction buildUrl(url: string, query?: HttpRequestOptions['query']): string {\n if (!query) return url;\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null) continue;\n params.append(k, String(v));\n }\n const qs = params.toString();\n if (!qs) return url;\n return url + (url.includes('?') ? '&' : '?') + qs;\n}\n\nfunction parseRetryAfter(headers: Headers): number | null {\n const ra = headers?.get?.('retry-after');\n if (!ra) return null;\n const seconds = Number(ra);\n if (Number.isFinite(seconds)) return Math.max(0, seconds);\n // HTTP-date format\n const dateMs = Date.parse(ra);\n if (!Number.isNaN(dateMs)) {\n return Math.max(0, Math.ceil((dateMs - Date.now()) / 1000));\n }\n return null;\n}\n\nfunction backoffDelay(attempt: number, base: number, max: number, retryAfter: number | null): number {\n if (retryAfter !== null) return Math.min(max, retryAfter * 1000);\n // Exponential backoff with full jitter\n const exp = Math.min(max, base * 2 ** attempt);\n return Math.floor(Math.random() * exp);\n}\n\nasync function readResponseBody(response: Response): Promise<unknown> {\n // Defensive against test fixtures with partial Response shapes.\n const contentType = response.headers?.get?.('content-type') || '';\n if (response.status === 204) return null;\n if (!contentType || contentType.includes('application/json')) {\n try {\n if (typeof response.json === 'function') return await response.json();\n } catch {\n return null;\n }\n }\n // Fall back to text for non-JSON responses (LinkedIn binary uploads, errors with HTML, etc.)\n if (typeof response.text !== 'function') return null;\n const text = await response.text();\n if (!text) return null;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\ntype RequestBody = NonNullable<RequestInit['body']>;\n\nfunction buildBody(opts: HttpRequestOptions): {\n body: RequestBody | undefined;\n headers: Record<string, string>;\n} {\n const headers: Record<string, string> = {};\n if (opts.json !== undefined) {\n headers['Content-Type'] = 'application/json';\n return { body: JSON.stringify(opts.json), headers };\n }\n if (opts.form !== undefined) {\n return { body: opts.form, headers };\n }\n if (opts.urlencoded !== undefined) {\n headers['Content-Type'] = 'application/x-www-form-urlencoded';\n const body = opts.urlencoded instanceof URLSearchParams\n ? opts.urlencoded.toString()\n : new URLSearchParams(opts.urlencoded).toString();\n return { body, headers };\n }\n if (opts.binary !== undefined) {\n const body: RequestBody = opts.binary instanceof Uint8Array\n ? opts.binary\n : opts.binary instanceof ArrayBuffer\n ? new Uint8Array(opts.binary)\n : new Uint8Array(opts.binary as Uint8Array);\n return { body, headers };\n }\n if (opts.text !== undefined) {\n headers['Content-Type'] = 'text/plain';\n return { body: opts.text, headers };\n }\n return { body: undefined, headers };\n}\n\n/**\n * Core request function. Throws SocialError on failure. Returns parsed body on success.\n *\n * @param provider — provider name used for error attribution\n * @param opts — request options\n */\nexport async function httpRequest<T = unknown, E = unknown>(\n provider: string,\n opts: HttpRequestOptions<E>,\n): Promise<HttpResponse<T>> {\n const method = opts.method ?? 'GET';\n const url = buildUrl(opts.url, opts.query);\n const timeout = opts.timeout ?? DEFAULT_TIMEOUT;\n const retry = opts.retry ?? { attempts: 0 };\n const retryStatuses = retry.on ?? DEFAULT_RETRY_STATUSES;\n const baseDelay = retry.baseDelayMs ?? 500;\n const maxDelay = retry.maxDelayMs ?? 30_000;\n\n const { body, headers: bodyHeaders } = buildBody(opts);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n ...bodyHeaders,\n ...(opts.headers ?? {}),\n };\n if (opts.bearer) headers.Authorization = `Bearer ${opts.bearer}`;\n\n let lastError: SocialError | null = null;\n const totalAttempts = retry.attempts + 1;\n\n for (let attempt = 0; attempt < totalAttempts; attempt++) {\n const controller = new AbortController();\n const timer = timeout > 0 ? setTimeout(() => controller.abort(), timeout) : null;\n\n // Combine caller-supplied signal with timeout signal\n const callerAbort = () => controller.abort();\n if (opts.signal) {\n if (opts.signal.aborted) controller.abort();\n else opts.signal.addEventListener('abort', callerAbort, { once: true });\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body,\n signal: controller.signal,\n });\n } catch (err) {\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener('abort', callerAbort);\n\n const isAbort = (err as Error).name === 'AbortError';\n const isTimeout = isAbort && !opts.signal?.aborted;\n lastError = new SocialError(provider, isTimeout ? `Request timed out after ${timeout}ms` : `Network error: ${(err as Error).message}`, {\n statusCode: isTimeout ? 504 : 502,\n retryable: true,\n originalError: err as Error,\n });\n // Retry on network errors / timeouts if we have attempts left\n if (attempt < totalAttempts - 1) {\n await sleep(backoffDelay(attempt, baseDelay, maxDelay, null));\n continue;\n }\n throw lastError;\n } finally {\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener('abort', callerAbort);\n }\n\n // Defensive against partial test fixtures: treat undefined `ok` as ok if\n // status is missing or 2xx; treat undefined headers as empty Headers.\n const status = response.status ?? 200;\n const responseHeaders = response.headers ?? new Headers();\n const isOk = response.ok ?? (status >= 200 && status < 300);\n\n if (isOk) {\n const data = await readResponseBody(response) as T;\n return { data, status, headers: responseHeaders };\n }\n\n // Non-OK response — read body and decide whether to retry / throw\n const raw = await readResponseBody(response);\n const retryAfter = parseRetryAfter(responseHeaders);\n const shouldRetry = retryStatuses.includes(status) && attempt < totalAttempts - 1;\n\n if (shouldRetry) {\n await sleep(backoffDelay(attempt, baseDelay, maxDelay, retryAfter));\n continue;\n }\n\n // Build SocialError with optional provider-specific parser\n const parsed = opts.parseError?.(raw, status, responseHeaders);\n const isRetryable = status === 429 || status >= 500;\n throw new SocialError(provider, parsed?.message ?? defaultErrorMessage(status, raw), {\n statusCode: status >= 400 && status < 500 ? status : 502,\n errorCode: parsed?.errorCode ?? null,\n hint: parsed?.hint ?? null,\n retryable: parsed?.retryable ?? isRetryable,\n retryAfter: parsed?.retryAfter ?? retryAfter,\n ...(parsed?.extras ?? {}),\n });\n }\n\n // Unreachable, but required for control-flow analysis\n throw lastError ?? new SocialError(provider, 'Unknown HTTP error');\n}\n\nfunction defaultErrorMessage(status: number, raw: unknown): string {\n if (raw && typeof raw === 'object') {\n const r = raw as Record<string, unknown>;\n const msg = r.message ?? r.error_description ?? r.detail ?? r.error;\n if (typeof msg === 'string') return msg;\n }\n if (typeof raw === 'string' && raw.trim()) return raw;\n return `HTTP ${status}`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n// Re-export error type for convenience\nexport { SocialError };\n"],"mappings":"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"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { _ as ValidationResult, a as CredentialFieldType, c as PrivacyLevel, d as ProviderMetadata, f as SetupGuideStep, g as UploadResult, h as UploadParams, i as CredentialField, l as ProviderConfig, m as TestStatus, n as AuthType, o as OAuthTokens, p as TestResult, r as AuthUrlOptions, s as PlatformProvider, t as AccountInfo, u as ProviderEnvironment, v as deriveCredentialFields } from "./base-DBtKFiSX.mjs";
|
|
2
|
+
import { TwitterProvider } from "./providers/twitter.mjs";
|
|
3
|
+
import { A as WhatsAppClientConfig, C as SocialClientOptions, E as TwitterClientConfig, O as UnifiedPostInput, S as RedditClientConfig, T as TikTokClientConfig, _ as MultiPostResult, a as YouTubeClient, b as ProviderConfigMap, c as LinkedInClient, d as FacebookClientConfig, f as InstagramClientConfig, g as MultiPostInput, h as MessageResult, i as TikTokClient, j as YouTubeClientConfig, k as UnifiedUploadInput, l as FacebookClient, m as MessageInput, n as WhatsAppClient, o as InstagramClient, p as LinkedInClientConfig, r as TelegramClient, s as RedditClient, t as fromEnv, u as TwitterClient, v as MultiUploadInput, w as TelegramClientConfig, x as ProviderName, y as PostResult } from "./env-DxOZHf0p.mjs";
|
|
4
|
+
import { FacebookProvider } from "./providers/facebook.mjs";
|
|
5
|
+
import { LinkedInProvider } from "./providers/linkedin.mjs";
|
|
6
|
+
import { RedditProvider } from "./providers/reddit.mjs";
|
|
7
|
+
import { InstagramProvider } from "./providers/instagram.mjs";
|
|
8
|
+
import { YouTubeProvider } from "./providers/youtube.mjs";
|
|
9
|
+
import { TikTokProvider } from "./providers/tiktok.mjs";
|
|
10
|
+
import { TelegramProvider } from "./providers/telegram.mjs";
|
|
11
|
+
import { WhatsAppProvider } from "./providers/whatsapp.mjs";
|
|
12
|
+
import { a as ProviderCapabilities, c as UnifiedPostInput$1, d as isPostingProvider, f as isUploadingProvider, i as ProviderAuth, l as UploadingProvider, n as MessagingProvider, o as UnifiedMedia, r as PostingProvider, s as UnifiedPost, u as isMessagingProvider } from "./contracts-Cdwa4zlg.mjs";
|
|
13
|
+
import { SocialClient } from "./client/index.mjs";
|
|
14
|
+
import { A as SocialErrorOptions, D as RetryConfig, O as httpRequest, S as generateCodeVerifier, T as HttpResponse, _ as buildAuthUrl, a as Page, b as PkceStore, c as paginate, d as metaExchangeLongLived, f as metaRefreshLongLivedFacebook, i as pollUntilComplete, k as SocialError, n as redactSecrets, p as metaRefreshLongLivedInstagram, r as PollOptions, s as PaginatedIterable, t as assertPublicHttpUrl, v as oauth2ExchangeCode, w as HttpRequestOptions, x as generateCodeChallenge, y as oauth2RefreshToken } from "./security-BXhfebWm.mjs";
|
|
15
|
+
|
|
16
|
+
//#region src/registry.d.ts
|
|
17
|
+
interface RegistryConfig {
|
|
18
|
+
/** Server port for default redirect URI construction */
|
|
19
|
+
port?: number;
|
|
20
|
+
/** Per-provider redirect URI overrides */
|
|
21
|
+
redirectUris?: Partial<Record<string, string>>;
|
|
22
|
+
/** Provider environment — 'sandbox' for dev/testing, 'production' for audited/live apps */
|
|
23
|
+
environment?: 'sandbox' | 'production';
|
|
24
|
+
}
|
|
25
|
+
interface ProviderRegistry {
|
|
26
|
+
/** Get a provider by platform name */
|
|
27
|
+
getProvider(name: string): PlatformProvider | null;
|
|
28
|
+
/** Get metadata for all registered providers */
|
|
29
|
+
getAllProviders(): ProviderMetadata[];
|
|
30
|
+
/** Check if a provider is registered */
|
|
31
|
+
hasProvider(name: string): boolean;
|
|
32
|
+
/** Get list of registered provider names */
|
|
33
|
+
getProviderNames(): string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a new provider registry with all 9 providers.
|
|
37
|
+
* Providers are dynamically imported in parallel for fast startup.
|
|
38
|
+
*/
|
|
39
|
+
declare function createRegistry(config?: RegistryConfig): Promise<ProviderRegistry>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { type AccountInfo, type AuthType, type AuthUrlOptions, type UnifiedPostInput as ClientPostInput, type CredentialField, type CredentialFieldType, FacebookClient, type FacebookClientConfig, FacebookProvider, type HttpRequestOptions, type HttpResponse, InstagramClient, type InstagramClientConfig, InstagramProvider, LinkedInClient, type LinkedInClientConfig, LinkedInProvider, type MessageInput, type MessageResult, type MessagingProvider, type MultiPostInput, type MultiPostResult, type MultiUploadInput, type OAuthTokens, type Page, type PaginatedIterable, PkceStore, PlatformProvider, type PollOptions, type PostResult, type PostingProvider, type PrivacyLevel, type ProviderAuth, type ProviderCapabilities, type ProviderConfig, type ProviderConfigMap, type ProviderEnvironment, type ProviderMetadata, type ProviderName, type ProviderRegistry, RedditClient, type RedditClientConfig, RedditProvider, type RegistryConfig, type RetryConfig, type SetupGuideStep, SocialClient, type SocialClientOptions, SocialError, type SocialErrorOptions, TelegramClient, type TelegramClientConfig, TelegramProvider, type TestResult, type TestStatus, TikTokClient, type TikTokClientConfig, TikTokProvider, TwitterClient, type TwitterClientConfig, TwitterProvider, type UnifiedMedia, type UnifiedPost, type UnifiedPostInput$1 as UnifiedPostInput, type UnifiedUploadInput, type UploadParams, type UploadResult, type UploadingProvider, type ValidationResult, WhatsAppClient, type WhatsAppClientConfig, WhatsAppProvider, YouTubeClient, type YouTubeClientConfig, YouTubeProvider, assertPublicHttpUrl, buildAuthUrl, createRegistry, deriveCredentialFields, fromEnv, generateCodeChallenge, generateCodeVerifier, httpRequest, isMessagingProvider, isPostingProvider, isUploadingProvider, metaExchangeLongLived, metaRefreshLongLivedFacebook, metaRefreshLongLivedInstagram, oauth2ExchangeCode, oauth2RefreshToken, paginate, pollUntilComplete, redactSecrets };
|
|
42
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;;;;;;;;;;;UAgBiB,cAAA;;EAEf,IAAA;EAF6B;EAI7B,YAAA,GAAe,OAAA,CAAQ,MAAA;EAAD;EAEtB,WAAA;AAAA;AAAA,UAGe,gBAAA;EALQ;EAOvB,WAAA,CAAY,IAAA,WAAe,gBAAA;EALhB;EAOX,eAAA,IAAmB,gBAAA;EAJJ;EAMf,WAAA,CAAY,IAAA;;EAEZ,gBAAA;AAAA;;;;;iBASoB,cAAA,CAAe,MAAA,GAAQ,cAAA,GAAsB,OAAA,CAAQ,gBAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { n as deriveCredentialFields, t as PlatformProvider } from "./base-Bw7e52V8.mjs";
|
|
2
|
+
import { t as SocialError } from "./errors-Cm6LeKf7.mjs";
|
|
3
|
+
import { i as metaRefreshLongLivedInstagram, n as metaExchangeLongLived, r as metaRefreshLongLivedFacebook } from "./meta-D3vcJU1c.mjs";
|
|
4
|
+
import { t as httpRequest } from "./http-DpcLSR1M.mjs";
|
|
5
|
+
import { n as generateCodeChallenge, r as generateCodeVerifier, t as PkceStore } from "./pkce-jq5II68b.mjs";
|
|
6
|
+
import { a as redactSecrets, c as oauth2ExchangeCode, i as assertPublicHttpUrl, l as oauth2RefreshToken, n as isPostingProvider, o as paginate, r as isUploadingProvider, s as buildAuthUrl, t as isMessagingProvider } from "./contracts-lCa069IK.mjs";
|
|
7
|
+
import { t as pollUntilComplete } from "./polling-DZ1apXtA.mjs";
|
|
8
|
+
import { TwitterProvider } from "./providers/twitter.mjs";
|
|
9
|
+
import { a as YouTubeClient, c as LinkedInClient, i as TikTokClient, l as FacebookClient, n as WhatsAppClient, o as InstagramClient, r as TelegramClient, s as RedditClient, t as fromEnv, u as TwitterClient } from "./env-Bl0cwwjC.mjs";
|
|
10
|
+
import { FacebookProvider } from "./providers/facebook.mjs";
|
|
11
|
+
import { LinkedInProvider } from "./providers/linkedin.mjs";
|
|
12
|
+
import { RedditProvider } from "./providers/reddit.mjs";
|
|
13
|
+
import { InstagramProvider } from "./providers/instagram.mjs";
|
|
14
|
+
import { YouTubeProvider } from "./providers/youtube.mjs";
|
|
15
|
+
import { TikTokProvider } from "./providers/tiktok.mjs";
|
|
16
|
+
import { TelegramProvider } from "./providers/telegram.mjs";
|
|
17
|
+
import { WhatsAppProvider } from "./providers/whatsapp.mjs";
|
|
18
|
+
import { SocialClient } from "./client/index.mjs";
|
|
19
|
+
|
|
20
|
+
//#region src/registry.ts
|
|
21
|
+
/**
|
|
22
|
+
* Create a new provider registry with all 9 providers.
|
|
23
|
+
* Providers are dynamically imported in parallel for fast startup.
|
|
24
|
+
*/
|
|
25
|
+
async function createRegistry(config = {}) {
|
|
26
|
+
const providers = /* @__PURE__ */ new Map();
|
|
27
|
+
const [{ YouTubeProvider }, { TikTokProvider }, { InstagramProvider }, { WhatsAppProvider }, { TelegramProvider }, { LinkedInProvider }, { FacebookProvider }, { TwitterProvider }, { RedditProvider }] = await Promise.all([
|
|
28
|
+
import("./providers/youtube.mjs"),
|
|
29
|
+
import("./providers/tiktok.mjs"),
|
|
30
|
+
import("./providers/instagram.mjs"),
|
|
31
|
+
import("./providers/whatsapp.mjs"),
|
|
32
|
+
import("./providers/telegram.mjs"),
|
|
33
|
+
import("./providers/linkedin.mjs"),
|
|
34
|
+
import("./providers/facebook.mjs"),
|
|
35
|
+
import("./providers/twitter.mjs"),
|
|
36
|
+
import("./providers/reddit.mjs")
|
|
37
|
+
]);
|
|
38
|
+
const { port, redirectUris = {}, environment } = config;
|
|
39
|
+
const providerConfig = (name) => ({
|
|
40
|
+
port,
|
|
41
|
+
redirectUri: redirectUris[name],
|
|
42
|
+
environment
|
|
43
|
+
});
|
|
44
|
+
providers.set("youtube", new YouTubeProvider(providerConfig("youtube")));
|
|
45
|
+
providers.set("tiktok", new TikTokProvider(providerConfig("tiktok")));
|
|
46
|
+
providers.set("instagram", new InstagramProvider(providerConfig("instagram")));
|
|
47
|
+
providers.set("whatsapp", new WhatsAppProvider(providerConfig("whatsapp")));
|
|
48
|
+
providers.set("telegram", new TelegramProvider(providerConfig("telegram")));
|
|
49
|
+
providers.set("linkedin", new LinkedInProvider(providerConfig("linkedin")));
|
|
50
|
+
providers.set("facebook", new FacebookProvider(providerConfig("facebook")));
|
|
51
|
+
providers.set("twitter", new TwitterProvider(providerConfig("twitter")));
|
|
52
|
+
providers.set("reddit", new RedditProvider(providerConfig("reddit")));
|
|
53
|
+
return {
|
|
54
|
+
getProvider(name) {
|
|
55
|
+
return providers.get(name) ?? null;
|
|
56
|
+
},
|
|
57
|
+
getAllProviders() {
|
|
58
|
+
return Array.from(providers.values()).map((p) => p.getMetadata());
|
|
59
|
+
},
|
|
60
|
+
hasProvider(name) {
|
|
61
|
+
return providers.has(name);
|
|
62
|
+
},
|
|
63
|
+
getProviderNames() {
|
|
64
|
+
return Array.from(providers.keys());
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { FacebookClient, FacebookProvider, InstagramClient, InstagramProvider, LinkedInClient, LinkedInProvider, PkceStore, PlatformProvider, RedditClient, RedditProvider, SocialClient, SocialError, TelegramClient, TelegramProvider, TikTokClient, TikTokProvider, TwitterClient, TwitterProvider, WhatsAppClient, WhatsAppProvider, YouTubeClient, YouTubeProvider, assertPublicHttpUrl, buildAuthUrl, createRegistry, deriveCredentialFields, fromEnv, generateCodeChallenge, generateCodeVerifier, httpRequest, isMessagingProvider, isPostingProvider, isUploadingProvider, metaExchangeLongLived, metaRefreshLongLivedFacebook, metaRefreshLongLivedInstagram, oauth2ExchangeCode, oauth2RefreshToken, paginate, pollUntilComplete, redactSecrets };
|
|
71
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/registry.ts"],"sourcesContent":["/**\n * Provider Registry Factory\n * =========================\n * Creates a registry of social media provider instances.\n * Factory pattern (not module-level singleton) for testability.\n *\n * Usage:\n * import { createRegistry } from '@classytic/social';\n *\n * const registry = await createRegistry({ port: 8060 });\n * const yt = registry.getProvider('youtube');\n * await yt.uploadVideo({ ... });\n */\n\nimport type { PlatformProvider, ProviderConfig, ProviderMetadata } from './base.js';\n\nexport interface RegistryConfig {\n /** Server port for default redirect URI construction */\n port?: number;\n /** Per-provider redirect URI overrides */\n redirectUris?: Partial<Record<string, string>>;\n /** Provider environment — 'sandbox' for dev/testing, 'production' for audited/live apps */\n environment?: 'sandbox' | 'production';\n}\n\nexport interface ProviderRegistry {\n /** Get a provider by platform name */\n getProvider(name: string): PlatformProvider | null;\n /** Get metadata for all registered providers */\n getAllProviders(): ProviderMetadata[];\n /** Check if a provider is registered */\n hasProvider(name: string): boolean;\n /** Get list of registered provider names */\n getProviderNames(): string[];\n}\n\nconst PROVIDER_NAMES = ['youtube', 'tiktok', 'instagram', 'whatsapp', 'telegram', 'linkedin', 'facebook', 'twitter', 'reddit'] as const;\n\n/**\n * Create a new provider registry with all 9 providers.\n * Providers are dynamically imported in parallel for fast startup.\n */\nexport async function createRegistry(config: RegistryConfig = {}): Promise<ProviderRegistry> {\n const providers = new Map<string, PlatformProvider>();\n\n // Dynamic import all providers in parallel\n const [\n { YouTubeProvider },\n { TikTokProvider },\n { InstagramProvider },\n { WhatsAppProvider },\n { TelegramProvider },\n { LinkedInProvider },\n { FacebookProvider },\n { TwitterProvider },\n { RedditProvider },\n ] = await Promise.all([\n import('./providers/youtube/index.js'),\n import('./providers/tiktok/index.js'),\n import('./providers/instagram/index.js'),\n import('./providers/whatsapp/index.js'),\n import('./providers/telegram/index.js'),\n import('./providers/linkedin/index.js'),\n import('./providers/facebook/index.js'),\n import('./providers/twitter/index.js'),\n import('./providers/reddit/index.js'),\n ]);\n\n const { port, redirectUris = {}, environment } = config;\n\n // Build per-provider config\n const providerConfig = (name: string): ProviderConfig => ({\n port,\n redirectUri: redirectUris[name],\n environment,\n });\n\n // Register all providers\n providers.set('youtube', new YouTubeProvider(providerConfig('youtube')));\n providers.set('tiktok', new TikTokProvider(providerConfig('tiktok')));\n providers.set('instagram', new InstagramProvider(providerConfig('instagram')));\n providers.set('whatsapp', new WhatsAppProvider(providerConfig('whatsapp')));\n providers.set('telegram', new TelegramProvider(providerConfig('telegram')));\n providers.set('linkedin', new LinkedInProvider(providerConfig('linkedin')));\n providers.set('facebook', new FacebookProvider(providerConfig('facebook')));\n providers.set('twitter', new TwitterProvider(providerConfig('twitter')));\n providers.set('reddit', new RedditProvider(providerConfig('reddit')));\n\n return {\n getProvider(name: string): PlatformProvider | null {\n return providers.get(name) ?? null;\n },\n\n getAllProviders(): ProviderMetadata[] {\n return Array.from(providers.values()).map(p => p.getMetadata());\n },\n\n hasProvider(name: string): boolean {\n return providers.has(name);\n },\n\n getProviderNames(): string[] {\n return Array.from(providers.keys());\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0CA,eAAsB,eAAe,SAAyB,EAAE,EAA6B;CAC3F,MAAM,4BAAY,IAAI,KAA+B;CAGrD,MAAM,CACJ,EAAE,mBACF,EAAE,kBACF,EAAE,qBACF,EAAE,oBACF,EAAE,oBACF,EAAE,oBACF,EAAE,oBACF,EAAE,mBACF,EAAE,oBACA,MAAM,QAAQ,IAAI;EACpB,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACR,CAAC;CAEF,MAAM,EAAE,MAAM,eAAe,EAAE,EAAE,gBAAgB;CAGjD,MAAM,kBAAkB,UAAkC;EACxD;EACA,aAAa,aAAa;EAC1B;EACD;AAGD,WAAU,IAAI,WAAW,IAAI,gBAAgB,eAAe,UAAU,CAAC,CAAC;AACxE,WAAU,IAAI,UAAU,IAAI,eAAe,eAAe,SAAS,CAAC,CAAC;AACrE,WAAU,IAAI,aAAa,IAAI,kBAAkB,eAAe,YAAY,CAAC,CAAC;AAC9E,WAAU,IAAI,YAAY,IAAI,iBAAiB,eAAe,WAAW,CAAC,CAAC;AAC3E,WAAU,IAAI,YAAY,IAAI,iBAAiB,eAAe,WAAW,CAAC,CAAC;AAC3E,WAAU,IAAI,YAAY,IAAI,iBAAiB,eAAe,WAAW,CAAC,CAAC;AAC3E,WAAU,IAAI,YAAY,IAAI,iBAAiB,eAAe,WAAW,CAAC,CAAC;AAC3E,WAAU,IAAI,WAAW,IAAI,gBAAgB,eAAe,UAAU,CAAC,CAAC;AACxE,WAAU,IAAI,UAAU,IAAI,eAAe,eAAe,SAAS,CAAC,CAAC;AAErE,QAAO;EACL,YAAY,MAAuC;AACjD,UAAO,UAAU,IAAI,KAAK,IAAI;;EAGhC,kBAAsC;AACpC,UAAO,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,aAAa,CAAC;;EAGjE,YAAY,MAAuB;AACjC,UAAO,UAAU,IAAI,KAAK;;EAG5B,mBAA6B;AAC3B,UAAO,MAAM,KAAK,UAAU,MAAM,CAAC;;EAEtC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-DQk6qfdC.mjs";
|
|
2
|
+
import { i as OAuthTokensSchema, r as NonEmptyString } from "./shared-Fvc6xQku.mjs";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
//#region src/schemas/instagram.ts
|
|
6
|
+
/**
|
|
7
|
+
* Instagram zod v4 schemas.
|
|
8
|
+
*/
|
|
9
|
+
var instagram_exports = /* @__PURE__ */ __exportAll({
|
|
10
|
+
InstagramCarouselItemSchema: () => InstagramCarouselItemSchema,
|
|
11
|
+
InstagramCarouselUploadSchema: () => InstagramCarouselUploadSchema,
|
|
12
|
+
InstagramCredentialDataSchema: () => InstagramCredentialDataSchema,
|
|
13
|
+
InstagramCredentialsSchema: () => InstagramCredentialsSchema,
|
|
14
|
+
InstagramListMediaSchema: () => InstagramListMediaSchema,
|
|
15
|
+
InstagramPhotoUploadSchema: () => InstagramPhotoUploadSchema,
|
|
16
|
+
InstagramVideoUploadSchema: () => InstagramVideoUploadSchema,
|
|
17
|
+
instagramCapabilities: () => instagramCapabilities,
|
|
18
|
+
instagramInfo: () => instagramInfo
|
|
19
|
+
});
|
|
20
|
+
const InstagramCredentialsSchema = z.object({
|
|
21
|
+
appId: NonEmptyString.describe("Meta app ID"),
|
|
22
|
+
appSecret: NonEmptyString.describe("Meta app secret"),
|
|
23
|
+
redirectUri: z.url().optional()
|
|
24
|
+
});
|
|
25
|
+
const InstagramCredentialDataSchema = InstagramCredentialsSchema.extend({ oauthTokenData: z.union([z.string(), OAuthTokensSchema]).optional() });
|
|
26
|
+
const InstagramVideoUploadSchema = z.object({
|
|
27
|
+
videoUrl: z.url().describe("Public URL of an MP4 video (≤100MB, ≤90s for Reels)"),
|
|
28
|
+
caption: z.string().max(2200).optional(),
|
|
29
|
+
thumbOffset: z.number().int().nonnegative().optional().describe("Thumbnail offset in milliseconds"),
|
|
30
|
+
shareToFeed: z.boolean().optional().default(true),
|
|
31
|
+
igUserId: z.string().optional()
|
|
32
|
+
});
|
|
33
|
+
const InstagramPhotoUploadSchema = z.object({
|
|
34
|
+
imageUrl: z.url().describe("Public URL of a JPEG image (≤8MB)"),
|
|
35
|
+
caption: z.string().max(2200).optional(),
|
|
36
|
+
igUserId: z.string().optional()
|
|
37
|
+
});
|
|
38
|
+
const InstagramCarouselItemSchema = z.object({
|
|
39
|
+
type: z.enum(["IMAGE", "VIDEO"]),
|
|
40
|
+
url: z.url()
|
|
41
|
+
});
|
|
42
|
+
const InstagramCarouselUploadSchema = z.object({
|
|
43
|
+
items: z.array(InstagramCarouselItemSchema).min(2).max(10),
|
|
44
|
+
caption: z.string().max(2200).optional(),
|
|
45
|
+
igUserId: z.string().optional()
|
|
46
|
+
});
|
|
47
|
+
const InstagramListMediaSchema = z.object({
|
|
48
|
+
limit: z.number().int().min(1).max(100).optional().default(25),
|
|
49
|
+
cursor: z.string().optional()
|
|
50
|
+
});
|
|
51
|
+
const instagramCapabilities = {
|
|
52
|
+
auth: "oauth2",
|
|
53
|
+
posting: true,
|
|
54
|
+
upload: true,
|
|
55
|
+
messaging: false,
|
|
56
|
+
scheduling: false,
|
|
57
|
+
deletion: false,
|
|
58
|
+
listing: true,
|
|
59
|
+
analytics: true,
|
|
60
|
+
environments: false,
|
|
61
|
+
pkce: false
|
|
62
|
+
};
|
|
63
|
+
const instagramInfo = {
|
|
64
|
+
name: "instagram",
|
|
65
|
+
displayName: "Instagram",
|
|
66
|
+
scopes: [
|
|
67
|
+
"business_management",
|
|
68
|
+
"instagram_basic",
|
|
69
|
+
"instagram_content_publish",
|
|
70
|
+
"pages_show_list",
|
|
71
|
+
"pages_read_engagement"
|
|
72
|
+
],
|
|
73
|
+
rateLimits: { per24h: 25 },
|
|
74
|
+
fileLimits: {
|
|
75
|
+
photo: { maxSizeBytes: 8 * 1024 * 1024 },
|
|
76
|
+
video: {
|
|
77
|
+
maxSizeBytes: 100 * 1024 * 1024,
|
|
78
|
+
maxDurationSec: 90
|
|
79
|
+
},
|
|
80
|
+
carousel: {
|
|
81
|
+
minItems: 2,
|
|
82
|
+
maxItems: 10
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
docsUrl: "https://developers.facebook.com/docs/instagram-api"
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
export { instagram_exports as i, instagramCapabilities as n, instagramInfo as r, InstagramCredentialsSchema as t };
|
|
90
|
+
//# sourceMappingURL=instagram-BGaeUFU2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instagram-BGaeUFU2.mjs","names":[],"sources":["../src/schemas/instagram.ts"],"sourcesContent":["/**\n * Instagram zod v4 schemas.\n */\n\nimport { z } from 'zod';\nimport type { ProviderCapabilities } from '../common/contracts.js';\nimport { NonEmptyString, OAuthTokensSchema } from './shared.js';\n\n// ─── Credentials ────────────────────────────────────────────────────────────\n\nexport const InstagramCredentialsSchema = z.object({\n appId: NonEmptyString.describe('Meta app ID'),\n appSecret: NonEmptyString.describe('Meta app secret'),\n redirectUri: z.url().optional(),\n});\nexport type InstagramCredentialsInput = z.infer<typeof InstagramCredentialsSchema>;\n\nexport const InstagramCredentialDataSchema = InstagramCredentialsSchema.extend({\n oauthTokenData: z.union([z.string(), OAuthTokensSchema]).optional(),\n});\n\n// ─── Upload params ──────────────────────────────────────────────────────────\n\nexport const InstagramVideoUploadSchema = z.object({\n videoUrl: z.url().describe('Public URL of an MP4 video (≤100MB, ≤90s for Reels)'),\n caption: z.string().max(2200).optional(),\n thumbOffset: z.number().int().nonnegative().optional().describe('Thumbnail offset in milliseconds'),\n shareToFeed: z.boolean().optional().default(true),\n igUserId: z.string().optional(),\n});\n\nexport const InstagramPhotoUploadSchema = z.object({\n imageUrl: z.url().describe('Public URL of a JPEG image (≤8MB)'),\n caption: z.string().max(2200).optional(),\n igUserId: z.string().optional(),\n});\n\nexport const InstagramCarouselItemSchema = z.object({\n type: z.enum(['IMAGE', 'VIDEO']),\n url: z.url(),\n});\n\nexport const InstagramCarouselUploadSchema = z.object({\n items: z.array(InstagramCarouselItemSchema).min(2).max(10),\n caption: z.string().max(2200).optional(),\n igUserId: z.string().optional(),\n});\n\n// ─── List options ───────────────────────────────────────────────────────────\n\nexport const InstagramListMediaSchema = z.object({\n limit: z.number().int().min(1).max(100).optional().default(25),\n cursor: z.string().optional(),\n});\n\n// ─── Capabilities ───────────────────────────────────────────────────────────\n\nexport const instagramCapabilities: ProviderCapabilities = {\n auth: 'oauth2',\n posting: true,\n upload: true,\n messaging: false,\n scheduling: false,\n deletion: false,\n listing: true,\n analytics: true,\n environments: false,\n pkce: false,\n};\n\nexport const instagramInfo = {\n name: 'instagram' as const,\n displayName: 'Instagram',\n scopes: [\n 'business_management',\n 'instagram_basic',\n 'instagram_content_publish',\n 'pages_show_list',\n 'pages_read_engagement',\n ],\n rateLimits: { per24h: 25 },\n fileLimits: {\n photo: { maxSizeBytes: 8 * 1024 * 1024 },\n video: { maxSizeBytes: 100 * 1024 * 1024, maxDurationSec: 90 },\n carousel: { minItems: 2, maxItems: 10 },\n },\n docsUrl: 'https://developers.facebook.com/docs/instagram-api',\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAUA,MAAa,6BAA6B,EAAE,OAAO;CACjD,OAAO,eAAe,SAAS,cAAc;CAC7C,WAAW,eAAe,SAAS,kBAAkB;CACrD,aAAa,EAAE,KAAK,CAAC,UAAU;CAChC,CAAC;AAGF,MAAa,gCAAgC,2BAA2B,OAAO,EAC7E,gBAAgB,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC,UAAU,EACpE,CAAC;AAIF,MAAa,6BAA6B,EAAE,OAAO;CACjD,UAAU,EAAE,KAAK,CAAC,SAAS,sDAAsD;CACjF,SAAS,EAAE,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU;CACxC,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,mCAAmC;CACnG,aAAa,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,KAAK;CACjD,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAEF,MAAa,6BAA6B,EAAE,OAAO;CACjD,UAAU,EAAE,KAAK,CAAC,SAAS,oCAAoC;CAC/D,SAAS,EAAE,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU;CACxC,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAEF,MAAa,8BAA8B,EAAE,OAAO;CAClD,MAAM,EAAE,KAAK,CAAC,SAAS,QAAQ,CAAC;CAChC,KAAK,EAAE,KAAK;CACb,CAAC;AAEF,MAAa,gCAAgC,EAAE,OAAO;CACpD,OAAO,EAAE,MAAM,4BAA4B,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;CAC1D,SAAS,EAAE,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU;CACxC,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAIF,MAAa,2BAA2B,EAAE,OAAO;CAC/C,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG;CAC9D,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC9B,CAAC;AAIF,MAAa,wBAA8C;CACzD,MAAM;CACN,SAAS;CACT,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,UAAU;CACV,SAAS;CACT,WAAW;CACX,cAAc;CACd,MAAM;CACP;AAED,MAAa,gBAAgB;CAC3B,MAAM;CACN,aAAa;CACb,QAAQ;EACN;EACA;EACA;EACA;EACA;EACD;CACD,YAAY,EAAE,QAAQ,IAAI;CAC1B,YAAY;EACV,OAAO,EAAE,cAAc,IAAI,OAAO,MAAM;EACxC,OAAO;GAAE,cAAc,MAAM,OAAO;GAAM,gBAAgB;GAAI;EAC9D,UAAU;GAAE,UAAU;GAAG,UAAU;GAAI;EACxC;CACD,SAAS;CACV"}
|