@andesine/sdk 0.6.0 → 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/CHANGELOG.md +106 -0
- package/README.md +11 -3
- package/WEBHOOKS.md +7 -0
- package/dist/{client-DioqVOxl.js → client-CyhWWH37.js} +138 -18
- package/dist/client-CyhWWH37.js.map +1 -0
- package/dist/{client-C8wt7f3o.d.ts → client-QR7crUNC.d.ts} +137 -22
- package/dist/extensions.d.ts +8 -3
- package/dist/extensions.js +6 -3
- package/dist/extensions.js.map +1 -1
- package/dist/{index-B5qefVRv.d.ts → index-DcU5xEPe.d.ts} +38 -8
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/{schema-CrquN_J6.d.ts → schema-CMpGUItd.d.ts} +5540 -952
- package/dist/streaming.d.ts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/dist/webhooks.js +1861 -959
- package/dist/webhooks.js.map +1 -1
- package/openapi.json +10376 -2318
- package/package.json +1 -1
- package/dist/client-DioqVOxl.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,111 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
- `collections.get` returns one collection by `collectionID`, `collectionPath`, or
|
|
6
|
+
`collectionSlugPath`, with its name, path, and ancestors (`read:collections`).
|
|
7
|
+
- `extensions.listElements` lists the custom elements of the workspace's active extensions (e.g.
|
|
8
|
+
Tabs): their props, whether they have content, the blocks their content accepts, and the
|
|
9
|
+
elements that belong inside them (`read:entries`).
|
|
10
|
+
- `extensions.getSelf` and `extensions.verifySession` return `workspacePlan`, the workspace's
|
|
11
|
+
effective plan (`pro` on instances without billing), so extensions can offer plan features.
|
|
12
|
+
- Extension-managed publishable keys: `extensions.listSelfPublishableKeys`,
|
|
13
|
+
`createSelfPublishableKey`, `updateSelfPublishableKey`, and `deleteSelfPublishableKey`, for
|
|
14
|
+
extensions with the `publishable-keys` permission. The keys read published content of their
|
|
15
|
+
collections (and ask for AI answers with `answers` and the extension's `ai-answers` permission),
|
|
16
|
+
in their origins. Members can only delete them. They stop while the extension is disabled or
|
|
17
|
+
revoked; losing `publishable-keys` or `read:publishing`, or uninstalling, deletes them, and
|
|
18
|
+
losing `ai-answers` removes it.
|
|
19
|
+
- Keys have `extensionID`: the extension that manages the key, or `null`.
|
|
20
|
+
- `extensions.verifySession` takes optional `checks` (`{ collectionID, actions }`, up to 10) and
|
|
21
|
+
returns `checks` with `allowed` and the `denied` actions. An action is allowed when the
|
|
22
|
+
member can take it and the extension can read the collection, restricted collections included.
|
|
23
|
+
- `createExtensionBackend().verifySession(headers, { checks })` passes the checks; the results
|
|
24
|
+
are in `session.checks`.
|
|
25
|
+
|
|
26
|
+
## 0.7.0
|
|
27
|
+
|
|
28
|
+
- `auth.getIdentity` returns `client` (ID and registered name) for OAuth access tokens.
|
|
29
|
+
- Webhook events have an `actor`: the member, API key, extension, or app (OAuth client ID and
|
|
30
|
+
registered name, with the member) that made the change, or `null` for changes by Andesine.
|
|
31
|
+
- OAuth for MCP clients: the authorization server supports the authorization code flow with
|
|
32
|
+
PKCE and dynamic client registration, with the scopes `andesine:read` and `andesine:write`.
|
|
33
|
+
`auth.getIdentity` returns `scopes` and `workspaceID` for such tokens.
|
|
34
|
+
- `auth.getIdentity` returns the `permissions` of an API key, and `instance.get` returns
|
|
35
|
+
`appURL`, the web app URL (entries open at `{appURL}/{workspaceID}/{entryID}`).
|
|
36
|
+
- `versions.create` takes an optional `document`: ProseMirror JSON checked against the editor
|
|
37
|
+
and the entry's collection schema. The version has the new reason `import`, and the
|
|
38
|
+
current content does not change.
|
|
39
|
+
- `entries.get` returns `hash`, the hash of the current content, comparable to version hashes.
|
|
40
|
+
- Add `entries.move` and `collections.move` (API key permissions `entries` and
|
|
41
|
+
`collections`). Without `order`, a moved entry keeps its position in the same collection
|
|
42
|
+
and goes last in a new one.
|
|
43
|
+
- `entries.update` replaces the content with `document` and `expectedHash`, the hash of the
|
|
44
|
+
content it replaces. Only the changed blocks change, so live edits elsewhere are kept. A
|
|
45
|
+
different current hash returns the new error `CONTENT_HASH_MISMATCH` (409) with the current
|
|
46
|
+
`hash`. Current content without a version is first saved as an `auto` version, and `version`
|
|
47
|
+
also saves the new content as a `manual` version. Use `name` or `document`, not both. The
|
|
48
|
+
result is `{ hash, version }`; before, it was empty.
|
|
49
|
+
- `entries.create` takes an optional `document` in place of `name`; its title sets the name.
|
|
50
|
+
- MDX content: `entries.get`, `versions.get`, and `content.get` take `contentFormat: "mdx"`
|
|
51
|
+
and then also return the content as MDX in `mdx`: the title as H1, properties as
|
|
52
|
+
`<Property name value />` elements in their position, fragments as `<Fragment name>`
|
|
53
|
+
elements, and images as `asset:<assetID>` references (delivery URLs in published content).
|
|
54
|
+
`entries.create`, `entries.update`, and `versions.create` take `mdx` in place of `document`;
|
|
55
|
+
frontmatter properties are also read. Fields match by name or key. Node IDs and attributes
|
|
56
|
+
that MDX doesn't hold are kept from the current content. Invalid MDX returns the new error
|
|
57
|
+
`CONTENT_FORMAT_INVALID` (400) with the line and column.
|
|
58
|
+
- `Fragment` and `Property` are reserved element names; content writes with them return
|
|
59
|
+
`CONTENT_SCHEMA_INVALID`.
|
|
60
|
+
- `entries.update` takes `operations`, applied in order with all or none applied:
|
|
61
|
+
`replaceText` (`find` must occur once in one block's MDX), `replaceBlock`, `insertBlocks`
|
|
62
|
+
(`before`, `after`, or `position` with an optional `fragment`), `deleteBlocks`, and `setField`
|
|
63
|
+
(a property value, or MDX for a fragment). Anchors come from `entries.get` with
|
|
64
|
+
`contentFormat: "blocks"`, which returns the blocks with IDs, fragment keys, and MDX.
|
|
65
|
+
`expectedHash` is optional with operations; `name` can be combined with them. A missing or
|
|
66
|
+
ambiguous anchor returns the new error `CONTENT_OPERATION_INVALID` (409) with the operation
|
|
67
|
+
`index` and `reason`.
|
|
68
|
+
- Internal links: link marks can point to entries with `entry:<entryID>`, and an optional
|
|
69
|
+
`#anchor`. Content writes also accept `entry:<path>` (a path or slug path) and store the entry
|
|
70
|
+
ID; a link to a missing entry returns the new error `CONTENT_LINK_INVALID` (409).
|
|
71
|
+
`entries.get` and `versions.get` return `references`: the path, slug path, title, and
|
|
72
|
+
collection of each linked entry, or `available: false` for deleted and unreadable entries.
|
|
73
|
+
MDX and blocks show links by slug path. Published content resolves links to the entry's slug
|
|
74
|
+
path in the snapshot, and removes links to entries that aren't published (the text stays).
|
|
75
|
+
- Images follow content: content writes attach the `asset:<assetID>` images they newly
|
|
76
|
+
reference (the caller must be able to read each image and update the entry), so
|
|
77
|
+
`assets.attach` is no longer part of the public API. `entries.update` and `versions.create`
|
|
78
|
+
also import image URLs in MDX and wait until the images are ready; an image that fails or is
|
|
79
|
+
still processing returns the new error `CONTENT_IMAGE_UNAVAILABLE` (409). `entries.create`
|
|
80
|
+
accepts only `asset:` images. To remove an image, remove it from the content.
|
|
81
|
+
- `entries.create` takes `path`: a full name path. Missing parent collections are created with
|
|
82
|
+
exact names; a name already used at the path returns `CONTENT_NAME_CONFLICT`.
|
|
83
|
+
- Target collections by path: `entries.create` and `entries.move` take `collectionPath` or
|
|
84
|
+
`collectionSlugPath` in place of `collectionID`, `collections.create` takes `parentPath` or
|
|
85
|
+
`parentSlugPath`, `collections.move` takes `newParentPath` or `newParentSlugPath` (`/` is the
|
|
86
|
+
top level), and `publishing.getChannelContent` takes `collectionPath` or `collectionSlugPath`.
|
|
87
|
+
These select existing collections only.
|
|
88
|
+
- Preconditions: `expectedName` on `entries.update` and `collections.update`,
|
|
89
|
+
`expectedCollectionID` on `entries.move`, and `expectedParentID` on `collections.move`. A
|
|
90
|
+
different current value returns the new error `CONTENT_PRECONDITION_FAILED` (409) with the
|
|
91
|
+
current value.
|
|
92
|
+
- `Idempotency-Key` header on `entries.create`, `entries.update`, and `versions.create`: a
|
|
93
|
+
repeated request returns the first result for 24 hours (with `Idempotent-Replayed: true`).
|
|
94
|
+
The same key with a different body returns `IDEMPOTENCY_KEY_REUSED` (422), and a repeat while
|
|
95
|
+
the first request runs returns `IDEMPOTENCY_KEY_IN_PROGRESS` (409). The SDK sends a generated
|
|
96
|
+
key for these operations unless `headers` has one, and `retries` now also applies to them, including a retry that
|
|
97
|
+
arrives while the first attempt still runs (`IDEMPOTENCY_KEY_IN_PROGRESS`, with
|
|
98
|
+
`Retry-After: 1`).
|
|
99
|
+
- Add `entries.bulkUpdate`: the items of `entries.update` for many entries in one call (a name
|
|
100
|
+
without content is written as the title). All items are checked before any content changes,
|
|
101
|
+
and all or none apply; errors name the failing item. Supports `Idempotency-Key`.
|
|
102
|
+
- Add `entries.bulkMove`: the items of `entries.move` in one call, all or none. Moves that need a
|
|
103
|
+
schema migration aren't supported; use `entries.move` for them.
|
|
104
|
+
- Add `publishing.updateChannel`: renames a channel; its code doesn't change.
|
|
105
|
+
- `entries.create` takes `fields`: property values and fragment MDX by field name or key.
|
|
106
|
+
- `entries.get` returns the content of a document that is open in the editor, including edits
|
|
107
|
+
that aren't saved yet, so its `hash` matches what content writes compare against.
|
|
108
|
+
|
|
3
109
|
## 0.6.0
|
|
4
110
|
|
|
5
111
|
- No changes; versioned with the other public Andesine packages.
|
package/README.md
CHANGED
|
@@ -176,9 +176,17 @@ request execution, response reading, and retry delays. Supply `signal` per call
|
|
|
176
176
|
for cancellation.
|
|
177
177
|
|
|
178
178
|
Retries are **disabled by default**. Set `retries: 2` on the client or a call to
|
|
179
|
-
allow up to two retries of GET requests.
|
|
180
|
-
and HTTP 429, 500, 502, 503, and 504. They respect
|
|
181
|
-
increasing delays with jitter.
|
|
179
|
+
allow up to two retries of GET requests and idempotent writes. They retry network
|
|
180
|
+
`TypeError` failures and HTTP 429, 500, 502, 503, and 504. They respect
|
|
181
|
+
`Retry-After`, otherwise use increasing delays with jitter. Other writes are never
|
|
182
|
+
retried automatically.
|
|
183
|
+
|
|
184
|
+
Idempotent writes (`entries.create`, `entries.update`, and `versions.create`) send
|
|
185
|
+
an `Idempotency-Key` header, generated for each call unless you supply one in
|
|
186
|
+
`headers`. The server applies a key once and returns the first result for 24 hours,
|
|
187
|
+
so retries can't apply a write twice. A retry that arrives while the first attempt
|
|
188
|
+
still runs gets `IDEMPOTENCY_KEY_IN_PROGRESS` and is retried after `Retry-After`. Supply your own key to make a write safe
|
|
189
|
+
across separate calls, for example after a process restart.
|
|
182
190
|
|
|
183
191
|
```ts
|
|
184
192
|
await client.entries.get(
|
package/WEBHOOKS.md
CHANGED
|
@@ -275,6 +275,13 @@ or restricted resources can become unavailable. Publication snapshot references
|
|
|
275
275
|
can expire under the workspace policy; webhooks do not pin snapshots. Handle
|
|
276
276
|
missing references explicitly.
|
|
277
277
|
|
|
278
|
+
Each event has an `actor`: who made the change. It is a member (`memberID`), an
|
|
279
|
+
API key (`keyID`), an extension (`extensionID`), or an app such as an MCP client
|
|
280
|
+
(`clientID`, the `name` that the app registered, and the authorizing `memberID`).
|
|
281
|
+
It is `null` for changes by Andesine itself, and for editor saves that combine
|
|
282
|
+
several people's edits. App names are chosen by the app; don't use them for
|
|
283
|
+
access decisions. An extension's own webhooks don't receive its changes.
|
|
284
|
+
|
|
278
285
|
## Rotation, replay, and recovery
|
|
279
286
|
|
|
280
287
|
Normal rotation returns a new secret once and signs with both old and new keys
|
|
@@ -124,16 +124,6 @@ const createResources = (request) => ({
|
|
|
124
124
|
binary: false,
|
|
125
125
|
anonymous: false
|
|
126
126
|
}),
|
|
127
|
-
attach: operation(request, {
|
|
128
|
-
method: "post",
|
|
129
|
-
path: "/assets/{assetID}/attachments",
|
|
130
|
-
pathParams: ["assetID"],
|
|
131
|
-
queryParams: [],
|
|
132
|
-
body: true,
|
|
133
|
-
multipart: false,
|
|
134
|
-
binary: false,
|
|
135
|
-
anonymous: false
|
|
136
|
-
}),
|
|
137
127
|
register: operation(request, {
|
|
138
128
|
method: "post",
|
|
139
129
|
path: "/assets/uploads",
|
|
@@ -187,6 +177,7 @@ const createResources = (request) => ({
|
|
|
187
177
|
}) },
|
|
188
178
|
entries: {
|
|
189
179
|
create: operation(request, {
|
|
180
|
+
idempotent: true,
|
|
190
181
|
method: "post",
|
|
191
182
|
path: "/entries",
|
|
192
183
|
pathParams: [],
|
|
@@ -217,6 +208,7 @@ const createResources = (request) => ({
|
|
|
217
208
|
anonymous: false
|
|
218
209
|
}),
|
|
219
210
|
update: operation(request, {
|
|
211
|
+
idempotent: true,
|
|
220
212
|
method: "put",
|
|
221
213
|
path: "/entries/{id}",
|
|
222
214
|
pathParams: ["id"],
|
|
@@ -226,6 +218,37 @@ const createResources = (request) => ({
|
|
|
226
218
|
binary: false,
|
|
227
219
|
anonymous: false
|
|
228
220
|
}),
|
|
221
|
+
bulkUpdate: operation(request, {
|
|
222
|
+
idempotent: true,
|
|
223
|
+
method: "post",
|
|
224
|
+
path: "/entries/bulk/update",
|
|
225
|
+
pathParams: [],
|
|
226
|
+
queryParams: [],
|
|
227
|
+
body: true,
|
|
228
|
+
multipart: false,
|
|
229
|
+
binary: false,
|
|
230
|
+
anonymous: false
|
|
231
|
+
}),
|
|
232
|
+
move: operation(request, {
|
|
233
|
+
method: "post",
|
|
234
|
+
path: "/entries/{id}/move",
|
|
235
|
+
pathParams: ["id"],
|
|
236
|
+
queryParams: [],
|
|
237
|
+
body: true,
|
|
238
|
+
multipart: false,
|
|
239
|
+
binary: false,
|
|
240
|
+
anonymous: false
|
|
241
|
+
}),
|
|
242
|
+
bulkMove: operation(request, {
|
|
243
|
+
method: "post",
|
|
244
|
+
path: "/entries/bulk/move",
|
|
245
|
+
pathParams: [],
|
|
246
|
+
queryParams: [],
|
|
247
|
+
body: true,
|
|
248
|
+
multipart: false,
|
|
249
|
+
binary: false,
|
|
250
|
+
anonymous: false
|
|
251
|
+
}),
|
|
229
252
|
get: operation(request, {
|
|
230
253
|
method: "get",
|
|
231
254
|
path: "/entries/get",
|
|
@@ -234,7 +257,8 @@ const createResources = (request) => ({
|
|
|
234
257
|
"id",
|
|
235
258
|
"path",
|
|
236
259
|
"slugPath",
|
|
237
|
-
"expectedSchemaHash"
|
|
260
|
+
"expectedSchemaHash",
|
|
261
|
+
"contentFormat"
|
|
238
262
|
],
|
|
239
263
|
body: false,
|
|
240
264
|
multipart: false,
|
|
@@ -309,6 +333,46 @@ const createResources = (request) => ({
|
|
|
309
333
|
binary: false,
|
|
310
334
|
anonymous: false
|
|
311
335
|
}),
|
|
336
|
+
listSelfPublishableKeys: operation(request, {
|
|
337
|
+
method: "get",
|
|
338
|
+
path: "/extensions/self/publishable-keys",
|
|
339
|
+
pathParams: [],
|
|
340
|
+
queryParams: [],
|
|
341
|
+
body: false,
|
|
342
|
+
multipart: false,
|
|
343
|
+
binary: false,
|
|
344
|
+
anonymous: false
|
|
345
|
+
}),
|
|
346
|
+
createSelfPublishableKey: operation(request, {
|
|
347
|
+
method: "post",
|
|
348
|
+
path: "/extensions/self/publishable-keys",
|
|
349
|
+
pathParams: [],
|
|
350
|
+
queryParams: [],
|
|
351
|
+
body: true,
|
|
352
|
+
multipart: false,
|
|
353
|
+
binary: false,
|
|
354
|
+
anonymous: false
|
|
355
|
+
}),
|
|
356
|
+
updateSelfPublishableKey: operation(request, {
|
|
357
|
+
method: "patch",
|
|
358
|
+
path: "/extensions/self/publishable-keys/{keyID}",
|
|
359
|
+
pathParams: ["keyID"],
|
|
360
|
+
queryParams: [],
|
|
361
|
+
body: true,
|
|
362
|
+
multipart: false,
|
|
363
|
+
binary: false,
|
|
364
|
+
anonymous: false
|
|
365
|
+
}),
|
|
366
|
+
deleteSelfPublishableKey: operation(request, {
|
|
367
|
+
method: "delete",
|
|
368
|
+
path: "/extensions/self/publishable-keys/{keyID}",
|
|
369
|
+
pathParams: ["keyID"],
|
|
370
|
+
queryParams: [],
|
|
371
|
+
body: false,
|
|
372
|
+
multipart: false,
|
|
373
|
+
binary: false,
|
|
374
|
+
anonymous: false
|
|
375
|
+
}),
|
|
312
376
|
getSelfStorageEntry: operation(request, {
|
|
313
377
|
method: "get",
|
|
314
378
|
path: "/extensions/self/storage/entry",
|
|
@@ -352,6 +416,16 @@ const createResources = (request) => ({
|
|
|
352
416
|
multipart: false,
|
|
353
417
|
binary: false,
|
|
354
418
|
anonymous: false
|
|
419
|
+
}),
|
|
420
|
+
listElements: operation(request, {
|
|
421
|
+
method: "get",
|
|
422
|
+
path: "/extensions/elements",
|
|
423
|
+
pathParams: [],
|
|
424
|
+
queryParams: [],
|
|
425
|
+
body: false,
|
|
426
|
+
multipart: false,
|
|
427
|
+
binary: false,
|
|
428
|
+
anonymous: false
|
|
355
429
|
})
|
|
356
430
|
},
|
|
357
431
|
collections: {
|
|
@@ -395,6 +469,30 @@ const createResources = (request) => ({
|
|
|
395
469
|
binary: false,
|
|
396
470
|
anonymous: false
|
|
397
471
|
}),
|
|
472
|
+
move: operation(request, {
|
|
473
|
+
method: "post",
|
|
474
|
+
path: "/collections/{id}/move",
|
|
475
|
+
pathParams: ["id"],
|
|
476
|
+
queryParams: [],
|
|
477
|
+
body: true,
|
|
478
|
+
multipart: false,
|
|
479
|
+
binary: false,
|
|
480
|
+
anonymous: false
|
|
481
|
+
}),
|
|
482
|
+
get: operation(request, {
|
|
483
|
+
method: "get",
|
|
484
|
+
path: "/collections/get",
|
|
485
|
+
pathParams: [],
|
|
486
|
+
queryParams: [
|
|
487
|
+
"collectionID",
|
|
488
|
+
"collectionPath",
|
|
489
|
+
"collectionSlugPath"
|
|
490
|
+
],
|
|
491
|
+
body: false,
|
|
492
|
+
multipart: false,
|
|
493
|
+
binary: false,
|
|
494
|
+
anonymous: false
|
|
495
|
+
}),
|
|
398
496
|
list: operation(request, {
|
|
399
497
|
method: "get",
|
|
400
498
|
path: "/collections/list",
|
|
@@ -494,7 +592,8 @@ const createResources = (request) => ({
|
|
|
494
592
|
"slugPath",
|
|
495
593
|
"expectedSchemaHash",
|
|
496
594
|
"channel",
|
|
497
|
-
"snapshotID"
|
|
595
|
+
"snapshotID",
|
|
596
|
+
"contentFormat"
|
|
498
597
|
],
|
|
499
598
|
body: false,
|
|
500
599
|
multipart: false,
|
|
@@ -1148,12 +1247,26 @@ const createResources = (request) => ({
|
|
|
1148
1247
|
method: "get",
|
|
1149
1248
|
path: "/publishing/channels/{channel}/content",
|
|
1150
1249
|
pathParams: ["channel"],
|
|
1151
|
-
queryParams: [
|
|
1250
|
+
queryParams: [
|
|
1251
|
+
"collectionID",
|
|
1252
|
+
"collectionPath",
|
|
1253
|
+
"collectionSlugPath"
|
|
1254
|
+
],
|
|
1152
1255
|
body: false,
|
|
1153
1256
|
multipart: false,
|
|
1154
1257
|
binary: false,
|
|
1155
1258
|
anonymous: false
|
|
1156
1259
|
}),
|
|
1260
|
+
updateChannel: operation(request, {
|
|
1261
|
+
method: "put",
|
|
1262
|
+
path: "/publishing/channels/{code}",
|
|
1263
|
+
pathParams: ["code"],
|
|
1264
|
+
queryParams: [],
|
|
1265
|
+
body: true,
|
|
1266
|
+
multipart: false,
|
|
1267
|
+
binary: false,
|
|
1268
|
+
anonymous: false
|
|
1269
|
+
}),
|
|
1157
1270
|
deleteChannel: operation(request, {
|
|
1158
1271
|
method: "delete",
|
|
1159
1272
|
path: "/publishing/channels/{code}",
|
|
@@ -1177,6 +1290,7 @@ const createResources = (request) => ({
|
|
|
1177
1290
|
}) },
|
|
1178
1291
|
versions: {
|
|
1179
1292
|
create: operation(request, {
|
|
1293
|
+
idempotent: true,
|
|
1180
1294
|
method: "post",
|
|
1181
1295
|
path: "/entries/{entryID}/versions",
|
|
1182
1296
|
pathParams: ["entryID"],
|
|
@@ -1200,7 +1314,7 @@ const createResources = (request) => ({
|
|
|
1200
1314
|
method: "get",
|
|
1201
1315
|
path: "/versions/{id}",
|
|
1202
1316
|
pathParams: ["id"],
|
|
1203
|
-
queryParams: ["expectedSchemaHash"],
|
|
1317
|
+
queryParams: ["expectedSchemaHash", "contentFormat"],
|
|
1204
1318
|
body: false,
|
|
1205
1319
|
multipart: false,
|
|
1206
1320
|
binary: false,
|
|
@@ -1274,6 +1388,10 @@ const retryDelay = (attempt, response) => {
|
|
|
1274
1388
|
if (Number.isFinite(date)) return Math.max(0, date - Date.now());
|
|
1275
1389
|
return Math.min(1e3 * 2 ** attempt, 3e4) + Math.random() * 250;
|
|
1276
1390
|
};
|
|
1391
|
+
const isInProgressWrite = async (request, response) => {
|
|
1392
|
+
if (response.status !== 409 || !request.headers.has("Idempotency-Key")) return false;
|
|
1393
|
+
return (await response.clone().json().catch(() => null))?.code === "IDEMPOTENCY_KEY_IN_PROGRESS";
|
|
1394
|
+
};
|
|
1277
1395
|
const fetchWithRetries = async (fetcher, request, retries) => {
|
|
1278
1396
|
const signal = request.signal;
|
|
1279
1397
|
for (let attempt = 0;; attempt += 1) {
|
|
@@ -1286,13 +1404,14 @@ const fetchWithRetries = async (fetcher, request, retries) => {
|
|
|
1286
1404
|
await wait(retryDelay(attempt), signal);
|
|
1287
1405
|
continue;
|
|
1288
1406
|
}
|
|
1289
|
-
|
|
1407
|
+
const retryable = [
|
|
1290
1408
|
429,
|
|
1291
1409
|
500,
|
|
1292
1410
|
502,
|
|
1293
1411
|
503,
|
|
1294
1412
|
504
|
|
1295
|
-
].includes(response.status)
|
|
1413
|
+
].includes(response.status) || await isInProgressWrite(request, response);
|
|
1414
|
+
if (attempt >= retries || !retryable) return response;
|
|
1296
1415
|
const delay = retryDelay(attempt, response);
|
|
1297
1416
|
await response.body?.cancel();
|
|
1298
1417
|
await wait(delay, signal);
|
|
@@ -1343,6 +1462,7 @@ const createClient = (config = {}) => {
|
|
|
1343
1462
|
new Headers(options.headers).forEach((value, key) => headers.set(key, value));
|
|
1344
1463
|
if (definition.streaming && !headers.has("Accept")) headers.set("Accept", "text/event-stream");
|
|
1345
1464
|
if (credential && !definition.anonymous) headers.set("Authorization", `Bearer ${credential}`);
|
|
1465
|
+
if (definition.idempotent && !headers.has("Idempotency-Key")) headers.set("Idempotency-Key", crypto.randomUUID());
|
|
1346
1466
|
const timer = timeout > 0 ? setTimeout(() => controller.abort(new DOMException("Request timed out", "TimeoutError")), timeout) : void 0;
|
|
1347
1467
|
let streamOwnsRequest = false;
|
|
1348
1468
|
try {
|
|
@@ -1361,7 +1481,7 @@ const createClient = (config = {}) => {
|
|
|
1361
1481
|
else if (item !== void 0) form.append(key, typeof item === "string" ? item : JSON.stringify(item));
|
|
1362
1482
|
return form;
|
|
1363
1483
|
} : void 0,
|
|
1364
|
-
fetch: (request) => fetchWithRetries(fetcher, request, definition.method === "get" ? retries : 0)
|
|
1484
|
+
fetch: (request) => fetchWithRetries(fetcher, request, definition.method === "get" || definition.idempotent ? retries : 0)
|
|
1365
1485
|
});
|
|
1366
1486
|
const response = result.response;
|
|
1367
1487
|
if (response.status === 304) {
|
|
@@ -1421,4 +1541,4 @@ const createClient = (config = {}) => {
|
|
|
1421
1541
|
//#endregion
|
|
1422
1542
|
export { paginate as n, paginatePages as r, createClient as t };
|
|
1423
1543
|
|
|
1424
|
-
//# sourceMappingURL=client-
|
|
1544
|
+
//# sourceMappingURL=client-CyhWWH37.js.map
|