@onlyworlds/sdk 4.7.3 → 4.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/AGENTS.md +63 -62
- package/CHANGELOG.md +15 -0
- package/README.md +7 -0
- package/dist/index.d.ts +60 -1
- package/dist/index.js +42 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,62 +1,63 @@
|
|
|
1
|
-
# For AI agents using @onlyworlds/sdk
|
|
2
|
-
|
|
3
|
-
**Current as of**: SDK **4.x** · schema-dist **v0.31.0-dist.19** (canonical 00.31.00).
|
|
4
|
-
This line is asserted by `codegen:check` in CI — if the pin moves and this file is not
|
|
5
|
-
re-read against it, the check fails rather than letting this document rot quietly.
|
|
6
|
-
|
|
7
|
-
**Start with [SCHEMA.md](SCHEMA.md)** (in this package): the full generated schema reference —
|
|
8
|
-
every type, every field with its meaning, link directions, families, icons, display sections.
|
|
9
|
-
It is generated from the same canonical YAML as the types, so it cannot drift.
|
|
10
|
-
|
|
11
|
-
**What this package is**: the canonical typed TypeScript client for the OnlyWorlds v2 API,
|
|
12
|
-
plus the canonical constants (element types, icons, colour families, field schema).
|
|
13
|
-
OnlyWorlds is an open standard for portable world data — 22 element types, UUID-linked.
|
|
14
|
-
|
|
15
|
-
**Use the v2 surface.** `OwV2Client` + the `V2ElementType` slug union + the generated
|
|
16
|
-
interfaces in `types.generated.ts` (emitted from the canonical schema YAML, validated
|
|
17
|
-
against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum) is not in
|
|
18
|
-
4.x — it was removed at 4.0.0 and lives only in 3.x. Do not build new work on it.
|
|
19
|
-
|
|
20
|
-
**SDK vs MCP server — pick correctly**:
|
|
21
|
-
- Known, deterministic operations (CRUD, sync, bulk) → **this SDK**. Typed calls, typed
|
|
22
|
-
responses, far cheaper than tool-schema reasoning.
|
|
23
|
-
- Live exploration of a user's world from a chat/agent context → the **MCP server** at
|
|
24
|
-
`https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 12 tools).
|
|
25
|
-
|
|
26
|
-
**Wire facts that bite** (full details in README):
|
|
27
|
-
- Never send a `"world"` field in payloads — world identity comes from the API key (422 otherwise).
|
|
28
|
-
- v2 link fields use ONE name both directions (no `_ids` suffix — that is v1 dialect only).
|
|
29
|
-
- PATCH is destructive on sent fields; use `editLinks` (atomic add/remove) for relationships.
|
|
30
|
-
- World-meta changes do NOT appear in `/changes` — poll `GET /world` separately.
|
|
31
|
-
- Extension fields: `x_<toolname>_*` is the sanctioned namespace for tool-specific state;
|
|
32
|
-
unknown unprefixed fields 422. Extensions are capped at **64 KB per element** (422,
|
|
33
|
-
`param: extensions`).
|
|
34
|
-
- List filters: `name` (exact), `name__icontains`, `supertype`, `subtype`, and
|
|
35
|
-
`characters=<id>` on types with a `characters` link. Any other filter key — and
|
|
36
|
-
`?ordering=` — returns 422 naming the accepted ones. Sort client-side.
|
|
37
|
-
- Images: `uploadImage(bytes)` returns `{ url, ... }`; set `url` as `image_url`. The bytes go
|
|
38
|
-
to the edge with a single-use ticket from keel, never with the API key.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
in
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
1
|
+
# For AI agents using @onlyworlds/sdk
|
|
2
|
+
|
|
3
|
+
**Current as of**: SDK **4.x** · schema-dist **v0.31.0-dist.19** (canonical 00.31.00).
|
|
4
|
+
This line is asserted by `codegen:check` in CI — if the pin moves and this file is not
|
|
5
|
+
re-read against it, the check fails rather than letting this document rot quietly.
|
|
6
|
+
|
|
7
|
+
**Start with [SCHEMA.md](SCHEMA.md)** (in this package): the full generated schema reference —
|
|
8
|
+
every type, every field with its meaning, link directions, families, icons, display sections.
|
|
9
|
+
It is generated from the same canonical YAML as the types, so it cannot drift.
|
|
10
|
+
|
|
11
|
+
**What this package is**: the canonical typed TypeScript client for the OnlyWorlds v2 API,
|
|
12
|
+
plus the canonical constants (element types, icons, colour families, field schema).
|
|
13
|
+
OnlyWorlds is an open standard for portable world data — 22 element types, UUID-linked.
|
|
14
|
+
|
|
15
|
+
**Use the v2 surface.** `OwV2Client` + the `V2ElementType` slug union + the generated
|
|
16
|
+
interfaces in `types.generated.ts` (emitted from the canonical schema YAML, validated
|
|
17
|
+
against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum) is not in
|
|
18
|
+
4.x — it was removed at 4.0.0 and lives only in 3.x. Do not build new work on it.
|
|
19
|
+
|
|
20
|
+
**SDK vs MCP server — pick correctly**:
|
|
21
|
+
- Known, deterministic operations (CRUD, sync, bulk) → **this SDK**. Typed calls, typed
|
|
22
|
+
responses, far cheaper than tool-schema reasoning.
|
|
23
|
+
- Live exploration of a user's world from a chat/agent context → the **MCP server** at
|
|
24
|
+
`https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 12 tools).
|
|
25
|
+
|
|
26
|
+
**Wire facts that bite** (full details in README):
|
|
27
|
+
- Never send a `"world"` field in payloads — world identity comes from the API key (422 otherwise).
|
|
28
|
+
- v2 link fields use ONE name both directions (no `_ids` suffix — that is v1 dialect only).
|
|
29
|
+
- PATCH is destructive on sent fields; use `editLinks` (atomic add/remove) for relationships.
|
|
30
|
+
- World-meta changes do NOT appear in `/changes` — poll `GET /world` separately.
|
|
31
|
+
- Extension fields: `x_<toolname>_*` is the sanctioned namespace for tool-specific state;
|
|
32
|
+
unknown unprefixed fields 422. Extensions are capped at **64 KB per element** (422,
|
|
33
|
+
`param: extensions`).
|
|
34
|
+
- List filters: `name` (exact), `name__icontains`, `supertype`, `subtype`, and
|
|
35
|
+
`characters=<id>` on types with a `characters` link. Any other filter key — and
|
|
36
|
+
`?ordering=` — returns 422 naming the accepted ones. Sort client-side.
|
|
37
|
+
- Images: `uploadImage(bytes)` returns `{ url, ... }`; set `url` as `image_url`. The bytes go
|
|
38
|
+
to the edge with a single-use ticket from keel, never with the API key. `removeImage(urlOrKey)`
|
|
39
|
+
takes one back (its uploader or the world's owner); it leaves `image_url` on elements as is.
|
|
40
|
+
- Ids: the client mints **UUIDv7** on an id-less `create` (since 4.2.0; keel mints v7 too).
|
|
41
|
+
A v4 or v7 id you supply is accepted. **Never sort elements by id**: worlds mix v7, v4
|
|
42
|
+
and legacy `06x…` ids (nibble 7 too, but seconds-first). For creation order use
|
|
43
|
+
`created_at`; `change_seq` is last-write order, not creation.
|
|
44
|
+
A create with an id that already exists, or a PUT whose id belongs to **another world**,
|
|
45
|
+
returns 409 `id_conflict` (`err.isIdConflict`; retrying won't help). `/bulk` never throws:
|
|
46
|
+
check each slot for `status: 409` with `error.code: 'id_conflict'`. A different 409, `idempotency_error`, means an
|
|
47
|
+
Idempotency-Key was reused with another body (`err.isIdempotencyConflict`).
|
|
48
|
+
- Under load keel answers 503 `server_busy` with `Retry-After` (`err.isBusy`, `err.retryAfter`
|
|
49
|
+
in seconds). The client does not retry for you; back off and retry yourself. Works the same
|
|
50
|
+
in browsers.
|
|
51
|
+
- `created_by` rides every element read: the id of the membership that created it, `null` for
|
|
52
|
+
the world's owner and for anything made before memberships existed. It is read-only; a write
|
|
53
|
+
body that carries it has it dropped, never an error. A **contributor** can change only what
|
|
54
|
+
they created: anything else is 403 `not_author` (`err.isNotAuthor`; retrying will not help).
|
|
55
|
+
`/bulk` reports it per slot, not as a throw.
|
|
56
|
+
- A string holding an unpaired surrogate (text cut mid-emoji) is a 422 naming the field.
|
|
57
|
+
Slice strings by code point, not by UTF-16 unit.
|
|
58
|
+
- Colour carries the element's FAMILY (`elementColor(type, mode)`); the icon
|
|
59
|
+
(`ELEMENT_ICONS`) carries the TYPE. Icon + label are required alongside colour, not optional.
|
|
60
|
+
|
|
61
|
+
**Auth**: prefixed keys — `ow_w_` (read+write), `ow_r_` (read-only, no PIN — the share
|
|
62
|
+
primitive), `ow_a_` (account Bearer). Demo keys `0000000000`–`0000000009` are read-only
|
|
63
|
+
test credentials against real data.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ earlier history lives in git log only.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.8.0] — 2026-10-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **`removeImage(keyOrUrl, { ticket? })`**: removes one uploaded image. A removal ticket from
|
|
12
|
+
keel (`POST /media/remove-ticket`, keel D91), then the removal at the ticket's `remove_url`
|
|
13
|
+
with the ticket only, never the API key. Takes the object key or the whole `image_url`. The
|
|
14
|
+
image's uploader or the world's owner key may remove it; the bytes go back to the uploader's
|
|
15
|
+
storage. Elements keep their `image_url`: clear it yourself.
|
|
16
|
+
- **`createRemovalTicket(key)`** and the types **`OwRemovalTicket`** (`ticket`, `remove_url`,
|
|
17
|
+
`exp` in unix seconds, `key`, `referenced`: how many elements still show the image) and
|
|
18
|
+
**`OwRemovedImage`** (`removed`, `bytes`, `cache`). Refusals arrive as `OwApiError`: keel's
|
|
19
|
+
`permission_error`, `not_found`, `removal_in_flight` and `upload_pending` (both 409 with
|
|
20
|
+
Retry-After); the edge's `ticket_expired`, `ticket_used`, `ticket_invalid`, `not_removable`,
|
|
21
|
+
`remove_failed`.
|
|
22
|
+
|
|
8
23
|
## [4.7.3] — 2026-10-10
|
|
9
24
|
|
|
10
25
|
### Changed
|
package/README.md
CHANGED
|
@@ -101,6 +101,13 @@ await writer.patch('character', id, { image_url: image.url });
|
|
|
101
101
|
|
|
102
102
|
The SDK asks the API for a single-use ticket, then sends the bytes straight to the upload host, which never sees your key. webp, png, jpeg or avif (no SVG or gif), up to 15 MB. Each upload counts toward the world's daily limit and the account's storage. To upload yourself (for a progress bar), call `createMediaTicket()` and POST the bytes to its `upload_url` with `Authorization: Bearer <ticket>`.
|
|
103
103
|
|
|
104
|
+
```typescript
|
|
105
|
+
await writer.removeImage(image.url); // the image_url, or its object key
|
|
106
|
+
await writer.patch('character', id, { image_url: null });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The image's uploader or the world's owner can remove an uploaded image; the space goes back to the uploader's storage. Removal leaves elements as they are, so clear their `image_url` yourself (`createRemovalTicket(key).referenced` says how many still show it). A copy the network already holds can keep answering for a while.
|
|
110
|
+
|
|
104
111
|
## Sync
|
|
105
112
|
|
|
106
113
|
```typescript
|
package/dist/index.d.ts
CHANGED
|
@@ -1970,6 +1970,37 @@ interface OwMediaTicket {
|
|
|
1970
1970
|
membership: string | null;
|
|
1971
1971
|
};
|
|
1972
1972
|
}
|
|
1973
|
+
/**
|
|
1974
|
+
* POST /media/remove-ticket's 200: a short-lived, single-use permission to remove one
|
|
1975
|
+
* image. keel issues it to the image's uploader or the world's owner key; the edge at
|
|
1976
|
+
* `remove_url` does the removal.
|
|
1977
|
+
*/
|
|
1978
|
+
interface OwRemovalTicket {
|
|
1979
|
+
/** Opaque: send it to `remove_url` as `Authorization: Bearer <ticket>`, as is. */
|
|
1980
|
+
ticket: string;
|
|
1981
|
+
/** Where the removal goes: the upload host's /v1/remove (https://upload.onlyworlds.com/v1/remove on production). */
|
|
1982
|
+
remove_url: string;
|
|
1983
|
+
/** Unix seconds after which the edge refuses the ticket (10 minutes after issue). */
|
|
1984
|
+
exp: number;
|
|
1985
|
+
/** The object key the ticket removes. */
|
|
1986
|
+
key: string;
|
|
1987
|
+
/** How many of the world's elements show the image. Removal does not change them: clear their `image_url` yourself. */
|
|
1988
|
+
referenced: number;
|
|
1989
|
+
}
|
|
1990
|
+
/** The edge's 200 for one removal. */
|
|
1991
|
+
interface OwRemovedImage {
|
|
1992
|
+
/** The object key that was removed. */
|
|
1993
|
+
removed: string;
|
|
1994
|
+
/** The bytes given back to the uploading account's storage. */
|
|
1995
|
+
bytes: number;
|
|
1996
|
+
/**
|
|
1997
|
+
* `may_linger`: copies the network or a browser already holds can keep answering for days
|
|
1998
|
+
* or longer (images are cached as unchanging for a year). `purging`: the edge cache is
|
|
1999
|
+
* being cleared too.
|
|
2000
|
+
*/
|
|
2001
|
+
cache: 'may_linger' | 'purging' | (string & {});
|
|
2002
|
+
[k: string]: unknown;
|
|
2003
|
+
}
|
|
1973
2004
|
/** The edge's 201 for one upload. Put `url` in an element's `image_url`. */
|
|
1974
2005
|
interface OwUploadedImage {
|
|
1975
2006
|
/** The permanent public URL (https://media.onlyworlds.com/<key>). */
|
|
@@ -2280,6 +2311,34 @@ declare class OwV2Client {
|
|
|
2280
2311
|
key?: string;
|
|
2281
2312
|
ticket?: OwMediaTicket;
|
|
2282
2313
|
}): Promise<OwUploadedImage>;
|
|
2314
|
+
/**
|
|
2315
|
+
* POST /media/remove-ticket -- permission to remove ONE image (a write key and its
|
|
2316
|
+
* PIN). The image's uploader may remove it, and so may the world's owner key; an
|
|
2317
|
+
* agent seat answers as its sponsor. Only images uploaded with a ticket qualify.
|
|
2318
|
+
* `key` is the object key, or the whole image_url (the part after the host is taken).
|
|
2319
|
+
* The reply's `referenced` counts the world's elements still showing the image.
|
|
2320
|
+
* Refusals: 403 `permission_error` (neither uploader nor owner), 404 `not_found`
|
|
2321
|
+
* (no removable image under this key), 409 `removal_in_flight` (a ticket for this
|
|
2322
|
+
* image is already out) and 409 `upload_pending` (an upload is not yet recorded), both
|
|
2323
|
+
* with Retry-After.
|
|
2324
|
+
*/
|
|
2325
|
+
createRemovalTicket(key: string): Promise<OwRemovalTicket>;
|
|
2326
|
+
/**
|
|
2327
|
+
* Remove one uploaded image: a removal ticket from the API, then the removal at the
|
|
2328
|
+
* edge (the API key never leaves for the edge). Pass the object key or the whole
|
|
2329
|
+
* image_url, or a ticket from createRemovalTicket() to use it instead of fetching one.
|
|
2330
|
+
* The bytes go back to the uploading account's storage.
|
|
2331
|
+
*
|
|
2332
|
+
* Removal does not touch elements: clear or replace their `image_url` yourself (the
|
|
2333
|
+
* ticket's `referenced` says how many there are). A copy already cached by the network
|
|
2334
|
+
* or a browser can keep answering for a while (`cache: 'may_linger'`). The edge's
|
|
2335
|
+
* refusals arrive as OwApiError with its code: 401 `ticket_expired` / `ticket_used` /
|
|
2336
|
+
* `ticket_invalid`, 403 `not_removable`, 502 `remove_failed` (nothing removed; the
|
|
2337
|
+
* ticket is still unspent).
|
|
2338
|
+
*/
|
|
2339
|
+
removeImage(keyOrUrl: string, opts?: {
|
|
2340
|
+
ticket?: OwRemovalTicket;
|
|
2341
|
+
}): Promise<OwRemovedImage>;
|
|
2283
2342
|
/**
|
|
2284
2343
|
* Raw authenticated request against this client's baseUrl. Public since 4.0
|
|
2285
2344
|
* so auxiliary resources can ride the same transport — it structurally
|
|
@@ -2653,4 +2712,4 @@ declare class TokenResource {
|
|
|
2653
2712
|
getEncryptionInfo(): Promise<EncryptionInfo>;
|
|
2654
2713
|
}
|
|
2655
2714
|
|
|
2656
|
-
export { type AccessKeyResponse, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, FAMILY_COLORS, FAMILY_ORDER, FIELD_SCHEMA, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, OwApiError, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwChange, type OwChangesPage, type OwClientConfig, type OwElement, type OwElementBase, type OwErrorBody, type OwKeyKind, type OwLinkEdit, type OwMediaTicket, OwNetworkError, type OwPage, type OwUploadedImage, OwV2Client, type OwWorldMeta, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, detectKeyKind, elementColor, errorFromResponse, familyOf, getElementIcon, getElementLabel, isDemoKey, kindCanWrite, parseErrorEnvelope, pinExpectation };
|
|
2715
|
+
export { type AccessKeyResponse, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, FAMILY_COLORS, FAMILY_ORDER, FIELD_SCHEMA, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, OwApiError, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwChange, type OwChangesPage, type OwClientConfig, type OwElement, type OwElementBase, type OwErrorBody, type OwKeyKind, type OwLinkEdit, type OwMediaTicket, OwNetworkError, type OwPage, type OwRemovalTicket, type OwRemovedImage, type OwUploadedImage, OwV2Client, type OwWorldMeta, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, detectKeyKind, elementColor, errorFromResponse, familyOf, getElementIcon, getElementLabel, isDemoKey, kindCanWrite, parseErrorEnvelope, pinExpectation };
|
package/dist/index.js
CHANGED
|
@@ -348,6 +348,44 @@ var OwV2Client = class {
|
|
|
348
348
|
if (!res.ok) throw await errorFromResponse(res);
|
|
349
349
|
return await res.json();
|
|
350
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* POST /media/remove-ticket -- permission to remove ONE image (a write key and its
|
|
353
|
+
* PIN). The image's uploader may remove it, and so may the world's owner key; an
|
|
354
|
+
* agent seat answers as its sponsor. Only images uploaded with a ticket qualify.
|
|
355
|
+
* `key` is the object key, or the whole image_url (the part after the host is taken).
|
|
356
|
+
* The reply's `referenced` counts the world's elements still showing the image.
|
|
357
|
+
* Refusals: 403 `permission_error` (neither uploader nor owner), 404 `not_found`
|
|
358
|
+
* (no removable image under this key), 409 `removal_in_flight` (a ticket for this
|
|
359
|
+
* image is already out) and 409 `upload_pending` (an upload is not yet recorded), both
|
|
360
|
+
* with Retry-After.
|
|
361
|
+
*/
|
|
362
|
+
async createRemovalTicket(key) {
|
|
363
|
+
return this.request("POST", "/media/remove-ticket", { body: { key: objectKey(key) } });
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Remove one uploaded image: a removal ticket from the API, then the removal at the
|
|
367
|
+
* edge (the API key never leaves for the edge). Pass the object key or the whole
|
|
368
|
+
* image_url, or a ticket from createRemovalTicket() to use it instead of fetching one.
|
|
369
|
+
* The bytes go back to the uploading account's storage.
|
|
370
|
+
*
|
|
371
|
+
* Removal does not touch elements: clear or replace their `image_url` yourself (the
|
|
372
|
+
* ticket's `referenced` says how many there are). A copy already cached by the network
|
|
373
|
+
* or a browser can keep answering for a while (`cache: 'may_linger'`). The edge's
|
|
374
|
+
* refusals arrive as OwApiError with its code: 401 `ticket_expired` / `ticket_used` /
|
|
375
|
+
* `ticket_invalid`, 403 `not_removable`, 502 `remove_failed` (nothing removed; the
|
|
376
|
+
* ticket is still unspent).
|
|
377
|
+
*/
|
|
378
|
+
async removeImage(keyOrUrl, opts = {}) {
|
|
379
|
+
const ticket = opts.ticket ?? await this.createRemovalTicket(keyOrUrl);
|
|
380
|
+
let res;
|
|
381
|
+
try {
|
|
382
|
+
res = await this.fetchImpl(ticket.remove_url, { method: "POST", headers: { Authorization: `Bearer ${ticket.ticket}` } });
|
|
383
|
+
} catch (cause) {
|
|
384
|
+
throw new OwNetworkError(`OnlyWorlds image removal failed: POST ${ticket.remove_url}`, cause);
|
|
385
|
+
}
|
|
386
|
+
if (!res.ok) throw await errorFromResponse(res);
|
|
387
|
+
return await res.json();
|
|
388
|
+
}
|
|
351
389
|
// -- Core request machinery ----------------------------------------------
|
|
352
390
|
/**
|
|
353
391
|
* Raw authenticated request against this client's baseUrl. Public since 4.0
|
|
@@ -423,6 +461,10 @@ function mintUuid(now = Date.now()) {
|
|
|
423
461
|
for (let i = 0; i < 256; i++) hex.push((i + 256).toString(16).slice(1));
|
|
424
462
|
return hex[bytes[0]] + hex[bytes[1]] + hex[bytes[2]] + hex[bytes[3]] + "-" + hex[bytes[4]] + hex[bytes[5]] + "-" + hex[bytes[6]] + hex[bytes[7]] + "-" + hex[bytes[8]] + hex[bytes[9]] + "-" + hex[bytes[10]] + hex[bytes[11]] + hex[bytes[12]] + hex[bytes[13]] + hex[bytes[14]] + hex[bytes[15]];
|
|
425
463
|
}
|
|
464
|
+
function objectKey(keyOrUrl) {
|
|
465
|
+
if (!/^https?:\/\//i.test(keyOrUrl)) return keyOrUrl;
|
|
466
|
+
return decodeURIComponent(new URL(keyOrUrl).pathname.replace(/^\/+/, ""));
|
|
467
|
+
}
|
|
426
468
|
function buildQuery(params) {
|
|
427
469
|
const q = new URLSearchParams();
|
|
428
470
|
for (const [k, v] of Object.entries(params)) {
|