@onebooks/node 0.0.0-stage → 0.1.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 +21 -0
- package/README.md +359 -2
- package/dist/app-data.d.ts +107 -0
- package/dist/app-data.d.ts.map +1 -0
- package/dist/app-data.js +48 -0
- package/dist/app-data.js.map +1 -0
- package/dist/client.d.ts +58 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +214 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +114 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +49 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +39 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.d.ts +87 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +140 -0
- package/dist/oauth.js.map +1 -0
- package/dist/session-token.d.ts +36 -0
- package/dist/session-token.d.ts.map +1 -0
- package/dist/session-token.js +41 -0
- package/dist/session-token.js.map +1 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/webhook.d.ts +41 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +86 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +52 -4
package/dist/client.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { OneBooksApiError, parseRetryAfterMs, retryAfterSeconds } from './errors.js';
|
|
2
|
+
import { AppDataResource } from './app-data.js';
|
|
3
|
+
import { EventsResource } from './events.js';
|
|
4
|
+
const DEFAULT_API_BASE = 'https://api.getonebooks.com';
|
|
5
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
6
|
+
// 502/503/504 (and a network error) can mean the API DID process the request
|
|
7
|
+
// and only the response was lost — safe to replay only for a read, or for a
|
|
8
|
+
// write the server can de-duplicate by its Idempotency-Key.
|
|
9
|
+
const GATEWAY_STATUS = new Set([502, 503, 504]);
|
|
10
|
+
const BASE_BACKOFF_MS = 500;
|
|
11
|
+
const MAX_BACKOFF_MS = 8_000;
|
|
12
|
+
/**
|
|
13
|
+
* The retry rule, in one place:
|
|
14
|
+
* - `429` is retried for EVERY method — a rate-limited request was never
|
|
15
|
+
* processed, so replaying it can't duplicate anything.
|
|
16
|
+
* - A network error or `502`/`503`/`504` is retried only for `GET`/`HEAD`, or
|
|
17
|
+
* for any other method when the call set an `idempotencyKey` — otherwise a
|
|
18
|
+
* POST that the API processed before the connection dropped would be sent
|
|
19
|
+
* twice (a duplicate customer, expense, quote, …).
|
|
20
|
+
* - Nothing else is ever retried.
|
|
21
|
+
*/
|
|
22
|
+
export function canReplayAfterAmbiguousFailure(method, idempotencyKey) {
|
|
23
|
+
return method === 'GET' || method === 'HEAD' || !!idempotencyKey;
|
|
24
|
+
}
|
|
25
|
+
function sleep(ms) {
|
|
26
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
}
|
|
28
|
+
/** 429 honors `Retry-After` (seconds, or an HTTP date) when present; every
|
|
29
|
+
* other retryable status uses jittered exponential backoff. */
|
|
30
|
+
function computeDelayMs(attempt, retryAfterHeader) {
|
|
31
|
+
const retryAfterMs = parseRetryAfterMs(retryAfterHeader);
|
|
32
|
+
if (retryAfterMs !== undefined)
|
|
33
|
+
return retryAfterMs;
|
|
34
|
+
const base = Math.min(MAX_BACKOFF_MS, BASE_BACKOFF_MS * 2 ** attempt);
|
|
35
|
+
const jitter = Math.random() * base * 0.5;
|
|
36
|
+
return Math.min(MAX_BACKOFF_MS, base + jitter);
|
|
37
|
+
}
|
|
38
|
+
async function readBody(res) {
|
|
39
|
+
const text = await res.text();
|
|
40
|
+
if (!text)
|
|
41
|
+
return undefined;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(text);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function extractMessage(body, res) {
|
|
50
|
+
if (body && typeof body === 'object' && 'message' in body) {
|
|
51
|
+
const m = body.message;
|
|
52
|
+
if (typeof m === 'string')
|
|
53
|
+
return m;
|
|
54
|
+
if (Array.isArray(m))
|
|
55
|
+
return m.join('; ');
|
|
56
|
+
}
|
|
57
|
+
return res.statusText || `HTTP ${res.status}`;
|
|
58
|
+
}
|
|
59
|
+
function extractCode(body) {
|
|
60
|
+
if (body && typeof body === 'object' && 'code' in body) {
|
|
61
|
+
const c = body.code;
|
|
62
|
+
if (typeof c === 'string')
|
|
63
|
+
return c;
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Server-side OneBooks API client: authenticated `request()` with retries,
|
|
69
|
+
* plus `appData`/`events` resource helpers. OAuth flow helpers (PKCE, code
|
|
70
|
+
* exchange, session-token exchange, …) are standalone — see `oauth.ts` — since
|
|
71
|
+
* you need them before a client (and its token) exists.
|
|
72
|
+
*/
|
|
73
|
+
export class OneBooksClient {
|
|
74
|
+
apiBase;
|
|
75
|
+
apiVersion;
|
|
76
|
+
appData;
|
|
77
|
+
events;
|
|
78
|
+
maxRetries;
|
|
79
|
+
fetchImpl;
|
|
80
|
+
staticToken;
|
|
81
|
+
getAccessTokenFn;
|
|
82
|
+
constructor(options) {
|
|
83
|
+
if (!options.accessToken && !options.getAccessToken) {
|
|
84
|
+
throw new Error('OneBooksClient: provide either "accessToken" or "getAccessToken".');
|
|
85
|
+
}
|
|
86
|
+
this.staticToken = options.accessToken;
|
|
87
|
+
this.getAccessTokenFn = options.getAccessToken;
|
|
88
|
+
this.apiBase = (options.apiBase ?? DEFAULT_API_BASE).replace(/\/+$/, '');
|
|
89
|
+
this.apiVersion = options.apiVersion;
|
|
90
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
91
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
92
|
+
this.appData = new AppDataResource(this);
|
|
93
|
+
this.events = new EventsResource(this);
|
|
94
|
+
}
|
|
95
|
+
async resolveAccessToken() {
|
|
96
|
+
if (this.getAccessTokenFn)
|
|
97
|
+
return this.getAccessTokenFn();
|
|
98
|
+
if (this.staticToken)
|
|
99
|
+
return this.staticToken;
|
|
100
|
+
throw new Error('OneBooksClient: no access token available.');
|
|
101
|
+
}
|
|
102
|
+
buildUrl(path, query) {
|
|
103
|
+
const rel = path.startsWith('/') ? path.slice(1) : path;
|
|
104
|
+
const url = new URL(`${this.apiBase}/${rel}`);
|
|
105
|
+
if (query) {
|
|
106
|
+
for (const [key, value] of Object.entries(query)) {
|
|
107
|
+
if (value === undefined || value === null)
|
|
108
|
+
continue;
|
|
109
|
+
if (Array.isArray(value)) {
|
|
110
|
+
if (value.length === 0)
|
|
111
|
+
continue;
|
|
112
|
+
url.searchParams.set(key, value.join(','));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
url.searchParams.set(key, String(value));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return url.toString();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Issues one authenticated API request. Retries (up to `maxRetries`) a
|
|
123
|
+
* `429` for any method, honoring `Retry-After`; retries a network error or
|
|
124
|
+
* `502`/`503`/`504` (jittered backoff) only for `GET`/`HEAD` or when
|
|
125
|
+
* `options.idempotencyKey` is set — see `canReplayAfterAmbiguousFailure`.
|
|
126
|
+
* Never retries any other status. Resolves the parsed JSON body (or
|
|
127
|
+
* `undefined` for a `204`); throws `OneBooksApiError` on a non-retried
|
|
128
|
+
* failure (or rethrows the network error).
|
|
129
|
+
*/
|
|
130
|
+
async request(method, path, options = {}) {
|
|
131
|
+
const url = this.buildUrl(path, options.query);
|
|
132
|
+
const replayable = canReplayAfterAmbiguousFailure(method, options.idempotencyKey);
|
|
133
|
+
let attempt = 0;
|
|
134
|
+
for (;;) {
|
|
135
|
+
const headers = new Headers(options.headers);
|
|
136
|
+
headers.set('Accept', 'application/json');
|
|
137
|
+
headers.set('Authorization', `Bearer ${await this.resolveAccessToken()}`);
|
|
138
|
+
if (this.apiVersion)
|
|
139
|
+
headers.set('OneBooks-Version', this.apiVersion);
|
|
140
|
+
if (options.idempotencyKey)
|
|
141
|
+
headers.set('Idempotency-Key', options.idempotencyKey);
|
|
142
|
+
let body;
|
|
143
|
+
if (options.body !== undefined) {
|
|
144
|
+
headers.set('Content-Type', 'application/json');
|
|
145
|
+
body = JSON.stringify(options.body);
|
|
146
|
+
}
|
|
147
|
+
let res;
|
|
148
|
+
try {
|
|
149
|
+
res = await this.fetchImpl(url, { method, headers, body, signal: options.signal });
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
if (options.signal?.aborted || !replayable || attempt >= this.maxRetries)
|
|
153
|
+
throw err;
|
|
154
|
+
await sleep(computeDelayMs(attempt, null));
|
|
155
|
+
attempt += 1;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (res.ok) {
|
|
159
|
+
if (res.status === 204)
|
|
160
|
+
return undefined;
|
|
161
|
+
return (await readBody(res));
|
|
162
|
+
}
|
|
163
|
+
const retryable = res.status === 429 || (GATEWAY_STATUS.has(res.status) && replayable);
|
|
164
|
+
if (retryable && attempt < this.maxRetries) {
|
|
165
|
+
await readBody(res); // drain so keep-alive sockets stay reusable
|
|
166
|
+
await sleep(computeDelayMs(attempt, res.headers.get('retry-after')));
|
|
167
|
+
attempt += 1;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const parsedBody = await readBody(res);
|
|
171
|
+
throw new OneBooksApiError(res.status, extractMessage(parsedBody, res), {
|
|
172
|
+
code: extractCode(parsedBody),
|
|
173
|
+
body: parsedBody,
|
|
174
|
+
retryAfter: retryAfterSeconds(res),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
get(path, options) {
|
|
179
|
+
return this.request('GET', path, options);
|
|
180
|
+
}
|
|
181
|
+
post(path, body, options) {
|
|
182
|
+
return this.request('POST', path, { ...options, body });
|
|
183
|
+
}
|
|
184
|
+
put(path, body, options) {
|
|
185
|
+
return this.request('PUT', path, { ...options, body });
|
|
186
|
+
}
|
|
187
|
+
patch(path, body, options) {
|
|
188
|
+
return this.request('PATCH', path, { ...options, body });
|
|
189
|
+
}
|
|
190
|
+
delete(path, options) {
|
|
191
|
+
return this.request('DELETE', path, options);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Async-iterates every item of a `{ data, hasMore, nextCursor }` endpoint,
|
|
195
|
+
* paging automatically. `cursorParam` names the query parameter the
|
|
196
|
+
* endpoint reads the cursor from (default `"cursor"`; the events endpoint
|
|
197
|
+
* uses `"after"` — see `events.iterate()`, built on this).
|
|
198
|
+
*/
|
|
199
|
+
async *paginate(path, query = {}, paginateOptions = {}) {
|
|
200
|
+
const cursorParam = paginateOptions.cursorParam ?? 'cursor';
|
|
201
|
+
let cursor = query[cursorParam];
|
|
202
|
+
for (;;) {
|
|
203
|
+
const page = await this.get(path, {
|
|
204
|
+
query: { ...query, [cursorParam]: cursor },
|
|
205
|
+
});
|
|
206
|
+
for (const item of page.data)
|
|
207
|
+
yield item;
|
|
208
|
+
if (!page.hasMore || !page.nextCursor)
|
|
209
|
+
return;
|
|
210
|
+
cursor = page.nextCursor;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAS7C,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AACvD,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,6EAA6E;AAC7E,4EAA4E;AAC5E,4DAA4D;AAC5D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAChD,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,MAAM,cAAc,GAAG,KAAK,CAAC;AAE7B;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAkB,EAAE,cAAkC;IACnG,OAAO,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,cAAc,CAAC;AACnE,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;+DAC+D;AAC/D,SAAS,cAAc,CAAC,OAAe,EAAE,gBAA+B;IACtE,MAAM,YAAY,GAAG,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;IACzD,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,eAAe,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;IAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAa;IACnC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,IAAa,EAAE,GAAa;IAClD,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QAC1D,MAAM,CAAC,GAAI,IAA6B,CAAC,OAAO,CAAC;QACjD,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC,UAAU,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,WAAW,CAAC,IAAa;IAChC,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACvD,MAAM,CAAC,GAAI,IAA0B,CAAC,IAAI,CAAC;QAC3C,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAChB,OAAO,CAAS;IAChB,UAAU,CAAU;IACpB,OAAO,CAAkB;IACzB,MAAM,CAAiB;IAEf,UAAU,CAAS;IACnB,SAAS,CAAe;IACxB,WAAW,CAAU;IACrB,gBAAgB,CAAkC;IAEnE,YAAY,OAA8B;QACxC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;QAExC,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC9B,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1D,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAEO,QAAQ,CAAC,IAAY,EAAE,KAAmB;QAChD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;oBAAE,SAAS;gBACpD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;wBAAE,SAAS;oBACjC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC7C,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CACX,MAAkB,EAClB,IAAY,EACZ,UAA0B,EAAE;QAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,8BAA8B,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QAClF,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,SAAS,CAAC;YACR,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,MAAM,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;YAC1E,IAAI,IAAI,CAAC,UAAU;gBAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACtE,IAAI,OAAO,CAAC,cAAc;gBAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;YAEnF,IAAI,IAAwB,CAAC;YAC7B,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;gBAChD,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;YAED,IAAI,GAAa,CAAC;YAClB,IAAI,CAAC;gBACH,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YACrF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,UAAU,IAAI,OAAO,IAAI,IAAI,CAAC,UAAU;oBAAE,MAAM,GAAG,CAAC;gBACpF,MAAM,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3C,OAAO,IAAI,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YAED,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;oBAAE,OAAO,SAAc,CAAC;gBAC9C,OAAO,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAM,CAAC;YACpC,CAAC;YAED,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC;YACvF,IAAI,SAAS,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC3C,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,4CAA4C;gBACjE,MAAM,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;gBACrE,OAAO,IAAI,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACvC,MAAM,IAAI,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE;gBACtE,IAAI,EAAE,WAAW,CAAC,UAAU,CAAC;gBAC7B,IAAI,EAAE,UAAU;gBAChB,UAAU,EAAE,iBAAiB,CAAC,GAAG,CAAC;aACnC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,GAAG,CAAc,IAAY,EAAE,OAAsC;QACnE,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,CAAc,IAAY,EAAE,IAAc,EAAE,OAAsC;QACpF,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,GAAG,CAAc,IAAY,EAAE,IAAc,EAAE,OAAsC;QACnF,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAc,IAAY,EAAE,IAAc,EAAE,OAAsC;QACrF,OAAO,IAAI,CAAC,OAAO,CAAI,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,CAAc,IAAY,EAAE,OAAsC;QACtE,OAAO,IAAI,CAAC,OAAO,CAAI,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,CAAC,QAAQ,CACb,IAAY,EACZ,QAAqB,EAAE,EACvB,kBAA4C,EAAE;QAE9C,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,IAAI,QAAQ,CAAC;QAC5D,IAAI,MAAM,GAAG,KAAK,CAAC,WAAW,CAAuB,CAAC;QACtD,SAAS,CAAC;YACR,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAuB,IAAI,EAAE;gBACtD,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE;aAC3C,CAAC,CAAC;YACH,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU;gBAAE,OAAO;YAC9C,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC3B,CAAC;IACH,CAAC;CACF"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `error` codes the standard OAuth endpoints (`/oauth/token`,
|
|
3
|
+
* `/oauth/revoke`, `/oauth/introspect`, `/oauth/device/authorize`,
|
|
4
|
+
* `/oauth/register`) answer with — RFC 6749 §5.2, RFC 7009, RFC 7662,
|
|
5
|
+
* RFC 8628 §3.5, RFC 7591 §3.2.2 and RFC 8707 — plus `temporarily_unavailable`
|
|
6
|
+
* (rate limited) and `server_error`. An open union: a code added later still
|
|
7
|
+
* comes through as a plain string.
|
|
8
|
+
*/
|
|
9
|
+
export type OAuthErrorCode = 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | 'unsupported_grant_type' | 'invalid_scope' | 'invalid_target' | 'unsupported_token_type' | 'authorization_pending' | 'slow_down' | 'expired_token' | 'access_denied' | 'invalid_redirect_uri' | 'invalid_client_metadata' | 'temporarily_unavailable' | 'server_error' | (string & {});
|
|
10
|
+
export interface OneBooksApiErrorInit {
|
|
11
|
+
code?: string;
|
|
12
|
+
body?: unknown;
|
|
13
|
+
oauthError?: OAuthErrorCode;
|
|
14
|
+
oauthErrorDescription?: string;
|
|
15
|
+
retryAfter?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Thrown by every SDK call that receives a non-2xx response the client isn't
|
|
19
|
+
* retrying (see client.ts's retry policy).
|
|
20
|
+
*
|
|
21
|
+
* - `code` is the API's stable machine-readable error code when present (see
|
|
22
|
+
* the `errors` doc) — branch on it instead of matching `message` text. The
|
|
23
|
+
* standard OAuth endpoints never carry one.
|
|
24
|
+
* - `oauthError` is set instead on errors from the OAuth helpers: the RFC 6749
|
|
25
|
+
* §5.2 `error` code (e.g. `invalid_grant`), with `oauthErrorDescription` the
|
|
26
|
+
* optional `error_description`. `message` there reads
|
|
27
|
+
* `"<error>: <error_description>"` (just `"<error>"` without a description).
|
|
28
|
+
* - `retryAfter` is the response's `Retry-After`, in seconds, when it sent one
|
|
29
|
+
* (every `429` from the API does).
|
|
30
|
+
*/
|
|
31
|
+
export declare class OneBooksApiError extends Error {
|
|
32
|
+
readonly status: number;
|
|
33
|
+
readonly code?: string;
|
|
34
|
+
readonly body: unknown;
|
|
35
|
+
readonly oauthError?: OAuthErrorCode;
|
|
36
|
+
readonly oauthErrorDescription?: string;
|
|
37
|
+
readonly retryAfter?: number;
|
|
38
|
+
constructor(status: number, message: string, init?: OneBooksApiErrorInit);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* `Retry-After` (delta-seconds, or an HTTP date) as milliseconds from `now`;
|
|
42
|
+
* `undefined` when the header is absent or unparseable.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseRetryAfterMs(header: string | null, now?: number): number | undefined;
|
|
45
|
+
/** `Retry-After` in whole seconds (an HTTP date rounded up), for `OneBooksApiError.retryAfter`. */
|
|
46
|
+
export declare function retryAfterSeconds(res: Response): number | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* The error for a failed response from a standard OAuth endpoint.
|
|
49
|
+
*
|
|
50
|
+
* Reads the RFC 6749 §5.2 body — `{ "error": "<code>", "error_description"?: "<text>" }`.
|
|
51
|
+
* Against a server that predates it, falls back to the OneBooks-shaped body
|
|
52
|
+
* those endpoints used to send (`{ statusCode, message, error }`, where
|
|
53
|
+
* `message` carried the code and `error` is only the HTTP reason phrase), so
|
|
54
|
+
* `oauthError` is filled either way. Never parses prose: a legacy `message`
|
|
55
|
+
* that doesn't start with a known OAuth code leaves `oauthError` unset.
|
|
56
|
+
*/
|
|
57
|
+
export declare function oauthErrorFromResponse(res: Response, body: unknown): OneBooksApiError;
|
|
58
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,gBAAgB,GAChB,eAAe,GACf,qBAAqB,GACrB,wBAAwB,GACxB,eAAe,GACf,gBAAgB,GAChB,wBAAwB,GACxB,uBAAuB,GACvB,WAAW,GACX,eAAe,GACf,eAAe,GACf,sBAAsB,GACtB,yBAAyB,GACzB,yBAAyB,GACzB,cAAc,GACd,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAEjB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,oBAAyB;CAW7E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,GAAG,SAAS,CAOrG;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAGnE;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,gBAAgB,CA2BrF"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by every SDK call that receives a non-2xx response the client isn't
|
|
3
|
+
* retrying (see client.ts's retry policy).
|
|
4
|
+
*
|
|
5
|
+
* - `code` is the API's stable machine-readable error code when present (see
|
|
6
|
+
* the `errors` doc) — branch on it instead of matching `message` text. The
|
|
7
|
+
* standard OAuth endpoints never carry one.
|
|
8
|
+
* - `oauthError` is set instead on errors from the OAuth helpers: the RFC 6749
|
|
9
|
+
* §5.2 `error` code (e.g. `invalid_grant`), with `oauthErrorDescription` the
|
|
10
|
+
* optional `error_description`. `message` there reads
|
|
11
|
+
* `"<error>: <error_description>"` (just `"<error>"` without a description).
|
|
12
|
+
* - `retryAfter` is the response's `Retry-After`, in seconds, when it sent one
|
|
13
|
+
* (every `429` from the API does).
|
|
14
|
+
*/
|
|
15
|
+
export class OneBooksApiError extends Error {
|
|
16
|
+
status;
|
|
17
|
+
code;
|
|
18
|
+
body;
|
|
19
|
+
oauthError;
|
|
20
|
+
oauthErrorDescription;
|
|
21
|
+
retryAfter;
|
|
22
|
+
constructor(status, message, init = {}) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'OneBooksApiError';
|
|
25
|
+
this.status = status;
|
|
26
|
+
this.code = init.code;
|
|
27
|
+
this.body = init.body;
|
|
28
|
+
this.oauthError = init.oauthError;
|
|
29
|
+
this.oauthErrorDescription = init.oauthErrorDescription;
|
|
30
|
+
this.retryAfter = init.retryAfter;
|
|
31
|
+
Object.setPrototypeOf(this, OneBooksApiError.prototype);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `Retry-After` (delta-seconds, or an HTTP date) as milliseconds from `now`;
|
|
36
|
+
* `undefined` when the header is absent or unparseable.
|
|
37
|
+
*/
|
|
38
|
+
export function parseRetryAfterMs(header, now = Date.now()) {
|
|
39
|
+
if (!header)
|
|
40
|
+
return undefined;
|
|
41
|
+
const asSeconds = Number(header);
|
|
42
|
+
if (Number.isFinite(asSeconds) && asSeconds >= 0)
|
|
43
|
+
return asSeconds * 1000;
|
|
44
|
+
const asDate = Date.parse(header);
|
|
45
|
+
if (!Number.isNaN(asDate))
|
|
46
|
+
return Math.max(0, asDate - now);
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/** `Retry-After` in whole seconds (an HTTP date rounded up), for `OneBooksApiError.retryAfter`. */
|
|
50
|
+
export function retryAfterSeconds(res) {
|
|
51
|
+
const ms = parseRetryAfterMs(res.headers.get('retry-after'));
|
|
52
|
+
return ms === undefined ? undefined : Math.ceil(ms / 1000);
|
|
53
|
+
}
|
|
54
|
+
// The codes a server that predates the RFC-shaped OAuth errors put in
|
|
55
|
+
// `message` — bare, or as "<code>: <detail>" (e.g. "invalid_grant: expired").
|
|
56
|
+
const LEGACY_OAUTH_CODES = new Set([
|
|
57
|
+
'invalid_request',
|
|
58
|
+
'invalid_client',
|
|
59
|
+
'invalid_grant',
|
|
60
|
+
'unauthorized_client',
|
|
61
|
+
'unsupported_grant_type',
|
|
62
|
+
'invalid_scope',
|
|
63
|
+
'invalid_target',
|
|
64
|
+
'unsupported_token_type',
|
|
65
|
+
'authorization_pending',
|
|
66
|
+
'slow_down',
|
|
67
|
+
'expired_token',
|
|
68
|
+
'access_denied',
|
|
69
|
+
'invalid_redirect_uri',
|
|
70
|
+
'invalid_client_metadata',
|
|
71
|
+
]);
|
|
72
|
+
const LEGACY_OAUTH_MESSAGE = /^([a-z_]+)(?::\s*([\s\S]+))?$/;
|
|
73
|
+
function nonEmptyString(value) {
|
|
74
|
+
return typeof value === 'string' && value !== '' ? value : undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The error for a failed response from a standard OAuth endpoint.
|
|
78
|
+
*
|
|
79
|
+
* Reads the RFC 6749 §5.2 body — `{ "error": "<code>", "error_description"?: "<text>" }`.
|
|
80
|
+
* Against a server that predates it, falls back to the OneBooks-shaped body
|
|
81
|
+
* those endpoints used to send (`{ statusCode, message, error }`, where
|
|
82
|
+
* `message` carried the code and `error` is only the HTTP reason phrase), so
|
|
83
|
+
* `oauthError` is filled either way. Never parses prose: a legacy `message`
|
|
84
|
+
* that doesn't start with a known OAuth code leaves `oauthError` unset.
|
|
85
|
+
*/
|
|
86
|
+
export function oauthErrorFromResponse(res, body) {
|
|
87
|
+
const retryAfter = retryAfterSeconds(res);
|
|
88
|
+
if (body && typeof body === 'object') {
|
|
89
|
+
const fields = body;
|
|
90
|
+
const rfcError = 'statusCode' in fields ? undefined : nonEmptyString(fields.error);
|
|
91
|
+
if (rfcError) {
|
|
92
|
+
const description = nonEmptyString(fields.error_description);
|
|
93
|
+
return new OneBooksApiError(res.status, description ? `${rfcError}: ${description}` : rfcError, {
|
|
94
|
+
body,
|
|
95
|
+
oauthError: rfcError,
|
|
96
|
+
oauthErrorDescription: description,
|
|
97
|
+
retryAfter,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const legacyMessage = nonEmptyString(fields.message);
|
|
101
|
+
if (legacyMessage) {
|
|
102
|
+
const match = LEGACY_OAUTH_MESSAGE.exec(legacyMessage);
|
|
103
|
+
const legacyCode = match && LEGACY_OAUTH_CODES.has(match[1]) ? match[1] : undefined;
|
|
104
|
+
return new OneBooksApiError(res.status, legacyMessage, {
|
|
105
|
+
body,
|
|
106
|
+
oauthError: legacyCode,
|
|
107
|
+
oauthErrorDescription: legacyCode ? match?.[2] : undefined,
|
|
108
|
+
retryAfter,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return new OneBooksApiError(res.status, res.statusText || `HTTP ${res.status}`, { body, retryAfter });
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PaginatedResponse, QueryParams } from './types.js';
|
|
2
|
+
interface RequestClient {
|
|
3
|
+
get<T>(path: string, options?: {
|
|
4
|
+
query?: QueryParams;
|
|
5
|
+
}): Promise<T>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The event envelope from Contract 6's `/events` endpoints
|
|
9
|
+
* (`EventListItemDto` in `app-platform/events/events-query.service.ts`).
|
|
10
|
+
* `resourceType`/`resourceId` are null for app-targeted events that aren't
|
|
11
|
+
* about one ledger resource (`app.installed`, `business.redact`, …) — see
|
|
12
|
+
* the event catalog's `audience: 'app' | 'privacy'` entries.
|
|
13
|
+
*/
|
|
14
|
+
export interface OneBooksEventEnvelope<T = unknown> {
|
|
15
|
+
id: string;
|
|
16
|
+
type: string;
|
|
17
|
+
apiVersion: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
resourceType: string | null;
|
|
20
|
+
resourceId: string | null;
|
|
21
|
+
data: T;
|
|
22
|
+
}
|
|
23
|
+
export interface EventsListParams {
|
|
24
|
+
/** Event id cursor — resume after this event. */
|
|
25
|
+
after?: string;
|
|
26
|
+
/** ISO 8601 — only events created at or after this instant. */
|
|
27
|
+
since?: string;
|
|
28
|
+
/** Event type filter, e.g. `['invoice.paid', 'payment.received']`. */
|
|
29
|
+
types?: string[];
|
|
30
|
+
/** 1–100, default 50 server-side. */
|
|
31
|
+
limit?: number;
|
|
32
|
+
}
|
|
33
|
+
/** Partner events API (Contract 6): `client.events.*`. */
|
|
34
|
+
export declare class EventsResource {
|
|
35
|
+
private readonly client;
|
|
36
|
+
constructor(client: RequestClient);
|
|
37
|
+
/** `GET /events?after=&since=&types=&limit=`. */
|
|
38
|
+
list(params?: EventsListParams): Promise<PaginatedResponse<OneBooksEventEnvelope>>;
|
|
39
|
+
/** `GET /events/:id`. */
|
|
40
|
+
get(id: string): Promise<OneBooksEventEnvelope>;
|
|
41
|
+
/**
|
|
42
|
+
* Async-iterates every event from `params.after` (or the beginning)
|
|
43
|
+
* onward, paging automatically via `nextCursor`. Safe to persist the last
|
|
44
|
+
* consumed event's `id` and resume with `{ after: lastId }` later.
|
|
45
|
+
*/
|
|
46
|
+
iterate(params?: EventsListParams): AsyncGenerator<OneBooksEventEnvelope, void, undefined>;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAIjE,UAAU,aAAa;IACrB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACrE;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC,GAAG,OAAO;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0DAA0D;AAC1D,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAElD,iDAAiD;IACjD,IAAI,CAAC,MAAM,GAAE,gBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAAC;IAWtF,yBAAyB;IACzB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAI/C;;;;OAIG;IACI,OAAO,CAAC,MAAM,GAAE,gBAAqB,GAAG,cAAc,CAAC,qBAAqB,EAAE,IAAI,EAAE,SAAS,CAAC;CAStG"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Partner events API (Contract 6): `client.events.*`. */
|
|
2
|
+
export class EventsResource {
|
|
3
|
+
client;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
/** `GET /events?after=&since=&types=&limit=`. */
|
|
8
|
+
list(params = {}) {
|
|
9
|
+
return this.client.get('/events', {
|
|
10
|
+
query: {
|
|
11
|
+
after: params.after,
|
|
12
|
+
since: params.since,
|
|
13
|
+
types: params.types,
|
|
14
|
+
limit: params.limit,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** `GET /events/:id`. */
|
|
19
|
+
get(id) {
|
|
20
|
+
return this.client.get(`/events/${encodeURIComponent(id)}`);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Async-iterates every event from `params.after` (or the beginning)
|
|
24
|
+
* onward, paging automatically via `nextCursor`. Safe to persist the last
|
|
25
|
+
* consumed event's `id` and resume with `{ after: lastId }` later.
|
|
26
|
+
*/
|
|
27
|
+
async *iterate(params = {}) {
|
|
28
|
+
let after = params.after;
|
|
29
|
+
for (;;) {
|
|
30
|
+
const page = await this.list({ ...params, after });
|
|
31
|
+
for (const event of page.data)
|
|
32
|
+
yield event;
|
|
33
|
+
if (!page.hasMore || !page.nextCursor)
|
|
34
|
+
return;
|
|
35
|
+
after = page.nextCursor;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAoCA,0DAA0D;AAC1D,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,iDAAiD;IACjD,IAAI,CAAC,SAA2B,EAAE;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAA2C,SAAS,EAAE;YAC1E,KAAK,EAAE;gBACL,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB;SACF,CAAC,CAAC;IACL,CAAC;IAED,yBAAyB;IACzB,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAwB,WAAW,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,CAAC,OAAO,CAAC,SAA2B,EAAE;QAC1C,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACzB,SAAS,CAAC;YACR,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACnD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI;gBAAE,MAAM,KAAK,CAAC;YAC3C,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU;gBAAE,OAAO;YAC9C,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;QAC1B,CAAC;IACH,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { OneBooksClient } from './client.js';
|
|
2
|
+
export { OneBooksApiError } from './errors.js';
|
|
3
|
+
export type { OAuthErrorCode, OneBooksApiErrorInit } from './errors.js';
|
|
4
|
+
export type { HttpMethod, OneBooksClientOptions, PaginatedResponse, QueryParams, QueryValue, RequestOptions, } from './types.js';
|
|
5
|
+
export { AppDataResource } from './app-data.js';
|
|
6
|
+
export type { AppDataDefinition, AppDataFieldType, AppDataGetParams, AppDataSetInput, AppDataValue, LocalizedText, } from './app-data.js';
|
|
7
|
+
export { EventsResource } from './events.js';
|
|
8
|
+
export type { EventsListParams, OneBooksEventEnvelope } from './events.js';
|
|
9
|
+
export { verifySessionToken } from './session-token.js';
|
|
10
|
+
export type { SessionTokenClaims, VerifySessionTokenOptions } from './session-token.js';
|
|
11
|
+
export { verifyWebhook, parseWebhookEvent } from './webhook.js';
|
|
12
|
+
export type { VerifyWebhookOptions, WebhookEventEnvelope } from './webhook.js';
|
|
13
|
+
export * as oauth from './oauth.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EACV,UAAU,EACV,qBAAqB,EACrB,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAK/E,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { OneBooksClient } from './client.js';
|
|
2
|
+
export { OneBooksApiError } from './errors.js';
|
|
3
|
+
export { AppDataResource } from './app-data.js';
|
|
4
|
+
export { EventsResource } from './events.js';
|
|
5
|
+
export { verifySessionToken } from './session-token.js';
|
|
6
|
+
export { verifyWebhook, parseWebhookEvent } from './webhook.js';
|
|
7
|
+
// Standalone OAuth helpers (used before a client/token exists), grouped
|
|
8
|
+
// under a namespace so `oauth.exchangeCode(...)` reads like a client method
|
|
9
|
+
// without requiring a OneBooksClient instance to call them.
|
|
10
|
+
export * as oauth from './oauth.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAW/C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAUhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGhE,wEAAwE;AACxE,4EAA4E;AAC5E,4DAA4D;AAC5D,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC"}
|
package/dist/oauth.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface PkcePair {
|
|
2
|
+
codeVerifier: string;
|
|
3
|
+
codeChallenge: string;
|
|
4
|
+
codeChallengeMethod: 'S256';
|
|
5
|
+
}
|
|
6
|
+
/** RFC 7636 PKCE pair: a 43-character verifier and its S256 challenge. */
|
|
7
|
+
export declare function createPkcePair(): Promise<PkcePair>;
|
|
8
|
+
export interface BuildAuthorizeUrlOptions {
|
|
9
|
+
clientId: string;
|
|
10
|
+
redirectUri: string;
|
|
11
|
+
scopes: string[];
|
|
12
|
+
state: string;
|
|
13
|
+
codeChallenge: string;
|
|
14
|
+
codeChallengeMethod?: 'S256';
|
|
15
|
+
/** Default `https://app.getonebooks.com/oauth/authorize` — the authorize endpoint lives on the APP host, not the API host. */
|
|
16
|
+
authorizeUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Builds the `https://app.getonebooks.com/oauth/authorize` URL (Step 1 of the code + PKCE flow). */
|
|
19
|
+
export declare function buildAuthorizeUrl(options: BuildAuthorizeUrlOptions): string;
|
|
20
|
+
export interface TokenResponse {
|
|
21
|
+
access_token: string;
|
|
22
|
+
refresh_token?: string;
|
|
23
|
+
token_type: 'Bearer';
|
|
24
|
+
expires_in: number;
|
|
25
|
+
scope?: string;
|
|
26
|
+
issued_token_type?: string;
|
|
27
|
+
}
|
|
28
|
+
interface ClientAuth {
|
|
29
|
+
clientId: string;
|
|
30
|
+
/** Omit for a PUBLIC client — PKCE takes the place of a secret. */
|
|
31
|
+
clientSecret?: string;
|
|
32
|
+
}
|
|
33
|
+
interface OAuthCallOptions extends ClientAuth {
|
|
34
|
+
apiBase?: string;
|
|
35
|
+
fetch?: typeof fetch;
|
|
36
|
+
}
|
|
37
|
+
export interface ExchangeCodeOptions extends OAuthCallOptions {
|
|
38
|
+
code: string;
|
|
39
|
+
redirectUri: string;
|
|
40
|
+
/** Required for a PUBLIC (PKCE) client; omit for a CONFIDENTIAL client that skipped PKCE. */
|
|
41
|
+
codeVerifier?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Step 3: exchange an authorization code for tokens (`POST /oauth/token`). */
|
|
44
|
+
export declare function exchangeCode(options: ExchangeCodeOptions): Promise<TokenResponse>;
|
|
45
|
+
export interface RefreshOptions extends OAuthCallOptions {
|
|
46
|
+
refreshToken: string;
|
|
47
|
+
}
|
|
48
|
+
/** Refreshes an access token. Rotation is strict: persist BOTH new tokens before discarding the old ones. */
|
|
49
|
+
export declare function refresh(options: RefreshOptions): Promise<TokenResponse>;
|
|
50
|
+
export interface RevokeOptions extends OAuthCallOptions {
|
|
51
|
+
token: string;
|
|
52
|
+
tokenTypeHint?: 'access_token' | 'refresh_token';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `POST /oauth/revoke` (RFC 7009) — resolves for an unknown or already-invalid
|
|
56
|
+
* token too; rejects only when the request itself fails (`invalid_client`, a
|
|
57
|
+
* rate limit, …).
|
|
58
|
+
*/
|
|
59
|
+
export declare function revoke(options: RevokeOptions): Promise<void>;
|
|
60
|
+
export interface ExchangeSessionTokenOptions {
|
|
61
|
+
clientId: string;
|
|
62
|
+
/** Required — session-token exchange is confidential-client only (Contract 3). */
|
|
63
|
+
clientSecret: string;
|
|
64
|
+
sessionToken: string;
|
|
65
|
+
apiBase?: string;
|
|
66
|
+
fetch?: typeof fetch;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* RFC 8693 token exchange (Contract 3): trades an App Bridge session token
|
|
70
|
+
* (short-lived, ~60s) for a normal access/refresh token pair scoped to the
|
|
71
|
+
* installation. Confidential clients only.
|
|
72
|
+
*/
|
|
73
|
+
export declare function exchangeSessionToken(options: ExchangeSessionTokenOptions): Promise<TokenResponse>;
|
|
74
|
+
export interface IntrospectOptions extends OAuthCallOptions {
|
|
75
|
+
token: string;
|
|
76
|
+
}
|
|
77
|
+
export interface IntrospectionResult {
|
|
78
|
+
active: boolean;
|
|
79
|
+
scope?: string;
|
|
80
|
+
exp?: number;
|
|
81
|
+
client_id?: string;
|
|
82
|
+
sub?: string;
|
|
83
|
+
}
|
|
84
|
+
/** `POST /oauth/introspect` — a debugging aid, not a production hot path (just call the API and handle 401). */
|
|
85
|
+
export declare function introspect(options: IntrospectOptions): Promise<IntrospectionResult>;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|