@opencoredev/social-sdk 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +6 -0
  2. package/dist/cli.d.ts +13 -0
  3. package/dist/cli.js +234 -0
  4. package/dist/cloud/common.d.ts +25 -0
  5. package/dist/cloud/common.js +334 -0
  6. package/dist/cloud/lifecycle.d.ts +10 -0
  7. package/dist/cloud/lifecycle.js +112 -0
  8. package/dist/cloud/media.d.ts +23 -0
  9. package/dist/cloud/media.js +100 -0
  10. package/dist/cloud/outcomes.d.ts +9 -0
  11. package/dist/cloud/outcomes.js +195 -0
  12. package/dist/cloud/post-for-me.d.ts +69 -0
  13. package/dist/cloud/post-for-me.js +396 -0
  14. package/dist/cloud/zernio.d.ts +111 -0
  15. package/dist/cloud/zernio.js +632 -0
  16. package/dist/core/adapter.d.ts +158 -0
  17. package/dist/core/adapter.js +3 -0
  18. package/dist/core/client.d.ts +141 -0
  19. package/dist/core/client.js +1285 -0
  20. package/dist/core/concurrency.d.ts +9 -0
  21. package/dist/core/concurrency.js +79 -0
  22. package/dist/core/errors.d.ts +44 -0
  23. package/dist/core/errors.js +50 -0
  24. package/dist/core/idempotency.d.ts +33 -0
  25. package/dist/core/idempotency.js +58 -0
  26. package/dist/core/index.d.ts +6 -0
  27. package/dist/core/index.js +6 -0
  28. package/dist/core/pagination.d.ts +11 -0
  29. package/dist/core/pagination.js +81 -0
  30. package/dist/core/types.d.ts +396 -0
  31. package/dist/core/types.js +16 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.js +1 -0
  34. package/dist/platforms/bluesky.d.ts +261 -0
  35. package/dist/platforms/bluesky.js +1776 -0
  36. package/dist/platforms/instagram.d.ts +129 -0
  37. package/dist/platforms/instagram.js +1031 -0
  38. package/dist/platforms/linkedin.d.ts +108 -0
  39. package/dist/platforms/linkedin.js +890 -0
  40. package/dist/platforms/threads.d.ts +134 -0
  41. package/dist/platforms/threads.js +945 -0
  42. package/dist/platforms/tiktok.d.ts +31 -0
  43. package/dist/platforms/tiktok.js +593 -0
  44. package/dist/platforms/x-engagement.d.ts +16 -0
  45. package/dist/platforms/x-engagement.js +50 -0
  46. package/dist/platforms/x-text.d.ts +2 -0
  47. package/dist/platforms/x-text.js +123 -0
  48. package/dist/platforms/x-tlds.d.ts +1 -0
  49. package/dist/platforms/x-tlds.js +2 -0
  50. package/dist/platforms/x.d.ts +299 -0
  51. package/dist/platforms/x.js +1287 -0
  52. package/dist/platforms/youtube-upload.d.ts +32 -0
  53. package/dist/platforms/youtube-upload.js +296 -0
  54. package/dist/platforms/youtube.d.ts +108 -0
  55. package/dist/platforms/youtube.js +1100 -0
  56. package/dist/server/connections.d.ts +123 -0
  57. package/dist/server/connections.js +335 -0
  58. package/dist/server/credentials.d.ts +51 -0
  59. package/dist/server/credentials.js +108 -0
  60. package/dist/server/index.d.ts +4 -0
  61. package/dist/server/index.js +4 -0
  62. package/dist/server/oauth.d.ts +52 -0
  63. package/dist/server/oauth.js +553 -0
  64. package/dist/server/webhooks.d.ts +57 -0
  65. package/dist/server/webhooks.js +204 -0
  66. package/dist/testing/index.d.ts +46 -0
  67. package/dist/testing/index.js +564 -0
  68. package/dist/testing.d.ts +1 -0
  69. package/dist/testing.js +1 -0
  70. package/dist/transport/binary.d.ts +2 -0
  71. package/dist/transport/binary.js +29 -0
  72. package/dist/transport/budget.d.ts +3 -0
  73. package/dist/transport/budget.js +26 -0
  74. package/dist/transport/http.d.ts +44 -0
  75. package/dist/transport/http.js +259 -0
  76. package/dist/transport/json.d.ts +8 -0
  77. package/dist/transport/json.js +16 -0
  78. package/dist/transport/upload.d.ts +25 -0
  79. package/dist/transport/upload.js +153 -0
  80. package/dist/transport/validation.d.ts +5 -0
  81. package/dist/transport/validation.js +24 -0
  82. package/package.json +2 -7
@@ -0,0 +1,396 @@
1
+ /* oxlint-disable anti-slop/require-safety-comment-for-type-assertion -- validated external boundary or fixture contract. */
2
+ import { managedLifecycle } from "./lifecycle.js";
3
+ import { managedMedia } from "./media.js";
4
+ export { MemoryManagedMediaStore, } from "./media.js";
5
+ import { defineAdapter } from "../core/adapter.js";
6
+ import { SocialError } from "../core/errors.js";
7
+ import { array, object, optionalNumber, optionalString, string } from "../transport/validation.js";
8
+ import { verifyPostForMeWebhook, decodeWebhook } from "../server/webhooks.js";
9
+ import { accountMatches, capabilityManifest, managedHttp, managedPreparation, managedOptionIssues, optionsObject, platform, publicFields, } from "./common.js";
10
+ import { postForMeOutcome } from "./outcomes.js";
11
+ export function postForMe(options) {
12
+ const request = managedHttp("https://api.postforme.dev", options);
13
+ const mediaPipeline = managedMedia("post-for-me", options, (body, context) => request("/v1/media/create-upload-url", context, body));
14
+ const now = () => (options.clock?.() ?? new Date()).toISOString();
15
+ // oxlint-disable-next-line anti-slop/no-unknown-parameters -- provider payload is validated at this adapter boundary.
16
+ const account = (value, backend) => {
17
+ const row = object(value);
18
+ const handle = optionalString(row["username"]);
19
+ return {
20
+ ref: {
21
+ kind: "connected-account",
22
+ version: 1,
23
+ backend,
24
+ platform: platform(row["platform"]),
25
+ accountId: string(row["id"]),
26
+ },
27
+ displayName: handle ?? string(row["user_id"]),
28
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
29
+ ...(handle ? { handle } : {}),
30
+ status: row["status"] === "connected"
31
+ ? "connected"
32
+ : row["status"] === "disconnected"
33
+ ? "reconnect-required"
34
+ : "unknown",
35
+ };
36
+ };
37
+ // oxlint-disable-next-line anti-slop/no-unknown-parameters -- validated by account at this boundary.
38
+ const supportedAccount = (value, backend) => {
39
+ try {
40
+ return account(value, backend);
41
+ }
42
+ catch (error) {
43
+ if (error instanceof SocialError && error.code === "unsupported_capability")
44
+ return undefined;
45
+ throw error;
46
+ }
47
+ };
48
+ const feed = async (ref, context, metrics) => {
49
+ accountMatches(ref, context);
50
+ const result = object(await request(`/v1/social-account-feeds/${encodeURIComponent(ref.accountId)}`, context, undefined,
51
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
52
+ { platform_post_id: ref.postId, limit: "1", ...(metrics ? { expand: "metrics" } : {}) }));
53
+ const row = array(result["data"])
54
+ .map(object)
55
+ .find((item) => item["platform_post_id"] === ref.postId && item["social_account_id"] === ref.accountId);
56
+ if (!row)
57
+ throw new SocialError({
58
+ code: "upstream_failure",
59
+ operation: "posts.read",
60
+ message: "The native post is absent or inaccessible in this account feed.",
61
+ });
62
+ return row;
63
+ };
64
+ const adapter = defineAdapter({
65
+ id: "post-for-me",
66
+ capabilities: capabilityManifest("post-for-me", "v1 / OpenAPI 1.0", [
67
+ "accounts.read",
68
+ "posts.publish",
69
+ "posts.read",
70
+ "posts.list",
71
+ "posts.status",
72
+ "posts.cancelScheduled",
73
+ "posts.deleteBackendRecord",
74
+ "analytics.read",
75
+ "media.upload",
76
+ "webhooks.verify",
77
+ ]),
78
+ media: { upload: mediaPipeline.upload },
79
+ accounts: {
80
+ async list(input, context) {
81
+ const offset = input.cursor === undefined ? 0 : Number(input.cursor);
82
+ const limit = input.limit ?? 25;
83
+ if (!Number.isSafeInteger(offset) ||
84
+ offset < 0 ||
85
+ !Number.isSafeInteger(limit) ||
86
+ limit < 1 ||
87
+ limit > 100)
88
+ throw new SocialError({
89
+ code: "invalid_input",
90
+ operation: "accounts.read",
91
+ message: "Use an opaque returned cursor and a page size from 1 to 100.",
92
+ });
93
+ const result = object(await request("/v1/social-accounts", context, undefined, {
94
+ offset: String(offset),
95
+ limit: String(limit),
96
+ }));
97
+ const rows = array(result["data"]);
98
+ const meta = object(result["meta"]);
99
+ const next = meta["next"] ? String(offset + limit) : undefined;
100
+ return {
101
+ items: rows.flatMap((value) => {
102
+ const parsed = supportedAccount(value, context.backendInstance);
103
+ return parsed ? [parsed] : [];
104
+ }),
105
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
106
+ ...(next ? { nextCursor: next } : {}),
107
+ };
108
+ },
109
+ async get(ref, context) {
110
+ accountMatches(ref, context);
111
+ const result = account(await request(`/v1/social-accounts/${encodeURIComponent(ref.accountId)}`, context), context.backendInstance);
112
+ if (result.ref.accountId !== ref.accountId || result.ref.platform !== ref.platform)
113
+ throw new SocialError({
114
+ code: "unauthorized",
115
+ operation: "accounts.read",
116
+ message: "Account identity does not match the requested reference.",
117
+ });
118
+ return result;
119
+ },
120
+ },
121
+ posts: {
122
+ ...managedLifecycle("post-for-me", request, now),
123
+ async list(account, input, context) {
124
+ accountMatches(account, context);
125
+ const limit = input.limit ?? 25;
126
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
127
+ throw new SocialError({
128
+ code: "invalid_input",
129
+ operation: "posts.read",
130
+ message: "Post for Me feed page size must be between 1 and 100.",
131
+ });
132
+ const result = object(await request(`/v1/social-account-feeds/${encodeURIComponent(account.accountId)}`, context, undefined, {
133
+ limit: String(limit),
134
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
135
+ ...(input.cursor === undefined ? {} : { cursor: input.cursor }),
136
+ }));
137
+ const rows = array(result["data"])
138
+ .map(object)
139
+ .filter((row) => row["social_account_id"] === account.accountId)
140
+ .map((row) => publicFields(row, [
141
+ "platform_post_id",
142
+ "social_account_id",
143
+ "platform_account_id",
144
+ "platform_url",
145
+ "caption",
146
+ "posted_at",
147
+ "media",
148
+ "created_at",
149
+ ]));
150
+ const meta = result["meta"] === undefined ? {} : object(result["meta"]);
151
+ const hasMore = meta["has_more"];
152
+ const cursor = optionalString(meta["cursor"]);
153
+ // `has_more: false` is authoritative. Older responses may omit it;
154
+ // in that case, a non-empty `next` marker plus cursor permits continuation.
155
+ const next = hasMore === false
156
+ ? undefined
157
+ : hasMore === true
158
+ ? cursor
159
+ : optionalString(meta["next"]) && cursor
160
+ ? cursor
161
+ : undefined;
162
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
163
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- provider payload is validated at this adapter boundary.
164
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- validated external boundary or fixture contract.
165
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- validated external boundary or fixture contract.
166
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- validated external boundary or fixture contract.
167
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- validated external boundary or fixture contract.
168
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- validated external boundary or fixture contract.
169
+ return { items: rows, ...(next === undefined ? {} : { nextCursor: next }) };
170
+ },
171
+ prepareTarget(target) {
172
+ const issues = [
173
+ ...managedPreparation(target),
174
+ ...managedOptionIssues(target, "post-for-me"),
175
+ ];
176
+ if (target.account.platform === "tiktok") {
177
+ const privacy = optionsObject(target)["privacy"];
178
+ if (privacy !== "SELF_ONLY" && privacy !== "PUBLIC_TO_EVERYONE")
179
+ issues.push({
180
+ code: "tiktok.privacy_unsupported",
181
+ message: "Post for Me documents private/public privacy only; this adapter cannot map the selected privacy safely.",
182
+ severity: "error",
183
+ targetIndex: target.targetIndex,
184
+ });
185
+ }
186
+ for (const media of target.content.media ?? [])
187
+ if (media.altText !== undefined)
188
+ issues.push({
189
+ code: "media.alt_text_unsupported",
190
+ message: "Post for Me's current media schema does not document alt text. Choose a backend with an explicit accessibility mapping.",
191
+ severity: "error",
192
+ targetIndex: target.targetIndex,
193
+ });
194
+ return issues;
195
+ },
196
+ async publishTarget(target, context) {
197
+ accountMatches(target.account, context);
198
+ const media = [];
199
+ for (const item of target.content.media ?? [])
200
+ media.push({ url: await mediaPipeline.resolve(item, target.account, context) });
201
+ const config = optionsObject(target);
202
+ const platformConfig = {};
203
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
204
+ if (target.account.platform === "instagram" && typeof config["shareToFeed"] === "boolean")
205
+ platformConfig["share_to_feed"] = config["shareToFeed"];
206
+ if (target.account.platform === "x" &&
207
+ config["replySettings"] !== undefined &&
208
+ config["replySettings"] !== "everyone")
209
+ platformConfig["reply_settings"] = string(config["replySettings"]);
210
+ if (target.account.platform === "youtube") {
211
+ platformConfig["title"] = string(config["title"]);
212
+ platformConfig["privacy_status"] = string(config["visibility"]);
213
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
214
+ if (typeof config["madeForKids"] === "boolean")
215
+ platformConfig["made_for_kids"] = config["madeForKids"];
216
+ }
217
+ if (target.account.platform === "tiktok") {
218
+ platformConfig["privacy_status"] =
219
+ config["privacy"] === "SELF_ONLY" ? "private" : "public";
220
+ platformConfig["auto_add_music"] = false;
221
+ platformConfig["allow_duet"] = !config["disableDuet"];
222
+ platformConfig["allow_stitch"] = !config["disableStitch"];
223
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- provider payload is validated at this adapter boundary.
224
+ platformConfig["disclose_your_brand"] = config["ownBrand"];
225
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- provider payload is validated at this adapter boundary.
226
+ platformConfig["is_ai_generated"] = config["aiGenerated"];
227
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- provider payload is validated at this adapter boundary.
228
+ platformConfig["is_draft"] = config["draft"];
229
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
230
+ if (typeof config["disableComments"] === "boolean")
231
+ platformConfig["allow_comment"] = !config["disableComments"];
232
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
233
+ if (typeof config["brandedContent"] === "boolean")
234
+ platformConfig["disclose_branded_content"] = config["brandedContent"];
235
+ }
236
+ const response = await request("/v1/social-posts", context, {
237
+ caption: target.content.text ?? "",
238
+ social_accounts: [target.account.accountId],
239
+ media,
240
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
241
+ ...(target.schedule ? { scheduled_at: target.schedule.at } : {}),
242
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
243
+ ...(context.targetIdempotencyKey ? { external_id: context.targetIdempotencyKey } : {}),
244
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
245
+ ...(Object.keys(platformConfig).length
246
+ ? { platform_configurations: { [target.account.platform]: platformConfig } }
247
+ : {}),
248
+ });
249
+ const parent = object(response);
250
+ let results;
251
+ if (parent["status"] === "processed") {
252
+ try {
253
+ results = await request("/v1/social-post-results", context, undefined, {
254
+ post_id: string(parent["id"]),
255
+ social_account_id: target.account.accountId,
256
+ limit: "2",
257
+ });
258
+ }
259
+ catch {
260
+ /* Preserve the accepted parent if immediate reconciliation is unavailable. */
261
+ }
262
+ }
263
+ return postForMeOutcome(parent, results, {
264
+ account: target.account,
265
+ targetIndex: target.targetIndex,
266
+ observedAt: now(),
267
+ });
268
+ },
269
+ async getDelivery(ref, context) {
270
+ const account = {
271
+ kind: "connected-account",
272
+ version: 1,
273
+ backend: ref.backend,
274
+ platform: ref.platform,
275
+ accountId: ref.accountId,
276
+ };
277
+ accountMatches(account, context);
278
+ const parent = await request(`/v1/social-posts/${encodeURIComponent(ref.deliveryId)}`, context);
279
+ const results = await request("/v1/social-post-results", context, undefined, {
280
+ post_id: ref.deliveryId,
281
+ social_account_id: ref.accountId,
282
+ limit: "2",
283
+ });
284
+ return postForMeOutcome(parent, results, { account, targetIndex: 0, observedAt: now() });
285
+ },
286
+ async get(ref, context) {
287
+ return publicFields(await feed(ref, context, false), [
288
+ "platform_post_id",
289
+ "social_account_id",
290
+ "platform_account_id",
291
+ "platform_url",
292
+ "caption",
293
+ "posted_at",
294
+ ]);
295
+ },
296
+ },
297
+ analytics: {
298
+ async getPostMetrics(ref, context) {
299
+ const row = await feed(ref, context, true);
300
+ if (row["metrics"] === undefined || row["metrics"] === null)
301
+ return [];
302
+ const metrics = object(row["metrics"]);
303
+ const values = ref.platform === "x" && metrics["public_metrics"] !== undefined
304
+ ? object(metrics["public_metrics"])
305
+ : metrics;
306
+ const result = [];
307
+ const fields = ref.platform === "x"
308
+ ? [
309
+ ["likes", "like_count"],
310
+ ["comments", "reply_count"],
311
+ ["reposts", "repost_count"],
312
+ ["impressions", "impression_count"],
313
+ ]
314
+ : ref.platform === "linkedin"
315
+ ? [
316
+ ["likes", "likeCount"],
317
+ ["comments", "commentCount"],
318
+ ["impressions", "impressionCount"],
319
+ ]
320
+ : ref.platform === "bluesky"
321
+ ? [
322
+ ["likes", "likeCount"],
323
+ ["comments", "replyCount"],
324
+ ["reposts", "repostCount"],
325
+ ]
326
+ : // Other platforms report provider-shaped counters; accept the common spellings.
327
+ [
328
+ ["likes", "likes"],
329
+ ["likes", "like_count"],
330
+ ["likes", "likeCount"],
331
+ ["comments", "comments"],
332
+ ["comments", "comment_count"],
333
+ ["comments", "commentCount"],
334
+ ["comments", "replies"],
335
+ ["shares", "shares"],
336
+ ["shares", "share_count"],
337
+ ["reposts", "reposts"],
338
+ ["reposts", "repost_count"],
339
+ ["views", "views"],
340
+ ["views", "view_count"],
341
+ ["views", "viewCount"],
342
+ ["impressions", "impressions"],
343
+ ["reach", "reach"],
344
+ ];
345
+ const seen = new Set();
346
+ for (const [name, key] of fields) {
347
+ if (seen.has(name))
348
+ continue;
349
+ const value = optionalNumber(values[key]);
350
+ if (value === undefined)
351
+ continue;
352
+ seen.add(name);
353
+ result.push({
354
+ name,
355
+ value,
356
+ unit: "count",
357
+ period: "lifetime",
358
+ fetchedAt: now(),
359
+ freshness: "unknown",
360
+ source: `post-for-me:${ref.platform}:feed`,
361
+ });
362
+ }
363
+ return result;
364
+ },
365
+ },
366
+ webhooks: {
367
+ async verify(input) {
368
+ await verifyPostForMeWebhook({ ...input, secret: options.webhookSecret ?? "" });
369
+ return { valid: true, method: "shared-secret" };
370
+ },
371
+ async decode(input, context) {
372
+ const event = await decodeWebhook({
373
+ provider: "post-for-me",
374
+ backend: context.backendInstance,
375
+ body: input.body,
376
+ receivedAt: now(),
377
+ });
378
+ return { ...event };
379
+ },
380
+ },
381
+ native: {
382
+ async createConnection(input, context) {
383
+ platform(input.platform);
384
+ const result = object(await request("/v1/social-accounts/auth-url", context, {
385
+ platform: input.platform,
386
+ external_id: input.externalId,
387
+ permissions: input.permissions,
388
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
389
+ ...(input.redirectUrl ? { redirect_url_override: input.redirectUrl } : {}),
390
+ }));
391
+ return { url: string(result["url"]), platform: string(result["platform"]) };
392
+ },
393
+ },
394
+ });
395
+ return adapter;
396
+ }
@@ -0,0 +1,111 @@
1
+ export { MemoryManagedMediaStore, type ManagedMediaStore, type ManagedMediaRecord, } from "./media.js";
2
+ import type { AccountRecord, AdapterOperationContext, CommentRef, ConnectedAccountRef, ConversationRef, JsonObject, MetricValue, PlatformPostRef, PreparedPublishTarget } from "../core/types.js";
3
+ import { type ManagedOptions } from "./common.js";
4
+ export interface ZernioConnectionOptions {
5
+ platform: string;
6
+ profileId: string;
7
+ redirectUrl: string;
8
+ }
9
+ export declare function zernio(options: ManagedOptions): {
10
+ id: string;
11
+ capabilities: {
12
+ capabilities: (import("../index.js").CapabilityDeclaration | {
13
+ platform: string;
14
+ operation: string;
15
+ availability: "available";
16
+ })[];
17
+ schemaVersion: 1;
18
+ backend: string;
19
+ apiRevision: string;
20
+ runtime: readonly string[];
21
+ };
22
+ media: {
23
+ upload: (item: import("../index.js").MediaAttachment, account: ConnectedAccountRef, context: AdapterOperationContext) => Promise<import("../index.js").MediaRef>;
24
+ };
25
+ accounts: {
26
+ list(input: {
27
+ cursor?: string;
28
+ limit?: number;
29
+ }, context: AdapterOperationContext): Promise<{
30
+ nextCursor?: string;
31
+ items: AccountRecord[];
32
+ }>;
33
+ get(ref: ConnectedAccountRef, context: AdapterOperationContext): Promise<AccountRecord>;
34
+ };
35
+ posts: {
36
+ list(account: ConnectedAccountRef, input: {
37
+ readonly cursor?: string;
38
+ readonly limit?: number;
39
+ }, context: AdapterOperationContext): Promise<{
40
+ nextCursor?: string;
41
+ items: JsonObject[];
42
+ }>;
43
+ prepareTarget(target: PreparedPublishTarget): import("../index.js").PreparationIssue[];
44
+ publishTarget(target: PreparedPublishTarget, context: AdapterOperationContext): Promise<import("../index.js").DeliveryOutcome>;
45
+ getDelivery(ref: {
46
+ backend: string;
47
+ platform: string;
48
+ accountId: string;
49
+ deliveryId: string;
50
+ }, context: AdapterOperationContext): Promise<import("../index.js").DeliveryOutcome>;
51
+ get(ref: PlatformPostRef, context: AdapterOperationContext): Promise<JsonObject>;
52
+ removeFromPlatform?: (ref: PlatformPostRef, context: AdapterOperationContext) => Promise<void>;
53
+ cancelScheduled(ref: import("../index.js").ScheduledJobRef, context: AdapterOperationContext): Promise<import("../index.js").ScheduleCancellation>;
54
+ deleteBackendRecord(ref: import("../index.js").BackendPostRef, context: AdapterOperationContext): Promise<void>;
55
+ };
56
+ analytics: {
57
+ getAccountMetrics(ref: ConnectedAccountRef, context: AdapterOperationContext): Promise<readonly MetricValue[]>;
58
+ getPostMetrics(ref: PlatformPostRef, context: AdapterOperationContext): Promise<readonly MetricValue[]>;
59
+ };
60
+ comments: {
61
+ list(ref: PlatformPostRef, input: {
62
+ readonly cursor?: string;
63
+ readonly limit?: number;
64
+ }, context: AdapterOperationContext): Promise<{
65
+ nextCursor?: string;
66
+ items: JsonObject[];
67
+ }>;
68
+ reply(ref: CommentRef, content: {
69
+ text: string;
70
+ }, context: AdapterOperationContext): Promise<CommentRef>;
71
+ };
72
+ messages: {
73
+ listConversations(ref: ConnectedAccountRef, input: {
74
+ readonly cursor?: string;
75
+ readonly limit?: number;
76
+ }, context: AdapterOperationContext): Promise<{
77
+ nextCursor?: string;
78
+ items: JsonObject[];
79
+ }>;
80
+ listMessages(ref: ConversationRef, input: {
81
+ readonly cursor?: string;
82
+ readonly limit?: number;
83
+ }, context: AdapterOperationContext): Promise<{
84
+ nextCursor?: string;
85
+ items: JsonObject[];
86
+ }>;
87
+ send(ref: ConversationRef, content: {
88
+ text: string;
89
+ }, context: AdapterOperationContext): Promise<JsonObject>;
90
+ };
91
+ webhooks: {
92
+ verify(input: {
93
+ headers: Headers;
94
+ body: Uint8Array;
95
+ }): Promise<{
96
+ valid: true;
97
+ method: "hmac";
98
+ }>;
99
+ decode(input: {
100
+ headers: Headers;
101
+ body: Uint8Array;
102
+ }, context: AdapterOperationContext): Promise<JsonObject>;
103
+ };
104
+ native: {
105
+ createConnection(input: ZernioConnectionOptions, context: AdapterOperationContext): Promise<{
106
+ providerState?: string;
107
+ url: string;
108
+ }>;
109
+ listProfiles(context: AdapterOperationContext): Promise<JsonObject[]>;
110
+ };
111
+ };