@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,112 @@
1
+ import { SocialError } from "../core/errors.js";
2
+ import { array, object, string } from "../transport/validation.js";
3
+ import { accountMatches } from "./common.js";
4
+ const reject = (message) => {
5
+ throw new SocialError({ code: "invalid_input", operation: "posts.lifecycle", message });
6
+ };
7
+ const unconfirmed = () => {
8
+ throw new SocialError({
9
+ code: "ambiguous_outcome",
10
+ operation: "posts.lifecycle",
11
+ message: "The provider did not confirm the mutation. Reconcile before retrying.",
12
+ retryDisposition: { kind: "reconcile-first" },
13
+ });
14
+ };
15
+ /** Mutations affect whole provider records. Reject records shared by destinations. */
16
+ export function managedLifecycle(provider, request, now) {
17
+ const path = (id) => `${provider === "zernio" ? "/v1/posts" : "/v1/social-posts"}/${encodeURIComponent(id)}`;
18
+ async function owned(ref, id, context) {
19
+ accountMatches(ref, context);
20
+ if (!id)
21
+ reject("A backend record identifier is required.");
22
+ const response = object(await request(path(id), context));
23
+ const record = object(response["post"] ?? response);
24
+ if (record[provider === "zernio" ? "_id" : "id"] !== id)
25
+ reject("Provider returned a different backend record.");
26
+ const entries = array(record[provider === "zernio" ? "platforms" : "social_accounts"]).map(object);
27
+ if (entries.length !== 1)
28
+ reject("This operation requires a backend record with exactly one destination.");
29
+ const entry = entries[0];
30
+ const rawId = provider === "zernio" ? entry["accountId"] : entry["id"];
31
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
32
+ const accountId = typeof rawId === "string" ? rawId : object(rawId)["_id"];
33
+ const platform = entry["platform"] === "twitter" ? "x" : entry["platform"];
34
+ if (accountId !== ref.accountId || platform !== ref.platform)
35
+ throw new SocialError({
36
+ code: "unauthorized",
37
+ operation: "posts.lifecycle",
38
+ message: "Backend record does not belong to the authorized account and platform.",
39
+ });
40
+ return record;
41
+ }
42
+ async function deleteRecord(id, context) {
43
+ const response = object(await request(path(id), context, undefined, {}, "DELETE"));
44
+ if (provider === "post-for-me"
45
+ ? response["success"] !== true
46
+ : response["message"] !== "Post deleted successfully")
47
+ unconfirmed();
48
+ }
49
+ return {
50
+ async cancelScheduled(ref, context) {
51
+ const record = await owned(ref, ref.jobId, context);
52
+ const scheduledAt = record[provider === "zernio" ? "scheduledFor" : "scheduled_at"];
53
+ if (record["status"] !== "scheduled" ||
54
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
55
+ typeof scheduledAt !== "string" ||
56
+ !Number.isFinite(Date.parse(scheduledAt)) ||
57
+ Date.parse(scheduledAt) <= Date.parse(now()))
58
+ reject("Only a future scheduled record can be cancelled. Reconcile a due or dispatched post.");
59
+ if (provider === "zernio") {
60
+ await deleteRecord(ref.jobId, context);
61
+ return { state: "cancelled", backendRecord: "deleted" };
62
+ }
63
+ // A missing/null scheduled_at means publish immediately. Keep the timestamp.
64
+ // oxlint-disable-next-line anti-slop/no-known-value-widening -- provider payload is validated at this adapter boundary.
65
+ const body = {
66
+ caption: string(record["caption"]),
67
+ social_accounts: [ref.accountId],
68
+ scheduled_at: string(scheduledAt),
69
+ isDraft: true,
70
+ };
71
+ for (const key of [
72
+ "media",
73
+ "platform_configurations",
74
+ "account_configurations",
75
+ "external_id",
76
+ ]) {
77
+ if (record[key] !== undefined && record[key] !== null)
78
+ // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- provider payload is validated at this adapter boundary.
79
+ body[key] = record[key];
80
+ }
81
+ const result = object(await request(path(ref.jobId), context, body, {}, "PUT"));
82
+ if (result["id"] !== ref.jobId || result["status"] !== "draft")
83
+ unconfirmed();
84
+ return { state: "cancelled", backendRecord: "retained" };
85
+ },
86
+ async deleteBackendRecord(ref, context) {
87
+ const record = await owned(ref, ref.recordId, context);
88
+ if (record["status"] !== "draft")
89
+ reject("Delete only a draft backend record. Cancel a future schedule explicitly; never infer native deletion.");
90
+ await deleteRecord(ref.recordId, context);
91
+ },
92
+ // oxlint-disable-next-line anti-slop/no-conditional-empty-object-spread -- provider payload is validated at this adapter boundary.
93
+ ...(provider === "zernio"
94
+ ? {
95
+ async removeFromPlatform(ref, context) {
96
+ if (!["x", "threads", "bluesky", "youtube", "linkedin", "facebook"].includes(ref.platform))
97
+ reject("Zernio does not support native removal for this platform.");
98
+ const id = string(ref.native?.["backendRecordId"]);
99
+ const record = await owned(ref, id, context);
100
+ const entry = object(array(record["platforms"])[0]);
101
+ if (entry["status"] !== "published" || entry["platformPostId"] !== ref.postId)
102
+ reject("The backend record does not identify this published native post.");
103
+ const result = object(await request(`${path(id)}/unpublish`, context, {
104
+ platform: ref.platform === "x" ? "twitter" : ref.platform,
105
+ }));
106
+ if (result["success"] !== true)
107
+ unconfirmed();
108
+ },
109
+ }
110
+ : {}),
111
+ };
112
+ }
@@ -0,0 +1,23 @@
1
+ import type { AdapterOperationContext, ConnectedAccountRef, JsonObject, MediaAttachment, MediaRef } from "../core/types.js";
2
+ import { type ManagedOptions } from "./common.js";
3
+ /** Keep this record server-side. A provider storage URL may grant access to the asset. */
4
+ export interface ManagedMediaRecord {
5
+ readonly ref: MediaRef;
6
+ readonly publicUrl: string;
7
+ readonly expiresAt?: string;
8
+ readonly kind: "image" | "video";
9
+ readonly mimeType: string;
10
+ }
11
+ export interface ManagedMediaStore {
12
+ put(record: ManagedMediaRecord): Promise<void>;
13
+ get(mediaId: string): Promise<ManagedMediaRecord | undefined>;
14
+ }
15
+ export declare class MemoryManagedMediaStore implements ManagedMediaStore {
16
+ private readonly records;
17
+ put(record: ManagedMediaRecord): Promise<void>;
18
+ get(mediaId: string): Promise<ManagedMediaRecord | undefined>;
19
+ }
20
+ export declare function managedMedia(provider: "zernio" | "post-for-me", options: ManagedOptions, presign: (body: JsonObject, context: AdapterOperationContext) => Promise<unknown>): {
21
+ resolve: (item: MediaAttachment, account: ConnectedAccountRef, context: AdapterOperationContext) => Promise<string>;
22
+ upload(item: MediaAttachment, account: ConnectedAccountRef, context: AdapterOperationContext): Promise<MediaRef>;
23
+ };
@@ -0,0 +1,100 @@
1
+ import { SocialError } from "../core/errors.js";
2
+ import { accountMatches, uploadManagedMedia } from "./common.js";
3
+ export class MemoryManagedMediaStore {
4
+ records = new Map();
5
+ async put(record) {
6
+ this.records.set(record.ref.mediaId, structuredClone(record));
7
+ }
8
+ async get(mediaId) {
9
+ const record = this.records.get(mediaId);
10
+ return record ? structuredClone(record) : undefined;
11
+ }
12
+ }
13
+ export function managedMedia(provider, options,
14
+ // oxlint-disable-next-line anti-slop/no-unknown-returns -- provider payload is validated at this adapter boundary.
15
+ presign) {
16
+ const store = options.mediaStore ?? new MemoryManagedMediaStore();
17
+ async function resolve(item, account, context) {
18
+ accountMatches(account, context);
19
+ if (item.source.kind !== "media-ref")
20
+ return uploadManagedMedia(item, (body) => presign(body, context), {
21
+ options,
22
+ context,
23
+ provider,
24
+ });
25
+ const ref = item.source.ref;
26
+ if (ref.backend !== account.backend ||
27
+ ref.accountId !== account.accountId ||
28
+ ref.platform !== account.platform)
29
+ throw new SocialError({
30
+ code: "unauthorized",
31
+ operation: "media.resolve",
32
+ message: "Media reference belongs to another account or backend.",
33
+ });
34
+ const record = await store.get(ref.mediaId);
35
+ if (!record ||
36
+ record.ref.backend !== ref.backend ||
37
+ record.ref.accountId !== ref.accountId ||
38
+ record.ref.platform !== ref.platform)
39
+ throw new SocialError({
40
+ code: "media_error",
41
+ operation: "media.resolve",
42
+ message: "Media reference is unknown to this server-side store.",
43
+ });
44
+ if (record.expiresAt &&
45
+ Date.parse(record.expiresAt) <= (options.clock?.() ?? new Date()).getTime())
46
+ throw new SocialError({
47
+ code: "media_error",
48
+ operation: "media.resolve",
49
+ message: "Stored media has expired. Upload a new asset explicitly.",
50
+ });
51
+ if (record.kind !== item.kind ||
52
+ (item.mimeType !== undefined && item.mimeType !== record.mimeType))
53
+ throw new SocialError({
54
+ code: "media_error",
55
+ operation: "media.resolve",
56
+ message: "Media kind or MIME type differs from the stored asset.",
57
+ });
58
+ return record.publicUrl;
59
+ }
60
+ return {
61
+ resolve,
62
+ async upload(item, account, context) {
63
+ accountMatches(account, context);
64
+ if (item.source.kind === "media-ref") {
65
+ await resolve(item, account, context);
66
+ return item.source.ref;
67
+ }
68
+ if (!item.mimeType)
69
+ throw new SocialError({
70
+ code: "invalid_input",
71
+ operation: "media.upload",
72
+ message: "Provide the asset MIME type.",
73
+ });
74
+ const publicUrl = await resolve(item, account, context);
75
+ const ref = {
76
+ kind: "media",
77
+ version: 1,
78
+ backend: account.backend,
79
+ platform: account.platform,
80
+ accountId: account.accountId,
81
+ mediaId: crypto.randomUUID(),
82
+ };
83
+ const uploaded = item.source.kind !== "https-url";
84
+ const record = {
85
+ ref,
86
+ publicUrl,
87
+ kind: item.kind,
88
+ mimeType: item.mimeType,
89
+ };
90
+ if (provider === "zernio" && uploaded) {
91
+ const expiresAt = new Date((options.clock?.() ?? new Date()).getTime() + 7 * 86400_000).toISOString();
92
+ await store.put({ ...record, expiresAt });
93
+ }
94
+ else {
95
+ await store.put(record);
96
+ }
97
+ return ref;
98
+ },
99
+ };
100
+ }
@@ -0,0 +1,9 @@
1
+ import type { ConnectedAccountRef, DeliveryOutcome } from "../core/types.js";
2
+ export interface OutcomeContext {
3
+ account: ConnectedAccountRef;
4
+ targetIndex: number;
5
+ observedAt: string;
6
+ }
7
+ /** Never infer destination success from the aggregate HTTP/parent status. */
8
+ export declare function zernioOutcome(value: unknown, context: OutcomeContext): DeliveryOutcome;
9
+ export declare function postForMeOutcome(parentValue: unknown, resultsValue: unknown | undefined, context: OutcomeContext): DeliveryOutcome;
@@ -0,0 +1,195 @@
1
+ import { array, object, optionalString, string } from "../transport/validation.js";
2
+ function delivery(context, deliveryId) {
3
+ return {
4
+ kind: "delivery",
5
+ version: 1,
6
+ backend: context.account.backend,
7
+ platform: context.account.platform,
8
+ accountId: context.account.accountId,
9
+ deliveryId,
10
+ };
11
+ }
12
+ /** Never infer destination success from the aggregate HTTP/parent status. */
13
+ // oxlint-disable-next-line anti-slop/no-unknown-parameters -- provider payload is validated at this adapter boundary.
14
+ export function zernioOutcome(value, context) {
15
+ const response = object(value);
16
+ const post = object(response["post"] ?? response["existingPost"] ?? response);
17
+ const postId = string(post["_id"]);
18
+ const platform = context.account.platform === "x" ? "twitter" : context.account.platform;
19
+ const entries = array(post["platforms"]).map(object);
20
+ const matches = entries.filter((entry) => {
21
+ const accountId =
22
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
23
+ typeof entry["accountId"] === "string"
24
+ ? entry["accountId"]
25
+ : // oxlint-disable-next-line anti-slop/no-runtime-typeof -- provider payload is validated at this adapter boundary.
26
+ entry["accountId"] && typeof entry["accountId"] === "object"
27
+ ? optionalString(object(entry["accountId"])["_id"])
28
+ : undefined;
29
+ return entry["platform"] === platform && accountId === context.account.accountId;
30
+ });
31
+ const base = { ...context, delivery: delivery(context, postId) };
32
+ if (matches.length !== 1)
33
+ return {
34
+ ...base,
35
+ state: "unknown",
36
+ reason: "unmapped-state",
37
+ diagnostic: "Response has no unique matching account outcome.",
38
+ };
39
+ const entry = matches[0];
40
+ if (!entry)
41
+ throw new Error("Missing matched outcome");
42
+ const status = optionalString(entry["status"]) ?? "unknown";
43
+ const stateBase = { ...base, backendState: status };
44
+ switch (status) {
45
+ case "published": {
46
+ const nativeId = optionalString(entry["platformPostId"]);
47
+ if (!nativeId)
48
+ return {
49
+ ...stateBase,
50
+ state: "unknown",
51
+ reason: "unmapped-state",
52
+ diagnostic: "Provider reports publication without a native identifier; reconcile to resolve the native post.",
53
+ };
54
+ const url = optionalString(entry["platformPostUrl"]);
55
+ const published = {
56
+ ...stateBase,
57
+ state: "published",
58
+ post: {
59
+ kind: "platform-post",
60
+ version: 1,
61
+ backend: context.account.backend,
62
+ platform: context.account.platform,
63
+ accountId: context.account.accountId,
64
+ postId: nativeId,
65
+ native: { backendRecordId: postId },
66
+ },
67
+ };
68
+ return url ? { ...published, url } : published;
69
+ }
70
+ case "failed":
71
+ return {
72
+ ...stateBase,
73
+ state: "failed",
74
+ code: optionalString(entry["errorCategory"]) ?? "upstream_failure",
75
+ message: "Zernio reports that this destination failed. Inspect account permissions and sanitized provider diagnostics.",
76
+ retryDisposition: entry["errorCategory"] === "auth_expired"
77
+ ? { kind: "after-reconnect" }
78
+ : { kind: "never" },
79
+ };
80
+ case "processing":
81
+ case "uploading":
82
+ return { ...stateBase, state: "processing" };
83
+ case "pending":
84
+ return post["status"] === "scheduled"
85
+ ? {
86
+ ...stateBase,
87
+ state: "scheduled",
88
+ job: {
89
+ kind: "scheduled-job",
90
+ version: 1,
91
+ backend: context.account.backend,
92
+ platform: context.account.platform,
93
+ accountId: context.account.accountId,
94
+ jobId: postId,
95
+ },
96
+ }
97
+ : { ...stateBase, state: "accepted" };
98
+ default:
99
+ return {
100
+ ...stateBase,
101
+ state: "unknown",
102
+ reason: "unmapped-state",
103
+ diagnostic: "Unmapped destination status; no success or cancellation inferred.",
104
+ };
105
+ }
106
+ }
107
+ export function postForMeOutcome(
108
+ // oxlint-disable-next-line anti-slop/no-unknown-parameters -- provider payload is validated at this adapter boundary.
109
+ parentValue,
110
+ // oxlint-disable-next-line anti-slop/no-unknown-parameters -- provider payload is validated at this adapter boundary.
111
+ resultsValue, context) {
112
+ const parent = object(parentValue);
113
+ const postId = string(parent["id"]);
114
+ const backendState = optionalString(parent["status"]) ?? "unknown";
115
+ const base = { ...context, delivery: delivery(context, postId), backendState };
116
+ if (resultsValue !== undefined) {
117
+ const results = array(object(resultsValue)["data"]).map(object);
118
+ const matches = results.filter((result) => result["post_id"] === postId && result["social_account_id"] === context.account.accountId);
119
+ if (matches.length > 1)
120
+ return {
121
+ ...base,
122
+ state: "unknown",
123
+ reason: "unmapped-state",
124
+ diagnostic: "More than one result exists for the target; reconcile the provider records.",
125
+ };
126
+ const result = matches[0];
127
+ if (result) {
128
+ if (result["success"] === false)
129
+ return {
130
+ ...base,
131
+ state: "failed",
132
+ code: "upstream_failure",
133
+ message: "Post for Me reports that this account's attempt failed.",
134
+ retryDisposition: { kind: "never" },
135
+ };
136
+ if (result["success"] === true) {
137
+ const data = object(result["platform_data"]);
138
+ const postId = optionalString(data["id"]);
139
+ if (postId) {
140
+ const url = optionalString(data["url"]);
141
+ const published = {
142
+ ...base,
143
+ state: "published",
144
+ post: {
145
+ kind: "platform-post",
146
+ version: 1,
147
+ backend: context.account.backend,
148
+ platform: context.account.platform,
149
+ accountId: context.account.accountId,
150
+ postId,
151
+ },
152
+ };
153
+ return url ? { ...published, url } : published;
154
+ }
155
+ }
156
+ return {
157
+ ...base,
158
+ state: "unknown",
159
+ reason: "unmapped-state",
160
+ diagnostic: "Destination result lacks a confirmed native post identifier.",
161
+ };
162
+ }
163
+ }
164
+ switch (backendState) {
165
+ case "scheduled":
166
+ return {
167
+ ...base,
168
+ state: "scheduled",
169
+ job: {
170
+ kind: "scheduled-job",
171
+ version: 1,
172
+ backend: context.account.backend,
173
+ platform: context.account.platform,
174
+ accountId: context.account.accountId,
175
+ jobId: postId,
176
+ },
177
+ };
178
+ case "processing":
179
+ return { ...base, state: "processing" };
180
+ case "processed":
181
+ return {
182
+ ...base,
183
+ state: "unknown",
184
+ reason: "unmapped-state",
185
+ diagnostic: "The parent is processed, but this account has no confirmed result.",
186
+ };
187
+ default:
188
+ return {
189
+ ...base,
190
+ state: "unknown",
191
+ reason: "unmapped-state",
192
+ diagnostic: "Unmapped parent status; no destination success inferred.",
193
+ };
194
+ }
195
+ }
@@ -0,0 +1,69 @@
1
+ export { MemoryManagedMediaStore, type ManagedMediaStore, type ManagedMediaRecord, } from "./media.js";
2
+ import type { AccountRecord, AdapterOperationContext, ConnectedAccountRef, JsonObject, MetricValue, PlatformPostRef } from "../core/types.js";
3
+ import { managedPreparation, type ManagedOptions } from "./common.js";
4
+ export interface PostForMeConnectionOptions {
5
+ platform: string;
6
+ externalId: string;
7
+ permissions: readonly ("posts" | "feeds")[];
8
+ redirectUrl?: string;
9
+ }
10
+ export declare function postForMe(options: ManagedOptions): {
11
+ id: string;
12
+ capabilities: import("../index.js").CapabilityManifest;
13
+ media: {
14
+ upload: (item: import("../index.js").MediaAttachment, account: ConnectedAccountRef, context: AdapterOperationContext) => Promise<import("../index.js").MediaRef>;
15
+ };
16
+ accounts: {
17
+ list(input: {
18
+ cursor?: string;
19
+ limit?: number;
20
+ }, context: AdapterOperationContext): Promise<{
21
+ nextCursor?: string;
22
+ items: AccountRecord[];
23
+ }>;
24
+ get(ref: ConnectedAccountRef, context: AdapterOperationContext): Promise<AccountRecord>;
25
+ };
26
+ posts: {
27
+ list(account: ConnectedAccountRef, input: {
28
+ readonly cursor?: string;
29
+ readonly limit?: number;
30
+ }, context: AdapterOperationContext): Promise<{
31
+ nextCursor?: string;
32
+ items: JsonObject[];
33
+ }>;
34
+ prepareTarget(target: Parameters<typeof managedPreparation>[0]): import("../index.js").PreparationIssue[];
35
+ publishTarget(target: Parameters<typeof managedPreparation>[0], context: AdapterOperationContext): Promise<import("../index.js").DeliveryOutcome>;
36
+ getDelivery(ref: {
37
+ deliveryId: string;
38
+ accountId: string;
39
+ platform: string;
40
+ backend: string;
41
+ }, context: AdapterOperationContext): Promise<import("../index.js").DeliveryOutcome>;
42
+ get(ref: PlatformPostRef, context: AdapterOperationContext): Promise<JsonObject>;
43
+ removeFromPlatform?: (ref: PlatformPostRef, context: AdapterOperationContext) => Promise<void>;
44
+ cancelScheduled(ref: import("../index.js").ScheduledJobRef, context: AdapterOperationContext): Promise<import("../index.js").ScheduleCancellation>;
45
+ deleteBackendRecord(ref: import("../index.js").BackendPostRef, context: AdapterOperationContext): Promise<void>;
46
+ };
47
+ analytics: {
48
+ getPostMetrics(ref: PlatformPostRef, context: AdapterOperationContext): Promise<readonly MetricValue[]>;
49
+ };
50
+ webhooks: {
51
+ verify(input: {
52
+ headers: Headers;
53
+ body: Uint8Array;
54
+ }): Promise<{
55
+ valid: true;
56
+ method: "shared-secret";
57
+ }>;
58
+ decode(input: {
59
+ headers: Headers;
60
+ body: Uint8Array;
61
+ }, context: AdapterOperationContext): Promise<JsonObject>;
62
+ };
63
+ native: {
64
+ createConnection(input: PostForMeConnectionOptions, context: AdapterOperationContext): Promise<{
65
+ url: string;
66
+ platform: string;
67
+ }>;
68
+ };
69
+ };