@oxchannels/sdk 1.0.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 +7 -0
- package/QUICKSTART.md +604 -0
- package/README.md +193 -0
- package/contracts/openapi-agent-bootstrap-contract-v2.json +1266 -0
- package/contracts/openapi-dashboard-contract-v2.json +98996 -0
- package/contracts/openapi-partner-contract-v2.json +14808 -0
- package/contracts/openapi-public-contract-v2.json +13489 -0
- package/dist/client.d.ts +83 -0
- package/dist/client.js +661 -0
- package/dist/generated/agent-bootstrap-contract-v2-schema.d.ts +398 -0
- package/dist/generated/agent-bootstrap-contract-v2-schema.js +1 -0
- package/dist/generated/client.d.ts +1 -0
- package/dist/generated/client.js +2 -0
- package/dist/generated/contracts/api-errors.d.ts +83 -0
- package/dist/generated/contracts/api-errors.js +296 -0
- package/dist/generated/contracts/json-data.d.ts +16 -0
- package/dist/generated/contracts/json-data.js +308 -0
- package/dist/generated/dashboard-contract-v2-schema.d.ts +45429 -0
- package/dist/generated/dashboard-contract-v2-schema.js +1 -0
- package/dist/generated/partner-contract-v2-schema.d.ts +6458 -0
- package/dist/generated/partner-contract-v2-schema.js +1 -0
- package/dist/generated/public-contract-v2-schema.d.ts +4112 -0
- package/dist/generated/public-contract-v2-schema.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -0
- package/generated/provenance.json +87 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @oxchannels/sdk
|
|
2
|
+
|
|
3
|
+
> **Closed beta.** OxChannels is in a closed beta. This package is published so invited
|
|
4
|
+
> partners can install it with `npm install`, but it is useful only with an API key issued by
|
|
5
|
+
> the OxChannels team for your workspace, and there is no self-service sign-up yet. Endpoints,
|
|
6
|
+
> contracts and this SDK may still change between beta releases without a major version bump;
|
|
7
|
+
> read the changelog notes on each release before upgrading. To join the beta or report an
|
|
8
|
+
> issue, contact OxChannels at https://oxchannels.com.
|
|
9
|
+
|
|
10
|
+
Typed TypeScript client for the OxChannels REST API. Everything in it is generated from the sealed
|
|
11
|
+
OpenAPI contracts (`docs/api/generated/openapi-*-contract-v2.json`): `openapi-typescript@7.13.0`
|
|
12
|
+
produces four isolated path sets, `openapi-fetch@0.17.0` supplies the runtime, and there is no
|
|
13
|
+
handwritten wire DTO anywhere. The package directory in the repository is `packages/openapi-client`.
|
|
14
|
+
|
|
15
|
+
- Guide with the full publishing walkthrough: `QUICKSTART.md`, shipped inside this package
|
|
16
|
+
(source: `docs/guides/sdk-quickstart.md` in the OxChannels repository).
|
|
17
|
+
- Single-source example, type-checked on every test run: `examples/publish-everywhere.ts` in the
|
|
18
|
+
repository package directory.
|
|
19
|
+
- Runtime: Node 24 (or any runtime with WHATWG `fetch`); ESM only.
|
|
20
|
+
|
|
21
|
+
## What you can do with it
|
|
22
|
+
|
|
23
|
+
- Read the workspace context and the publishing context: which channels are connected, which
|
|
24
|
+
targets are ready, what each target can carry (text, image, video, variants, limits).
|
|
25
|
+
- Upload media once and reuse it across targets.
|
|
26
|
+
- Create one publication per target against the capability snapshot you were shown, submit it,
|
|
27
|
+
and follow the operation to a confirmed effect with the provider's URL of the content.
|
|
28
|
+
- Receive webhooks about operation status and reconcile idempotently on retries.
|
|
29
|
+
|
|
30
|
+
Supported channels in the beta: Bluesky, Facebook pages, Instagram business accounts, LinkedIn,
|
|
31
|
+
Mastodon, Telegram channels, Threads, TikTok, X and YouTube. Every request is authenticated with a
|
|
32
|
+
workspace-scoped API key; the key carries scopes (`context:read`, `targets:read`,
|
|
33
|
+
`operations:read`, `operations:write`, `webhooks:manage`) and can be rotated or revoked in the
|
|
34
|
+
OxChannels panel.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @oxchannels/sdk
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The tarball carries `dist/` (runtime and `.d.ts`), the four OpenAPI documents it was generated from
|
|
43
|
+
(`contracts/*.json`), `generated/provenance.json` with the SHA-256 of every source and output,
|
|
44
|
+
`QUICKSTART.md` and the licence. It has one runtime dependency, `openapi-fetch`.
|
|
45
|
+
|
|
46
|
+
## First publication
|
|
47
|
+
|
|
48
|
+
The partner surface is what an external system uses to publish. Create one client per service key
|
|
49
|
+
(the key comes from the panel, API keys), then walk the flow: who am I, where can I publish,
|
|
50
|
+
upload media once, create a publication per target, submit the action, follow it.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { createOxStudioClient } from '@oxchannels/sdk';
|
|
54
|
+
|
|
55
|
+
const client = createOxStudioClient({
|
|
56
|
+
baseUrl: 'https://api.oxchannels.com',
|
|
57
|
+
serviceKey: () => process.env.OXS_API_KEY!,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const context = (await client.GET('/v1/integration/publishing-context')).data!;
|
|
61
|
+
for (const target of context.targets) {
|
|
62
|
+
if (target.readiness !== 'READY' || target.capability === null) continue;
|
|
63
|
+
|
|
64
|
+
const publication = (
|
|
65
|
+
await client.POST('/v1/integration/publications', {
|
|
66
|
+
body: {
|
|
67
|
+
targetId: target.targetId,
|
|
68
|
+
capabilityGeneration: target.capability.generation,
|
|
69
|
+
capabilityHash: target.capability.snapshotHash,
|
|
70
|
+
body: 'Hello from @oxchannels/sdk',
|
|
71
|
+
locale: 'en',
|
|
72
|
+
mediaAssetIds: [],
|
|
73
|
+
options: {},
|
|
74
|
+
clientReference: `my-run:${target.targetId}`,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
).data!;
|
|
78
|
+
|
|
79
|
+
const action = (
|
|
80
|
+
await client.POST('/v1/integration/publishing-actions', {
|
|
81
|
+
body: {
|
|
82
|
+
mode: 'PUBLISH_NOW',
|
|
83
|
+
contentRevisionId: publication.revision.id,
|
|
84
|
+
targetIds: [target.targetId],
|
|
85
|
+
oxStudioRun: {
|
|
86
|
+
schemaVersion: 'ox-studio-run.v1',
|
|
87
|
+
workflowRunId: 'my-run',
|
|
88
|
+
workflowTaskId: 'publish',
|
|
89
|
+
taskGeneration: 1,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
).data!;
|
|
94
|
+
console.log(target.connectorKey, action.actionId, action.outcome);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`examples/publish-everywhere.ts` is the complete version: media upload with the scan wait,
|
|
99
|
+
per-target stale-snapshot recovery, polling the action to a terminal outcome and the webhook
|
|
100
|
+
subscription. Every non-2xx response is thrown as `OxChannelsApiErrorV2`, so `data` is defined
|
|
101
|
+
whenever a call returns.
|
|
102
|
+
|
|
103
|
+
## Clients and surfaces
|
|
104
|
+
|
|
105
|
+
- `createPartnerClient` (alias `createOxStudioClient`) accepts an OxChannels service key as Bearer
|
|
106
|
+
authentication (`serviceKey`, or the equivalent `bearer` spelling; never both) and an optional
|
|
107
|
+
correlation ID. Its base URL must use HTTPS. Development HTTP is available only through
|
|
108
|
+
`allowInsecureLoopbackForDevelopment: true` and only for the exact loopback hosts `localhost`,
|
|
109
|
+
`127.0.0.1` or `[::1]`. Every request remains bound to the configured origin and uses
|
|
110
|
+
`redirect: error`, so a per-call override or redirect cannot move the service key to another
|
|
111
|
+
origin. It does not expose or simulate partner OAuth.
|
|
112
|
+
- `createPublicClient` covers health and unauthenticated identity bootstrap. Public and dashboard
|
|
113
|
+
transports accept HTTPS or a browser-relative same-origin base URL; development HTTP requires the
|
|
114
|
+
explicit loopback-only opt-in used by the privileged clients.
|
|
115
|
+
- `createDashboardV2Client` (also `createDashboardContractClient`) uses the browser session plus
|
|
116
|
+
CSRF for the dashboard projection. Both dashboard factories accept `expectedProviderBindingId`, a
|
|
117
|
+
selector-aware supplier used only for the exact BYO binding mutation path. Returning the current
|
|
118
|
+
secret-free binding UUID adds the `X-OxChannels-Expected-Binding-Id` compare-and-set header;
|
|
119
|
+
returning `undefined` performs initial binding creation. Malformed values and supplier failures
|
|
120
|
+
stop before transport.
|
|
121
|
+
- `createAgentBootstrapClient` covers only the one-time Local Agent enrollment surface, with the
|
|
122
|
+
same HTTPS, configured-origin and `redirect: error` boundary as the partner client.
|
|
123
|
+
|
|
124
|
+
Every client overwrites `OxChannels-Contract-Set` with the exact value `2.0.0` on every request.
|
|
125
|
+
The raw OpenAPI keeps that header required for fetch operations, while the SDK projection removes it
|
|
126
|
+
from caller-facing types; dashboard mutation types similarly omit the SDK-managed CSRF header.
|
|
127
|
+
Operations marked `x-oxchannels-browser-navigation-only` (local sign-in, social sign-in start and
|
|
128
|
+
callback, the MCP authorization front door and the provider OAuth callback) are removed from the
|
|
129
|
+
fetch projections: callers must navigate the browser to those redirect endpoints. The generator
|
|
130
|
+
requires those exact public GET operations, a sole `302` success and a required `Location` header;
|
|
131
|
+
missing or unknown markers fail generation.
|
|
132
|
+
|
|
133
|
+
Dashboard mutations fail before transport unless the configured CSRF supplier returns a safe value
|
|
134
|
+
of at least 16 characters, while reads do not require one. Partner, public and agent clients
|
|
135
|
+
explicitly omit browser credentials; only the dashboard client includes its session cookie. All
|
|
136
|
+
clients force `redirect: error`, the exact configured origin and the expected credentials mode.
|
|
137
|
+
Per-call base URL, redirect, credentials or transport overrides are rejected before an
|
|
138
|
+
authentication or CSRF supplier is read; SDK-managed credentials are attached only after request
|
|
139
|
+
middleware has completed.
|
|
140
|
+
|
|
141
|
+
## Errors
|
|
142
|
+
|
|
143
|
+
A v2 error is parsed by the canonical browser-safe parser (copied by the generator from
|
|
144
|
+
`packages/contracts/src/api-errors.ts` into `src/generated/contracts/`, so the published package has
|
|
145
|
+
no workspace dependency) and thrown as `OxChannelsApiErrorV2`, preserving the stable `code`,
|
|
146
|
+
`category`, trace and correlation IDs, `retryable`, `effectEvidence`, optional `retryAfterSeconds`
|
|
147
|
+
and bounded validation `violations`. The parsed code must also match the HTTP status contract
|
|
148
|
+
(`409` allows only the two conflict variants, `5xx` only the safe internal variant, unlisted `4xx`
|
|
149
|
+
only validation); a mismatch, malformed body or oversized error becomes
|
|
150
|
+
`OxChannelsApiProtocolError`. Response bodies and service keys are never copied into that error.
|
|
151
|
+
Error bodies are streamed into a strict 64 KiB budget and the stream is cancelled on overflow. The
|
|
152
|
+
unauthorized hook runs only after a canonical `AUTHENTICATION_REQUIRED` response is parsed. Caller
|
|
153
|
+
abort signals are combined with, and cannot disable, the SDK timeout (15 s by default, at most
|
|
154
|
+
120 s); the timeout is released only when the response body reaches EOF or is cancelled. The
|
|
155
|
+
legacy `OxChannelsApiError` remains as the base class.
|
|
156
|
+
|
|
157
|
+
None of the wrappers retries writes; recovery continues to use explicit idempotency lookup and
|
|
158
|
+
operation status. See `docs/guides/idempotency.md` in the OxChannels repository and the
|
|
159
|
+
"Idempotency and retries" section of `QUICKSTART.md`.
|
|
160
|
+
|
|
161
|
+
## Generated sources and provenance
|
|
162
|
+
|
|
163
|
+
`pnpm openapi:generate` (from the repository root) regenerates the four projections, copies the two
|
|
164
|
+
contract runtime sources and writes `generated/provenance.json` with separate source and output
|
|
165
|
+
SHA-256 values. `pnpm openapi:check` rejects a missing projection, provenance drift, trust-surface
|
|
166
|
+
drift, fake `/v2` wire paths, a v2 operation without the mandatory contract-set header, and a
|
|
167
|
+
runtime-source copy that no longer matches its origin.
|
|
168
|
+
|
|
169
|
+
Projections are generated with `immutable: false` on purpose: `openapi-fetch` only recognises
|
|
170
|
+
mutable arrays when it derives the `data` type, so a `readonly` projection would leave response
|
|
171
|
+
arrays without `map`, `find` or iteration. Request bodies therefore expect plain arrays; spread a
|
|
172
|
+
`readonly` array before passing it.
|
|
173
|
+
|
|
174
|
+
## Versioning and release
|
|
175
|
+
|
|
176
|
+
The package version (`1.0.0` first) is independent of the sealed contract distribution recorded in
|
|
177
|
+
`contracts.lock.json`. `.github/workflows/release-sdk.yml` builds, tests, compares the four
|
|
178
|
+
contracts of the previously published tarball with the current documents to classify the semver
|
|
179
|
+
level (`scripts/contracts/diff-surface.mjs`), publishes with `pnpm publish --access public` and
|
|
180
|
+
tags `sdk-v<version>`. Pack and publish go through pnpm, never npm: the manifest uses the
|
|
181
|
+
`catalog:` and `workspace:` protocols and only pnpm rewrites them to concrete versions. The
|
|
182
|
+
`prepack` script copies the contracts and the licence into the package directory; both are
|
|
183
|
+
git-ignored there. Details in
|
|
184
|
+
`docs/guides/contract-versioning.md` in the OxChannels repository.
|
|
185
|
+
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
pnpm --filter @oxchannels/sdk build # tsc -> dist/
|
|
190
|
+
pnpm --filter @oxchannels/sdk test # runtime tests + type test of the example and consumer
|
|
191
|
+
pnpm --filter @oxchannels/sdk lint
|
|
192
|
+
cd packages/openapi-client && pnpm pack --pack-destination /tmp/sdk-pack
|
|
193
|
+
```
|