@openhandle/sdk 0.5.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +239 -0
  3. package/dist/errors.d.ts +26 -0
  4. package/dist/errors.d.ts.map +1 -0
  5. package/dist/errors.js +31 -0
  6. package/dist/errors.js.map +1 -0
  7. package/dist/generated/operations.d.ts +1830 -0
  8. package/dist/generated/operations.d.ts.map +1 -0
  9. package/dist/generated/operations.js +2455 -0
  10. package/dist/generated/operations.js.map +1 -0
  11. package/dist/generated/public-types.d.ts +679 -0
  12. package/dist/generated/public-types.d.ts.map +1 -0
  13. package/dist/generated/public-types.js +3 -0
  14. package/dist/generated/public-types.js.map +1 -0
  15. package/dist/generated/resources.d.ts +1949 -0
  16. package/dist/generated/resources.d.ts.map +1 -0
  17. package/dist/generated/resources.js +3 -0
  18. package/dist/generated/resources.js.map +1 -0
  19. package/dist/generated/schema.d.ts +30218 -0
  20. package/dist/generated/schema.d.ts.map +1 -0
  21. package/dist/generated/schema.js +3 -0
  22. package/dist/generated/schema.js.map +1 -0
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +10 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/references.d.ts +3 -0
  28. package/dist/references.d.ts.map +1 -0
  29. package/dist/references.js +162 -0
  30. package/dist/references.js.map +1 -0
  31. package/dist/runtime.d.ts +16 -0
  32. package/dist/runtime.d.ts.map +1 -0
  33. package/dist/runtime.js +230 -0
  34. package/dist/runtime.js.map +1 -0
  35. package/dist/types.d.ts +99 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +2 -0
  38. package/dist/types.js.map +1 -0
  39. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenHandle
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,239 @@
1
+ # OpenHandle TypeScript SDK
2
+
3
+ The official TypeScript and JavaScript client for the OpenHandle API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @openhandle/sdk
9
+ ```
10
+
11
+ The package is also compatible with npm, Yarn, and Bun.
12
+
13
+ ## Usage
14
+
15
+ Create a Test key in the [Openhandle dashboard](https://app.openhandle.dev),
16
+ store it as `OPENHANDLE_TEST_KEY`, and create one reusable client:
17
+
18
+ ```ts
19
+ import { OpenHandle } from '@openhandle/sdk';
20
+
21
+ const openhandle = new OpenHandle({ apiKey: process.env.OPENHANDLE_TEST_KEY! });
22
+ const profile = openhandle.instagram.profile('northstar_forge_test');
23
+
24
+ const response = await profile.get();
25
+ const posts = await profile.posts.list({ freshness: '24h' });
26
+
27
+ console.log(response.data.handle, posts.data.length);
28
+ ```
29
+
30
+ The key selects the environment. `oh_test_` keys return deterministic synthetic
31
+ data with a `$0.000` actual charge; `oh_live_` keys use real public identifiers
32
+ and normal billing. Never ship an API key in a browser or mobile bundle.
33
+
34
+ See the [API reference](https://openhandle.dev/docs/api-reference) for a typed
35
+ SDK example for every operation.
36
+
37
+ ## Resource selection
38
+
39
+ The SDK follows one predictable grammar:
40
+
41
+ ```text
42
+ openhandle.<platform>.<resource>(reference).<subresource>.<operation>(options)
43
+ ```
44
+
45
+ Only terminal operations such as `get`, `list`, `search`, and `fetch` perform
46
+ network requests. Selecting a resource is synchronous and reusable:
47
+
48
+ ```ts
49
+ const post = openhandle.instagram.post('Db04otPRpRH');
50
+
51
+ const details = await post.get();
52
+ const comments = await post.comments.list();
53
+ ```
54
+
55
+ Profile strings are usernames, including all-numeric usernames. Use an
56
+ explicit reference for platform IDs and URLs:
57
+
58
+ ```ts
59
+ openhandle.instagram.profile({ id: '25025320' });
60
+ openhandle.instagram.profile({ url: 'https://www.instagram.com/openai/' });
61
+ ```
62
+
63
+ Platform IDs are opaque strings. Numeric ID values are rejected.
64
+
65
+ Use `fetch` when the URL's platform or resource is not known:
66
+
67
+ ```ts
68
+ const response = await openhandle.fetch('https://www.instagram.com/p/Db04otPRpRH/', {
69
+ freshness: '24h',
70
+ });
71
+ ```
72
+
73
+ ## Responses and billing
74
+
75
+ Successful responses preserve the public envelope and add normalized request
76
+ metadata:
77
+
78
+ ```ts
79
+ const response = await openhandle.instagram.profile('northstar_forge_test').get();
80
+
81
+ response.data; // Typed, camel-cased resource
82
+ response.platform;
83
+ response.resource;
84
+ response.capturedAt;
85
+ response.source;
86
+ response.requestId;
87
+ response.billing.cost;
88
+ response.billing.environment;
89
+ ```
90
+
91
+ Unavailable metrics are `null`, never `0`. Monetary values are decimal strings
92
+ so applications do not lose precision.
93
+
94
+ ## Pagination
95
+
96
+ List operations return a typed page with its opaque cursor and a lazy `next()`
97
+ helper:
98
+
99
+ ```ts
100
+ let page = await openhandle.instagram.profile('northstar_forge_test').posts.list();
101
+
102
+ while (true) {
103
+ for (const post of page.data) {
104
+ console.log(post.id);
105
+ }
106
+
107
+ const nextPage = await page.next();
108
+ if (!nextPage) break;
109
+ page = nextPage;
110
+ }
111
+ ```
112
+
113
+ Each call to `next()` that fetches a page is one request. It returns `null`
114
+ without a request after the final page.
115
+
116
+ ## Errors and retries
117
+
118
+ API failures throw `OpenHandleError`. Branch on `code`, never `message`, and
119
+ include `requestId` in logs or support requests:
120
+
121
+ ```ts
122
+ import { OpenHandleError } from '@openhandle/sdk';
123
+
124
+ try {
125
+ await openhandle.instagram.profile('quiet_harbor_test').get();
126
+ } catch (error) {
127
+ if (error instanceof OpenHandleError) {
128
+ console.error(error.code, error.status, error.retryable, error.requestId);
129
+ }
130
+ throw error;
131
+ }
132
+ ```
133
+
134
+ The client retries explicitly retryable API failures and transient Fetch
135
+ failures up to `maxRetries`. It honors `Retry-After` and uses capped exponential
136
+ backoff with jitter. Reference-validation errors occur before a request and are
137
+ available as `OpenHandleReferenceError` and `ReferenceMismatchError`.
138
+
139
+ ## Configuration
140
+
141
+ ```ts
142
+ const openhandle = new OpenHandle({
143
+ apiKey: process.env.OPENHANDLE_TEST_KEY!,
144
+ baseUrl: 'https://api.openhandle.dev',
145
+ maxRetries: 2,
146
+ timeoutMs: 30_000,
147
+ });
148
+
149
+ await openhandle.instagram.profile('northstar_forge_test').get({
150
+ maxRetries: 0,
151
+ signal: abortController.signal,
152
+ timeoutMs: 10_000,
153
+ });
154
+ ```
155
+
156
+ | Option | Default | Meaning |
157
+ |---|---:|---|
158
+ | `apiKey` | required | Secret Test or Live API key |
159
+ | `baseUrl` | `https://api.openhandle.dev` | API origin, useful for proxies and tests |
160
+ | `fetch` | `globalThis.fetch` | Custom Fetch implementation |
161
+ | `maxRetries` | `2` | Retry attempts after the initial request |
162
+ | `timeoutMs` | `30000` | Timeout for each request attempt |
163
+
164
+ `maxRetries`, `timeoutMs`, and an `AbortSignal` can also be supplied per
165
+ operation. Per-operation values override client defaults.
166
+
167
+ ## Runtime support
168
+
169
+ The package is ESM-only and supports Node.js 20 or newer. It also works with
170
+ runtimes that provide the standard Fetch and AbortSignal APIs.
171
+
172
+ ## TypeScript conventions
173
+
174
+ Request options and response fields use camel case. The exported `components`
175
+ type represents the raw OpenAPI wire schema; terminal SDK operation return
176
+ types apply the camel-case transformation automatically.
177
+
178
+ The root package also exports camel-cased model types and named aliases for
179
+ every operation. These are useful for wrappers, caches, callbacks, and public
180
+ function signatures:
181
+
182
+ ```ts
183
+ import type {
184
+ InstagramProfile,
185
+ InstagramProfilePostsOptions,
186
+ InstagramProfilePostsPage,
187
+ InstagramProfileResponse,
188
+ } from '@openhandle/sdk';
189
+
190
+ async function getProfile(): Promise<InstagramProfileResponse> {
191
+ return openhandle.instagram.profile('northstar_forge_test').get();
192
+ }
193
+
194
+ function readProfile(profile: InstagramProfile) {
195
+ return profile.handle;
196
+ }
197
+ ```
198
+
199
+ Operation names omit the terminal `get` or `list`: for example,
200
+ `instagram.profile.posts.list` produces `InstagramProfilePostsOptions` and
201
+ `InstagramProfilePostsPage`. Search terminals keep `Search` in the name when
202
+ needed to avoid ambiguity.
203
+
204
+ For example:
205
+
206
+ ```ts
207
+ const result = await openhandle.instagram.profile('northstar_forge_test').posts.list({
208
+ freshness: '24h',
209
+ since: '2026-08-01T00:00:00Z',
210
+ });
211
+
212
+ result.data[0]?.publishedAt;
213
+ ```
214
+
215
+ ## Development
216
+
217
+ The SDK is generated from the pinned OpenAPI document in
218
+ [`openapi/openhandle.json`](./openapi/openhandle.json). The generator, runtime,
219
+ tests, and generated output are all kept in this repository so releases are
220
+ reproducible without access to the private OpenHandle API implementation.
221
+
222
+ ```bash
223
+ pnpm install
224
+ pnpm generate
225
+ pnpm test
226
+ ```
227
+
228
+ `pnpm generate:check` fails when the committed generated files do not match the
229
+ pinned OpenAPI document.
230
+
231
+ ## Releases
232
+
233
+ Conventional commits feed an automated release pull request. Merging that pull
234
+ request creates a `v*` tag; the tag workflow tests and publishes the package to
235
+ npm using trusted publishing. Registry credentials are not stored in GitHub.
236
+
237
+ ## License
238
+
239
+ [MIT](./LICENSE)
@@ -0,0 +1,26 @@
1
+ export interface OpenHandleErrorInput {
2
+ cause?: unknown;
3
+ code: string;
4
+ details?: Record<string, unknown>;
5
+ message: string;
6
+ requestId?: string;
7
+ retryable?: boolean;
8
+ retryAfter?: number;
9
+ status?: number;
10
+ }
11
+ export declare class OpenHandleError extends Error {
12
+ readonly code: string;
13
+ readonly details?: Record<string, unknown>;
14
+ readonly requestId?: string;
15
+ readonly retryable: boolean;
16
+ readonly retryAfter?: number;
17
+ readonly status?: number;
18
+ constructor(input: OpenHandleErrorInput);
19
+ }
20
+ export declare class OpenHandleReferenceError extends TypeError {
21
+ constructor(message: string);
22
+ }
23
+ export declare class ReferenceMismatchError extends OpenHandleReferenceError {
24
+ constructor(expectedPlatform: string, expectedResource: string, actualPlatform: string, actualResource: string);
25
+ }
26
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEb,KAAK,EAAE,oBAAoB;CAU1C;AAED,qBAAa,wBAAyB,SAAQ,SAAS;gBACvC,OAAO,EAAE,MAAM;CAI9B;AAED,qBAAa,sBAAuB,SAAQ,wBAAwB;gBACpD,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;CAIjH"}
package/dist/errors.js ADDED
@@ -0,0 +1,31 @@
1
+ export class OpenHandleError extends Error {
2
+ code;
3
+ details;
4
+ requestId;
5
+ retryable;
6
+ retryAfter;
7
+ status;
8
+ constructor(input) {
9
+ super(input.message, { cause: input.cause });
10
+ this.name = 'OpenHandleError';
11
+ this.code = input.code;
12
+ this.details = input.details;
13
+ this.requestId = input.requestId;
14
+ this.retryable = input.retryable ?? false;
15
+ this.retryAfter = input.retryAfter;
16
+ this.status = input.status;
17
+ }
18
+ }
19
+ export class OpenHandleReferenceError extends TypeError {
20
+ constructor(message) {
21
+ super(message);
22
+ this.name = 'OpenHandleReferenceError';
23
+ }
24
+ }
25
+ export class ReferenceMismatchError extends OpenHandleReferenceError {
26
+ constructor(expectedPlatform, expectedResource, actualPlatform, actualResource) {
27
+ super(`Expected a ${expectedPlatform} ${expectedResource} URL, received a ${actualPlatform} ${actualResource} URL.`);
28
+ this.name = 'ReferenceMismatchError';
29
+ }
30
+ }
31
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC7B,IAAI,CAAS;IACb,OAAO,CAA2B;IAClC,SAAS,CAAU;IACnB,SAAS,CAAU;IACnB,UAAU,CAAU;IACpB,MAAM,CAAU;IAEzB,YAAY,KAA2B;QACnC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC;QAC1C,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC/B,CAAC;CACJ;AAED,MAAM,OAAO,wBAAyB,SAAQ,SAAS;IACnD,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IAC3C,CAAC;CACJ;AAED,MAAM,OAAO,sBAAuB,SAAQ,wBAAwB;IAChE,YAAY,gBAAwB,EAAE,gBAAwB,EAAE,cAAsB,EAAE,cAAsB;QAC1G,KAAK,CAAC,cAAc,gBAAgB,IAAI,gBAAgB,oBAAoB,cAAc,IAAI,cAAc,OAAO,CAAC,CAAC;QACrH,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACzC,CAAC;CACJ"}