@bozonx/social-posting-tiktok 0.8.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ivan K
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # @bozonx/social-posting-tiktok
2
+
3
+ TikTok Content Posting API support for `@bozonx/social-posting`.
4
+
5
+ The adapter queries Creator Info before every publication (`cacheableForSecs: 0`), submits public
6
+ media URLs through Direct Post, and returns a secret-free handle while TikTok processes the post.
7
+ Call `checkStatus()` with that handle until the result is published or failed. Video, short video,
8
+ single-photo and photo carousel requests are supported.
9
+
10
+ The OAuth grant needs `video.publish`; an audited TikTok app is still required for live use.
11
+
12
+ ```ts
13
+ import { tiktok } from '@bozonx/social-posting-tiktok';
14
+ ```
@@ -0,0 +1,2 @@
1
+ import type { PlatformCapabilities } from '@bozonx/social-posting';
2
+ export declare const tiktokCapabilities: PlatformCapabilities;
@@ -0,0 +1,82 @@
1
+ import { PostType } from '@bozonx/social-posting';
2
+ const pull = {
3
+ acceptedSources: ['url'],
4
+ transport: 'pull',
5
+ requiresPubliclyFetchableUrl: true,
6
+ };
7
+ export const tiktokCapabilities = {
8
+ name: 'tiktok',
9
+ displayName: 'TikTok',
10
+ sources: [
11
+ {
12
+ url: 'https://developers.tiktok.com/doc/content-posting-api-reference-direct-post',
13
+ supports: ['direct post', 'creator info', 'status'],
14
+ verifiedAt: '2026-08-30',
15
+ },
16
+ ],
17
+ postTypes: {
18
+ [PostType.SHORT_VIDEO]: {
19
+ requiredFields: ['media'],
20
+ minMediaCount: 1,
21
+ maxMediaCount: 1,
22
+ mediaCounts: { video: { min: 1, max: 1 } },
23
+ },
24
+ [PostType.VIDEO]: {
25
+ requiredFields: ['media'],
26
+ minMediaCount: 1,
27
+ maxMediaCount: 1,
28
+ mediaCounts: { video: { min: 1, max: 1 } },
29
+ },
30
+ [PostType.IMAGE]: {
31
+ requiredFields: ['media'],
32
+ minMediaCount: 1,
33
+ maxMediaCount: 1,
34
+ mediaCounts: { image: { min: 1, max: 1 } },
35
+ },
36
+ [PostType.ALBUM]: {
37
+ requiredFields: ['media'],
38
+ minMediaCount: 2,
39
+ maxMediaCount: 35,
40
+ mediaCounts: { image: { min: 2, max: 35 } },
41
+ },
42
+ },
43
+ supportedBodyFormats: ['text'],
44
+ targetBodyFormat: 'text',
45
+ media: { image: { ...pull }, video: { ...pull } },
46
+ supportedVisibility: ['public', 'private'],
47
+ defaultVisibility: 'public',
48
+ supportsReply: false,
49
+ auth: {
50
+ kind: 'oauth2',
51
+ scopes: ['video.publish'],
52
+ docsUrl: 'https://developers.tiktok.com/doc/content-posting-api-get-started/',
53
+ },
54
+ extraFields: [
55
+ { name: 'privacyLevel', type: 'string' },
56
+ { name: 'disableComment', type: 'boolean' },
57
+ { name: 'disableDuet', type: 'boolean' },
58
+ { name: 'disableStitch', type: 'boolean' },
59
+ { name: 'brandContentToggle', type: 'boolean' },
60
+ { name: 'brandOrganicToggle', type: 'boolean' },
61
+ ],
62
+ allowUnknownExtraFields: false,
63
+ supportsNativeScheduling: false,
64
+ supportsDraft: false,
65
+ supportsDeletion: false,
66
+ supportsEdit: false,
67
+ asyncProcessing: { supported: true, typicalSecs: 30, maxWaitSecs: 3600, pollIntervalSecs: 5 },
68
+ ignoredFields: [
69
+ 'description',
70
+ 'tags',
71
+ 'language',
72
+ 'sensitive',
73
+ 'contentWarning',
74
+ 'commentsEnabled',
75
+ 'thumbnail',
76
+ 'inReplyTo',
77
+ 'repostOf',
78
+ 'poll',
79
+ 'scheduledAt',
80
+ ],
81
+ };
82
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `@bozonx/social-posting-tiktok` — Tiktok support for `@bozonx/social-posting`.
3
+ */
4
+ import type { PlatformModule } from '@bozonx/social-posting';
5
+ /** The descriptor a host registers to publish to Tiktok. */
6
+ export declare const tiktok: PlatformModule;
7
+ export { TiktokPlatform } from './tiktok.platform.js';
8
+ export type { TikTokExtra, TiktokPlatformDeps } from './tiktok.platform.js';
9
+ export { TiktokAuthValidator } from './tiktok-auth.validator.js';
10
+ export { tiktokCapabilities } from './capabilities.js';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ import { TiktokPlatform } from './tiktok.platform.js';
2
+ import { TiktokAuthValidator } from './tiktok-auth.validator.js';
3
+ import { tiktokCapabilities } from './capabilities.js';
4
+ /** The descriptor a host registers to publish to Tiktok. */
5
+ export const tiktok = {
6
+ name: 'tiktok',
7
+ // The API family this network speaks, when it shares one ('mastodon-api',
8
+ // 'atproto'). Metadata only — see deriveModule() for serving a family.
9
+ // dialect: undefined,
10
+ capabilities: tiktokCapabilities,
11
+ create: deps => new TiktokPlatform(deps),
12
+ authValidator: new TiktokAuthValidator(),
13
+ };
14
+ export { TiktokPlatform } from './tiktok.platform.js';
15
+ export { TiktokAuthValidator } from './tiktok-auth.validator.js';
16
+ export { tiktokCapabilities } from './capabilities.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,4DAA4D;AAC5D,MAAM,CAAC,MAAM,MAAM,GAAmB;IACpC,IAAI,EAAE,QAAQ;IACd,0EAA0E;IAC1E,uEAAuE;IACvE,sBAAsB;IACtB,YAAY,EAAE,kBAAkB;IAChC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC;IACxC,aAAa,EAAE,IAAI,mBAAmB,EAAE;CACzC,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { AuthValidation, IAuthValidator } from '@bozonx/social-posting/platform';
2
+ /**
3
+ * Validates the shape of Tiktok credentials.
4
+ *
5
+ * Return `code: ErrorCode.AUTH_REFRESH_REQUIRED` for credentials that are
6
+ * well-formed but spent, so the host re-authorizes instead of retrying forever.
7
+ */
8
+ export declare class TiktokAuthValidator implements IAuthValidator {
9
+ readonly providerName = "tiktok";
10
+ validate(auth: Record<string, unknown>): AuthValidation;
11
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Validates the shape of Tiktok credentials.
3
+ *
4
+ * Return `code: ErrorCode.AUTH_REFRESH_REQUIRED` for credentials that are
5
+ * well-formed but spent, so the host re-authorizes instead of retrying forever.
6
+ */
7
+ export class TiktokAuthValidator {
8
+ providerName = 'tiktok';
9
+ validate(auth) {
10
+ const errors = [];
11
+ if (typeof auth.accessToken !== 'string' || auth.accessToken.length === 0) {
12
+ errors.push("Field 'accessToken' is required for Tiktok auth");
13
+ }
14
+ return { errors };
15
+ }
16
+ }
17
+ //# sourceMappingURL=tiktok-auth.validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiktok-auth.validator.js","sourceRoot":"","sources":["../src/tiktok-auth.validator.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IACrB,YAAY,GAAG,QAAQ,CAAC;IAEjC,QAAQ,CAAC,IAA6B;QACpC,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ import type { AccountConfig, ILogger, PlatformCapabilities, PostRequest, ResolvedAccountConfig, ResumeHandle } from '@bozonx/social-posting';
2
+ import type { IPlatform, PlatformPublishResponse, PlatformStatusResponse, PublishOptions, RuntimeCapabilities } from '@bozonx/social-posting/platform';
3
+ export declare const DEFAULT_API_BASE_URL = "https://open.tiktokapis.com/v2";
4
+ export declare const STATUS_STEP = "publish-status";
5
+ export interface TikTokExtra extends Record<string, unknown> {
6
+ privacyLevel?: string;
7
+ disableComment?: boolean;
8
+ disableDuet?: boolean;
9
+ disableStitch?: boolean;
10
+ brandContentToggle?: boolean;
11
+ brandOrganicToggle?: boolean;
12
+ }
13
+ export interface TiktokPlatformDeps {
14
+ logger: ILogger;
15
+ fetch?: typeof fetch;
16
+ }
17
+ export declare class TiktokPlatform implements IPlatform {
18
+ private readonly deps;
19
+ readonly name = "tiktok";
20
+ readonly capabilities: PlatformCapabilities;
21
+ constructor(deps: TiktokPlatformDeps);
22
+ resolveCapabilities(account: ResolvedAccountConfig, signal?: AbortSignal): Promise<RuntimeCapabilities>;
23
+ publish(request: PostRequest<TikTokExtra>, account: AccountConfig & ResolvedAccountConfig, options?: PublishOptions): Promise<PlatformPublishResponse>;
24
+ checkStatus(handle: ResumeHandle, account: ResolvedAccountConfig, signal?: AbortSignal): Promise<PlatformStatusResponse>;
25
+ private call;
26
+ }
@@ -0,0 +1,186 @@
1
+ import { ErrorCode, PlatformError, PostType, ValidationError } from '@bozonx/social-posting';
2
+ import { httpRequest, validateAgainstCapabilities } from '@bozonx/social-posting/platform';
3
+ import { tiktokCapabilities } from './capabilities.js';
4
+ export const DEFAULT_API_BASE_URL = 'https://open.tiktokapis.com/v2';
5
+ export const STATUS_STEP = 'publish-status';
6
+ export class TiktokPlatform {
7
+ deps;
8
+ name = 'tiktok';
9
+ capabilities = tiktokCapabilities;
10
+ constructor(deps) {
11
+ this.deps = deps;
12
+ }
13
+ async resolveCapabilities(account, signal) {
14
+ const raw = await this.call('/post/publish/creator_info/query/', account, {
15
+ method: 'POST',
16
+ body: '{}',
17
+ signal,
18
+ });
19
+ const data = obj(raw.data);
20
+ const max = num(data.max_video_post_duration_sec);
21
+ return {
22
+ fetchedAt: new Date().toISOString(),
23
+ cacheableForSecs: 0,
24
+ capabilities: {
25
+ media: max && this.capabilities.media?.video
26
+ ? { video: { ...this.capabilities.media.video, maxDurationSecs: max } }
27
+ : {},
28
+ },
29
+ };
30
+ }
31
+ async publish(request, account, options) {
32
+ if (options?.signal?.aborted)
33
+ throw new PlatformError('Request aborted before publishing', ErrorCode.NETWORK_ERROR, {
34
+ retryable: false,
35
+ });
36
+ if (options?.resume) {
37
+ const resumed = await this.checkStatus(options.resume, account, options.signal);
38
+ if (resumed.status === 'failed')
39
+ throw (resumed.error ??
40
+ new PlatformError('TikTok publication failed', ErrorCode.CONTENT_REJECTED, {
41
+ retryable: false,
42
+ }));
43
+ if (resumed.status === 'processing')
44
+ return {
45
+ status: 'processing',
46
+ postId: resumed.postId,
47
+ handle: options.resume,
48
+ checkAfterMs: resumed.checkAfterMs,
49
+ raw: resumed.raw,
50
+ };
51
+ return {
52
+ status: 'published',
53
+ postId: resumed.postId,
54
+ url: resumed.url,
55
+ ref: resumed.ref,
56
+ raw: resumed.raw,
57
+ };
58
+ }
59
+ const staticCheck = validateAgainstCapabilities(request, this.capabilities, {
60
+ target: account.target,
61
+ });
62
+ if (staticCheck.issues.length)
63
+ throw new ValidationError(staticCheck.issues);
64
+ let caps = options?.capabilities ?? this.capabilities;
65
+ if (!options?.capabilities) {
66
+ const runtime = await this.resolveCapabilities(account, options?.signal);
67
+ caps = {
68
+ ...this.capabilities,
69
+ media: { ...this.capabilities.media, ...runtime.capabilities.media },
70
+ };
71
+ }
72
+ const checked = validateAgainstCapabilities(request, caps, { target: account.target });
73
+ if (checked.issues.length)
74
+ throw new ValidationError(checked.issues);
75
+ const media = request.media ?? [], photo = request.type === PostType.IMAGE || request.type === PostType.ALBUM;
76
+ const firstMedia = media[0];
77
+ if (!firstMedia)
78
+ throw new ValidationError('TikTok requires media');
79
+ const source_info = photo
80
+ ? { source: 'PULL_FROM_URL', photo_cover_index: 0, photo_images: media.map(m => url(m)) }
81
+ : { source: 'PULL_FROM_URL', video_url: url(firstMedia) };
82
+ const post_info = {
83
+ title: request.body ?? '',
84
+ privacy_level: request.extra?.privacyLevel ??
85
+ (request.visibility === 'private' ? 'SELF_ONLY' : 'PUBLIC_TO_EVERYONE'),
86
+ disable_comment: request.extra?.disableComment ?? false,
87
+ disable_duet: request.extra?.disableDuet ?? false,
88
+ disable_stitch: request.extra?.disableStitch ?? false,
89
+ brand_content_toggle: request.extra?.brandContentToggle ?? false,
90
+ brand_organic_toggle: request.extra?.brandOrganicToggle ?? false,
91
+ };
92
+ const raw = await this.call(photo ? '/post/publish/content/init/' : '/post/publish/video/init/', account, { method: 'POST', body: JSON.stringify({ post_info, source_info }), signal: options?.signal });
93
+ const id = str(obj(raw.data).publish_id) ?? str(raw.publish_id) ?? str(raw.id);
94
+ if (!id)
95
+ throw new PlatformError('TikTok returned no publish id', ErrorCode.UNKNOWN_OUTCOME, {
96
+ retryable: false,
97
+ });
98
+ return {
99
+ status: 'processing',
100
+ postId: id,
101
+ handle: { version: 1, platform: 'tiktok', step: STATUS_STEP, state: { publishId: id } },
102
+ checkAfterMs: 5000,
103
+ raw,
104
+ };
105
+ }
106
+ async checkStatus(handle, account, signal) {
107
+ if (handle.platform !== 'tiktok' || handle.step !== STATUS_STEP)
108
+ throw new ValidationError('Invalid TikTok status handle');
109
+ const id = str(handle.state.publishId);
110
+ if (!id)
111
+ throw new ValidationError('TikTok status handle has no publish id');
112
+ const raw = await this.call('/post/publish/status/fetch/', account, {
113
+ method: 'POST',
114
+ body: JSON.stringify({ publish_id: id }),
115
+ signal,
116
+ });
117
+ const data = obj(raw.data), status = str(data.status) ?? '', safe = raw;
118
+ if (['FAILED', 'PUBLISH_FAILED'].includes(status))
119
+ return {
120
+ status: 'failed',
121
+ postId: id,
122
+ error: new PlatformError('TikTok rejected the publication', ErrorCode.CONTENT_REJECTED, {
123
+ retryable: false,
124
+ platformCode: status,
125
+ }),
126
+ raw: safe,
127
+ };
128
+ if (!['PUBLISH_COMPLETE', 'PUBLISHED'].includes(status))
129
+ return { status: 'processing', postId: id, checkAfterMs: 5000, raw: safe };
130
+ const availableIds = Array.isArray(data.publicly_available_post_id)
131
+ ? data.publicly_available_post_id
132
+ : Array.isArray(data.publicaly_available_post_id)
133
+ ? data.publicaly_available_post_id
134
+ : [];
135
+ const postId = str(availableIds[0]) ?? id;
136
+ return { status: 'published', postId, ref: { postId }, raw: safe };
137
+ }
138
+ async call(path, a, init) {
139
+ const token = a.auth.accessToken;
140
+ if (typeof token !== 'string' || !token)
141
+ throw new ValidationError('TikTok accessToken is required');
142
+ const r = await httpRequest(`${DEFAULT_API_BASE_URL}${path}`, {
143
+ ...init,
144
+ headers: {
145
+ authorization: `Bearer ${token}`,
146
+ 'content-type': 'application/json; charset=UTF-8',
147
+ },
148
+ fetch: this.deps.fetch,
149
+ });
150
+ if (!r.ok)
151
+ throw await ttError(r);
152
+ return safeJson(r);
153
+ }
154
+ }
155
+ function url(m) {
156
+ if (m.source.kind !== 'url')
157
+ throw new ValidationError('TikTok pull publishing requires media URLs');
158
+ return m.source.url;
159
+ }
160
+ const obj = (v) => v && typeof v === 'object' && !Array.isArray(v) ? v : {};
161
+ const str = (v) => (typeof v === 'string' && v ? v : undefined);
162
+ const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
163
+ async function safeJson(r) {
164
+ try {
165
+ return (await r.json());
166
+ }
167
+ catch {
168
+ return {};
169
+ }
170
+ }
171
+ async function ttError(r) {
172
+ const b = await r.text(), n = Number(r.headers.get('retry-after'));
173
+ if (r.status === 429)
174
+ return new PlatformError(`TikTok rate limited: ${b}`, ErrorCode.RATE_LIMIT_ERROR, {
175
+ retryable: true,
176
+ retryAfterMs: Number.isFinite(n) ? n * 1000 : undefined,
177
+ httpStatus: r.status,
178
+ });
179
+ if (r.status === 401 || r.status === 403)
180
+ return new PlatformError(`TikTok rejected credentials: ${b}`, ErrorCode.AUTH_REFRESH_REQUIRED, {
181
+ retryable: false,
182
+ httpStatus: r.status,
183
+ });
184
+ return new PlatformError(`TikTok responded with ${r.status}: ${b}`, r.status >= 500 ? ErrorCode.PLATFORM_ERROR : ErrorCode.CONTENT_REJECTED, { retryable: r.status >= 500, httpStatus: r.status });
185
+ }
186
+ //# sourceMappingURL=tiktok.platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiktok.platform.js","sourceRoot":"","sources":["../src/tiktok.platform.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@bozonx/social-posting-tiktok",
3
+ "version": "0.8.0",
4
+ "description": "Tiktok platform for @bozonx/social-posting",
5
+ "keywords": [
6
+ "social-media",
7
+ "posting",
8
+ "tiktok"
9
+ ],
10
+ "type": "module",
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "workerd": "./dist/index.js",
17
+ "import": "./dist/index.js",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "dependencies": {},
27
+ "peerDependencies": {
28
+ "@bozonx/social-posting": "^0.8.0"
29
+ },
30
+ "devDependencies": {
31
+ "@bozonx/social-posting": "0.8.0",
32
+ "@bozonx/social-posting-conformance": "0.8.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "provenance": true
37
+ },
38
+ "sideEffects": false,
39
+ "author": "Ivan K",
40
+ "license": "MIT",
41
+ "engines": {
42
+ "node": ">=24.0.0"
43
+ },
44
+ "scripts": {
45
+ "build": "tsc -p tsconfig.build.json",
46
+ "clean": "rm -rf dist *.tsbuildinfo",
47
+ "typecheck": "tsc -p tsconfig.json --noEmit"
48
+ }
49
+ }