diff --git a/.gitmodules b/.gitmodules
index fb58cdea..1c43db7a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,3 +28,9 @@
[submodule "deps/bcrypt"]
path = deps/bcrypt
url = https://github.com/rg3/bcrypt
+[submodule "deps/libqrencode"]
+ path = deps/libqrencode
+ url = https://github.com/fukuchi/libqrencode.git
+[submodule "deps/quirc"]
+ path = deps/quirc
+ url = https://github.com/dlbeer/quirc.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53c0bbf8..71979595 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.22)
-project(offs C CXX)
+project(offs LANGUAGES C CXX VERSION 0.1.0)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
@@ -173,6 +173,10 @@ else()
endif()
add_library(offs STATIC ${C_SRC})
+# Propagate the project version as OFFS_VERSION so version.h's default
+# "0.0.0" is only a fallback for non-CMake builds. PUBLIC so consumers link
+# the version metadata. Update update_actor.c:183 reads this at runtime.
+target_compile_definitions(offs PUBLIC OFFS_VERSION="${PROJECT_VERSION}")
# Opt-in AddressSanitizer instrumentation of the offs library only (not the
# external deps: msquic/poll-dancer/libcbor are add_subdirectory/ExternalProject
# targets that inherit CMAKE_C_FLAGS, so setting /fsanitize=address globally
@@ -184,8 +188,37 @@ add_library(offs STATIC ${C_SRC})
# unaffected.
option(OFFS_ENABLE_ASAN "Instrument the offs library with AddressSanitizer (MSVC) for debugging" OFF)
if(OFFS_ENABLE_ASAN)
- target_compile_options(offs PRIVATE /fsanitize=address /Z7)
+ if(MSVC)
+ target_compile_options(offs PRIVATE /fsanitize=address /Z7)
+ else()
+ # GCC/Clang: -fsanitize=address with -g for symbolicated stack traces.
+ # Scoping to the offs target (PRIVATE) keeps external deps uninstrumented,
+ # matching the MSVC policy above. The test executable must also enable ASan
+ # so the runtime is pulled in at link time — see OFFS_ENABLE_ASAN handling
+ # in test/CMakeLists.txt.
+ target_compile_options(offs PRIVATE -fsanitize=address -fno-omit-frame-pointer -g)
+ target_link_options(offs INTERFACE -fsanitize=address)
+ endif()
endif()
+
+# Optional UndefinedBehaviorSanitizer and ThreadSanitizer (GCC/Clang only).
+# These are OFF by default and have no MSVC equivalent in this build. TSan and
+# ASan are mutually exclusive — do not enable both in the same build.
+option(OFFS_ENABLE_UBSAN "Instrument the offs library with UndefinedBehaviorSanitizer (GCC/Clang)" OFF)
+if(OFFS_ENABLE_UBSAN AND NOT MSVC)
+ target_compile_options(offs PRIVATE -fsanitize=undefined -fno-omit-frame-pointer -g)
+ target_link_options(offs INTERFACE -fsanitize=undefined)
+endif()
+
+option(OFFS_ENABLE_TSAN "Instrument the offs library with ThreadSanitizer (GCC/Clang). Mutually exclusive with OFFS_ENABLE_ASAN." OFF)
+if(OFFS_ENABLE_TSAN AND NOT MSVC)
+ if(OFFS_ENABLE_ASAN)
+ message(FATAL_ERROR "OFFS_ENABLE_TSAN and OFFS_ENABLE_ASAN are mutually exclusive; enable only one.")
+ endif()
+ target_compile_options(offs PRIVATE -fsanitize=thread -fno-omit-frame-pointer -g)
+ target_link_options(offs INTERFACE -fsanitize=thread)
+endif()
+
# Release manifest signature verification: the ed25519 public key (PEM) used by
# update_verify_manifest to verify signed release manifests. Pass a path to a
# PEM file at configure time; the contents are embedded as a C string literal
@@ -357,18 +390,60 @@ else()
message(FATAL_ERROR "OpenSSL not found.")
endif()
-# libqrencode for QR code generation (optional)
-find_package(PkgConfig QUIET)
-if(PkgConfig_FOUND)
- pkg_check_modules(QRENCODE QUIET libqrencode)
+# libqrencode — QR encoder, vendored submodule (deps/libqrencode). Required:
+# QR peer-info generation is a first-class client-API feature, not an optional
+# extra, so a missing submodule is a loud error like deps/bcrypt. Built
+# without PNG support and without CLI tools — only the core encoder is used,
+# via src/QR/qr.c (added by the next task).
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/deps/libqrencode/CMakeLists.txt)
+ set(WITH_TOOLS OFF CACHE BOOL "" FORCE)
+ set(WITH_TESTS OFF CACHE BOOL "" FORCE)
+ set(WITHOUT_PNG ON CACHE BOOL "" FORCE)
+ # libqrencode turns its own tests back on whenever BUILD_TESTING is set
+ # (its CMakeLists does `if(BUILD_TESTING) set(WITH_TESTS ON)`), which would
+ # defeat the WITH_TESTS=OFF above and register ctest entries for binaries
+ # that are never built. Shadow BUILD_TESTING with a plain directory-scoped
+ # variable just for this add_subdirectory — the cache value the project's
+ # own test suite (test/CMakeLists.txt) depends on stays untouched.
+ set(_OFFS_QRENCODE_BUILD_TESTING ${BUILD_TESTING})
+ set(BUILD_TESTING OFF)
+ add_subdirectory(deps/libqrencode EXCLUDE_FROM_ALL)
+ set(BUILD_TESTING ${_OFFS_QRENCODE_BUILD_TESTING})
+ unset(_OFFS_QRENCODE_BUILD_TESTING)
+ target_include_directories(offs PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/deps/libqrencode)
+ target_link_libraries(offs PRIVATE qrencode)
+else()
+ message(FATAL_ERROR "deps/libqrencode submodule missing. Run: git submodule update --init --recursive")
endif()
-if(QRENCODE_FOUND)
- target_compile_definitions(offs PRIVATE HAS_QRENCODE)
- target_include_directories(offs PRIVATE ${QRENCODE_INCLUDE_DIRS})
- target_link_libraries(offs PRIVATE ${QRENCODE_LIBRARIES})
- message(STATUS "libqrencode found — QR code generation enabled")
+
+# quirc — QR decoder, vendored submodule (deps/quirc). Upstream ships no
+# CMakeLists.txt (Makefile-only, see deps/quirc/Makefile LIB_OBJ), so compile
+# its four decoder sources (quirc.c, decode.c, identify.c, version_db.c)
+# directly into a static library. Only decode is used (via src/QR/qr.c).
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/deps/quirc/lib/quirc.c)
+ add_library(quirc STATIC
+ deps/quirc/lib/quirc.c
+ deps/quirc/lib/decode.c
+ deps/quirc/lib/identify.c
+ deps/quirc/lib/version_db.c)
+ target_include_directories(quirc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/deps/quirc/lib)
+ # The default QUIRC_MAX_REGIONS=254 is too small for dense version-40 QR
+ # codes (one region per isolated module): the region budget is exhausted
+ # before the bottom-left finder pattern is labeled, making large payloads
+ # undecodable. 65000 is near quirc's documented ceiling (65534); pixel type
+ # widens beyond 8-bit automatically (16-bit for limits below UINT16_MAX).
+ target_compile_definitions(quirc PRIVATE QUIRC_MAX_REGIONS=65000)
+ if(NOT MSVC)
+ # identify.c uses rint/sqrt; MSVC's CRT provides both intrinsically.
+ target_link_libraries(quirc PUBLIC m)
+ endif()
+ if(MSVC)
+ # Silence size-conversion warnings in vendored code, matching the bcrypt target's policy.
+ target_compile_options(quirc PRIVATE /W0)
+ endif()
+ target_link_libraries(offs PRIVATE quirc)
else()
- message(STATUS "libqrencode not found — QR code generation disabled")
+ message(FATAL_ERROR "deps/quirc submodule missing. Run: git submodule update --init --recursive")
endif()
add_subdirectory(src/Platform)
@@ -376,4 +451,30 @@ add_subdirectory(src/Network/Relay)
add_subdirectory(tools/offs-ca)
add_subdirectory(tools/offs-release-sign)
add_subdirectory(test)
-add_subdirectory(examples)
\ No newline at end of file
+add_subdirectory(examples)
+
+# ---------------------------------------------------------------------------
+# Install / packaging
+# ---------------------------------------------------------------------------
+# Public client API headers — the installed surface of liboffs. Keep this
+# list explicit (not a glob) so an accidental header addition does not become
+# part of the installed API.
+set(OFFS_PUBLIC_HEADERS
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ClientLibs/c/offs_client.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ClientLibs/c/offs_ofd_resolver.h
+)
+
+include(GNUInstallDirs)
+install(TARGETS offs
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+install(FILES ${OFFS_PUBLIC_HEADERS}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/offs)
+
+# Generate a pkg-config file so downstream consumers can do
+# pkg-config --cflags --libs offs
+# The .pc.in template is configured with the install dirs and version.
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/offs.pc.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/offs.pc" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/offs.pc"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
\ No newline at end of file
diff --git a/deps/libqrencode b/deps/libqrencode
new file mode 160000
index 00000000..715e29fd
--- /dev/null
+++ b/deps/libqrencode
@@ -0,0 +1 @@
+Subproject commit 715e29fd4cd71b6e452ae0f4e36d917b43122ce8
diff --git a/deps/quirc b/deps/quirc
new file mode 160000
index 00000000..927d6809
--- /dev/null
+++ b/deps/quirc
@@ -0,0 +1 @@
+Subproject commit 927d680904dc95fdff4cd9d022eb374b438ff8f2
diff --git a/docs/OFFS_API_CLI_SPEC.md b/docs/OFFS_API_CLI_SPEC.md
new file mode 100644
index 00000000..f6d60449
--- /dev/null
+++ b/docs/OFFS_API_CLI_SPEC.md
@@ -0,0 +1,711 @@
+# OFFS API / CLI Feature Specification for GUI Download Manager
+
+This document catalogs every feature exposed by the OFFS HTTP API, the
+socket (CBOR) wire protocol, and the `offs` CLI, including the exact data
+types each sends and receives. It is intended as the requirements source
+for building a GUI download/upload manager with full feature parity.
+
+Sources of truth (verify against these if anything here seems wrong):
+
+| Area | File |
+|---|---|
+| GET/PUT `/offsystem` routes | `src/ClientAPI/HTTP/off_routes.c` |
+| Block routes | `src/ClientAPI/HTTP/block_routes.c` |
+| Peer/friend routes | `src/ClientAPI/HTTP/peer_routes.c` |
+| Config routes | `src/ClientAPI/HTTP/config_routes.c` |
+| Health | `src/ClientAPI/health_handler.c`, `health_routes.c` |
+| Auth middleware | `src/ClientAPI/HTTP/auth_middleware.c` |
+| CBOR wire protocol | `src/ClientAPI/client_api_wire.h` |
+| C client library | `src/ClientLibs/c/offs_client.h/.c` |
+| JS client library | `src/ClientLibs/js/offs-client/src/` |
+| `offs` CLI | `OFFS/src/offs/` (main.c, cli_util.c, commands/*) |
+| `offsd` daemon flags | `OFFS/src/offsd/main.c:198-229` |
+| ORI / OFF URL | `src/OFFStreams/off_url.h/.c` |
+| OFD directories | `src/OFFStreams/ofd.h/.c`, JS mirror `ofd.js` |
+| Blocks / cache | `src/BlockCache/block.h`, `block_cache.h` |
+| Peer info | `src/Network/peer_info.h/.c`, `node_id.h` |
+| Config fields | `src/Configuration/config_json.c` |
+| Size limits | `src/Util/validation.h` |
+
+---
+
+## 1. Core concepts (needed to design the GUI)
+
+### 1.1 Blocks
+
+- OFFS splits every file into fixed-size **blocks** and XOR-mixes each data
+ block with `tuple_size - 1` random blocks. A **tuple** is the ordered list
+ of block hashes needed to reconstruct one data block.
+- Block sizes (`src/BlockCache/block.h`):
+ - `mega` = 1,000,000 bytes
+ - `standard` = 128,000 bytes (default for all URL-based transfers)
+ - `mini` = 64,000
+ - `nano` = 136
+- Every block is content-addressed by a **32-byte BLAKE3 hash**, rendered
+ as **base58** text in URLs and APIs
+ (alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`).
+
+### 1.2 ORI / OFF URL
+
+The universal file reference. `PUT /offsystem` returns one; `GET` consumes one.
+
+String format (`src/OFFStreams/off_url.c:216-222`):
+
+```
+[server-address]/offsystem/v3/{content-type}/{stream-length}/{file-hash-b58}/{descriptor-hash-b58}/{file-name}
+```
+
+- `server-address` — e.g. `http://localhost:23402` (default when parsing a bare ORI)
+- `content-type` — MIME type, may contain `/` (e.g. `application/octet-stream`),
+ or the special value `offsystem/directory` for OFD directories
+- `stream-length` — total file size in bytes (decimal)
+- `file-hash`, `descriptor-hash` — 32-byte BLAKE3, base58-encoded
+- `file-name` — free text (no `/`)
+
+In-memory form (`ori_t`, `src/OFFStreams/ori.h:49-59`):
+
+```c
+typedef struct {
+ refcounter_t refcounter;
+ buffer_t* descriptor_hash; // 32 bytes
+ size_t descriptor_offset;
+ block_size_e block_type; // 128000 default
+ size_t tuple_size; // 3 default
+ buffer_t* file_hash; // 32 bytes
+ size_t file_offset;
+ char* file_name;
+ size_t final_byte; // total file size
+} ori_t;
+```
+
+URL-parseable form (`off_url_t`, `src/OFFStreams/off_url.h:16-24`):
+
+```c
+typedef struct {
+ char* server_address;
+ char* content_type;
+ size_t stream_length;
+ size_t stream_offset;
+ buffer_t* file_hash; // 32-byte BLAKE3
+ buffer_t* descriptor_hash; // 32-byte BLAKE3
+ char* file_name;
+} off_url_t;
+```
+
+A GUI needs an ORI parser/renderer: split into the 7 fields above, and
+re-compose for display/copy.
+
+### 1.3 OFD — OFF File Directory
+
+A directory is itself an OFFS object ("OFF File Directory") stored as an
+OFF URL with content type `offsystem/directory`. Its body is CBOR:
+`{"v": 1, "entries": [...]}` where each entry is a map:
+
+| Key | Meaning | Present for |
+|---|---|---|
+| `n` | name (string) | all |
+| `t` | type: 0 = file, 1 = directory | all |
+| `f` | file hash (bstr, 32) | files |
+| `D` | descriptor hash (bstr, 32) | files |
+| `s` | final byte / file size | files |
+| `B` | block type (default 128000) | files |
+| `T` | tuple size (default 3) | files |
+| `o` | file offset | files |
+| `d` | directory hash (bstr) | directories |
+
+Defined in `src/OFFStreams/ofd.c:77-155`; JS mirror in
+`src/ClientLibs/js/offs-client/src/ofd.js:86-138`.
+
+Downloading a directory URL resolves a path inside it: `/index.html` is
+served if the requested name ends in `.ofd`; otherwise the named entry is
+looked up. `?ofd=raw` returns the raw OFD CBOR bytes as `application/cbor`.
+
+The JS client's `putFolder()` shows the intended directory workflow:
+recursively upload the tree, build an OFD CBOR per directory, upload each
+directory as `content type: offsystem/directory` with file name `
.ofd`,
+and return the root directory's ORI. A GUI file browser should be able to
+parse an OFD and list/download its children.
+
+### 1.4 Limits and validation
+
+From `src/Util/validation.h` and route code:
+
+- `OFFS_MAX_CBOR_MESSAGE_SIZE` = 64 MB (also `OFFS_MAX_STREAM_LENGTH`)
+- Block PUT body: `0 < size <= 128000`
+- `type` header ≤ 256 chars; `file-name` ≤ 1024 chars, no `/`
+- `tuple-size` default 3, must be ≤ node config `max_tuple_size` (daemon default 5)
+- Single Range header only (no multi-range)
+- Uploads are rejected with 500 if the cache cannot fit
+ `writeable_off_stream_estimate_required_bytes(stream_length, tuple_size, 32)`
+
+---
+
+## 2. HTTP API (REST surface)
+
+Base: the daemon's HTTP port (default **23402**; HTTPS port configurable).
+
+### 2.1 Download — `GET /offsystem/v3/{type}/{stream-length}/{file-hash}/{descriptor-hash}/{file-name}`
+
+Route pattern (`off_routes.c:71`):
+
+```
+/offsystem/v3/([-+._a-zA-Z0-9]+/[-+._a-zA-Z0-9-]+|[-+._a-zA-Z0-9]+)/([0-9]+)/([base58]+)/([base58]+)/([^!`&*()+]+|\[ !$`&*()+]+)+
+```
+
+Request:
+
+- Path params: content type (percent-decoded), stream length (decimal),
+ file hash (base58, decodes to 32 bytes), descriptor hash (base58, 32 bytes),
+ file name.
+- Query params:
+ - `?ofd=raw` — for `offsystem/directory` type: return raw OFD bytes as
+ `application/cbor` (404 if neither the OFD cache nor block cache has it).
+ - Without `?ofd=raw`, directory URLs resolve `index.html` (if the name ends
+ in `.ofd`) or the named path inside the OFD; 404 if unresolvable.
+ - `?load=1` (or bare `?load`) — **cache-load mode**: the daemon pulls the
+ file's tuples into its block cache WITHOUT sending any file data. Any
+ other value (`?load=0`, etc.) is ignored and data is served normally.
+- Optional header `Range: bytes=start-end | start- | -suffix`
+ (single range; multi-range rejected). With `?load=1`, Range selects which
+ tuples are loaded (trimmed to the byte range); 206/416 semantics are the
+ same as a ranged GET.
+- `?load=1` response is `application/x-ndjson`, one JSON object per line:
+ - Progress (one per resolved tuple): `{"tuples_loaded":n,"tuples_total":m}`
+ - Terminal: `{"status":"loaded|partial|failed","tuples_loaded":n,"tuples_total":m}`
+ (`partial` = some tuples skipped; `failed` = none loaded)
+- `?load=1` on a directory ORI (after resolution) →
+ `400` "Load requires a file ORI, not a directory".
+- Known limitation: loads taking longer than ~60 s are truncated by the
+ connection idle/hard timers (tracked as OFFS-190).
+
+Response:
+
+| Status | Meaning | Body |
+|---|---|---|
+| 200 | Full content | `Content-Type` from URL type or MIME-from-extension, `Accept-Ranges: bytes`, `Content-Length`, streamed body |
+| 206 | Valid Range | `Content-Range: bytes start-end/size`, partial body |
+| 416 | Invalid Range | `Content-Range: bytes */{size}` |
+| 404 | Unresolved directory path / missing raw OFD | — |
+| 400 | URL failed to parse | — |
+
+GUI notes: the body streams as blocks arrive from cache/network — support
+progress by counting received bytes against `Content-Length` (or the range
+length). Range support enables resume/partial download.
+
+### 2.2 Upload — `PUT /offsystem`
+
+Required headers:
+
+| Header | Constraints |
+|---|---|
+| `type` | content type, ≤ 256 chars |
+| `file-name` | ≤ 1024 chars, no `/` |
+| `stream-length` | decimal, 1..64 MB |
+
+Optional headers:
+
+| Header | Meaning |
+|---|---|
+| `server-address` | embedded into the returned ORI string |
+| `recycler` | JSON array of OFF URLs, e.g. `["/offsystem/v3/..."]` — recycles blocks from those files instead of allocating fresh ones |
+| `temporary` | `"true"` marks upload temporary |
+| `tuple-size` | erasure width, default 3; 400 if > node `max_tuple_size` |
+| `Content-Type: multipart/form-data` | body parsed as multipart; first file part used (forces buffered path) |
+
+Body: raw bytes (may be chunked/streamed) or multipart. Streaming path:
+after headers pass validation, body chunks stream directly into the
+block-writing pipeline; bytes beyond `stream-length` are dropped.
+
+Responses:
+
+| Status | Meaning | Body |
+|---|---|---|
+| 200 | Success | `text/plain` — the ORI (OFF URL) string |
+| 400 | Missing/invalid headers or tuple-size | — |
+| 500 | Cache full ("configure larger max_capacity_bytes") | — |
+
+CORS: `Access-Control-Allow-Origin: *`,
+`Access-Control-Expose-Headers: Content-Type, Content-Range, Content-Length`.
+
+### 2.3 Blocks (auth required)
+
+Registered only when an API key is configured.
+
+#### `PUT /blocks`
+
+- Optional query `?encoding=base58` → hash returned as base58 text.
+- Body: raw block bytes, `0 < size <= 128000`, else 400.
+- Response `201 Created`: 32-byte hash (`application/octet-stream`) or
+ base58 string (`text/plain`); 500 on failure.
+
+#### `GET /blocks/{base58-hash}`
+
+- Path hash must decode to exactly 32 bytes else 400.
+- `200` `application/octet-stream` raw block data (padded to block size);
+ `404` if absent.
+
+#### `DELETE /blocks/{base58-hash}`
+
+- `204 No Content` on success; `404` if not removed.
+
+#### `POST /blocks/defragment`
+
+- Query: `threshold=<0.0..1.0>` (default 0.5).
+- `200` JSON: `{"result": , "sections_defragmented": , "blocks_relocated": }`.
+
+### 2.4 Peers and friends (auth required)
+
+#### `GET /peer/info`
+
+- Requires a node identity (CA + node cert): without one the daemon has no
+ authority public key and cannot produce peer info.
+- Query `format=`: `cbor` (default) | `base58` | `qrcode`.
+- `200`:
+ - `cbor`: `application/cbor` peer-info map (§5.5)
+ - `base58`: `text/plain` base58 of the CBOR
+ - `qrcode`: `image/x-portable-pixmap` QR of the CBOR bytes (always
+ available — vendored libqrencode; image includes a 4-module quiet zone)
+- LAN (HOST) candidates included only when the request is authenticated.
+
+#### `POST /peer/connect`
+
+- Body, one of:
+ - `application/cbor` peer-info map
+ - plain-text base58 (default)
+ - `image/x-portable-pixmap` — P6 PPM QR image; the daemon decodes the QR
+ and parses the embedded peer-info CBOR
+- `200` JSON: `{"status": <0..4>, "message": "..."}` —
+ 0 OK "Connection initiated", 1 already connected, 2 invalid peer info,
+ 3 failed, 4 rejected. An undecodable image or invalid peer info is
+ **not** a 400: it returns HTTP 200 with
+ `{"status": 2, "message": "Invalid peer info"}`.
+
+#### `GET /peers`
+
+- `200` JSON array: `[{"node_id": string, "connected": bool, "is_friend": bool, "in_ring": bool}]`
+ (connection-manager peers plus gossip/ring members, the latter
+ `in_ring: true, connected: false`).
+
+#### `POST /friends`
+
+- Body: peer info — CBOR map, base58 text, or `image/x-portable-pixmap`
+ QR image (decoded server-side like `/peer/connect`; undecodable input
+ yields HTTP 200 `{"status": 2, "message": "Invalid peer info"}`).
+- `201`/`200` `{"status":"added"}`; `409` `{"status":"already_friend"}`;
+ 400 invalid. Persists and attempts immediate connect.
+
+#### `DELETE /friends/{node_id}`
+
+- `200` `{"status":"removed"}`; `404` unknown; `400` bad node_id.
+
+#### `GET /friends`
+
+- `200` JSON array: `[{"node_id": string, "connected": bool}]`.
+
+### 2.5 Config (local-binding protected)
+
+#### `GET /config`
+
+- `200` full config as JSON (§7). 401 if unauthenticated.
+
+#### `PUT /config`
+
+- Body: JSON object of field → value (known fields in §7).
+- `200` JSON: `{"staged": [field...], "rejected": [{"field":..., "reason":...}], "restart_required": bool}`
+- Mutations on non-loopback bindings → `403 {"error":"config mutation requires local transport"}`.
+
+#### `POST /config/restart`
+
+- `202 {"message":"restarting"}` if a pending config exists;
+ `409 {"error":"no pending config to apply"}` otherwise.
+
+### 2.6 Health — `GET /health`
+
+`200` `application/json` (`src/ClientAPI/health_handler.c:95-142`):
+
+```json
+{
+ "status": "running|stopped|draining|unknown",
+ "uptime_seconds": 0,
+ "node_id": "<48-char base58 string>",
+ "peer_count": 0,
+ "total_connections": 0,
+ "avg_hebbian_weight": 0.0,
+ "block_cache": { "current_bytes": 0, "max_bytes": 0, "block_count": 0 },
+ "rate_limits": [
+ { "type": "find_block|store_block|seeking_blocks|ping_capacity|ping",
+ "accepted": 0, "rejected": 0, "avg_tokens": 0.0, "effective_rate": 0.0 }
+ ],
+ "rpc_calls": [ { "name": "", "count": 0 } ]
+}
+```
+
+`node_id` omitted if unknown. `rate_limits` and `rpc_calls` are arrays of
+the above shapes (only non-zero RPC names listed).
+
+### 2.7 Authentication (HTTP)
+
+- Enabled when the node has an API key configured. Middleware chain on all
+ routes: draining check → CORS → bearer auth.
+- `Authorization: Bearer `; token checked against the stored bcrypt
+ hash. Missing header/scheme → `401` + `WWW-Authenticate: Bearer`;
+ wrong key → `403`.
+- Loopback bindings may bypass bearer via config `config_local_binding_no_auth`.
+- `/offsystem` GET/PUT and `/health` are registered regardless of auth;
+ `/blocks`, `/peer/*`, `/friends` are only registered when auth is enabled.
+
+---
+
+## 3. Socket wire protocol (Unix / TCP / WebSocket / WebTransport)
+
+All non-HTTP transports (the daemon's Unix socket — default
+`/var/run/offs.sock` — TCP, WS, and WebTransport) speak a **length-prefixed
+CBOR** protocol. Every frame is a **CBOR array whose first element is the
+message type**. Defined in `src/ClientAPI/client_api_wire.h`.
+
+- Unix / TCP / WebTransport: length-prefixed via `stream_frame_encode`.
+- WebSocket: binary WS frames (no extra length prefix), upgrade at `GET /offs`.
+- Max frame: 64 MB; clients auto-chunk large buffers (C client: 256 KB chunks).
+- On auth-enabled sockets, frames are rejected with status 5 (UNAUTHORIZED)
+ until an `AUTH_REQUEST` succeeds.
+
+Message types (`client_api_wire.h:13-48`):
+
+| Type | Name | Payload shape |
+|---|---|---|
+| 1 | PUT_REQUEST | see below |
+| 2 | PUT_DATA | `[2, bytestring]` |
+| 3 | PUT_END | `[3]` |
+| 4 | PUT_RESPONSE | `[4, ori_string]` |
+| 5 | GET_REQUEST | `[5, ori_string, has_range, range_start?, range_end?]` |
+| 6 | GET_RESPONSE_START | `[6, content_type, content_length, has_range, range_start?, range_end?]` |
+| 7 | GET_DATA | `[7, bytestring]` |
+| 8 | GET_END | `[8]` |
+| 11 | ERROR | `[11, status_code, message]` |
+| 12 | AUTH_REQUEST | `[12, api_key: bytestring]` |
+| 13 | BLOCK_PUT_REQUEST | `[13, data: bstr, encoding: uint]` (0=raw, 1=base58) |
+| 14 | BLOCK_PUT_RESPONSE | `[14, status: uint, hash: bstr|tstr]` |
+| 15 | BLOCK_GET_REQUEST | `[15, hash: bstr]` |
+| 16 | BLOCK_GET_RESPONSE | `[16, status: uint, data: bstr]` |
+| 17 | BLOCK_DELETE_REQUEST | `[17, hash: bstr]` |
+| 18 | BLOCK_DELETE_RESPONSE | `[18, status: uint]` |
+| 19 | HEALTH_REQUEST | `[19]` |
+| 20 | HEALTH_RESPONSE | `[20, json_string]` |
+| 21 | PEER_INFO_REQUEST | `[21]` or `[21, format]` (format 0=raw CBOR default, 1=base58, 2=PPM QR image) |
+| 22 | PEER_INFO_RESPONSE | `[22, format_byte, data: bstr]` (format 0=raw CBOR, 1=base58 text, 2=PPM QR image) |
+| 23 | PEER_CONNECT | `[23, format_byte, data: bstr]` (format 0=raw CBOR, 1=base58, 2=PPM QR image) |
+| 24 | PEER_CONNECT_RESULT | `[24, status: uint]` |
+| 25 | PEER_LIST_REQUEST | `[25]` |
+| 26 | PEER_LIST_RESPONSE | `[26, peers: cbor_array]` |
+| 27 | FRIEND_ADD | `[27, format_byte, data: bstr]` (format 0=raw CBOR, 1=base58, 2=PPM QR image) |
+| 28 | FRIEND_REMOVE | `[28, node_id: bstr]` |
+| 29 | FRIEND_LIST | `[29]` |
+| 30 | FRIEND_LIST_RESPONSE | `[30, friends: cbor_array]` |
+| 31 | UPDATE_STATUS_REQUEST | `[31]` |
+| 32 | UPDATE_STATUS_RESPONSE | `[32, json_string]` |
+| 33 | CONFIG_SHOW_REQUEST | `[33]` |
+| 34 | CONFIG_SHOW_RESPONSE | `[34, json_string]` |
+| 35 | CONFIG_SET_REQUEST | `[35, field: tstr, value: tstr]` (value always a string) |
+| 36 | CONFIG_SET_RESPONSE | `[36, status: uint, restart_required: uint, message: tstr]` (status 0=staged, 1=rejected) |
+| 37 | CONFIG_RELOAD_REQUEST | `[37]` |
+| 38 | CONFIG_RELOAD_RESPONSE | `[38, status: uint, message: tstr]` (0=restarting, 1=none/error) |
+| 39 | LOAD_REQUEST | `[39, ori_string]` or `[39, ori_string, has_range, range_start, range_end]` — same optional-range shape as GET_REQUEST; pulls the file's blocks into the cache, no data sent back |
+| 40 | LOAD_PROGRESS | `[40, tuples_loaded: uint, tuples_total: uint]` (one per resolved tuple; `total - loaded` includes in-flight and skipped) |
+| 41 | LOAD_END | `[41, status: uint, tuples_loaded: uint, tuples_total: uint]` (status 0=loaded, 1=partial, 2=failed) |
+
+Peer-info payloads (PEER_INFO_RESPONSE/PEER_CONNECT/FRIEND_ADD data) are
+capped at 2 MB (`CLIENT_API_PEER_INFO_MAX_PAYLOAD`, `client_api_wire.c`) —
+raised to fit QR PPM images, which are far larger than the raw CBOR blob.
+
+Status codes (`client_api_wire.h:51-56`):
+0 OK, 1 BAD_REQUEST, 2 NOT_FOUND, 3 INTERNAL_ERROR, 4 RANGE_NOT_SATISFIABLE,
+5 UNAUTHORIZED.
+
+### 3.1 PUT flow (socket)
+
+1. `[1, content_type, file_name, stream_length, server_address, data,
+ recycler_urls, temporary, tuple_size?]`
+ - `data` empty for streaming; 9-element form (with `tuple_size`) only
+ when tuple size is set.
+ - `recycler_urls` = array of OFF URL strings.
+2. `[2, chunk: bstr]` repeated (client chunks at 63 MiB; framer cap forces
+ chunking — the C client chunks >1 MB buffers into 256 KB).
+3. `[3]` PUT_END.
+4. Reply `[4, ori_string]` or `[11, status, message]`.
+
+`tuple_size` must be ≤ daemon `max_tuple_size` (default 5).
+
+### 3.2 GET flow (socket)
+
+1. `[5, ori_string, has_range, range_start?, range_end?]`
+2. `[6, content_type, content_length, has_range, range_start?, range_end?]`
+3. `[7, chunk: bstr]` repeated
+4. `[8]` GET_END, or `[11, status, message]` (status 4 = range not satisfiable).
+
+### 3.3 LOAD flow (socket)
+
+1. `[39, ori_string, has_range?, range_start?, range_end?]`
+2. `[40, tuples_loaded, tuples_total]` repeated (one per resolved tuple)
+3. `[41, status, tuples_loaded, tuples_total]`, or `[11, status, message]`
+ (daemon-side rejections — bad ORI, unauthorized — arrive as ERROR frames
+ before the first LOAD_PROGRESS).
+
+Transport note: LOAD is **network-aware on the unix transport** (the unix
+connection has access to the node's network actor, so missing tuples are
+fetched from peers). WS/TCP LOAD is **cache-only** — those connections carry
+no network actor, so only tuples already in the block cache resolve (missing
+tuples are skipped → `partial`). WebTransport has no LOAD (it has no GET
+support either).
+
+### 3.4 Other socket-only surfaces
+
+- Update status (31/32) JSON:
+ `{"enabled": bool, "channel": str, "check_interval_hours": n, "state": str|"idle", "current_version": str, "available_version": str|"none"}`
+- Config show (33/34) returns the same JSON as HTTP `GET /config`.
+
+---
+
+## 4. `offs` CLI (feature parity checklist)
+
+Entry: `OFFS/src/offs/main.c`. Global flags: `--socket ` (default
+`/var/run/offs.sock`), `--lang `. Commands (`cli_util.c:25-40`):
+`start, stop, restart, put, get, block, peer, config, friend, health, status,
+version, help`. Transport: Unix socket, CBOR frames (§3).
+
+| Command | Args/flags | Operation | Output |
+|---|---|---|---|
+| `offs put ` | `--temporary`, `--recycler `, `--tuple-size N`, `--help` | Streaming PUT (§3.1); content type from extension; chunks 63 MiB | progress on stderr (`Putting : n/total bytes (pct)`); success prints ORI |
+| `offs get [--output ]` | `--output` | GET flow (§3.2); detects truncation (no GET_END) | bytes to stdout/file |
+| `offs load ` | — | LOAD flow (§3.3): pull the file's tuples into the daemon cache, no file data | progress on stderr; exit 0 loaded/partial, 1 failed |
+| `offs block put ` | `--encoding base58` | BLOCK_PUT | hash |
+| `offs block get ` | hash | BLOCK_GET | raw block bytes |
+| `offs block delete ` | hash | BLOCK_DELETE | "ok" |
+| `offs peer info` | `--qr ` or `--qr -` (stdout) | PEER_INFO | "Peer Info" + base58 blob, or QR PPM image |
+| `offs peer list` | — | PEER_LIST | peer count |
+| `offs peer connect ` | peer info base58, or `--qr ` (read PPM QR image) | PEER_CONNECT | "ok" |
+| `offs friend add ` | peer info, or `--qr ` (read PPM QR image) | FRIEND_ADD | "ok" |
+| `offs friend remove ` | node id | FRIEND_REMOVE | "ok" |
+| `offs friend list` | — | FRIEND_LIST | friend count |
+| `offs health` | — | HEALTH | pretty-printed health JSON |
+| `offs status` | — | HEALTH + UPDATE_STATUS | health JSON + update status (enabled/channel/current_version/state/available_version/check_interval_hours) |
+| `offs version` | — | client-side | `offs version 0.1.0` |
+| `offs start/stop/restart` | — | daemon lifecycle via service/pid files (no socket) | — |
+| `offs config show` | — | CONFIG_SHOW | config JSON |
+| `offs config get ` | field | CONFIG_SHOW | value |
+| `offs config set =` | — | CONFIG_SET | status |
+| `offs config add/remove ` | — | CONFIG_SET | status |
+| `offs config set-auth ` | bcrypt hash | CONFIG_SET | status |
+| `offs config generate-auth [--cost N]` | bcrypt client-side | CONFIG_SET | status |
+| `offs config reload` | — | CONFIG_RELOAD | status |
+
+`start`/`stop`/`restart`/`version` never open the socket.
+
+### 4.1 `offsd` daemon flags (for a GUI that manages the daemon)
+
+`OFFS/src/offsd/main.c:198-229`: `--config`, `--host`, `--port` (HTTP, default
+23402), `--quic-port` (23401), `--unix `, `--cache-dir`, `--data-dir`,
+`--pid-file`, `--workers`, `--foreground`, `--log-file`, `--log-level`,
+`--log-structured`, `--metrics-server`, `--ca-cert`, `--node-cert`,
+`--node-key`, `--relay-url`, `--max-capacity-bytes` (default 5 GiB),
+`--api-key` (random one generated + printed if omitted), `--ws-port`,
+`--wt-port`, `--wt-h3-port`, `--ws-cert/--ws-key`, `--wt-cert/--wt-key`,
+`--allow-secure`, `--help`.
+
+---
+
+## 5. Data types reference
+
+### 5.1 Block
+
+```c
+typedef enum { mega = 1000000, standard = 128000, mini = 64000, nano = 136 } block_size_e;
+
+typedef struct {
+ refcounter_t refcounter;
+ buffer_t* data; // payload, padded to block size
+ buffer_t* hash; // 32-byte BLAKE3
+} block_t;
+```
+
+### 5.2 Tuple (XOR recipe)
+
+Ordered list of block hashes (`tuple_size` entries) that reconstruct one
+data block. Descriptor = sequence of tuples + 32-byte pad; descriptor
+itself is stored as blocks.
+
+### 5.3 Recipes
+
+- `new_blocks_recipe_t` — allocate fresh random blocks (default).
+- `recycler_recipe_t` — recycle blocks from existing ORIs (the `recycler`
+ header / `--recycler` flag: JSON array of OFF URLs).
+
+### 5.4 ORI — see §1.2.
+
+### 5.5 Peer info
+
+```c
+#define NODE_ID_HASH_SIZE 32
+#define NODE_ID_STRING_SIZE 48
+typedef struct node_id_t { uint8_t hash[32]; char str[48]; } node_id_t;
+
+typedef enum { PEER_ADDR_DIRECT=0, PEER_ADDR_RELAY=1, PEER_ADDR_HOST=2, PEER_ADDR_SRFLX=3 } peer_addr_type_e;
+typedef struct peer_address_t { peer_addr_type_e type; char* host; uint16_t port; uint32_t relay_id; } peer_address_t;
+
+#define PEER_INFO_MAX_ADDRESSES 8
+typedef struct {
+ node_id_t node_id;
+ uint8_t* public_key; size_t public_key_len;
+ peer_address_t* addresses; size_t address_count;
+} peer_info_t;
+```
+
+CBOR encoding (`src/Network/peer_info.c:62-121`): map of 3 pairs —
+`node_id` (bstr 32), `public_key` (bstr), `addresses` (array of maps:
+`type` u8, `host` tstr, `port` u16, `relay_id` u32). Base58 form =
+base58(CBOR bytes). This blob is what `peer connect` / `friend add`
+consume and what `peer info` produces — QR-code exchange is the intended
+sharing mechanism.
+
+### 5.6 OFD — see §1.3.
+
+---
+
+## 6. Client libraries (reference behavior)
+
+### 6.1 C client (`src/ClientLibs/c/offs_client.h`)
+
+- Connect URLs: `unix://path`, `tcp://host:port`, `ws://`, `wss://`, `wt://`,
+ `wts://`. Config defaults: connect timeout 5000 ms, max retries 3,
+ retry base delay 1000 ms with exponential backoff + jitter,
+ `allow_secure=false`.
+- Sends `AUTH_REQUEST [12, api_key]` immediately on connect when a key is set.
+- Operations: `put` (buffered, auto-chunks >1 MB), `put_stream_start/data/end`,
+ `get` (data/end/error callbacks, range supported on the wire),
+ `load` (`offs_client_load(ori, has_range, range_start, range_end,
+ progress_cb, progress_ctx, end_cb, end_ctx)` — cache-load without file
+ data; progress_cb fires per resolved tuple, end_cb fires exactly once with
+ status `CLIENT_API_LOAD_STATUS_LOADED/PARTIAL/FAILED`; one load
+ outstanding per connection),
+ `block_put/get/delete`, `health`, plus `offs_http_get(url)` (blocking HTTP/1.1).
+- Callback model (`offs_client.h:52-61`) — a GUI download manager should
+ mirror this event model:
+ `put_response(ctx, ori)`, `get_data(ctx, data, len)`, `get_end(ctx)`,
+ `error(ctx, status_code, message)`, `block_put(ctx, status, hash, len, is_text)`,
+ `block_get(ctx, status, data, len)`, `block_delete(ctx, status)`,
+ `health(ctx, json)`.
+
+### 6.2 JS client (`src/ClientLibs/js/offs-client/`)
+
+`OffsClient` (HTTP / WS / WT transports, auto-selected by URL scheme):
+
+- `put(options, data)` → PUT `/offsystem` (headers `type`, `file-name`,
+ `stream-length`, optional `server-address`, `recycler` JSON array,
+ `temporary: true`, `tuple-size`); response body text = ORI string.
+- `putStreamStart/putStreamData/putStreamEnd` (CBOR transports only).
+- `get(ori, {onStart, onData, onEnd, onError}, range)` — parses
+ `Content-Type`, `Content-Length`, `Content-Range`.
+- `load(ori, {onProgress, onEnd, onError}, range)` — cache-load without file
+ data. On HTTP transports streams the `?load=1` ndjson body; on CBOR
+ transports uses LOAD_PROGRESS/LOAD_END frames (status is the string
+ `"loaded"|"partial"|"failed"` on HTTP, numeric on CBOR —
+ `wire.LOAD_STATUS` map: `loaded: 0, partial: 1, failed: 2`).
+- `delete(offUrl)`.
+- `blockPut(data, encoding)`, `blockGet(hash)`, `blockDelete(hash)`.
+- `health()`, `peerInfo(format)` (format `'cbor'` (default) | `'base58'` |
+ `'qrcode'` — PPM QR image), `peerConnect(peerInfo, format)`,
+ `peerConnectQr(ppmBytes)` (shorthand for format 2), `peerList()`,
+ `friendAdd`/`friendAddQr(ppmBytes)`/`friendRemove`/`friendList`,
+ `configShow()`, `configSet(f,v)`, `configReload()`.
+- `putFolder(items, options)`: recursive directory upload, builds OFD CBOR
+ per directory, uploads directories as `offsystem/directory` named
+ `.ofd`, returns root ORI. Progress callback
+ `onProgress(name, uploaded, total)`.
+- Static `OffsClient.offUrlToHttpUrl(ori, baseUrl)`.
+
+---
+
+## 7. Configuration fields (`GET/PUT /config`, CONFIG_SET)
+
+Known fields (`src/Configuration/config_json.c:15-33`):
+
+| Kind | Fields |
+|---|---|
+| string | `api_key_hash`, `https_cert_path`, `https_key_path`, `tcp_tls_cert_path`, `tcp_tls_key_path` |
+| bool | `http_enabled`, `https_enabled`, `unix_enabled`, `tcp_enabled`, `ws_enabled`, `wt_enabled`, `tcp_tls_enabled`, `allow_secure`, `fsync_data` |
+| number | `cache_size`, `max_snapshots`, `max_wals`, `max_capacity_bytes`, `scheduler_thread_count`, `http_port`, `https_port`, `tcp_port`, `ws_port`, `wt_port` |
+
+Semantics: PUT stages changes to `{data_dir}/pending_config.json` and
+returns which fields staged/rejected plus `restart_required`;
+`POST /config/restart` applies pending config (409 if none). Config
+mutations are refused (403) on non-loopback bindings regardless of auth.
+
+Update status (wire 31/32) JSON:
+`{"enabled": bool, "channel": str, "check_interval_hours": n, "state": str|"idle", "current_version": str, "available_version": str|"none"}`.
+Channels: `stable|rc|dev`.
+
+---
+
+## 8. Security model
+
+- HTTP admin endpoints (blocks, peers, friends, config): `Authorization:
+ Bearer `, bcrypt-checked server-side. 401 + `WWW-Authenticate:
+ Bearer` if missing; 403 on wrong key.
+- CBOR transports: send `[12, api_key: bstr]` as the first frame; all frames
+ rejected with status 5 until auth succeeds.
+- `/config` mutations additionally require a loopback transport.
+- `allow_secure` (default false): encryption-only + reputation mode;
+ when true, node certificates are validated against the CA (secure mode).
+
+---
+
+## 9. GUI feature checklist (derived from the above)
+
+**Downloads**
+- [ ] Accept an ORI/OFF URL string (parse + validate the 7 fields)
+- [ ] Streamed download with progress (bytes received / `Content-Length` or range length)
+- [ ] Range requests: `bytes=start-end`, `start-`, `-suffix` → resume, partial download
+- [ ] 416 handling (`Content-Range: bytes */size`) → query size then retry
+- [ ] Directory (OFD) URLs: parse `?ofd=raw` CBOR, list entries, download children,
+ resolve `index.html` for `.ofd` names
+- [ ] Error surface: 400 bad URL, 404 unresolved, socket statuses 1–5
+- [ ] Known gap: GET of a missing block can hang (no wanted-list expiry — see
+ `docs/PRODUCTION_BLOCKERS.md`); the GUI should implement its own timeout/cancel
+- [x] Cache load / pin to node (pre-fetch a file's tuples into the daemon block
+ cache without receiving file data) — implemented across all surfaces:
+ HTTP `GET ...?load=1` (ndjson progress), wire frames 39–41, C
+ `offs_client_load`, JS `load()`, Dart `loadContent`, CLI `offs load`
+
+**Uploads**
+- [ ] File upload with `type`, `file-name`, `stream-length` headers (or wire PUT flow)
+- [ ] Optional: `server-address`, `recycler` (list of ORIs), `temporary`, `tuple-size`
+- [ ] Streaming upload (chunked body / PUT_DATA frames) for large files
+- [ ] Multipart form upload variant
+- [ ] Display returned ORI; copy to clipboard
+- [ ] Folder upload (recursive, build OFD per directory, upload as
+ `offsystem/directory`) with per-file progress
+
+**Blocks**
+- [ ] Put block (raw or base58 encoding option)
+- [ ] Get block (display hex/base58/raw)
+- [ ] Delete block
+- [ ] Defragment with threshold slider (0.0–1.0) and result counts
+
+**Peers / friends**
+- [x] Show my peer info (CBOR / base58 / QR code) — supported server-side:
+ HTTP `?format=qrcode`, wire format 2, CLI `offs peer info --qr |-`
+- [x] Connect to peer (paste base58 or scan QR) — supported server-side:
+ HTTP `Content-Type: image/x-portable-pixmap` body, wire format 2,
+ CLI `offs peer connect --qr ` / `offs friend add --qr `
+- [ ] Peer list with connected / friend / in-ring state
+- [ ] Friend add/remove/list
+
+**Node management**
+- [ ] Health dashboard (status, uptime, node_id, peer/connections, hebbian weight, block cache bytes/count, rate-limit stats, RPC counters)
+- [ ] Config viewer/editor (§7 fields), staged/rejected feedback, restart prompt
+- [ ] Daemon start/stop/restart; update status display
+- [ ] Bearer API key management (bcrypt generate/check)
+
+**Cross-cutting**
+- [ ] Transport choice: HTTP REST and/or socket CBOR frames (unix/tcp/ws/wt)
+- [ ] Auth: bearer header (HTTP) or AUTH_REQUEST first frame (sockets)
+- [ ] ORI copy/paste everywhere (parse, render, validate base58 hashes)
\ No newline at end of file
diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md
index b16bf08d..b72f538a 100644
--- a/docs/OPERATIONS.md
+++ b/docs/OPERATIONS.md
@@ -2,7 +2,7 @@
## Known issues
-### NULL-buffer heap corruption in HTTP body handlers (root cause under investigation)
+### NULL-buffer heap corruption in HTTP body handlers (root cause: data races — fixed)
**Symptom:** Historically, `buffer->data` was observed NULL inside the HTTP
body handling paths — `_on_body` (http_parser body callback in
@@ -10,53 +10,39 @@ body handling paths — `_on_body` (http_parser body callback in
body handler in `src/ClientAPI/HTTP/off_routes.c`), and `_pipe_on_data`
(response piping callback in `src/ClientAPI/HTTP/http_response.c`). The
`buffer_t` struct had `capacity` set correctly but `data == NULL` and `size`
-held garbage, suggesting the struct fields were overwritten by heap corruption
-from an unknown source.
-
-**Guards in place:** Defensive sentinels were restored at the entry of each
-of those three handlers. A NULL `buffer->data` (or NULL `chunk`/`at` pointer)
-now logs an `error`-level message identifying the handler and the suspicious
-pointer values, then returns without dereferencing. In `_on_body` the parse
-is aborted by returning `1` to http-parser; in the streamed-PUT and
-response-pipe paths the chunk is dropped. This prevents the NULL dereference
-crash but does not address the underlying corruption.
-
-**Root cause status:** Under investigation. The corruption is not easily
-reproducible under ASAN (ASAN redzones mask the bug), and the flaky
-`TestStream*` segfaults observed in ASAN builds do not produce an ASAN
-report (the SIGSEGV bypasses ASAN's signal handler, produces no core dump,
-does not reproduce under gdb/strace/pty, and does not reproduce in non-ASAN
-builds). The failing `TestStream*` tests (`TestPushFileStream.*`,
-`TestPullFileStream.*`, `TestStreamActor.*`) are file-stream + scheduler
-tests and do not exercise the HTTP body handlers directly, so the sentinel
-guards do not resolve their segfaults — but the guards are retained as the
-spec's accepted fallback for the historical NULL-buffer crash.
-
-**Investigation notes:**
-
-- The flaky ASAN segfault is timing-dependent (reproduces only when stdout
- is file-redirected, not under a pty; ~30% rate in isolated process runs).
-- ASAN installs its SIGSEGV handler but does not fire a report when the
- segfault occurs, suggesting the fault happens in a state where ASAN's
- handler cannot safely run (e.g. during process teardown after main
- returns, or in a thread that hasn't registered its stack with ASAN).
-- `buffer_ensure_capacity` aborts on OOM, so `buffer->data` is never NULL
- in normal operation — the NULL must come from external heap corruption.
-- Candidates not yet ruled out: a missing `REFERENCE` on a `buffer_t*`
- crossing an actor boundary; a `stream_notify` CONSUME/yield ownership
- bug; a double-free in dispatch (per the
- `feedback_double_free_dispatch.md` memory note — `actor_run` frees
- `msg->payload`; dispatch must not also free it); a `stream_deactivate`
- freeing a buffer while a handler still reads it.
-
-**Next steps for a future investigation:**
-
-1. Run the `TestStream*` tests under ThreadSanitizer (TSAN) to catch the
- race that ASAN misses.
-2. Audit `actor_run`'s payload destroy path against every dispatch handler
- in `src/Streams/` and `src/ClientAPI/HTTP/` for the double-free pattern
- documented in `feedback_double_free_dispatch.md`.
-3. Stress-run the file-stream pipeline under valgrind with
- `--track-origins=yes` to capture the corruption source.
-4. Once the root cause is found, remove the sentinel guards and replace
- with the minimal fix.
\ No newline at end of file
+held garbage.
+
+**Root cause:** The NULL `buffer->data` was a downstream symptom of heap
+corruption from two cross-thread data races, not a `buffer_t` bug. TSAN
+caught both (ASAN and valgrind miss them):
+
+1. **`connection->sock` use-after-free** — `_connection_close_fd` (worker
+ thread) freed the socket and set `connection->sock = NULL` while
+ `_connection_read_callback` (I/O thread) read it. Fixed by making
+ `connection->sock` an `ATOMIC(platform_socket_t*)` and deferring the
+ socket's close+free to the I/O thread's destroy stack
+ (`http_server_defer_socket_destroy`), mirroring the existing
+ watcher/timer deferral.
+
+2. **`pipe_notifiers` use-after-free WRITE** — `readable_push_stream_pipe` /
+ `writeable_pull_stream_pipe` called `on_pipe`/`on_piped` synchronously on
+ the caller's thread, writing `pipe_notifiers` while
+ `stream_unsubscribe_pipe_notifiers` (worker thread) freed it. Fixed by
+ routing pipe/piped through the stream actor via the already-declared
+ `STREAM_PIPE`/`STREAM_PIPED` messages and `stream_pipe_internal` /
+ `stream_piped_internal`.
+
+**Guards in place:** The defensive sentinels at the entry of the three body
+handlers remain as cheap no-op checks (http-parser never legitimately passes
+NULL `at`/`length`), but they are no longer the fix — the underlying races
+are resolved.
+
+**Verification:** `TestPushFileStream.*`, `TestPullFileStream.*`,
+`TestStreamActor.*`, `TestHttpServer.*`, `TestOffRoutes.*`, and
+`TestHttpServerSsl.*` all pass under TSAN with zero data-race reports, and
+the full 849-test suite passes. The GET-path pipeline refcount leak in
+`_setup_stream_pipeline` (off_routes.c) that previously leaked 48 bytes
+direct + 209 bytes indirect per GET request has also been fixed — the
+`get_pipeline_t` refcount now reaches zero in all paths via a `desc_done`
+flag that ensures desc contributes exactly one deref whether close or
+error fires first.
\ No newline at end of file
diff --git a/docs/superpowers/plans/2026-08-27-qr-peer-connect.md b/docs/superpowers/plans/2026-08-27-qr-peer-connect.md
new file mode 100644
index 00000000..90eb1c21
--- /dev/null
+++ b/docs/superpowers/plans/2026-08-27-qr-peer-connect.md
@@ -0,0 +1,1625 @@
+# QR Peer Connect Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Make QR codes a first-class, symmetric peer-info transport: any client API surface (HTTP, unix/TCP/WS/WT sockets, C client lib, JS client lib, `offs` CLI) can generate a QR image of local peer info and submit a QR image to connect/add a friend.
+
+**Architecture:** Two vendored submodules (`deps/libqrencode` encoder, `deps/quirc` decoder) feed a new `src/QR/` codec module with exactly two operations (`qr_encode_to_ppm`, `qr_decode_from_ppm`). All transports call these two functions so behavior cannot drift. Wire format byte 2 = "PPM QR image" on `PEER_INFO_REQUEST/RESPONSE`, `PEER_CONNECT`, and `FRIEND_ADD`. HTTP routes dispatch by Content-Type on bodies and share one payload-decode helper with the socket handlers.
+
+**Tech Stack:** C (liboffs), libqrencode (submodule), quirc (submodule), CMake, GTest, libcbor, JS (offs-client package), cURL (manual verification).
+
+**Spec:** `docs/superpowers/specs/2026-08-27-qr-peer-connect-design.md`
+**Harmony ticket:** OFFS-187
+
+**Deviations from spec (decided during planning):**
+- `qr_encode_to_ppm` / `qr_decode_from_ppm` return `malloc`'d `uint8_t*` + length instead of `buffer_t` — the wire structs own raw `uint8_t*` payloads, so plain malloc ownership transfers cleanly into `client_api_peer_info_response_t.data` (freed by `client_api_peer_info_response_destroy`) without refcounter surgery.
+- The C client library has **no peer/friend functions today** — `peer_info`/`peer_connect`/`friend_add` (plus `_ex` and `_qr` forms) are new functions, not modifications.
+- HTTP-level round-trip testing via GTest would require a full `offs_node_t` + CA + authority fixture; instead the shared decode helper and QR module get unit tests, and the HTTP path gets a concrete manual curl round-trip verification (Task 9) against the example server.
+
+---
+
+## File Structure
+
+| File | Action | Responsibility |
+|---|---|---|
+| `deps/libqrencode` | Create (submodule) | QR encoder |
+| `deps/quirc` | Create (submodule) | QR decoder |
+| `CMakeLists.txt:393-406` | Modify | Replace pkg-config probe with submodule builds |
+| `src/QR/qr.h`, `src/QR/qr.c` | Create | PPM QR encode/decode codec (only place qrencode/quirc are called) |
+| `test/test_qr.cpp` | Create | Codec unit tests |
+| `src/ClientAPI/client_api_wire.h/.c` | Modify | `PEER_INFO_REQUEST` format byte (encode + decode) |
+| `test/test_qr_wire.cpp` | Create | Wire format-2 frame tests |
+| `src/ClientAPI/peer_handlers.h/.c` | Modify | Shared `peer_info_from_payload` helper; format 2 in info/connect/friend handlers |
+| `test/test_peer_payload.cpp` | Create | Payload-dispatch unit tests (incl. QR round trip) |
+| `src/ClientAPI/HTTP/peer_routes.c` | Modify | Encode via `src/QR`; accept `image/x-portable-pixmap` bodies |
+| `src/ClientLibs/c/offs_client.h/.c` | Modify | New peer/QR client functions + response dispatch |
+| `src/ClientLibs/js/offs-client/src/wire.js` | Modify | `encodePeerInfoRequest(format)` |
+| `src/ClientLibs/js/offs-client/src/transports/http-transport.js` | Modify | Content-Type by format; `qrcode` fetch |
+| `src/ClientLibs/js/offs-client/src/index.js` | Modify | Pass format on CBOR transports; `peerConnectQr`/`friendAddQr` sugar |
+| `OFFS/src/offs/commands/peer.c` | Modify | `--qr` on `info` and `connect` |
+| `OFFS/src/offs/commands/friend.c` | Modify | `--qr` on `add` |
+| `test/CMakeLists.txt` | Modify | Register new test files |
+| `docs/OFFS_API_CLI_SPEC.md` | Modify | Document format byte 2 + PPM body support |
+
+Note: `CMakeLists.txt` uses `file(GLOB_RECURSE C_SRC "src/*/*.c")` — new files under `src/QR/` are picked up automatically after re-running CMake.
+
+---
+
+### Task 1: Vendor libqrencode + quirc submodules and wire CMake
+
+**Files:**
+- Create: `deps/libqrencode` (submodule), `deps/quirc` (submodule)
+- Modify: `CMakeLists.txt` (qrencode probe block, lines 393-406)
+
+- [ ] **Step 1: Add the submodules**
+
+```bash
+git submodule add https://github.com/fukuchi/libqrencode.git deps/libqrencode
+git submodule add https://github.com/dlbeer/quirc.git deps/quirc
+```
+
+This updates `.gitmodules` automatically. Do not commit yet (Task 1 Step 5 commits everything together).
+
+- [ ] **Step 2: Replace the pkg-config qrencode probe in CMakeLists.txt**
+
+Find this block (lines 393-406):
+
+```cmake
+# libqrencode for QR code generation (optional)
+find_package(PkgConfig QUIET)
+if(PkgConfig_FOUND)
+ pkg_check_modules(QRENCODE QUIET libqrencode)
+endif()
+if(QRENCODE_FOUND)
+ target_compile_definitions(offs PRIVATE HAS_QRENCODE)
+ target_include_directories(offs PRIVATE ${QRENCODE_INCLUDE_DIRS})
+ target_link_libraries(offs PRIVATE ${QRENCODE_LIBRARIES})
+ message(STATUS "libqrencode found — QR code generation enabled")
+else()
+ message(STATUS "libqrencode not found — QR code generation disabled")
+endif()
+```
+
+Replace it with:
+
+```cmake
+# libqrencode — QR encoder, vendored submodule (deps/libqrencode). Required:
+# QR peer-info generation is a first-class client-API feature, not an optional
+# extra, so a missing submodule is a loud error like deps/bcrypt. Built
+# without PNG support and without CLI tools — only the core encoder is used,
+# via src/QR/qr.c.
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/deps/libqrencode/CMakeLists.txt)
+ set(WITH_TOOLS OFF CACHE BOOL "" FORCE)
+ set(WITH_TEST OFF CACHE BOOL "" FORCE)
+ set(WITHOUT_PNG ON CACHE BOOL "" FORCE)
+ add_subdirectory(deps/libqrencode)
+ target_include_directories(offs PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/deps/libqrencode)
+ target_link_libraries(offs PRIVATE qrencode)
+else()
+ message(FATAL_ERROR "deps/libqrencode submodule missing. Run: git submodule update --init --recursive")
+endif()
+
+# quirc — QR decoder, vendored submodule (deps/quirc). Upstream ships no
+# CMakeLists.txt (Makefile-only, see deps/quirc/Makefile LIB_OBJ), so compile
+# the four decoder sources directly into a static library. Only decode is
+# used (via src/QR/qr.c); quirc_encode.c is intentionally not built.
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/deps/quirc/lib/quirc.c)
+ add_library(quirc STATIC
+ deps/quirc/lib/quirc.c
+ deps/quirc/lib/decode.c
+ deps/quirc/lib/identify.c
+ deps/quirc/lib/version_db.c)
+ target_include_directories(quirc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/deps/quirc/lib)
+ target_link_libraries(offs PRIVATE quirc)
+else()
+ message(FATAL_ERROR "deps/quirc submodule missing. Run: git submodule update --init --recursive")
+endif()
+```
+
+- [ ] **Step 3: Configure and build to verify**
+
+```bash
+cmake -B build -DCMAKE_BUILD_TYPE=Debug && cmake --build build -j$(nproc) 2>&1 | tail -5
+```
+
+Expected: configures without errors; `qrencode` and `quirc` targets build; `offs` links. If libqrencode's CMake emits a `qrencode` shared/static target name other than `qrencode`, check `deps/libqrencode/CMakeLists.txt` for the actual target name (`add_library(qrencode ...)`) and adjust the `target_link_libraries` line.
+
+- [ ] **Step 4: Verify test target still links** (CMake propagates PRIVATE deps of the static `offs` lib to `testliboffs` via `$`; confirm rather than assume)
+
+```bash
+cmake --build build --target testliboffs -j$(nproc) 2>&1 | tail -3
+```
+
+Expected: links cleanly. If it fails with undefined `QRcode_encodeData`/quirc symbols, add `target_link_libraries(testliboffs PRIVATE qrencode quirc)` next to the existing `target_link_libraries(testliboffs PRIVATE blake3)` line in `test/CMakeLists.txt`.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add .gitmodules deps/libqrencode deps/quirc CMakeLists.txt test/CMakeLists.txt
+git commit -m "build: vendor libqrencode and quirc as required submodules"
+```
+
+---
+
+### Task 2: `src/QR` codec module (TDD)
+
+**Files:**
+- Create: `src/QR/qr.h`, `src/QR/qr.c`
+- Create: `test/test_qr.cpp`
+- Modify: `test/CMakeLists.txt` (add `test_qr.cpp` to the `add_executable(testliboffs ...)` source list)
+
+- [ ] **Step 1: Write the failing test**
+
+Create `test/test_qr.cpp`:
+
+```cpp
+#include
+#include
+#include
+#include
+
+extern "C" {
+#include "../src/QR/qr.h"
+}
+
+namespace qr_test {
+
+/* Build a binary P6 PPM of the given dimensions filled with the given gray
+ value (RGB triplets r=g=b=gray). Returns malloc'd buffer; caller frees. */
+static uint8_t* _make_ppm(int width, int height, uint8_t gray, size_t* out_len) {
+ char header[64];
+ int header_len = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", width, height);
+ size_t pixel_len = (size_t)width * height * 3;
+ uint8_t* ppm = (uint8_t*)malloc(header_len + pixel_len);
+ if (ppm == NULL) return NULL;
+ memcpy(ppm, header, header_len);
+ for (size_t i = 0; i < pixel_len; i++) ppm[header_len + i] = gray;
+ *out_len = header_len + pixel_len;
+ return ppm;
+}
+
+TEST(QrEncode, RejectsNullAndEmpty) {
+ size_t len = 0;
+ EXPECT_TRUE(qr_encode_to_ppm(NULL, 10, &len) == NULL);
+ uint8_t one = 0x01;
+ EXPECT_TRUE(qr_encode_to_ppm(&one, 0, &len) == NULL);
+}
+
+TEST(QrRoundTrip, PayloadSurvivesEncodeDecode) {
+ /* 64 pseudo-random bytes (deterministic LCG so the test never flakes) */
+ uint8_t payload[64];
+ uint32_t state = 12345;
+ for (size_t i = 0; i < sizeof(payload); i++) {
+ state = state * 1103515245 + 12345;
+ payload[i] = (uint8_t)(state >> 16);
+ }
+
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm(payload, sizeof(payload), &ppm_len);
+ ASSERT_NE(ppm, nullptr);
+ ASSERT_GT(ppm_len, 0u);
+ /* Generated images are binary P6 */
+ EXPECT_EQ(0, memcmp(ppm, "P6\n", 3));
+
+ size_t decoded_len = 0;
+ uint8_t* decoded = qr_decode_from_ppm(ppm, ppm_len, &decoded_len);
+ free(ppm);
+ ASSERT_NE(decoded, nullptr);
+ EXPECT_EQ(decoded_len, sizeof(payload));
+ EXPECT_EQ(0, memcmp(decoded, payload, sizeof(payload)));
+ free(decoded);
+}
+
+TEST(QrDecode, RejectsBadMagic) {
+ const char* not_ppm = "P5\n1 1\n255\n";
+ size_t len = 0;
+ EXPECT_TRUE(qr_decode_from_ppm((const uint8_t*)not_ppm, strlen(not_ppm), &len) == NULL);
+}
+
+TEST(QrDecode, RejectsWrongMaxval) {
+ const char* ppm = "P6\n1 1\n65535\n";
+ size_t len = 0;
+ EXPECT_TRUE(qr_decode_from_ppm((const uint8_t*)ppm, strlen(ppm), &len) == NULL);
+}
+
+TEST(QrDecode, RejectsTruncatedPixels) {
+ size_t full_len = 0;
+ uint8_t* ppm = _make_ppm(10, 10, 255, &full_len);
+ ASSERT_NE(ppm, nullptr);
+ /* Header + less than w*h*3 pixel bytes */
+ size_t header_len = full_len - 10u * 10u * 3u;
+ size_t len = 0;
+ EXPECT_TRUE(qr_decode_from_ppm(ppm, header_len + 10, &len) == NULL);
+ free(ppm);
+}
+
+TEST(QrDecode, NoQrCodeInBlankImage) {
+ size_t ppm_len = 0;
+ uint8_t* ppm = _make_ppm(200, 200, 255, &ppm_len);
+ ASSERT_NE(ppm, nullptr);
+ size_t len = 0;
+ EXPECT_TRUE(qr_decode_from_ppm(ppm, ppm_len, &len) == NULL);
+ free(ppm);
+}
+
+TEST(QrDecode, RejectsNullAndEmpty) {
+ size_t len = 0;
+ EXPECT_TRUE(qr_decode_from_ppm(NULL, 10, &len) == NULL);
+ EXPECT_TRUE(qr_decode_from_ppm((const uint8_t*)"P6\n1 1\n255\n", 0, &len) == NULL);
+}
+
+} // namespace qr_test
+```
+
+Add `test_qr.cpp` to the `add_executable(testliboffs ...)` source list in `test/CMakeLists.txt` (next to `test_block.cpp`).
+
+- [ ] **Step 2: Run test to verify it fails**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs --gtest_filter='Qr*'
+```
+
+Expected: **compile failure** — `src/QR/qr.h` does not exist yet.
+
+- [ ] **Step 3: Write the header**
+
+Create `src/QR/qr.h`:
+
+```c
+//
+// QR codec: encode payloads into QR images (libqrencode) and decode QR
+// images back into payloads (quirc). The image format both directions
+// produce and accept is binary P6 PPM — the daemon never accepts an image
+// format it does not itself generate. The only callers are the client API
+// handlers (HTTP/peer_routes.c and ClientAPI/peer_handlers.c); this module
+// knows nothing about peer info, CBOR, or transports.
+//
+
+#ifndef LIBOFFS_QR_H
+#define LIBOFFS_QR_H
+
+#include
+#include
+
+/* Encode payload bytes into a QR code rendered as a binary P6 PPM image
+ (error-correction level M, 4x pixel scale — byte-compatible with the
+ rendering previously inline in HTTP/peer_routes.c). Returns a malloc'd
+ buffer (caller frees with free()) and sets *out_len, or NULL on failure. */
+uint8_t* qr_encode_to_ppm(const uint8_t* payload, size_t payload_len,
+ size_t* out_len);
+
+/* Parse a binary P6 PPM, locate the first decodable QR code, and return its
+ payload bytes as a malloc'd buffer (caller frees with free()). Returns
+ NULL and does not touch *out_len if the image is not valid P6, contains
+ no QR code, or the QR payload fails to decode. */
+uint8_t* qr_decode_from_ppm(const uint8_t* ppm_data, size_t ppm_len,
+ size_t* out_len);
+
+#endif /* LIBOFFS_QR_H */
+```
+
+- [ ] **Step 4: Write the implementation**
+
+Create `src/QR/qr.c`:
+
+```c
+#include "qr.h"
+#include
+#include
+#include
+#include
+#include
+
+/* Matches the rendering previously inline in HTTP/peer_routes.c so images
+ already in circulation stay decodable. */
+#define QR_PIXEL_SCALE 4
+
+/* Strict P6: magic, whitespace, width, whitespace, height, whitespace,
+ maxval (must be exactly 255), exactly one whitespace byte, then
+ width*height*3 binary RGB bytes. Anything else is rejected — the encoder
+ below is the only producer we support. */
+static const uint8_t* _ppm_skip_ws(const uint8_t* p, const uint8_t* end) {
+ while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++;
+ return p;
+}
+
+static const uint8_t* _ppm_read_int(const uint8_t* p, const uint8_t* end,
+ int* out) {
+ p = _ppm_skip_ws(p, end);
+ if (p >= end || *p < '0' || *p > '9') return NULL;
+ int value = 0;
+ while (p < end && *p >= '0' && *p <= '9') {
+ value = value * 10 + (*p - '0');
+ if (value > 1000000) return NULL; /* sane image size bound */
+ p++;
+ }
+ *out = value;
+ return p;
+}
+
+uint8_t* qr_encode_to_ppm(const uint8_t* payload, size_t payload_len,
+ size_t* out_len) {
+ if (payload == NULL || payload_len == 0 || out_len == NULL) return NULL;
+
+ QRcode* code = QRcode_encodeData((int)payload_len, payload, 0, QR_ECLEVEL_M);
+ if (code == NULL) return NULL;
+
+ int qr_size = code->width;
+ int img_size = qr_size * QR_PIXEL_SCALE;
+ size_t header_len = (size_t)snprintf(NULL, 0, "P6\n%d %d\n255\n", img_size, img_size);
+ size_t ppm_size = header_len + (size_t)img_size * img_size * 3;
+
+ uint8_t* ppm = malloc(ppm_size);
+ if (ppm == NULL) {
+ QRcode_free(code);
+ return NULL;
+ }
+ int printed = snprintf((char*)ppm, header_len + 1, "P6\n%d %d\n255\n", img_size, img_size);
+ size_t offset = (size_t)printed;
+ for (int y = 0; y < qr_size; y++) {
+ for (int sy = 0; sy < QR_PIXEL_SCALE; sy++) {
+ for (int x = 0; x < qr_size; x++) {
+ uint8_t pixel = (code->data[y * qr_size + x] & 1) ? 0 : 255;
+ for (int sx = 0; sx < QR_PIXEL_SCALE; sx++) {
+ ppm[offset++] = pixel;
+ ppm[offset++] = pixel;
+ ppm[offset++] = pixel;
+ }
+ }
+ }
+ }
+ QRcode_free(code);
+
+ *out_len = ppm_size;
+ return ppm;
+}
+
+uint8_t* qr_decode_from_ppm(const uint8_t* ppm_data, size_t ppm_len,
+ size_t* out_len) {
+ if (ppm_data == NULL || ppm_len == 0 || out_len == NULL) return NULL;
+ if (ppm_len < 2 || ppm_data[0] != 'P' || ppm_data[1] != '6') return NULL;
+
+ const uint8_t* cursor = ppm_data + 2;
+ const uint8_t* end = ppm_data + ppm_len;
+ int width = 0, height = 0, maxval = 0;
+
+ cursor = _ppm_read_int(cursor, end, &width);
+ if (cursor == NULL || width <= 0) return NULL;
+ cursor = _ppm_read_int(cursor, end, &height);
+ if (cursor == NULL || height <= 0) return NULL;
+ cursor = _ppm_read_int(cursor, end, &maxval);
+ if (cursor == NULL || maxval != 255) return NULL;
+ /* P6 requires exactly one whitespace between maxval and pixel data */
+ if (cursor >= end || (*cursor != ' ' && *cursor != '\t' &&
+ *cursor != '\n' && *cursor != '\r')) {
+ return NULL;
+ }
+ cursor++;
+
+ size_t pixel_len = (size_t)width * height * 3;
+ if ((size_t)(end - cursor) < pixel_len) return NULL;
+
+ struct quirc* decoder = quirc_new();
+ if (decoder == NULL) return NULL;
+ if (quirc_resize(decoder, width, height) < 0) {
+ quirc_destroy(decoder);
+ return NULL;
+ }
+
+ int gray_w = 0, gray_h = 0;
+ uint8_t* gray = quirc_begin(decoder, &gray_w, &gray_h);
+ if (gray == NULL) {
+ quirc_destroy(decoder);
+ return NULL;
+ }
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ const uint8_t* rgb = cursor + ((size_t)y * width + x) * 3;
+ /* ITU-R BT.601 luma, matching standard PPM→grayscale conversion */
+ gray[y * width + x] =
+ (uint8_t)((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000);
+ }
+ }
+ quirc_end(decoder);
+
+ uint8_t* result = NULL;
+ size_t result_len = 0;
+ int count = quirc_count(decoder);
+ for (int i = 0; i < count && result == NULL; i++) {
+ struct quirc_code code;
+ struct quirc_data data;
+ quirc_extract(decoder, i, &code);
+ if (quirc_decode(&code, &data) == 0) {
+ result = malloc(data.payload_len);
+ if (result != NULL) {
+ memcpy(result, data.payload, data.payload_len);
+ result_len = data.payload_len;
+ }
+ }
+ }
+ quirc_destroy(decoder);
+
+ if (result == NULL) return NULL;
+ *out_len = result_len;
+ return result;
+}
+```
+
+- [ ] **Step 5: Run tests to verify they pass**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs --gtest_filter='Qr*'
+```
+
+Expected: all `Qr*` tests PASS.
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add src/QR test/test_qr.cpp test/CMakeLists.txt
+git commit -m "feat(qr): add PPM QR codec module (libqrencode encode, quirc decode)"
+```
+
+---
+
+### Task 3: Wire protocol — `PEER_INFO_REQUEST` format byte (TDD)
+
+**Files:**
+- Modify: `src/ClientAPI/client_api_wire.h` (comment at ~line 240, decls at ~line 378)
+- Modify: `src/ClientAPI/client_api_wire.c:1077-1083`
+- Create: `test/test_qr_wire.cpp`
+- Modify: `test/CMakeLists.txt` (add `test_qr_wire.cpp`)
+
+Note: `client_api_peer_connect_decode` and `client_api_friend_add_decode` already accept any format byte (they only validate "is a uint") and their payloads are already bstr — **no changes needed there**; only the request frame gains format support.
+
+- [ ] **Step 1: Write the failing test**
+
+Create `test/test_qr_wire.cpp`:
+
+```cpp
+#include
+#include
+
+extern "C" {
+#include "../src/ClientAPI/client_api_wire.h"
+#include
+}
+
+namespace qr_wire_test {
+
+TEST(PeerInfoRequestWire, BareFrameDecodesToFormatCbor) {
+ cbor_item_t* frame = client_api_peer_info_request_encode();
+ uint8_t format = 99;
+ ASSERT_EQ(0, client_api_peer_info_request_decode(frame, &format));
+ EXPECT_EQ(0, format); /* backward compatible default: raw CBOR */
+ cbor_decref(&frame);
+}
+
+TEST(PeerInfoRequestWire, FormatTwoRoundTrips) {
+ cbor_item_t* frame = client_api_peer_info_request_encode_format(2);
+ uint8_t format = 0;
+ ASSERT_EQ(0, client_api_peer_info_request_decode(frame, &format));
+ EXPECT_EQ(2, format);
+ cbor_decref(&frame);
+}
+
+TEST(PeerInfoRequestWire, FormatOneRoundTrips) {
+ cbor_item_t* frame = client_api_peer_info_request_encode_format(1);
+ uint8_t format = 0;
+ ASSERT_EQ(0, client_api_peer_info_request_decode(frame, &format));
+ EXPECT_EQ(1, format);
+ cbor_decref(&frame);
+}
+
+TEST(PeerInfoRequestWire, UnknownFormatRejected) {
+ cbor_item_t* array = cbor_new_definite_array(2);
+ cbor_item_t* type = cbor_build_uint8(CLIENT_API_PEER_INFO_REQUEST);
+ cbor_item_t* fmt = cbor_build_uint8(7);
+ (void)cbor_array_push(array, type);
+ (void)cbor_array_push(array, fmt);
+ cbor_decref(&type);
+ cbor_decref(&fmt);
+ uint8_t format = 0;
+ EXPECT_NE(0, client_api_peer_info_request_decode(array, &format));
+ cbor_decref(&array);
+}
+
+TEST(PeerInfoRequestWire, ExtraElementRejected) {
+ cbor_item_t* array = cbor_new_definite_array(3);
+ cbor_item_t* type = cbor_build_uint8(CLIENT_API_PEER_INFO_REQUEST);
+ cbor_item_t* fmt = cbor_build_uint8(2);
+ cbor_item_t* extra = cbor_build_uint8(7);
+ (void)cbor_array_push(array, type);
+ (void)cbor_array_push(array, fmt);
+ (void)cbor_array_push(array, extra);
+ cbor_decref(&type);
+ cbor_decref(&fmt);
+ cbor_decref(&extra);
+ uint8_t format = 0;
+ EXPECT_NE(0, client_api_peer_info_request_decode(array, &format));
+ cbor_decref(&array);
+}
+
+TEST(PeerConnectWire, FormatTwoPassesThrough) {
+ /* PEER_CONNECT/FRIEND_ADD decoders already accept any format byte —
+ pin that behavior so format 2 (PPM image) flows through unchanged. */
+ cbor_item_t* array = cbor_new_definite_array(3);
+ cbor_item_t* type = cbor_build_uint8(CLIENT_API_PEER_CONNECT);
+ cbor_item_t* fmt = cbor_build_uint8(2);
+ const uint8_t image_bytes[] = {'P', '6', '\n'};
+ cbor_item_t* data = cbor_build_bytestring(image_bytes, sizeof(image_bytes));
+ (void)cbor_array_push(array, type);
+ (void)cbor_array_push(array, fmt);
+ (void)cbor_array_push(array, data);
+ cbor_decref(&type);
+ cbor_decref(&fmt);
+ cbor_decref(&data);
+
+ client_api_peer_connect_t msg;
+ ASSERT_EQ(0, client_api_peer_connect_decode(array, &msg));
+ EXPECT_EQ(2, msg.format);
+ EXPECT_EQ(sizeof(image_bytes), msg.data_size);
+ client_api_peer_connect_destroy(&msg);
+ cbor_decref(&array);
+}
+
+} // namespace qr_wire_test
+```
+
+Add `test_qr_wire.cpp` to the test source list in `test/CMakeLists.txt`.
+
+- [ ] **Step 2: Run test to verify it fails**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc)
+```
+
+Expected: **compile failure** — `client_api_peer_info_request_encode_format` / `client_api_peer_info_request_decode` undeclared.
+
+- [ ] **Step 3: Update the header**
+
+In `src/ClientAPI/client_api_wire.h`, update the frame comments (~line 239-247):
+
+```c
+// --- Peer Info Request ---
+// [type] or [type, format: uint]
+// format: 0 = raw CBOR (default), 1 = Base58 text, 2 = PPM QR image
+
+// --- Peer Info Response ---
+// [type, format_byte, data: bstr]
+// format_byte: 0 = raw CBOR, 1 = Base58 text, 2 = PPM QR image
+```
+
+and add declarations next to the existing one (~line 378):
+
+```c
+cbor_item_t* client_api_peer_info_request_encode(void);
+/* Same frame with an explicit response format byte:
+ 0 = raw CBOR, 1 = base58 text, 2 = PPM QR image. */
+cbor_item_t* client_api_peer_info_request_encode_format(uint8_t format);
+/* Decode [type] or [type, format]; *format defaults to 0 for the 1-element
+ form. Rejects unknown formats and frames with extra elements. */
+int client_api_peer_info_request_decode(cbor_item_t* item, uint8_t* format);
+```
+
+- [ ] **Step 4: Implement in client_api_wire.c**
+
+Replace `client_api_peer_info_request_encode` (lines 1077-1083) with:
+
+```c
+cbor_item_t* client_api_peer_info_request_encode(void) {
+ return client_api_peer_info_request_encode_format(0);
+}
+
+cbor_item_t* client_api_peer_info_request_encode_format(uint8_t format) {
+ cbor_item_t* array = cbor_new_definite_array(2);
+ cbor_item_t* item = cbor_build_uint8(CLIENT_API_PEER_INFO_REQUEST);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+ item = cbor_build_uint8(format);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+ return array;
+}
+
+int client_api_peer_info_request_decode(cbor_item_t* item, uint8_t* format) {
+ if (item == NULL || format == NULL || !cbor_isa_array(item)) return -1;
+ size_t size = cbor_array_size(item);
+ if (size < 1 || size > 2) return -1;
+
+ cbor_item_t* type_item = cbor_array_get(item, 0);
+ if (!cbor_isa_uint(type_item) ||
+ cbor_get_uint8(type_item) != CLIENT_API_PEER_INFO_REQUEST) {
+ cbor_decref(&type_item);
+ return -1;
+ }
+ cbor_decref(&type_item);
+
+ *format = 0; /* bare [type] frame means raw CBOR, as before */
+ if (size == 2) {
+ cbor_item_t* format_item = cbor_array_get(item, 1);
+ if (!cbor_isa_uint(format_item) || cbor_get_uint8(format_item) > 2) {
+ cbor_decref(&format_item);
+ return -1;
+ }
+ *format = cbor_get_uint8(format_item);
+ cbor_decref(&format_item);
+ }
+ return 0;
+}
+```
+
+- [ ] **Step 5: Run tests to verify they pass**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs --gtest_filter='PeerInfoRequestWire*:PeerConnectWire*'
+```
+
+Expected: PASS.
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add src/ClientAPI/client_api_wire.h src/ClientAPI/client_api_wire.c test/test_qr_wire.cpp test/CMakeLists.txt
+git commit -m "feat(wire): PEER_INFO_REQUEST gains response format byte (2 = PPM QR image)"
+```
+
+---
+
+### Task 4: Shared payload helper + daemon handler format 2 (TDD)
+
+**Files:**
+- Modify: `src/ClientAPI/peer_handlers.h` (add decl)
+- Modify: `src/ClientAPI/peer_handlers.c:96-156, 19-94, 223-306`
+- Create: `test/test_peer_payload.cpp`
+- Modify: `test/CMakeLists.txt` (add `test_peer_payload.cpp`)
+
+- [ ] **Step 1: Write the failing test**
+
+Create `test/test_peer_payload.cpp`:
+
+```cpp
+#include
+#include
+#include
+
+extern "C" {
+#include "../src/ClientAPI/peer_handlers.h"
+#include "../src/QR/qr.h"
+#include "../src/Network/peer_info.h"
+#include
+}
+
+namespace peer_payload_test {
+
+/* A minimal valid peer_info: one DIRECT address, 4-byte public key. */
+static peer_info_t _make_info() {
+ peer_info_t info;
+ memset(&info, 0, sizeof(info));
+ for (size_t i = 0; i < NODE_ID_HASH_SIZE; i++) info.node_id.hash[i] = (uint8_t)(i + 1);
+ snprintf(info.node_id.str, NODE_ID_STRING_SIZE, "testnode");
+ static const uint8_t key[4] = {0xDE, 0xAD, 0xBE, 0xEF};
+ info.public_key = (uint8_t*)key;
+ info.public_key_len = sizeof(key);
+ info.address_count = 1;
+ info.addresses = (peer_address_t*)calloc(1, sizeof(peer_address_t));
+ info.addresses[0].type = PEER_ADDR_DIRECT;
+ info.addresses[0].host = strdup("10.0.0.1");
+ info.addresses[0].port = 23401;
+ return info;
+}
+
+static void _free_info(peer_info_t* info) {
+ free(info->addresses[0].host);
+ free(info->addresses);
+}
+
+TEST(PeerInfoFromPayload, FormatTwoQrImageRoundTrips) {
+ peer_info_t original = _make_info();
+
+ cbor_item_t* encoded = peer_info_encode(&original);
+ ASSERT_NE(encoded, nullptr);
+ size_t serialized_len = cbor_serialized_size(encoded);
+ uint8_t* serialized = (uint8_t*)malloc(serialized_len);
+ ASSERT_GT(cbor_serialize(encoded, serialized, serialized_len), 0u);
+ cbor_decref(&encoded);
+
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm(serialized, serialized_len, &ppm_len);
+ free(serialized);
+ ASSERT_NE(ppm, nullptr);
+
+ peer_info_t decoded;
+ memset(&decoded, 0, sizeof(decoded));
+ ASSERT_EQ(0, peer_info_from_payload(2, ppm, ppm_len, &decoded));
+ free(ppm);
+
+ EXPECT_EQ(0, memcmp(decoded.node_id.hash, original.node_id.hash, NODE_ID_HASH_SIZE));
+ EXPECT_EQ(1u, decoded.address_count);
+ EXPECT_STREQ(decoded.addresses[0].host, "10.0.0.1");
+ EXPECT_EQ(23401, decoded.addresses[0].port);
+ peer_info_destroy(&decoded);
+ _free_info(&original);
+}
+
+TEST(PeerInfoFromPayload, FormatTwoGarbageImageRejected) {
+ peer_info_t decoded;
+ memset(&decoded, 0, sizeof(decoded));
+ const char* garbage = "not an image at all";
+ EXPECT_NE(0, peer_info_from_payload(2, (const uint8_t*)garbage, strlen(garbage), &decoded));
+}
+
+TEST(PeerInfoFromPayload, FormatTwoNonPeerInfoQrRejected) {
+ /* A valid QR whose payload is not peer_info CBOR */
+ const char* payload = "hello, not a peer info map";
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm((const uint8_t*)payload, strlen(payload), &ppm_len);
+ ASSERT_NE(ppm, nullptr);
+
+ peer_info_t decoded;
+ memset(&decoded, 0, sizeof(decoded));
+ EXPECT_NE(0, peer_info_from_payload(2, ppm, ppm_len, &decoded));
+ free(ppm);
+}
+
+TEST(PeerInfoFromPayload, UnknownFormatRejected) {
+ peer_info_t decoded;
+ memset(&decoded, 0, sizeof(decoded));
+ EXPECT_NE(0, peer_info_from_payload(7, (const uint8_t*)"x", 1, &decoded));
+}
+
+} // namespace peer_payload_test
+```
+
+Add `test_peer_payload.cpp` to the test source list.
+
+- [ ] **Step 2: Run test to verify it fails**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc)
+```
+
+Expected: **compile failure** — `peer_info_from_payload` undeclared.
+
+- [ ] **Step 3: Add the helper declaration**
+
+In `src/ClientAPI/peer_handlers.h`, add:
+
+```c
+#include "../Network/peer_info.h"
+#include
+#include
+
+/* Decode a peer_info payload by wire format byte: 0 = raw CBOR peer_info
+ map, 1 = base58 text, 2 = PPM QR image (decoded via src/QR, then parsed
+ as CBOR peer_info). Returns 0 on success, -1 if the payload is not
+ decodable in the given format. Shared by the socket handlers and the
+ HTTP routes so both transports accept exactly the same inputs. */
+int peer_info_from_payload(uint8_t format, const uint8_t* data,
+ size_t data_size, peer_info_t* info);
+```
+
+(Adjust includes to whatever the header already has.)
+
+- [ ] **Step 4: Implement the helper and refactor the handlers**
+
+In `src/ClientAPI/peer_handlers.c`, add the include and the helper, and replace the inline format branches:
+
+```c
+#include "../QR/qr.h"
+
+int peer_info_from_payload(uint8_t format, const uint8_t* data,
+ size_t data_size, peer_info_t* info) {
+ if (info == NULL) return -1;
+
+ if (format == 0) {
+ /* CBOR bytes */
+ struct cbor_load_result load_result;
+ cbor_item_t* decoded = cbor_load(data, data_size, &load_result);
+ if (decoded == NULL || load_result.error.code != CBOR_ERR_NONE) {
+ if (decoded != NULL) cbor_decref(&decoded);
+ return -1;
+ }
+ int rc = peer_info_decode(decoded, info);
+ cbor_decref(&decoded);
+ return rc;
+ }
+
+ if (format == 1) {
+ /* Base58 text */
+ char* b58_str = get_clear_memory(data_size + 1);
+ if (b58_str == NULL) return -1;
+ memcpy(b58_str, data, data_size);
+ b58_str[data_size] = '\0';
+ int rc = peer_info_from_base58(b58_str, info);
+ free(b58_str);
+ return rc;
+ }
+
+ if (format == 2) {
+ /* PPM QR image → payload bytes → CBOR peer_info */
+ size_t payload_len = 0;
+ uint8_t* payload = qr_decode_from_ppm(data, data_size, &payload_len);
+ if (payload == NULL) return -1;
+ struct cbor_load_result load_result;
+ cbor_item_t* decoded = cbor_load(payload, payload_len, &load_result);
+ free(payload);
+ if (decoded == NULL || load_result.error.code != CBOR_ERR_NONE) {
+ if (decoded != NULL) cbor_decref(&decoded);
+ return -1;
+ }
+ int rc = peer_info_decode(decoded, info);
+ cbor_decref(&decoded);
+ return rc;
+ }
+
+ return -1;
+}
+```
+
+In `peer_handle_connect` (lines 108-131), replace the `decode_ok` block:
+
+```c
+ int decode_ok = peer_info_from_payload(msg.format, msg.data, msg.data_size,
+ &remote_info);
+
+ client_api_peer_connect_destroy(&msg);
+```
+
+(delete the old `if (msg.format == 0) {...} else if (msg.format == 1) {...}` branches and the `memset(&remote_info, ...)` stays before the call).
+
+In `peer_handle_friend_add` (lines 243-262), make the same replacement:
+
+```c
+ int decode_ok = peer_info_from_payload(msg.format, msg.data, msg.data_size,
+ new_friend);
+
+ client_api_friend_add_destroy(&msg);
+```
+
+In `peer_handle_info_request` (line 19): stop discarding the frame and honor the requested format.
+
+Add after the auth check:
+
+```c
+ uint8_t format = 0;
+ if (client_api_peer_info_request_decode(frame, &format) != 0) {
+ ctx->send_error(ctx->conn, CLIENT_API_STATUS_BAD_REQUEST,
+ "Invalid peer info request");
+ return;
+ }
+```
+
+Remove the `(void)frame;` line. Then change the response-building tail (lines 84-93) to:
+
+```c
+ /* Build and send response */
+ client_api_peer_info_response_t response;
+ memset(&response, 0, sizeof(response));
+
+ if (format == 2) {
+ /* PPM QR image — ownership of the encoded image transfers to the
+ response struct, which frees it in client_api_peer_info_response_destroy. */
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm(serialized, bytes_serialized, &ppm_len);
+ free(serialized);
+ if (ppm == NULL) {
+ ctx->send_error(ctx->conn, CLIENT_API_STATUS_INTERNAL_ERROR,
+ "QR encoding failed");
+ return;
+ }
+ response.format = 2;
+ response.data = ppm;
+ response.data_size = ppm_len;
+ } else {
+ response.format = format; /* 0 = raw CBOR */
+ response.data = serialized;
+ response.data_size = bytes_serialized;
+ }
+
+ cbor_item_t* out_frame = client_api_peer_info_response_encode(&response);
+ ctx->send_frame(ctx->conn, out_frame);
+```
+
+(The `free(serialized)` before the QR branch replaces the old ownership: previously `serialized` was handed to the response directly — in format 0 it still is.)
+
+- [ ] **Step 5: Run tests to verify they pass**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs --gtest_filter='PeerInfoFromPayload*:PeerInfoRequestWire*'
+```
+
+Expected: PASS.
+
+- [ ] **Step 6: Run the full suite to catch regressions in the refactored handlers**
+
+```bash
+./build/test/testliboffs
+```
+
+Expected: all tests PASS (no new failures — the unix/ws transport peer tests exercise these handlers).
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add src/ClientAPI/peer_handlers.h src/ClientAPI/peer_handlers.c test/test_peer_payload.cpp test/CMakeLists.txt
+git commit -m "feat(peers): decode QR images (format 2) in socket peer handlers"
+```
+
+---
+
+### Task 5: HTTP peer routes — vendored encoder + PPM bodies
+
+**Files:**
+- Modify: `src/ClientAPI/HTTP/peer_routes.c` (includes at 22-24; `_peer_info_handler` 155-260; `_decode_peer_info_body` 105-125)
+
+- [ ] **Step 1: Swap the qrencode include for the QR module**
+
+Remove:
+
+```c
+#ifdef HAS_QRENCODE
+#include
+#endif
+```
+
+Add (with the other project includes):
+
+```c
+#include "../../QR/qr.h"
+```
+
+- [ ] **Step 2: Simplify `_peer_info_handler`'s QR branch**
+
+Delete both `#ifdef HAS_QRENCODE` ... `#endif` regions (the render block at ~179-244 and the 501 stub at ~246-254) and replace the QR branch with:
+
+```c
+ if (strcmp(format, "qrcode") == 0) {
+ cbor_item_t* cbor_map = peer_info_encode(info);
+ if (cbor_map == NULL) {
+ http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ http_response_set_header(response, "Content-Type", "text/plain");
+ http_response_write(response, "Failed to encode peer info", 25);
+ http_response_end(response);
+ peer_info_destroy(info);
+ free(info);
+ return;
+ }
+
+ uint8_t* serialized = NULL;
+ size_t serialized_len = _serialize_cbor(cbor_map, &serialized);
+ cbor_decref(&cbor_map);
+ if (serialized_len == 0) {
+ http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ http_response_set_header(response, "Content-Type", "text/plain");
+ http_response_write(response, "CBOR serialization failed", 25);
+ http_response_end(response);
+ peer_info_destroy(info);
+ free(info);
+ return;
+ }
+
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm(serialized, serialized_len, &ppm_len);
+ free(serialized);
+ if (ppm == NULL) {
+ http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ http_response_set_header(response, "Content-Type", "text/plain");
+ http_response_write(response, "QR encoding failed", 18);
+ http_response_end(response);
+ peer_info_destroy(info);
+ free(info);
+ return;
+ }
+
+ http_response_set_status(response, HTTP_STATUS_OK);
+ http_response_set_header(response, "Content-Type", "image/x-portable-pixmap");
+ http_response_write(response, (const char*)ppm, ppm_len);
+ free(ppm);
+ http_response_end(response);
+ peer_info_destroy(info);
+ free(info);
+ return;
+ }
+```
+
+The generated image stays byte-identical to the old output (same `QR_ECLEVEL_M`, same 4x scale — Task 2 moved the rendering verbatim).
+
+- [ ] **Step 3: Accept PPM bodies in `_decode_peer_info_body`**
+
+Add this branch at the top of the Content-Type dispatch (before the base58 default), and make the CBOR branch use the shared helper so both transports accept identical inputs:
+
+```c
+#include "../peer_handlers.h" /* peer_info_from_payload */
+```
+
+```c
+static int _decode_peer_info_body(http_request_t* request, peer_info_t* info) {
+ const char* content_type = http_request_header(request, "Content-Type");
+
+ if (content_type != NULL && strstr(content_type, "image/x-portable-pixmap") != NULL) {
+ /* QR image body — decode via the shared payload helper (format 2) */
+ if (request->body == NULL || request->body->size == 0) return -1;
+ return peer_info_from_payload(2, request->body->data, request->body->size, info);
+ }
+
+ if (content_type != NULL && strstr(content_type, "application/cbor") != NULL) {
+ if (request->body == NULL || request->body->size == 0) return -1;
+ return peer_info_from_payload(0, request->body->data, request->body->size, info);
+ }
+
+ /* Default: base58 text (text/plain or no Content-Type) */
+ if (request->body == NULL || request->body->size == 0) return -1;
+ return peer_info_from_payload(1, request->body->data, request->body->size, info);
+}
+```
+
+This replaces the existing inline CBOR/base58 branches in `_decode_peer_info_body` (lines 105-125) — the old code is functionally identical to formats 0/1 of the helper, so the two transports can no longer drift.
+
+- [ ] **Step 4: Build and run the full suite**
+
+```bash
+cmake --build build -j$(nproc) && ./build/test/testliboffs
+```
+
+Expected: builds without `HAS_QRENCODE` anywhere; all tests PASS.
+
+- [ ] **Step 5: Confirm the 501 path is gone**
+
+```bash
+grep -rn "HAS_QRENCODE\|QR code generation not available" src/
+```
+
+Expected: no output.
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add src/ClientAPI/HTTP/peer_routes.c
+git commit -m "feat(http): QR peer info via vendored encoder; accept PPM QR bodies on connect/friend"
+```
+
+---
+
+### Task 6: C client library — peer/QR functions
+
+**Files:**
+- Modify: `src/ClientLibs/c/offs_client.h` (callback decls ~52-61, new functions after `offs_client_health` at ~124)
+- Modify: `src/ClientLibs/c/offs_client.c` (struct fields ~151-166, `_handle_frame` switch ~530, new functions after `offs_client_health` at ~1855)
+
+The C client currently has **no** peer functions — these are all new, following the `offs_client_health` pattern (store callback under lock, encode request, `_send_frame`, dispatch in `_handle_frame`).
+
+- [ ] **Step 1: Add callback typedefs and function decls to offs_client.h**
+
+After the existing callback typedefs (~line 61):
+
+```c
+typedef void (*offs_peer_info_cb_t)(void* ctx, uint8_t format, const uint8_t* data, size_t data_len);
+typedef void (*offs_peer_connect_cb_t)(void* ctx, uint8_t status);
+typedef void (*offs_friend_list_cb_t)(void* ctx, cbor_item_t* friends);
+```
+
+After `offs_client_health` (~line 124):
+
+```c
+/* Peer operations. format: 0 = raw CBOR peer_info, 1 = base58 text,
+ 2 = PPM QR image. The _qr forms are sugar for format 2. */
+int offs_client_peer_info(offs_client_t* client, offs_peer_info_cb_t callback, void* ctx);
+int offs_client_peer_info_ex(offs_client_t* client, uint8_t format,
+ offs_peer_info_cb_t callback, void* ctx);
+int offs_client_peer_connect(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+int offs_client_peer_connect_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+int offs_client_friend_add(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+int offs_client_friend_add_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+```
+
+(`offs_client.h` already transitively sees `cbor.h` via wire includes; add `#include ` if not.)
+
+- [ ] **Step 2: Add struct fields and dispatch**
+
+In the `offs_client` struct (offs_client.c ~line 151-166) add:
+
+```c
+ offs_peer_info_cb_t peer_info_cb;
+ void* peer_info_cb_ctx;
+ offs_peer_connect_cb_t peer_connect_cb;
+ void* peer_connect_cb_ctx;
+```
+
+In the `_handle_frame` callback-snapshot block (after `health_cb_ctx`) add:
+
+```c
+ offs_peer_info_cb_t peer_info_cb = client->peer_info_cb;
+ void* peer_info_cb_ctx = client->peer_info_cb_ctx;
+ offs_peer_connect_cb_t peer_connect_cb = client->peer_connect_cb;
+ void* peer_connect_cb_ctx = client->peer_connect_cb_ctx;
+```
+
+In the switch, add two cases before `default:`:
+
+```c
+ case CLIENT_API_PEER_INFO_RESPONSE: {
+ client_api_peer_info_response_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_peer_info_response_decode(frame, &msg) == 0) {
+ if (peer_info_cb != NULL) {
+ peer_info_cb(peer_info_cb_ctx, msg.format, msg.data, msg.data_size);
+ }
+ client_api_peer_info_response_destroy(&msg);
+ }
+ break;
+ }
+ case CLIENT_API_PEER_CONNECT_RESULT: {
+ client_api_peer_connect_result_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_peer_connect_result_decode(frame, &msg) == 0) {
+ if (peer_connect_cb != NULL) {
+ peer_connect_cb(peer_connect_cb_ctx, msg.status);
+ }
+ client_api_peer_connect_result_destroy(&msg);
+ }
+ break;
+ }
+```
+
+(`FRIEND_ADD` replies reuse `CLIENT_API_PEER_CONNECT_RESULT` — `peer_handle_friend_add` sends exactly that frame, so one callback type covers both.)
+
+- [ ] **Step 3: Implement the functions**
+
+After `offs_client_health` (offs_client.c ~line 1855):
+
+```c
+int offs_client_peer_info_ex(offs_client_t* client, uint8_t format,
+ offs_peer_info_cb_t callback, void* ctx) {
+ if (client == NULL || !client->connected) return -1;
+
+ platform_mutex_lock(client->lock);
+ client->peer_info_cb = callback;
+ client->peer_info_cb_ctx = ctx;
+ platform_mutex_unlock(client->lock);
+
+ cbor_item_t* frame = (format == 0)
+ ? client_api_peer_info_request_encode()
+ : client_api_peer_info_request_encode_format(format);
+ _send_frame(client, frame);
+ return 0;
+}
+
+int offs_client_peer_info(offs_client_t* client,
+ offs_peer_info_cb_t callback, void* ctx) {
+ return offs_client_peer_info_ex(client, 0, callback, ctx);
+}
+
+int offs_client_peer_connect(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ if (client == NULL || !client->connected || data == NULL || data_len == 0) return -1;
+
+ platform_mutex_lock(client->lock);
+ client->peer_connect_cb = callback;
+ client->peer_connect_cb_ctx = ctx;
+ platform_mutex_unlock(client->lock);
+
+ client_api_peer_connect_t msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.format = format;
+ msg.data = (uint8_t*)data;
+ msg.data_size = data_len;
+
+ cbor_item_t* frame = client_api_peer_connect_encode(&msg);
+ _send_frame(client, frame);
+ return 0;
+}
+
+int offs_client_peer_connect_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ return offs_client_peer_connect(client, 2, ppm, ppm_len, callback, ctx);
+}
+
+int offs_client_friend_add(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ if (client == NULL || !client->connected || data == NULL || data_len == 0) return -1;
+
+ platform_mutex_lock(client->lock);
+ client->peer_connect_cb = callback;
+ client->peer_connect_cb_ctx = ctx;
+ platform_mutex_unlock(client->lock);
+
+ client_api_friend_add_t msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.format = format;
+ msg.data = (uint8_t*)data;
+ msg.data_size = data_len;
+
+ cbor_item_t* frame = client_api_friend_add_encode(&msg);
+ _send_frame(client, frame);
+ return 0;
+}
+
+int offs_client_friend_add_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ return offs_client_friend_add(client, 2, ppm, ppm_len, callback, ctx);
+}
+```
+
+- [ ] **Step 4: Build and run the suite**
+
+```bash
+cmake --build build -j$(nproc) && ./build/test/testliboffs --gtest_filter='OffsClient*'
+```
+
+Expected: builds; existing client tests still PASS (the new callback fields default to NULL and the new response cases are additive).
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/ClientLibs/c/offs_client.h src/ClientLibs/c/offs_client.c
+git commit -m "feat(client): C client library peer info/connect/friend-add with QR format support"
+```
+
+---
+
+### Task 7: JS client QR support
+
+**Files:**
+- Modify: `src/ClientLibs/js/offs-client/src/wire.js:269-270`
+- Modify: `src/ClientLibs/js/offs-client/src/transports/http-transport.js:275-330`
+- Modify: `src/ClientLibs/js/offs-client/src/index.js:396-460`
+
+- [ ] **Step 1: `wire.js` — request frame gains the format byte**
+
+Replace:
+
+```js
+export function encodePeerInfoRequest() {
+ return encoder.encode([MSG.PEER_INFO_REQUEST]);
+}
+```
+
+with:
+
+```js
+export function encodePeerInfoRequest(format = 0) {
+ if (format === 0) {
+ return encoder.encode([MSG.PEER_INFO_REQUEST]); // old 1-element shape
+ }
+ return encoder.encode([MSG.PEER_INFO_REQUEST, format]);
+}
+```
+
+(Keep the 1-element shape for format 0 so old daemons can parse new clients' requests.)
+
+- [ ] **Step 2: `http-transport.js` — Content-Type by format, and pass format through**
+
+Update the body-dispatch helper used by `peerConnect` (line 292-299) and `friendAdd` (line 321-328). Both currently send `format === 1 ? text : peerInfo` with a single hard-coded Content-Type. Change both to:
+
+```js
+const CONTENT_TYPES = { 0: 'application/cbor', 1: 'text/plain', 2: 'image/x-portable-pixmap' };
+```
+
+and in each method:
+
+```js
+const response = await fetch(this.url('/peer/connect'), {
+ method: 'POST',
+ headers: { 'Content-Type': CONTENT_TYPES[format] ?? 'application/cbor' },
+ body: format === 1 ? new TextDecoder().decode(peerInfo) : peerInfo,
+});
+```
+
+(same for `/friends`). Also verify `peerInfo(format)` (line 275): it already passes the string through to `?format=${format}` — the daemon accepts `cbor|base58|qrcode`, so `'qrcode'` needs no change. Make it return the raw PPM `Uint8Array` for `qrcode` if it doesn't already (check the existing response handling and keep its behavior; only the Content-Type dispatch above is a required change).
+
+- [ ] **Step 3: `index.js` — pass format on CBOR transports, add QR sugar**
+
+In `peerInfo` (line 396), map the JS format string to the wire byte and pass it:
+
+```js
+const FORMAT_WIRE = { cbor: 0, base58: 1, qrcode: 2 };
+
+async peerInfo(format = 'cbor') {
+ if (this.transport instanceof HttpTransport) {
+ return this.transport.peerInfo(format);
+ }
+
+ const requestBytes = wire.encodePeerInfoRequest(FORMAT_WIRE[format] ?? 0);
+ const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_INFO_RESPONSE);
+ return wire.decodePeerInfoResponse(responseBytes);
+}
+```
+
+Add sugar methods after `peerConnect`:
+
+```js
+/**
+ * Connect to a peer from a QR image (binary P6 PPM bytes).
+ * @param {Uint8Array} ppmBytes
+ * @returns {Promise<{status: number}>}
+ */
+async peerConnectQr(ppmBytes) {
+ return this.peerConnect(ppmBytes, 2);
+}
+
+/**
+ * Add a friend from a QR image (binary P6 PPM bytes).
+ * @param {Uint8Array} ppmBytes
+ * @returns {Promise}
+ */
+async friendAddQr(ppmBytes) {
+ return this.friendAdd(ppmBytes, 2);
+}
+```
+
+- [ ] **Step 4: Build the package**
+
+```bash
+cd src/ClientLibs/js/offs-client && npm install && npm run build
+```
+
+Expected: build succeeds; `dist/offs-client.esm.js` and `dist/offs-client.umd.js` regenerate (they are tracked in git).
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/ClientLibs/js/offs-client
+git commit -m "feat(js-client): QR peer info/connect/friend support (format byte 2)"
+```
+
+---
+
+### Task 8: CLI `--qr` flags
+
+**Files:**
+- Modify: `OFFS/src/offs/commands/peer.c` (info at 25-56, connect at 85-120)
+- Modify: `OFFS/src/offs/commands/friend.c` (add at 18-48)
+
+- [ ] **Step 1: `offs peer info --qr `**
+
+In `cmd_peer`, replace the `info` block's fixed request with flag parsing:
+
+```c
+ if (strcmp(subcommand, "info") == 0) {
+ uint8_t format = 0;
+ const char* qr_path = NULL;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--qr") == 0 && i + 1 < argc) {
+ format = 2; /* PPM QR image */
+ qr_path = argv[++i];
+ } else {
+ printf("Usage: offs peer info [--qr |-]\n");
+ return 1;
+ }
+ }
+
+ cbor_item_t* request = client_api_peer_info_request_encode_format(format);
+ cbor_item_t* response = cli_client_send(client, request);
+ cbor_decref(&request);
+
+ if (response != NULL) {
+ uint8_t type = client_api_wire_get_type(response);
+ if (type == CLIENT_API_PEER_INFO_RESPONSE) {
+ client_api_peer_info_response_t peer_resp;
+ memset(&peer_resp, 0, sizeof(peer_resp));
+ if (client_api_peer_info_response_decode(response, &peer_resp) == 0) {
+ if (format == 2) {
+ /* Write the PPM image to qr_path ("-" = stdout) */
+ FILE* out = (strcmp(qr_path, "-") == 0)
+ ? stdout
+ : fopen(qr_path, "wb");
+ if (out == NULL) {
+ fprintf(stderr, "cannot open %s\n", qr_path);
+ } else {
+ fwrite(peer_resp.data, 1, peer_resp.data_size, out);
+ if (out != stdout) fclose(out);
+ }
+ } else {
+ /* existing base58 output path, unchanged */
+ size_t b58_len = base58_encoded_length(peer_resp.data_size) + 1;
+ char* b58 = (char*)malloc(b58_len);
+ if (b58 != NULL) {
+ int enc_rc = base58_encode(peer_resp.data, peer_resp.data_size,
+ b58, b58_len);
+ if (enc_rc > 0) {
+ b58[enc_rc] = '\0';
+ printf("%s\n", L10N_PEER_INFO_PROMPT);
+ printf(" Data: %s\n", b58);
+ }
+ free(b58);
+ }
+ }
+ client_api_peer_info_response_destroy(&peer_resp);
+ }
+ } else if (type == CLIENT_API_ERROR) {
+ client_api_error_t err_msg;
+ memset(&err_msg, 0, sizeof(err_msg));
+ if (client_api_error_decode(response, &err_msg) == 0) {
+ fprintf(stderr, "%s: %s\n", L10N_ERROR, err_msg.message);
+ client_api_error_destroy(&err_msg);
+ }
+ }
+ cbor_decref(&response);
+ }
+ return 0;
+ }
+```
+
+- [ ] **Step 2: `offs peer connect --qr `**
+
+Replace the fixed `peer_con` block (lines 89-95) with:
+
+```c
+ uint8_t format = 1; /* default: base58 text (existing behavior) */
+ uint8_t* file_data = NULL;
+ size_t file_size = 0;
+
+ if (strcmp(argv[1], "--qr") == 0) {
+ if (argc < 3) {
+ fprintf(stderr, "%s\n", L10N_PEER_CONNECT_USAGE);
+ return 1;
+ }
+ FILE* input = fopen(argv[2], "rb");
+ if (input == NULL) {
+ fprintf(stderr, "cannot open %s\n", argv[2]);
+ return 1;
+ }
+ fseek(input, 0, SEEK_END);
+ long file_len = ftell(input);
+ fseek(input, 0, SEEK_SET);
+ file_data = (uint8_t*)malloc((size_t)file_len);
+ if (file_data == NULL || fread(file_data, 1, (size_t)file_len, input) != (size_t)file_len) {
+ fprintf(stderr, "cannot read %s\n", argv[2]);
+ fclose(input);
+ free(file_data);
+ return 1;
+ }
+ fclose(input);
+ file_size = (size_t)file_len;
+ format = 2;
+ }
+
+ client_api_peer_connect_t peer_con;
+ memset(&peer_con, 0, sizeof(peer_con));
+ peer_con.format = format;
+ peer_con.data = file_data != NULL ? file_data : (uint8_t*)argv[1];
+ peer_con.data_size = file_data != NULL ? file_size : strlen(argv[1]);
+```
+
+and before every `return` in the connect branch, free the buffer: add `free(file_data);` after the response handling (the data pointer is only borrowed by the encode — `client_api_peer_connect_encode` copies). The cleanest spot: immediately after `cbor_decref(&request)`.
+
+- [ ] **Step 3: `offs friend add [--qr | ]`**
+
+Same pattern in `cmd_friend`'s `add` branch: if `argv[1] == "--qr"`, read `argv[2]` into a malloc'd buffer (identical code to Step 2), set `friend_req.format = 2` and point `friend_req.data`/`data_size` at the buffer; otherwise keep the existing format-0/base58 path. Free the buffer after `cbor_decref(&request)`.
+
+- [ ] **Step 4: Rebuild the CLI**
+
+The `offs` CLI lives in the sibling OFFS project (`OFFS/deps/liboffs` is a checkout of this repo). Rebuild there per its build docs; if the OFFS build is not available in this environment, verify by inspection and note it in the ticket.
+
+```bash
+cmake --build OFFS/deps/liboffs/build -j$(nproc) 2>&1 | tail -3 || echo "OFFS build not configured in this environment"
+```
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add OFFS/src/offs/commands/peer.c OFFS/src/offs/commands/friend.c
+git commit -m "feat(cli): offs peer info/connect and friend add accept --qr PPM files"
+```
+
+---
+
+### Task 9: Manual end-to-end verification (HTTP + CLI)
+
+**Files:** none (verification only)
+
+- [ ] **Step 1: Start the example server**
+
+```bash
+cmake --build build -j$(nproc) && ./build/examples/off_server --port 23482 &
+```
+
+(Use a non-default port so this doesn't collide with a running daemon. Note: the example server registers peer routes only with auth configured — if peer routes are missing, run it with `--api-key testkey` and pass `-H "Authorization: Bearer testkey"` to every curl below.)
+
+- [ ] **Step 2: HTTP generate → HTTP decode round trip**
+
+```bash
+curl -s -H "Authorization: Bearer testkey" \
+ "http://127.0.0.1:23482/peer/info?format=qrcode" -o /tmp/peer_qr.ppm
+file /tmp/peer_qr.ppm # or: head -c 20 /tmp/peer_qr.ppm
+curl -s -H "Authorization: Bearer testkey" \
+ -H "Content-Type: image/x-portable-pixmap" \
+ --data-binary @/tmp/peer_qr.ppm \
+ "http://127.0.0.1:23482/peer/connect"
+```
+
+Expected: the file starts with `P6`; the connect response is JSON `{"status": ..., "message": ...}` — status 0/3/4 are all acceptable here (the peer is ourselves / unreachable); the important part is it is **not** a 400 decode failure.
+
+```bash
+curl -s -H "Authorization: Bearer testkey" \
+ -H "Content-Type: image/x-portable-pixmap" \
+ --data-binary "garbage" \
+ "http://127.0.0.1:23482/peer/connect" -w "\n%{http_code}\n"
+```
+
+Expected: `400` (image decode failure).
+
+- [ ] **Step 3: Verify base58 path still works** (backward compat)
+
+```bash
+curl -s -H "Authorization: Bearer testkey" \
+ "http://127.0.0.1:23482/peer/info?format=base58" -o /tmp/peer_b58.txt
+curl -s -H "Authorization: Bearer testkey" \
+ --data-binary @/tmp/peer_b58.txt \
+ "http://127.0.0.1:23482/peer/connect"
+```
+
+Expected: JSON status response, not 400.
+
+- [ ] **Step 4: Stop the server**
+
+```bash
+kill %1
+```
+
+- [ ] **Step 5: Post verification evidence to the ticket**
+
+```bash
+H=/home/victor/.claude/skills/harmony/harmony
+$H comment add OFFS-187 "Manual HTTP round trip verified: GET /peer/info?format=qrcode → P6 PPM; POST /peer/connect with Content-Type image/x-portable-pixmap decodes it; garbage image → 400; base58 path unchanged."
+```
+
+---
+
+### Task 10: Docs, leak check, ticket close
+
+**Files:**
+- Modify: `docs/OFFS_API_CLI_SPEC.md`
+
+- [ ] **Step 1: Update the API spec doc**
+
+In `docs/OFFS_API_CLI_SPEC.md`:
+- §2.4 `GET /peer/info`: remove the "requires `HAS_QRENCODE`; else `501`" caveat — QR generation is now always available (vendored libqrencode).
+- §2.4 `POST /peer/connect` and `POST /friends`: add third accepted body type: `image/x-portable-pixmap` — daemon decodes the QR (P6 PPM) and parses the peer info; 400 on decode failure.
+- §3 wire table: `PEER_INFO_REQUEST` is `[21]` or `[21, format]` (0 = raw CBOR, 1 = base58, **2 = PPM QR image**); `PEER_CONNECT`/`FRIEND_ADD` accept format 2 with a PPM image payload.
+- §9 checklist: mark QR display/scan as supported server-side (HTTP `?format=qrcode`, wire format 2, `--qr` CLI flags).
+
+- [ ] **Step 2: Run the full test suite under valgrind** (project convention: rebuild with `-gdwarf-4` if valgrind chokes on DWARF5)
+
+```bash
+cd build && cmake -DCMAKE_C_FLAGS="-gdwarf-4" -DCMAKE_CXX_FLAGS="-gdwarf-4" . && make testliboffs -j$(nproc) && valgrind --leak-check=full --error-exitcode=1 ./test/testliboffs --gtest_filter='Qr*:PeerInfoFromPayload*:PeerInfoRequestWire*'
+```
+
+Expected: 0 leaks, 0 errors in the new tests. (Pre-existing scheduler shutdown error at scheduler.c:119 is a known non-issue — see project memory.)
+
+- [ ] **Step 3: Run the de-wonk audit**
+
+Invoke the `de-wonk` skill per CLAUDE.md before declaring the work done, and resolve anything it finds (in particular: no stray `HAS_QRENCODE` conditionals, no TODOs in touched files, `dist/` rebuilt and committed).
+
+- [ ] **Step 4: Close the Harmony ticket**
+
+```bash
+H=/home/victor/.claude/skills/harmony/harmony
+$H ticket close OFFS-187 "QR peer connect shipped: libqrencode+quirc vendored, src/QR codec, wire format byte 2 on PEER_INFO/PEER_CONNECT/FRIEND_ADD, HTTP PPM bodies, C client peer ops, JS client QR methods, CLI --qr flags. Tests: test_qr, test_qr_wire, test_peer_payload + manual HTTP round trip."
+```
+
+Then execute the required actions the close response emits (`write_session_summary`, `tag_notify_list`).
+
+- [ ] **Step 5: Final commit**
+
+```bash
+git add docs/OFFS_API_CLI_SPEC.md
+git commit -m "docs: document QR peer-info format 2 across API spec"
+```
+
+---
+
+## Self-Review Notes
+
+- **Spec coverage:** spec §1 (deps/build) → Task 1; §2 (src/QR) → Task 2; §3 (wire) → Task 3; §4 daemon handlers → Task 4; §4 HTTP → Task 5; §5 C client → Task 6; §5 JS → Task 7; §6 CLI → Task 8; §7 errors → covered by helper statuses in Tasks 4/5 and verified in Task 9; §8 testing → Tasks 2-4 unit tests + Task 9 manual + Task 10 valgrind. Spec §8's "test_peer_routes.cpp HTTP round trip" is replaced by the manual curl verification (deviation noted in the header).
+- **Type consistency:** format byte 2 used uniformly; `peer_info_from_payload(format, data, size, info)` signature consistent across Tasks 4/5; `qr_encode_to_ppm`/`qr_decode_from_ppm` signatures match between Tasks 2, 4, 5.
+- **Backward compat:** `client_api_peer_info_request_encode()` keeps its old signature; 1-element frames still decode to format 0; `peer_connect`/`friend_add` decoders never validated format values, so old frames flow unchanged.
\ No newline at end of file
diff --git a/docs/superpowers/plans/2026-08-29-cache-load.md b/docs/superpowers/plans/2026-08-29-cache-load.md
new file mode 100644
index 00000000..bbf34f8d
--- /dev/null
+++ b/docs/superpowers/plans/2026-08-29-cache-load.md
@@ -0,0 +1,700 @@
+# Cache Load Command Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** A `load` command on every client surface (HTTP `?load=1`, wire frames 39–41, C client, JS client, Dart binding, `offs load` CLI) that pulls a file's tuples into the daemon's block cache without transferring file data, streaming tuple-level progress to the client.
+
+**Architecture:** A `load_mode` flag on `readable_off_stream` makes tuple-level block failures skip the tuple (and tally it) instead of tearing down the stream; every consumer reuses the pipeline's existing events. A shared load-consumer shape forwards progress as ndjson lines (HTTP `GET ...?load=1`) or as new wire frames `LOAD_PROGRESS 40` / `LOAD_END 41`, requested by `LOAD_REQUEST 39` (GET_REQUEST-shaped). C/JS/Dart bindings and the CLI are thin wrappers.
+
+**Tech Stack:** C (liboffs core + ClientAPI), libcbor, GTest, JS (offs-client, vite), Dart/Flutter (off_api.dart), the `offs` CLI (OFFS repo).
+
+**Spec:** `docs/superpowers/specs/2026-08-28-cache-load-design.md`
+
+**Working agreement (from the QR feature execution):**
+- Subagents stage ONLY the files each task lists; the repo has unrelated uncommitted user work (src/Actor, src/BlockCache, demo/, docs/ARCHITECTURE.md, src/ClientLibs/js/offs-client/src/ofd.js, etc.) — never stage it. No Co-Authored-By lines. No TODOs in completed work (CLAUDE.md).
+- Full-suite gate: `cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs` (875 tests / 186 suites green at plan time; counts grow).
+- TDD on every code task: failing test first, observed failure, then implement.
+- `dist/` files are gitignored-but-tracked: stage them by explicit path.
+
+---
+
+## File Structure
+
+| File | Action | Responsibility |
+|---|---|---|
+| `src/OFFStreams/readable_off_stream.h/.c` | Modify | `load_mode` flag: skip-on-tuple-miss, tallies, `tuple_loaded_event` |
+| `src/Streams/stream.h` | Modify | New event enum value `tuple_loaded_event = 15` |
+| `test/test_readable_load.cpp` | Create | Load-mode stream unit tests |
+| `src/ClientAPI/client_api_wire.h/.c` | Modify | `LOAD_REQUEST 39` / `LOAD_PROGRESS 40` / `LOAD_END 41` |
+| `test/test_load_wire.cpp` | Create | Wire frame tests |
+| `src/ClientAPI/HTTP/off_routes.c` | Modify | `?load=1` branch → ndjson streaming |
+| `src/ClientAPI/Unix/unix_connection.c` | Modify | `LOAD_REQUEST` dispatch → frames 40/41 |
+| `src/ClientAPI/WS/ws_connection.c` | Modify | Load dispatch (mirrors its GET subset) |
+| `src/ClientAPI/TCP/tcp_connection.c` | Modify | Load dispatch (mirrors its GET support) |
+| `src/ClientLibs/c/offs_client.h/.c` | Modify | `offs_client_load` + callbacks + dispatch |
+| `src/ClientLibs/js/offs-client/src/{wire.js,index.js,transports/http-transport.js}` | Modify | `load()` both transports; `dist/` rebuilt |
+| `examples/off_client/lib/services/off_api.dart` | Modify | `load()` + QR catch-up (`connectPeerImage`/`addFriendImage`) |
+| `OFFS/src/offs/commands/load.c` (OFFS repo) | Create | `offs load ` |
+| `OFFS/src/offs/cli_util.c`, `OFFS/src/offs/l10n/en.h` | Modify | Register command, usage strings |
+| `test/test_off_routes_load.cpp` | Create | `?load=1` ndjson surface test |
+| `docs/OFFS_API_CLI_SPEC.md` | Modify | Document the load surface |
+
+Task order (each builds on the last): 1 wire frames → 2 stream load-mode + tests → 3 unix transport → 4 HTTP → 5 WS/TCP → 6 C client → 7 JS client → 8 Dart binding → 9 CLI → 10 e2e + docs + close.
+
+---
+
+### Task 1: Wire frames 39/40/41 (TDD)
+
+**Files:**
+- Modify: `src/ClientAPI/client_api_wire.h` (message-type defines ~line 45, structs ~line 100-110 near GET frames, decls near the GET encoders)
+- Modify: `src/ClientAPI/client_api_wire.c` (encode/decode next to the GET implementations at ~line 363)
+- Create: `test/test_load_wire.cpp`
+- Modify: `test/CMakeLists.txt` (add `test_load_wire.cpp` to the `add_executable(testliboffs ...)` list, next to `test_qr_wire.cpp`)
+
+- [ ] **Step 1: Write the failing test** — create `test/test_load_wire.cpp`:
+
+```cpp
+#include
+#include
+
+extern "C" {
+#include "../src/ClientAPI/client_api_wire.h"
+#include
+}
+
+namespace load_wire_test {
+
+static client_api_load_request_t _make_req(const char* ori, uint8_t has_range,
+ size_t start, size_t end) {
+ client_api_load_request_t req;
+ memset(&req, 0, sizeof(req));
+ req.ori_string = (char*)ori;
+ req.has_range = has_range;
+ req.range_start = start;
+ req.range_end = end;
+ return req;
+}
+
+TEST(LoadRequestWire, EncodeDecodeRoundTripNoRange) {
+ client_api_load_request_t req = _make_req("http://n/offsystem/v3/standard/10/a/b/f", 0, 0, 0);
+ cbor_item_t* frame = client_api_load_request_encode(&req);
+ ASSERT_NE(frame, nullptr);
+
+ client_api_load_request_t decoded;
+ memset(&decoded, 0, sizeof(decoded));
+ ASSERT_EQ(0, client_api_load_request_decode(frame, &decoded));
+ EXPECT_STREQ(decoded.ori_string, req.ori_string);
+ EXPECT_EQ(0, decoded.has_range);
+
+ client_api_load_request_destroy(&decoded);
+ client_api_load_request_destroy(&req);
+ cbor_decref(&frame);
+}
+
+TEST(LoadRequestWire, EncodeDecodeRoundTripWithRange) {
+ client_api_load_request_t req = _make_req("ori-string", 1, 128000, 256000);
+ cbor_item_t* frame = client_api_load_request_encode(&req);
+ ASSERT_NE(frame, nullptr);
+
+ client_api_load_request_t decoded;
+ memset(&decoded, 0, sizeof(decoded));
+ ASSERT_EQ(0, client_api_load_request_decode(frame, &decoded));
+ EXPECT_EQ(1, decoded.has_range);
+ EXPECT_EQ(128000u, decoded.range_start);
+ EXPECT_EQ(256000u, decoded.range_end);
+
+ client_api_load_request_destroy(&decoded);
+ client_api_load_request_destroy(&req);
+ cbor_decref(&frame);
+}
+
+TEST(LoadProgressWire, EncodesCounts) {
+ /* [40, tuples_loaded, tuples_total] */
+ cbor_item_t* frame = client_api_load_progress_encode(7, 20);
+ ASSERT_NE(frame, nullptr);
+ size_t loaded = 0, total = 0;
+ ASSERT_EQ(0, client_api_load_progress_decode(frame, &loaded, &total));
+ EXPECT_EQ(7u, loaded);
+ EXPECT_EQ(20u, total);
+ cbor_decref(&frame);
+}
+
+TEST(LoadEndWire, EncodesFullTally) {
+ /* [41, status, tuples_loaded, tuples_total] */
+ cbor_item_t* frame = client_api_load_end_encode(1, 180, 200);
+ ASSERT_NE(frame, nullptr);
+
+ uint8_t status = 99;
+ size_t loaded = 0, total = 0;
+ ASSERT_EQ(0, client_api_load_end_decode(frame, &status, &loaded, &total));
+ EXPECT_EQ(1, status);
+ EXPECT_EQ(180u, loaded);
+ EXPECT_EQ(200u, total);
+ cbor_decref(&frame);
+}
+
+TEST(LoadWire, FrameTypesDoNotCollide) {
+ EXPECT_EQ(39, CLIENT_API_LOAD_REQUEST);
+ EXPECT_EQ(40, CLIENT_API_LOAD_PROGRESS);
+ EXPECT_EQ(41, CLIENT_API_LOAD_END);
+}
+
+} // namespace load_wire_test
+```
+
+Add `test_load_wire.cpp` to the test source list (one line).
+
+- [ ] **Step 2: Run to verify compile failure**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc)
+```
+Expected: undeclared `client_api_load_request_encode` etc.
+
+- [ ] **Step 3: Header additions** — in `src/ClientAPI/client_api_wire.h`:
+
+With the other type defines (~line 38, between CONFIG_RELOAD_RESPONSE 38 and ERROR 11... place numerically with the others):
+
+```c
+#define CLIENT_API_LOAD_REQUEST 39
+#define CLIENT_API_LOAD_PROGRESS 40
+#define CLIENT_API_LOAD_END 41
+```
+
+Structs (after the GET group, mirroring `client_api_get_request_t`'s comment):
+
+```c
+// --- Load Request ---
+// [type, ori_string, has_range?, range_start?, range_end?] — same optional-range
+// shape as GET_REQUEST. Asks the daemon to pull the file's blocks into its
+// block cache without sending file data; progress arrives as LOAD_PROGRESS
+// frames, terminated by LOAD_END.
+typedef struct {
+ char* ori_string;
+ uint8_t has_range; /* 0 → no range elements; 1 → following two present */
+ size_t range_start;
+ size_t range_end;
+} client_api_load_request_t;
+
+// --- Load Progress ---
+// [type, tuples_loaded: uint, tuples_total: uint]
+// (tuples_total - tuples_loaded includes both in-flight and skipped tuples)
+
+// --- Load End ---
+// [type, status: uint, tuples_loaded: uint, tuples_total: uint]
+// status: 0 = loaded, 1 = partial (some tuples skipped), 2 = failed
+```
+
+Declarations (next to the GET encoders):
+
+```c
+cbor_item_t* client_api_load_request_encode(const client_api_load_request_t* msg);
+int client_api_load_request_decode(cbor_item_t* item, client_api_load_request_t* msg);
+void client_api_load_request_destroy(client_api_load_request_t* msg);
+cbor_item_t* client_api_load_progress_encode(size_t tuples_loaded, size_t tuples_total);
+int client_api_load_progress_decode(cbor_item_t* item, size_t* tuples_loaded, size_t* tuples_total);
+cbor_item_t* client_api_load_end_encode(uint8_t status, size_t tuples_loaded, size_t tuples_total);
+int client_api_load_end_decode(cbor_item_t* item, uint8_t* status, size_t* tuples_loaded, size_t* tuples_total);
+```
+
+- [ ] **Step 4: Implement in `client_api_wire.c`** — model each on the GET equivalents (`client_api_get_request_encode` at line 363, `client_api_get_response_start_*`, and the get_data decode). Reference shapes:
+
+```c
+cbor_item_t* client_api_load_request_encode(const client_api_load_request_t* msg) {
+ /* 2 elements without a range, 4 with — same convention as GET_REQUEST. */
+ size_t count = msg->has_range ? 4 : 2;
+ cbor_item_t* array = cbor_new_definite_array(count);
+ /* [0] = type, [1] = ori_string, optional [2] range_start, [3] range_end.
+ Copy the element-building style used by client_api_get_request_encode
+ immediately above (cbor_build_uint8 / cbor_build_string / cbor_build_uint64
+ as used there; decref each built item after push). */
+ ...build per the GET encoder...
+}
+```
+
+Decode validates: array, `[0] == CLIENT_API_LOAD_REQUEST`, `ori_string` is a tstr; range elements only when 4 elements, `has_range` set to 1 by shape (mirror exactly how `client_api_get_request_decode` handles its optional range elements — read it and follow). `client_api_load_progress_encode(size_t, size_t)` builds `[40, loaded, total]` (definite array of 3, uints); decode reads three uints with the same `cbor_isa_uint` guards used by the peer_connect decoders. `client_api_load_end_encode(uint8_t status, ...)` builds `[41, status, loaded, total]`; decode extracts the three ints, no range validation needed beyond uint-ness. Destroy semantics: copy what `client_api_get_request_destroy` does for `ori_string` (free the malloc'd copy; decode must copy the string like the GET decoder does — verify by reading it).
+
+- [ ] **Step 5: Run tests**
+
+```bash
+cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs --gtest_filter='LoadWire*:LoadRequestWire*:LoadProgressWire*:LoadEndWire*' && ./build/test/testliboffs 2>&1 | tail -2
+```
+Expected: all new tests PASS; full suite green (875 + 5 new).
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add src/ClientAPI/client_api_wire.h src/ClientAPI/client_api_wire.c test/test_load_wire.cpp test/CMakeLists.txt
+git commit -m "feat(wire): LOAD_REQUEST/LOAD_PROGRESS/LOAD_END frames (39-41) for cache-only fetch"
+```
+
+---
+
+### Task 2: Load mode in `readable_off_stream` (TDD)
+
+**Files:**
+- Modify: `src/OFFStreams/readable_off_stream.h` (struct + constructor decl)
+- Modify: `src/OFFStreams/readable_off_stream.c` (skip paths, load event, tallies)
+- Modify: `src/Streams/stream.h:40` (new event enum value)
+- Test: `test/test_readable_load.cpp` (create)
+- Modify: `test/CMakeLists.txt` (add one line)
+
+**Design decisions locked in this task:**
+- New event: add `load_tuple_event = 15` as the LAST enumerator of `stream_event_e` in `src/Streams/stream.h` (after `error_event = 14`). Payload = `test_read_load_tuple_payload_t` (see below) heap-allocated, freed with `free`.
+- The load constructor is additive; `readable_off_stream_create` keeps its exact signature and delegates with `load_mode = 0`.
+
+- [ ] **Step 1: Write the failing test** — create `test/test_readable_load.cpp`:
+
+```cpp
+#include
+#include
+#include
+
+extern "C" {
+#include "../src/OFFStreams/readable_off_stream.h"
+#include "../src/OFFStreams/readable_descriptor.h"
+#include "../src/OFFStreams/tuple.h"
+#include "../src/OFFStreams/tuple_cache.h"
+#include "../src/BlockCache/block_cache.h"
+#include "../src/BlockCache/block.h"
+#include "../src/Buffer/buffer.h"
+#include "../src/Scheduler/scheduler.h"
+#include "../src/Timer/timer_actor.h"
+#include "../src/Util/rm_rf.h"
+#include
+#include
+}
+
+namespace readable_load_test {
+
+#include "test_off_stream_fixture.inc" /* see note below */
+```
+
+**IMPORTANT — fixture reuse:** `test/test_readable_off_stream.cpp` already contains a working fixture that creates a scheduler pool, temp cache dir, block cache, and tuple cache, and tests that write tuples through `readable_off_stream` with a real `block_cache` and assert on emitted events. READ that file first and reuse its fixture pattern verbatim (copy its setUp/tearDown and its helper that builds a `block_cache_t` seeded with computed XOR-recipe blocks). Write these four tests against that pattern:
+
+```cpp
+TEST(ReadableOffLoad, CountsTuplesViaLoadEvent) {
+ // load mode constructor; write 3 complete tuples (all blocks seeded in cache);
+ // subscribe load-event; assert 3 notifications, each payload's tuples_loaded
+ // counting 1,2,3 and tuples_skipped == 0; data_event still fires (rendering
+ // unchanged); close_event fires at the end.
+}
+
+TEST(ReadableOffLoad, MissingNetworkTupleSkipsAndContinues) {
+ // load mode; network = NULL (local-only); tuple 2's block hashes are NOT in
+ // the cache. Assert: stream does NOT deactivate; 2 load events with
+ // tuples_loaded 1 then 2; tuples_skipped == 1 in the second event's payload;
+ // tuple 3 (seeded) renders after the skip.
+}
+
+TEST(ReadableOffNormal, NetworkNullMissStillDeactivates) {
+ // default constructor path (regression guard): same scenario as above,
+ // assert the stream DOES deactivate and error_event fires — normal GET
+ // behavior is unchanged.
+}
+
+TEST(ReadableOffLoad, TuplesSkippedReportedInPayload) {
+ // two missing tuples interleaved (skip, load, skip, load): final
+ // tuples_loaded == 2, tuples_skipped == 2 across 4 events.
+}
+```
+
+The test needs the stream's *public* observable surface only (stream_subscribe on events). If the existing test file's fixture cannot seed a cache with XOR-recipe blocks directly (it likely already does — check `test_readable_off_stream.cpp`/`test_readable_descriptor.cpp` for helpers), reuse them.
+
+- [ ] **Step 2: Run to verify compile failure** — `cmake --build build --target testliboffs -j$(nproc)` → undeclared `readable_off_stream_create_load`.
+
+- [ ] **Step 3: Implement**
+
+In `src/OFFStreams/readable_off_stream.h` — add to the struct:
+
+```c
+ /* Load mode: cache-only fetch. Missing data tuples are skipped and
+ tallied instead of tearing the stream down; each resolved tuple emits
+ load_tuple_event. Rendering still happens (consumers discard it). */
+ uint8_t load_mode;
+ size_t tuples_loaded;
+ size_t tuples_skipped;
+```
+
+and:
+
+```c
+/* Payload for load_tuple_event (load mode only). Heap-allocated; freed by the
+ subscriber with free(). */
+typedef struct {
+ size_t tuples_loaded;
+ size_t tuples_skipped;
+} load_tuple_payload_t;
+
+readable_off_stream_t* readable_off_stream_create_ex(
+ scheduler_pool_t* pool, block_cache_t* bc, tuple_cache_t* tc,
+ ori_t* ori, size_t descriptor_pad, network_t* network, uint8_t load_mode);
+```
+
+`readable_off_stream.h` needs `#include "../Streams/stream.h"` (already there).
+
+In `readable_off_stream.c`:
+
+(a) Add a small notifier next to `_render_origin_data`:
+
+```c
+/* fire the load event after each tuple resolves (complete OR skipped) — consumers
+ count tuple progress without watching render events (which byte-trimming can
+ batch at range boundaries). */
+static void _notify_load_tuple(readable_off_stream_t* stream) {
+ if (!stream->load_mode) return;
+ load_tuple_payload_t* payload = get_clear_memory(sizeof(load_tuple_payload_t));
+ payload->tuples_loaded = stream->tuples_loaded;
+ payload->tuples_skipped = stream->tuples_skipped;
+ stream_notify((stream_t*)stream, load_tuple_event, payload, free);
+}
+```
+
+Call site 1 — end of `_finish_decode_and_render` (before `_drain_tuple_queue`):
+
+```c
+ stream->tuples_loaded++;
+ if (stream->load_mode) {
+ _notify_load_tuple(stream);
+ }
+```
+
+Call site 2 — every tuple-completion success path: `_render_origin_data` fires complete/close when `sent_bytes >= final_byte`; rendering with offset trimming still one-data-event-per-tuple in practice, but do NOT depend on it — `load_tuple_event` is the count.
+
+(b) Skip-on-miss. In `CACHE_GET_RESULT`'s `result->block == NULL` branch (readable_off_stream.c:206-238):
+- If `stream->network != NULL`: keep the existing NETWORK_LOCAL_FIND_BLOCK path unchanged.
+- Else (local-only): if `stream->load_mode`, replace the `stream_deactivate` block with `_skip_pending_tuple(stream)`; else keep `stream_deactivate`.
+
+In `NETWORK_FIND_BLOCK_RESULT`'s `else` branch (`found == 0`, line 289-298):
+- If `stream->load_mode`, replace the cleanup+`stream_deactivate` with `_skip_pending_tuple(stream)`; else keep existing.
+
+Add the shared helper above the dispatch function:
+
+```c
+/* Load mode only: abandon the current tuple (its blocks never arrived) and
+ continue with the next queued one. In-flight cache fetches for this tuple
+ are drained via the pending_fetches staleness check in CACHE_GET_RESULT. */
+static void _skip_pending_tuple(readable_off_stream_t* stream) {
+ stream->tuples_skipped++;
+ if (stream->load_mode) {
+ _notify_load_tuple(stream);
+ }
+ if (stream->xor_accumulator != NULL) {
+ DESTROY(stream->xor_accumulator, buffer);
+ stream->xor_accumulator = NULL;
+ }
+ if (stream->pending_tuple != NULL) {
+ DESTROY(stream->pending_tuple, tuple);
+ stream->pending_tuple = NULL;
+ }
+ stream->blocks_expected = 0;
+ stream->blocks_received = 0;
+ pending_block_fetch_t* fetch = stream->pending_fetches;
+ while (fetch != NULL) {
+ pending_block_fetch_t* next = fetch->next;
+ /* Move hash to stale list rather than freeing: late results for this
+ tuple's hashes must be recognized and dropped (see stale check). */
+ ... see stale-list design below ...
+ }
+ stream->pending_fetches = NULL;
+ _drain_tuple_queue(stream);
+}
+```
+
+**Stale-fetch handling (critical correctness point):** after a skip, the daemon may still be awaiting results for hashes the abandoned tuple requested (`pending_get_t` in block_cache resolves later; a `CACHE_GET_RESULT` for an old hash would otherwise be XOR-accumulated into the NEXT tuple). Add to the struct:
+
+```c
+ pending_block_fetch_t* stale_fetches; /* hashes of an abandoned tuple */
+```
+
+In `_skip_pending_tuple`, move the pending fetches' hashes into `stale_fetches` (transfer ownership, do not free the `buffer_t*` hashes). In `CACHE_GET_RESULT` (both block!=NULL and block==NULL arms) and `NETWORK_FIND_BLOCK_RESULT` (found=1 direct-return), FIRST check whether `result->hash` matches a stale hash (walk `stale_fetches`, compare with `buffer_compare(result->hash, stale->hash) == 0`); if it matches, remove the entry from the stale list (destroy hash node), DESTROY the result's block/hash buffers, and `break` without touching `xor_accumulator` or `blocks_received`. Cap the staleness list implicitly — it lives only until the matching late results arrive, and tuples are processed one at a time.
+
+- [ ] **Step 4: Add the constructor** (readable_off_stream.c):
+
+```c
+readable_off_stream_t* readable_off_stream_create_ex(
+ scheduler_pool_t* pool, block_cache_t* bc, tuple_cache_t* tc,
+ ori_t* ori, size_t descriptor_pad, network_t* network, uint8_t load_mode) {
+ ... existing create body ...
+ stream->load_mode = load_mode;
+ ...
+}
+
+readable_off_stream_t* readable_off_stream_create(
+ scheduler_pool_t* pool, block_cache_t* bc, tuple_cache_t* tc,
+ ori_t* ori, size_t descriptor_pad, network_t* network) {
+ return readable_off_stream_create_ex(pool, bc, tc, ori, descriptor_pad, network, 0);
+}
+```
+
+Header: declare `readable_off_stream_create_ex` with a comment explaining the flag ("load mode: missing data tuples are skipped and tallied via load_tuple_event instead of deactivating the stream; descriptor misses remain fatal").
+
+- [ ] **Step 5: Run tests**
+
+```bash
+cmake -B build -DCMAKE_BUILD_TYPE=Debug >/dev/null && cmake --build build --target testliboffs -j$(nproc) && ./build/test/testliboffs --gtest_filter='ReadableOffLoad*:ReadableOffNormal*' && ./build/test/testliboffs 2>&1 | tail -2
+```
+Expected: 4 new tests PASS; full suite green (the existing readable-off-stream/descriptor suites prove normal mode is untouched).
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add src/Streams/stream.h src/OFFStreams/readable_off_stream.h src/OFFStreams/readable_off_stream.c test/test_readable_load.cpp test/CMakeLists.txt
+git commit -m "feat(off-stream): load mode skips missing tuples and emits counted progress events"
+```
+
+---
+
+### Task 3: Unix socket LOAD dispatch
+
+**Files:**
+- Modify: `src/ClientAPI/Unix/unix_connection.c` (`_unix_handle_get` at 347 is the template; add `_unix_handle_load` + its pipeline type + dispatch case)
+
+NOTE this transport's GET passes `network = NULL` today (`readable_off_stream_create(..., NULL)` at ~line 415). For LOAD, pass the network actor — the connection has one: `conn->peer_ctx.network` (set at unix_connection.c:1169 from `transport->config_node->network`). If `peer_ctx` is only populated on the authenticated path, read how `config_node` reaches the transport and use the same access; if it is genuinely unavailable on some connections, load proceeds cache-only (network == NULL is a legal mode) — but DO pass it when present; verify at implementation time which connection path peer_ctx is filled on (line 1169 context) and report.
+
+- [ ] **Step 1: Add the pipeline struct + handlers** (model exactly on `unix_get_pipeline_t` and `_unix_get_on_rs_data/_unix_get_on_rs_close/_unix_get_on_rs_error` — read them first, they are just above `_unix_handle_get`):
+
+```c
+typedef struct {
+ refcounter_t refcounter;
+ unix_connection_t* conn;
+ readable_off_stream_t* rs;
+ readable_descriptor_t* desc;
+ size_t tuples_total; /* ceil(final_byte / block_size) - offset_tuple */
+} unix_load_pipeline_t;
+
+static void _unix_load_on_tuple_loaded(stream_t* stream_source, void* user, void* payload, void (*payload_destroy)(void*)) {
+ (void)stream_source;
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)user;
+ /* payload is load_tuple_payload_t{tuples_loaded, tuples_skipped} — heap, free here */
+ load_tuple_payload_t* progress = (load_tuple_payload_t*)payload;
+ cbor_item_t* frame = client_api_load_progress_encode(progress->tuples_loaded, pipeline->tuples_total);
+ _unix_connection_send_frame(pipeline->conn, frame);
+ free(progress);
+}
+
+static void _unix_load_on_close(stream_t* stream_source, void* user) {
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)user;
+ uint8_t status = pipeline->tuples_skipped() ... /* see below */
+ cbor_item_t* frame = client_api_load_end_encode(status, pipeline->tuples_loaded, pipeline->tuples_total);
+ _unix_connection_send_frame(pipeline->conn, frame);
+ DEREFERENCE(pipeline, unix_load_pipeline_t); /* terminal */
+}
+```
+
+Concrete rules for the implementer:
+- Track on the pipeline (not the stream): `tuples_total` computed from the ORI exactly as `readable_descriptor` does — `total = ceil(url->stream_length_final / block_size) - (file_offset / block_size)` where `block_size` comes from `_block_size_for_type(ori->block_type)` (copy that 10-line static helper or expose it — prefer exposing: add `size_t off_block_size_for_type(block_size_e type);` to `src/OFFStreams/readable_off_stream.h` and have both call it).
+- `LOAD_END` status: 0 if no tuple was skipped and stream closed normally; 1 if ≥1 skipped; 2 if the desc/rs `error_event` fired (descriptor unrecoverable or fatal). Subscribe to `error_event` on BOTH desc and rs → send LOAD_END(2) and release.
+- Subscribe to `load_tuple_event` (Task 2's event) on rs for progress; to `close_event` on rs for the terminal; unsubscribe/deref symmetric to the GET pipeline (copy its subscription/refcount discipline exactly — the GET pipeline struct at unix_connection.c is the model, including its destroy).
+- Dispatch: in the switch (~line 630) add `case CLIENT_API_LOAD_REQUEST: _unix_handle_load(conn, frame); break;` guarded by the same `_check_authenticated` pattern as `_unix_handle_get`. ORI parsing, directory (OFD) rejection: a load of an `offsystem/directory` URL resolves the OFD then loads the resolved entry — for v1, REJECT directory ORIs with `CLIENT_API_STATUS_BAD_REQUEST, "Load requires a file ORI, not a directory"` (same posture as the sync GET path: directories are resolved in HTTP land; extend later if asked). Note this decision in the commit message.
+- The pipeline holds refs to `ori`, `rs`, `desc` using the same REFERENCE pattern `_unix_handle_get` uses.
+
+Also add WS and TCP equivalents in the SAME task only if their GET handlers exist: `src/ClientAPI/WS/ws_connection.c:893` handles `CLIENT_API_GET_REQUEST` — mirror a `CLIENT_API_LOAD_REQUEST` case with the same pipeline shape (WS connection carries the same `config_node`/network access — verify, it was added for peer routes). `src/ClientAPI/TCP/tcp_connection.c` has an equivalent GET handler (line ~397) — mirror there too. If a transport's GET handler differs materially (WT), leave WT alone and note it in the report.
+
+- [ ] **Step 1: implement** per above **Step 2: full suite green** `./build/test/testliboffs 2>&1 | tail -2` **Step 3: commit**
+
+```bash
+git add src/ClientAPI/Unix/unix_connection.c src/ClientAPI/WS/ws_connection.c src/ClientAPI/TCP/tcp_connection.c src/OFFStreams/readable_off_stream.h src/OFFStreams/readable_off_stream.c
+git commit -m "feat(transports): dispatch LOAD frames on unix/tcp/ws transports"
+```
+
+---
+
+### Task 4: HTTP `?load=1` streaming route (TDD where practical)
+
+**Files:**
+- Modify: `src/ClientAPI/HTTP/off_routes.c` (URL handler ~340-540; the `?ofd=raw` branch at ~369-384 is the pattern)
+
+- [ ] **Step 1: Write the failing test** — create `test/test_off_routes_load.cpp` modeled EXACTLY on `test/test_off_routes.cpp` (same fixture: `scheduler_pool_create`, `mkdtemp` cache dir, `block_cache_create` with the config it uses — the block cache must be seeded with real readable content, which the existing test_off_stream fixtures already do; reuse the seeding helper from `test_off_stream_integration` if present). Request bytes use one of the existing `_send_and_recv` helpers. Test:
+
+```cpp
+TEST_F(TestOffRoutesLoad, LoadStreamsNdjsonProgress) {
+ // 1. Upload a small file through the normal PUT flow (fixture helper).
+ // 2. GET its OFF URL with "?load=1" appended; assert Content-Type
+ // application/x-ndjson; parse body: one "\n"-delimited progress line per
+ // tuple, each {"tuples_loaded":n,"tuples_total":m}; final line
+ // {"status":"loaded","tuples_loaded":N,"tuples_total":N}.
+ // 3. GET the SAME url WITHOUT ?load=1; assert normal bytes (regression pin).
+ // 4. GET "?load=1" for an ORI with descriptor-hash of 32 zero bytes:
+ // stream ends "failed" (descriptor unrecoverable).
+}
+```
+
+- [ ] **Step 2: implement** — in `_off_get_handler` (off_routes.c:340-432): after URL parse, before the plain-data path, add:
+
+```c
+ if (request->query_string != NULL && strstr(request->query_string, "load") != NULL) {
+ _off_load_handler(request, response, ...same ctx...);
+ return;
+ }
+```
+
+(precedent: the `?ofd=` check at off_routes.c:165). The load branch: build the SAME pipeline as `_off_stream_file_get` does (readable_descriptor + readable_off_stream via `_setup_stream_pipeline` with the load-mode constructor), then, instead of `http_response_pipe`, subscribe:
+
+```c
+http_response_set_status(response, HTTP_STATUS_OK);
+http_response_set_header(response, "Content-Type", "application/x-ndjson");
+http_response_set_header(response, "Cache-Control", "no-store");
+/* stream events → http_response_write per progress tuple (ndjson line),
+ close → terminal line + http_response_end */
+```
+
+Model the ctx on `get_pipeline_t` (off_routes.c:161-173 — refcounted struct holding `http_response_t* response`), emitting `{"tuples_loaded":%zu,"tuples_total":%zu}\n` via `snprintf` + `http_response_write`, and the terminal line per the design doc. Use `http_response_write` after headers are set (no Content-Length for a length-unknown body — check how other unbounded streaming responses are sent; `_send_stream_response` (`off_routes.c:287`) sets `Content-Length` explicitly: for load mode, use *chunked/close-delimited* streaming — mirror whatever the existing pipe path does for Content-Length (it uses `body_length`... check `http_response_pipe`); if a Content-Length is mandatory on this server, use the tuple-total-derived upper bound and rely on terminal-line + http_response_end).
+
+Also: `load` must NOT also match OFD handling — query check must be `strstr(..., "?load=1")` or param parse on the raw query string, tested for both `?load=1` and bare `?load`.
+
+- [ ] **Step 3: full suite green; run new test file**; **Step 4: commit**
+
+```bash
+git add src/ClientAPI/HTTP/off_routes.c test/test_off_routes_load.cpp test/CMakeLists.txt
+git commit -m "feat(http): ?load=1 streams ndjson tuple progress for cache-only fetch"
+```
+
+---
+
+### Task 4: C client `offs_client_load` (TDD-lite, pattern-verified)
+
+**Files:**
+- Modify: `src/ClientLibs/c/offs_client.h` (callbacks + decls after the peer ops)
+- Modify: `src/ClientLibs/c/offs_client.c` (struct fields, snapshot, switch cases, function)
+
+- [ ] **Step 1: callbacks + decls** (offs_client.h, next to the peer typedefs):
+
+```c
+typedef void (*offs_load_progress_cb_t)(void* ctx, size_t tuples_loaded, size_t tuples_total);
+typedef void (*offs_load_end_cb_t)(void* ctx, uint8_t status, size_t tuples_loaded, size_t tuples_total);
+```
+
+```c
+/* Load a file's blocks into the daemon's block cache without receiving file
+ data. Progress fires per reconstructed tuple; END fires exactly once with
+ the terminal status (0=loaded, 1=partial, 2=failed). Errors from the
+ daemon (bad ORI, unauthorized) arrive on the error callback registered
+ via offs_client_get()-style callbacks (see peer ops' error caveat). */
+int offs_client_load(offs_client_t* client, const char* ori_string,
+ offs_load_progress_cb_t progress_cb, void* progress_ctx,
+ offs_load_end_cb_t end_cb, void* end_ctx);
+```
+
+- [ ] **Step 2: implement** following the `offs_client_peer_info_ex` pattern exactly (encode-before-register ordering, format: none here — build `client_api_load_request_t{ori_string=ori, has_range=0}` and `client_api_load_request_encode`; `_send_frame`; return -1 guards). Dispatch in `_handle_frame` (snapshot-under-lock discipline identical to the peer ops):
+
+```c
+ case CLIENT_API_LOAD_PROGRESS: {
+ size_t tuples_loaded = 0, tuples_total = 0;
+ if (client_api_load_progress_decode(frame, &tuples_loaded, &tuples_total) == 0) {
+ if (load_progress_cb != NULL) load_progress_cb(load_progress_cb_ctx, tuples_loaded, tuples_total);
+ }
+ break;
+ }
+ case CLIENT_API_LOAD_END: {
+ uint8_t status = 0; size_t loaded = 0, total = 0;
+ if (client_api_load_end_decode(frame, &status, &loaded, &total) == 0) {
+ if (load_end_cb != NULL) load_end_cb(end_cb_ctx, status, loaded, total);
+ }
+ break;
+ }
+```
+
+- [ ] **Step 3: build + full suite; commit** `git commit -m "feat(client): C client library load operation"` (stage the two offs_client files).
+
+---
+
+### Task 5: JS client `load()` + rebuild dist
+
+**Files:**
+- Modify: `src/ClientLibs/js/offs-client/src/wire.js` (frames 39/40/41: `encodeLoadRequest(ori, range)`, `decodeLoadProgress`, `isLoadEnd`, `decodeLoadEnd`; `MSG.LOAD_REQUEST: 39` etc.)
+- Modify: `src/ClientLibs/js/offs-client/src/transports/http-transport.js`: `load(oriOrUrl, callbacks, range)` → `fetch(url + '?load=1')`, read `response.body` as a stream, split on `\n`, JSON.parse each line, `onProgress` per progress line, `onEnd` on the terminal line.
+- Modify: `src/ClientLibs/js/offs-client/src/index.js`: add `load(ori, callbacks, range)` after `get` — HTTP path as above; CBOR transports: `wire.encodeLoadRequest(ori, range)` then loop `this._waitForResponse([wire.MSG.LOAD_PROGRESS, wire.MSG.LOAD_END])` mirroring the GET loop (index.js get()).
+
+- [ ] Implement all three; **verify with `npm test`** (package's vitest suite) and `npm run build`; **grep dist** for `encodeLoadRequest`. **Commit** the three src files + 4 dist files (explicit paths; dist is gitignored but tracked) with `feat(js-client): load() — cache-only fetch with tuple progress` (all in ONE commit so dist matches src).
+
+---
+
+### Task 6: Dart/Flutter binding — `load()` + QR catch-up
+
+**Files:**
+- Modify: `examples/off_client/lib/services/off_api.dart`
+
+- [ ] Implement (following the file's existing patterns — read `uploadFile`/`downloadFile`/`connectPeer` first; this binding is HTTP-only):
+
+```dart
+ /// Load a file's blocks into the daemon's block cache without downloading
+ /// the data. Streams application/x-ndjson progress: one
+ /// {"tuples_loaded":n,"tuples_total":m} line per resolved tuple, terminal
+ /// line {"status":"loaded|partial|failed",...}.
+ Future> loadContent(
+ String offUrl, {
+ void Function(int loaded, int total)? onProgress,
+ }) async {
+ /* stream-load offUrl + '?load=1' via the same http client used by
+ downloadFile; read response lines; onProgress per progress line;
+ parse + return the terminal line. */
+ }
+
+ Future connectPeerImage(Uint8List ppmBytes) async {
+ /* POST /peer/connect with Content-Type: image/x-portable-pixmap, body =
+ ppmBytes; parse {"status": n} JSON (match connectPeer's status mapping). */
+ }
+
+ Future addFriendImage(Uint8List ppmBytes) async {
+ /* POST /friends with Content-Type: image/x-portable-pixmap; mirror addFriend. */
+ }
+```
+
+Run `dart analyze examples/off_client` (if the Flutter toolchain is present — if not, report inspection-only, same as the CLI task in the QR feature).
+
+- [ ] **Verify + commit**: `git add examples/off_client/lib/services/off_api.dart && git commit -m "feat(binding): Dart loadContent + QR peer image catch-up"`
+
+---
+
+### Task 7: `offs load` CLI
+
+**Files (OFFS repo `/home/victor/Workspace/src/github.com/vijayee/OFFS`):**
+- Create: `src/offs/commands/load.c`
+- Modify: `src/offs/cli_util.c` (command table + `main.c` dispatch if separate), `src/offs/l10n/en.h` (`L10N_LOAD_USAGE`)
+
+- [ ] **Implement `cmd_load`** modeled exactly on `commands/get.c`'s frame loop (shown in the controller context; mirror its structure):
+
+```c
+int cmd_load(int argc, char** argv, cli_client_t* client) {
+ /* args: offs load ; parse --help only */
+ client_api_load_request_t req; memset(&req, 0, sizeof(req));
+ req.ori_string = (char*)ori; req.has_range = 0;
+ /* send LOAD_REQUEST via cli_client_send_frame (copy get.c's send+error flow) */
+ /* loop cli_client_recv_frame:
+ - LOAD_PROGRESS [40]: decode; fprintf(stderr, "Loading %s: %zu/%zu tuples (%d%%)\r",
+ ori, loaded, total, (int)(100 * loaded / max(total,1))); \r or \n? use \n like put.c's progress
+ - LOAD_END [41]: decode status/loaded/total; break;
+ - ERROR: print message, had_error = true; break; */
+ /* after loop: if no LOAD_END -> "load truncated" error 1.
+ exit 0 for status 0/1 (partial prints
+ "Warning: partial load (%zu/%zu tuples)" on stderr); exit 1 for failed. */
+}
+```
+
+Register `"load"` in the command table (`src/offs/cli_util.c:25-40`) pointing at `cmd_load`; add `L10N_LOAD_USAGE`, `L10N_LOAD_STAGED`-style strings to `src/offs/l10n/en.h` following the existing naming/grammar conventions. Update the OFFS `deps/liboffs` submodule ONLY IF a liboffs commit containing frames 39–41 is available to the submodule clone (same fetch-from-local-repo dance as the QR e2e; otherwise verification is compile-check against the liboffs working tree — state which you did).
+
+**Commit**: `feat(cli): offs load streams tuple progress while warming the daemon block cache`.
+
+---
+
+### Task 8: End-to-end verification (manual)
+
+- [ ] Build `offsd` + `offs` in the OFFS repo against a temporary `deps/liboffs` checkout of this repo's master (the QR e2e proved the pattern; the helper memory `reference_offs_sibling_repo.md` documents it). Start offsd with node certs on a test port. Verify: (1) `offs put` a small file; (2) wipe... no — simpler: `offs get` confirm normal data flow; `offs load ` prints tuple progress lines and a loaded terminal; re-run `offs load` on the same ORI → completes immediately (all tuples already cached — fast path proves blocks were cached, not re-fetched); (3) `curl ?load=1` over HTTP with bearer → ndjson lines; (4) curl an ORI with a garbage descriptor hash → `failed` terminal within the 30 s deadline window; (5) CLI missing ORI path and unauthorized (401) behavior. Post evidence to the Harmony ticket.
+
+---
+
+### Task 9: Docs, valgrind, close
+
+- [ ] Update `docs/OFFS_API_CLI_SPEC.md`: new load surface (§2.1 query flag, §3 frames 39–41, JS/Dart/C binding sections, CLI table row `offs load`, §9 checklist item). Update `docs/HowOFFSWorks.md` client-features §8/9 if it lists commands.
+- [ ] Valgrind `-gdwarf-4` on new suites (`ReadableOffLoad*`, `LoadWire*`, HTTP load test) — 0 leaks, 0 errors.
+- [ ] De-wonk audit + Harmony ticket close (create the OFFS-xxx ticket for this feature at plan start, close at end with the required summary/notify actions).
+
+---
+
+## Self-review notes
+
+- **Spec coverage**: §1 semantics → Task 2 (+ fixture tests); §2 load consumer → Tasks 3/4; §3 wire → Task 1; §4 HTTP → Task 4; §5 bindings → Tasks 4 (C), 5 (JS), 5 (Dart incl. QR catch-up), 7 (CLI); §6 testing → Task 2-5 unit suites + Task 8 e2e + Task 9 valgrind; §7 exclusions respected (no parallel prefetch, no block metrics, no job API).
+- **Type consistency**: `client_api_load_request_t{ori_string,has_range,range_start,range_end}` used consistently; `load_tuple_payload_t{tuples_loaded,tuples_skipped}` defined in Task 2 and consumed in Task 3/4; statuses 0/1/2 identical across wire/HTTP/CLI.
+- **Known risk called out for implementers**: HTTP load response framing (Content-Length vs close-delimited) must follow what `http_response_pipe`/chunked support actually allows — verify in Task 4 Step 2 against `http_response.h` rather than assuming.
+- WT transport intentionally omitted (its GET support is partial; load rides the transports where GET exists). Revisit if WT GET lands.
\ No newline at end of file
diff --git a/docs/superpowers/specs/2026-08-27-qr-peer-connect-design.md b/docs/superpowers/specs/2026-08-27-qr-peer-connect-design.md
new file mode 100644
index 00000000..9d19d903
--- /dev/null
+++ b/docs/superpowers/specs/2026-08-27-qr-peer-connect-design.md
@@ -0,0 +1,153 @@
+# QR Peer Connect — Design
+
+Date: 2026-08-27
+Status: Approved design (brainstorm session 2026-08-27)
+
+## Goal
+
+Peer information can already be shared as a QR image over HTTP
+(`GET /peer/info?format=qrcode`), but only conditionally (system libqrencode)
+and only in one direction: there is no decode path anywhere. This feature
+makes QR a first-class, symmetric transport for peer info across **every**
+client API surface — HTTP, the CBOR socket transports (unix/TCP/WS/WT), the
+C client library, the JS client library, and the `offs` CLI:
+
+- **Generate**: any transport can produce a QR image (PPM) of the local
+ peer info.
+- **Decode**: any transport can submit a QR image (PPM) to connect to a peer
+ or add a friend.
+
+Decisions made during brainstorming:
+
+1. Decode is **daemon-side**: clients submit image bytes; the daemon decodes.
+2. Accepted image format = **the format we produce** (binary P6 PPM). No
+ general image-codec dependency.
+3. Full parity: QR generation is added to the socket wire protocol too, not
+ left HTTP-only.
+4. Both `peer connect` and `friend add` accept QR images.
+
+## 1. Dependencies and build
+
+Two new git submodules, added to `.gitmodules` and wired with
+`add_subdirectory` following the existing `bcrypt`/`libcbor` pattern:
+
+| Submodule | Role | Notes |
+|---|---|---|
+| `deps/libqrencode` | QR encoder | Vendored; replaces the pkg-config probe. `HAS_QRENCODE` becomes unconditional and the `501 QR code generation not available` branch in `peer_routes.c` is deleted. |
+| `deps/quirc` | QR decoder | Small pure-C BSD library, no transitive deps. Linked into the liboffs core (not per-transport). |
+
+Both are required (loud `FATAL_ERROR` on missing submodule, like bcrypt), not
+optional probes.
+
+## 2. QR codec module — `src/QR/`
+
+Exactly two public operations; all transports call these so behavior cannot
+drift:
+
+```c
+/* Serialize the CBOR payload into a P6 PPM QR image (libqrencode,
+ QR_ECLEVEL_M, 4x pixel scale — byte-compatible with today's output).
+ Returns buffer (caller frees) or NULL on encode failure. */
+buffer_t* qr_encode_to_ppm(const uint8_t* cbor_data, size_t cbor_len);
+
+/* Parse a P6 PPM, decode the QR with quirc, return the raw payload bytes.
+ Returns buffer or NULL (bad image / no QR found / decode failure). */
+buffer_t* qr_decode_from_ppm(const uint8_t* ppm_data, size_t ppm_len);
+```
+
+- The PPM rendering code currently inside `_peer_info_handler`
+ (`src/ClientAPI/HTTP/peer_routes.c:180-244`) moves here verbatim.
+- The PPM parser is strict: `P6` magic, whitespace, dimensions, `255` maxval,
+ binary pixel data — exactly what we generate. RGB → luma conversion feeds
+ quirc's grayscale buffer.
+- Neither function knows about peer_info, HTTP, or CBOR framing; callers
+ decide what the payload means. The module is independently testable.
+
+## 3. Wire protocol changes (`src/ClientAPI/client_api_wire.h`)
+
+Format byte **2** = "PPM QR image", consistently:
+
+| Frame | Current | Change |
+|---|---|---|
+| `PEER_INFO_REQUEST` (21) | `[21]` | `[21]` or `[21, format]`; 0 = raw CBOR (default, backward compatible), 1 = base58, 2 = PPM QR image |
+| `PEER_INFO_RESPONSE` (22) | `[22, format_byte, data]` | unchanged shape; format 2 legal, `data` = PPM bytes |
+| `PEER_CONNECT` (23) | `[23, format_byte, data]` | format 2 accepted: `data` = PPM image → decode → peer_info CBOR → connect |
+| `FRIEND_ADD` (27) | `[27, format_byte, data]` | format 2 accepted, same flow |
+
+Backward compatibility: frame decoders accept the old shapes unchanged
+(1-element `PEER_INFO_REQUEST`, formats 0/1 everywhere). Old clients keep
+working.
+
+## 4. HTTP changes (`src/ClientAPI/HTTP/peer_routes.c`)
+
+- `GET /peer/info?format=qrcode` — handler shrinks to
+ `qr_encode_to_ppm(peer_info_encode(info))`. Vendored encoder means this
+ always works; the `#ifdef HAS_QRENCODE` / 501 branches are removed.
+- `POST /peer/connect` and `POST /friends` — body dispatch by `Content-Type`:
+ - `application/cbor` → as today
+ - text (base58) → as today
+ - `image/x-portable-pixmap` → `qr_decode_from_ppm()` → peer_info CBOR →
+ existing flow
+
+Both routes share one helper (`peer_info_from_body()`) so HTTP and sockets
+cannot drift on what a valid QR peer is.
+
+## 5. Client libraries
+
+**C client** (`src/ClientLibs/c/offs_client.h`) — generalized `_ex` forms
+with explicit format byte, plus QR sugar:
+
+```c
+offs_client_peer_info_ex(client, format /*0|1|2*/, cb, ctx);
+offs_client_peer_connect_ex(client, format, data, data_len, cb, ctx);
+offs_client_friend_add_ex(client, format, data, data_len, cb, ctx);
+offs_client_peer_info_qr(...); /* format 2 sugar: returns PPM */
+offs_client_peer_connect_qr(client, ppm, ppm_len, cb, ctx);
+offs_client_friend_add_qr(client, ppm, ppm_len, cb, ctx);
+```
+
+**JS client** (`src/ClientLibs/js/offs-client/`):
+
+- `peerInfo(format)` — format passthrough (`'cbor' | 'base58' | 'qrcode'`);
+ HTTP transport maps `qrcode` to the query param, CBOR transports send
+ format byte 2.
+- `peerConnectQr(ppmBytes)` / `friendAddQr(ppmBytes)` — HTTP: POST with
+ `Content-Type: image/x-portable-pixmap`; CBOR transports: format 2 frame.
+ `dist/` rebuilt via the package's existing build.
+
+## 6. CLI (`OFFS/src/offs/`)
+
+- `offs peer info --qr ` — format-2 request; writes PPM to ``
+ (`-` = stdout).
+- `offs peer connect --qr ` / `offs friend add --qr ` — read
+ PPM from file, send format 2, print usual `ok`/error.
+
+## 7. Error handling
+
+One rule everywhere — *image problems* vs *peer problems* are distinct:
+
+| Failure | Socket | HTTP |
+|---|---|---|
+| Bad PPM header / truncated image | `ERROR`, status `BAD_REQUEST`, "qr decode failed: " | 400 text/plain |
+| QR found but payload not valid peer info | `ERROR`, status `BAD_REQUEST`, "invalid peer info in qr" | 400 text/plain |
+| Connect-level outcome (already connected, rejected, ...) | unchanged `PEER_CONNECT_RESULT` | unchanged `{"status": 0..4}` |
+
+## 8. Testing
+
+Following the existing `test/` gtest layout:
+
+- `test_qr.cpp` — unit: PPM parser edge cases (bad magic, truncated data,
+ wrong maxval), encode→decode round-trip (bytes in == bytes out), decode of
+ a hand-built PPM.
+- `test_peer_routes.cpp` additions — HTTP round trip:
+ `GET /peer/info?format=qrcode` → feed PPM into `POST /peer/connect` and
+ `POST /friends` (QR content type); 400 paths for garbage images.
+- Wire-frame tests — format-2 encode/decode; old-shape backward compat.
+- Valgrind pass with `-gdwarf-4` per project convention; no new leaks.
+
+## 9. Out of scope
+
+- PNG/JPEG/camera image support (daemon accepts only the PPM it produces).
+- QR generation/decode in the GUI itself (separate project; this feature
+ gives it the server-side primitives).
+- Non-peer-info QR payloads.
\ No newline at end of file
diff --git a/docs/superpowers/specs/2026-08-28-cache-load-design.md b/docs/superpowers/specs/2026-08-28-cache-load-design.md
new file mode 100644
index 00000000..740b31fc
--- /dev/null
+++ b/docs/superpowers/specs/2026-08-28-cache-load-design.md
@@ -0,0 +1,178 @@
+# Cache Load Command — Design
+
+Date: 2026-08-28
+Status: Approved design (brainstorm session 2026-08-28)
+
+## Goal
+
+A **load** command on every client surface (HTTP, CBOR socket transports, C
+client library, JS client library, Dart/Flutter binding, `offs` CLI) that
+works like a GET but transfers no file data: the daemon resolves each of the
+file's reconstructed data chunks (tuples) into its block cache — from local
+cache or via the network wanted-list — without sending file data to the
+client, and instead reports **tuple-level progress**
+(`tuples_loaded / tuples_total`) as it goes.
+
+Use case: "pin a file to a node without downloading it locally" — the
+download-manager counterpart to GET.
+
+Decisions made during brainstorming:
+
+1. Progress metric is **tuple-level only**. Tuples are the meaningful unit
+ (a tuple is reconstructable only when all `tuple_size` of its blocks are
+ present); a per-block progress event was considered and dropped as
+ unnecessary — the existing per-tuple render event already fires once per
+ reconstructed tuple.
+2. **Continue-and-report**: a tuple whose blocks never arrive (30 s
+ network deadline) is *skipped*; the walk continues. Terminal status
+ reflects the full outcome.
+3. HTTP delivers progress as a **streaming `application/x-ndjson`**
+ response; socket transports get dedicated frames.
+4. HTTP reuses the **existing OFF URL with `?load=1`** (precedent:
+ `?ofd=raw`) — no new route pattern, auth or CORS.
+5. The Dart/Flutter binding is included in scope, **plus a catch-up of the
+ QR peer surfaces it never received** (the QR feature shipped without
+ binding updates).
+
+## 1. Semantics
+
+- `total_tuples = ceil(final_byte / block_size)` — computed from the parsed
+ ORI with zero I/O (`readable_descriptor.c:327-328` already does this).
+- A tuple is *loaded* when all `tuple_size` of its blocks resolve: either
+ present in the block cache (`CACHE_GET_RESULT` with block) or fetched from
+ the network (`NETWORK_FIND_BLOCK_RESULT` with found=1 — this path already
+ verifies + `block_cache_put`, so arrival means cached).
+- "Loaded into cache" is the persistent-index state; in-memory LRU eviction
+ never loses a block.
+- A tuple whose blocks don't resolve within the wanted-list deadline
+ (default 30 s/block) is skipped; the dispatcher continues to the next
+ tuple. Load-mode metrics tally skipped tuples.
+- **Descriptor blocks are not skippable**: a missing *descriptor tree* block
+ stops enumeration entirely (nothing downstream can be discovered), so a
+ descriptor miss ends the load as `failed` with the tallies so far.
+- Terminal statuses: `loaded` (every tuple loaded), `partial` (≥1 tuple
+ skipped), `failed` (0 tuples loaded, or descriptor unrecoverable).
+- Range requests are honored for partial loads (`[file_offset, final_byte)`
+ restricts the enumerated tuple range exactly as GET does).
+
+## 2. Internal design
+
+Approach: **load mode on the existing GET pipeline** (approach chosen over a
+standalone prober, which would fork the descriptor-walk + wanted-list
+plumbing into a second codepath).
+
+Changes to `src/OFFStreams/readable_off_stream.*`:
+
+1. A `load_mode` construction/dispatch flag with two effects:
+ - Block-resolution failure for a **data** tuple (network `found=0`) does
+ not `stream_deactivate`; it aborts the current tuple, counts one
+ skipped tuple, and continues with the next (`OFF_STREAM_WRITE` resume).
+ Descriptor-node misses keep the existing teardown (see §1).
+ - Each skipped/aborted tuple is tallied on the stream so the consumer can
+ report it in the terminal event.
+2. Tuple-completion signal: the plan must verify that the stream's existing
+ `data_event` fires exactly once per reconstructed tuple (including at
+ range-offset boundaries, where rendering trims bytes). If trimming
+ batches or splits events, the fallback is one optional load-mode
+ `tuple_done` event emitted from `_finish_decode_and_render` (the same
+ place tuple completion is tallied today) — cheap and unambiguous. The
+ consumer discards any payload and emits progress on the signal;
+ `close_event` (stream walked to completion) and `error_event` (fatal)
+ are reused as-is.
+3. Normal GETs are untouched: default mode keeps `stream_deactivate` on
+ miss.
+
+New shared consumer (`src/ClientAPI/load_helpers.c` or similar, shared by
+HTTP and socket transports so they cannot drift): given the pipeline
+subscription, forwards per-tuple progress to the client and produces the
+terminal tallies (`tuples_loaded`, `tuples_total`, status).
+
+Concurrency note (accepted v1 limitation, same as GET): one tuple in flight
+at a time. A file with many permanently-missing blocks completes in
+`skipped × 30 s` worst case; wanted-list coalescing mitigates duplicates.
+The progress stream makes this *visible*. Parallel multi-tuple prefetch is
+v2, out of scope.
+
+## 3. Wire protocol (`src/ClientAPI/client_api_wire.h/.c`)
+
+| Frame | Shape |
+|---|---|
+| `LOAD_REQUEST 39` | `[39, ori_string, has_range?, range_start?, range_end?]` — same optional-range shape as `GET_REQUEST` |
+| `LOAD_PROGRESS 40` | `[40, tuples_loaded: uint, tuples_total: uint]` (repeated, one per tuple resolution) |
+| `LOAD_END 41` | `[41, status: uint, tuples_loaded: uint, tuples_total: uint]` — status 0=loaded, 1=partial, 2=failed |
+
+Request-level failures (unparseable ORI, unauthorized) use the existing
+`ERROR` frame `[11, status, message]`. Encode/decode functions follow the
+existing naming convention
+(`client_api_load_request_encode/decode`, etc.). All transports that
+dispatch GET (unix, TCP, WS) dispatch LOAD frames the same way; WebTransport
+follows its GET support status.
+
+## 4. HTTP
+
+`GET /offsystem/v3/{type}/{stream-length}/{file-hash}/{descriptor-hash}/{file-name}?load=1`
+
+- Query flag `?load` switches the handler from data streaming to load mode
+ (`?ofd=raw` precedent for query behavior on this route). Auth, CORS
+ registration, and `Range` handling unchanged.
+- Response: `Content-Type: application/x-ndjson` piped through the existing
+ streaming response machinery. One progress line per tuple:
+ `{"tuples_loaded":n,"tuples_total":m}\n`, then a terminal line:
+ `{"status":"loaded|partial|failed","tuples_loaded":n,"tuples_total":m}`
+ followed by end-of-body.
+- Request-level failures keep normal HTTP statuses (400 bad URL, 404
+ descriptor unrecoverable is expressed in-band as `failed` terminal event
+ where possible; a URL that cannot even parse is 400 before the stream
+ starts).
+
+## 5. Client bindings (all kept in lockstep)
+
+- **C client** (`src/ClientLibs/c/offs_client.h/.c`):
+ `offs_client_load(ori_string, on_progress_cb, on_end_cb, on_error_cb, ctx)`
+ — progress callback `(ctx, tuples_loaded, tuples_total)`, end callback
+ `(ctx, status, tuples_loaded, tuples_total)`. Same lock/snapshot/dispatch
+ pattern as the peer ops.
+- **JS client** (`src/ClientLibs/js/offs-client/`):
+ `load(ori, { onProgress(tuplesLoaded, tuplesTotal), onEnd(status, tuplesLoaded, tuplesTotal), onError })`
+ — HTTP transport reads the ndjson stream via the existing chunked
+ body machinery; CBOR transports use frames 39–41. `dist/` rebuilt.
+- **Dart/Flutter binding** (`examples/off_client/lib/services/off_api.dart`):
+ `load(String offUrl, {void Function(int, int)? onProgress})` returning the
+ terminal result — via the HTTP ndjson stream. **Catch-up for QR** (never
+ added in the QR feature): `connectPeerImage(Uint8List ppmBytes)` and
+ `addFriendImage(Uint8List ppmBytes)` posting `image/x-portable-pixmap`
+ bodies; `getPeerInfo(format: 'qrcode')` already works via the existing
+ `format` param.
+- **CLI** (`OFFS/src/offs/commands/load.c`): `offs load ` printing
+ `Loading : n/m tuples (pct)` on stderr (same pattern as `put`),
+ exit 0 on loaded/partial (partial prints a warning histogram line),
+ exit 1 on failed. HTTP-only option is unnecessary — the CLI ships over
+ the existing unix socket.
+- **GUI note**: the ndjson stream maps directly to a progress bar
+ (`tuples_loaded/tuples_total`); terminal status distinguishes
+ "available on this node" from "partially available".
+
+## 6. Testing
+
+- `readable_off_stream` load-mode unit tests: skip-on-tuple-timeout,
+ descriptor-miss → failed, tallies correct, normal (non-load) mode
+ unchanged.
+- Wire tests: 39/40/41 encode/decode round-trips, optional-range variants,
+ backward-compat (frames < 39 unaffected).
+- HTTP route test: `?load=1` ndjson shape (progress lines + terminal line),
+ content type, and normal GET unchanged on the same URL without the flag.
+- Binding tests: JS unit for `load()` over a mock transport; Dart analyzer
+ run on the binding change.
+- E2E against a real daemon: load of a previously-uploaded file →
+ `loaded` with full tallies; load of an ORI referencing garbage hashes →
+ `failed`/`partial` behavior confirmed within the 30 s deadline window;
+ CLI progress output.
+- Valgrind with `-gdwarf-4` on new suites; ASAN if harnesses allow.
+
+## 7. Out of scope
+
+- Parallel multi-tuple prefetch (v2; wanted-list coalescing and progress
+ streaming make sequential acceptable for v1).
+- Block-level progress reporting (rejected in brainstorm — tuple-level only).
+- Load-job persistence/retry across daemon restarts.
+- A pollable job-id API (the streaming design removes the need).
\ No newline at end of file
diff --git a/examples/off_client/lib/services/off_api.dart b/examples/off_client/lib/services/off_api.dart
index df47b6d4..a3e55ca5 100644
--- a/examples/off_client/lib/services/off_api.dart
+++ b/examples/off_client/lib/services/off_api.dart
@@ -204,6 +204,79 @@ class OffApi extends ChangeNotifier {
}
}
+ /// Load a file's blocks into the daemon's block cache without transferring
+ /// the data ("pin to node"). Streams application/x-ndjson progress:
+ /// {"tuples_loaded":n,"tuples_total":m} per resolved tuple, terminated by
+ /// {"status":"loaded|partial|failed","tuples_loaded":n,"tuples_total":m}.
+ /// onProgress fires per progress line; the returned map is the terminal line.
+ Future> loadContent(
+ String offUrl, {
+ void Function(int loaded, int total)? onProgress,
+ }) async {
+ final uri = Uri.parse(offUrl);
+ final request = http.Request('GET', uri);
+ final client = http.Client();
+ try {
+ final streamed = await client.send(request);
+ try {
+ if (streamed.statusCode != 200) {
+ final errorBody = await streamed.stream.bytesToString();
+ throw Exception('Load failed: ${streamed.statusCode} $errorBody');
+ }
+
+ Map? terminal;
+ String lineBuffer = '';
+
+ void handleLine(String line) {
+ final trimmed = line.trim();
+ if (trimmed.isEmpty) return;
+ Object? decoded;
+ try {
+ decoded = json.decode(trimmed);
+ } on FormatException {
+ throw FormatException('Bad ndjson line: $trimmed');
+ }
+ if (decoded is! Map) {
+ throw FormatException('Bad ndjson line: $trimmed');
+ }
+ if (decoded.containsKey('status')) {
+ terminal = decoded;
+ } else {
+ onProgress?.call(
+ (decoded['tuples_loaded'] as num).toInt(),
+ (decoded['tuples_total'] as num).toInt(),
+ );
+ }
+ }
+
+ await for (final chunk in streamed.stream) {
+ lineBuffer += utf8.decode(chunk, allowMalformed: true);
+ var newlineIndex = lineBuffer.indexOf('\n');
+ while (newlineIndex >= 0) {
+ handleLine(lineBuffer.substring(0, newlineIndex));
+ lineBuffer = lineBuffer.substring(newlineIndex + 1);
+ newlineIndex = lineBuffer.indexOf('\n');
+ }
+ }
+ // Tolerate a final line missing its terminating newline.
+ if (lineBuffer.trim().isNotEmpty) {
+ handleLine(lineBuffer);
+ }
+
+ if (terminal == null) {
+ throw StateError('load stream ended without terminal line');
+ }
+ return terminal!;
+ } finally {
+ // Ensure the connection is released on early exits (non-200, parse
+ // errors) as well as the happy path.
+ await streamed.stream.drain().catchError((_) {});
+ }
+ } finally {
+ client.close();
+ }
+ }
+
Future deleteContent(String offUrl) async {
final uri = Uri.parse(offUrl);
final request = http.Request('DELETE', uri);
@@ -262,6 +335,22 @@ class OffApi extends ChangeNotifier {
throw Exception('Peer connect failed: ${response.statusCode}');
}
+ /// Connect to a peer from a QR image (binary P6 PPM, exactly the bytes the
+ /// daemon's /peer/info?format=qrcode returns). Posts image/x-portable-pixmap.
+ /// Returns the daemon's status json ({"status": 0..4, "message": ...}).
+ Future> connectPeerImage(Uint8List ppmBytes) async {
+ final uri = Uri.parse('$baseUrl/peer/connect');
+ final response = await http.post(uri, headers: {
+ if (_apiKey != null) 'Authorization': 'Bearer $_apiKey',
+ 'Content-Type': 'image/x-portable-pixmap',
+ }, body: ppmBytes);
+ if (response.statusCode == 200) {
+ return json.decode(utf8.decode(response.bodyBytes))
+ as Map;
+ }
+ throw Exception('Peer connect failed: ${response.statusCode}');
+ }
+
Future>> listPeers() async {
final uri = Uri.parse('$baseUrl/peers');
final response = await http.get(uri, headers: {
@@ -286,6 +375,23 @@ class OffApi extends ChangeNotifier {
}
}
+ /// Add a friend from a QR image (binary P6 PPM, exactly the bytes the
+ /// daemon's /peer/info?format=qrcode returns). Posts image/x-portable-pixmap.
+ /// Returns the daemon's status json ({"status": "added"} on success); a
+ /// non-200 response (e.g. 409 already_friend) throws, mirroring addFriend.
+ Future> addFriendImage(Uint8List ppmBytes) async {
+ final uri = Uri.parse('$baseUrl/friends');
+ final response = await http.post(uri, headers: {
+ if (_apiKey != null) 'Authorization': 'Bearer $_apiKey',
+ 'Content-Type': 'image/x-portable-pixmap',
+ }, body: ppmBytes);
+ if (response.statusCode == 200) {
+ return json.decode(utf8.decode(response.bodyBytes))
+ as Map;
+ }
+ throw Exception('Friend add failed: ${response.statusCode}');
+ }
+
Future removeFriend(String nodeId) async {
final uri = Uri.parse('$baseUrl/friends/$nodeId');
final response = await http.delete(uri, headers: {
diff --git a/src/ClientAPI/HTTP/http_connection.c b/src/ClientAPI/HTTP/http_connection.c
index 5e74df6a..3b90cf51 100644
--- a/src/ClientAPI/HTTP/http_connection.c
+++ b/src/ClientAPI/HTTP/http_connection.c
@@ -339,9 +339,13 @@ static void _connection_stop_watcher(http_connection_t* connection) {
/* Close the fd and mark connection as closing. Used from dispatch (worker thread). */
static void _connection_close_fd(http_connection_t* connection) {
- if (connection->sock != NULL) {
- platform_socket_destroy(connection->sock);
- connection->sock = NULL;
+ platform_socket_t* sock = ATOMIC_EXCHANGE(&connection->sock, NULL);
+ if (sock != NULL) {
+ if (connection->server != NULL) {
+ http_server_defer_socket_destroy(connection->server, sock);
+ } else {
+ platform_socket_destroy(sock);
+ }
}
connection->is_closing = 1;
}
@@ -359,8 +363,9 @@ static int _connection_send_raw_blocking(http_connection_t* connection,
const uint8_t* data, size_t len,
size_t* out_sent) {
size_t sent_total = 0;
+ platform_socket_t* sock = ATOMIC_LOAD(&connection->sock);
for (int attempts = 0; attempts < 2000 && sent_total < len; attempts++) {
- ssize_t sent = platform_socket_send(connection->sock, data + sent_total,
+ ssize_t sent = platform_socket_send(sock, data + sent_total,
len - sent_total);
if (sent > 0) {
sent_total += (size_t)sent;
@@ -461,13 +466,13 @@ static int _connection_send_all_blocking(http_connection_t* connection,
* cross-thread race on the BIO. */
static void _connection_ssl_data_handle(http_connection_t* connection,
buffer_t* data) {
- if (connection->sock == NULL || connection->ssl == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL || connection->ssl == NULL) {
return;
}
BIO_write(connection->rbio, data->data, (int)data->size);
for (int batch = 0; batch < 16; batch++) {
- if (connection->sock == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL) {
return;
}
char buffer[READ_BUFFER_SIZE];
@@ -566,7 +571,7 @@ void http_connection_dispatch(void* state, message_t* msg) {
/* ASIO-style: the I/O thread notified us that data is available.
Perform the actual recv() and parsing here on the scheduler worker. */
atomic_store(&connection->read_pending, 0);
- if (connection->sock == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL) {
break;
}
#ifndef _WIN32
@@ -582,7 +587,7 @@ void http_connection_dispatch(void* state, message_t* msg) {
goes through READABLE -> _connection_do_reads. */
buffer_t* data = (buffer_t*)msg->payload;
msg->payload = NULL; /* Take ownership — actor_run won't destroy it */
- if (connection->sock == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL) {
DESTROY(data, buffer);
break;
}
@@ -629,7 +634,7 @@ void http_connection_dispatch(void* state, message_t* msg) {
case HTTP_CONNECTION_WRITE: {
buffer_t* buf = (buffer_t*)msg->payload;
msg->payload = NULL; /* Take ownership — actor_run won't destroy it */
- if (connection->sock == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL) {
DESTROY(buf, buffer);
break;
}
@@ -696,7 +701,7 @@ void http_connection_dispatch(void* state, message_t* msg) {
break;
}
/* Try direct send */
- ssize_t sent = platform_socket_send(connection->sock, buf->data, buf->size);
+ ssize_t sent = platform_socket_send(ATOMIC_LOAD(&connection->sock), buf->data, buf->size);
if (sent < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
connection->write_buffer = buf;
@@ -728,7 +733,7 @@ void http_connection_dispatch(void* state, message_t* msg) {
}
case HTTP_CONNECTION_WRITABLE: {
- if (connection->sock == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL) {
break;
}
if (connection->write_buffer == NULL || connection->write_buffer->size == 0) {
@@ -736,7 +741,7 @@ void http_connection_dispatch(void* state, message_t* msg) {
_connection_update_watcher(connection, PD_EVENT_READ);
break;
}
- ssize_t sent = platform_socket_send(connection->sock, connection->write_buffer->data,
+ ssize_t sent = platform_socket_send(ATOMIC_LOAD(&connection->sock), connection->write_buffer->data,
connection->write_buffer->size);
if (sent > 0) {
if ((size_t)sent >= connection->write_buffer->size) {
@@ -745,8 +750,8 @@ void http_connection_dispatch(void* state, message_t* msg) {
connection->write_pending = 0;
if (connection->is_closing) {
/* All data flushed — finish the deferred close */
- if (connection->sock != NULL) {
- platform_socket_shutdown(connection->sock, PLATFORM_SHUT_WR);
+ if (ATOMIC_LOAD(&connection->sock) != NULL) {
+ platform_socket_shutdown(ATOMIC_LOAD(&connection->sock), PLATFORM_SHUT_WR);
}
_connection_stop_watcher(connection);
_connection_close_fd(connection);
@@ -785,8 +790,8 @@ void http_connection_dispatch(void* state, message_t* msg) {
_connection_update_watcher(connection, PD_EVENT_READ | PD_EVENT_WRITE);
break;
}
- if (connection->sock != NULL) {
- platform_socket_shutdown(connection->sock, PLATFORM_SHUT_WR);
+ if (ATOMIC_LOAD(&connection->sock) != NULL) {
+ platform_socket_shutdown(ATOMIC_LOAD(&connection->sock), PLATFORM_SHUT_WR);
}
_connection_stop_watcher(connection);
_connection_close_fd(connection);
@@ -915,10 +920,11 @@ static void _connection_read_callback(pd_loop_t* loop, pd_watcher_t* watcher,
if (total_read == 0) {
/* POSIX path: synchronous recv. The socket may already be closed if the
connection was torn down concurrently with a pending READ event. */
- if (connection->sock == NULL) {
+ platform_socket_t* sock = ATOMIC_LOAD(&connection->sock);
+ if (sock == NULL) {
return;
}
- ssize_t bytes_read = platform_socket_recv(connection->sock, buffer, sizeof(buffer));
+ ssize_t bytes_read = platform_socket_recv(sock, buffer, sizeof(buffer));
if (bytes_read <= 0) {
if (bytes_read == 0) {
message_t msg;
@@ -965,7 +971,7 @@ static void _connection_do_reads(http_connection_t* connection) {
}
for (int batch = 0; batch < 16; batch++) {
char buffer[READ_BUFFER_SIZE];
- if (connection->sock == NULL) {
+ if (ATOMIC_LOAD(&connection->sock) == NULL) {
return;
}
@@ -1012,7 +1018,7 @@ http_connection_t* http_connection_create(http_server_t* server, platform_socket
http_connection_t* connection = get_clear_memory(sizeof(http_connection_t));
refcounter_init((refcounter_t*)connection);
connection->server = server;
- connection->sock = sock;
+ ATOMIC_STORE(&connection->sock, sock);
connection->ssl = NULL;
connection->rbio = NULL;
connection->wbio = NULL;
@@ -1116,9 +1122,9 @@ void http_connection_destroy(http_connection_t* connection) {
pd_timer_destroy(timer);
}
}
- if (connection->sock != NULL) {
- platform_socket_destroy(connection->sock);
- connection->sock = NULL;
+ platform_socket_t* sock = ATOMIC_EXCHANGE(&connection->sock, NULL);
+ if (sock != NULL) {
+ platform_socket_destroy(sock);
}
if (connection->request != NULL) {
DESTROY(connection->request, http_request);
@@ -1140,7 +1146,7 @@ void http_connection_destroy(http_connection_t* connection) {
}
void http_connection_write(http_connection_t* connection, const char* data, size_t length) {
- if (connection == NULL || connection->sock == NULL) {
+ if (connection == NULL || ATOMIC_LOAD(&connection->sock) == NULL) {
return;
}
buffer_t* buf = buffer_create_from_pointer_copy((uint8_t*)data, length);
diff --git a/src/ClientAPI/HTTP/http_connection.h b/src/ClientAPI/HTTP/http_connection.h
index 040e7e0c..87f44260 100644
--- a/src/ClientAPI/HTTP/http_connection.h
+++ b/src/ClientAPI/HTTP/http_connection.h
@@ -32,7 +32,7 @@ typedef struct http_connection_t {
refcounter_t refcounter;
actor_t actor;
http_server_t* server;
- platform_socket_t* sock;
+ ATOMIC(platform_socket_t*) sock;
ATOMIC(pd_watcher_t*) watcher;
SSL* ssl;
/* Windows IOCP only: memory BIO pair decoupling OpenSSL from the socket so
diff --git a/src/ClientAPI/HTTP/http_response.c b/src/ClientAPI/HTTP/http_response.c
index 2cae777e..0639156b 100644
--- a/src/ClientAPI/HTTP/http_response.c
+++ b/src/ClientAPI/HTTP/http_response.c
@@ -26,7 +26,11 @@ static void _send_headers(http_response_t* response) {
}
response->headers_sent = 1;
- if (http_headers_get(&response->headers, "Content-Length") == NULL) {
+ /* The body length of an unknown-length response only settles when the
+ response ends — emit close-delimited framing instead of stamping a
+ Content-Length from the bytes written so far. */
+ if (!response->unknown_length &&
+ http_headers_get(&response->headers, "Content-Length") == NULL) {
char content_length_str[32];
snprintf(content_length_str, sizeof(content_length_str), "%zu", response->body_length);
http_headers_set(&response->headers, "Content-Length", content_length_str);
diff --git a/src/ClientAPI/HTTP/http_response.h b/src/ClientAPI/HTTP/http_response.h
index cbc24797..c5dcdfd7 100644
--- a/src/ClientAPI/HTTP/http_response.h
+++ b/src/ClientAPI/HTTP/http_response.h
@@ -19,6 +19,12 @@ typedef struct http_response_t {
uint8_t headers_sent;
uint8_t is_piped;
uint8_t keep_alive;
+ /* 1 = the body length is not known until the response ends (e.g. the load
+ ndjson surface). _send_headers must NOT stamp a Content-Length from the
+ accumulated body_length; the response is close-delimited, and the caller
+ forces keep_alive = 0 before the first write so it terminates the
+ connection at http_response_end. */
+ uint8_t unknown_length;
size_t body_length;
http_connection_t* connection;
} http_response_t;
diff --git a/src/ClientAPI/HTTP/http_server.c b/src/ClientAPI/HTTP/http_server.c
index ef9beee4..7c43319a 100644
--- a/src/ClientAPI/HTTP/http_server.c
+++ b/src/ClientAPI/HTTP/http_server.c
@@ -28,7 +28,7 @@ static void _destroy_stack_init(http_server_t* server) {
static void _destroy_stack_push_watcher(http_server_t* server, pd_watcher_t* watcher) {
server_destroy_node_t* node = get_clear_memory(sizeof(server_destroy_node_t));
node->watcher = watcher;
- node->is_timer = 0;
+ node->type = 0;
platform_mutex_lock(server->destroy_lock);
node->next = server->destroy_head;
server->destroy_head = node;
@@ -39,7 +39,18 @@ static void _destroy_stack_push_watcher(http_server_t* server, pd_watcher_t* wat
static void _destroy_stack_push_timer(http_server_t* server, pd_timer_t* timer) {
server_destroy_node_t* node = get_clear_memory(sizeof(server_destroy_node_t));
node->timer = timer;
- node->is_timer = 1;
+ node->type = 1;
+ platform_mutex_lock(server->destroy_lock);
+ node->next = server->destroy_head;
+ server->destroy_head = node;
+ platform_mutex_unlock(server->destroy_lock);
+ pd_loop_async_send(server->loop, NULL);
+}
+
+void http_server_defer_socket_destroy(http_server_t* server, platform_socket_t* sock) {
+ server_destroy_node_t* node = get_clear_memory(sizeof(server_destroy_node_t));
+ node->sock = sock;
+ node->type = 2;
platform_mutex_lock(server->destroy_lock);
node->next = server->destroy_head;
server->destroy_head = node;
@@ -55,9 +66,11 @@ static void _destroy_stack_drain(http_server_t* server) {
platform_mutex_unlock(server->destroy_lock);
while (node != NULL) {
server_destroy_node_t* next = node->next;
- if (node->is_timer) {
+ if (node->type == 1) {
pd_timer_stop(node->timer);
pd_timer_destroy(node->timer);
+ } else if (node->type == 2) {
+ platform_socket_destroy(node->sock);
} else {
pd_watcher_destroy(node->watcher);
}
@@ -254,9 +267,9 @@ void http_server_destroy(http_server_t* server) {
for (int i = 0; i < server->connections.length; i++) {
http_connection_t* conn = server->connections.data[i];
conn->is_closing = 1;
- if (conn->sock != NULL) {
- platform_socket_destroy(conn->sock);
- conn->sock = NULL;
+ platform_socket_t* sock = ATOMIC_EXCHANGE(&conn->sock, NULL);
+ if (sock != NULL) {
+ platform_socket_destroy(sock);
}
conn->server = NULL;
}
diff --git a/src/ClientAPI/HTTP/http_server.h b/src/ClientAPI/HTTP/http_server.h
index 7c5bc1db..39905754 100644
--- a/src/ClientAPI/HTTP/http_server.h
+++ b/src/ClientAPI/HTTP/http_server.h
@@ -31,9 +31,10 @@ typedef vec_t(http_middleware_entry_t) vec_middleware_t;
typedef vec_t(http_connection_t*) vec_connection_t;
typedef struct server_destroy_node_t {
- pd_watcher_t* watcher; /* valid when is_timer == 0 */
- pd_timer_t* timer; /* valid when is_timer == 1 */
- uint8_t is_timer;
+ pd_watcher_t* watcher; /* valid when type == 0 */
+ pd_timer_t* timer; /* valid when type == 1 */
+ platform_socket_t* sock; /* valid when type == 2 */
+ uint8_t type; /* 0 = watcher, 1 = timer, 2 = socket */
struct server_destroy_node_t* next;
} server_destroy_node_t;
@@ -85,6 +86,10 @@ void http_server_set_timeouts(http_server_t* server, uint32_t idle_ms, uint32_t
void http_server_dispatch(http_server_t* server, http_request_t* request, http_response_t* response);
+/* Defer a connection socket's close+free to the I/O thread's destroy stack so
+ it is never freed while the I/O-thread read callback may still be using it. */
+void http_server_defer_socket_destroy(http_server_t* server, platform_socket_t* sock);
+
http_route_t* http_server_match_route(http_server_t* server, int method, const char* path);
void http_server_use(http_server_t* server, http_middleware_t middleware, void* user_data, void (*user_data_destroy)(void*));
diff --git a/src/ClientAPI/HTTP/off_routes.c b/src/ClientAPI/HTTP/off_routes.c
index 4772ed3c..4d354612 100644
--- a/src/ClientAPI/HTTP/off_routes.c
+++ b/src/ClientAPI/HTTP/off_routes.c
@@ -7,6 +7,7 @@
#endif
#include "off_routes.h"
#include "http_response.h"
+#include "../client_api_wire.h"
#include "http_request.h"
#include "http_connection.h"
#include "http_server.h"
@@ -165,6 +166,11 @@ typedef struct {
tuple_cache_t* tc;
http_response_t* response;
ori_t* ori;
+ /* desc_done ensures desc contributes exactly one pipeline deref,
+ whether close or error fires first. stream_deactivate emits both
+ close_event and error_event, so without this flag the pipeline
+ would be dereffed twice for desc. */
+ uint8_t desc_done;
} get_pipeline_t;
static void _pipeline_on_tuple(void* ctx, void* data) {
@@ -177,7 +183,11 @@ static void _pipeline_on_desc_close(void* ctx, void* unused) {
(void)unused;
get_pipeline_t* pipeline = (get_pipeline_t*)ctx;
readable_descriptor_t* desc = pipeline->desc;
- int is_zero = refcounter_dereference_is_zero((refcounter_t*)pipeline);
+ int is_zero = 0;
+ if (!pipeline->desc_done) {
+ pipeline->desc_done = 1;
+ is_zero = refcounter_dereference_is_zero((refcounter_t*)pipeline);
+ }
stream_deferred_deref((stream_t*)desc);
if (is_zero) {
DESTROY(pipeline->ori, ori);
@@ -193,7 +203,12 @@ static void _pipeline_on_desc_error(void* ctx, void* error) {
end/destroy the response here; _pipe_on_error and _pipe_on_close
both fire on stream deactivation and would double-free. */
stream_deactivate((stream_t*)pipeline->rs, NULL);
- if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ int is_zero = 0;
+ if (!pipeline->desc_done) {
+ pipeline->desc_done = 1;
+ is_zero = refcounter_dereference_is_zero((refcounter_t*)pipeline);
+ }
+ if (is_zero) {
DESTROY(pipeline->ori, ori);
free(pipeline);
}
@@ -223,11 +238,10 @@ static void _setup_stream_pipeline(http_response_t* response, scheduler_pool_t*
pipeline->tc = tc;
pipeline->response = response;
pipeline->ori = stream_ori;
+ /* Two derefs total: one for desc-done (close or error, whichever
+ fires first — guarded by desc_done), one for rs-done. */
refcounter_init((refcounter_t*)pipeline);
refcounter_reference((refcounter_t*)pipeline);
- refcounter_reference((refcounter_t*)pipeline);
- refcounter_reference((refcounter_t*)pipeline);
- refcounter_reference((refcounter_t*)pipeline);
stream_subscribe((stream_t*)desc, data_event, pipeline,
(void (*)(void*, void*))_pipeline_on_tuple, NULL);
@@ -242,6 +256,303 @@ static void _setup_stream_pipeline(http_response_t* response, scheduler_pool_t*
readable_descriptor_push(desc);
}
+/* ---- ?load=1 cache-load pipeline ---- */
+
+/* True when the request's query string enables the given parameter: either a
+ bare token ("?load") or "load=1". Any other value ("?load=0") is treated as
+ NOT enabled. Parameters are '&'-separated, so a file NAME that happens to
+ contain "load" can never match (names live in the path, not the query
+ string). */
+static int _query_has_param(const char* query_string, const char* name) {
+ if (query_string == NULL) return 0;
+ size_t name_len = strlen(name);
+ const char* cursor = query_string;
+ while (*cursor != '\0') {
+ const char* separator = strchr(cursor, '&');
+ size_t token_len = separator != NULL ? (size_t)(separator - cursor) : strlen(cursor);
+ if (token_len == name_len && strncmp(cursor, name, name_len) == 0) {
+ return 1;
+ }
+ if (token_len > name_len && strncmp(cursor, name, name_len) == 0 &&
+ cursor[name_len] == '=') {
+ /* Bare token matched above; here only "?load=1" enables —
+ "?load=0" and any other value do not. */
+ return token_len == name_len + 2 && cursor[name_len + 1] == '1';
+ }
+ if (separator == NULL) break;
+ cursor = separator + 1;
+ }
+ return 0;
+}
+
+/* Pipeline context for GET ...?load=1: pulls a file's blocks into the block
+ * cache without serving file data, forwarding tuple-level progress as ndjson
+ * lines and terminating with exactly one terminal line. Refcount discipline
+ * mirrors get_pipeline_t; the terminal state machine mirrors the unix
+ * _unix_load_pipeline_t. */
+typedef struct {
+ refcounter_t refcounter;
+ http_response_t* response;
+ /* Snapshot of response->connection at setup time. Held so the terminal
+ can release the setup's connection reference even if another teardown
+ has since detached the response (response->connection == NULL). */
+ http_connection_t* connection;
+ readable_off_stream_t* rs;
+ readable_descriptor_t* desc;
+ ori_t* ori;
+ size_t tuples_total; /* ceil(final_byte / block_size) - offset tuples */
+ size_t tuples_loaded; /* maintained from load_tuple_event payloads */
+ size_t tuples_skipped; /* maintained from load_tuple_event payloads */
+ uint8_t failed; /* an error_event fired on desc or rs */
+ uint8_t terminal_written; /* guards the single terminal line */
+ /* desc_done ensures desc contributes exactly one pipeline deref,
+ whether close or error fires first (stream_deactivate emits both). */
+ uint8_t desc_done;
+} off_load_pipeline_t;
+
+static void _load_pipeline_free(off_load_pipeline_t* pipeline) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+}
+
+/* The single ndjson terminal line and the end of the response. The
+ connection lifetime mirrors http_response_pipe's _pipe_on_close: the load
+ setup took one reference each on the response and connection, released
+ here once the response is ended (keep_alive is 0, so end() closes the
+ socket — the body is close-delimited). */
+static void _load_pipeline_terminal(off_load_pipeline_t* pipeline) {
+ if (pipeline->terminal_written) {
+ return;
+ }
+ pipeline->terminal_written = 1;
+ uint8_t status = CLIENT_API_LOAD_STATUS_LOADED;
+ if (pipeline->failed) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_total > 0 && pipeline->tuples_loaded == 0) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_skipped > 0) {
+ status = CLIENT_API_LOAD_STATUS_PARTIAL;
+ }
+ char line[128];
+ int line_len = snprintf(line, sizeof(line),
+ "{\"status\":\"%s\",\"tuples_loaded\":%zu,\"tuples_total\":%zu}\n",
+ status == CLIENT_API_LOAD_STATUS_FAILED ? "failed" :
+ status == CLIENT_API_LOAD_STATUS_PARTIAL ? "partial" : "loaded",
+ pipeline->tuples_loaded, pipeline->tuples_total);
+ http_response_t* response = pipeline->response;
+ http_connection_t* connection = pipeline->connection;
+ pipeline->response = NULL;
+ pipeline->connection = NULL;
+ /* Client-vanished guard: whenever another teardown detached the response
+ (response->connection == NULL), its write path is dead — skip the
+ final line and just drop this pipeline's setup references, exactly
+ like the live path releases them below. */
+ if (response->connection != NULL) {
+ http_response_write(response, line, (size_t)line_len);
+ http_response_end(response);
+ }
+ response->connection = NULL;
+ http_response_destroy(response);
+ http_connection_destroy(connection);
+}
+
+/* The load_tuple_event payload is CONSUME-transferred: the notify machinery
+ * holds the reference and destroys it after dispatch. Copy the counters,
+ * never destroy or dereference the payload here. */
+static void _load_pipeline_on_tuple_loaded(void* ctx, void* data) {
+ off_load_pipeline_t* pipeline = (off_load_pipeline_t*)ctx;
+ load_tuple_payload_t* progress = (load_tuple_payload_t*)data;
+ if (progress != NULL) {
+ pipeline->tuples_loaded = progress->tuples_loaded;
+ pipeline->tuples_skipped = progress->tuples_skipped;
+ }
+ char line[64];
+ int line_len = snprintf(line, sizeof(line),
+ "{\"tuples_loaded\":%zu,\"tuples_total\":%zu}\n",
+ pipeline->tuples_loaded, pipeline->tuples_total);
+ /* The terminal tears the response down (exactly once) — never touch it
+ past that point. */
+ if (!pipeline->terminal_written && pipeline->response->connection != NULL) {
+ http_response_write(pipeline->response, line, (size_t)line_len);
+ }
+
+ /* Pipeline-driven completion: a skipped tuple never renders and never
+ advances sent_bytes, so the render path cannot close the stream once
+ the tally completes. close_event — not this tally — is the single
+ terminal trigger; request_close is idempotent, so the all-loaded path
+ (already closed by render) is unaffected. */
+ if (pipeline->tuples_loaded + pipeline->tuples_skipped >= pipeline->tuples_total) {
+ readable_off_stream_request_close(pipeline->rs);
+ }
+}
+
+static void _load_pipeline_on_tuple(void* ctx, void* data) {
+ off_load_pipeline_t* pipeline = (off_load_pipeline_t*)ctx;
+ tuple_t* tuple = (tuple_t*)data;
+ readable_off_stream_write(pipeline->rs, tuple);
+}
+
+static void _load_pipeline_on_rs_close(void* ctx, void* unused) {
+ (void)unused;
+ off_load_pipeline_t* pipeline = (off_load_pipeline_t*)ctx;
+ readable_off_stream_t* rs = pipeline->rs;
+ /* Tally-before-close ordering (Task 2) guarantees the tuple counters
+ were updated before this terminal line is written. */
+ _load_pipeline_terminal(pipeline);
+ int is_zero = refcounter_dereference_is_zero((refcounter_t*)pipeline);
+ stream_deferred_deref((stream_t*)rs);
+ if (is_zero) {
+ _load_pipeline_free(pipeline);
+ }
+}
+
+static void _load_pipeline_on_rs_error(void* ctx, void* error) {
+ (void)error;
+ off_load_pipeline_t* pipeline = (off_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ /* Deactivating queues rs close_event right after this error; that close
+ writes the single terminal line and tears down the response. Only
+ deactivate when the error did not already come from one —
+ stream_deactivate re-notifies error_event UNCONDITIONALLY, so an
+ unguarded re-deactivate here would loop forever. */
+ if (!pipeline->rs->stream.is_deactivated) {
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+ }
+}
+
+static void _load_pipeline_on_desc_close(void* ctx, void* unused) {
+ (void)unused;
+ off_load_pipeline_t* pipeline = (off_load_pipeline_t*)ctx;
+ readable_descriptor_t* desc = pipeline->desc;
+ int is_zero = 0;
+ if (!pipeline->desc_done) {
+ pipeline->desc_done = 1;
+ is_zero = refcounter_dereference_is_zero((refcounter_t*)pipeline);
+ }
+ /* desc close while the final tuple is still in flight must NOT end the
+ response — only the rs close_event does that. */
+ stream_deferred_deref((stream_t*)desc);
+ if (is_zero) {
+ _load_pipeline_free(pipeline);
+ }
+}
+
+static void _load_pipeline_on_desc_error(void* ctx, void* error) {
+ (void)error;
+ off_load_pipeline_t* pipeline = (off_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ /* Mark failed and end the load via the rs close path (exactly one
+ terminal); DESC_ERROR implies DESC_CLOSE right after. No desc
+ re-deactivate here — the error already fired FROM a deactivated
+ descriptor, and re-deactivating would re-queue error_event. */
+ if (!pipeline->rs->stream.is_deactivated) {
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+ }
+ int is_zero = 0;
+ if (!pipeline->desc_done) {
+ pipeline->desc_done = 1;
+ is_zero = refcounter_dereference_is_zero((refcounter_t*)pipeline);
+ }
+ if (is_zero) {
+ _load_pipeline_free(pipeline);
+ }
+}
+
+static void _setup_load_pipeline(http_response_t* response, scheduler_pool_t* pool,
+ block_cache_t* bc, tuple_cache_t* tc, ori_t* stream_ori,
+ size_t descriptor_pad, network_t* network) {
+ readable_off_stream_t* rs = readable_off_stream_create_ex(pool, bc, tc, stream_ori,
+ descriptor_pad, network, 1);
+ readable_descriptor_t* desc = readable_descriptor_create(pool, bc, stream_ori,
+ descriptor_pad, network);
+
+ off_load_pipeline_t* pipeline = get_clear_memory(sizeof(off_load_pipeline_t));
+ pipeline->desc = desc;
+ pipeline->rs = rs;
+ pipeline->response = response;
+ pipeline->connection = response->connection;
+ pipeline->ori = stream_ori;
+ size_t block_size = off_block_size_for_type(stream_ori->block_type);
+ pipeline->tuples_total = (stream_ori->final_byte / block_size) +
+ ((stream_ori->final_byte % block_size) > 0 ? 1 : 0) -
+ (stream_ori->file_offset / block_size);
+ /* Two derefs total: one for rs-done (close), one for desc-done (close or
+ error, whichever fires first — guarded by desc_done). */
+ refcounter_init((refcounter_t*)pipeline);
+ refcounter_reference((refcounter_t*)pipeline);
+
+ stream_subscribe((stream_t*)rs, load_tuple_event, pipeline,
+ (void (*)(void*, void*))_load_pipeline_on_tuple_loaded, NULL);
+ stream_once((stream_t*)rs, close_event, pipeline,
+ (void (*)(void*, void*))_load_pipeline_on_rs_close, NULL);
+ stream_subscribe((stream_t*)rs, error_event, pipeline,
+ (void (*)(void*, void*))_load_pipeline_on_rs_error, NULL);
+ stream_once((stream_t*)desc, close_event, pipeline,
+ (void (*)(void*, void*))_load_pipeline_on_desc_close, NULL);
+ stream_once((stream_t*)desc, error_event, pipeline,
+ (void (*)(void*, void*))_load_pipeline_on_desc_error, NULL);
+ /* The descriptor feeds tuples into the off_stream; in load mode the
+ stream tallies/skips them instead of rendering file data. */
+ stream_subscribe((stream_t*)desc, data_event, pipeline,
+ (void (*)(void*, void*))_load_pipeline_on_tuple, NULL);
+
+ /* Unknown-length streaming body: no Content-Length is possible (the
+ terminal status and line count settle only at the end), so the
+ response is close-delimited and the connection is closed at the
+ terminal. Hold the response/connection for the duration, exactly like
+ http_response_pipe does. */
+ response->unknown_length = 1;
+ response->keep_alive = 0;
+ response->is_piped = 1;
+ response->connection->piped_pending = 1;
+ refcounter_reference((refcounter_t*)response);
+ refcounter_reference((refcounter_t*)response->connection);
+
+ readable_descriptor_push(desc);
+}
+
+/* GET ...?load=1 — pull the file's blocks into the block cache and stream
+ tuple-level progress as application/x-ndjson. Same ORI construction as
+ the GET data path, minus content-length framing. */
+static void _off_load_stream(http_request_t* request, http_response_t* response,
+ off_routes_context_t* ctx, off_url_t* url) {
+ size_t file_size = url->stream_length;
+ const char* range_header = http_request_header(request, "Range");
+ range_request_t range = parse_range_header(range_header, file_size);
+
+ http_response_set_status(response, HTTP_STATUS_OK);
+ http_response_set_header(response, "Content-Type", "application/x-ndjson");
+ http_response_set_header(response, "Cache-Control", "no-store");
+
+ if (range_header != NULL && !range.valid) {
+ http_response_set_status(response, HTTP_STATUS_RANGE_NOT_SATISFIABLE);
+ char cr_str[64];
+ snprintf(cr_str, sizeof(cr_str), "bytes */%zu", file_size);
+ http_response_set_header(response, "Content-Range", cr_str);
+ http_response_end(response);
+ return;
+ }
+
+ ori_t* stream_ori = ori_create(file_size);
+ stream_ori->descriptor_hash = buffer_copy(url->descriptor_hash);
+ stream_ori->file_hash = buffer_copy(url->file_hash);
+ stream_ori->file_name = strdup(url->file_name);
+ stream_ori->block_type = standard;
+ stream_ori->tuple_size = 3;
+
+ if (range.valid) {
+ http_response_set_status(response, HTTP_STATUS_PARTIAL_CONTENT);
+ char cr_str[128];
+ snprintf(cr_str, sizeof(cr_str), "bytes %zu-%zu/%zu",
+ range.start, range.end, file_size);
+ http_response_set_header(response, "Content-Range", cr_str);
+ stream_ori->file_offset = range.start;
+ stream_ori->final_byte = range.end + 1;
+ }
+
+ _setup_load_pipeline(response, ctx->pool, ctx->bc, ctx->tc, stream_ori, 32, ctx->network);
+}
+
/* ---- Async GET handler state ---- */
typedef enum {
@@ -333,6 +644,25 @@ static void _off_get_handler(http_request_t* request, http_response_t* response,
return;
}
+ /* ?load=1 (or bare ?load) — cache-load flow: pull the file's blocks into
+ the block cache without serving file data; progress streams as ndjson.
+ Checked BEFORE the directory branch: v1 rejects directory ORIs with a
+ clear 400 (parity with the socket LOAD handler). */
+ if (_query_has_param(request->query_string, "load")) {
+ if (url->content_type != NULL &&
+ strstr(url->content_type, "offsystem/directory") != NULL) {
+ http_response_set_status(response, 400);
+ http_response_write(response, "Load requires a file ORI, not a directory",
+ strlen("Load requires a file ORI, not a directory"));
+ http_response_end(response);
+ off_url_destroy(url);
+ return;
+ }
+ _off_load_stream(request, response, ctx, url);
+ off_url_destroy(url);
+ return;
+ }
+
/* Directory content type — needs async resolution */
if (url->content_type && strstr(url->content_type, "offsystem/directory") != NULL) {
diff --git a/src/ClientAPI/HTTP/peer_routes.c b/src/ClientAPI/HTTP/peer_routes.c
index ef8977eb..67d3937a 100644
--- a/src/ClientAPI/HTTP/peer_routes.c
+++ b/src/ClientAPI/HTTP/peer_routes.c
@@ -14,15 +14,13 @@
#include "../../Node/node.h"
#include "../../Util/allocator.h"
#include "../../Util/base58.h"
+#include "../../QR/qr.h"
+#include "../peer_handlers.h" /* peer_info_from_payload — shared decode helper */
#include
#include
#include
#include
-#ifdef HAS_QRENCODE
-#include
-#endif
-
typedef struct {
offs_node_t* node;
} peer_routes_ctx_t;
@@ -95,33 +93,20 @@ static size_t _serialize_cbor(cbor_item_t* item, uint8_t** out_bytes) {
static int _decode_peer_info_body(http_request_t* request, peer_info_t* info) {
const char* content_type = http_request_header(request, "Content-Type");
- if (content_type != NULL && strstr(content_type, "application/cbor") != NULL) {
- /* CBOR body */
+ if (content_type != NULL && strstr(content_type, "image/x-portable-pixmap") != NULL) {
+ /* QR image body — decode via the shared payload helper (format 2) */
if (request->body == NULL || request->body->size == 0) return -1;
+ return peer_info_from_payload(2, request->body->data, request->body->size, info);
+ }
- struct cbor_load_result load_result;
- cbor_item_t* item = cbor_load(request->body->data, request->body->size, &load_result);
- if (item == NULL || load_result.error.code != CBOR_ERR_NONE) {
- if (item != NULL) cbor_decref(&item);
- return -1;
- }
-
- int rc = peer_info_decode(item, info);
- cbor_decref(&item);
- return rc;
+ if (content_type != NULL && strstr(content_type, "application/cbor") != NULL) {
+ if (request->body == NULL || request->body->size == 0) return -1;
+ return peer_info_from_payload(0, request->body->data, request->body->size, info);
}
- /* Default: try Base58 (text/plain or no Content-Type) */
+ /* Default: base58 text (text/plain or no Content-Type) */
if (request->body == NULL || request->body->size == 0) return -1;
-
- /* Null-terminate body for base58_decode */
- char* body_str = get_clear_memory(request->body->size + 1);
- memcpy(body_str, request->body->data, request->body->size);
- body_str[request->body->size] = '\0';
-
- int rc = peer_info_from_base58(body_str, info);
- free(body_str);
- return rc;
+ return peer_info_from_payload(1, request->body->data, request->body->size, info);
}
/* --- Connect to peer and return status code --- */
@@ -171,89 +156,58 @@ static void _peer_info_handler(http_request_t* request, http_response_t* respons
if (info == NULL) {
http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
http_response_set_header(response, "Content-Type", "text/plain");
- http_response_write(response, "Failed to populate local addresses", 32);
+ http_response_write(response, "Failed to populate local addresses", 34);
http_response_end(response);
return;
}
-#ifdef HAS_QRENCODE
if (strcmp(format, "qrcode") == 0) {
- cbor_item_t* qr_cbor = peer_info_encode(info);
- if (qr_cbor == NULL) {
+ cbor_item_t* cbor_map = peer_info_encode(info);
+ if (cbor_map == NULL) {
http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
http_response_set_header(response, "Content-Type", "text/plain");
- http_response_write(response, "Failed to encode peer info", 25);
+ http_response_write(response, "Failed to encode peer info", 26);
http_response_end(response);
peer_info_destroy(info);
free(info);
return;
}
- size_t buf_size = cbor_serialized_size(qr_cbor);
- uint8_t* buf = get_clear_memory(buf_size);
- cbor_serialize(qr_cbor, buf, buf_size);
- cbor_decref(&qr_cbor);
-
- QRcode* qr = QRcode_encodeData((int)buf_size, buf, 0, QR_ECLEVEL_M);
- free(buf);
-
- if (qr == NULL) {
+ uint8_t* serialized = NULL;
+ size_t serialized_len = _serialize_cbor(cbor_map, &serialized);
+ cbor_decref(&cbor_map);
+ if (serialized_len == 0) {
http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
http_response_set_header(response, "Content-Type", "text/plain");
- http_response_write(response, "QR encoding failed", 18);
+ http_response_write(response, "CBOR serialization failed", 25);
http_response_end(response);
peer_info_destroy(info);
free(info);
return;
}
- // Generate a simple PPM (portable pixmap) image from QR bitmap
- // PPM is trivial to generate without libpng, widely supported
- int qr_size = qr->width;
- int scale = 4;
- int img_size = qr_size * scale;
- size_t ppm_header_len = snprintf(NULL, 0, "P6\n%d %d\n255\n", img_size, img_size);
- size_t ppm_size = ppm_header_len + (size_t)(img_size * img_size * 3);
- char* ppm = get_clear_memory(ppm_size);
- snprintf(ppm, ppm_size, "P6\n%d %d\n255\n", img_size, img_size);
- size_t offset = ppm_header_len;
- for (int y = 0; y < qr_size; y++) {
- for (int sy = 0; sy < scale; sy++) {
- for (int x = 0; x < qr_size; x++) {
- uint8_t pixel = (qr->data[y * qr_size + x] & 1) ? 0 : 255;
- for (int sx = 0; sx < scale; sx++) {
- ppm[offset++] = (char)pixel;
- ppm[offset++] = (char)pixel;
- ppm[offset++] = (char)pixel;
- }
- }
- }
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm(serialized, serialized_len, &ppm_len);
+ free(serialized);
+ if (ppm == NULL) {
+ http_response_set_status(response, HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ http_response_set_header(response, "Content-Type", "text/plain");
+ http_response_write(response, "QR encoding failed", 18);
+ http_response_end(response);
+ peer_info_destroy(info);
+ free(info);
+ return;
}
- QRcode_free(qr);
-
http_response_set_status(response, HTTP_STATUS_OK);
http_response_set_header(response, "Content-Type", "image/x-portable-pixmap");
- http_response_write(response, ppm, ppm_size);
+ http_response_write(response, (const char*)ppm, ppm_len);
free(ppm);
http_response_end(response);
peer_info_destroy(info);
free(info);
return;
}
-#endif
-
-#ifndef HAS_QRENCODE
- if (strcmp(format, "qrcode") == 0) {
- http_response_set_status(response, 501);
- http_response_set_header(response, "Content-Type", "text/plain");
- http_response_write(response, "QR code generation not available", 30);
- http_response_end(response);
- peer_info_destroy(info);
- free(info);
- return;
- }
-#endif
if (strcmp(format, "base58") == 0) {
char* b58 = peer_info_to_base58(info);
diff --git a/src/ClientAPI/TCP/tcp_connection.c b/src/ClientAPI/TCP/tcp_connection.c
index 6eb64526..4c5de8cc 100644
--- a/src/ClientAPI/TCP/tcp_connection.c
+++ b/src/ClientAPI/TCP/tcp_connection.c
@@ -220,6 +220,199 @@ static tcp_get_pipeline_t* _tcp_get_pipeline_create(tcp_connection_t* conn, ori_
return pipeline;
}
+/* --- LOAD pipeline callbacks --- */
+
+/* Pipeline context for LOAD requests. Subscription/refcount discipline
+ * mirrors tcp_get_pipeline_t. The TCP connection carries no network actor
+ * (no config_node on TCP/WS/WT transports), so load runs cache-only here. */
+typedef struct {
+ refcounter_t refcounter;
+ tcp_connection_t* conn;
+ readable_off_stream_t* rs;
+ readable_descriptor_t* desc;
+ ori_t* ori;
+ size_t tuples_total; /* ceil(final_byte / block_size) - offset tuples */
+ size_t tuples_loaded; /* maintained from load_tuple_event payloads */
+ size_t tuples_skipped; /* maintained from load_tuple_event payloads */
+ uint8_t failed; /* an error_event fired on desc or rs */
+ uint8_t terminal_sent; /* guards the single LOAD_END frame */
+} tcp_load_pipeline_t;
+
+static void _tcp_load_send_terminal(tcp_load_pipeline_t* pipeline) {
+ if (pipeline->terminal_sent) {
+ return;
+ }
+ pipeline->terminal_sent = 1;
+ uint8_t status = CLIENT_API_LOAD_STATUS_LOADED;
+ if (pipeline->failed) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_total > 0 && pipeline->tuples_loaded == 0) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_skipped > 0) {
+ status = CLIENT_API_LOAD_STATUS_PARTIAL;
+ }
+ cbor_item_t* frame = client_api_load_end_encode(
+ status, pipeline->tuples_loaded, pipeline->tuples_total);
+ _tcp_connection_send_frame(pipeline->conn, frame);
+}
+
+static void _tcp_load_on_tuple(void* ctx, void* data) {
+ tcp_load_pipeline_t* pipeline = (tcp_load_pipeline_t*)ctx;
+ tuple_t* tuple = (tuple_t*)data;
+ readable_off_stream_write(pipeline->rs, tuple);
+}
+
+/* The load_tuple_event payload is CONSUME-transferred: the notify machinery
+ * holds the reference and destroys it after dispatch. Copy the counters,
+ * never destroy or dereference the payload here. */
+static void _tcp_load_on_tuple_loaded(void* ctx, void* data) {
+ tcp_load_pipeline_t* pipeline = (tcp_load_pipeline_t*)ctx;
+ load_tuple_payload_t* progress = (load_tuple_payload_t*)data;
+ if (progress != NULL) {
+ pipeline->tuples_loaded = progress->tuples_loaded;
+ pipeline->tuples_skipped = progress->tuples_skipped;
+ }
+ cbor_item_t* frame = client_api_load_progress_encode(
+ pipeline->tuples_loaded, pipeline->tuples_total);
+ _tcp_connection_send_frame(pipeline->conn, frame);
+
+ /* Pipeline-driven completion: a skipped tuple never renders and never
+ * advances sent_bytes, so the render path cannot close the stream once the
+ * tally completes. When every tuple the descriptor enumerates has resolved
+ * (loaded + skipped reached the computed total), close the load stream so
+ * its close_event subscriber sends the terminal LOAD_END. close_event — not
+ * this tally — is the single LOAD_END trigger; request_close is idempotent,
+ * so the all-loaded path (already closed by render) is unaffected. */
+ if (pipeline->tuples_loaded + pipeline->tuples_skipped >= pipeline->tuples_total) {
+ readable_off_stream_request_close(pipeline->rs);
+ }
+}
+
+static void _tcp_load_on_rs_close(void* ctx, void* unused) {
+ (void)unused;
+ tcp_load_pipeline_t* pipeline = (tcp_load_pipeline_t*)ctx;
+ /* Tally-before-close ordering (load mode) guarantees the tuple counters
+ * were updated before this terminal frame is sent; if not, last known
+ * counters are reported. */
+ _tcp_load_send_terminal(pipeline);
+ stream_deferred_deref((stream_t*)pipeline->rs);
+ ori_destroy(pipeline->ori);
+ if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+ }
+}
+
+static void _tcp_load_on_desc_close(void* ctx, void* unused) {
+ (void)unused;
+ tcp_load_pipeline_t* pipeline = (tcp_load_pipeline_t*)ctx;
+ stream_deferred_deref((stream_t*)pipeline->desc);
+ ori_destroy(pipeline->ori);
+ if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+ }
+}
+
+static void _tcp_load_on_rs_error(void* ctx, void* error) {
+ (void)error;
+ tcp_load_pipeline_t* pipeline = (tcp_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ /* stream_deactivate queues a close right after the error, which emits the
+ * terminal LOAD_END FAILED; terminal_sent keeps exactly one terminal. */
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+}
+
+static void _tcp_load_on_desc_error(void* ctx, void* error) {
+ (void)error;
+ tcp_load_pipeline_t* pipeline = (tcp_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+ stream_deactivate((stream_t*)pipeline->desc, NULL);
+}
+
+static void _tcp_handle_load(tcp_connection_t* conn, cbor_item_t* frame) {
+ if (!conn->is_authenticated) {
+ _tcp_connection_send_error(conn, CLIENT_API_STATUS_UNAUTHORIZED, "Authentication required");
+ return;
+ }
+ client_api_load_request_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_load_request_decode(frame, &msg) != 0) {
+ _tcp_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST, "Invalid load request");
+ return;
+ }
+
+ off_url_t* url = off_url_parse(msg.ori_string);
+ client_api_load_request_destroy(&msg);
+
+ if (url == NULL) {
+ _tcp_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST, "Invalid OFF URL");
+ return;
+ }
+
+ /* v1: directory ORIs are not loadable (resolved in HTTP land); reject. */
+ if (url->content_type != NULL && strstr(url->content_type, "offsystem/directory") != NULL) {
+ off_url_destroy(url);
+ _tcp_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST,
+ "Load requires a file ORI, not a directory");
+ return;
+ }
+
+ ori_t* ori = ori_create(url->stream_length);
+ ori->block_type = standard;
+ ori->tuple_size = 3;
+ if (url->descriptor_hash != NULL) {
+ ori->descriptor_hash = REFERENCE(url->descriptor_hash, buffer_t);
+ }
+ if (url->file_hash != NULL) {
+ ori->file_hash = REFERENCE(url->file_hash, buffer_t);
+ }
+ if (url->file_name != NULL) {
+ ori->file_name = get_memory(strlen(url->file_name) + 1);
+ memcpy(ori->file_name, url->file_name, strlen(url->file_name) + 1);
+ }
+ off_url_destroy(url);
+
+ /* Cache-only: TCP connections have no network actor access. */
+ network_t* network = NULL;
+
+ tcp_load_pipeline_t* pipeline = get_clear_memory(sizeof(tcp_load_pipeline_t));
+ refcounter_init((refcounter_t*)pipeline);
+ pipeline->conn = conn;
+ pipeline->ori = ori;
+ size_t block_size = off_block_size_for_type(ori->block_type);
+ pipeline->tuples_total = (ori->final_byte / block_size) +
+ ((ori->final_byte % block_size) > 0 ? 1 : 0) -
+ (ori->file_offset / block_size);
+
+ /* Reference count: 1 base + 1 for error callbacks that may both fire */
+ REFERENCE(pipeline, tcp_load_pipeline_t);
+
+ size_t descriptor_pad = 32;
+
+ readable_off_stream_t* rs = readable_off_stream_create_ex(
+ conn->pool, conn->bc, conn->tc, REFERENCE(ori, ori_t), descriptor_pad, network, 1);
+ readable_descriptor_t* desc = readable_descriptor_create(
+ conn->pool, conn->bc, REFERENCE(ori, ori_t), descriptor_pad, network);
+
+ pipeline->rs = rs;
+ pipeline->desc = desc;
+
+ /* NO data_event consumer on rs: load mode never serves file data */
+ stream_subscribe((stream_t*)rs, load_tuple_event, pipeline, _tcp_load_on_tuple_loaded, NULL);
+ stream_subscribe((stream_t*)rs, close_event, pipeline, _tcp_load_on_rs_close, NULL);
+ stream_subscribe((stream_t*)rs, error_event, pipeline, _tcp_load_on_rs_error, NULL);
+ stream_subscribe((stream_t*)desc, close_event, pipeline, _tcp_load_on_desc_close, NULL);
+ stream_subscribe((stream_t*)desc, error_event, pipeline, _tcp_load_on_desc_error, NULL);
+
+ /* Pipe: descriptor provides tuples to the off_stream */
+ stream_subscribe((stream_t*)desc, data_event, pipeline, _tcp_load_on_tuple, NULL);
+
+ /* Start the descriptor pull */
+ readable_descriptor_push(desc);
+}
+
/* --- PUT pipeline callbacks --- */
static void _tcp_put_on_descriptor_close(void* ctx, void* unused) {
@@ -612,6 +805,9 @@ static void _tcp_dispatch_frame(tcp_connection_t* conn, uint8_t type, cbor_item_
case CLIENT_API_GET_REQUEST:
_tcp_handle_get(conn, frame);
break;
+ case CLIENT_API_LOAD_REQUEST:
+ _tcp_handle_load(conn, frame);
+ break;
case CLIENT_API_PUT_REQUEST:
_tcp_handle_put(conn, frame);
break;
diff --git a/src/ClientAPI/Unix/unix_connection.c b/src/ClientAPI/Unix/unix_connection.c
index 5abc3e94..2822fcb3 100644
--- a/src/ClientAPI/Unix/unix_connection.c
+++ b/src/ClientAPI/Unix/unix_connection.c
@@ -222,6 +222,217 @@ static unix_get_pipeline_t* _unix_get_pipeline_create(unix_connection_t* conn, o
return pipeline;
}
+/* --- LOAD pipeline callbacks --- */
+
+/* Pipeline context for LOAD requests: pulls a file's blocks into the block
+ * cache without serving file data, forwarding tuple-level progress as
+ * LOAD_PROGRESS frames and terminating with exactly one LOAD_END frame.
+ * Subscription/refcount discipline mirrors unix_get_pipeline_t. */
+typedef struct {
+ refcounter_t refcounter;
+ unix_connection_t* conn;
+ readable_off_stream_t* rs;
+ readable_descriptor_t* desc;
+ ori_t* ori;
+ size_t tuples_total; /* ceil(final_byte / block_size) - offset tuples */
+ size_t tuples_loaded; /* maintained from load_tuple_event payloads */
+ size_t tuples_skipped; /* maintained from load_tuple_event payloads */
+ uint8_t failed; /* an error_event fired on desc or rs */
+ uint8_t terminal_sent; /* guards the single LOAD_END frame */
+} unix_load_pipeline_t;
+
+static void _unix_load_send_terminal(unix_load_pipeline_t* pipeline) {
+ if (pipeline->terminal_sent) {
+ return;
+ }
+ pipeline->terminal_sent = 1;
+ uint8_t status = CLIENT_API_LOAD_STATUS_LOADED;
+ if (pipeline->failed) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_total > 0 && pipeline->tuples_loaded == 0) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_skipped > 0) {
+ status = CLIENT_API_LOAD_STATUS_PARTIAL;
+ }
+ cbor_item_t* frame = client_api_load_end_encode(
+ status, pipeline->tuples_loaded, pipeline->tuples_total);
+ _unix_connection_send_frame(pipeline->conn, frame);
+}
+
+static void _unix_load_on_tuple(void* ctx, void* data) {
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)ctx;
+ tuple_t* tuple = (tuple_t*)data;
+ readable_off_stream_write(pipeline->rs, tuple);
+}
+
+/* The load_tuple_event payload is CONSUME-transferred: the notify machinery
+ * holds the reference and destroys it after dispatch. Copy the counters,
+ * never destroy or dereference the payload here. */
+static void _unix_load_on_tuple_loaded(void* ctx, void* data) {
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)ctx;
+ load_tuple_payload_t* progress = (load_tuple_payload_t*)data;
+ if (progress != NULL) {
+ pipeline->tuples_loaded = progress->tuples_loaded;
+ pipeline->tuples_skipped = progress->tuples_skipped;
+ }
+ cbor_item_t* frame = client_api_load_progress_encode(
+ pipeline->tuples_loaded, pipeline->tuples_total);
+ _unix_connection_send_frame(pipeline->conn, frame);
+
+ /* Pipeline-driven completion: a skipped tuple never renders and never
+ * advances sent_bytes, so the render path cannot close the stream once the
+ * tally completes. When every tuple the descriptor enumerates has resolved
+ * (loaded + skipped reached the computed total), close the load stream so
+ * its close_event subscriber sends the terminal LOAD_END. close_event — not
+ * this tally — is the single LOAD_END trigger; request_close is idempotent,
+ * so the all-loaded path (already closed by render) is unaffected. */
+ if (pipeline->tuples_loaded + pipeline->tuples_skipped >= pipeline->tuples_total) {
+ readable_off_stream_request_close(pipeline->rs);
+ }
+}
+
+static void _unix_load_on_rs_close(void* ctx, void* unused) {
+ (void)unused;
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)ctx;
+ /* Tally-before-close ordering (Task 2) guarantees the tuple counters were
+ * updated before this terminal frame is sent. If a close arrived first
+ * anyway, the last known counters are reported. */
+ _unix_load_send_terminal(pipeline);
+ stream_deferred_deref((stream_t*)pipeline->rs);
+ ori_destroy(pipeline->ori);
+ if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+ }
+}
+
+static void _unix_load_on_desc_close(void* ctx, void* unused) {
+ (void)unused;
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)ctx;
+ stream_deferred_deref((stream_t*)pipeline->desc);
+ ori_destroy(pipeline->ori);
+ if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+ }
+}
+
+static void _unix_load_on_rs_error(void* ctx, void* error) {
+ (void)error;
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ /* stream_deactivate queues a close right after the error, which emits the
+ * terminal LOAD_END FAILED; terminal_sent keeps exactly one terminal. Only
+ * deactivate when this error did not already come from one —
+ * stream_deactivate re-notifies error_event UNCONDITIONALLY, so an
+ * unguarded re-deactivate here would loop forever on the stream's actor. */
+ if (!pipeline->rs->stream.is_deactivated) {
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+ }
+}
+
+static void _unix_load_on_desc_error(void* ctx, void* error) {
+ (void)error;
+ unix_load_pipeline_t* pipeline = (unix_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ /* Deactivating rs routes the failure into the rs close path (exactly one
+ * terminal LOAD_END). Both deactivates are guarded: the error may have
+ * fired FROM a deactivated stream, and stream_deactivate re-notifies
+ * error_event unconditionally on its target, so re-deactivating either
+ * stream from this handler would re-enter these handlers forever. */
+ if (!pipeline->rs->stream.is_deactivated) {
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+ }
+ if (!((stream_t*)pipeline->desc)->is_deactivated) {
+ stream_deactivate((stream_t*)pipeline->desc, NULL);
+ }
+}
+
+static void _unix_handle_load(unix_connection_t* conn, cbor_item_t* frame) {
+ if (!conn->is_authenticated) {
+ _unix_connection_send_error(conn, CLIENT_API_STATUS_UNAUTHORIZED, "Authentication required");
+ return;
+ }
+ client_api_load_request_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_load_request_decode(frame, &msg) != 0) {
+ _unix_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST, "Invalid load request");
+ return;
+ }
+
+ off_url_t* url = off_url_parse(msg.ori_string);
+ client_api_load_request_destroy(&msg);
+
+ if (url == NULL) {
+ _unix_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST, "Invalid OFF URL");
+ return;
+ }
+
+ /* v1: directory ORIs are not loadable — directories are resolved in HTTP
+ * land; reject explicitly so the client gets a clear error. */
+ if (url->content_type != NULL && strstr(url->content_type, "offsystem/directory") != NULL) {
+ off_url_destroy(url);
+ _unix_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST,
+ "Load requires a file ORI, not a directory");
+ return;
+ }
+
+ /* Synchronous load path (same ORI construction as the GET path) */
+ ori_t* ori = ori_create(url->stream_length);
+ ori->block_type = standard;
+ ori->tuple_size = 3;
+ if (url->descriptor_hash != NULL) {
+ ori->descriptor_hash = REFERENCE(url->descriptor_hash, buffer_t);
+ }
+ if (url->file_hash != NULL) {
+ ori->file_hash = REFERENCE(url->file_hash, buffer_t);
+ }
+ if (url->file_name != NULL) {
+ ori->file_name = get_memory(strlen(url->file_name) + 1);
+ memcpy(ori->file_name, url->file_name, strlen(url->file_name) + 1);
+ }
+ off_url_destroy(url);
+
+ /* No GET_RESPONSE_START: load reports progress via LOAD_PROGRESS/LOAD_END */
+
+ network_t* network = conn->peer_ctx.network;
+
+ unix_load_pipeline_t* pipeline = get_clear_memory(sizeof(unix_load_pipeline_t));
+ refcounter_init((refcounter_t*)pipeline);
+ pipeline->conn = conn;
+ pipeline->ori = ori;
+ size_t block_size = off_block_size_for_type(ori->block_type);
+ pipeline->tuples_total = (ori->final_byte / block_size) +
+ ((ori->final_byte % block_size) > 0 ? 1 : 0) -
+ (ori->file_offset / block_size);
+
+ /* Reference count: 1 base + 1 for error callbacks that may both fire */
+ REFERENCE(pipeline, unix_load_pipeline_t);
+
+ size_t descriptor_pad = 32;
+
+ readable_off_stream_t* rs = readable_off_stream_create_ex(
+ conn->pool, conn->bc, conn->tc, REFERENCE(ori, ori_t), descriptor_pad, network, 1);
+ readable_descriptor_t* desc = readable_descriptor_create(
+ conn->pool, conn->bc, REFERENCE(ori, ori_t), descriptor_pad, network);
+
+ pipeline->rs = rs;
+ pipeline->desc = desc;
+
+ /* NO data_event consumer on rs: load mode never serves file data */
+ stream_subscribe((stream_t*)rs, load_tuple_event, pipeline, _unix_load_on_tuple_loaded, NULL);
+ stream_subscribe((stream_t*)rs, close_event, pipeline, _unix_load_on_rs_close, NULL);
+ stream_subscribe((stream_t*)rs, error_event, pipeline, _unix_load_on_rs_error, NULL);
+ stream_subscribe((stream_t*)desc, close_event, pipeline, _unix_load_on_desc_close, NULL);
+ stream_subscribe((stream_t*)desc, error_event, pipeline, _unix_load_on_desc_error, NULL);
+
+ /* Pipe: descriptor provides tuples to the off_stream */
+ stream_subscribe((stream_t*)desc, data_event, pipeline, _unix_load_on_tuple, NULL);
+
+ /* Start the descriptor pull */
+ readable_descriptor_push(desc);
+}
+
/* --- PUT pipeline callbacks --- */
static void _unix_put_on_descriptor_close(void* ctx, void* unused) {
@@ -630,6 +841,9 @@ static void _unix_dispatch_frame(unix_connection_t* conn, uint8_t type, cbor_ite
case CLIENT_API_GET_REQUEST:
_unix_handle_get(conn, frame);
break;
+ case CLIENT_API_LOAD_REQUEST:
+ _unix_handle_load(conn, frame);
+ break;
case CLIENT_API_PUT_REQUEST:
_unix_handle_put(conn, frame);
break;
diff --git a/src/ClientAPI/WS/ws_connection.c b/src/ClientAPI/WS/ws_connection.c
index a9d07000..34508255 100644
--- a/src/ClientAPI/WS/ws_connection.c
+++ b/src/ClientAPI/WS/ws_connection.c
@@ -501,6 +501,199 @@ static ws_get_pipeline_t* _ws_get_pipeline_create(ws_connection_t* conn, ori_t*
return pipeline;
}
+/* --- LOAD pipeline callbacks --- */
+
+/* Pipeline context for LOAD requests. Subscription/refcount discipline
+ * mirrors ws_get_pipeline_t. The WS connection carries no network actor
+ * (no config_node on TCP/WS/WT transports), so load runs cache-only here. */
+typedef struct {
+ refcounter_t refcounter;
+ ws_connection_t* conn;
+ readable_off_stream_t* rs;
+ readable_descriptor_t* desc;
+ ori_t* ori;
+ size_t tuples_total; /* ceil(final_byte / block_size) - offset tuples */
+ size_t tuples_loaded; /* maintained from load_tuple_event payloads */
+ size_t tuples_skipped; /* maintained from load_tuple_event payloads */
+ uint8_t failed; /* an error_event fired on desc or rs */
+ uint8_t terminal_sent; /* guards the single LOAD_END frame */
+} ws_load_pipeline_t;
+
+static void _ws_load_send_terminal(ws_load_pipeline_t* pipeline) {
+ if (pipeline->terminal_sent) {
+ return;
+ }
+ pipeline->terminal_sent = 1;
+ uint8_t status = CLIENT_API_LOAD_STATUS_LOADED;
+ if (pipeline->failed) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_total > 0 && pipeline->tuples_loaded == 0) {
+ status = CLIENT_API_LOAD_STATUS_FAILED;
+ } else if (pipeline->tuples_skipped > 0) {
+ status = CLIENT_API_LOAD_STATUS_PARTIAL;
+ }
+ cbor_item_t* frame = client_api_load_end_encode(
+ status, pipeline->tuples_loaded, pipeline->tuples_total);
+ _ws_connection_send_frame(pipeline->conn, frame);
+}
+
+static void _ws_load_on_tuple(void* ctx, void* data) {
+ ws_load_pipeline_t* pipeline = (ws_load_pipeline_t*)ctx;
+ tuple_t* tuple = (tuple_t*)data;
+ readable_off_stream_write(pipeline->rs, tuple);
+}
+
+/* The load_tuple_event payload is CONSUME-transferred: the notify machinery
+ * holds the reference and destroys it after dispatch. Copy the counters,
+ * never destroy or dereference the payload here. */
+static void _ws_load_on_tuple_loaded(void* ctx, void* data) {
+ ws_load_pipeline_t* pipeline = (ws_load_pipeline_t*)ctx;
+ load_tuple_payload_t* progress = (load_tuple_payload_t*)data;
+ if (progress != NULL) {
+ pipeline->tuples_loaded = progress->tuples_loaded;
+ pipeline->tuples_skipped = progress->tuples_skipped;
+ }
+ cbor_item_t* frame = client_api_load_progress_encode(
+ pipeline->tuples_loaded, pipeline->tuples_total);
+ _ws_connection_send_frame(pipeline->conn, frame);
+
+ /* Pipeline-driven completion: a skipped tuple never renders and never
+ * advances sent_bytes, so the render path cannot close the stream once the
+ * tally completes. When every tuple the descriptor enumerates has resolved
+ * (loaded + skipped reached the computed total), close the load stream so
+ * its close_event subscriber sends the terminal LOAD_END. close_event — not
+ * this tally — is the single LOAD_END trigger; request_close is idempotent,
+ * so the all-loaded path (already closed by render) is unaffected. */
+ if (pipeline->tuples_loaded + pipeline->tuples_skipped >= pipeline->tuples_total) {
+ readable_off_stream_request_close(pipeline->rs);
+ }
+}
+
+static void _ws_load_on_rs_close(void* ctx, void* unused) {
+ (void)unused;
+ ws_load_pipeline_t* pipeline = (ws_load_pipeline_t*)ctx;
+ /* Tally-before-close ordering (load mode) guarantees the tuple counters
+ * were updated before this terminal frame is sent; if not, last known
+ * counters are reported. */
+ _ws_load_send_terminal(pipeline);
+ stream_deferred_deref((stream_t*)pipeline->rs);
+ ori_destroy(pipeline->ori);
+ if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+ }
+}
+
+static void _ws_load_on_desc_close(void* ctx, void* unused) {
+ (void)unused;
+ ws_load_pipeline_t* pipeline = (ws_load_pipeline_t*)ctx;
+ stream_deferred_deref((stream_t*)pipeline->desc);
+ ori_destroy(pipeline->ori);
+ if (refcounter_dereference_is_zero((refcounter_t*)pipeline)) {
+ DESTROY(pipeline->ori, ori);
+ free(pipeline);
+ }
+}
+
+static void _ws_load_on_rs_error(void* ctx, void* error) {
+ (void)error;
+ ws_load_pipeline_t* pipeline = (ws_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ /* stream_deactivate queues a close right after the error, which emits the
+ * terminal LOAD_END FAILED; terminal_sent keeps exactly one terminal. */
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+}
+
+static void _ws_load_on_desc_error(void* ctx, void* error) {
+ (void)error;
+ ws_load_pipeline_t* pipeline = (ws_load_pipeline_t*)ctx;
+ pipeline->failed = 1;
+ stream_deactivate((stream_t*)pipeline->rs, NULL);
+ stream_deactivate((stream_t*)pipeline->desc, NULL);
+}
+
+static void _ws_handle_load(ws_connection_t* conn, cbor_item_t* frame) {
+ if (!conn->is_authenticated) {
+ _ws_connection_send_error(conn, CLIENT_API_STATUS_UNAUTHORIZED, "Authentication required");
+ return;
+ }
+ client_api_load_request_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_load_request_decode(frame, &msg) != 0) {
+ _ws_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST, "Invalid load request");
+ return;
+ }
+
+ off_url_t* url = off_url_parse(msg.ori_string);
+ client_api_load_request_destroy(&msg);
+
+ if (url == NULL) {
+ _ws_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST, "Invalid OFF URL");
+ return;
+ }
+
+ /* v1: directory ORIs are not loadable (resolved in HTTP land); reject. */
+ if (url->content_type != NULL && strstr(url->content_type, "offsystem/directory") != NULL) {
+ off_url_destroy(url);
+ _ws_connection_send_error(conn, CLIENT_API_STATUS_BAD_REQUEST,
+ "Load requires a file ORI, not a directory");
+ return;
+ }
+
+ ori_t* ori = ori_create(url->stream_length);
+ ori->block_type = standard;
+ ori->tuple_size = 3;
+ if (url->descriptor_hash != NULL) {
+ ori->descriptor_hash = REFERENCE(url->descriptor_hash, buffer_t);
+ }
+ if (url->file_hash != NULL) {
+ ori->file_hash = REFERENCE(url->file_hash, buffer_t);
+ }
+ if (url->file_name != NULL) {
+ ori->file_name = get_memory(strlen(url->file_name) + 1);
+ memcpy(ori->file_name, url->file_name, strlen(url->file_name) + 1);
+ }
+ off_url_destroy(url);
+
+ /* Cache-only: WS connections have no network actor access. */
+ network_t* network = NULL;
+
+ ws_load_pipeline_t* pipeline = get_clear_memory(sizeof(ws_load_pipeline_t));
+ refcounter_init((refcounter_t*)pipeline);
+ pipeline->conn = conn;
+ pipeline->ori = ori;
+ size_t block_size = off_block_size_for_type(ori->block_type);
+ pipeline->tuples_total = (ori->final_byte / block_size) +
+ ((ori->final_byte % block_size) > 0 ? 1 : 0) -
+ (ori->file_offset / block_size);
+
+ /* Reference count: 1 base + 1 for error callbacks that may both fire */
+ REFERENCE(pipeline, ws_load_pipeline_t);
+
+ size_t descriptor_pad = 32;
+
+ readable_off_stream_t* rs = readable_off_stream_create_ex(
+ conn->pool, conn->bc, conn->tc, REFERENCE(ori, ori_t), descriptor_pad, network, 1);
+ readable_descriptor_t* desc = readable_descriptor_create(
+ conn->pool, conn->bc, REFERENCE(ori, ori_t), descriptor_pad, network);
+
+ pipeline->rs = rs;
+ pipeline->desc = desc;
+
+ /* NO data_event consumer on rs: load mode never serves file data */
+ stream_subscribe((stream_t*)rs, load_tuple_event, pipeline, _ws_load_on_tuple_loaded, NULL);
+ stream_subscribe((stream_t*)rs, close_event, pipeline, _ws_load_on_rs_close, NULL);
+ stream_subscribe((stream_t*)rs, error_event, pipeline, _ws_load_on_rs_error, NULL);
+ stream_subscribe((stream_t*)desc, close_event, pipeline, _ws_load_on_desc_close, NULL);
+ stream_subscribe((stream_t*)desc, error_event, pipeline, _ws_load_on_desc_error, NULL);
+
+ /* Pipe: descriptor provides tuples to the off_stream */
+ stream_subscribe((stream_t*)desc, data_event, pipeline, _ws_load_on_tuple, NULL);
+
+ /* Start the descriptor pull */
+ readable_descriptor_push(desc);
+}
+
/* --- PUT pipeline callbacks --- */
static void _ws_put_on_descriptor_close(void* ctx, void* unused) {
@@ -893,6 +1086,9 @@ static void _ws_dispatch_frame(ws_connection_t* conn, uint8_t type, cbor_item_t*
case CLIENT_API_GET_REQUEST:
_ws_handle_get(conn, frame);
break;
+ case CLIENT_API_LOAD_REQUEST:
+ _ws_handle_load(conn, frame);
+ break;
case CLIENT_API_PUT_REQUEST:
_ws_handle_put(conn, frame);
break;
diff --git a/src/ClientAPI/client_api_wire.c b/src/ClientAPI/client_api_wire.c
index f80629c7..93ded012 100644
--- a/src/ClientAPI/client_api_wire.c
+++ b/src/ClientAPI/client_api_wire.c
@@ -9,6 +9,11 @@
#include
#include
+/* PPM QR images are large: a version-40 QR at 4x scale is a ~740x740 P6
+ PPM (~1.6 MB) for a 2331-byte payload. 2 MB covers the worst case while
+ still bounding allocation. */
+#define CLIENT_API_PEER_INFO_MAX_PAYLOAD (2 * 1024 * 1024)
+
// --- Helper: encode a string as CBOR text string (empty string for NULL) ---
static cbor_item_t* _encode_string(const char* str) {
if (str == NULL) {
@@ -563,7 +568,215 @@ int client_api_get_end_decode(cbor_item_t* item) {
return type == CLIENT_API_GET_END ? 0 : -1;
}
-// --- Error ---
+// --- Load Request ---
+// [type, ori_string] or [type, ori_string, has_range, range_start, range_end]
+
+cbor_item_t* client_api_load_request_encode(const client_api_load_request_t* msg) {
+ cbor_item_t* array;
+ cbor_item_t* item;
+
+ if (msg->has_range) {
+ array = cbor_new_definite_array(5);
+ } else {
+ array = cbor_new_definite_array(2);
+ }
+
+ item = cbor_build_uint8(CLIENT_API_LOAD_REQUEST);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = _encode_string(msg->ori_string);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ if (msg->has_range) {
+ item = cbor_build_uint8(1);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint64(msg->range_start);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint64(msg->range_end);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+ }
+
+ return array;
+}
+
+int client_api_load_request_decode(cbor_item_t* item, client_api_load_request_t* msg) {
+ if (!cbor_isa_array(item) || cbor_array_size(item) < 2) return -1;
+ memset(msg, 0, sizeof(*msg));
+
+ cbor_item_t* type_item = cbor_array_get(item, 0);
+ if (!cbor_isa_uint(type_item) || cbor_get_uint8(type_item) != CLIENT_API_LOAD_REQUEST) {
+ cbor_decref(&type_item);
+ return -1;
+ }
+ cbor_decref(&type_item);
+
+ cbor_item_t* ori = cbor_array_get(item, 1);
+ msg->ori_string = _decode_string(ori, OFFS_MAX_ORI_STRING_LEN);
+ cbor_decref(&ori);
+
+ if (validate_ori_string(msg->ori_string) != 0) {
+ free(msg->ori_string);
+ msg->ori_string = NULL;
+ return -1;
+ }
+
+ /* The 5-element ranged shape mirrors GET_REQUEST: a literal 1 flag in
+ position 2, then the range bounds. has_range is derived from the array
+ shape alone, not from decoding the flag element. */
+ if (cbor_array_size(item) >= 5) {
+ cbor_item_t* range_start = cbor_array_get(item, 3);
+ if (!cbor_isa_uint(range_start)) {
+ cbor_decref(&range_start);
+ client_api_load_request_destroy(msg);
+ memset(msg, 0, sizeof(*msg));
+ return -1;
+ }
+ msg->range_start = _decode_size(range_start);
+ cbor_decref(&range_start);
+
+ cbor_item_t* range_end = cbor_array_get(item, 4);
+ if (!cbor_isa_uint(range_end)) {
+ cbor_decref(&range_end);
+ client_api_load_request_destroy(msg);
+ memset(msg, 0, sizeof(*msg));
+ return -1;
+ }
+ msg->range_end = _decode_size(range_end);
+ cbor_decref(&range_end);
+
+ msg->has_range = 1;
+ }
+
+ return 0;
+}
+
+void client_api_load_request_destroy(client_api_load_request_t* msg) {
+ if (msg == NULL) return;
+ free(msg->ori_string);
+ msg->ori_string = NULL;
+}
+
+// --- Load Progress ---
+// [type, tuples_loaded: uint, tuples_total: uint]
+
+cbor_item_t* client_api_load_progress_encode(size_t tuples_loaded, size_t tuples_total) {
+ cbor_item_t* array = cbor_new_definite_array(3);
+ cbor_item_t* item;
+
+ item = cbor_build_uint8(CLIENT_API_LOAD_PROGRESS);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint64(tuples_loaded);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint64(tuples_total);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ return array;
+}
+
+int client_api_load_progress_decode(cbor_item_t* item, size_t* tuples_loaded, size_t* tuples_total) {
+ if (!cbor_isa_array(item) || cbor_array_size(item) < 3) return -1;
+
+ cbor_item_t* type_item = cbor_array_get(item, 0);
+ if (!cbor_isa_uint(type_item) || cbor_get_uint8(type_item) != CLIENT_API_LOAD_PROGRESS) {
+ cbor_decref(&type_item);
+ return -1;
+ }
+ cbor_decref(&type_item);
+
+ cbor_item_t* loaded_item = cbor_array_get(item, 1);
+ if (!cbor_isa_uint(loaded_item)) {
+ cbor_decref(&loaded_item);
+ return -1;
+ }
+ *tuples_loaded = _decode_size(loaded_item);
+ cbor_decref(&loaded_item);
+
+ cbor_item_t* total_item = cbor_array_get(item, 2);
+ if (!cbor_isa_uint(total_item)) {
+ cbor_decref(&total_item);
+ return -1;
+ }
+ *tuples_total = _decode_size(total_item);
+ cbor_decref(&total_item);
+
+ return 0;
+}
+
+// --- Load End ---
+// [type, status: uint, tuples_loaded: uint, tuples_total: uint]
+// status: 0 = loaded, 1 = partial (some tuples skipped), 2 = failed
+
+cbor_item_t* client_api_load_end_encode(uint8_t status, size_t tuples_loaded, size_t tuples_total) {
+ cbor_item_t* array = cbor_new_definite_array(4);
+ cbor_item_t* item;
+
+ item = cbor_build_uint8(CLIENT_API_LOAD_END);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint8(status);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint64(tuples_loaded);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ item = cbor_build_uint64(tuples_total);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+
+ return array;
+}
+
+int client_api_load_end_decode(cbor_item_t* item, uint8_t* status, size_t* tuples_loaded, size_t* tuples_total) {
+ if (!cbor_isa_array(item) || cbor_array_size(item) < 4) return -1;
+
+ cbor_item_t* type_item = cbor_array_get(item, 0);
+ if (!cbor_isa_uint(type_item) || cbor_get_uint8(type_item) != CLIENT_API_LOAD_END) {
+ cbor_decref(&type_item);
+ return -1;
+ }
+ cbor_decref(&type_item);
+
+ cbor_item_t* status_item = cbor_array_get(item, 1);
+ if (!cbor_isa_uint(status_item)) {
+ cbor_decref(&status_item);
+ return -1;
+ }
+ *status = cbor_get_uint8(status_item);
+ cbor_decref(&status_item);
+
+ cbor_item_t* loaded_item = cbor_array_get(item, 2);
+ if (!cbor_isa_uint(loaded_item)) {
+ cbor_decref(&loaded_item);
+ return -1;
+ }
+ *tuples_loaded = _decode_size(loaded_item);
+ cbor_decref(&loaded_item);
+
+ cbor_item_t* total_item = cbor_array_get(item, 3);
+ if (!cbor_isa_uint(total_item)) {
+ cbor_decref(&total_item);
+ return -1;
+ }
+ *tuples_total = _decode_size(total_item);
+ cbor_decref(&total_item);
+
+ return 0;
+}
// [type, status_code, message_string]
cbor_item_t* client_api_error_encode(const client_api_error_t* msg) {
@@ -1072,16 +1285,54 @@ void client_api_update_status_response_destroy(client_api_update_status_response
}
// --- Peer Info Request ---
-// [type] — no payload
+// [type] or [type, format: uint]
cbor_item_t* client_api_peer_info_request_encode(void) {
- cbor_item_t* array = cbor_new_definite_array(1);
+ return client_api_peer_info_request_encode_format(0);
+}
+
+cbor_item_t* client_api_peer_info_request_encode_format(uint8_t format) {
+ if (format > 2) return NULL; /* only 0/1/2 are defined; decode rejects the rest */
+ /* Format 0 keeps the original 1-element frame shape so old daemons and
+ old capture tooling see byte-identical requests. */
+ cbor_item_t* array = cbor_new_definite_array(format == 0 ? 1 : 2);
cbor_item_t* item = cbor_build_uint8(CLIENT_API_PEER_INFO_REQUEST);
(void)cbor_array_push(array, item);
cbor_decref(&item);
+ if (format != 0) {
+ item = cbor_build_uint8(format);
+ (void)cbor_array_push(array, item);
+ cbor_decref(&item);
+ }
return array;
}
+int client_api_peer_info_request_decode(cbor_item_t* item, uint8_t* format) {
+ if (item == NULL || format == NULL || !cbor_isa_array(item)) return -1;
+ size_t size = cbor_array_size(item);
+ if (size < 1 || size > 2) return -1;
+
+ cbor_item_t* type_item = cbor_array_get(item, 0);
+ if (!cbor_isa_uint(type_item) ||
+ cbor_get_uint8(type_item) != CLIENT_API_PEER_INFO_REQUEST) {
+ cbor_decref(&type_item);
+ return -1;
+ }
+ cbor_decref(&type_item);
+
+ *format = 0; /* bare [type] frame means raw CBOR */
+ if (size == 2) {
+ cbor_item_t* format_item = cbor_array_get(item, 1);
+ if (!cbor_isa_uint(format_item) || cbor_get_uint8(format_item) > 2) {
+ cbor_decref(&format_item);
+ return -1;
+ }
+ *format = cbor_get_uint8(format_item);
+ cbor_decref(&format_item);
+ }
+ return 0;
+}
+
// --- Peer Info Response ---
// [type, format_byte, data: bstr]
@@ -1129,7 +1380,7 @@ int client_api_peer_info_response_decode(cbor_item_t* item, client_api_peer_info
return -1;
}
msg->data_size = cbor_bytestring_length(data_item);
- if (msg->data_size > 65536) {
+ if (msg->data_size > CLIENT_API_PEER_INFO_MAX_PAYLOAD) {
cbor_decref(&data_item);
return -1;
}
@@ -1194,7 +1445,9 @@ int client_api_peer_connect_decode(cbor_item_t* item, client_api_peer_connect_t*
return -1;
}
msg->data_size = cbor_bytestring_length(data_item);
- if (msg->data_size > 65536) {
+ /* format 2 carries a PPM QR image, which is larger than raw peer info —
+ see peer_info_response cap */
+ if (msg->data_size > CLIENT_API_PEER_INFO_MAX_PAYLOAD) {
cbor_decref(&data_item);
return -1;
}
@@ -1356,7 +1609,9 @@ int client_api_friend_add_decode(cbor_item_t* item, client_api_friend_add_t* msg
return -1;
}
msg->data_size = cbor_bytestring_length(data_item);
- if (msg->data_size > 65536) {
+ /* format 2 carries a PPM QR image, which is larger than raw peer info —
+ see peer_info_response cap */
+ if (msg->data_size > CLIENT_API_PEER_INFO_MAX_PAYLOAD) {
cbor_decref(&data_item);
return -1;
}
diff --git a/src/ClientAPI/client_api_wire.h b/src/ClientAPI/client_api_wire.h
index c62d05a2..85024961 100644
--- a/src/ClientAPI/client_api_wire.h
+++ b/src/ClientAPI/client_api_wire.h
@@ -46,6 +46,9 @@
#define CLIENT_API_CONFIG_SET_RESPONSE 36
#define CLIENT_API_CONFIG_RELOAD_REQUEST 37
#define CLIENT_API_CONFIG_RELOAD_RESPONSE 38
+#define CLIENT_API_LOAD_REQUEST 39
+#define CLIENT_API_LOAD_PROGRESS 40
+#define CLIENT_API_LOAD_END 41
// Status codes for responses
#define CLIENT_API_STATUS_OK 0
@@ -121,6 +124,32 @@ typedef struct {
// [type] — no payload
// (no struct needed, encode/decode handle it directly)
+// --- Load Request ---
+// [type, ori_string] or [type, ori_string, has_range, range_start, range_end] —
+// the same optional-range shape as GET_REQUEST: an unranged request is 2
+// elements, a ranged request carries the literal has_range flag (uint8 1) in
+// position 2 followed by the two range bounds, and has_range on the struct is
+// derived from the array shape on decode. Asks the daemon to pull the file's
+// blocks into its block cache without sending file data; progress arrives as
+// LOAD_PROGRESS frames, terminated by LOAD_END.
+typedef struct {
+ char* ori_string;
+ uint8_t has_range; /* 0 → no range elements; 1 → following two present */
+ size_t range_start;
+ size_t range_end;
+} client_api_load_request_t;
+
+// --- Load Progress ---
+// [type, tuples_loaded: uint, tuples_total: uint]
+// (tuples_total - tuples_loaded includes both in-flight and skipped tuples)
+
+// --- Load End ---
+// [type, status: uint, tuples_loaded: uint, tuples_total: uint]
+// status: 0 = loaded, 1 = partial (some tuples skipped), 2 = failed
+#define CLIENT_API_LOAD_STATUS_LOADED 0
+#define CLIENT_API_LOAD_STATUS_PARTIAL 1
+#define CLIENT_API_LOAD_STATUS_FAILED 2
+
// --- Error ---
// [type, status_code, message_string]
typedef struct {
@@ -239,11 +268,12 @@ typedef struct {
} client_api_config_reload_response_t;
// --- Peer Info Request ---
-// [type] — no payload
+// [type] or [type, format: uint]
+// format: 0 = raw CBOR (default), 1 = Base58 text, 2 = PPM QR image
// --- Peer Info Response ---
// [type, format_byte, data: bstr]
-// format_byte: 0 = raw CBOR, 1 = Base58 text
+// format_byte: 0 = raw CBOR, 1 = Base58 text, 2 = PPM QR image
typedef struct {
uint8_t format;
uint8_t* data;
@@ -306,6 +336,9 @@ cbor_item_t* client_api_get_request_encode(const client_api_get_request_t* msg);
cbor_item_t* client_api_get_response_start_encode(const client_api_get_response_start_t* msg);
cbor_item_t* client_api_get_data_encode(const client_api_get_data_t* msg);
cbor_item_t* client_api_get_end_encode(void);
+cbor_item_t* client_api_load_request_encode(const client_api_load_request_t* msg);
+cbor_item_t* client_api_load_progress_encode(size_t tuples_loaded, size_t tuples_total);
+cbor_item_t* client_api_load_end_encode(uint8_t status, size_t tuples_loaded, size_t tuples_total);
cbor_item_t* client_api_error_encode(const client_api_error_t* msg);
// Decode functions — fill existing struct, return 0 on success, -1 on error
@@ -317,6 +350,9 @@ int client_api_get_request_decode(cbor_item_t* item, client_api_get_request_t* m
int client_api_get_response_start_decode(cbor_item_t* item, client_api_get_response_start_t* msg);
int client_api_get_data_decode(cbor_item_t* item, client_api_get_data_t* msg);
int client_api_get_end_decode(cbor_item_t* item);
+int client_api_load_request_decode(cbor_item_t* item, client_api_load_request_t* msg);
+int client_api_load_progress_decode(cbor_item_t* item, size_t* tuples_loaded, size_t* tuples_total);
+int client_api_load_end_decode(cbor_item_t* item, uint8_t* status, size_t* tuples_loaded, size_t* tuples_total);
int client_api_error_decode(cbor_item_t* item, client_api_error_t* msg);
cbor_item_t* client_api_auth_request_encode(const client_api_auth_request_t* auth);
@@ -376,6 +412,12 @@ int client_api_config_reload_response_decode(cbor_item_t* item, client_api_confi
void client_api_config_reload_response_destroy(client_api_config_reload_response_t* msg);
cbor_item_t* client_api_peer_info_request_encode(void);
+/* Same frame with an explicit response format byte:
+ 0 = raw CBOR, 1 = base58 text, 2 = PPM QR image. */
+cbor_item_t* client_api_peer_info_request_encode_format(uint8_t format);
+/* Decode [type] or [type, format]; *format is 0 for the 1-element form.
+ Rejects unknown formats (anything > 2) and frames with extra elements. */
+int client_api_peer_info_request_decode(cbor_item_t* item, uint8_t* format);
cbor_item_t* client_api_peer_info_response_encode(const client_api_peer_info_response_t* msg);
int client_api_peer_info_response_decode(cbor_item_t* item, client_api_peer_info_response_t* msg);
@@ -416,6 +458,7 @@ void client_api_put_response_destroy(client_api_put_response_t* msg);
void client_api_get_request_destroy(client_api_get_request_t* msg);
void client_api_get_response_start_destroy(client_api_get_response_start_t* msg);
void client_api_get_data_destroy(client_api_get_data_t* msg);
+void client_api_load_request_destroy(client_api_load_request_t* msg);
void client_api_error_destroy(client_api_error_t* msg);
#endif // OFFS_CLIENT_API_WIRE_H
\ No newline at end of file
diff --git a/src/ClientAPI/peer_handlers.c b/src/ClientAPI/peer_handlers.c
index fb646e7e..39f6d5d5 100644
--- a/src/ClientAPI/peer_handlers.c
+++ b/src/ClientAPI/peer_handlers.c
@@ -7,6 +7,7 @@
#include "../Network/node_id.h"
#include "../Util/base58.h"
#include "../Util/allocator.h"
+#include "../QR/qr.h"
#include
#include
@@ -16,14 +17,67 @@
#define PEER_LIST_KEY_IS_FRIEND 3
#define PEER_LIST_KEY_RTT_MS 4
-void peer_handle_info_request(peer_handler_ctx_t* ctx, cbor_item_t* frame) {
- (void)frame; /* no payload */
+int peer_info_from_payload(uint8_t format, const uint8_t* data,
+ size_t data_size, peer_info_t* info) {
+ if (info == NULL) return -1;
+
+ if (format == 0) {
+ /* CBOR bytes */
+ struct cbor_load_result load_result;
+ cbor_item_t* decoded = cbor_load(data, data_size, &load_result);
+ if (decoded == NULL || load_result.error.code != CBOR_ERR_NONE) {
+ if (decoded != NULL) cbor_decref(&decoded);
+ return -1;
+ }
+ int rc = peer_info_decode(decoded, info);
+ cbor_decref(&decoded);
+ return rc;
+ }
+
+ if (format == 1) {
+ /* Base58 text */
+ char* b58_str = get_clear_memory(data_size + 1);
+ if (b58_str == NULL) return -1;
+ memcpy(b58_str, data, data_size);
+ b58_str[data_size] = '\0';
+ int rc = peer_info_from_base58(b58_str, info);
+ free(b58_str);
+ return rc;
+ }
+ if (format == 2) {
+ /* PPM QR image → payload bytes → CBOR peer_info */
+ size_t payload_len = 0;
+ uint8_t* payload = qr_decode_from_ppm(data, data_size, &payload_len);
+ if (payload == NULL) return -1;
+ struct cbor_load_result load_result;
+ cbor_item_t* decoded = cbor_load(payload, payload_len, &load_result);
+ free(payload);
+ if (decoded == NULL || load_result.error.code != CBOR_ERR_NONE) {
+ if (decoded != NULL) cbor_decref(&decoded);
+ return -1;
+ }
+ int rc = peer_info_decode(decoded, info);
+ cbor_decref(&decoded);
+ return rc;
+ }
+
+ return -1;
+}
+
+void peer_handle_info_request(peer_handler_ctx_t* ctx, cbor_item_t* frame) {
if (!ctx->is_authenticated) {
ctx->send_error(ctx->conn, CLIENT_API_STATUS_UNAUTHORIZED, "Authentication required");
return;
}
+ uint8_t format = 0;
+ if (client_api_peer_info_request_decode(frame, &format) != 0) {
+ ctx->send_error(ctx->conn, CLIENT_API_STATUS_BAD_REQUEST,
+ "Invalid peer info request");
+ return;
+ }
+
authority_t* auth = ctx->authority;
if (auth->public_key == NULL) {
ctx->send_error(ctx->conn, CLIENT_API_STATUS_INTERNAL_ERROR, "No local public key configured");
@@ -84,12 +138,43 @@ void peer_handle_info_request(peer_handler_ctx_t* ctx, cbor_item_t* frame) {
/* Build and send response */
client_api_peer_info_response_t response;
memset(&response, 0, sizeof(response));
- response.format = 0; /* raw CBOR */
- response.data = serialized;
- response.data_size = bytes_serialized;
+
+ if (format == 2) {
+ /* PPM QR image — ownership of the encoded image transfers to the
+ response struct; client_api_peer_info_response_destroy frees it. */
+ size_t ppm_len = 0;
+ uint8_t* ppm = qr_encode_to_ppm(serialized, bytes_serialized, &ppm_len);
+ free(serialized);
+ if (ppm == NULL) {
+ ctx->send_error(ctx->conn, CLIENT_API_STATUS_INTERNAL_ERROR,
+ "QR encoding failed");
+ return;
+ }
+ response.format = 2;
+ response.data = ppm;
+ response.data_size = ppm_len;
+ } else if (format == 1) {
+ /* Base58 text — encode the CBOR payload so the format label matches. */
+ size_t b58_len = base58_encoded_length(bytes_serialized) + 1;
+ char* b58 = get_clear_memory(b58_len);
+ int encoded_len = base58_encode(serialized, bytes_serialized, b58, b58_len);
+ free(serialized);
+ if (encoded_len <= 0) {
+ ctx->send_error(ctx->conn, CLIENT_API_STATUS_INTERNAL_ERROR,
+ "Base58 encoding failed");
+ return;
+ }
+ response.format = 1;
+ response.data = (uint8_t*)b58;
+ response.data_size = (size_t)encoded_len;
+ } else {
+ response.format = 0; /* raw CBOR */
+ response.data = serialized;
+ response.data_size = bytes_serialized;
+ }
cbor_item_t* out_frame = client_api_peer_info_response_encode(&response);
- free(serialized);
+ client_api_peer_info_response_destroy(&response);
ctx->send_frame(ctx->conn, out_frame);
}
@@ -107,26 +192,8 @@ void peer_handle_connect(peer_handler_ctx_t* ctx, cbor_item_t* frame) {
peer_info_t remote_info;
memset(&remote_info, 0, sizeof(remote_info));
- int decode_ok = -1;
-
- if (msg.format == 0) {
- /* CBOR bytes — load and decode */
- struct cbor_load_result load_result;
- cbor_item_t* decoded = cbor_load(msg.data, msg.data_size, &load_result);
- if (decoded != NULL && load_result.error.code == CBOR_ERR_NONE) {
- decode_ok = peer_info_decode(decoded, &remote_info);
- cbor_decref(&decoded);
- }
- } else if (msg.format == 1) {
- /* Base58 text — interpret as null-terminated string */
- char* b58_str = get_clear_memory(msg.data_size + 1);
- if (b58_str != NULL) {
- memcpy(b58_str, msg.data, msg.data_size);
- b58_str[msg.data_size] = '\0';
- decode_ok = peer_info_from_base58(b58_str, &remote_info);
- free(b58_str);
- }
- }
+ int decode_ok = peer_info_from_payload(msg.format, msg.data, msg.data_size,
+ &remote_info);
client_api_peer_connect_destroy(&msg);
@@ -240,26 +307,8 @@ void peer_handle_friend_add(peer_handler_ctx_t* ctx, cbor_item_t* frame) {
return;
}
- int decode_ok = -1;
-
- if (msg.format == 0) {
- /* CBOR bytes */
- struct cbor_load_result load_result;
- cbor_item_t* decoded = cbor_load(msg.data, msg.data_size, &load_result);
- if (decoded != NULL && load_result.error.code == CBOR_ERR_NONE) {
- decode_ok = peer_info_decode(decoded, new_friend);
- cbor_decref(&decoded);
- }
- } else if (msg.format == 1) {
- /* Base58 text */
- char* b58_str = get_clear_memory(msg.data_size + 1);
- if (b58_str != NULL) {
- memcpy(b58_str, msg.data, msg.data_size);
- b58_str[msg.data_size] = '\0';
- decode_ok = peer_info_from_base58(b58_str, new_friend);
- free(b58_str);
- }
- }
+ int decode_ok = peer_info_from_payload(msg.format, msg.data, msg.data_size,
+ new_friend);
client_api_friend_add_destroy(&msg);
diff --git a/src/ClientAPI/peer_handlers.h b/src/ClientAPI/peer_handlers.h
index ac3a40aa..82b24c7f 100644
--- a/src/ClientAPI/peer_handlers.h
+++ b/src/ClientAPI/peer_handlers.h
@@ -14,6 +14,8 @@
#include
#include "block_handlers.h"
+#include "../Network/peer_info.h"
+#include
typedef struct {
block_connection_t* conn;
@@ -32,4 +34,12 @@ void peer_handle_friend_add(peer_handler_ctx_t* ctx, cbor_item_t* frame);
void peer_handle_friend_remove(peer_handler_ctx_t* ctx, cbor_item_t* frame);
void peer_handle_friend_list_request(peer_handler_ctx_t* ctx, cbor_item_t* frame);
+/* Decode a peer_info payload by wire format byte: 0 = raw CBOR peer_info
+ map, 1 = base58 text, 2 = PPM QR image (decoded via src/QR, then parsed
+ as CBOR peer_info). Returns 0 on success, -1 if the payload is not
+ decodable in the given format. Shared by the socket handlers and the
+ HTTP routes so both transports accept exactly the same inputs. */
+int peer_info_from_payload(uint8_t format, const uint8_t* data,
+ size_t data_size, peer_info_t* info);
+
#endif // OFFS_PEER_HANDLERS_H
diff --git a/src/ClientLibs/c/offs_client.c b/src/ClientLibs/c/offs_client.c
index b8a676fc..181eb9e9 100644
--- a/src/ClientLibs/c/offs_client.c
+++ b/src/ClientLibs/c/offs_client.c
@@ -164,6 +164,14 @@ struct offs_client_t {
void* block_delete_cb_ctx;
offs_health_cb_t health_cb;
void* health_cb_ctx;
+ offs_peer_info_cb_t peer_info_cb;
+ void* peer_info_cb_ctx;
+ offs_peer_connect_cb_t peer_connect_cb;
+ void* peer_connect_cb_ctx;
+ offs_load_progress_cb_t load_progress_cb;
+ void* load_progress_cb_ctx;
+ offs_load_end_cb_t load_end_cb;
+ void* load_end_cb_ctx;
};
/* Forward declaration — needed for MsQuic callbacks that call _handle_frame */
@@ -510,6 +518,14 @@ static void _handle_frame(offs_client_t* client, uint8_t type, cbor_item_t* fram
void* block_delete_cb_ctx = client->block_delete_cb_ctx;
offs_health_cb_t health_cb = client->health_cb;
void* health_cb_ctx = client->health_cb_ctx;
+ offs_peer_info_cb_t peer_info_cb = client->peer_info_cb;
+ void* peer_info_cb_ctx = client->peer_info_cb_ctx;
+ offs_peer_connect_cb_t peer_connect_cb = client->peer_connect_cb;
+ void* peer_connect_cb_ctx = client->peer_connect_cb_ctx;
+ offs_load_progress_cb_t load_progress_cb = client->load_progress_cb;
+ void* load_progress_cb_ctx = client->load_progress_cb_ctx;
+ offs_load_end_cb_t load_end_cb = client->load_end_cb;
+ void* load_end_cb_ctx = client->load_end_cb_ctx;
platform_mutex_unlock(client->lock);
switch (type) {
@@ -599,6 +615,46 @@ static void _handle_frame(offs_client_t* client, uint8_t type, cbor_item_t* fram
}
break;
}
+ case CLIENT_API_PEER_INFO_RESPONSE: {
+ client_api_peer_info_response_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_peer_info_response_decode(frame, &msg) == 0) {
+ if (peer_info_cb != NULL) {
+ peer_info_cb(peer_info_cb_ctx, msg.format, msg.data, msg.data_size);
+ }
+ client_api_peer_info_response_destroy(&msg);
+ }
+ break;
+ }
+ case CLIENT_API_PEER_CONNECT_RESULT: {
+ client_api_peer_connect_result_t msg;
+ memset(&msg, 0, sizeof(msg));
+ if (client_api_peer_connect_result_decode(frame, &msg) == 0) {
+ if (peer_connect_cb != NULL) {
+ peer_connect_cb(peer_connect_cb_ctx, msg.status);
+ }
+ client_api_peer_connect_result_destroy(&msg);
+ }
+ break;
+ }
+ case CLIENT_API_LOAD_PROGRESS: {
+ size_t tuples_loaded = 0, tuples_total = 0;
+ if (client_api_load_progress_decode(frame, &tuples_loaded, &tuples_total) == 0) {
+ if (load_progress_cb != NULL) {
+ load_progress_cb(load_progress_cb_ctx, tuples_loaded, tuples_total);
+ }
+ }
+ break;
+ }
+ case CLIENT_API_LOAD_END: {
+ uint8_t status = 0; size_t loaded = 0, total = 0;
+ if (client_api_load_end_decode(frame, &status, &loaded, &total) == 0) {
+ if (load_end_cb != NULL) {
+ load_end_cb(load_end_cb_ctx, status, loaded, total);
+ }
+ }
+ break;
+ }
default:
break;
}
@@ -1095,7 +1151,7 @@ static offs_client_t* _connect_attempt(const char* transport_url, const char* ap
} else if (strncmp(transport_url, "tcp://", 6) == 0) {
const char* addr = transport_url + 6;
char* host = get_memory(strlen(addr) + 1);
- strcpy(host, addr);
+ memcpy(host, addr, strlen(addr) + 1);
char* colon = strrchr(host, ':');
if (colon == NULL) {
free(host);
@@ -1121,7 +1177,7 @@ static offs_client_t* _connect_attempt(const char* transport_url, const char* ap
uint8_t is_ssl = (transport_url[4] == 's');
const char* addr_start = is_ssl ? transport_url + 6 : transport_url + 5;
char* addr_copy = get_memory(strlen(addr_start) + 1);
- strcpy(addr_copy, addr_start);
+ memcpy(addr_copy, addr_start, strlen(addr_start) + 1);
/* Extract path (everything after first /) */
char* path_start = strchr(addr_copy, '/');
if (path_start != NULL) {
@@ -1220,7 +1276,7 @@ static offs_client_t* _connect_attempt(const char* transport_url, const char* ap
uint8_t is_secure = (transport_url[4] == 's');
const char* addr_start = is_secure ? transport_url + 6 : transport_url + 5;
char* addr_copy = get_memory(strlen(addr_start) + 1);
- strcpy(addr_copy, addr_start);
+ memcpy(addr_copy, addr_start, strlen(addr_start) + 1);
/* Extract host and port */
char* colon = strrchr(addr_copy, ':');
@@ -1854,6 +1910,117 @@ int offs_client_health(offs_client_t* client,
return 0;
}
+int offs_client_peer_info_ex(offs_client_t* client, uint8_t format,
+ offs_peer_info_cb_t callback, void* ctx) {
+ if (client == NULL || !client->connected) return -1;
+
+ cbor_item_t* frame = client_api_peer_info_request_encode_format(format);
+ if (frame == NULL) return -1; /* invalid format (> 2) rejected by encoder */
+
+ platform_mutex_lock(client->lock);
+ client->peer_info_cb = callback;
+ client->peer_info_cb_ctx = ctx;
+ platform_mutex_unlock(client->lock);
+
+ _send_frame(client, frame);
+ return 0;
+}
+
+int offs_client_peer_info(offs_client_t* client,
+ offs_peer_info_cb_t callback, void* ctx) {
+ return offs_client_peer_info_ex(client, 0, callback, ctx);
+}
+
+int offs_client_peer_info_qr(offs_client_t* client,
+ offs_peer_info_cb_t callback, void* ctx) {
+ return offs_client_peer_info_ex(client, 2, callback, ctx);
+}
+
+int offs_client_peer_connect(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ if (client == NULL || !client->connected || data == NULL || data_len == 0) return -1;
+ if (format > 2) return -1; /* only 0/1/2 are defined */
+
+ client_api_peer_connect_t msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.format = format;
+ msg.data = (uint8_t*)data;
+ msg.data_size = data_len;
+
+ cbor_item_t* frame = client_api_peer_connect_encode(&msg);
+ if (frame == NULL) return -1; /* cbor allocation failure */
+
+ platform_mutex_lock(client->lock);
+ client->peer_connect_cb = callback;
+ client->peer_connect_cb_ctx = ctx;
+ platform_mutex_unlock(client->lock);
+
+ _send_frame(client, frame);
+ return 0;
+}
+
+int offs_client_peer_connect_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ return offs_client_peer_connect(client, 2, ppm, ppm_len, callback, ctx);
+}
+
+int offs_client_friend_add(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ if (client == NULL || !client->connected || data == NULL || data_len == 0) return -1;
+ if (format > 2) return -1; /* only 0/1/2 are defined */
+
+ client_api_friend_add_t msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.format = format;
+ msg.data = (uint8_t*)data;
+ msg.data_size = data_len;
+
+ cbor_item_t* frame = client_api_friend_add_encode(&msg);
+ if (frame == NULL) return -1; /* cbor allocation failure */
+
+ platform_mutex_lock(client->lock);
+ client->peer_connect_cb = callback;
+ client->peer_connect_cb_ctx = ctx;
+ platform_mutex_unlock(client->lock);
+
+ _send_frame(client, frame);
+ return 0;
+}
+
+int offs_client_friend_add_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx) {
+ return offs_client_friend_add(client, 2, ppm, ppm_len, callback, ctx);
+}
+
+int offs_client_load(offs_client_t* client, const char* ori_string,
+ uint8_t has_range, size_t range_start, size_t range_end,
+ offs_load_progress_cb_t progress_cb, void* progress_ctx,
+ offs_load_end_cb_t end_cb, void* end_ctx) {
+ if (client == NULL || !client->connected || ori_string == NULL) return -1;
+
+ client_api_load_request_t msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.ori_string = (char*)ori_string;
+ msg.has_range = has_range;
+ msg.range_start = range_start;
+ msg.range_end = range_end;
+
+ cbor_item_t* frame = client_api_load_request_encode(&msg);
+ if (frame == NULL) return -1; /* cbor allocation failure */
+
+ platform_mutex_lock(client->lock);
+ client->load_progress_cb = progress_cb;
+ client->load_progress_cb_ctx = progress_ctx;
+ client->load_end_cb = end_cb;
+ client->load_end_cb_ctx = end_ctx;
+ platform_mutex_unlock(client->lock);
+
+ _send_frame(client, frame);
+ return 0;
+}
+
buffer_t* offs_http_get(const char* url) {
if (!url) return NULL;
diff --git a/src/ClientLibs/c/offs_client.h b/src/ClientLibs/c/offs_client.h
index a6f09f0f..794713d2 100644
--- a/src/ClientLibs/c/offs_client.h
+++ b/src/ClientLibs/c/offs_client.h
@@ -59,6 +59,10 @@ typedef void (*offs_block_get_cb_t)(void* ctx, uint8_t status,
const uint8_t* data, size_t data_len);
typedef void (*offs_block_delete_cb_t)(void* ctx, uint8_t status);
typedef void (*offs_health_cb_t)(void* ctx, const char* json_response);
+typedef void (*offs_peer_info_cb_t)(void* ctx, uint8_t format, const uint8_t* data, size_t data_len);
+typedef void (*offs_peer_connect_cb_t)(void* ctx, uint8_t status);
+typedef void (*offs_load_progress_cb_t)(void* ctx, size_t tuples_loaded, size_t tuples_total);
+typedef void (*offs_load_end_cb_t)(void* ctx, uint8_t status, size_t tuples_loaded, size_t tuples_total);
/* Connection lifecycle */
offs_client_t* offs_client_connect(const char* transport_url, const char* api_key);
@@ -124,6 +128,50 @@ int offs_client_block_delete(offs_client_t* client,
int offs_client_health(offs_client_t* client,
offs_health_cb_t callback, void* ctx);
+/* Peer operations. format: 0 = raw CBOR peer_info, 1 = base58 text,
+ 2 = PPM QR image. The _qr forms are sugar for format 2.
+ Error delivery: daemon-side rejections (unauthorized, undecodable peer
+ info, etc.) arrive as ERROR frames dispatched to the error callback
+ registered via offs_client_get()'s callbacks — if no error callback is
+ registered, failures are silent. Success results arrive on the
+ per-operation callback.
+ Concurrency: one outstanding operation per callback slot — issuing
+ peer_connect and then friend_add before the first result arrives
+ delivers the first result to the second callback. */
+int offs_client_peer_info(offs_client_t* client, offs_peer_info_cb_t callback, void* ctx);
+int offs_client_peer_info_ex(offs_client_t* client, uint8_t format,
+ offs_peer_info_cb_t callback, void* ctx);
+int offs_client_peer_info_qr(offs_client_t* client, offs_peer_info_cb_t callback, void* ctx);
+int offs_client_peer_connect(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+int offs_client_peer_connect_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+int offs_client_friend_add(offs_client_t* client, uint8_t format,
+ const uint8_t* data, size_t data_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+int offs_client_friend_add_qr(offs_client_t* client, const uint8_t* ppm, size_t ppm_len,
+ offs_peer_connect_cb_t callback, void* ctx);
+
+/* Load a file's blocks into the daemon's block cache without receiving file
+ data. has_range + range_start/range_end limit which portion of the ORI is
+ preloaded; has_range = 0 loads the whole file (bounds ignored). Passed as
+ flat scalars rather than a struct because the public header exposes no
+ range type — consistent with the header's flat-parameter style.
+ progress_cb fires once per resolved tuple; end_cb fires EXACTLY ONCE with
+ the terminal status (CLIENT_API_LOAD_STATUS_LOADED/PARTIAL/FAILED,
+ defined in ClientAPI/client_api_wire.h).
+ Error delivery: daemon-side rejections (unauthorized, undecodable ORI,
+ etc.) arrive as ERROR frames dispatched to the error callback registered
+ via offs_client_get()'s callbacks — if no error callback is registered,
+ failures before the first LOAD_PROGRESS are silent.
+ Concurrency: only one load may be outstanding per connection (shared
+ one-op-per-slot rule; see peer operations above). */
+int offs_client_load(offs_client_t* client, const char* ori_string,
+ uint8_t has_range, size_t range_start, size_t range_end,
+ offs_load_progress_cb_t progress_cb, void* progress_ctx,
+ offs_load_end_cb_t end_cb, void* end_ctx);
+
/* Raw HTTP GET — opens a temporary TCP connection to fetch data from a URL.
Returns a buffer_t* with the response body, or NULL on error.
Caller must DESTROY the returned buffer. */
diff --git a/src/ClientLibs/js/offs-client/dist/offs-client.esm.js b/src/ClientLibs/js/offs-client/dist/offs-client.esm.js
index 46f52d4b..d85debe8 100644
--- a/src/ClientLibs/js/offs-client/dist/offs-client.esm.js
+++ b/src/ClientLibs/js/offs-client/dist/offs-client.esm.js
@@ -1,496 +1,147 @@
-var tr = Object.defineProperty;
-var rr = (t, e, r) => e in t ? tr(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r;
-var B = (t, e, r) => rr(t, typeof e != "symbol" ? e + "" : e, r);
-class D {
- /**
- * @param {string} url
- * @param {string} [apiKey]
- * @param {any} [_options]
- */
- constructor(e, r, n) {
- /** @type {string} */
- B(this, "baseUrl");
- /** @type {string|undefined} */
- B(this, "apiKey");
- /** @type {AbortController|null} */
- B(this, "abortController", null);
- this.baseUrl = e.replace(/\/$/, ""), this.apiKey = r;
- }
- /**
- * @returns {Promise}
- */
- async connect() {
- this.abortController = new AbortController();
- }
- disconnect() {
- this.abortController && (this.abortController.abort(), this.abortController = null);
- }
- isConnected() {
- return this.abortController !== null;
+var ar = Object.defineProperty;
+var fr = (t, e, r) => e in t ? ar(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r;
+var L = (t, e, r) => fr(t, typeof e != "symbol" ? e + "" : e, r);
+let He;
+try {
+ He = new TextDecoder();
+} catch {
+}
+let E, ce, c = 0;
+const lr = 105, cr = 57342, ur = 57343, it = 57337, ot = 6, he = {};
+let Ee = 11281e4, oe = 1681e4, T = {}, F, Ne, Be = 0, ge = 0, G, Z, H = [], je = [], z, W, we, at = {
+ useRecords: !1,
+ mapsAsObjects: !0
+}, me = !1, xt = 2;
+try {
+ new Function("");
+} catch {
+ xt = 1 / 0;
+}
+class Se {
+ constructor(e) {
+ if (e && ((e.keyMap || e._keyMap) && !e.useRecords && (e.useRecords = !1, e.mapsAsObjects = !0), e.useRecords === !1 && e.mapsAsObjects === void 0 && (e.mapsAsObjects = !0), e.getStructures && (e.getShared = e.getStructures), e.getShared && !e.structures && ((e.structures = []).uninitialized = !0), e.keyMap)) {
+ this.mapKey = /* @__PURE__ */ new Map();
+ for (let [r, n] of Object.entries(e.keyMap)) this.mapKey.set(n, r);
+ }
+ Object.assign(this, e);
}
- /**
- * @param {string} path
- * @returns {string}
- */
- url(e) {
- return `${this.baseUrl}${e}`;
+ /*
+ decodeKey(key) {
+ return this.keyMap
+ ? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
+ : key
}
- /**
- * @returns {Record}
- */
- authHeaders() {
- const e = {};
- return this.apiKey && (e.Authorization = `Bearer ${this.apiKey}`), e;
+ */
+ decodeKey(e) {
+ return this.keyMap && this.mapKey.get(e) || e;
}
- /**
- * @param {(type: number, bytes: Uint8Array) => void} _handler
- */
- setMessageHandler(e) {
+ encodeKey(e) {
+ return this.keyMap && this.keyMap.hasOwnProperty(e) ? this.keyMap[e] : e;
}
- /**
- * Send raw bytes — not used directly for HTTP; use the typed methods.
- * @param {Uint8Array} _bytes
- */
- send(e) {
- throw new Error("HttpTransport does not support raw send; use OffsClient methods");
+ encodeKeys(e) {
+ if (!this._keyMap) return e;
+ let r = /* @__PURE__ */ new Map();
+ for (let [n, s] of Object.entries(e)) r.set(this._keyMap.hasOwnProperty(n) ? this._keyMap[n] : n, s);
+ return r;
}
- /**
- * Upload a file to PUT /offsystem.
- * @param {import('../types.js').OffsPutOptions} options
- * @param {ReadableStream|Uint8Array} body
- * @returns {Promise<{oriString: string}>}
- */
- async put(e, r) {
- var p, y;
- const n = {
- ...this.authHeaders(),
- type: e.contentType,
- "file-name": e.fileName,
- "stream-length": String(e.streamLength)
- };
- e.serverAddress && (n["server-address"] = e.serverAddress), (p = e.recyclerUrls) != null && p.length && (n.recycler = JSON.stringify(e.recyclerUrls)), e.temporary && (n.temporary = "true"), e.tupleSize !== void 0 && (n["tuple-size"] = String(e.tupleSize));
- let s = r;
- r && typeof r.getReader == "function" && (s = await this._readStream(r));
- const o = await fetch(this.url("/offsystem"), {
- method: "PUT",
- headers: n,
- body: s,
- signal: (y = this.abortController) == null ? void 0 : y.signal
- });
- if (!o.ok) {
- const _ = await o.text();
- throw new Error(`Upload failed: ${o.status} ${_}`);
+ decodeKeys(e) {
+ if (!this._keyMap || e.constructor.name != "Map") return e;
+ if (!this._mapKey) {
+ this._mapKey = /* @__PURE__ */ new Map();
+ for (let [n, s] of Object.entries(this._keyMap)) this._mapKey.set(s, n);
}
- return { oriString: await o.text() };
+ let r = {};
+ return e.forEach((n, s) => r[Y(this._mapKey.has(s) ? this._mapKey.get(s) : s)] = n), r;
}
- /**
- * Read a ReadableStream into a Uint8Array.
- * The OFFS HTTP server is HTTP/1.1, so request streaming via duplex: 'half'
- * causes ERR_ALPN_NEGOTIATION_FAILED. Buffering the body avoids that.
- * @param {ReadableStream} stream
- * @returns {Promise}
- */
- async _readStream(e) {
- const r = e.getReader(), n = [];
- let s = 0;
- for (; ; ) {
- const { done: p, value: y } = await r.read();
- if (p) break;
- n.push(y), s += y.length;
- }
- const o = new Uint8Array(s);
- let l = 0;
- for (const p of n)
- o.set(p, l), l += p.length;
- return o;
+ mapDecode(e, r) {
+ let n = this.decode(e);
+ if (this._keyMap)
+ switch (n.constructor.name) {
+ case "Array":
+ return n.map((s) => this.decodeKeys(s));
+ }
+ return n;
}
- /**
- * Download from GET /offsystem/v3/...
- * @param {string} offUrl
- * @param {import('../types.js').OffsGetCallbacks} callbacks
- */
- async get(e, r) {
- var P, L, G, V, C, q, re;
- const n = await fetch(e, {
- method: "GET",
- headers: this.authHeaders(),
- signal: (P = this.abortController) == null ? void 0 : P.signal
- });
- if (!n.ok) {
- const I = await n.text();
- (L = r.onError) == null || L.call(r, n.status, I);
- return;
- }
- const s = n.headers.get("content-type") || "application/octet-stream", o = parseInt(n.headers.get("content-length") || "0", 10), l = n.status === 206, p = n.headers.get("content-range");
- let y, _;
- if (p) {
- const I = p.match(/bytes (\d+)-(\d+)\//);
- I && (y = parseInt(I[1], 10), _ = parseInt(I[2], 10));
- }
- (G = r.onStart) == null || G.call(r, s, o, l, y, _);
- const g = (V = n.body) == null ? void 0 : V.getReader();
- if (!g) {
- (C = r.onEnd) == null || C.call(r);
- return;
- }
+ decode(e, r) {
+ if (E)
+ return _t(() => (Ke(), this ? this.decode(e, r) : Se.prototype.decode.call(at, e, r)));
+ ce = r > -1 ? r : e.length, c = 0, ge = 0, Ne = null, G = null, E = e;
try {
- for (; ; ) {
- const { done: I, value: S } = await g.read();
- if (I) break;
- S && r.onData(S);
- }
- (q = r.onEnd) == null || q.call(r);
- } catch (I) {
- (re = r.onError) == null || re.call(r, 0, String(I));
+ W = e.dataView || (e.dataView = new DataView(e.buffer, e.byteOffset, e.byteLength));
+ } catch (n) {
+ throw E = null, e instanceof Uint8Array ? n : new Error("Source must be a Uint8Array or Buffer but was a " + (e && typeof e == "object" ? e.constructor.name : typeof e));
}
+ if (this instanceof Se) {
+ if (T = this, z = this.sharedValues && (this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) : this.sharedValues), this.structures)
+ return F = this.structures, Oe();
+ (!F || F.length > 0) && (F = []);
+ } else
+ T = at, (!F || F.length > 0) && (F = []), z = null;
+ return Oe();
}
- /**
- * Delete content.
- * @param {string} offUrl
- * @returns {Promise}
- */
- async delete(e) {
- var n;
- const r = await fetch(e, {
- method: "DELETE",
- headers: this.authHeaders(),
- signal: (n = this.abortController) == null ? void 0 : n.signal
- });
- if (!r.ok) {
- const s = await r.text();
- throw new Error(`Delete failed: ${r.status} ${s}`);
+ decodeMultiple(e, r) {
+ let n, s = 0;
+ try {
+ let o = e.length;
+ me = !0;
+ let l = this ? this.decode(e, o) : Xe.decode(e, o);
+ if (r) {
+ if (r(l) === !1)
+ return;
+ for (; c < o; )
+ if (s = c, r(Oe()) === !1)
+ return;
+ } else {
+ for (n = [l]; c < o; )
+ s = c, n.push(Oe());
+ return n;
+ }
+ } catch (o) {
+ throw o.lastPosition = s, o.values = n, o;
+ } finally {
+ me = !1, Ke();
}
}
- /**
- * @param {Uint8Array} data
- * @param {number} [encoding]
- * @returns {Promise<{status: number, hash: Uint8Array|string}>}
- */
- async blockPut(e, r = 0) {
- var l;
- const n = r === 1 ? "?encoding=base58" : "", s = await fetch(this.url(`/blocks${n}`), {
- method: "PUT",
- headers: { ...this.authHeaders(), "Content-Type": "application/octet-stream" },
- body: e,
- signal: (l = this.abortController) == null ? void 0 : l.signal
- });
- if (!s.ok) {
- const p = await s.text();
- throw new Error(`Block put failed: ${s.status} ${p}`);
+}
+function Oe() {
+ try {
+ let t = A();
+ if (G) {
+ if (c >= G.postBundlePosition) {
+ let e = new Error("Unexpected bundle position");
+ throw e.incomplete = !0, e;
+ }
+ c = G.postBundlePosition, G = null;
}
- const o = await s.arrayBuffer();
- return { status: 0, hash: new Uint8Array(o) };
- }
- /**
- * @param {string} base58Hash
- * @returns {Promise<{status: number, data: Uint8Array}>}
- */
- async blockGet(e) {
- var s;
- const r = await fetch(this.url(`/blocks/${e}`), {
- method: "GET",
- headers: this.authHeaders(),
- signal: (s = this.abortController) == null ? void 0 : s.signal
- });
- if (!r.ok)
- return { status: 2, data: new Uint8Array(0) };
- const n = await r.arrayBuffer();
- return { status: 0, data: new Uint8Array(n) };
- }
- /**
- * @param {string} base58Hash
- * @returns {Promise<{status: number}>}
- */
- async blockDelete(e) {
- var n;
- return { status: (await fetch(this.url(`/blocks/${e}`), {
- method: "DELETE",
- headers: this.authHeaders(),
- signal: (n = this.abortController) == null ? void 0 : n.signal
- })).ok ? 0 : 2 };
- }
- /**
- * @returns {Promise}
- */
- async health() {
- var r;
- const e = await fetch(this.url("/health"), {
- method: "GET",
- headers: this.authHeaders(),
- signal: (r = this.abortController) == null ? void 0 : r.signal
- });
- if (!e.ok)
- throw new Error(`Health check failed: ${e.status}`);
- return e.json();
- }
- /**
- * @param {string} [format='cbor']
- * @returns {Promise<{format: number, data: Uint8Array}>}
- */
- async peerInfo(e = "cbor") {
- var o;
- const r = e === "base58" ? 1 : 0, n = await fetch(this.url(`/peer/info?format=${e}`), {
- method: "GET",
- headers: this.authHeaders(),
- signal: (o = this.abortController) == null ? void 0 : o.signal
- });
- if (!n.ok) throw new Error(`Peer info failed: ${n.status}`);
- const s = await n.arrayBuffer();
- return { format: r, data: new Uint8Array(s) };
- }
- /**
- * @param {Uint8Array} peerInfo
- * @param {number} [format=0]
- * @returns {Promise<{status: number}>}
- */
- async peerConnect(e, r = 0) {
- var s;
- const n = await fetch(this.url("/peer/connect"), {
- method: "POST",
- headers: { ...this.authHeaders(), "Content-Type": r === 1 ? "text/plain" : "application/cbor" },
- body: r === 1 ? new TextDecoder().decode(e) : e,
- signal: (s = this.abortController) == null ? void 0 : s.signal
- });
- if (!n.ok) throw new Error(`Peer connect failed: ${n.status}`);
- return { status: 0 };
- }
- /**
- * @returns {Promise}
- */
- async peerList() {
- var r;
- const e = await fetch(this.url("/peers"), {
- method: "GET",
- headers: this.authHeaders(),
- signal: (r = this.abortController) == null ? void 0 : r.signal
- });
- if (!e.ok) throw new Error(`Peer list failed: ${e.status}`);
- return e.json();
- }
- /**
- * @param {Uint8Array} peerInfo
- * @param {number} [format=0]
- * @returns {Promise}
- */
- async friendAdd(e, r = 0) {
- var s;
- const n = await fetch(this.url("/friends"), {
- method: "POST",
- headers: { ...this.authHeaders(), "Content-Type": r === 1 ? "text/plain" : "application/cbor" },
- body: r === 1 ? new TextDecoder().decode(e) : e,
- signal: (s = this.abortController) == null ? void 0 : s.signal
- });
- if (!n.ok) throw new Error(`Friend add failed: ${n.status}`);
- }
- /**
- * @param {string} nodeId
- * @returns {Promise}
- */
- async friendRemove(e) {
- var n;
- const r = await fetch(this.url(`/friends/${e}`), {
- method: "DELETE",
- headers: this.authHeaders(),
- signal: (n = this.abortController) == null ? void 0 : n.signal
- });
- if (!r.ok) throw new Error(`Friend remove failed: ${r.status}`);
- }
- /**
- * @returns {Promise}
- */
- async friendList() {
- var r;
- const e = await fetch(this.url("/friends"), {
- method: "GET",
- headers: this.authHeaders(),
- signal: (r = this.abortController) == null ? void 0 : r.signal
- });
- if (!e.ok) throw new Error(`Friend list failed: ${e.status}`);
- return e.json();
- }
- /**
- * @returns {Promise}
- */
- async configShow() {
- var r;
- const e = await fetch(this.url("/config"), {
- method: "GET",
- headers: this.authHeaders(),
- signal: (r = this.abortController) == null ? void 0 : r.signal
- });
- if (!e.ok) throw new Error(`Config show failed: ${e.status}`);
- return e.json();
- }
- /**
- * @param {string} field
- * @param {string} value
- * @returns {Promise<{staged: any, rejected: any, restart_required: boolean}>}
- */
- async configSet(e, r) {
- var s;
- const n = await fetch(this.url("/config"), {
- method: "PUT",
- headers: { ...this.authHeaders(), "Content-Type": "application/json" },
- body: JSON.stringify({ [e]: r }),
- signal: (s = this.abortController) == null ? void 0 : s.signal
- });
- if (!n.ok) throw new Error(`Config set failed: ${n.status}`);
- return n.json();
- }
- /**
- * @returns {Promise}
- */
- async configReload() {
- var r;
- const e = await fetch(this.url("/config/restart"), {
- method: "POST",
- headers: this.authHeaders(),
- signal: (r = this.abortController) == null ? void 0 : r.signal
- });
- if (!e.ok) throw new Error(`Config reload failed: ${e.status}`);
- }
-}
-let Me;
-try {
- Me = new TextDecoder();
-} catch {
-}
-let w, le, c = 0;
-const nr = 105, sr = 57342, ir = 57343, nt = 57337, st = 6, de = {};
-let ye = 11281e4, ie = 1681e4, T = {}, k, Pe, Ne = 0, Ee = 0, H, Z, F = [], He = [], z, W, we, it = {
- useRecords: !1,
- mapsAsObjects: !0
-}, ge = !1, wt = 2;
-try {
- new Function("");
-} catch {
- wt = 1 / 0;
-}
-class me {
- constructor(e) {
- if (e && ((e.keyMap || e._keyMap) && !e.useRecords && (e.useRecords = !1, e.mapsAsObjects = !0), e.useRecords === !1 && e.mapsAsObjects === void 0 && (e.mapsAsObjects = !0), e.getStructures && (e.getShared = e.getStructures), e.getShared && !e.structures && ((e.structures = []).uninitialized = !0), e.keyMap)) {
- this.mapKey = /* @__PURE__ */ new Map();
- for (let [r, n] of Object.entries(e.keyMap)) this.mapKey.set(n, r);
- }
- Object.assign(this, e);
- }
- /*
- decodeKey(key) {
- return this.keyMap
- ? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
- : key
- }
- */
- decodeKey(e) {
- return this.keyMap && this.mapKey.get(e) || e;
- }
- encodeKey(e) {
- return this.keyMap && this.keyMap.hasOwnProperty(e) ? this.keyMap[e] : e;
- }
- encodeKeys(e) {
- if (!this._keyMap) return e;
- let r = /* @__PURE__ */ new Map();
- for (let [n, s] of Object.entries(e)) r.set(this._keyMap.hasOwnProperty(n) ? this._keyMap[n] : n, s);
- return r;
- }
- decodeKeys(e) {
- if (!this._keyMap || e.constructor.name != "Map") return e;
- if (!this._mapKey) {
- this._mapKey = /* @__PURE__ */ new Map();
- for (let [n, s] of Object.entries(this._keyMap)) this._mapKey.set(s, n);
- }
- let r = {};
- return e.forEach((n, s) => r[Y(this._mapKey.has(s) ? this._mapKey.get(s) : s)] = n), r;
- }
- mapDecode(e, r) {
- let n = this.decode(e);
- if (this._keyMap)
- switch (n.constructor.name) {
- case "Array":
- return n.map((s) => this.decodeKeys(s));
- }
- return n;
- }
- decode(e, r) {
- if (w)
- return mt(() => (qe(), this ? this.decode(e, r) : me.prototype.decode.call(it, e, r)));
- le = r > -1 ? r : e.length, c = 0, Ee = 0, Pe = null, H = null, w = e;
- try {
- W = e.dataView || (e.dataView = new DataView(e.buffer, e.byteOffset, e.byteLength));
- } catch (n) {
- throw w = null, e instanceof Uint8Array ? n : new Error("Source must be a Uint8Array or Buffer but was a " + (e && typeof e == "object" ? e.constructor.name : typeof e));
- }
- if (this instanceof me) {
- if (T = this, z = this.sharedValues && (this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) : this.sharedValues), this.structures)
- return k = this.structures, Re();
- (!k || k.length > 0) && (k = []);
- } else
- T = it, (!k || k.length > 0) && (k = []), z = null;
- return Re();
- }
- decodeMultiple(e, r) {
- let n, s = 0;
- try {
- let o = e.length;
- ge = !0;
- let l = this ? this.decode(e, o) : Ze.decode(e, o);
- if (r) {
- if (r(l) === !1)
- return;
- for (; c < o; )
- if (s = c, r(Re()) === !1)
- return;
- } else {
- for (n = [l]; c < o; )
- s = c, n.push(Re());
- return n;
- }
- } catch (o) {
- throw o.lastPosition = s, o.values = n, o;
- } finally {
- ge = !1, qe();
- }
- }
-}
-function Re() {
- try {
- let t = A();
- if (H) {
- if (c >= H.postBundlePosition) {
- let e = new Error("Unexpected bundle position");
- throw e.incomplete = !0, e;
- }
- c = H.postBundlePosition, H = null;
- }
- if (c == le)
- k = null, w = null, Z && (Z = null);
- else if (c > le) {
- let e = new Error("Unexpected end of CBOR data");
- throw e.incomplete = !0, e;
- } else if (!ge)
- throw new Error("Data read, but end of buffer not reached");
- return t;
- } catch (t) {
- throw qe(), (t instanceof RangeError || t.message.startsWith("Unexpected end of buffer")) && (t.incomplete = !0), t;
+ if (c == ce)
+ F = null, E = null, Z && (Z = null);
+ else if (c > ce) {
+ let e = new Error("Unexpected end of CBOR data");
+ throw e.incomplete = !0, e;
+ } else if (!me)
+ throw new Error("Data read, but end of buffer not reached");
+ return t;
+ } catch (t) {
+ throw Ke(), (t instanceof RangeError || t.message.startsWith("Unexpected end of buffer")) && (t.incomplete = !0), t;
}
}
function A() {
- let t = w[c++], e = t >> 5;
+ let t = E[c++], e = t >> 5;
if (t = t & 31, t > 23)
switch (t) {
case 24:
- t = w[c++];
+ t = E[c++];
break;
case 25:
if (e == 7)
- return lr();
+ return yr();
t = W.getUint16(c), c += 2;
break;
case 26:
if (e == 7) {
let r = W.getFloat32(c);
if (T.useFloat32 > 2) {
- let n = Je[(w[c] & 127) << 1 | w[c + 1] >> 7];
+ let n = Ye[(E[c] & 127) << 1 | E[c + 1] >> 7];
return c += 4, (n * r + (r > 0 ? 0.5 : -0.5) >> 0) / n;
}
return c += 4, r;
@@ -516,23 +167,23 @@ function A() {
throw new Error("Indefinite length not supported for byte or text strings");
case 4:
let r = [], n, s = 0;
- for (; (n = A()) != de; ) {
- if (s >= ye) throw new Error(`Array length exceeds ${ye}`);
+ for (; (n = A()) != he; ) {
+ if (s >= Ee) throw new Error(`Array length exceeds ${Ee}`);
r[s++] = n;
}
return e == 4 ? r : e == 3 ? r.join("") : Buffer.concat(r);
case 5:
let o;
if (T.mapsAsObjects) {
- let l = {}, p = 0;
+ let l = {}, h = 0;
if (T.keyMap)
- for (; (o = A()) != de; ) {
- if (p++ >= ie) throw new Error(`Property count exceeds ${ie}`);
+ for (; (o = A()) != he; ) {
+ if (h++ >= oe) throw new Error(`Property count exceeds ${oe}`);
l[Y(T.decodeKey(o))] = A();
}
else
- for (; (o = A()) != de; ) {
- if (p++ >= ie) throw new Error(`Property count exceeds ${ie}`);
+ for (; (o = A()) != he; ) {
+ if (h++ >= oe) throw new Error(`Property count exceeds ${oe}`);
l[Y(o)] = A();
}
return l;
@@ -540,24 +191,24 @@ function A() {
we && (T.mapsAsObjects = !0, we = !1);
let l = /* @__PURE__ */ new Map();
if (T.keyMap) {
- let p = 0;
- for (; (o = A()) != de; ) {
- if (p++ >= ie)
- throw new Error(`Map size exceeds ${ie}`);
+ let h = 0;
+ for (; (o = A()) != he; ) {
+ if (h++ >= oe)
+ throw new Error(`Map size exceeds ${oe}`);
l.set(T.decodeKey(o), A());
}
} else {
- let p = 0;
- for (; (o = A()) != de; ) {
- if (p++ >= ie)
- throw new Error(`Map size exceeds ${ie}`);
+ let h = 0;
+ for (; (o = A()) != he; ) {
+ if (h++ >= oe)
+ throw new Error(`Map size exceeds ${oe}`);
l.set(o, A());
}
}
return l;
}
case 7:
- return de;
+ return he;
default:
throw new Error("Invalid major type for indefinite length " + e);
}
@@ -570,23 +221,23 @@ function A() {
case 1:
return ~t;
case 2:
- return fr(t);
+ return pr(t);
case 3:
- if (Ee >= c)
- return Pe.slice(c - Ne, (c += t) - Ne);
- if (Ee == 0 && le < 140 && t < 32) {
- let s = t < 16 ? xt(t) : ar(t);
+ if (ge >= c)
+ return Ne.slice(c - Be, (c += t) - Be);
+ if (ge == 0 && ce < 140 && t < 32) {
+ let s = t < 16 ? gt(t) : hr(t);
if (s != null)
return s;
}
- return or(t);
+ return dr(t);
case 4:
- if (t >= ye) throw new Error(`Array length exceeds ${ye}`);
+ if (t >= Ee) throw new Error(`Array length exceeds ${Ee}`);
let r = new Array(t);
for (let s = 0; s < t; s++) r[s] = A();
return r;
case 5:
- if (t >= ie) throw new Error(`Map size exceeds ${ye}`);
+ if (t >= oe) throw new Error(`Map size exceeds ${Ee}`);
if (T.mapsAsObjects) {
let s = {};
if (T.keyMap) for (let o = 0; o < t; o++) s[Y(T.decodeKey(A()))] = A();
@@ -600,46 +251,46 @@ function A() {
return s;
}
case 6:
- if (t >= nt) {
- let s = k[t & 8191];
+ if (t >= it) {
+ let s = F[t & 8191];
if (s)
- return s.read || (s.read = je(s)), s.read();
+ return s.read || (s.read = qe(s)), s.read();
if (t < 65536) {
- if (t == ir) {
- let o = pe(), l = A(), p = A();
- Ge(l, p);
+ if (t == ur) {
+ let o = ye(), l = A(), h = A();
+ Ge(l, h);
let y = {};
- if (T.keyMap) for (let _ = 2; _ < o; _++) {
- let g = T.decodeKey(p[_ - 2]);
+ if (T.keyMap) for (let m = 2; m < o; m++) {
+ let g = T.decodeKey(h[m - 2]);
y[Y(g)] = A();
}
- else for (let _ = 2; _ < o; _++) {
- let g = p[_ - 2];
+ else for (let m = 2; m < o; m++) {
+ let g = h[m - 2];
y[Y(g)] = A();
}
return y;
- } else if (t == sr) {
- let o = pe(), l = A();
- for (let p = 2; p < o; p++)
+ } else if (t == cr) {
+ let o = ye(), l = A();
+ for (let h = 2; h < o; h++)
Ge(l++, A());
return A();
- } else if (t == nt)
- return yr();
- if (T.getShared && (Qe(), s = k[t & 8191], s))
- return s.read || (s.read = je(s)), s.read();
+ } else if (t == it)
+ return Sr();
+ if (T.getShared && (Ze(), s = F[t & 8191], s))
+ return s.read || (s.read = qe(s)), s.read();
}
}
- let n = F[t];
+ let n = H[t];
if (n)
return n.handlesRead ? n(A) : n(A());
{
let s = A();
- for (let o = 0; o < He.length; o++) {
- let l = He[o](t, s);
+ for (let o = 0; o < je.length; o++) {
+ let l = je[o](t, s);
if (l !== void 0)
return l;
}
- return new ce(s, t);
+ return new ue(s, t);
}
case 7:
switch (t) {
@@ -653,7 +304,7 @@ function A() {
return;
case 31:
default:
- let s = (z || fe())[t];
+ let s = (z || le())[t];
if (s !== void 0)
return s;
throw new Error("Unknown token " + t);
@@ -666,15 +317,15 @@ function A() {
throw new Error("Unknown CBOR token " + t);
}
}
-const ot = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
-function je(t) {
+const ft = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
+function qe(t) {
if (!t) throw new Error("Structure is required in record definition");
function e() {
- let r = w[c++];
+ let r = E[c++];
if (r = r & 31, r > 23)
switch (r) {
case 24:
- r = w[c++];
+ r = E[c++];
break;
case 25:
r = W.getUint16(c), c += 2;
@@ -683,7 +334,7 @@ function je(t) {
r = W.getUint32(c), c += 4;
break;
default:
- throw new Error("Expected array header, but got " + w[c - 1]);
+ throw new Error("Expected array header, but got " + E[c - 1]);
}
let n = this.compiledReader;
for (; n; ) {
@@ -691,9 +342,9 @@ function je(t) {
return n(A);
n = n.next;
}
- if (this.slowReads++ >= wt) {
+ if (this.slowReads++ >= xt) {
let o = this.length == r ? this : this.slice(0, r);
- return n = T.keyMap ? new Function("r", "return {" + o.map((l) => T.decodeKey(l)).map((l) => ot.test(l) ? Y(l) + ":r()" : "[" + JSON.stringify(l) + "]:r()").join(",") + "}") : new Function("r", "return {" + o.map((l) => ot.test(l) ? Y(l) + ":r()" : "[" + JSON.stringify(l) + "]:r()").join(",") + "}"), this.compiledReader && (n.next = this.compiledReader), n.propertyCount = r, this.compiledReader = n, n(A);
+ return n = T.keyMap ? new Function("r", "return {" + o.map((l) => T.decodeKey(l)).map((l) => ft.test(l) ? Y(l) + ":r()" : "[" + JSON.stringify(l) + "]:r()").join(",") + "}") : new Function("r", "return {" + o.map((l) => ft.test(l) ? Y(l) + ":r()" : "[" + JSON.stringify(l) + "]:r()").join(",") + "}"), this.compiledReader && (n.next = this.compiledReader), n.propertyCount = r, this.compiledReader = n, n(A);
}
let s = {};
if (T.keyMap) for (let o = 0; o < r; o++) s[Y(T.decodeKey(this[o]))] = A();
@@ -709,238 +360,238 @@ function Y(t) {
if (t == null) return t + "";
throw new Error("Invalid property name type " + typeof t);
}
-let or = Ke;
-function Ke(t) {
+let dr = $e;
+function $e(t) {
let e;
- if (t < 16 && (e = xt(t)))
+ if (t < 16 && (e = gt(t)))
return e;
- if (t > 64 && Me)
- return Me.decode(w.subarray(c, c += t));
+ if (t > 64 && He)
+ return He.decode(E.subarray(c, c += t));
const r = c + t, n = [];
for (e = ""; c < r; ) {
- const s = w[c++];
+ const s = E[c++];
if (!(s & 128))
n.push(s);
else if ((s & 224) === 192)
- if (s < 194 || c >= r || (w[c] & 192) !== 128)
+ if (s < 194 || c >= r || (E[c] & 192) !== 128)
n.push(65533);
else {
- const o = w[c++] & 63;
+ const o = E[c++] & 63;
n.push((s & 31) << 6 | o);
}
else if ((s & 240) === 224) {
- const o = c < r ? w[c] : 0;
+ const o = c < r ? E[c] : 0;
if (c >= r || (o & 192) !== 128 || s === 224 && o < 160 || s === 237 && o >= 160)
n.push(65533);
- else if (c++, c >= r || (w[c] & 192) !== 128)
+ else if (c++, c >= r || (E[c] & 192) !== 128)
n.push(65533);
else {
- const l = w[c++] & 63;
+ const l = E[c++] & 63;
n.push((s & 31) << 12 | (o & 63) << 6 | l);
}
} else if ((s & 248) === 240) {
- const o = c < r ? w[c] : 0;
+ const o = c < r ? E[c] : 0;
if (s > 244 || c >= r || (o & 192) !== 128 || s === 240 && o < 144 || s === 244 && o >= 144)
n.push(65533);
- else if (c++, c >= r || (w[c] & 192) !== 128)
+ else if (c++, c >= r || (E[c] & 192) !== 128)
n.push(65533);
else {
- const l = w[c++] & 63;
- if (c >= r || (w[c] & 192) !== 128)
+ const l = E[c++] & 63;
+ if (c >= r || (E[c] & 192) !== 128)
n.push(65533);
else {
- const p = w[c++] & 63;
- let y = (s & 7) << 18 | (o & 63) << 12 | l << 6 | p;
+ const h = E[c++] & 63;
+ let y = (s & 7) << 18 | (o & 63) << 12 | l << 6 | h;
y -= 65536, n.push(y >>> 10 & 1023 | 55296), n.push(56320 | y & 1023);
}
}
} else
n.push(65533);
- n.length >= 4096 && (e += j.apply(String, n), n.length = 0);
+ n.length >= 4096 && (e += K.apply(String, n), n.length = 0);
}
- return n.length > 0 && (e += j.apply(String, n)), e;
+ return n.length > 0 && (e += K.apply(String, n)), e;
}
-let j = String.fromCharCode;
-function ar(t) {
+let K = String.fromCharCode;
+function hr(t) {
let e = c, r = new Array(t);
for (let n = 0; n < t; n++) {
- const s = w[c++];
+ const s = E[c++];
if ((s & 128) > 0) {
c = e;
return;
}
r[n] = s;
}
- return j.apply(String, r);
+ return K.apply(String, r);
}
-function xt(t) {
+function gt(t) {
if (t < 4)
if (t < 2) {
if (t === 0)
return "";
{
- let e = w[c++];
+ let e = E[c++];
if ((e & 128) > 1) {
c -= 1;
return;
}
- return j(e);
+ return K(e);
}
} else {
- let e = w[c++], r = w[c++];
+ let e = E[c++], r = E[c++];
if ((e & 128) > 0 || (r & 128) > 0) {
c -= 2;
return;
}
if (t < 3)
- return j(e, r);
- let n = w[c++];
+ return K(e, r);
+ let n = E[c++];
if ((n & 128) > 0) {
c -= 3;
return;
}
- return j(e, r, n);
+ return K(e, r, n);
}
else {
- let e = w[c++], r = w[c++], n = w[c++], s = w[c++];
+ let e = E[c++], r = E[c++], n = E[c++], s = E[c++];
if ((e & 128) > 0 || (r & 128) > 0 || (n & 128) > 0 || (s & 128) > 0) {
c -= 4;
return;
}
if (t < 6) {
if (t === 4)
- return j(e, r, n, s);
+ return K(e, r, n, s);
{
- let o = w[c++];
+ let o = E[c++];
if ((o & 128) > 0) {
c -= 5;
return;
}
- return j(e, r, n, s, o);
+ return K(e, r, n, s, o);
}
} else if (t < 8) {
- let o = w[c++], l = w[c++];
+ let o = E[c++], l = E[c++];
if ((o & 128) > 0 || (l & 128) > 0) {
c -= 6;
return;
}
if (t < 7)
- return j(e, r, n, s, o, l);
- let p = w[c++];
- if ((p & 128) > 0) {
+ return K(e, r, n, s, o, l);
+ let h = E[c++];
+ if ((h & 128) > 0) {
c -= 7;
return;
}
- return j(e, r, n, s, o, l, p);
+ return K(e, r, n, s, o, l, h);
} else {
- let o = w[c++], l = w[c++], p = w[c++], y = w[c++];
- if ((o & 128) > 0 || (l & 128) > 0 || (p & 128) > 0 || (y & 128) > 0) {
+ let o = E[c++], l = E[c++], h = E[c++], y = E[c++];
+ if ((o & 128) > 0 || (l & 128) > 0 || (h & 128) > 0 || (y & 128) > 0) {
c -= 8;
return;
}
if (t < 10) {
if (t === 8)
- return j(e, r, n, s, o, l, p, y);
+ return K(e, r, n, s, o, l, h, y);
{
- let _ = w[c++];
- if ((_ & 128) > 0) {
+ let m = E[c++];
+ if ((m & 128) > 0) {
c -= 9;
return;
}
- return j(e, r, n, s, o, l, p, y, _);
+ return K(e, r, n, s, o, l, h, y, m);
}
} else if (t < 12) {
- let _ = w[c++], g = w[c++];
- if ((_ & 128) > 0 || (g & 128) > 0) {
+ let m = E[c++], g = E[c++];
+ if ((m & 128) > 0 || (g & 128) > 0) {
c -= 10;
return;
}
if (t < 11)
- return j(e, r, n, s, o, l, p, y, _, g);
- let P = w[c++];
+ return K(e, r, n, s, o, l, h, y, m, g);
+ let P = E[c++];
if ((P & 128) > 0) {
c -= 11;
return;
}
- return j(e, r, n, s, o, l, p, y, _, g, P);
+ return K(e, r, n, s, o, l, h, y, m, g, P);
} else {
- let _ = w[c++], g = w[c++], P = w[c++], L = w[c++];
- if ((_ & 128) > 0 || (g & 128) > 0 || (P & 128) > 0 || (L & 128) > 0) {
+ let m = E[c++], g = E[c++], P = E[c++], N = E[c++];
+ if ((m & 128) > 0 || (g & 128) > 0 || (P & 128) > 0 || (N & 128) > 0) {
c -= 12;
return;
}
if (t < 14) {
if (t === 12)
- return j(e, r, n, s, o, l, p, y, _, g, P, L);
+ return K(e, r, n, s, o, l, h, y, m, g, P, N);
{
- let G = w[c++];
- if ((G & 128) > 0) {
+ let q = E[c++];
+ if ((q & 128) > 0) {
c -= 13;
return;
}
- return j(e, r, n, s, o, l, p, y, _, g, P, L, G);
+ return K(e, r, n, s, o, l, h, y, m, g, P, N, q);
}
} else {
- let G = w[c++], V = w[c++];
- if ((G & 128) > 0 || (V & 128) > 0) {
+ let q = E[c++], v = E[c++];
+ if ((q & 128) > 0 || (v & 128) > 0) {
c -= 14;
return;
}
if (t < 15)
- return j(e, r, n, s, o, l, p, y, _, g, P, L, G, V);
- let C = w[c++];
- if ((C & 128) > 0) {
+ return K(e, r, n, s, o, l, h, y, m, g, P, N, q, v);
+ let B = E[c++];
+ if ((B & 128) > 0) {
c -= 15;
return;
}
- return j(e, r, n, s, o, l, p, y, _, g, P, L, G, V, C);
+ return K(e, r, n, s, o, l, h, y, m, g, P, N, q, v, B);
}
}
}
}
}
-function fr(t) {
+function pr(t) {
return T.copyBuffers ? (
// specifically use the copying slice (not the node one)
- Uint8Array.prototype.slice.call(w, c, c += t)
- ) : w.subarray(c, c += t);
+ Uint8Array.prototype.slice.call(E, c, c += t)
+ ) : E.subarray(c, c += t);
}
-let Et = new Float32Array(1), Oe = new Uint8Array(Et.buffer, 0, 4);
-function lr() {
- let t = w[c++], e = w[c++], r = (t & 127) >> 2;
+let mt = new Float32Array(1), Te = new Uint8Array(mt.buffer, 0, 4);
+function yr() {
+ let t = E[c++], e = E[c++], r = (t & 127) >> 2;
if (r === 31)
return e || t & 3 ? NaN : t & 128 ? -1 / 0 : 1 / 0;
if (r === 0) {
let n = ((t & 3) << 8 | e) / 16777216;
return t & 128 ? -n : n;
}
- return Oe[3] = t & 128 | // sign bit
- (r >> 1) + 56, Oe[2] = (t & 7) << 5 | // last exponent bit and first two mantissa bits
- e >> 3, Oe[1] = e << 5, Oe[0] = 0, Et[0];
+ return Te[3] = t & 128 | // sign bit
+ (r >> 1) + 56, Te[2] = (t & 7) << 5 | // last exponent bit and first two mantissa bits
+ e >> 3, Te[1] = e << 5, Te[0] = 0, mt[0];
}
new Array(4096);
-class ce {
+class ue {
constructor(e, r) {
this.value = e, this.tag = r;
}
}
-F[0] = (t) => new Date(t);
-F[1] = (t) => new Date(Math.round(t * 1e3));
-F[2] = (t) => {
+H[0] = (t) => new Date(t);
+H[1] = (t) => new Date(Math.round(t * 1e3));
+H[2] = (t) => {
let e = BigInt(0);
for (let r = 0, n = t.byteLength; r < n; r++)
e = BigInt(t[r]) + (e << BigInt(8));
return e;
};
-F[3] = (t) => BigInt(-1) - F[2](t);
-F[4] = (t) => +(t[1] + "e" + t[0]);
-F[5] = (t) => t[1] * Math.exp(t[0] * Math.log(2));
+H[3] = (t) => BigInt(-1) - H[2](t);
+H[4] = (t) => +(t[1] + "e" + t[0]);
+H[5] = (t) => t[1] * Math.exp(t[0] * Math.log(2));
const Ge = (t, e) => {
t = t - 57344;
- let r = k[t];
- r && r.isShared && ((k.restoreStructures || (k.restoreStructures = []))[t] = r), k[t] = e, e.read = je(e);
+ let r = F[t];
+ r && r.isShared && ((F.restoreStructures || (F.restoreStructures = []))[t] = r), F[t] = e, e.read = qe(e);
};
-F[nr] = (t) => {
+H[lr] = (t) => {
let e = t.length, r = t[1];
Ge(t[0], r);
let n = {};
@@ -950,14 +601,14 @@ F[nr] = (t) => {
}
return n;
};
-F[14] = (t) => H ? H[0].slice(H.position0, H.position0 += t) : new ce(t, 14);
-F[15] = (t) => H ? H[1].slice(H.position1, H.position1 += t) : new ce(t, 15);
-let cr = { Error, RegExp };
-F[27] = (t) => (cr[t[0]] || Error)(t[1], t[2]);
-const gt = (t) => {
- if (w[c++] != 132) {
+H[14] = (t) => G ? G[0].slice(G.position0, G.position0 += t) : new ue(t, 14);
+H[15] = (t) => G ? G[1].slice(G.position1, G.position1 += t) : new ue(t, 15);
+let Er = { Error, RegExp };
+H[27] = (t) => (Er[t[0]] || Error)(t[1], t[2]);
+const St = (t) => {
+ if (E[c++] != 132) {
let r = new Error("Packed values structure must be followed by a 4 element array");
- throw w.length < c && (r.incomplete = !0), r;
+ throw E.length < c && (r.incomplete = !0), r;
}
let e = t();
if (!e || !e.length) {
@@ -966,70 +617,70 @@ const gt = (t) => {
}
return z = z ? e.concat(z.slice(e.length)) : e, z.prefixes = t(), z.suffixes = t(), t();
};
-gt.handlesRead = !0;
-F[51] = gt;
-F[st] = (t) => {
+St.handlesRead = !0;
+H[51] = St;
+H[ot] = (t) => {
if (!z)
if (T.getShared)
- Qe();
+ Ze();
else
- return new ce(t, st);
+ return new ue(t, ot);
if (typeof t == "number")
return z[16 + (t >= 0 ? 2 * t : -2 * t - 1)];
let e = new Error("No support for non-integer packed references yet");
throw t === void 0 && (e.incomplete = !0), e;
};
-F[28] = (t) => {
+H[28] = (t) => {
Z || (Z = /* @__PURE__ */ new Map(), Z.id = 0);
- let e = Z.id++, r = c, n = w[c], s;
+ let e = Z.id++, r = c, n = E[c], s;
n >> 5 == 4 ? s = [] : s = {};
let o = { target: s };
Z.set(e, o);
let l = t();
return o.used ? (Object.getPrototypeOf(s) !== Object.getPrototypeOf(l) && (c = r, s = l, Z.set(e, { target: s }), l = t()), Object.assign(s, l)) : (o.target = l, l);
};
-F[28].handlesRead = !0;
-F[29] = (t) => {
+H[28].handlesRead = !0;
+H[29] = (t) => {
let e = Z.get(t);
return e.used = !0, e.target;
};
-F[258] = (t) => new Set(t);
-(F[259] = (t) => (T.mapsAsObjects && (T.mapsAsObjects = !1, we = !0), t())).handlesRead = !0;
-function he(t, e) {
+H[258] = (t) => new Set(t);
+(H[259] = (t) => (T.mapsAsObjects && (T.mapsAsObjects = !1, we = !0), t())).handlesRead = !0;
+function pe(t, e) {
return typeof t == "string" ? t + e : t instanceof Array ? t.concat(e) : Object.assign({}, t, e);
}
-function fe() {
+function le() {
if (!z)
if (T.getShared)
- Qe();
+ Ze();
else
throw new Error("No packed values available");
return z;
}
-const ur = 1399353956;
-He.push((t, e) => {
+const wr = 1399353956;
+je.push((t, e) => {
if (t >= 225 && t <= 255)
- return he(fe().prefixes[t - 224], e);
+ return pe(le().prefixes[t - 224], e);
if (t >= 28704 && t <= 32767)
- return he(fe().prefixes[t - 28672], e);
+ return pe(le().prefixes[t - 28672], e);
if (t >= 1879052288 && t <= 2147483647)
- return he(fe().prefixes[t - 1879048192], e);
+ return pe(le().prefixes[t - 1879048192], e);
if (t >= 216 && t <= 223)
- return he(e, fe().suffixes[t - 216]);
+ return pe(e, le().suffixes[t - 216]);
if (t >= 27647 && t <= 28671)
- return he(e, fe().suffixes[t - 27639]);
+ return pe(e, le().suffixes[t - 27639]);
if (t >= 1811940352 && t <= 1879048191)
- return he(e, fe().suffixes[t - 1811939328]);
- if (t == ur)
+ return pe(e, le().suffixes[t - 1811939328]);
+ if (t == wr)
return {
packedValues: z,
- structures: k.slice(0),
+ structures: F.slice(0),
version: e
};
if (t == 55799)
return e;
});
-const dr = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1, at = [
+const xr = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1, lt = [
Uint8Array,
Uint8ClampedArray,
Uint16Array,
@@ -1041,45 +692,45 @@ const dr = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1, at = [
typeof BigInt64Array > "u" ? { name: "BigInt64Array" } : BigInt64Array,
Float32Array,
Float64Array
-], hr = [64, 68, 69, 70, 71, 72, 77, 78, 79, 85, 86];
-for (let t = 0; t < at.length; t++)
- pr(at[t], hr[t]);
-function pr(t, e) {
+], gr = [64, 68, 69, 70, 71, 72, 77, 78, 79, 85, 86];
+for (let t = 0; t < lt.length; t++)
+ mr(lt[t], gr[t]);
+function mr(t, e) {
let r = "get" + t.name.slice(0, -5), n;
typeof t == "function" ? n = t.BYTES_PER_ELEMENT : t = null;
for (let s = 0; s < 2; s++) {
if (!s && n == 1)
continue;
let o = n == 2 ? 1 : n == 4 ? 2 : n == 8 ? 3 : 0;
- F[s ? e : e - 4] = n == 1 || s == dr ? (l) => {
+ H[s ? e : e - 4] = n == 1 || s == xr ? (l) => {
if (!t)
throw new Error("Could not find typed array for code " + e);
return !T.copyBuffers && (n === 1 || n === 2 && !(l.byteOffset & 1) || n === 4 && !(l.byteOffset & 3) || n === 8 && !(l.byteOffset & 7)) ? new t(l.buffer, l.byteOffset, l.byteLength >> o) : new t(Uint8Array.prototype.slice.call(l, 0).buffer);
} : (l) => {
if (!t)
throw new Error("Could not find typed array for code " + e);
- let p = new DataView(l.buffer, l.byteOffset, l.byteLength), y = l.length >> o, _ = new t(y), g = p[r];
+ let h = new DataView(l.buffer, l.byteOffset, l.byteLength), y = l.length >> o, m = new t(y), g = h[r];
for (let P = 0; P < y; P++)
- _[P] = g.call(p, P << o, s);
- return _;
+ m[P] = g.call(h, P << o, s);
+ return m;
};
}
}
-function yr() {
- let t = pe(), e = c + A();
+function Sr() {
+ let t = ye(), e = c + A();
for (let n = 2; n < t; n++) {
- let s = pe();
+ let s = ye();
c += s;
}
let r = c;
- return c = e, H = [Ke(pe()), Ke(pe())], H.position0 = 0, H.position1 = 0, H.postBundlePosition = c, c = r, A();
+ return c = e, G = [$e(ye()), $e(ye())], G.position0 = 0, G.position1 = 0, G.postBundlePosition = c, c = r, A();
}
-function pe() {
- let t = w[c++] & 31;
+function ye() {
+ let t = E[c++] & 31;
if (t > 23)
switch (t) {
case 24:
- t = w[c++];
+ t = E[c++];
break;
case 25:
t = W.getUint16(c), c += 2;
@@ -1090,121 +741,121 @@ function pe() {
}
return t;
}
-function Qe() {
+function Ze() {
if (T.getShared) {
- let t = mt(() => (w = null, T.getShared())) || {}, e = t.structures || [];
- T.sharedVersion = t.version, z = T.sharedValues = t.packedValues, k === !0 ? T.structures = k = e : k.splice.apply(k, [0, e.length].concat(e));
+ let t = _t(() => (E = null, T.getShared())) || {}, e = t.structures || [];
+ T.sharedVersion = t.version, z = T.sharedValues = t.packedValues, F === !0 ? T.structures = F = e : F.splice.apply(F, [0, e.length].concat(e));
}
}
-function mt(t) {
- let e = le, r = c, n = Ne, s = Ee, o = Pe, l = Z, p = H, y = new Uint8Array(w.slice(0, le)), _ = k, g = T, P = ge, L = t();
- return le = e, c = r, Ne = n, Ee = s, Pe = o, Z = l, H = p, w = y, ge = P, k = _, T = g, W = new DataView(w.buffer, w.byteOffset, w.byteLength), L;
+function _t(t) {
+ let e = ce, r = c, n = Be, s = ge, o = Ne, l = Z, h = G, y = new Uint8Array(E.slice(0, ce)), m = F, g = T, P = me, N = t();
+ return ce = e, c = r, Be = n, ge = s, Ne = o, Z = l, G = h, E = y, me = P, F = m, T = g, W = new DataView(E.buffer, E.byteOffset, E.byteLength), N;
}
-function qe() {
- w = null, Z = null, k = null;
+function Ke() {
+ E = null, Z = null, F = null;
}
-const Je = new Array(147);
+const Ye = new Array(147);
for (let t = 0; t < 256; t++)
- Je[t] = +("1e" + Math.floor(45.15 - t * 0.30103));
-let Ze = new me({ useRecords: !1 });
-const $ = Ze.decode;
-Ze.decodeMultiple;
-let Ae;
+ Ye[t] = +("1e" + Math.floor(45.15 - t * 0.30103));
+let Xe = new Se({ useRecords: !1 });
+const j = Xe.decode;
+Xe.decodeMultiple;
+let Ue;
try {
- Ae = new TextEncoder();
+ Ue = new TextEncoder();
} catch {
}
-let $e, St;
-const Be = typeof globalThis == "object" && globalThis.Buffer, Se = typeof Be < "u", Ce = Se ? Be.allocUnsafeSlow : Uint8Array, ft = Se ? Be : Uint8Array, lt = 256, ct = Se ? 4294967296 : 2144337920;
-let Ie, f, N, i = 0, oe, M = null;
-const wr = 61440, xr = /[\u0080-\uFFFF]/, Q = Symbol("record-id");
-class bt extends me {
+let ve, Rt;
+const Ce = typeof globalThis == "object" && globalThis.Buffer, _e = typeof Ce < "u", Le = _e ? Ce.allocUnsafeSlow : Uint8Array, ct = _e ? Ce : Uint8Array, ut = 256, dt = _e ? 4294967296 : 2144337920;
+let Ie, f, C, i = 0, ae, $ = null;
+const _r = 61440, Rr = /[\u0080-\uFFFF]/, Q = Symbol("record-id");
+class bt extends Se {
constructor(e) {
super(e), this.offset = 0;
let r, n, s, o, l;
e = e || {};
- let p = ft.prototype.utf8Write ? function(a, x) {
- return f.utf8Write(a, x, f.byteLength - x);
- } : Ae && Ae.encodeInto ? function(a, x) {
- return Ae.encodeInto(a, f.subarray(x)).written;
- } : !1, y = this, _ = e.structures || e.saveStructures, g = e.maxSharedStructures;
- if (g == null && (g = _ ? 128 : 0), g > 8190)
+ let h = ct.prototype.utf8Write ? function(a, w) {
+ return f.utf8Write(a, w, f.byteLength - w);
+ } : Ue && Ue.encodeInto ? function(a, w) {
+ return Ue.encodeInto(a, f.subarray(w)).written;
+ } : !1, y = this, m = e.structures || e.saveStructures, g = e.maxSharedStructures;
+ if (g == null && (g = m ? 128 : 0), g > 8190)
throw new Error("Maximum maxSharedStructure is 8190");
let P = e.sequential;
P && (g = 0), this.structures || (this.structures = []), this.saveStructures && (this.saveShared = this.saveStructures);
- let L, G, V = e.sharedValues, C;
- if (V) {
- C = /* @__PURE__ */ Object.create(null);
- for (let a = 0, x = V.length; a < x; a++)
- C[V[a]] = a;
+ let N, q, v = e.sharedValues, B;
+ if (v) {
+ B = /* @__PURE__ */ Object.create(null);
+ for (let a = 0, w = v.length; a < w; a++)
+ B[v[a]] = a;
}
- let q = [], re = 0, I = 0;
- this.mapEncode = function(a, x) {
+ let M = [], ne = 0, I = 0;
+ this.mapEncode = function(a, w) {
if (this._keyMap && !this._mapped)
switch (a.constructor.name) {
case "Array":
a = a.map((d) => this.encodeKeys(d));
break;
}
- return this.encode(a, x);
- }, this.encode = function(a, x) {
- if (f || (f = new Ce(8192), N = new DataView(f.buffer, 0, 8192), i = 0), oe = f.length - 10, oe - i < 2048 ? (f = new Ce(f.length), N = new DataView(f.buffer, 0, f.length), oe = f.length - 10, i = 0) : x === ht && (i = i + 7 & 2147483640), r = i, y.useSelfDescribedHeader && (N.setUint32(i, 3654940416), i += 3), l = y.structuredClone ? /* @__PURE__ */ new Map() : null, y.bundleStrings && typeof a != "string" ? (M = [], M.size = 1 / 0) : M = null, n = y.structures, n) {
+ return this.encode(a, w);
+ }, this.encode = function(a, w) {
+ if (f || (f = new Le(8192), C = new DataView(f.buffer, 0, 8192), i = 0), ae = f.length - 10, ae - i < 2048 ? (f = new Le(f.length), C = new DataView(f.buffer, 0, f.length), ae = f.length - 10, i = 0) : w === yt && (i = i + 7 & 2147483640), r = i, y.useSelfDescribedHeader && (C.setUint32(i, 3654940416), i += 3), l = y.structuredClone ? /* @__PURE__ */ new Map() : null, y.bundleStrings && typeof a != "string" ? ($ = [], $.size = 1 / 0) : $ = null, n = y.structures, n) {
if (n.uninitialized) {
- let h = y.getShared() || {};
- y.structures = n = h.structures || [], y.sharedVersion = h.version;
- let u = y.sharedValues = h.packedValues;
+ let p = y.getShared() || {};
+ y.structures = n = p.structures || [], y.sharedVersion = p.version;
+ let u = y.sharedValues = p.packedValues;
if (u) {
- C = {};
- for (let m = 0, b = u.length; m < b; m++)
- C[u[m]] = m;
+ B = {};
+ for (let S = 0, R = u.length; S < R; S++)
+ B[u[S]] = S;
}
}
let d = n.length;
if (d > g && !P && (d = g), !n.transitions) {
n.transitions = /* @__PURE__ */ Object.create(null);
- for (let h = 0; h < d; h++) {
- let u = n[h];
+ for (let p = 0; p < d; p++) {
+ let u = n[p];
if (!u)
continue;
- let m, b = n.transitions;
- for (let R = 0, O = u.length; R < O; R++) {
- b[Q] === void 0 && (b[Q] = h);
- let U = u[R];
- m = b[U], m || (m = b[U] = /* @__PURE__ */ Object.create(null)), b = m;
+ let S, R = n.transitions;
+ for (let b = 0, O = u.length; b < O; b++) {
+ R[Q] === void 0 && (R[Q] = p);
+ let U = u[b];
+ S = R[U], S || (S = R[U] = /* @__PURE__ */ Object.create(null)), R = S;
}
- b[Q] = h | 1048576;
+ R[Q] = p | 1048576;
}
}
P || (n.nextId = d);
}
- if (s && (s = !1), o = n || [], G = C, e.pack) {
+ if (s && (s = !1), o = n || [], q = B, e.pack) {
let d = /* @__PURE__ */ new Map();
- if (d.values = [], d.encoder = y, d.maxValues = e.maxPrivatePackedValues || (C ? 16 : 1 / 0), d.objectMap = C || !1, d.samplingPackedValues = L, Ue(a, d), d.values.length > 0) {
+ if (d.values = [], d.encoder = y, d.maxValues = e.maxPrivatePackedValues || (B ? 16 : 1 / 0), d.objectMap = B || !1, d.samplingPackedValues = N, Pe(a, d), d.values.length > 0) {
f[i++] = 216, f[i++] = 51, te(4);
- let h = d.values;
- S(h), te(0), te(0), G = Object.create(C || null);
- for (let u = 0, m = h.length; u < m; u++)
- G[h[u]] = u;
+ let p = d.values;
+ _(p), te(0), te(0), q = Object.create(B || null);
+ for (let u = 0, S = p.length; u < S; u++)
+ q[p[u]] = u;
}
}
- Ie = x & De;
+ Ie = w & Fe;
try {
if (Ie)
return;
- if (S(a), M && dt(r, S), y.offset = i, l && l.idsToInsert) {
- i += l.idsToInsert.length * 2, i > oe && J(i), y.offset = i;
- let d = mr(f.subarray(r, i), l.idsToInsert);
+ if (_(a), $ && pt(r, _), y.offset = i, l && l.idsToInsert) {
+ i += l.idsToInsert.length * 2, i > ae && J(i), y.offset = i;
+ let d = Tr(f.subarray(r, i), l.idsToInsert);
return l = null, d;
}
- return x & ht ? (f.start = r, f.end = i, f) : f.subarray(r, i);
+ return w & yt ? (f.start = r, f.end = i, f) : f.subarray(r, i);
} finally {
if (n) {
- if (I < 10 && I++, n.length > g && (n.length = g), re > 1e4)
- n.transitions = null, I = 0, re = 0, q.length > 0 && (q = []);
- else if (q.length > 0 && !P) {
- for (let d = 0, h = q.length; d < h; d++)
- q[d][Q] = void 0;
- q = [];
+ if (I < 10 && I++, n.length > g && (n.length = g), ne > 1e4)
+ n.transitions = null, I = 0, ne = 0, M.length > 0 && (M = []);
+ else if (M.length > 0 && !P) {
+ for (let d = 0, p = M.length; d < p; d++)
+ M[d][Q] = void 0;
+ M = [];
}
}
if (s && y.saveShared) {
@@ -1212,76 +863,76 @@ class bt extends me {
let d = f.subarray(r, i);
return y.updateSharedData() === !1 ? y.encode(a) : d;
}
- x & br && (i = r);
+ w & Ur && (i = r);
}
- }, this.findCommonStringsToPack = () => (L = /* @__PURE__ */ new Map(), C || (C = /* @__PURE__ */ Object.create(null)), (a) => {
- let x = a && a.threshold || 4, d = this.pack ? a.maxPrivatePackedValues || 16 : 0;
- V || (V = this.sharedValues = []);
- for (let [h, u] of L)
- u.count > x && (C[h] = d++, V.push(h), s = !0);
+ }, this.findCommonStringsToPack = () => (N = /* @__PURE__ */ new Map(), B || (B = /* @__PURE__ */ Object.create(null)), (a) => {
+ let w = a && a.threshold || 4, d = this.pack ? a.maxPrivatePackedValues || 16 : 0;
+ v || (v = this.sharedValues = []);
+ for (let [p, u] of N)
+ u.count > w && (B[p] = d++, v.push(p), s = !0);
for (; this.saveShared && this.updateSharedData() === !1; )
;
- L = null;
+ N = null;
});
- const S = (a) => {
- i > oe && (f = J(i));
- var x = typeof a, d;
- if (x === "string") {
- if (G) {
- let b = G[a];
- if (b >= 0) {
- b < 16 ? f[i++] = b + 224 : (f[i++] = 198, b & 1 ? S(15 - b >> 1) : S(b - 16 >> 1));
+ const _ = (a) => {
+ i > ae && (f = J(i));
+ var w = typeof a, d;
+ if (w === "string") {
+ if (q) {
+ let R = q[a];
+ if (R >= 0) {
+ R < 16 ? f[i++] = R + 224 : (f[i++] = 198, R & 1 ? _(15 - R >> 1) : _(R - 16 >> 1));
return;
- } else if (L && !e.pack) {
- let R = L.get(a);
- R ? R.count++ : L.set(a, {
+ } else if (N && !e.pack) {
+ let b = N.get(a);
+ b ? b.count++ : N.set(a, {
count: 1
});
}
}
- let h = a.length;
- if (M && h >= 4 && h < 1024) {
- if ((M.size += h) > wr) {
- let R, O = (M[0] ? M[0].length * 3 + M[1].length : 0) + 10;
- i + O > oe && (f = J(i + O)), f[i++] = 217, f[i++] = 223, f[i++] = 249, f[i++] = M.position ? 132 : 130, f[i++] = 26, R = i - r, i += 4, M.position && dt(r, S), M = ["", ""], M.size = 0, M.position = R;
+ let p = a.length;
+ if ($ && p >= 4 && p < 1024) {
+ if (($.size += p) > _r) {
+ let b, O = ($[0] ? $[0].length * 3 + $[1].length : 0) + 10;
+ i + O > ae && (f = J(i + O)), f[i++] = 217, f[i++] = 223, f[i++] = 249, f[i++] = $.position ? 132 : 130, f[i++] = 26, b = i - r, i += 4, $.position && pt(r, _), $ = ["", ""], $.size = 0, $.position = b;
}
- let b = xr.test(a);
- M[b ? 0 : 1] += a, f[i++] = b ? 206 : 207, S(h);
+ let R = Rr.test(a);
+ $[R ? 0 : 1] += a, f[i++] = R ? 206 : 207, _(p);
return;
}
let u;
- h < 32 ? u = 1 : h < 256 ? u = 2 : h < 65536 ? u = 3 : u = 5;
- let m = h * 3;
- if (i + m > oe && (f = J(i + m)), h < 64 || !p) {
- let b, R, O, U = i + u;
- for (b = 0; b < h; b++)
- R = a.charCodeAt(b), R < 128 ? f[U++] = R : R < 2048 ? (f[U++] = R >> 6 | 192, f[U++] = R & 63 | 128) : (R & 64512) === 55296 && ((O = a.charCodeAt(b + 1)) & 64512) === 56320 ? (R = 65536 + ((R & 1023) << 10) + (O & 1023), b++, f[U++] = R >> 18 | 240, f[U++] = R >> 12 & 63 | 128, f[U++] = R >> 6 & 63 | 128, f[U++] = R & 63 | 128) : (f[U++] = R >> 12 | 224, f[U++] = R >> 6 & 63 | 128, f[U++] = R & 63 | 128);
+ p < 32 ? u = 1 : p < 256 ? u = 2 : p < 65536 ? u = 3 : u = 5;
+ let S = p * 3;
+ if (i + S > ae && (f = J(i + S)), p < 64 || !h) {
+ let R, b, O, U = i + u;
+ for (R = 0; R < p; R++)
+ b = a.charCodeAt(R), b < 128 ? f[U++] = b : b < 2048 ? (f[U++] = b >> 6 | 192, f[U++] = b & 63 | 128) : (b & 64512) === 55296 && ((O = a.charCodeAt(R + 1)) & 64512) === 56320 ? (b = 65536 + ((b & 1023) << 10) + (O & 1023), R++, f[U++] = b >> 18 | 240, f[U++] = b >> 12 & 63 | 128, f[U++] = b >> 6 & 63 | 128, f[U++] = b & 63 | 128) : (f[U++] = b >> 12 | 224, f[U++] = b >> 6 & 63 | 128, f[U++] = b & 63 | 128);
d = U - i - u;
} else
- d = p(a, i + u, m);
- d < 24 ? f[i++] = 96 | d : d < 256 ? (u < 2 && f.copyWithin(i + 2, i + 1, i + 1 + d), f[i++] = 120, f[i++] = d) : d < 65536 ? (u < 3 && f.copyWithin(i + 3, i + 2, i + 2 + d), f[i++] = 121, f[i++] = d >> 8, f[i++] = d & 255) : (u < 5 && f.copyWithin(i + 5, i + 3, i + 3 + d), f[i++] = 122, N.setUint32(i, d), i += 4), i += d;
- } else if (x === "number")
+ d = h(a, i + u, S);
+ d < 24 ? f[i++] = 96 | d : d < 256 ? (u < 2 && f.copyWithin(i + 2, i + 1, i + 1 + d), f[i++] = 120, f[i++] = d) : d < 65536 ? (u < 3 && f.copyWithin(i + 3, i + 2, i + 2 + d), f[i++] = 121, f[i++] = d >> 8, f[i++] = d & 255) : (u < 5 && f.copyWithin(i + 5, i + 3, i + 3 + d), f[i++] = 122, C.setUint32(i, d), i += 4), i += d;
+ } else if (w === "number")
if (!this.alwaysUseFloat && a >>> 0 === a)
- a < 24 ? f[i++] = a : a < 256 ? (f[i++] = 24, f[i++] = a) : a < 65536 ? (f[i++] = 25, f[i++] = a >> 8, f[i++] = a & 255) : (f[i++] = 26, N.setUint32(i, a), i += 4);
+ a < 24 ? f[i++] = a : a < 256 ? (f[i++] = 24, f[i++] = a) : a < 65536 ? (f[i++] = 25, f[i++] = a >> 8, f[i++] = a & 255) : (f[i++] = 26, C.setUint32(i, a), i += 4);
else if (!this.alwaysUseFloat && a >> 0 === a)
- a >= -24 ? f[i++] = 31 - a : a >= -256 ? (f[i++] = 56, f[i++] = ~a) : a >= -65536 ? (f[i++] = 57, N.setUint16(i, ~a), i += 2) : (f[i++] = 58, N.setUint32(i, ~a), i += 4);
+ a >= -24 ? f[i++] = 31 - a : a >= -256 ? (f[i++] = 56, f[i++] = ~a) : a >= -65536 ? (f[i++] = 57, C.setUint16(i, ~a), i += 2) : (f[i++] = 58, C.setUint32(i, ~a), i += 4);
else if (!this.alwaysUseFloat && a < 0 && a >= -4294967296 && Math.floor(a) === a)
- f[i++] = 58, N.setUint32(i, -1 - a), i += 4;
+ f[i++] = 58, C.setUint32(i, -1 - a), i += 4;
else {
- let h;
- if ((h = this.useFloat32) > 0 && a < 4294967296 && a >= -2147483648) {
- f[i++] = 250, N.setFloat32(i, a);
+ let p;
+ if ((p = this.useFloat32) > 0 && a < 4294967296 && a >= -2147483648) {
+ f[i++] = 250, C.setFloat32(i, a);
let u;
- if (h < 4 || // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
- (u = a * Je[(f[i] & 127) << 1 | f[i + 1] >> 7]) >> 0 === u) {
+ if (p < 4 || // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
+ (u = a * Ye[(f[i] & 127) << 1 | f[i + 1] >> 7]) >> 0 === u) {
i += 4;
return;
} else
i--;
}
- f[i++] = 251, N.setFloat64(i, a), i += 8;
+ f[i++] = 251, C.setFloat64(i, a), i += 8;
}
- else if (x === "object")
+ else if (w === "object")
if (!a)
f[i++] = 246;
else {
@@ -1289,34 +940,34 @@ class bt extends me {
let u = l.get(a);
if (u) {
if (f[i++] = 216, f[i++] = 29, f[i++] = 25, !u.references) {
- let m = l.idsToInsert || (l.idsToInsert = []);
- u.references = [], m.push(u);
+ let S = l.idsToInsert || (l.idsToInsert = []);
+ u.references = [], S.push(u);
}
u.references.push(i - r), i += 2;
return;
} else
l.set(a, { offset: i - r });
}
- let h = a.constructor;
- if (h === Object)
+ let p = a.constructor;
+ if (p === Object)
this.skipFunction === !0 && (a = Object.fromEntries([...Object.keys(a).filter((u) => typeof a[u] != "function").map((u) => [u, a[u]])])), X(a);
- else if (h === Array) {
+ else if (p === Array) {
d = a.length, d < 24 ? f[i++] = 128 | d : te(d);
for (let u = 0; u < d; u++)
- S(a[u]);
- } else if (h === Map)
- if ((this.mapsAsObjects ? this.useTag259ForMaps !== !1 : this.useTag259ForMaps) && (f[i++] = 217, f[i++] = 1, f[i++] = 3), d = a.size, d < 24 ? f[i++] = 160 | d : d < 256 ? (f[i++] = 184, f[i++] = d) : d < 65536 ? (f[i++] = 185, f[i++] = d >> 8, f[i++] = d & 255) : (f[i++] = 186, N.setUint32(i, d), i += 4), y.keyMap)
- for (let [u, m] of a)
- S(y.encodeKey(u)), S(m);
+ _(a[u]);
+ } else if (p === Map)
+ if ((this.mapsAsObjects ? this.useTag259ForMaps !== !1 : this.useTag259ForMaps) && (f[i++] = 217, f[i++] = 1, f[i++] = 3), d = a.size, d < 24 ? f[i++] = 160 | d : d < 256 ? (f[i++] = 184, f[i++] = d) : d < 65536 ? (f[i++] = 185, f[i++] = d >> 8, f[i++] = d & 255) : (f[i++] = 186, C.setUint32(i, d), i += 4), y.keyMap)
+ for (let [u, S] of a)
+ _(y.encodeKey(u)), _(S);
else
- for (let [u, m] of a)
- S(u), S(m);
+ for (let [u, S] of a)
+ _(u), _(S);
else {
- for (let u = 0, m = $e.length; u < m; u++) {
- let b = St[u];
- if (a instanceof b) {
- let R = $e[u], O = R.tag;
- O == null && (O = R.getTag && R.getTag.call(this, a)), O < 24 ? f[i++] = 192 | O : O < 256 ? (f[i++] = 216, f[i++] = O) : O < 65536 ? (f[i++] = 217, f[i++] = O >> 8, f[i++] = O & 255) : O > -1 && (f[i++] = 218, N.setUint32(i, O), i += 4), R.encode.call(this, a, S, J);
+ for (let u = 0, S = ve.length; u < S; u++) {
+ let R = Rt[u];
+ if (a instanceof R) {
+ let b = ve[u], O = b.tag;
+ O == null && (O = b.getTag && b.getTag.call(this, a)), O < 24 ? f[i++] = 192 | O : O < 256 ? (f[i++] = 216, f[i++] = O) : O < 65536 ? (f[i++] = 217, f[i++] = O >> 8, f[i++] = O & 255) : O > -1 && (f[i++] = 218, C.setUint32(i, O), i += 4), b.encode.call(this, a, _, J);
return;
}
}
@@ -1327,168 +978,168 @@ class bt extends me {
}
f[i++] = 159;
for (let u of a)
- S(u);
+ _(u);
f[i++] = 255;
return;
}
- if (a[Symbol.asyncIterator] || ke(a)) {
+ if (a[Symbol.asyncIterator] || De(a)) {
let u = new Error("Iterable/blob should be serialized as iterator");
throw u.iteratorNotHandled = !0, u;
}
if (this.useToJSON && a.toJSON) {
const u = a.toJSON();
if (u !== a)
- return S(u);
+ return _(u);
}
X(a);
}
}
- else if (x === "boolean")
+ else if (w === "boolean")
f[i++] = a ? 245 : 244;
- else if (x === "bigint") {
+ else if (w === "bigint") {
if (a < BigInt(1) << BigInt(64) && a >= 0)
- f[i++] = 27, N.setBigUint64(i, a);
+ f[i++] = 27, C.setBigUint64(i, a);
else if (a > -(BigInt(1) << BigInt(64)) && a < 0)
- f[i++] = 59, N.setBigUint64(i, -a - BigInt(1));
+ f[i++] = 59, C.setBigUint64(i, -a - BigInt(1));
else if (this.largeBigIntToFloat)
- f[i++] = 251, N.setFloat64(i, Number(a));
+ f[i++] = 251, C.setFloat64(i, Number(a));
else {
a >= BigInt(0) ? f[i++] = 194 : (f[i++] = 195, a = BigInt(-1) - a);
- let h = [];
+ let p = [];
for (; a; )
- h.push(Number(a & BigInt(255))), a >>= BigInt(8);
- ve(new Uint8Array(h.reverse()), J);
+ p.push(Number(a & BigInt(255))), a >>= BigInt(8);
+ Ve(new Uint8Array(p.reverse()), J);
return;
}
i += 8;
- } else if (x === "undefined")
+ } else if (w === "undefined")
f[i++] = 247;
else
- throw new Error("Unknown type: " + x);
+ throw new Error("Unknown type: " + w);
}, X = this.useRecords === !1 ? this.variableMapSize ? (a) => {
- let x = Object.keys(a), d = Object.values(a), h = x.length;
- if (h < 24 ? f[i++] = 160 | h : h < 256 ? (f[i++] = 184, f[i++] = h) : h < 65536 ? (f[i++] = 185, f[i++] = h >> 8, f[i++] = h & 255) : (f[i++] = 186, N.setUint32(i, h), i += 4), y.keyMap)
- for (let u = 0; u < h; u++)
- S(y.encodeKey(x[u])), S(d[u]);
+ let w = Object.keys(a), d = Object.values(a), p = w.length;
+ if (p < 24 ? f[i++] = 160 | p : p < 256 ? (f[i++] = 184, f[i++] = p) : p < 65536 ? (f[i++] = 185, f[i++] = p >> 8, f[i++] = p & 255) : (f[i++] = 186, C.setUint32(i, p), i += 4), y.keyMap)
+ for (let u = 0; u < p; u++)
+ _(y.encodeKey(w[u])), _(d[u]);
else
- for (let u = 0; u < h; u++)
- S(x[u]), S(d[u]);
+ for (let u = 0; u < p; u++)
+ _(w[u]), _(d[u]);
} : (a) => {
f[i++] = 185;
- let x = i - r;
+ let w = i - r;
i += 2;
let d = 0;
if (y.keyMap)
- for (let h in a) (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(h)) && (S(y.encodeKey(h)), S(a[h]), d++);
+ for (let p in a) (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(p)) && (_(y.encodeKey(p)), _(a[p]), d++);
else
- for (let h in a) (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(h)) && (S(h), S(a[h]), d++);
- f[x++ + r] = d >> 8, f[x + r] = d & 255;
- } : (a, x) => {
- let d, h = o.transitions || (o.transitions = /* @__PURE__ */ Object.create(null)), u = 0, m = 0, b, R;
+ for (let p in a) (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(p)) && (_(p), _(a[p]), d++);
+ f[w++ + r] = d >> 8, f[w + r] = d & 255;
+ } : (a, w) => {
+ let d, p = o.transitions || (o.transitions = /* @__PURE__ */ Object.create(null)), u = 0, S = 0, R, b;
if (this.keyMap) {
- R = Object.keys(a).map((U) => this.encodeKey(U)), m = R.length;
- for (let U = 0; U < m; U++) {
- let rt = R[U];
- d = h[rt], d || (d = h[rt] = /* @__PURE__ */ Object.create(null), u++), h = d;
+ b = Object.keys(a).map((U) => this.encodeKey(U)), S = b.length;
+ for (let U = 0; U < S; U++) {
+ let st = b[U];
+ d = p[st], d || (d = p[st] = /* @__PURE__ */ Object.create(null), u++), p = d;
}
} else
- for (let U in a) (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(U)) && (d = h[U], d || (h[Q] & 1048576 && (b = h[Q] & 65535), d = h[U] = /* @__PURE__ */ Object.create(null), u++), h = d, m++);
- let O = h[Q];
+ for (let U in a) (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(U)) && (d = p[U], d || (p[Q] & 1048576 && (R = p[Q] & 65535), d = p[U] = /* @__PURE__ */ Object.create(null), u++), p = d, S++);
+ let O = p[Q];
if (O !== void 0)
O &= 65535, f[i++] = 217, f[i++] = O >> 8 | 224, f[i++] = O & 255;
- else if (R || (R = h.__keys__ || (h.__keys__ = Object.keys(a))), b === void 0 ? (O = o.nextId++, O || (O = 0, o.nextId = 1), O >= lt && (o.nextId = (O = g) + 1)) : O = b, o[O] = R, O < g) {
- f[i++] = 217, f[i++] = O >> 8 | 224, f[i++] = O & 255, h = o.transitions;
- for (let U = 0; U < m; U++)
- (h[Q] === void 0 || h[Q] & 1048576) && (h[Q] = O), h = h[R[U]];
- h[Q] = O | 1048576, s = !0;
+ else if (b || (b = p.__keys__ || (p.__keys__ = Object.keys(a))), R === void 0 ? (O = o.nextId++, O || (O = 0, o.nextId = 1), O >= ut && (o.nextId = (O = g) + 1)) : O = R, o[O] = b, O < g) {
+ f[i++] = 217, f[i++] = O >> 8 | 224, f[i++] = O & 255, p = o.transitions;
+ for (let U = 0; U < S; U++)
+ (p[Q] === void 0 || p[Q] & 1048576) && (p[Q] = O), p = p[b[U]];
+ p[Q] = O | 1048576, s = !0;
} else {
- if (h[Q] = O, N.setUint32(i, 3655335680), i += 3, u && (re += I * u), q.length >= lt - g && (q.shift()[Q] = void 0), q.push(h), te(m + 2), S(57344 + O), S(R), x) return;
+ if (p[Q] = O, C.setUint32(i, 3655335680), i += 3, u && (ne += I * u), M.length >= ut - g && (M.shift()[Q] = void 0), M.push(p), te(S + 2), _(57344 + O), _(b), w) return;
for (let U in a)
- (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(U)) && S(a[U]);
+ (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(U)) && _(a[U]);
return;
}
- if (m < 24 ? f[i++] = 128 | m : te(m), !x)
+ if (S < 24 ? f[i++] = 128 | S : te(S), !w)
for (let U in a)
- (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(U)) && S(a[U]);
+ (typeof a.hasOwnProperty != "function" || a.hasOwnProperty(U)) && _(a[U]);
}, J = (a) => {
- let x;
+ let w;
if (a > 16777216) {
- if (a - r > ct)
+ if (a - r > dt)
throw new Error("Encoded buffer would be larger than maximum buffer size");
- x = Math.min(
- ct,
+ w = Math.min(
+ dt,
Math.round(Math.max((a - r) * (a > 67108864 ? 1.25 : 2), 4194304) / 4096) * 4096
);
} else
- x = (Math.max(a - r << 2, f.length - 1) >> 12) + 1 << 12;
- let d = new Ce(x);
- return N = new DataView(d.buffer, 0, x), f.copy ? f.copy(d, 0, r, a) : d.set(f.slice(r, a)), i -= r, r = 0, oe = d.length - 10, f = d;
+ w = (Math.max(a - r << 2, f.length - 1) >> 12) + 1 << 12;
+ let d = new Le(w);
+ return C = new DataView(d.buffer, 0, w), f.copy ? f.copy(d, 0, r, a) : d.set(f.slice(r, a)), i -= r, r = 0, ae = d.length - 10, f = d;
};
- let v = 100, ae = 1e3;
- this.encodeAsIterable = function(a, x) {
- return be(a, x, ne);
- }, this.encodeAsAsyncIterable = function(a, x) {
- return be(a, x, _e);
+ let V = 100, fe = 1e3;
+ this.encodeAsIterable = function(a, w) {
+ return Re(a, w, se);
+ }, this.encodeAsAsyncIterable = function(a, w) {
+ return Re(a, w, be);
};
- function* ne(a, x, d) {
- let h = a.constructor;
- if (h === Object) {
+ function* se(a, w, d) {
+ let p = a.constructor;
+ if (p === Object) {
let u = y.useRecords !== !1;
- u ? X(a, !0) : ut(Object.keys(a).length, 160);
- for (let m in a) {
- let b = a[m];
- u || S(m), b && typeof b == "object" ? x[m] ? yield* ne(b, x[m]) : yield* ue(b, x, m) : S(b);
+ u ? X(a, !0) : ht(Object.keys(a).length, 160);
+ for (let S in a) {
+ let R = a[S];
+ u || _(S), R && typeof R == "object" ? w[S] ? yield* se(R, w[S]) : yield* de(R, w, S) : _(R);
}
- } else if (h === Array) {
+ } else if (p === Array) {
let u = a.length;
te(u);
- for (let m = 0; m < u; m++) {
- let b = a[m];
- b && (typeof b == "object" || i - r > v) ? x.element ? yield* ne(b, x.element) : yield* ue(b, x, "element") : S(b);
+ for (let S = 0; S < u; S++) {
+ let R = a[S];
+ R && (typeof R == "object" || i - r > V) ? w.element ? yield* se(R, w.element) : yield* de(R, w, "element") : _(R);
}
} else if (a[Symbol.iterator] && !a.buffer) {
f[i++] = 159;
for (let u of a)
- u && (typeof u == "object" || i - r > v) ? x.element ? yield* ne(u, x.element) : yield* ue(u, x, "element") : S(u);
+ u && (typeof u == "object" || i - r > V) ? w.element ? yield* se(u, w.element) : yield* de(u, w, "element") : _(u);
f[i++] = 255;
- } else ke(a) ? (ut(a.size, 64), yield f.subarray(r, i), yield a, se()) : a[Symbol.asyncIterator] ? (f[i++] = 159, yield f.subarray(r, i), yield a, se(), f[i++] = 255) : S(a);
- d && i > r ? yield f.subarray(r, i) : i - r > v && (yield f.subarray(r, i), se());
+ } else De(a) ? (ht(a.size, 64), yield f.subarray(r, i), yield a, ie()) : a[Symbol.asyncIterator] ? (f[i++] = 159, yield f.subarray(r, i), yield a, ie(), f[i++] = 255) : _(a);
+ d && i > r ? yield f.subarray(r, i) : i - r > V && (yield f.subarray(r, i), ie());
}
- function* ue(a, x, d) {
- let h = i - r;
+ function* de(a, w, d) {
+ let p = i - r;
try {
- S(a), i - r > v && (yield f.subarray(r, i), se());
+ _(a), i - r > V && (yield f.subarray(r, i), ie());
} catch (u) {
if (u.iteratorNotHandled)
- x[d] = {}, i = r + h, yield* ne.call(this, a, x[d]);
+ w[d] = {}, i = r + p, yield* se.call(this, a, w[d]);
else throw u;
}
}
- function se() {
- v = ae, y.encode(null, De);
+ function ie() {
+ V = fe, y.encode(null, Fe);
}
- function be(a, x, d) {
- return x && x.chunkThreshold ? v = ae = x.chunkThreshold : v = 100, a && typeof a == "object" ? (y.encode(null, De), d(a, y.iterateProperties || (y.iterateProperties = {}), !0)) : [y.encode(a)];
+ function Re(a, w, d) {
+ return w && w.chunkThreshold ? V = fe = w.chunkThreshold : V = 100, a && typeof a == "object" ? (y.encode(null, Fe), d(a, y.iterateProperties || (y.iterateProperties = {}), !0)) : [y.encode(a)];
}
- async function* _e(a, x) {
- for (let d of ne(a, x, !0)) {
- let h = d.constructor;
- if (h === ft || h === Uint8Array)
+ async function* be(a, w) {
+ for (let d of se(a, w, !0)) {
+ let p = d.constructor;
+ if (p === ct || p === Uint8Array)
yield d;
- else if (ke(d)) {
- let u = d.stream().getReader(), m;
- for (; !(m = await u.read()).done; )
- yield m.value;
+ else if (De(d)) {
+ let u = d.stream().getReader(), S;
+ for (; !(S = await u.read()).done; )
+ yield S.value;
} else if (d[Symbol.asyncIterator])
for await (let u of d)
- se(), u ? yield* _e(u, x.async || (x.async = {})) : yield y.encode(u);
+ ie(), u ? yield* be(u, w.async || (w.async = {})) : yield y.encode(u);
else
yield d;
}
}
}
useBuffer(e) {
- f = e, N = new DataView(f.buffer, f.byteOffset, f.byteLength), i = 0;
+ f = e, C = new DataView(f.buffer, f.byteOffset, f.byteLength), i = 0;
}
clearSharedData() {
this.structures && (this.structures = []), this.sharedValues && (this.sharedValues = void 0);
@@ -1496,33 +1147,33 @@ class bt extends me {
updateSharedData() {
let e = this.sharedVersion || 0;
this.sharedVersion = e + 1;
- let r = this.structures.slice(0), n = new _t(r, this.sharedValues, this.sharedVersion), s = this.saveShared(
+ let r = this.structures.slice(0), n = new Ot(r, this.sharedValues, this.sharedVersion), s = this.saveShared(
n,
(o) => (o && o.version || 0) == e
);
return s === !1 ? (n = this.getShared() || {}, this.structures = n.structures || [], this.sharedValues = n.packedValues, this.sharedVersion = n.version, this.structures.nextId = this.structures.length) : r.forEach((o, l) => this.structures[l] = o), s;
}
}
-function ut(t, e) {
- t < 24 ? f[i++] = e | t : t < 256 ? (f[i++] = e | 24, f[i++] = t) : t < 65536 ? (f[i++] = e | 25, f[i++] = t >> 8, f[i++] = t & 255) : (f[i++] = e | 26, N.setUint32(i, t), i += 4);
+function ht(t, e) {
+ t < 24 ? f[i++] = e | t : t < 256 ? (f[i++] = e | 24, f[i++] = t) : t < 65536 ? (f[i++] = e | 25, f[i++] = t >> 8, f[i++] = t & 255) : (f[i++] = e | 26, C.setUint32(i, t), i += 4);
}
-class _t {
+class Ot {
constructor(e, r, n) {
this.structures = e, this.packedValues = r, this.version = n;
}
}
function te(t) {
- t < 24 ? f[i++] = 128 | t : t < 256 ? (f[i++] = 152, f[i++] = t) : t < 65536 ? (f[i++] = 153, f[i++] = t >> 8, f[i++] = t & 255) : (f[i++] = 154, N.setUint32(i, t), i += 4);
+ t < 24 ? f[i++] = 128 | t : t < 256 ? (f[i++] = 152, f[i++] = t) : t < 65536 ? (f[i++] = 153, f[i++] = t >> 8, f[i++] = t & 255) : (f[i++] = 154, C.setUint32(i, t), i += 4);
}
-const Er = typeof Blob > "u" ? function() {
+const br = typeof Blob > "u" ? function() {
} : Blob;
-function ke(t) {
- if (t instanceof Er)
+function De(t) {
+ if (t instanceof br)
return !0;
let e = t[Symbol.toStringTag];
return e === "Blob" || e === "File";
}
-function Ue(t, e) {
+function Pe(t, e) {
switch (typeof t) {
case "string":
if (t.length > 3) {
@@ -1545,24 +1196,24 @@ function Ue(t, e) {
if (t)
if (t instanceof Array)
for (let n = 0, s = t.length; n < s; n++)
- Ue(t[n], e);
+ Pe(t[n], e);
else {
let n = !e.encoder.useRecords;
for (var r in t)
- t.hasOwnProperty(r) && (n && Ue(r, e), Ue(t[r], e));
+ t.hasOwnProperty(r) && (n && Pe(r, e), Pe(t[r], e));
}
break;
case "function":
console.log(t);
}
}
-const gr = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1;
-St = [
+const Or = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1;
+Rt = [
Date,
Set,
Error,
RegExp,
- ce,
+ ue,
ArrayBuffer,
Uint8Array,
Uint8ClampedArray,
@@ -1577,15 +1228,15 @@ St = [
} : BigInt64Array,
Float32Array,
Float64Array,
- _t
+ Ot
];
-$e = [
+ve = [
{
// Date
tag: 1,
encode(t, e) {
let r = t.getTime() / 1e3;
- (this.useTimestamp32 || t.getMilliseconds() === 0) && r >= 0 && r < 4294967296 ? (f[i++] = 26, N.setUint32(i, r), i += 4) : (f[i++] = 251, N.setFloat64(i, r), i += 8);
+ (this.useTimestamp32 || t.getMilliseconds() === 0) && r >= 0 && r < 4294967296 ? (f[i++] = 26, C.setUint32(i, r), i += 4) : (f[i++] = 251, C.setFloat64(i, r), i += 8);
}
},
{
@@ -1625,17 +1276,17 @@ $e = [
{
// ArrayBuffer
encode(t, e, r) {
- ve(t, r);
+ Ve(t, r);
}
},
{
// Uint8Array
getTag(t) {
- if (t.constructor === Uint8Array && (this.tagUint8Array || Se && this.tagUint8Array !== !1))
+ if (t.constructor === Uint8Array && (this.tagUint8Array || _e && this.tagUint8Array !== !1))
return 64;
},
encode(t, e, r) {
- ve(t, r);
+ Ve(t, r);
}
},
ee(68, 1),
@@ -1659,293 +1310,746 @@ $e = [
packedObjectMap[s[o]] = o;
}
if (n) {
- N.setUint32(i, 3655335424), i += 3;
+ C.setUint32(i, 3655335424), i += 3;
let s = n.slice(0);
- s.unshift(57344), s.push(new ce(t.version, 1399353956)), e(s);
+ s.unshift(57344), s.push(new ue(t.version, 1399353956)), e(s);
} else
- e(new ce(t.version, 1399353956));
+ e(new ue(t.version, 1399353956));
+ }
+ }
+];
+function ee(t, e) {
+ return !Or && e > 1 && (t -= 4), {
+ tag: t,
+ encode: function(n, s) {
+ let o = n.byteLength, l = n.byteOffset || 0, h = n.buffer || n;
+ s(_e ? Ce.from(h, l, o) : new Uint8Array(h, l, o));
}
+ };
+}
+function Ve(t, e) {
+ let r = t.byteLength;
+ r < 24 ? f[i++] = 64 + r : r < 256 ? (f[i++] = 88, f[i++] = r) : r < 65536 ? (f[i++] = 89, f[i++] = r >> 8, f[i++] = r & 255) : (f[i++] = 90, C.setUint32(i, r), i += 4), i + r >= f.length && e(i + r), f.set(t.buffer ? t : new Uint8Array(t), i), i += r;
+}
+function Tr(t, e) {
+ let r, n = e.length * 2, s = t.length - n;
+ e.sort((o, l) => o.offset > l.offset ? 1 : -1);
+ for (let o = 0; o < e.length; o++) {
+ let l = e[o];
+ l.id = o;
+ for (let h of l.references)
+ t[h++] = o >> 8, t[h] = o & 255;
+ }
+ for (; r = e.pop(); ) {
+ let o = r.offset;
+ t.copyWithin(o + n, o, s), n -= 2;
+ let l = o + n;
+ t[l++] = 216, t[l++] = 28, s = o;
+ }
+ return t;
+}
+function pt(t, e) {
+ C.setUint32($.position + t, i - $.position - t + 1);
+ let r = $;
+ $ = null, e(r[0]), e(r[1]);
+}
+let et = new bt({ useRecords: !1 });
+const Ar = et.encode;
+et.encodeAsIterable;
+et.encodeAsAsyncIterable;
+const yt = 512, Ur = 1024, Fe = 2048, k = new bt({ tagUint8Array: !1 }), x = {
+ PUT_REQUEST: 1,
+ PUT_DATA: 2,
+ PUT_END: 3,
+ PUT_RESPONSE: 4,
+ GET_REQUEST: 5,
+ GET_RESPONSE_START: 6,
+ GET_DATA: 7,
+ GET_END: 8,
+ ERROR: 11,
+ AUTH_REQUEST: 12,
+ BLOCK_PUT_REQUEST: 13,
+ BLOCK_PUT_RESPONSE: 14,
+ BLOCK_GET_REQUEST: 15,
+ BLOCK_GET_RESPONSE: 16,
+ BLOCK_DELETE_REQUEST: 17,
+ BLOCK_DELETE_RESPONSE: 18,
+ HEALTH_REQUEST: 19,
+ HEALTH_RESPONSE: 20,
+ PEER_INFO_REQUEST: 21,
+ PEER_INFO_RESPONSE: 22,
+ PEER_CONNECT: 23,
+ PEER_CONNECT_RESULT: 24,
+ PEER_LIST_REQUEST: 25,
+ PEER_LIST_RESPONSE: 26,
+ FRIEND_ADD: 27,
+ FRIEND_REMOVE: 28,
+ FRIEND_LIST: 29,
+ FRIEND_LIST_RESPONSE: 30,
+ UPDATE_STATUS_REQUEST: 31,
+ UPDATE_STATUS_RESPONSE: 32,
+ CONFIG_SHOW_REQUEST: 33,
+ CONFIG_SHOW_RESPONSE: 34,
+ CONFIG_SET_REQUEST: 35,
+ CONFIG_SET_RESPONSE: 36,
+ CONFIG_RELOAD_REQUEST: 37,
+ CONFIG_RELOAD_RESPONSE: 38,
+ LOAD_REQUEST: 39,
+ LOAD_PROGRESS: 40,
+ LOAD_END: 41
+}, Pr = {
+ loaded: 0,
+ partial: 1,
+ failed: 2
+}, re = { cbor: 0, base58: 1, qrcode: 2 }, We = {
+ [re.cbor]: "application/cbor",
+ [re.base58]: "text/plain",
+ [re.qrcode]: "image/x-portable-pixmap"
+}, Nr = {
+ OK: 0,
+ BAD_REQUEST: 1,
+ NOT_FOUND: 2,
+ INTERNAL_ERROR: 3,
+ RANGE_NOT_SATISFIABLE: 4,
+ UNAUTHORIZED: 5
+};
+function tt(t) {
+ const e = j(t);
+ return Array.isArray(e) ? e[0] : null;
+}
+function rt(t) {
+ const e = new TextEncoder().encode(t);
+ return k.encode([x.AUTH_REQUEST, e]);
+}
+function ze(t, e = null) {
+ const r = t.recyclerUrls || [], n = [
+ x.PUT_REQUEST,
+ t.contentType,
+ t.fileName,
+ t.streamLength,
+ t.serverAddress || null,
+ e || new Uint8Array(0),
+ r,
+ t.temporary ? 1 : 0
+ ];
+ return t.tupleSize !== void 0 && n.push(t.tupleSize), k.encode(n);
+}
+function Tt(t) {
+ return k.encode([x.PUT_DATA, t]);
+}
+function At() {
+ return k.encode([x.PUT_END]);
+}
+function Qe(t) {
+ const e = j(t);
+ if (e[0] !== x.PUT_RESPONSE) throw new Error("Not a put response");
+ return { oriString: e[1] };
+}
+function Ut(t, e) {
+ const r = e && (e.start !== void 0 || e.end !== void 0), n = [x.GET_REQUEST, t, r ? 1 : 0];
+ return r && (n.push(e.start || 0), n.push(e.end || 0)), k.encode(n);
+}
+function Pt(t) {
+ const e = j(t);
+ if (e[0] !== x.GET_RESPONSE_START) throw new Error("Not a get response start");
+ return {
+ contentType: e[1],
+ contentLength: e[2],
+ hasRange: e[3] === 1,
+ rangeStart: e[3] ? e[4] : void 0,
+ rangeEnd: e[3] ? e[5] : void 0
+ };
+}
+function Nt(t) {
+ const e = j(t);
+ if (e[0] !== x.GET_DATA) throw new Error("Not a get data");
+ return e[1];
+}
+function Bt(t) {
+ const e = j(t);
+ return Array.isArray(e) && e[0] === x.GET_END;
+}
+function Ct(t, e) {
+ return e && (e.start !== void 0 || e.end !== void 0) ? k.encode([
+ x.LOAD_REQUEST,
+ t,
+ 1,
+ e.start || 0,
+ e.end || 0
+ ]) : k.encode([x.LOAD_REQUEST, t]);
+}
+function Lt(t) {
+ const e = j(t);
+ if (!(Array.isArray(e) && e[0] === x.LOAD_PROGRESS))
+ throw new Error("Not a load progress");
+ return { tuplesLoaded: e[1], tuplesTotal: e[2] };
+}
+function It(t) {
+ const e = j(t);
+ return Array.isArray(e) && e[0] === x.LOAD_END;
+}
+function Dt(t) {
+ const e = j(t);
+ if (!(Array.isArray(e) && e[0] === x.LOAD_END))
+ throw new Error("Not a load end");
+ return { status: e[1], tuplesLoaded: e[2], tuplesTotal: e[3] };
+}
+function Ft(t) {
+ const e = j(t);
+ return !Array.isArray(e) || e[0] !== x.ERROR ? null : { statusCode: e[1], message: e[2] };
+}
+function kt(t, e = 0) {
+ return k.encode([x.BLOCK_PUT_REQUEST, t, e]);
+}
+function Mt(t) {
+ const e = j(t);
+ if (e[0] !== x.BLOCK_PUT_RESPONSE) throw new Error("Not a block put response");
+ return { status: e[1], hash: e[2] };
+}
+function Ht(t) {
+ return k.encode([x.BLOCK_GET_REQUEST, t]);
+}
+function jt(t) {
+ const e = j(t);
+ if (e[0] !== x.BLOCK_GET_RESPONSE) throw new Error("Not a block get response");
+ return { status: e[1], data: e[2] };
+}
+function qt(t) {
+ return k.encode([x.BLOCK_DELETE_REQUEST, t]);
+}
+function $t(t) {
+ const e = j(t);
+ if (e[0] !== x.BLOCK_DELETE_RESPONSE) throw new Error("Not a block delete response");
+ return { status: e[1] };
+}
+function Gt() {
+ return k.encode([x.HEALTH_REQUEST]);
+}
+function Kt(t) {
+ const e = j(t);
+ if (e[0] !== x.HEALTH_RESPONSE) throw new Error("Not a health response");
+ return { json: e[1] };
+}
+function vt(t = 0) {
+ return t === 0 ? k.encode([x.PEER_INFO_REQUEST]) : k.encode([x.PEER_INFO_REQUEST, t]);
+}
+function Vt(t) {
+ const e = j(t);
+ if (e[0] !== x.PEER_INFO_RESPONSE) throw new Error("Not a peer info response");
+ return { format: e[1], data: e[2] };
+}
+function Wt(t, e) {
+ return k.encode([x.PEER_CONNECT, t, e]);
+}
+function zt(t) {
+ const e = j(t);
+ if (e[0] !== x.PEER_CONNECT_RESULT) throw new Error("Not a peer connect result");
+ return { status: e[1] };
+}
+function Qt() {
+ return k.encode([x.PEER_LIST_REQUEST]);
+}
+function Jt(t) {
+ const e = j(t);
+ if (e[0] !== x.PEER_LIST_RESPONSE) throw new Error("Not a peer list response");
+ return e[1];
+}
+function Zt(t, e) {
+ return k.encode([x.FRIEND_ADD, t, e]);
+}
+function Yt(t) {
+ return k.encode([x.FRIEND_REMOVE, t]);
+}
+function Xt() {
+ return k.encode([x.FRIEND_LIST]);
+}
+function er(t) {
+ const e = j(t);
+ if (e[0] !== x.FRIEND_LIST_RESPONSE) throw new Error("Not a friend list response");
+ return e[1];
+}
+function tr() {
+ return k.encode([x.CONFIG_SHOW_REQUEST]);
+}
+function rr(t) {
+ const e = j(t);
+ if (e[0] !== x.CONFIG_SHOW_RESPONSE) throw new Error("Not a config show response");
+ return { json: e[1] };
+}
+function nr(t, e) {
+ return k.encode([x.CONFIG_SET_REQUEST, t, e]);
+}
+function sr(t) {
+ const e = j(t);
+ if (e[0] !== x.CONFIG_SET_RESPONSE) throw new Error("Not a config set response");
+ return { status: e[1], restartRequired: e[2] === 1, message: e[3] };
+}
+function ir() {
+ return k.encode([x.CONFIG_RELOAD_REQUEST]);
+}
+function or(t) {
+ const e = j(t);
+ if (e[0] !== x.CONFIG_RELOAD_RESPONSE) throw new Error("Not a config reload response");
+ return { status: e[1], message: e[2] };
+}
+const Qr = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
+ __proto__: null,
+ LOAD_STATUS: Pr,
+ MSG: x,
+ PEER_CONTENT_TYPES: We,
+ PEER_FORMATS: re,
+ STATUS: Nr,
+ decodeBlockDeleteResponse: $t,
+ decodeBlockGetResponse: jt,
+ decodeBlockPutResponse: Mt,
+ decodeConfigReloadResponse: or,
+ decodeConfigSetResponse: sr,
+ decodeConfigShowResponse: rr,
+ decodeError: Ft,
+ decodeFriendListResponse: er,
+ decodeGetData: Nt,
+ decodeGetResponseStart: Pt,
+ decodeHealthResponse: Kt,
+ decodeLoadEnd: Dt,
+ decodeLoadProgress: Lt,
+ decodePeerConnectResult: zt,
+ decodePeerInfoResponse: Vt,
+ decodePeerListResponse: Jt,
+ decodePutResponse: Qe,
+ encodeAuthRequest: rt,
+ encodeBlockDeleteRequest: qt,
+ encodeBlockGetRequest: Ht,
+ encodeBlockPutRequest: kt,
+ encodeConfigReloadRequest: ir,
+ encodeConfigSetRequest: nr,
+ encodeConfigShowRequest: tr,
+ encodeFriendAdd: Zt,
+ encodeFriendListRequest: Xt,
+ encodeFriendRemove: Yt,
+ encodeGetRequest: Ut,
+ encodeHealthRequest: Gt,
+ encodeLoadRequest: Ct,
+ encodePeerConnect: Wt,
+ encodePeerInfoRequest: vt,
+ encodePeerListRequest: Qt,
+ encodePutData: Tt,
+ encodePutEnd: At,
+ encodePutRequest: ze,
+ getMessageType: tt,
+ isGetEnd: Bt,
+ isLoadEnd: It
+}, Symbol.toStringTag, { value: "Module" }));
+class D {
+ /**
+ * @param {string} url
+ * @param {string} [apiKey]
+ * @param {any} [_options]
+ */
+ constructor(e, r, n) {
+ /** @type {string} */
+ L(this, "baseUrl");
+ /** @type {string|undefined} */
+ L(this, "apiKey");
+ /** @type {AbortController|null} */
+ L(this, "abortController", null);
+ this.baseUrl = e.replace(/\/$/, ""), this.apiKey = r;
+ }
+ /**
+ * @returns {Promise}
+ */
+ async connect() {
+ this.abortController = new AbortController();
+ }
+ disconnect() {
+ this.abortController && (this.abortController.abort(), this.abortController = null);
+ }
+ isConnected() {
+ return this.abortController !== null;
+ }
+ /**
+ * @param {string} path
+ * @returns {string}
+ */
+ url(e) {
+ return `${this.baseUrl}${e}`;
+ }
+ /**
+ * @returns {Record}
+ */
+ authHeaders() {
+ const e = {};
+ return this.apiKey && (e.Authorization = `Bearer ${this.apiKey}`), e;
+ }
+ /**
+ * @param {(type: number, bytes: Uint8Array) => void} _handler
+ */
+ setMessageHandler(e) {
+ }
+ /**
+ * Send raw bytes — not used directly for HTTP; use the typed methods.
+ * @param {Uint8Array} _bytes
+ */
+ send(e) {
+ throw new Error("HttpTransport does not support raw send; use OffsClient methods");
+ }
+ /**
+ * Upload a file to PUT /offsystem.
+ * @param {import('../types.js').OffsPutOptions} options
+ * @param {ReadableStream|Uint8Array} body
+ * @returns {Promise<{oriString: string}>}
+ */
+ async put(e, r) {
+ var h, y;
+ const n = {
+ ...this.authHeaders(),
+ type: e.contentType,
+ "file-name": e.fileName,
+ "stream-length": String(e.streamLength)
+ };
+ e.serverAddress && (n["server-address"] = e.serverAddress), (h = e.recyclerUrls) != null && h.length && (n.recycler = JSON.stringify(e.recyclerUrls)), e.temporary && (n.temporary = "true"), e.tupleSize !== void 0 && (n["tuple-size"] = String(e.tupleSize));
+ let s = r;
+ r && typeof r.getReader == "function" && (s = await this._readStream(r));
+ const o = await fetch(this.url("/offsystem"), {
+ method: "PUT",
+ headers: n,
+ body: s,
+ signal: (y = this.abortController) == null ? void 0 : y.signal
+ });
+ if (!o.ok) {
+ const m = await o.text();
+ throw new Error(`Upload failed: ${o.status} ${m}`);
+ }
+ return { oriString: await o.text() };
+ }
+ /**
+ * Read a ReadableStream into a Uint8Array.
+ * The OFFS HTTP server is HTTP/1.1, so request streaming via duplex: 'half'
+ * causes ERR_ALPN_NEGOTIATION_FAILED. Buffering the body avoids that.
+ * @param {ReadableStream} stream
+ * @returns {Promise}
+ */
+ async _readStream(e) {
+ const r = e.getReader(), n = [];
+ let s = 0;
+ for (; ; ) {
+ const { done: h, value: y } = await r.read();
+ if (h) break;
+ n.push(y), s += y.length;
+ }
+ const o = new Uint8Array(s);
+ let l = 0;
+ for (const h of n)
+ o.set(h, l), l += h.length;
+ return o;
+ }
+ /**
+ * Download from GET /offsystem/v3/...
+ * @param {string} offUrl
+ * @param {import('../types.js').OffsGetCallbacks} callbacks
+ */
+ async get(e, r) {
+ var P, N, q, v, B, M, ne;
+ const n = await fetch(e, {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (P = this.abortController) == null ? void 0 : P.signal
+ });
+ if (!n.ok) {
+ const I = await n.text();
+ (N = r.onError) == null || N.call(r, n.status, I);
+ return;
+ }
+ const s = n.headers.get("content-type") || "application/octet-stream", o = parseInt(n.headers.get("content-length") || "0", 10), l = n.status === 206, h = n.headers.get("content-range");
+ let y, m;
+ if (h) {
+ const I = h.match(/bytes (\d+)-(\d+)\//);
+ I && (y = parseInt(I[1], 10), m = parseInt(I[2], 10));
+ }
+ (q = r.onStart) == null || q.call(r, s, o, l, y, m);
+ const g = (v = n.body) == null ? void 0 : v.getReader();
+ if (!g) {
+ (B = r.onEnd) == null || B.call(r);
+ return;
+ }
+ try {
+ for (; ; ) {
+ const { done: I, value: _ } = await g.read();
+ if (I) break;
+ _ && r.onData(_);
+ }
+ (M = r.onEnd) == null || M.call(r);
+ } catch (I) {
+ (ne = r.onError) == null || ne.call(r, 0, String(I));
+ }
+ }
+ /**
+ * Cache-only load: GET offUrl + '?load=1'. The daemon pulls the file's
+ * blocks into its block cache without serving file data and streams
+ * application/x-ndjson progress, one JSON object per line:
+ * {"tuples_loaded":n,"tuples_total":m} — per resolved tuple
+ * {"status":"loaded|partial|failed",...} — terminal line
+ * The terminal line is also reported through onEnd.
+ * @param {string} offUrl
+ * @param {import('../types.js').OffsGetCallbacks} callbacks
+ * @param {{start?: number, end?: number}} [range]
+ * @returns {Promise}
+ */
+ async load(e, r = {}, n) {
+ var m, g, P;
+ const s = e.includes("?") ? "&" : "?", o = await fetch(`${e}${s}load=1`, {
+ method: "GET",
+ headers: n ? { ...this.authHeaders(), Range: `bytes=${n.start || 0}-${n.end || 0}` } : this.authHeaders(),
+ signal: (m = this.abortController) == null ? void 0 : m.signal
+ });
+ if (!o.ok) {
+ const N = await o.text();
+ throw new Error(`Load failed: ${o.status} ${N}`);
+ }
+ const l = (g = o.body) == null ? void 0 : g.getReader();
+ if (!l) return;
+ const h = new TextDecoder();
+ let y = "";
+ try {
+ for (; ; ) {
+ const { done: q, value: v } = await l.read();
+ if (q) break;
+ y += h.decode(v, { stream: !0 });
+ let B;
+ for (; (B = y.indexOf(`
+`)) !== -1; ) {
+ const M = y.slice(0, B).trim();
+ y = y.slice(B + 1), M && this._handleLoadLine(M, r);
+ }
+ }
+ y += h.decode();
+ const N = y.trim();
+ N && this._handleLoadLine(N, r);
+ } catch (N) {
+ (P = r.onError) == null || P.call(r, 0, String(N));
+ }
+ }
+ /**
+ * Parse one ndjson progress/status line and dispatch to callbacks.
+ * @param {string} line
+ * @param {import('../types.js').OffsGetCallbacks} callbacks
+ */
+ _handleLoadLine(e, r) {
+ var s, o;
+ let n;
+ try {
+ n = JSON.parse(e);
+ } catch {
+ throw new Error(`Bad ndjson line: ${e}`);
+ }
+ n.status !== void 0 ? (s = r.onEnd) == null || s.call(r, n.status, n.tuples_loaded || 0, n.tuples_total || 0) : (o = r.onProgress) == null || o.call(r, n.tuples_loaded || 0, n.tuples_total || 0);
+ }
+ /**
+ * Delete content.
+ * @param {string} offUrl
+ * @returns {Promise}
+ */
+ async delete(e) {
+ var n;
+ const r = await fetch(e, {
+ method: "DELETE",
+ headers: this.authHeaders(),
+ signal: (n = this.abortController) == null ? void 0 : n.signal
+ });
+ if (!r.ok) {
+ const s = await r.text();
+ throw new Error(`Delete failed: ${r.status} ${s}`);
+ }
+ }
+ /**
+ * @param {Uint8Array} data
+ * @param {number} [encoding]
+ * @returns {Promise<{status: number, hash: Uint8Array|string}>}
+ */
+ async blockPut(e, r = 0) {
+ var l;
+ const n = r === 1 ? "?encoding=base58" : "", s = await fetch(this.url(`/blocks${n}`), {
+ method: "PUT",
+ headers: { ...this.authHeaders(), "Content-Type": "application/octet-stream" },
+ body: e,
+ signal: (l = this.abortController) == null ? void 0 : l.signal
+ });
+ if (!s.ok) {
+ const h = await s.text();
+ throw new Error(`Block put failed: ${s.status} ${h}`);
+ }
+ const o = await s.arrayBuffer();
+ return { status: 0, hash: new Uint8Array(o) };
+ }
+ /**
+ * @param {string} base58Hash
+ * @returns {Promise<{status: number, data: Uint8Array}>}
+ */
+ async blockGet(e) {
+ var s;
+ const r = await fetch(this.url(`/blocks/${e}`), {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (s = this.abortController) == null ? void 0 : s.signal
+ });
+ if (!r.ok)
+ return { status: 2, data: new Uint8Array(0) };
+ const n = await r.arrayBuffer();
+ return { status: 0, data: new Uint8Array(n) };
+ }
+ /**
+ * @param {string} base58Hash
+ * @returns {Promise<{status: number}>}
+ */
+ async blockDelete(e) {
+ var n;
+ return { status: (await fetch(this.url(`/blocks/${e}`), {
+ method: "DELETE",
+ headers: this.authHeaders(),
+ signal: (n = this.abortController) == null ? void 0 : n.signal
+ })).ok ? 0 : 2 };
+ }
+ /**
+ * @returns {Promise}
+ */
+ async health() {
+ var r;
+ const e = await fetch(this.url("/health"), {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (r = this.abortController) == null ? void 0 : r.signal
+ });
+ if (!e.ok)
+ throw new Error(`Health check failed: ${e.status}`);
+ return e.json();
+ }
+ /**
+ * @param {string} [format='cbor']
+ * @returns {Promise<{format: number, data: Uint8Array}>}
+ */
+ async peerInfo(e = "cbor") {
+ var o;
+ const r = re[e] ?? 0, n = await fetch(this.url(`/peer/info?format=${e}`), {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (o = this.abortController) == null ? void 0 : o.signal
+ });
+ if (!n.ok) throw new Error(`Peer info failed: ${n.status}`);
+ const s = await n.arrayBuffer();
+ return { format: r, data: new Uint8Array(s) };
+ }
+ /**
+ * @param {Uint8Array} peerInfo
+ * @param {number} [format=0]
+ * @returns {Promise<{status: number}>}
+ */
+ async peerConnect(e, r = 0) {
+ var s;
+ const n = await fetch(this.url("/peer/connect"), {
+ method: "POST",
+ headers: { ...this.authHeaders(), "Content-Type": We[r] ?? "application/cbor" },
+ body: r === re.base58 ? new TextDecoder().decode(e) : e,
+ signal: (s = this.abortController) == null ? void 0 : s.signal
+ });
+ if (!n.ok) throw new Error(`Peer connect failed: ${n.status}`);
+ return { status: 0 };
+ }
+ /**
+ * @returns {Promise}
+ */
+ async peerList() {
+ var r;
+ const e = await fetch(this.url("/peers"), {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (r = this.abortController) == null ? void 0 : r.signal
+ });
+ if (!e.ok) throw new Error(`Peer list failed: ${e.status}`);
+ return e.json();
}
-];
-function ee(t, e) {
- return !gr && e > 1 && (t -= 4), {
- tag: t,
- encode: function(n, s) {
- let o = n.byteLength, l = n.byteOffset || 0, p = n.buffer || n;
- s(Se ? Be.from(p, l, o) : new Uint8Array(p, l, o));
- }
- };
-}
-function ve(t, e) {
- let r = t.byteLength;
- r < 24 ? f[i++] = 64 + r : r < 256 ? (f[i++] = 88, f[i++] = r) : r < 65536 ? (f[i++] = 89, f[i++] = r >> 8, f[i++] = r & 255) : (f[i++] = 90, N.setUint32(i, r), i += 4), i + r >= f.length && e(i + r), f.set(t.buffer ? t : new Uint8Array(t), i), i += r;
-}
-function mr(t, e) {
- let r, n = e.length * 2, s = t.length - n;
- e.sort((o, l) => o.offset > l.offset ? 1 : -1);
- for (let o = 0; o < e.length; o++) {
- let l = e[o];
- l.id = o;
- for (let p of l.references)
- t[p++] = o >> 8, t[p] = o & 255;
+ /**
+ * @param {Uint8Array} peerInfo
+ * @param {number} [format=0]
+ * @returns {Promise}
+ */
+ async friendAdd(e, r = 0) {
+ var s;
+ const n = await fetch(this.url("/friends"), {
+ method: "POST",
+ headers: { ...this.authHeaders(), "Content-Type": We[r] ?? "application/cbor" },
+ body: r === re.base58 ? new TextDecoder().decode(e) : e,
+ signal: (s = this.abortController) == null ? void 0 : s.signal
+ });
+ if (!n.ok) throw new Error(`Friend add failed: ${n.status}`);
}
- for (; r = e.pop(); ) {
- let o = r.offset;
- t.copyWithin(o + n, o, s), n -= 2;
- let l = o + n;
- t[l++] = 216, t[l++] = 28, s = o;
+ /**
+ * @param {string} nodeId
+ * @returns {Promise}
+ */
+ async friendRemove(e) {
+ var n;
+ const r = await fetch(this.url(`/friends/${e}`), {
+ method: "DELETE",
+ headers: this.authHeaders(),
+ signal: (n = this.abortController) == null ? void 0 : n.signal
+ });
+ if (!r.ok) throw new Error(`Friend remove failed: ${r.status}`);
+ }
+ /**
+ * @returns {Promise}
+ */
+ async friendList() {
+ var r;
+ const e = await fetch(this.url("/friends"), {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (r = this.abortController) == null ? void 0 : r.signal
+ });
+ if (!e.ok) throw new Error(`Friend list failed: ${e.status}`);
+ return e.json();
+ }
+ /**
+ * @returns {Promise}
+ */
+ async configShow() {
+ var r;
+ const e = await fetch(this.url("/config"), {
+ method: "GET",
+ headers: this.authHeaders(),
+ signal: (r = this.abortController) == null ? void 0 : r.signal
+ });
+ if (!e.ok) throw new Error(`Config show failed: ${e.status}`);
+ return e.json();
+ }
+ /**
+ * @param {string} field
+ * @param {string} value
+ * @returns {Promise<{staged: any, rejected: any, restart_required: boolean}>}
+ */
+ async configSet(e, r) {
+ var s;
+ const n = await fetch(this.url("/config"), {
+ method: "PUT",
+ headers: { ...this.authHeaders(), "Content-Type": "application/json" },
+ body: JSON.stringify({ [e]: r }),
+ signal: (s = this.abortController) == null ? void 0 : s.signal
+ });
+ if (!n.ok) throw new Error(`Config set failed: ${n.status}`);
+ return n.json();
+ }
+ /**
+ * @returns {Promise}
+ */
+ async configReload() {
+ var r;
+ const e = await fetch(this.url("/config/restart"), {
+ method: "POST",
+ headers: this.authHeaders(),
+ signal: (r = this.abortController) == null ? void 0 : r.signal
+ });
+ if (!e.ok) throw new Error(`Config reload failed: ${e.status}`);
}
- return t;
-}
-function dt(t, e) {
- N.setUint32(M.position + t, i - M.position - t + 1);
- let r = M;
- M = null, e(r[0]), e(r[1]);
-}
-let Ye = new bt({ useRecords: !1 });
-const Sr = Ye.encode;
-Ye.encodeAsIterable;
-Ye.encodeAsAsyncIterable;
-const ht = 512, br = 1024, De = 2048, K = new bt({ tagUint8Array: !1 }), E = {
- PUT_REQUEST: 1,
- PUT_DATA: 2,
- PUT_END: 3,
- PUT_RESPONSE: 4,
- GET_REQUEST: 5,
- GET_RESPONSE_START: 6,
- GET_DATA: 7,
- GET_END: 8,
- ERROR: 11,
- AUTH_REQUEST: 12,
- BLOCK_PUT_REQUEST: 13,
- BLOCK_PUT_RESPONSE: 14,
- BLOCK_GET_REQUEST: 15,
- BLOCK_GET_RESPONSE: 16,
- BLOCK_DELETE_REQUEST: 17,
- BLOCK_DELETE_RESPONSE: 18,
- HEALTH_REQUEST: 19,
- HEALTH_RESPONSE: 20,
- PEER_INFO_REQUEST: 21,
- PEER_INFO_RESPONSE: 22,
- PEER_CONNECT: 23,
- PEER_CONNECT_RESULT: 24,
- PEER_LIST_REQUEST: 25,
- PEER_LIST_RESPONSE: 26,
- FRIEND_ADD: 27,
- FRIEND_REMOVE: 28,
- FRIEND_LIST: 29,
- FRIEND_LIST_RESPONSE: 30,
- UPDATE_STATUS_REQUEST: 31,
- UPDATE_STATUS_RESPONSE: 32,
- CONFIG_SHOW_REQUEST: 33,
- CONFIG_SHOW_RESPONSE: 34,
- CONFIG_SET_REQUEST: 35,
- CONFIG_SET_RESPONSE: 36,
- CONFIG_RELOAD_REQUEST: 37,
- CONFIG_RELOAD_RESPONSE: 38
-}, _r = {
- OK: 0,
- BAD_REQUEST: 1,
- NOT_FOUND: 2,
- INTERNAL_ERROR: 3,
- RANGE_NOT_SATISFIABLE: 4,
- UNAUTHORIZED: 5
-};
-function Xe(t) {
- const e = $(t);
- return Array.isArray(e) ? e[0] : null;
-}
-function et(t) {
- const e = new TextEncoder().encode(t);
- return K.encode([E.AUTH_REQUEST, e]);
-}
-function Ve(t, e = null) {
- const r = t.recyclerUrls || [], n = [
- E.PUT_REQUEST,
- t.contentType,
- t.fileName,
- t.streamLength,
- t.serverAddress || null,
- e || new Uint8Array(0),
- r,
- t.temporary ? 1 : 0
- ];
- return t.tupleSize !== void 0 && n.push(t.tupleSize), K.encode(n);
-}
-function Rt(t) {
- return K.encode([E.PUT_DATA, t]);
-}
-function Ot() {
- return K.encode([E.PUT_END]);
-}
-function We(t) {
- const e = $(t);
- if (e[0] !== E.PUT_RESPONSE) throw new Error("Not a put response");
- return { oriString: e[1] };
-}
-function Tt(t, e) {
- const r = e && (e.start !== void 0 || e.end !== void 0), n = [E.GET_REQUEST, t, r ? 1 : 0];
- return r && (n.push(e.start || 0), n.push(e.end || 0)), K.encode(n);
-}
-function At(t) {
- const e = $(t);
- if (e[0] !== E.GET_RESPONSE_START) throw new Error("Not a get response start");
- return {
- contentType: e[1],
- contentLength: e[2],
- hasRange: e[3] === 1,
- rangeStart: e[3] ? e[4] : void 0,
- rangeEnd: e[3] ? e[5] : void 0
- };
-}
-function Ut(t) {
- const e = $(t);
- if (e[0] !== E.GET_DATA) throw new Error("Not a get data");
- return e[1];
-}
-function Pt(t) {
- const e = $(t);
- return Array.isArray(e) && e[0] === E.GET_END;
-}
-function Nt(t) {
- const e = $(t);
- return !Array.isArray(e) || e[0] !== E.ERROR ? null : { statusCode: e[1], message: e[2] };
-}
-function Bt(t, e = 0) {
- return K.encode([E.BLOCK_PUT_REQUEST, t, e]);
-}
-function Ct(t) {
- const e = $(t);
- if (e[0] !== E.BLOCK_PUT_RESPONSE) throw new Error("Not a block put response");
- return { status: e[1], hash: e[2] };
-}
-function It(t) {
- return K.encode([E.BLOCK_GET_REQUEST, t]);
-}
-function kt(t) {
- const e = $(t);
- if (e[0] !== E.BLOCK_GET_RESPONSE) throw new Error("Not a block get response");
- return { status: e[1], data: e[2] };
-}
-function Dt(t) {
- return K.encode([E.BLOCK_DELETE_REQUEST, t]);
-}
-function Ft(t) {
- const e = $(t);
- if (e[0] !== E.BLOCK_DELETE_RESPONSE) throw new Error("Not a block delete response");
- return { status: e[1] };
-}
-function Lt() {
- return K.encode([E.HEALTH_REQUEST]);
-}
-function Mt(t) {
- const e = $(t);
- if (e[0] !== E.HEALTH_RESPONSE) throw new Error("Not a health response");
- return { json: e[1] };
-}
-function Ht() {
- return K.encode([E.PEER_INFO_REQUEST]);
-}
-function jt(t) {
- const e = $(t);
- if (e[0] !== E.PEER_INFO_RESPONSE) throw new Error("Not a peer info response");
- return { format: e[1], data: e[2] };
-}
-function Kt(t, e) {
- return K.encode([E.PEER_CONNECT, t, e]);
-}
-function Gt(t) {
- const e = $(t);
- if (e[0] !== E.PEER_CONNECT_RESULT) throw new Error("Not a peer connect result");
- return { status: e[1] };
-}
-function qt() {
- return K.encode([E.PEER_LIST_REQUEST]);
-}
-function $t(t) {
- const e = $(t);
- if (e[0] !== E.PEER_LIST_RESPONSE) throw new Error("Not a peer list response");
- return e[1];
-}
-function vt(t, e) {
- return K.encode([E.FRIEND_ADD, t, e]);
-}
-function Vt(t) {
- return K.encode([E.FRIEND_REMOVE, t]);
-}
-function Wt() {
- return K.encode([E.FRIEND_LIST]);
-}
-function zt(t) {
- const e = $(t);
- if (e[0] !== E.FRIEND_LIST_RESPONSE) throw new Error("Not a friend list response");
- return e[1];
-}
-function Qt() {
- return K.encode([E.CONFIG_SHOW_REQUEST]);
-}
-function Jt(t) {
- const e = $(t);
- if (e[0] !== E.CONFIG_SHOW_RESPONSE) throw new Error("Not a config show response");
- return { json: e[1] };
-}
-function Zt(t, e) {
- return K.encode([E.CONFIG_SET_REQUEST, t, e]);
-}
-function Yt(t) {
- const e = $(t);
- if (e[0] !== E.CONFIG_SET_RESPONSE) throw new Error("Not a config set response");
- return { status: e[1], restartRequired: e[2] === 1, message: e[3] };
-}
-function Xt() {
- return K.encode([E.CONFIG_RELOAD_REQUEST]);
-}
-function er(t) {
- const e = $(t);
- if (e[0] !== E.CONFIG_RELOAD_RESPONSE) throw new Error("Not a config reload response");
- return { status: e[1], message: e[2] };
}
-const Gr = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
- __proto__: null,
- MSG: E,
- STATUS: _r,
- decodeBlockDeleteResponse: Ft,
- decodeBlockGetResponse: kt,
- decodeBlockPutResponse: Ct,
- decodeConfigReloadResponse: er,
- decodeConfigSetResponse: Yt,
- decodeConfigShowResponse: Jt,
- decodeError: Nt,
- decodeFriendListResponse: zt,
- decodeGetData: Ut,
- decodeGetResponseStart: At,
- decodeHealthResponse: Mt,
- decodePeerConnectResult: Gt,
- decodePeerInfoResponse: jt,
- decodePeerListResponse: $t,
- decodePutResponse: We,
- encodeAuthRequest: et,
- encodeBlockDeleteRequest: Dt,
- encodeBlockGetRequest: It,
- encodeBlockPutRequest: Bt,
- encodeConfigReloadRequest: Xt,
- encodeConfigSetRequest: Zt,
- encodeConfigShowRequest: Qt,
- encodeFriendAdd: vt,
- encodeFriendListRequest: Wt,
- encodeFriendRemove: Vt,
- encodeGetRequest: Tt,
- encodeHealthRequest: Lt,
- encodePeerConnect: Kt,
- encodePeerInfoRequest: Ht,
- encodePeerListRequest: qt,
- encodePutData: Rt,
- encodePutEnd: Ot,
- encodePutRequest: Ve,
- getMessageType: Xe,
- isGetEnd: Pt
-}, Symbol.toStringTag, { value: "Module" }));
-class Rr {
+class Br {
/**
* @param {string} url
* @param {string} [apiKey]
@@ -1953,13 +2057,13 @@ class Rr {
*/
constructor(e, r, n) {
/** @type {WebSocket|null} */
- B(this, "socket", null);
+ L(this, "socket", null);
/** @type {string|undefined} */
- B(this, "apiKey");
+ L(this, "apiKey");
/** @type {((type: number, bytes: Uint8Array) => void)|null} */
- B(this, "messageHandler", null);
+ L(this, "messageHandler", null);
/** @type {Promise|null} */
- B(this, "openPromise", null);
+ L(this, "openPromise", null);
this.url = e, this.apiKey = r;
}
/**
@@ -1970,7 +2074,7 @@ class Rr {
const n = this.socket;
if (!n) return r(new Error("Socket not created"));
n.onopen = () => {
- this.apiKey && this.send(et(this.apiKey)), e();
+ this.apiKey && this.send(rt(this.apiKey)), e();
}, n.onerror = (s) => {
var l;
const o = s.message || ((l = s.error) == null ? void 0 : l.message) || "unknown";
@@ -1978,9 +2082,9 @@ class Rr {
}, n.onclose = () => {
this.socket = null, this.openPromise = null;
}, n.onmessage = (s) => {
- var p;
- const o = new Uint8Array(s.data), l = Xe(o);
- l !== null && ((p = this.messageHandler) == null || p.call(this, l, o));
+ var h;
+ const o = new Uint8Array(s.data), l = tt(o);
+ l !== null && ((h = this.messageHandler) == null || h.call(this, l, o));
};
}), this.openPromise);
}
@@ -2005,7 +2109,7 @@ class Rr {
this.messageHandler = e;
}
}
-class Or {
+class Cr {
/**
* @param {string} url
* @param {string} [apiKey]
@@ -2013,19 +2117,19 @@ class Or {
*/
constructor(e, r, n) {
/** @type {WebTransport|null} */
- B(this, "transport", null);
+ L(this, "transport", null);
/** @type {WritableStreamWriter|null} */
- B(this, "writer", null);
+ L(this, "writer", null);
/** @type {ReadableStreamReader|null} */
- B(this, "reader", null);
+ L(this, "reader", null);
/** @type {string|undefined} */
- B(this, "apiKey");
+ L(this, "apiKey");
/** @type {((type: number, bytes: Uint8Array) => void)|null} */
- B(this, "messageHandler", null);
+ L(this, "messageHandler", null);
/** @type {Promise|null} */
- B(this, "openPromise", null);
+ L(this, "openPromise", null);
/** @type {boolean} */
- B(this, "running", !1);
+ L(this, "running", !1);
this.url = e, this.apiKey = r;
}
/**
@@ -2034,7 +2138,7 @@ class Or {
async connect() {
return this.transport ? this.openPromise || Promise.resolve() : (this.transport = new WebTransport(this.url), this.openPromise = this.transport.ready.then(async () => {
const e = await this.transport.createBidirectionalStream();
- this.writer = e.writable.getWriter(), this.reader = e.readable.getReader(), this.running = !0, this._readLoop(), this.apiKey && await this.send(et(this.apiKey));
+ this.writer = e.writable.getWriter(), this.reader = e.readable.getReader(), this.running = !0, this._readLoop(), this.apiKey && await this.send(rt(this.apiKey));
}), this.openPromise);
}
disconnect() {
@@ -2066,25 +2170,25 @@ class Or {
const { done: n, value: s } = await this.reader.read();
if (n) break;
const o = s instanceof Uint8Array ? s : new Uint8Array(s.buffer, s.byteOffset, s.byteLength);
- for (e = e ? Tr(e, o) : o; e.length >= 4; ) {
- const p = new DataView(e.buffer, e.byteOffset, e.length).getUint32(0, !1);
- if (e.length < 4 + p) break;
- const y = e.subarray(4, 4 + p), _ = Xe(y);
- _ !== null && ((r = this.messageHandler) == null || r.call(this, _, y)), e = e.subarray(4 + p);
+ for (e = e ? Lr(e, o) : o; e.length >= 4; ) {
+ const h = new DataView(e.buffer, e.byteOffset, e.length).getUint32(0, !1);
+ if (e.length < 4 + h) break;
+ const y = e.subarray(4, 4 + h), m = tt(y);
+ m !== null && ((r = this.messageHandler) == null || r.call(this, m, y)), e = e.subarray(4 + h);
}
}
} catch {
}
}
}
-function Tr(t, e) {
+function Lr(t, e) {
const r = new Uint8Array(t.length + e.length);
return r.set(t, 0), r.set(e, t.length), r;
}
-const ze = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", tt = new Int8Array(128);
-tt.fill(-1);
-for (let t = 0; t < ze.length; t++)
- tt[ze.charCodeAt(t)] = t;
+const Je = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", nt = new Int8Array(128);
+nt.fill(-1);
+for (let t = 0; t < Je.length; t++)
+ nt[Je.charCodeAt(t)] = t;
function xe(t) {
if (t.length === 0) return null;
let e = 0;
@@ -2094,11 +2198,11 @@ function xe(t) {
for (let n = e; n < t.length; n++) {
const s = t.charCodeAt(n);
if (s >= 128) return null;
- const o = tt[s];
+ const o = nt[s];
if (o < 0) return null;
let l = o;
- for (let p = 0; p < r.length; p++)
- l += r[p] * 58, r[p] = l & 255, l >>= 8;
+ for (let h = 0; h < r.length; h++)
+ l += r[h] * 58, r[h] = l & 255, l >>= 8;
for (; l > 0; )
r.push(l & 255), l >>= 8;
}
@@ -2106,7 +2210,7 @@ function xe(t) {
r.push(0);
return r.reverse(), new Uint8Array(r);
}
-function Fe(t) {
+function ke(t) {
if (t.length === 0) return "";
const e = Array.from(t);
let r = 0;
@@ -2115,27 +2219,27 @@ function Fe(t) {
const n = [];
for (let o = r; o < e.length; o++) {
let l = e[o];
- for (let p = 0; p < n.length; p++)
- l += n[p] * 256, n[p] = l % 58, l = Math.floor(l / 58);
+ for (let h = 0; h < n.length; h++)
+ l += n[h] * 256, n[h] = l % 58, l = Math.floor(l / 58);
for (; l > 0; )
n.push(l % 58), l = Math.floor(l / 58);
}
- return "1".repeat(r) + n.reverse().map((o) => ze[o]).join("");
+ return "1".repeat(r) + n.reverse().map((o) => Je[o]).join("");
}
-function pt(t) {
+function Et(t) {
const e = t.indexOf("/offsystem/v3/");
if (e < 0) return null;
const n = t.slice(e + 14).split("/");
if (n.length < 4) return null;
- const s = n[n.length - 4], o = n[n.length - 3], l = n[n.length - 2], p = n.slice(n.length - 1).join("/"), y = parseInt(s, 10);
+ const s = n[n.length - 4], o = n[n.length - 3], l = n[n.length - 2], h = n.slice(n.length - 1).join("/"), y = parseInt(s, 10);
return !Number.isFinite(y) || xe(o) === null || xe(l) === null ? null : {
fileHashB58: o,
descriptorHashB58: l,
streamLength: y,
- fileName: decodeURIComponent(p)
+ fileName: decodeURIComponent(h)
};
}
-function Ar(t) {
+function Ir(t) {
const e = {
html: "text/html",
htm: "text/html",
@@ -2191,17 +2295,17 @@ function Ar(t) {
const n = t.slice(r + 1).toLowerCase();
return e[n] || "application/octet-stream";
}
-function Ur(t) {
+function Dr(t) {
return typeof t.arrayBuffer == "function" ? t.arrayBuffer().then((e) => new Uint8Array(e)) : new Promise((e, r) => {
const n = new FileReader();
n.onload = () => e(new Uint8Array(n.result)), n.onerror = () => r(n.error), n.readAsArrayBuffer(t);
});
}
-function Te(t) {
+function Ae(t) {
const r = t.replace(/\\\\/g, "/").split("/").filter(Boolean);
return r.length > 0 ? r[r.length - 1] : "file";
}
-function yt(t, e = 65536) {
+function wt(t, e = 65536) {
let r = 0;
return new ReadableStream({
pull(n) {
@@ -2210,13 +2314,13 @@ function yt(t, e = 65536) {
return;
}
const s = Math.min(r + e, t.size), o = t.slice(r, s);
- return Ur(o).then((l) => {
+ return Dr(o).then((l) => {
n.enqueue(l), r = s;
});
}
});
}
-function Pr(t) {
+function Fr(t) {
if (typeof FileList < "u" && t instanceof FileList) {
const e = [];
for (let r = 0; r < t.length; r++) {
@@ -2228,21 +2332,21 @@ function Pr(t) {
}
return Array.isArray(t) ? t.map((e) => e instanceof File || e instanceof Blob ? { path: e.webkitRelativePath || e.name, file: e } : { path: e.path, file: e.file }) : Object.entries(t).map(([e, r]) => ({ path: e, file: r }));
}
-function Nr(t, e = "http://localhost:23402") {
+function kr(t, e = "http://localhost:23402") {
if (!t || /^https?:\/\//i.test(t)) return t;
let r = t;
r.startsWith("offs://") && (r = r.slice(7));
const n = "/offsystem/v3/", s = r.indexOf(n);
return s >= 0 && (r = r.slice(s)), r.startsWith(n) ? `${e.replace(/\/$/, "")}${r}` : t;
}
-const Br = 128e3, Cr = 3;
-function Ir({
+const Mr = 128e3, Hr = 3;
+function jr({
name: t,
fileHash: e,
descriptorHash: r,
finalByte: n,
- blockType: s = Br,
- tupleSize: o = Cr,
+ blockType: s = Mr,
+ tupleSize: o = Hr,
fileOffset: l = 0
}) {
return {
@@ -2256,10 +2360,10 @@ function Ir({
fileOffset: l
};
}
-function kr({ name: t, dirHash: e }) {
+function qr({ name: t, dirHash: e }) {
return { name: t, isDirectory: !0, dirHash: e };
}
-function Dr(t) {
+function $r(t) {
const e = t.map((r) => {
const n = {
n: r.name,
@@ -2267,18 +2371,18 @@ function Dr(t) {
};
return r.isDirectory ? n.d = r.dirHash : (n.f = r.fileHash, n.D = r.descriptorHash, n.s = r.finalByte, n.B = r.blockType, n.T = r.tupleSize, n.o = r.fileOffset), n;
});
- return Sr({ v: 1, entries: e });
+ return Ar({ v: 1, entries: e });
}
-function Fr() {
+function Gr() {
return {
connectTimeoutMs: 5e3,
requestTimeoutMs: 3e4
};
}
-function Lr(t, e, r) {
- return t.startsWith("ws://") || t.startsWith("wss://") ? new Rr(t, e, r) : t.startsWith("wt://") || t.startsWith("wts://") ? new Or(t, e, r) : new D(t, e, r);
+function Kr(t, e, r) {
+ return t.startsWith("ws://") || t.startsWith("wss://") ? new Br(t, e, r) : t.startsWith("wt://") || t.startsWith("wts://") ? new Cr(t, e, r) : new D(t, e, r);
}
-class qr {
+class Jr {
/**
* @param {string} url
* @param {string} [apiKey]
@@ -2286,26 +2390,26 @@ class qr {
*/
constructor(e, r, n) {
/** @type {string} */
- B(this, "url");
+ L(this, "url");
/** @type {string|undefined} */
- B(this, "apiKey");
+ L(this, "apiKey");
/** @type {OffsClientConfig} */
- B(this, "config");
+ L(this, "config");
/** @type {HttpTransport|WsTransport|WtTransport} */
- B(this, "transport");
+ L(this, "transport");
/** @type {Map} */
- B(this, "pending", /* @__PURE__ */ new Map());
+ L(this, "pending", /* @__PURE__ */ new Map());
/** @type {{type: number, bytes: Uint8Array}[]} */
- B(this, "inboundQueue", []);
+ L(this, "inboundQueue", []);
/** @type {number} */
- B(this, "nextRequestId", 1);
+ L(this, "nextRequestId", 1);
/** @type {boolean} */
- B(this, "streamingPut", !1);
+ L(this, "streamingPut", !1);
/** @type {OffsPutOptions|null} */
- B(this, "streamOptions", null);
+ L(this, "streamOptions", null);
/** @type {boolean} */
- B(this, "connected", !1);
- this.url = e, this.apiKey = r, this.config = { ...Fr(), ...n }, this.transport = (n == null ? void 0 : n.transport) || Lr(e, r, n), this.transport.setMessageHandler(this._onMessage.bind(this));
+ L(this, "connected", !1);
+ this.url = e, this.apiKey = r, this.config = { ...Gr(), ...n }, this.transport = (n == null ? void 0 : n.transport) || Kr(e, r, n), this.transport.setMessageHandler(this._onMessage.bind(this));
}
/**
* @returns {Promise}
@@ -2372,8 +2476,8 @@ class qr {
* @param {Uint8Array} bytes
*/
_onMessage(e, r) {
- if (e === E.ERROR) {
- const n = Nt(r);
+ if (e === x.ERROR) {
+ const n = Ft(r);
if (n)
for (const s of this.pending.values())
this._reject(s.id, new Error(`Server error ${n.statusCode}: ${n.message}`));
@@ -2417,14 +2521,14 @@ class qr {
throw new Error("Use object options (contentType, fileName, streamLength)");
const n = {
...e,
- fileName: Te(e.fileName)
+ fileName: Ae(e.fileName)
};
if (this.transport instanceof D) {
const l = r || new Uint8Array(0);
return this.transport.put(n, l);
}
- const s = Ve(n, r), o = await this._sendAndWait(s, E.PUT_RESPONSE);
- return We(o);
+ const s = ze(n, r), o = await this._sendAndWait(s, x.PUT_RESPONSE);
+ return Qe(o);
}
/**
* @param {OffsPutOptions} options
@@ -2433,7 +2537,7 @@ class qr {
async putStreamStart(e) {
if (this.streamingPut = !0, this.streamOptions = e, this.transport instanceof D)
return;
- const r = Ve(e);
+ const r = ze(e);
await this.transport.send(r);
}
/**
@@ -2443,7 +2547,7 @@ class qr {
async putStreamData(e) {
if (this.transport instanceof D)
throw new Error("HTTP transport does not support putStreamData; use put with ReadableStream");
- await this.transport.send(Rt(e));
+ await this.transport.send(Tt(e));
}
/**
* @returns {Promise<{oriString: string}>}
@@ -2455,9 +2559,9 @@ class qr {
if (!e) throw new Error("No stream in progress");
return this.transport.put(e, new Uint8Array(0));
}
- await this.transport.send(Ot());
- const r = await this._request(this.nextRequestId - 1, E.PUT_RESPONSE);
- return We(r);
+ await this.transport.send(At());
+ const r = await this._request(this.nextRequestId - 1, x.PUT_RESPONSE);
+ return Qe(r);
}
/**
* @param {string} oriString
@@ -2465,18 +2569,56 @@ class qr {
* @param {{start?: number, end?: number}} [range]
*/
async get(e, r, n) {
- var p, y;
+ var h, y;
if (this.transport instanceof D)
return this.transport.get(e, r);
- const s = Tt(e, n), o = await this._sendAndWait(s, E.GET_RESPONSE_START), l = At(o);
- for ((p = r.onStart) == null || p.call(r, l.contentType, l.contentLength, l.hasRange, l.rangeStart, l.rangeEnd); ; ) {
- const _ = await this._waitForResponse([E.GET_DATA, E.GET_END]);
- if (Pt(_)) break;
- const g = Ut(_);
+ const s = Ut(e, n), o = await this._sendAndWait(s, x.GET_RESPONSE_START), l = Pt(o);
+ for ((h = r.onStart) == null || h.call(r, l.contentType, l.contentLength, l.hasRange, l.rangeStart, l.rangeEnd); ; ) {
+ const m = await this._waitForResponse([x.GET_DATA, x.GET_END]);
+ if (Bt(m)) break;
+ const g = Nt(m);
r.onData(g);
}
(y = r.onEnd) == null || y.call(r);
}
+ /**
+ * Load a file's blocks into the daemon's block cache without downloading
+ * the file data. Progress is reported per resolved tuple; the operation
+ * ends with a terminal status.
+ *
+ * HTTP transports stream an application/x-ndjson body whose progress lines
+ * are {"tuples_loaded":n,"tuples_total":m} objects and whose terminal line
+ * carries a status string ("loaded"|"partial"|"failed"). CBOR transports
+ * use LOAD_PROGRESS/LOAD_END frames whose status is numeric
+ * (0=loaded, 1=partial, 2=failed) — see wire.LOAD_STATUS.
+ *
+ * @param {string} oriString
+ * @param {Object} [callbacks]
+ * @param {(tuplesLoaded: number, tuplesTotal: number) => void} [callbacks.onProgress]
+ * @param {(status: string|number, tuplesLoaded: number, tuplesTotal: number) => void} [callbacks.onEnd]
+ * @param {(statusCode: number, message: string) => void} [callbacks.onError]
+ * @param {{start?: number, end?: number}} [range]
+ * @returns {Promise}
+ */
+ async load(e, r = {}, n) {
+ var h, y;
+ if (this.transport instanceof D)
+ return this.transport.load(e, r, n);
+ const s = Ct(e, n);
+ await this.transport.send(s);
+ let o = null;
+ for (; ; ) {
+ const m = await this._waitForResponse([x.LOAD_PROGRESS, x.LOAD_END]);
+ if (It(m)) {
+ o = m;
+ break;
+ }
+ const g = Lt(m);
+ (h = r.onProgress) == null || h.call(r, g.tuplesLoaded, g.tuplesTotal);
+ }
+ const l = Dt(o);
+ (y = r.onEnd) == null || y.call(r, l.status, l.tuplesLoaded, l.tuplesTotal);
+ }
/**
* @param {Uint8Array} data
* @param {number} [encoding=0]
@@ -2485,8 +2627,8 @@ class qr {
async blockPut(e, r = 0) {
if (this.transport instanceof D)
return this.transport.blockPut(e, r);
- const n = Bt(e, r), s = await this._sendAndWait(n, E.BLOCK_PUT_RESPONSE);
- return Ct(s);
+ const n = kt(e, r), s = await this._sendAndWait(n, x.BLOCK_PUT_RESPONSE);
+ return Mt(s);
}
/**
* @param {string|Uint8Array} hash
@@ -2495,9 +2637,9 @@ class qr {
async blockGet(e) {
if (typeof e == "string") return this.transport.blockGet(e);
if (this.transport instanceof D)
- return this.transport.blockGet(Fe(e));
- const r = It(e), n = await this._sendAndWait(r, E.BLOCK_GET_RESPONSE);
- return kt(n);
+ return this.transport.blockGet(ke(e));
+ const r = Ht(e), n = await this._sendAndWait(r, x.BLOCK_GET_RESPONSE);
+ return jt(n);
}
/**
* @param {string|Uint8Array} hash
@@ -2506,9 +2648,9 @@ class qr {
async blockDelete(e) {
if (typeof e == "string") return this.transport.blockDelete(e);
if (this.transport instanceof D)
- return this.transport.blockDelete(Fe(e));
- const r = Dt(e), n = await this._sendAndWait(r, E.BLOCK_DELETE_RESPONSE);
- return Ft(n);
+ return this.transport.blockDelete(ke(e));
+ const r = qt(e), n = await this._sendAndWait(r, x.BLOCK_DELETE_RESPONSE);
+ return $t(n);
}
/**
* @returns {Promise}
@@ -2516,7 +2658,7 @@ class qr {
async health() {
if (this.transport instanceof D)
return this.transport.health();
- const e = Lt(), r = await this._sendAndWait(e, E.HEALTH_RESPONSE), { json: n } = Mt(r);
+ const e = Gt(), r = await this._sendAndWait(e, x.HEALTH_RESPONSE), { json: n } = Kt(r);
return JSON.parse(n);
}
/**
@@ -2526,8 +2668,8 @@ class qr {
async peerInfo(e = "cbor") {
if (this.transport instanceof D)
return this.transport.peerInfo(e);
- const r = Ht(), n = await this._sendAndWait(r, E.PEER_INFO_RESPONSE);
- return jt(n);
+ const r = vt(re[e] ?? 0), n = await this._sendAndWait(r, x.PEER_INFO_RESPONSE);
+ return Vt(n);
}
/**
* @param {Uint8Array} peerInfo
@@ -2537,8 +2679,24 @@ class qr {
async peerConnect(e, r = 0) {
if (this.transport instanceof D)
return this.transport.peerConnect(e, r);
- const n = Kt(r, e), s = await this._sendAndWait(n, E.PEER_CONNECT_RESULT);
- return Gt(s);
+ const n = Wt(r, e), s = await this._sendAndWait(n, x.PEER_CONNECT_RESULT);
+ return zt(s);
+ }
+ /**
+ * Connect to a peer from a QR image (binary P6 PPM bytes).
+ * @param {Uint8Array} ppmBytes
+ * @returns {Promise<{status: number}>}
+ */
+ async peerConnectQr(e) {
+ return this.peerConnect(e, re.qrcode);
+ }
+ /**
+ * Add a friend from a QR image (binary P6 PPM bytes).
+ * @param {Uint8Array} ppmBytes
+ * @returns {Promise}
+ */
+ async friendAddQr(e) {
+ return this.friendAdd(e, re.qrcode);
}
/**
* Convert an OFF URL/URI string into an HTTP URL usable by a browser.
@@ -2547,7 +2705,7 @@ class qr {
* @returns {string}
*/
static offUrlToHttpUrl(e, r) {
- return Nr(e, r);
+ return kr(e, r);
}
/**
* @returns {Promise}
@@ -2555,8 +2713,8 @@ class qr {
async peerList() {
if (this.transport instanceof D)
return this.transport.peerList();
- const e = qt(), r = await this._sendAndWait(e, E.PEER_LIST_RESPONSE);
- return $t(r);
+ const e = Qt(), r = await this._sendAndWait(e, x.PEER_LIST_RESPONSE);
+ return Jt(r);
}
/**
* @param {Uint8Array} peerInfo
@@ -2566,7 +2724,7 @@ class qr {
async friendAdd(e, r = 0) {
if (this.transport instanceof D)
return this.transport.friendAdd(e, r);
- const n = vt(r, e);
+ const n = Zt(r, e);
await this.transport.send(n);
}
/**
@@ -2575,8 +2733,8 @@ class qr {
*/
async friendRemove(e) {
if (this.transport instanceof D)
- return this.transport.friendRemove(typeof e == "string" ? e : Fe(e));
- const r = typeof e == "string" ? new TextEncoder().encode(e) : e, n = Vt(r);
+ return this.transport.friendRemove(typeof e == "string" ? e : ke(e));
+ const r = typeof e == "string" ? new TextEncoder().encode(e) : e, n = Yt(r);
await this.transport.send(n);
}
/**
@@ -2585,8 +2743,8 @@ class qr {
async friendList() {
if (this.transport instanceof D)
return this.transport.friendList();
- const e = Wt(), r = await this._sendAndWait(e, E.FRIEND_LIST_RESPONSE);
- return zt(r);
+ const e = Xt(), r = await this._sendAndWait(e, x.FRIEND_LIST_RESPONSE);
+ return er(r);
}
/**
* @returns {Promise}
@@ -2594,7 +2752,7 @@ class qr {
async configShow() {
if (this.transport instanceof D)
return this.transport.configShow();
- const e = Qt(), r = await this._sendAndWait(e, E.CONFIG_SHOW_RESPONSE), { json: n } = Jt(r);
+ const e = tr(), r = await this._sendAndWait(e, x.CONFIG_SHOW_RESPONSE), { json: n } = rr(r);
return JSON.parse(n);
}
/**
@@ -2605,8 +2763,8 @@ class qr {
async configSet(e, r) {
if (this.transport instanceof D)
return this.transport.configSet(e, r);
- const n = Zt(e, r), s = await this._sendAndWait(n, E.CONFIG_SET_RESPONSE);
- return Yt(s);
+ const n = nr(e, r), s = await this._sendAndWait(n, x.CONFIG_SET_RESPONSE);
+ return sr(s);
}
/**
* @returns {Promise<{status: number, message: string}>}
@@ -2614,8 +2772,8 @@ class qr {
async configReload() {
if (this.transport instanceof D)
return this.transport.configReload();
- const e = Xt(), r = await this._sendAndWait(e, E.CONFIG_RELOAD_RESPONSE);
- return er(r);
+ const e = ir(), r = await this._sendAndWait(e, x.CONFIG_RELOAD_RESPONSE);
+ return or(r);
}
/**
* Upload a folder recursively and return the root directory's ORI URL.
@@ -2631,108 +2789,108 @@ class qr {
* @returns {Promise<{oriString: string}>}
*/
async putFolder(e, r = {}) {
- const n = Pr(e);
+ const n = Fr(e);
if (n.length === 0)
throw new Error("No files to upload");
const s = r.recyclerUrls || [], o = n.length;
let l = 0;
- const p = (g) => {
+ const h = (g) => {
var P;
l++, (P = r.onProgress) == null || P.call(r, g, l, o);
- }, y = Mr(n.map((g) => g.path)), _ = async (g) => {
- const P = Te(g || y || "root"), G = Hr(n, g), V = jr(n, g), C = [];
- for (const I of V) {
- const X = (await _(I)).oriString, J = pt(X);
+ }, y = vr(n.map((g) => g.path)), m = async (g) => {
+ const P = Ae(g || y || "root"), q = Vr(n, g), v = Wr(n, g), B = [];
+ for (const I of v) {
+ const X = (await m(I)).oriString, J = Et(X);
if (!J)
throw new Error(`Failed to parse subdirectory URL: ${X}`);
- const v = xe(J.fileHashB58);
- if (!v)
+ const V = xe(J.fileHashB58);
+ if (!V)
throw new Error(`Invalid directory hash in URL: ${X}`);
- C.push(kr({
- name: Te(I),
- dirHash: v
+ B.push(qr({
+ name: Ae(I),
+ dirHash: V
}));
}
- for (const I of G) {
- const S = Te(I.path), X = Ar(S), J = I.file.size;
- let v;
+ for (const I of q) {
+ const _ = Ae(I.path), X = Ir(_), J = I.file.size;
+ let V;
if (this.transport instanceof D) {
- const se = yt(I.file);
- v = (await this.put({
+ const ie = wt(I.file);
+ V = (await this.put({
contentType: X,
- fileName: S,
+ fileName: _,
streamLength: J,
serverAddress: r.serverAddress,
recyclerUrls: s,
temporary: r.temporary
- }, se)).oriString;
+ }, ie)).oriString;
} else {
await this.putStreamStart({
contentType: X,
- fileName: S,
+ fileName: _,
streamLength: J,
serverAddress: r.serverAddress,
recyclerUrls: s,
temporary: r.temporary
});
- const se = yt(I.file).getReader();
+ const ie = wt(I.file).getReader();
for (; ; ) {
- const { done: _e, value: a } = await se.read();
- if (_e) break;
+ const { done: be, value: a } = await ie.read();
+ if (be) break;
await this.putStreamData(a);
}
- v = (await this.putStreamEnd()).oriString;
+ V = (await this.putStreamEnd()).oriString;
}
- const ae = pt(v);
- if (!ae)
- throw new Error(`Failed to parse file URL: ${v}`);
- const ne = xe(ae.fileHashB58), ue = xe(ae.descriptorHashB58);
- if (!ne || !ue)
- throw new Error(`Invalid hash in file URL: ${v}`);
- C.push(Ir({
- name: S,
- fileHash: ne,
- descriptorHash: ue,
- finalByte: ae.streamLength
- })), p(S);
+ const fe = Et(V);
+ if (!fe)
+ throw new Error(`Failed to parse file URL: ${V}`);
+ const se = xe(fe.fileHashB58), de = xe(fe.descriptorHashB58);
+ if (!se || !de)
+ throw new Error(`Invalid hash in file URL: ${V}`);
+ B.push(jr({
+ name: _,
+ fileHash: se,
+ descriptorHash: de,
+ finalByte: fe.streamLength
+ })), h(_);
}
- if (C.length === 0)
+ if (B.length === 0)
throw new Error(`Empty directory: ${g || y}`);
- const q = Dr(C), re = `${P}.ofd`;
+ const M = $r(B), ne = `${P}.ofd`;
return this.transport instanceof D ? this.put({
contentType: "offsystem/directory",
- fileName: re,
- streamLength: q.length,
+ fileName: ne,
+ streamLength: M.length,
serverAddress: r.serverAddress,
recyclerUrls: s,
temporary: r.temporary
- }, q) : (await this.putStreamStart({
+ }, M) : (await this.putStreamStart({
contentType: "offsystem/directory",
- fileName: re,
- streamLength: q.length,
+ fileName: ne,
+ streamLength: M.length,
serverAddress: r.serverAddress,
recyclerUrls: s,
temporary: r.temporary
- }), await this.putStreamData(q), this.putStreamEnd());
+ }), await this.putStreamData(M), this.putStreamEnd());
};
- return _(y);
+ return m(y);
}
}
-function Mr(t) {
+function vr(t) {
if (t.length === 0) return "";
const e = t.map((o) => o.split("/").filter(Boolean)), r = e[0];
let n = r.length;
for (let o = 1; o < e.length; o++) {
const l = e[o];
- let p = 0;
- for (; p < Math.min(n, l.length) && r[p] === l[p]; )
- p++;
- if (n = p, n === 0) break;
+ let h = 0;
+ for (; h < Math.min(n, l.length) && r[h] === l[h]; )
+ h++;
+ if (n = h, n === 0) break;
}
const s = Math.min(n, r.length - 1);
return r.slice(0, s).join("/");
}
-function Hr(t, e) {
+function Vr(t, e) {
const r = e ? `${e}/` : "";
return t.filter((n) => {
if (!n.path.startsWith(r)) return !1;
@@ -2740,7 +2898,7 @@ function Hr(t, e) {
return s.length > 0 && !s.includes("/");
});
}
-function jr(t, e) {
+function Wr(t, e) {
const r = e ? `${e}/` : "", n = /* @__PURE__ */ new Set();
for (const s of t) {
if (!s.path.startsWith(r)) continue;
@@ -2751,15 +2909,15 @@ function jr(t, e) {
}
return Array.from(n);
}
-var Le = globalThis.OffsClient;
-Le && Le.OffsClient && (globalThis.OffsClient = Le.OffsClient);
+var Me = globalThis.OffsClient;
+Me && Me.OffsClient && (globalThis.OffsClient = Me.OffsClient);
export {
- qr as OffsClient,
+ Jr as OffsClient,
xe as base58Decode,
- Fe as base58Encode,
- Ar as mimeFromExtension,
- Nr as offUrlToHttpUrl,
- pt as parseOffUrl,
- Gr as wire
+ ke as base58Encode,
+ Ir as mimeFromExtension,
+ kr as offUrlToHttpUrl,
+ Et as parseOffUrl,
+ Qr as wire
};
//# sourceMappingURL=offs-client.esm.js.map
diff --git a/src/ClientLibs/js/offs-client/dist/offs-client.esm.js.map b/src/ClientLibs/js/offs-client/dist/offs-client.esm.js.map
index cdaafd42..4f552759 100644
--- a/src/ClientLibs/js/offs-client/dist/offs-client.esm.js.map
+++ b/src/ClientLibs/js/offs-client/dist/offs-client.esm.js.map
@@ -1 +1 @@
-{"version":3,"file":"offs-client.esm.js","sources":["../src/transports/http-transport.js","../node_modules/cbor-x/decode.js","../node_modules/cbor-x/encode.js","../src/wire.js","../src/transports/ws-transport.js","../src/transports/wt-transport.js","../src/util.js","../src/ofd.js","../src/index.js"],"sourcesContent":["\n/**\n * HTTP REST transport for the OFFS client.\n * Maps wire messages to the HTTP routes in src/ClientAPI/HTTP/.\n */\nexport class HttpTransport {\n /** @type {string} */\n baseUrl;\n /** @type {string|undefined} */\n apiKey;\n /** @type {AbortController|null} */\n abortController = null;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [_options]\n */\n constructor(url, apiKey, _options) {\n this.baseUrl = url.replace(/\\/$/, '');\n this.apiKey = apiKey;\n }\n\n /**\n * @returns {Promise}\n */\n async connect() {\n this.abortController = new AbortController();\n }\n\n disconnect() {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n isConnected() {\n return this.abortController !== null;\n }\n\n /**\n * @param {string} path\n * @returns {string}\n */\n url(path) {\n return `${this.baseUrl}${path}`;\n }\n\n /**\n * @returns {Record}\n */\n authHeaders() {\n const headers = {};\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return headers;\n }\n\n /**\n * @param {(type: number, bytes: Uint8Array) => void} _handler\n */\n setMessageHandler(_handler) {\n // HTTP is request/response; no async messages.\n }\n\n /**\n * Send raw bytes — not used directly for HTTP; use the typed methods.\n * @param {Uint8Array} _bytes\n */\n send(_bytes) {\n throw new Error('HttpTransport does not support raw send; use OffsClient methods');\n }\n\n /**\n * Upload a file to PUT /offsystem.\n * @param {import('../types.js').OffsPutOptions} options\n * @param {ReadableStream|Uint8Array} body\n * @returns {Promise<{oriString: string}>}\n */\n async put(options, body) {\n const headers = {\n ...this.authHeaders(),\n 'type': options.contentType,\n 'file-name': options.fileName,\n 'stream-length': String(options.streamLength),\n };\n if (options.serverAddress) headers['server-address'] = options.serverAddress;\n if (options.recyclerUrls?.length) headers['recycler'] = JSON.stringify(options.recyclerUrls);\n if (options.temporary) headers['temporary'] = 'true';\n if (options.tupleSize !== undefined) headers['tuple-size'] = String(options.tupleSize);\n\n let requestBody = body;\n if (body && typeof body.getReader === 'function') {\n requestBody = await this._readStream(body);\n }\n\n const response = await fetch(this.url('/offsystem'), {\n method: 'PUT',\n headers,\n body: requestBody,\n signal: this.abortController?.signal\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Upload failed: ${response.status} ${text}`);\n }\n const oriString = await response.text();\n return { oriString };\n }\n\n /**\n * Read a ReadableStream into a Uint8Array.\n * The OFFS HTTP server is HTTP/1.1, so request streaming via duplex: 'half'\n * causes ERR_ALPN_NEGOTIATION_FAILED. Buffering the body avoids that.\n * @param {ReadableStream} stream\n * @returns {Promise}\n */\n async _readStream(stream) {\n const reader = stream.getReader();\n const chunks = [];\n let totalLength = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n }\n\n /**\n * Download from GET /offsystem/v3/...\n * @param {string} offUrl\n * @param {import('../types.js').OffsGetCallbacks} callbacks\n */\n async get(offUrl, callbacks) {\n const response = await fetch(offUrl, {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n callbacks.onError?.(response.status, text);\n return;\n }\n\n const contentType = response.headers.get('content-type') || 'application/octet-stream';\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10);\n const hasRange = response.status === 206;\n const rangeHeader = response.headers.get('content-range');\n let rangeStart, rangeEnd;\n if (rangeHeader) {\n const match = rangeHeader.match(/bytes (\\d+)-(\\d+)\\//);\n if (match) {\n rangeStart = parseInt(match[1], 10);\n rangeEnd = parseInt(match[2], 10);\n }\n }\n callbacks.onStart?.(contentType, contentLength, hasRange, rangeStart, rangeEnd);\n\n const reader = response.body?.getReader();\n if (!reader) {\n callbacks.onEnd?.();\n return;\n }\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) callbacks.onData(value);\n }\n callbacks.onEnd?.();\n } catch (err) {\n callbacks.onError?.(0, String(err));\n }\n }\n\n /**\n * Delete content.\n * @param {string} offUrl\n * @returns {Promise}\n */\n async delete(offUrl) {\n const response = await fetch(offUrl, {\n method: 'DELETE',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Delete failed: ${response.status} ${text}`);\n }\n }\n\n /**\n * @param {Uint8Array} data\n * @param {number} [encoding]\n * @returns {Promise<{status: number, hash: Uint8Array|string}>}\n */\n async blockPut(data, encoding = 0) {\n const query = encoding === 1 ? '?encoding=base58' : '';\n const response = await fetch(this.url(`/blocks${query}`), {\n method: 'PUT',\n headers: { ...this.authHeaders(), 'Content-Type': 'application/octet-stream' },\n body: data,\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Block put failed: ${response.status} ${text}`);\n }\n const hash = await response.arrayBuffer();\n return { status: 0, hash: new Uint8Array(hash) };\n }\n\n /**\n * @param {string} base58Hash\n * @returns {Promise<{status: number, data: Uint8Array}>}\n */\n async blockGet(base58Hash) {\n const response = await fetch(this.url(`/blocks/${base58Hash}`), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n return { status: 2, data: new Uint8Array(0) }; // NOT_FOUND\n }\n const data = await response.arrayBuffer();\n return { status: 0, data: new Uint8Array(data) };\n }\n\n /**\n * @param {string} base58Hash\n * @returns {Promise<{status: number}>}\n */\n async blockDelete(base58Hash) {\n const response = await fetch(this.url(`/blocks/${base58Hash}`), {\n method: 'DELETE',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n return { status: response.ok ? 0 : 2 };\n }\n\n /**\n * @returns {Promise}\n */\n async health() {\n const response = await fetch(this.url('/health'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n throw new Error(`Health check failed: ${response.status}`);\n }\n return response.json();\n }\n\n /**\n * @param {string} [format='cbor']\n * @returns {Promise<{format: number, data: Uint8Array}>}\n */\n async peerInfo(format = 'cbor') {\n const fmt = format === 'base58' ? 1 : 0;\n const response = await fetch(this.url(`/peer/info?format=${format}`), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Peer info failed: ${response.status}`);\n const data = await response.arrayBuffer();\n return { format: fmt, data: new Uint8Array(data) };\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise<{status: number}>}\n */\n async peerConnect(peerInfo, format = 0) {\n const response = await fetch(this.url('/peer/connect'), {\n method: 'POST',\n headers: { ...this.authHeaders(), 'Content-Type': format === 1 ? 'text/plain' : 'application/cbor' },\n body: format === 1 ? new TextDecoder().decode(peerInfo) : peerInfo,\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Peer connect failed: ${response.status}`);\n return { status: 0 };\n }\n\n /**\n * @returns {Promise}\n */\n async peerList() {\n const response = await fetch(this.url('/peers'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Peer list failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise}\n */\n async friendAdd(peerInfo, format = 0) {\n const response = await fetch(this.url('/friends'), {\n method: 'POST',\n headers: { ...this.authHeaders(), 'Content-Type': format === 1 ? 'text/plain' : 'application/cbor' },\n body: format === 1 ? new TextDecoder().decode(peerInfo) : peerInfo,\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Friend add failed: ${response.status}`);\n }\n\n /**\n * @param {string} nodeId\n * @returns {Promise}\n */\n async friendRemove(nodeId) {\n const response = await fetch(this.url(`/friends/${nodeId}`), {\n method: 'DELETE',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Friend remove failed: ${response.status}`);\n }\n\n /**\n * @returns {Promise}\n */\n async friendList() {\n const response = await fetch(this.url('/friends'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Friend list failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @returns {Promise}\n */\n async configShow() {\n const response = await fetch(this.url('/config'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Config show failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @param {string} field\n * @param {string} value\n * @returns {Promise<{staged: any, rejected: any, restart_required: boolean}>}\n */\n async configSet(field, value) {\n const response = await fetch(this.url('/config'), {\n method: 'PUT',\n headers: { ...this.authHeaders(), 'Content-Type': 'application/json' },\n body: JSON.stringify({ [field]: value }),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Config set failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @returns {Promise}\n */\n async configReload() {\n const response = await fetch(this.url('/config/restart'), {\n method: 'POST',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Config reload failed: ${response.status}`);\n }\n}\n","let decoder\ntry {\n\tdecoder = new TextDecoder()\n} catch(error) {}\nlet src\nlet srcEnd\nlet position = 0\nlet alreadySet\nconst EMPTY_ARRAY = []\nconst LEGACY_RECORD_INLINE_ID = 105\nconst RECORD_DEFINITIONS_ID = 0xdffe\nconst RECORD_INLINE_ID = 0xdfff // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'\nconst BUNDLED_STRINGS_ID = 0xdff9\nconst PACKED_TABLE_TAG_ID = 51\nconst PACKED_REFERENCE_TAG_ID = 6\nconst STOP_CODE = {}\nlet maxArraySize = 112810000 // This is the maximum array size in V8. We would potentially detect and set it higher\n// for JSC, but this is pretty large and should be sufficient for most use cases\nlet maxMapSize = 16810000 // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,\n// so we don't need to\n\nlet maxObjectSize = 16710000; // This is the maximum number of keys in a Map. It takes over a minute to create this\n// many keys in an object, so also probably a reasonable choice there.\nlet strings = EMPTY_ARRAY\nlet stringPosition = 0\nlet currentDecoder = {}\nlet currentStructures\nlet srcString\nlet srcStringStart = 0\nlet srcStringEnd = 0\nlet bundledStrings\nlet referenceMap\nlet currentExtensions = []\nlet currentExtensionRanges = []\nlet packedValues\nlet dataView\nlet restoreMapsAsObject\nlet defaultOptions = {\n\tuseRecords: false,\n\tmapsAsObjects: true\n}\nlet sequentialMode = false\nlet inlineObjectReadThreshold = 2;\nvar BlockedFunction // we use search and replace to change the next call to BlockedFunction to avoid CSP issues for\n// no-eval build\ntry {\n\tnew Function('')\n} catch(error) {\n\t// if eval variants are not supported, do not create inline object readers ever\n\tinlineObjectReadThreshold = Infinity\n}\n\n\n\nexport class Decoder {\n\tconstructor(options) {\n\t\tif (options) {\n\t\t\tif ((options.keyMap || options._keyMap) && !options.useRecords) {\n\t\t\t\toptions.useRecords = false\n\t\t\t\toptions.mapsAsObjects = true\n\t\t\t}\n\t\t\tif (options.useRecords === false && options.mapsAsObjects === undefined)\n\t\t\t\toptions.mapsAsObjects = true\n\t\t\tif (options.getStructures)\n\t\t\t\toptions.getShared = options.getStructures\n\t\t\tif (options.getShared && !options.structures)\n\t\t\t\t(options.structures = []).uninitialized = true // this is what we use to denote an uninitialized structures\n\t\t\tif (options.keyMap) {\n\t\t\t\tthis.mapKey = new Map()\n\t\t\t\tfor (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k)\n\t\t\t}\n\t\t}\n\t\tObject.assign(this, options)\n\t}\n\t/*\n\tdecodeKey(key) {\n\t\treturn this.keyMap\n\t\t\t? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key\n\t\t\t: key\n\t}\n\t*/\n\tdecodeKey(key) {\n\t\treturn this.keyMap ? this.mapKey.get(key) || key : key\n\t}\n\t\n\tencodeKey(key) {\n\t\treturn this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key\n\t}\n\n\tencodeKeys(rec) {\n\t\tif (!this._keyMap) return rec\n\t\tlet map = new Map()\n\t\tfor (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v)\n\t\treturn map\n\t}\n\n\tdecodeKeys(map) {\n\t\tif (!this._keyMap || map.constructor.name != 'Map') return map\n\t\tif (!this._mapKey) {\n\t\t\tthis._mapKey = new Map()\n\t\t\tfor (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k)\n\t\t}\n\t\tlet res = {}\n\t\t//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)\n\t\tmap.forEach((v,k) => res[safeKey(this._mapKey.has(k) ? this._mapKey.get(k) : k)] = v)\n\t\treturn res\n\t}\n\t\n\tmapDecode(source, end) {\n\t\n\t\tlet res = this.decode(source)\n\t\tif (this._keyMap) { \n\t\t\t//Experiemntal support for Optimised KeyMap decoding \n\t\t\tswitch (res.constructor.name) {\n\t\t\t\tcase 'Array': return res.map(r => this.decodeKeys(r))\n\t\t\t\t//case 'Map': return this.decodeKeys(res)\n\t\t\t}\n\t\t}\n\t\treturn res\n\t}\n\n\tdecode(source, end) {\n\t\tif (src) {\n\t\t\t// re-entrant execution, save the state and restore it after we do this decode\n\t\t\treturn saveState(() => {\n\t\t\t\tclearSource()\n\t\t\t\treturn this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)\n\t\t\t})\n\t\t}\n\t\tsrcEnd = end > -1 ? end : source.length\n\t\tposition = 0\n\t\tstringPosition = 0\n\t\tsrcStringEnd = 0\n\t\tsrcString = null\n\t\tstrings = EMPTY_ARRAY\n\t\tbundledStrings = null\n\t\tsrc = source\n\t\t// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend\n\t\t// technique for getting data from a database where it can be copied into an existing buffer instead of creating\n\t\t// new ones\n\t\ttry {\n\t\t\tdataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))\n\t\t} catch(error) {\n\t\t\t// if it doesn't have a buffer, maybe it is the wrong type of object\n\t\t\tsrc = null\n\t\t\tif (source instanceof Uint8Array)\n\t\t\t\tthrow error\n\t\t\tthrow new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))\n\t\t}\n\t\tif (this instanceof Decoder) {\n\t\t\tcurrentDecoder = this\n\t\t\tpackedValues = this.sharedValues &&\n\t\t\t\t(this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :\n\t\t\t\tthis.sharedValues)\n\t\t\tif (this.structures) {\n\t\t\t\tcurrentStructures = this.structures\n\t\t\t\treturn checkedRead()\n\t\t\t} else if (!currentStructures || currentStructures.length > 0) {\n\t\t\t\tcurrentStructures = []\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentDecoder = defaultOptions\n\t\t\tif (!currentStructures || currentStructures.length > 0)\n\t\t\t\tcurrentStructures = []\n\t\t\tpackedValues = null\n\t\t}\n\t\treturn checkedRead()\n\t}\n\tdecodeMultiple(source, forEach) {\n\t\tlet values, lastPosition = 0\n\t\ttry {\n\t\t\tlet size = source.length\n\t\t\tsequentialMode = true\n\t\t\tlet value = this ? this.decode(source, size) : defaultDecoder.decode(source, size)\n\t\t\tif (forEach) {\n\t\t\t\tif (forEach(value) === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\twhile(position < size) {\n\t\t\t\t\tlastPosition = position\n\t\t\t\t\tif (forEach(checkedRead()) === false) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvalues = [ value ]\n\t\t\t\twhile(position < size) {\n\t\t\t\t\tlastPosition = position\n\t\t\t\t\tvalues.push(checkedRead())\n\t\t\t\t}\n\t\t\t\treturn values\n\t\t\t}\n\t\t} catch(error) {\n\t\t\terror.lastPosition = lastPosition\n\t\t\terror.values = values\n\t\t\tthrow error\n\t\t} finally {\n\t\t\tsequentialMode = false\n\t\t\tclearSource()\n\t\t}\n\t}\n}\nexport function getPosition() {\n\treturn position\n}\nexport function checkedRead() {\n\ttry {\n\t\tlet result = read()\n\t\tif (bundledStrings) {\n\t\t\tif (position >= bundledStrings.postBundlePosition) {\n\t\t\t\tlet error = new Error('Unexpected bundle position');\n\t\t\t\terror.incomplete = true;\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\t// bundled strings to skip past\n\t\t\tposition = bundledStrings.postBundlePosition;\n\t\t\tbundledStrings = null;\n\t\t}\n\n\t\tif (position == srcEnd) {\n\t\t\t// finished reading this source, cleanup references\n\t\t\tcurrentStructures = null\n\t\t\tsrc = null\n\t\t\tif (referenceMap)\n\t\t\t\treferenceMap = null\n\t\t} else if (position > srcEnd) {\n\t\t\t// over read\n\t\t\tlet error = new Error('Unexpected end of CBOR data')\n\t\t\terror.incomplete = true\n\t\t\tthrow error\n\t\t} else if (!sequentialMode) {\n\t\t\tthrow new Error('Data read, but end of buffer not reached')\n\t\t}\n\t\t// else more to read, but we are reading sequentially, so don't clear source yet\n\t\treturn result\n\t} catch(error) {\n\t\tclearSource()\n\t\tif (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {\n\t\t\terror.incomplete = true\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport function read() {\n\tlet token = src[position++]\n\tlet majorType = token >> 5\n\ttoken = token & 0x1f\n\tif (token > 0x17) {\n\t\tswitch (token) {\n\t\t\tcase 0x18:\n\t\t\t\ttoken = src[position++]\n\t\t\t\tbreak\n\t\t\tcase 0x19:\n\t\t\t\tif (majorType == 7) {\n\t\t\t\t\treturn getFloat16()\n\t\t\t\t}\n\t\t\t\ttoken = dataView.getUint16(position)\n\t\t\t\tposition += 2\n\t\t\t\tbreak\n\t\t\tcase 0x1a:\n\t\t\t\tif (majorType == 7) {\n\t\t\t\t\tlet value = dataView.getFloat32(position)\n\t\t\t\t\tif (currentDecoder.useFloat32 > 2) {\n\t\t\t\t\t\t// this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved\n\t\t\t\t\t\tlet multiplier = mult10[((src[position] & 0x7f) << 1) | (src[position + 1] >> 7)]\n\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\treturn ((multiplier * value + (value > 0 ? 0.5 : -0.5)) >> 0) / multiplier\n\t\t\t\t\t}\n\t\t\t\t\tposition += 4\n\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\ttoken = dataView.getUint32(position)\n\t\t\t\tposition += 4\n\t\t\t\tif (majorType === 1) return -1 - token; // can't safely use negation operator here\n\t\t\t\tbreak\n\t\t\tcase 0x1b:\n\t\t\t\tif (majorType == 7) {\n\t\t\t\t\tlet value = dataView.getFloat64(position)\n\t\t\t\t\tposition += 8\n\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\tif (majorType > 1) {\n\t\t\t\t\tif (dataView.getUint32(position) > 0)\n\t\t\t\t\t\tthrow new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')\n\t\t\t\t\ttoken = dataView.getUint32(position + 4)\n\t\t\t\t} else if (currentDecoder.int64AsNumber) {\n\t\t\t\t\ttoken = dataView.getUint32(position) * 0x100000000\n\t\t\t\t\ttoken += dataView.getUint32(position + 4)\n\t\t\t\t} else token = dataView.getBigUint64(position)\n\t\t\t\tposition += 8\n\t\t\t\tbreak\n\t\t\tcase 0x1f: \n\t\t\t\t// indefinite length\n\t\t\t\tswitch(majorType) {\n\t\t\t\t\tcase 2: // byte string\n\t\t\t\t\tcase 3: // text string\n\t\t\t\t\t\tthrow new Error('Indefinite length not supported for byte or text strings')\n\t\t\t\t\tcase 4: // array\n\t\t\t\t\t\tlet array = []\n\t\t\t\t\t\tlet value, i = 0\n\t\t\t\t\t\twhile ((value = read()) != STOP_CODE) {\n\t\t\t\t\t\t\tif (i >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)\n\t\t\t\t\t\t\tarray[i++] = value\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn majorType == 4 ? array : majorType == 3 ? array.join('') : Buffer.concat(array)\n\t\t\t\t\tcase 5: // map\n\t\t\t\t\t\tlet key\n\t\t\t\t\t\tif (currentDecoder.mapsAsObjects) {\n\t\t\t\t\t\t\tlet object = {}\n\t\t\t\t\t\t\tlet i = 0;\n\t\t\t\t\t\t\tif (currentDecoder.keyMap) {\n\t\t\t\t\t\t\t\twhile((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)\n\t\t\t\t\t\t\t\t\tobject[safeKey(currentDecoder.decodeKey(key))] = read()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\twhile ((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)\n\t\t\t\t\t\t\t\t\tobject[safeKey(key)] = read()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn object\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (restoreMapsAsObject) {\n\t\t\t\t\t\t\t\tcurrentDecoder.mapsAsObjects = true\n\t\t\t\t\t\t\t\trestoreMapsAsObject = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet map = new Map()\n\t\t\t\t\t\t\tif (currentDecoder.keyMap) {\n\t\t\t\t\t\t\t\tlet i = 0;\n\t\t\t\t\t\t\t\twhile((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(`Map size exceeds ${maxMapSize}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tmap.set(currentDecoder.decodeKey(key), read())\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tlet i = 0;\n\t\t\t\t\t\t\t\twhile ((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(`Map size exceeds ${maxMapSize}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tmap.set(key, read())\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn map\n\t\t\t\t\t\t}\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\treturn STOP_CODE\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new Error('Invalid major type for indefinite length ' + majorType)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error('Unknown token ' + token)\n\t\t}\n\t}\n\tswitch (majorType) {\n\t\tcase 0: // positive int\n\t\t\treturn token\n\t\tcase 1: // negative int\n\t\t\treturn ~token\n\t\tcase 2: // buffer\n\t\t\treturn readBin(token)\n\t\tcase 3: // string\n\t\t\tif (srcStringEnd >= position) {\n\t\t\t\treturn srcString.slice(position - srcStringStart, (position += token) - srcStringStart)\n\t\t\t}\n\t\t\tif (srcStringEnd == 0 && srcEnd < 140 && token < 32) {\n\t\t\t\t// for small blocks, avoiding the overhead of the extract call is helpful\n\t\t\t\tlet string = token < 16 ? shortStringInJS(token) : longStringInJS(token)\n\t\t\t\tif (string != null)\n\t\t\t\t\treturn string\n\t\t\t}\n\t\t\treturn readFixedString(token)\n\t\tcase 4: // array\n\t\t\tif (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)\n\t\t\tlet array = new Array(token)\n\t\t //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())\t\n\t\t\t//else \n\t\t\tfor (let i = 0; i < token; i++) array[i] = read()\n\t\t\treturn array\n\t\tcase 5: // map\n\t\t\tif (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)\n\t\t\tif (currentDecoder.mapsAsObjects) {\n\t\t\t\tlet object = {}\n\t\t\t\tif (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read()\n\t\t\t\telse for (let i = 0; i < token; i++) object[safeKey(read())] = read()\n\t\t\t\treturn object\n\t\t\t} else {\n\t\t\t\tif (restoreMapsAsObject) {\n\t\t\t\t\tcurrentDecoder.mapsAsObjects = true\n\t\t\t\t\trestoreMapsAsObject = false\n\t\t\t\t}\n\t\t\t\tlet map = new Map()\n\t\t\t\tif (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read())\n\t\t\t\telse for (let i = 0; i < token; i++) map.set(read(), read())\n\t\t\t\treturn map\n\t\t\t}\n\t\tcase 6: // extension\n\t\t\tif (token >= BUNDLED_STRINGS_ID) {\n\t\t\t\tlet structure = currentStructures[token & 0x1fff] // check record structures first\n\t\t\t\t// At some point we may provide an option for dynamic tag assignment with a range like token >= 8 && (token < 16 || (token > 0x80 && token < 0xc0) || (token > 0x130 && token < 0x4000))\n\t\t\t\tif (structure) {\n\t\t\t\t\tif (!structure.read) structure.read = createStructureReader(structure)\n\t\t\t\t\treturn structure.read()\n\t\t\t\t}\n\t\t\t\tif (token < 0x10000) {\n\t\t\t\t\tif (token == RECORD_INLINE_ID) { // we do a special check for this so that we can keep the\n\t\t\t\t\t\t// currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)\n\t\t\t\t\t\tlet length = readJustLength()\n\t\t\t\t\t\tlet id = read()\n\t\t\t\t\t\tlet structure = read()\n\t\t\t\t\t\trecordDefinition(id, structure)\n\t\t\t\t\t\tlet object = {}\n\t\t\t\t\t\tif (currentDecoder.keyMap) for (let i = 2; i < length; i++) {\n\t\t\t\t\t\t\tlet key = currentDecoder.decodeKey(structure[i - 2])\n\t\t\t\t\t\t\tobject[safeKey(key)] = read()\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse for (let i = 2; i < length; i++) {\n\t\t\t\t\t\t\tlet key = structure[i - 2]\n\t\t\t\t\t\t\tobject[safeKey(key)] = read()\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn object\n\t\t\t\t\t}\n\t\t\t\t\telse if (token == RECORD_DEFINITIONS_ID) {\n\t\t\t\t\t\tlet length = readJustLength()\n\t\t\t\t\t\tlet id = read()\n\t\t\t\t\t\tfor (let i = 2; i < length; i++) {\n\t\t\t\t\t\t\trecordDefinition(id++, read())\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn read()\n\t\t\t\t\t} else if (token == BUNDLED_STRINGS_ID) {\n\t\t\t\t\t\treturn readBundleExt()\n\t\t\t\t\t}\n\t\t\t\t\tif (currentDecoder.getShared) {\n\t\t\t\t\t\tloadShared()\n\t\t\t\t\t\tstructure = currentStructures[token & 0x1fff]\n\t\t\t\t\t\tif (structure) {\n\t\t\t\t\t\t\tif (!structure.read)\n\t\t\t\t\t\t\t\tstructure.read = createStructureReader(structure)\n\t\t\t\t\t\t\treturn structure.read()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet extension = currentExtensions[token]\n\t\t\tif (extension) {\n\t\t\t\tif (extension.handlesRead)\n\t\t\t\t\treturn extension(read)\n\t\t\t\telse\n\t\t\t\t\treturn extension(read())\n\t\t\t} else {\n\t\t\t\tlet input = read()\n\t\t\t\tfor (let i = 0; i < currentExtensionRanges.length; i++) {\n\t\t\t\t\tlet value = currentExtensionRanges[i](token, input)\n\t\t\t\t\tif (value !== undefined)\n\t\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\treturn new Tag(input, token)\n\t\t\t}\n\t\tcase 7: // fixed value\n\t\t\tswitch (token) {\n\t\t\t\tcase 0x14: return false\n\t\t\t\tcase 0x15: return true\n\t\t\t\tcase 0x16: return null\n\t\t\t\tcase 0x17: return; // undefined\n\t\t\t\tcase 0x1f:\n\t\t\t\tdefault:\n\t\t\t\t\tlet packedValue = (packedValues || getPackedValues())[token]\n\t\t\t\t\tif (packedValue !== undefined)\n\t\t\t\t\t\treturn packedValue\n\t\t\t\t\tthrow new Error('Unknown token ' + token)\n\t\t\t}\n\t\tdefault: // negative int\n\t\t\tif (isNaN(token)) {\n\t\t\t\tlet error = new Error('Unexpected end of CBOR data')\n\t\t\t\terror.incomplete = true\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new Error('Unknown CBOR token ' + token)\n\t}\n}\nconst validName = /^[a-zA-Z_$][a-zA-Z\\d_$]*$/\nfunction createStructureReader(structure) {\n\tif (!structure) throw new Error('Structure is required in record definition');\n\tfunction readObject() {\n\t\t// get the array size from the header\n\t\tlet length = src[position++]\n\t\t//let majorType = token >> 5\n\t\tlength = length & 0x1f\n\t\tif (length > 0x17) {\n\t\t\tswitch (length) {\n\t\t\t\tcase 0x18:\n\t\t\t\t\tlength = src[position++]\n\t\t\t\t\tbreak\n\t\t\t\tcase 0x19:\n\t\t\t\t\tlength = dataView.getUint16(position)\n\t\t\t\t\tposition += 2\n\t\t\t\t\tbreak\n\t\t\t\tcase 0x1a:\n\t\t\t\t\tlength = dataView.getUint32(position)\n\t\t\t\t\tposition += 4\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error('Expected array header, but got ' + src[position - 1])\n\t\t\t}\n\t\t}\n\t\t// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function\n\t\tlet compiledReader = this.compiledReader // first look to see if we have the fast compiled function\n\t\twhile(compiledReader) {\n\t\t\t// we have a fast compiled object literal reader\n\t\t\tif (compiledReader.propertyCount === length)\n\t\t\t\treturn compiledReader(read) // with the right length, so we use it\n\t\t\tcompiledReader = compiledReader.next // see if there is another reader with the right length\n\t\t}\n\t\tif (this.slowReads++ >= inlineObjectReadThreshold) { // create a fast compiled reader\n\t\t\tlet array = this.length == length ? this : this.slice(0, length)\n\t\t\tcompiledReader = currentDecoder.keyMap \n\t\t\t? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? safeKey(k) + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')\n\t\t\t: new Function('r', 'return {' + array.map(key => validName.test(key) ? safeKey(key) + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}')\n\t\t\tif (this.compiledReader)\n\t\t\t\tcompiledReader.next = this.compiledReader // if there is an existing one, we store multiple readers as a linked list because it is usually pretty rare to have multiple readers (of different length) for the same structure\n\t\t\tcompiledReader.propertyCount = length\n\t\t\tthis.compiledReader = compiledReader\n\t\t\treturn compiledReader(read)\n\t\t}\n\t\tlet object = {}\n\t\tif (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[safeKey(currentDecoder.decodeKey(this[i]))] = read()\n\t\telse for (let i = 0; i < length; i++) {\n\t\t\tobject[safeKey(this[i])] = read();\n\t\t}\n\t\treturn object\n\t}\n\tstructure.slowReads = 0\n\treturn readObject\n}\n\nfunction safeKey(key) {\n\t// protect against prototype pollution\n\tif (typeof key === 'string') return key === '__proto__' ? '__proto_' : key\n\tif (typeof key === 'number' || typeof key === 'boolean' || typeof key === 'bigint') return key.toString();\n\tif (key == null) return key + '';\n\t// protect against expensive (DoS) string conversions\n\tthrow new Error('Invalid property name type ' + typeof key);\n}\n\nlet readFixedString = readStringJS\nlet readString8 = readStringJS\nlet readString16 = readStringJS\nlet readString32 = readStringJS\n\nexport let isNativeAccelerationEnabled = false\nexport function setExtractor(extractStrings) {\n\tisNativeAccelerationEnabled = true\n\treadFixedString = readString(1)\n\treadString8 = readString(2)\n\treadString16 = readString(3)\n\treadString32 = readString(5)\n\tfunction readString(headerLength) {\n\t\treturn function readString(length) {\n\t\t\tlet string = strings[stringPosition++]\n\t\t\tif (string == null) {\n\t\t\t\tif (bundledStrings)\n\t\t\t\t\treturn readStringJS(length)\n\t\t\t\tlet extraction = extractStrings(position, srcEnd, length, src)\n\t\t\t\tif (typeof extraction == 'string') {\n\t\t\t\t\tstring = extraction\n\t\t\t\t\tstrings = EMPTY_ARRAY\n\t\t\t\t} else {\n\t\t\t\t\tstrings = extraction\n\t\t\t\t\tstringPosition = 1\n\t\t\t\t\tsrcStringEnd = 1 // even if a utf-8 string was decoded, must indicate we are in the midst of extracted strings and can't skip strings\n\t\t\t\t\tstring = strings[0]\n\t\t\t\t\tif (string === undefined)\n\t\t\t\t\t\tthrow new Error('Unexpected end of buffer')\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet srcStringLength = string.length\n\t\t\tif (srcStringLength <= length) {\n\t\t\t\tposition += length\n\t\t\t\treturn string\n\t\t\t}\n\t\t\tsrcString = string\n\t\t\tsrcStringStart = position\n\t\t\tsrcStringEnd = position + srcStringLength\n\t\t\tposition += length\n\t\t\treturn string.slice(0, length) // we know we just want the beginning\n\t\t}\n\t}\n}\nfunction readStringJS(length) {\n\tlet result\n\tif (length < 16) {\n\t\tif (result = shortStringInJS(length))\n\t\t\treturn result\n\t}\n\tif (length > 64 && decoder)\n\t\treturn decoder.decode(src.subarray(position, position += length))\n\tconst end = position + length\n\tconst units = []\n\tresult = ''\n\twhile (position < end) {\n\t\tconst byte1 = src[position++]\n\t\tif ((byte1 & 0x80) === 0) {\n\t\t\t// 1 byte\n\t\t\tunits.push(byte1)\n\t\t} else if ((byte1 & 0xe0) === 0xc0) {\n\t\t\t// 2 bytes\n\t\t\tif (byte1 < 0xc2 || position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\tunits.push(0xFFFD)\n\t\t\t} else {\n\t\t\t\tconst byte2 = src[position++] & 0x3f\n\t\t\t\tunits.push(((byte1 & 0x1f) << 6) | byte2)\n\t\t\t}\n\t\t} else if ((byte1 & 0xf0) === 0xe0) {\n\t\t\t// 3 bytes\n\t\t\tconst byte2 = position < end ? src[position] : 0\n\t\t\tif (position >= end || (byte2 & 0xc0) !== 0x80 ||\n\t\t\t\t(byte1 === 0xe0 && byte2 < 0xa0) || (byte1 === 0xed && byte2 >= 0xa0)) {\n\t\t\t\tunits.push(0xFFFD)\n\t\t\t} else {\n\t\t\t\tposition++\n\t\t\t\tif (position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\t\tunits.push(0xFFFD)\n\t\t\t\t} else {\n\t\t\t\t\tconst byte3 = src[position++] & 0x3f\n\t\t\t\t\tunits.push(((byte1 & 0x1f) << 12) | ((byte2 & 0x3f) << 6) | byte3)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ((byte1 & 0xf8) === 0xf0) {\n\t\t\t// 4 bytes\n\t\t\tconst byte2 = position < end ? src[position] : 0\n\t\t\tif (byte1 > 0xf4 || position >= end || (byte2 & 0xc0) !== 0x80 ||\n\t\t\t\t(byte1 === 0xf0 && byte2 < 0x90) || (byte1 === 0xf4 && byte2 >= 0x90)) {\n\t\t\t\tunits.push(0xFFFD)\n\t\t\t} else {\n\t\t\t\tposition++\n\t\t\t\tif (position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\t\tunits.push(0xFFFD)\n\t\t\t\t} else {\n\t\t\t\t\tconst byte3 = src[position++] & 0x3f\n\t\t\t\t\tif (position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\t\t\tunits.push(0xFFFD)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst byte4 = src[position++] & 0x3f\n\t\t\t\t\t\tlet unit = ((byte1 & 0x07) << 0x12) | ((byte2 & 0x3f) << 0x0c) | (byte3 << 0x06) | byte4\n\t\t\t\t\t\tunit -= 0x10000\n\t\t\t\t\t\tunits.push(((unit >>> 10) & 0x3ff) | 0xd800)\n\t\t\t\t\t\tunits.push(0xdc00 | (unit & 0x3ff))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tunits.push(0xFFFD) // replacement character for invalid lead byte\n\t\t}\n\n\t\tif (units.length >= 0x1000) {\n\t\t\tresult += fromCharCode.apply(String, units)\n\t\t\tunits.length = 0\n\t\t}\n\t}\n\n\tif (units.length > 0) {\n\t\tresult += fromCharCode.apply(String, units)\n\t}\n\n\treturn result\n}\nlet fromCharCode = String.fromCharCode\nfunction longStringInJS(length) {\n\tlet start = position\n\tlet bytes = new Array(length)\n\tfor (let i = 0; i < length; i++) {\n\t\tconst byte = src[position++];\n\t\tif ((byte & 0x80) > 0) {\n\t\t\tposition = start\n \t\t\treturn\n \t\t}\n \t\tbytes[i] = byte\n \t}\n \treturn fromCharCode.apply(String, bytes)\n}\nfunction shortStringInJS(length) {\n\tif (length < 4) {\n\t\tif (length < 2) {\n\t\t\tif (length === 0)\n\t\t\t\treturn ''\n\t\t\telse {\n\t\t\t\tlet a = src[position++]\n\t\t\t\tif ((a & 0x80) > 1) {\n\t\t\t\t\tposition -= 1\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn fromCharCode(a)\n\t\t\t}\n\t\t} else {\n\t\t\tlet a = src[position++]\n\t\t\tlet b = src[position++]\n\t\t\tif ((a & 0x80) > 0 || (b & 0x80) > 0) {\n\t\t\t\tposition -= 2\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (length < 3)\n\t\t\t\treturn fromCharCode(a, b)\n\t\t\tlet c = src[position++]\n\t\t\tif ((c & 0x80) > 0) {\n\t\t\t\tposition -= 3\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn fromCharCode(a, b, c)\n\t\t}\n\t} else {\n\t\tlet a = src[position++]\n\t\tlet b = src[position++]\n\t\tlet c = src[position++]\n\t\tlet d = src[position++]\n\t\tif ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) {\n\t\t\tposition -= 4\n\t\t\treturn\n\t\t}\n\t\tif (length < 6) {\n\t\t\tif (length === 4)\n\t\t\t\treturn fromCharCode(a, b, c, d)\n\t\t\telse {\n\t\t\t\tlet e = src[position++]\n\t\t\t\tif ((e & 0x80) > 0) {\n\t\t\t\t\tposition -= 5\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn fromCharCode(a, b, c, d, e)\n\t\t\t}\n\t\t} else if (length < 8) {\n\t\t\tlet e = src[position++]\n\t\t\tlet f = src[position++]\n\t\t\tif ((e & 0x80) > 0 || (f & 0x80) > 0) {\n\t\t\t\tposition -= 6\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (length < 7)\n\t\t\t\treturn fromCharCode(a, b, c, d, e, f)\n\t\t\tlet g = src[position++]\n\t\t\tif ((g & 0x80) > 0) {\n\t\t\t\tposition -= 7\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn fromCharCode(a, b, c, d, e, f, g)\n\t\t} else {\n\t\t\tlet e = src[position++]\n\t\t\tlet f = src[position++]\n\t\t\tlet g = src[position++]\n\t\t\tlet h = src[position++]\n\t\t\tif ((e & 0x80) > 0 || (f & 0x80) > 0 || (g & 0x80) > 0 || (h & 0x80) > 0) {\n\t\t\t\tposition -= 8\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (length < 10) {\n\t\t\t\tif (length === 8)\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h)\n\t\t\t\telse {\n\t\t\t\t\tlet i = src[position++]\n\t\t\t\t\tif ((i & 0x80) > 0) {\n\t\t\t\t\t\tposition -= 9\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i)\n\t\t\t\t}\n\t\t\t} else if (length < 12) {\n\t\t\t\tlet i = src[position++]\n\t\t\t\tlet j = src[position++]\n\t\t\t\tif ((i & 0x80) > 0 || (j & 0x80) > 0) {\n\t\t\t\t\tposition -= 10\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (length < 11)\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j)\n\t\t\t\tlet k = src[position++]\n\t\t\t\tif ((k & 0x80) > 0) {\n\t\t\t\t\tposition -= 11\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k)\n\t\t\t} else {\n\t\t\t\tlet i = src[position++]\n\t\t\t\tlet j = src[position++]\n\t\t\t\tlet k = src[position++]\n\t\t\t\tlet l = src[position++]\n\t\t\t\tif ((i & 0x80) > 0 || (j & 0x80) > 0 || (k & 0x80) > 0 || (l & 0x80) > 0) {\n\t\t\t\t\tposition -= 12\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (length < 14) {\n\t\t\t\t\tif (length === 12)\n\t\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l)\n\t\t\t\t\telse {\n\t\t\t\t\t\tlet m = src[position++]\n\t\t\t\t\t\tif ((m & 0x80) > 0) {\n\t\t\t\t\t\t\tposition -= 13\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlet m = src[position++]\n\t\t\t\t\tlet n = src[position++]\n\t\t\t\t\tif ((m & 0x80) > 0 || (n & 0x80) > 0) {\n\t\t\t\t\t\tposition -= 14\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif (length < 15)\n\t\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n)\n\t\t\t\t\tlet o = src[position++]\n\t\t\t\t\tif ((o & 0x80) > 0) {\n\t\t\t\t\t\tposition -= 15\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction readBin(length) {\n\treturn currentDecoder.copyBuffers ?\n\t\t// specifically use the copying slice (not the node one)\n\t\tUint8Array.prototype.slice.call(src, position, position += length) :\n\t\tsrc.subarray(position, position += length)\n}\nfunction readExt(length) {\n\tlet type = src[position++]\n\tif (currentExtensions[type]) {\n\t\treturn currentExtensions[type](src.subarray(position, position += length))\n\t}\n\telse\n\t\tthrow new Error('Unknown extension type ' + type)\n}\nlet f32Array = new Float32Array(1)\nlet u8Array = new Uint8Array(f32Array.buffer, 0, 4)\nfunction getFloat16() {\n\tlet byte0 = src[position++]\n\tlet byte1 = src[position++]\n\tlet exponent = (byte0 & 0x7f) >> 2;\n\tif (exponent === 0x1f) { // specials\n\t\tif (byte1 || (byte0 & 3))\n\t\t\treturn NaN;\n\t\treturn (byte0 & 0x80) ? -Infinity : Infinity;\n\t}\n\tif (exponent === 0) { // sub-normals\n\t\t// significand with 10 fractional bits and divided by 2^14\n\t\tlet abs = (((byte0 & 3) << 8) | byte1) / (1 << 24)\n\t\treturn (byte0 & 0x80) ? -abs : abs\n\t}\n\n\tu8Array[3] = (byte0 & 0x80) | // sign bit\n\t\t((exponent >> 1) + 56) // 4 of 5 of the exponent bits, re-offset-ed\n\tu8Array[2] = ((byte0 & 7) << 5) | // last exponent bit and first two mantissa bits\n\t\t(byte1 >> 3) // next 5 bits of mantissa\n\tu8Array[1] = byte1 << 5; // last three bits of mantissa\n\tu8Array[0] = 0;\n\treturn f32Array[0];\n}\n\nlet keyCache = new Array(4096)\nfunction readKey() {\n\tlet length = src[position++]\n\tif (length >= 0x60 && length < 0x78) {\n\t\t// fixstr, potentially use key cache\n\t\tlength = length - 0x60\n\t\tif (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)\n\t\t\treturn srcString.slice(position - srcStringStart, (position += length) - srcStringStart)\n\t\telse if (!(srcStringEnd == 0 && srcEnd < 180))\n\t\t\treturn readFixedString(length)\n\t} else { // not cacheable, go back and do a standard read\n\t\tposition--\n\t\treturn read()\n\t}\n\tlet key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff\n\tlet entry = keyCache[key]\n\tlet checkPosition = position\n\tlet end = position + length - 3\n\tlet chunk\n\tlet i = 0\n\tif (entry && entry.bytes == length) {\n\t\twhile (checkPosition < end) {\n\t\t\tchunk = dataView.getUint32(checkPosition)\n\t\t\tif (chunk != entry[i++]) {\n\t\t\t\tcheckPosition = 0x70000000\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcheckPosition += 4\n\t\t}\n\t\tend += 3\n\t\twhile (checkPosition < end) {\n\t\t\tchunk = src[checkPosition++]\n\t\t\tif (chunk != entry[i++]) {\n\t\t\t\tcheckPosition = 0x70000000\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (checkPosition === end) {\n\t\t\tposition = checkPosition\n\t\t\treturn entry.string\n\t\t}\n\t\tend -= 3\n\t\tcheckPosition = position\n\t}\n\tentry = []\n\tkeyCache[key] = entry\n\tentry.bytes = length\n\twhile (checkPosition < end) {\n\t\tchunk = dataView.getUint32(checkPosition)\n\t\tentry.push(chunk)\n\t\tcheckPosition += 4\n\t}\n\tend += 3\n\twhile (checkPosition < end) {\n\t\tchunk = src[checkPosition++]\n\t\tentry.push(chunk)\n\t}\n\t// for small blocks, avoiding the overhead of the extract call is helpful\n\tlet string = length < 16 ? shortStringInJS(length) : longStringInJS(length)\n\tif (string != null)\n\t\treturn entry.string = string\n\treturn entry.string = readFixedString(length)\n}\n\nexport class Tag {\n\tconstructor(value, tag) {\n\t\tthis.value = value\n\t\tthis.tag = tag\n\t}\n}\n\ncurrentExtensions[0] = (dateString) => {\n\t// string date extension\n\treturn new Date(dateString)\n}\n\ncurrentExtensions[1] = (epochSec) => {\n\t// numeric date extension\n\treturn new Date(Math.round(epochSec * 1000))\n}\n\ncurrentExtensions[2] = (buffer) => {\n\t// bigint extension\n\tlet value = BigInt(0)\n\tfor (let i = 0, l = buffer.byteLength; i < l; i++) {\n\t\tvalue = BigInt(buffer[i]) + (value << BigInt(8))\n\t}\n\treturn value\n}\n\ncurrentExtensions[3] = (buffer) => {\n\t// negative bigint extension\n\treturn BigInt(-1) - currentExtensions[2](buffer)\n}\ncurrentExtensions[4] = (fraction) => {\n\t// best to reparse to maintain accuracy\n\treturn +(fraction[1] + 'e' + fraction[0])\n}\n\ncurrentExtensions[5] = (fraction) => {\n\t// probably not sufficiently accurate\n\treturn fraction[1] * Math.exp(fraction[0] * Math.log(2))\n}\n\n// the registration of the record definition extension\nconst recordDefinition = (id, structure) => {\n\tid = id - 0xe000\n\tlet existingStructure = currentStructures[id]\n\tif (existingStructure && existingStructure.isShared) {\n\t\t(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure\n\t}\n\tcurrentStructures[id] = structure\n\n\tstructure.read = createStructureReader(structure)\n}\ncurrentExtensions[LEGACY_RECORD_INLINE_ID] = (data) => {\n\tlet length = data.length\n\tlet structure = data[1]\n\trecordDefinition(data[0], structure)\n\tlet object = {}\n\tfor (let i = 2; i < length; i++) {\n\t\tlet key = structure[i - 2]\n\t\tobject[safeKey(key)] = data[i]\n\t}\n\treturn object\n}\ncurrentExtensions[14] = (value) => {\n\tif (bundledStrings)\n\t\treturn bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)\n\treturn new Tag(value, 14)\n}\ncurrentExtensions[15] = (value) => {\n\tif (bundledStrings)\n\t\treturn bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)\n\treturn new Tag(value, 15)\n}\nlet glbl = { Error, RegExp }\ncurrentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object\n\treturn (glbl[data[0]] || Error)(data[1], data[2])\n}\nconst packedTable = (read) => {\n\tif (src[position++] != 0x84) {\n\t\tlet error = new Error('Packed values structure must be followed by a 4 element array')\n\t\tif (src.length < position)\n\t\t\terror.incomplete = true\n\t\tthrow error\n\t}\n\tlet newPackedValues = read() // packed values\n\tif (!newPackedValues || !newPackedValues.length) {\n\t\tlet error = new Error('Packed values structure must be followed by a 4 element array')\n\t\terror.incomplete = true\n\t\tthrow error\n\t}\n\tpackedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues\n\tpackedValues.prefixes = read()\n\tpackedValues.suffixes = read()\n\treturn read() // read the rump\n}\npackedTable.handlesRead = true\ncurrentExtensions[51] = packedTable\n\ncurrentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference\n\tif (!packedValues) {\n\t\tif (currentDecoder.getShared)\n\t\t\tloadShared()\n\t\telse\n\t\t\treturn new Tag(data, PACKED_REFERENCE_TAG_ID)\n\t}\n\tif (typeof data == 'number')\n\t\treturn packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]\n\tlet error = new Error('No support for non-integer packed references yet')\n\tif (data === undefined)\n\t\terror.incomplete = true\n\tthrow error\n}\n\n// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref\n// the real thing would need to implemennt more logic to populate the stringRefs table and\n// maintain a stack of stringRef \"namespaces\".\n//\n// currentExtensions[25] = (id) => {\n// \treturn stringRefs[id]\n// }\n// currentExtensions[256] = (read) => {\n// \tstringRefs = []\n// \ttry {\n// \t\treturn read()\n// \t} finally {\n// \t\tstringRefs = null\n// \t}\n// }\n// currentExtensions[256].handlesRead = true\n\ncurrentExtensions[28] = (read) => { \n\t// shareable http://cbor.schmorp.de/value-sharing (for structured clones)\n\tif (!referenceMap) {\n\t\treferenceMap = new Map()\n\t\treferenceMap.id = 0\n\t}\n\tlet id = referenceMap.id++\n\tlet startingPosition = position\n\tlet token = src[position]\n\tlet target\n\t// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read\n\t// ahead past references to record structure definitions\n\tif ((token >> 5) == 4)\n\t\ttarget = []\n\telse\n\t\ttarget = {}\n\n\tlet refEntry = { target } // a placeholder object\n\treferenceMap.set(id, refEntry)\n\tlet targetProperties = read() // read the next value as the target object to id\n\tif (refEntry.used) {// there is a cycle, so we have to assign properties to original target\n\t\tif (Object.getPrototypeOf(target) !== Object.getPrototypeOf(targetProperties)) {\n\t\t\t// this means that the returned target does not match the targetProperties, so we need rerun the read to\n\t\t\t// have the correctly create instance be assigned as a reference, then we do the copy the properties back to the\n\t\t\t// target\n\t\t\t// reset the position so that the read can be repeated\n\t\t\tposition = startingPosition\n\t\t\t// the returned instance is our new target for references\n\t\t\ttarget = targetProperties\n\t\t\treferenceMap.set(id, { target })\n\t\t\ttargetProperties = read()\n\t\t}\n\t\treturn Object.assign(target, targetProperties)\n\t}\n\trefEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one\n\treturn targetProperties // no cycle, can just use the returned read object\n}\ncurrentExtensions[28].handlesRead = true\n\ncurrentExtensions[29] = (id) => {\n\t// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)\n\tlet refEntry = referenceMap.get(id)\n\trefEntry.used = true\n\treturn refEntry.target\n}\n\ncurrentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md\n(currentExtensions[259] = (read) => {\n\t// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec\n\t// for decoding as a standard Map\n\tif (currentDecoder.mapsAsObjects) {\n\t\tcurrentDecoder.mapsAsObjects = false\n\t\trestoreMapsAsObject = true\n\t}\n\treturn read()\n}).handlesRead = true\nfunction combine(a, b) {\n\tif (typeof a === 'string')\n\t\treturn a + b\n\tif (a instanceof Array)\n\t\treturn a.concat(b)\n\treturn Object.assign({}, a, b)\n}\nfunction getPackedValues() {\n\tif (!packedValues) {\n\t\tif (currentDecoder.getShared)\n\t\t\tloadShared()\n\t\telse\n\t\t\tthrow new Error('No packed values available')\n\t}\n\treturn packedValues\n}\nconst SHARED_DATA_TAG_ID = 0x53687264 // ascii 'Shrd'\ncurrentExtensionRanges.push((tag, input) => {\n\tif (tag >= 225 && tag <= 255)\n\t\treturn combine(getPackedValues().prefixes[tag - 224], input)\n\tif (tag >= 28704 && tag <= 32767)\n\t\treturn combine(getPackedValues().prefixes[tag - 28672], input)\n\tif (tag >= 1879052288 && tag <= 2147483647)\n\t\treturn combine(getPackedValues().prefixes[tag - 1879048192], input)\n\tif (tag >= 216 && tag <= 223)\n\t\treturn combine(input, getPackedValues().suffixes[tag - 216])\n\tif (tag >= 27647 && tag <= 28671)\n\t\treturn combine(input, getPackedValues().suffixes[tag - 27639])\n\tif (tag >= 1811940352 && tag <= 1879048191)\n\t\treturn combine(input, getPackedValues().suffixes[tag - 1811939328])\n\tif (tag == SHARED_DATA_TAG_ID) {// we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)\n\t\treturn {\n\t\t\tpackedValues: packedValues,\n\t\t\tstructures: currentStructures.slice(0),\n\t\t\tversion: input,\n\t\t}\n\t}\n\tif (tag == 55799) // self-descriptive CBOR tag, just return input value\n\t\treturn input\n})\n\nconst isLittleEndianMachine = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1\nexport const typedArrays = [Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,\n\ttypeof BigUint64Array == 'undefined' ? { name:'BigUint64Array' } : BigUint64Array, Int8Array, Int16Array, Int32Array,\n\ttypeof BigInt64Array == 'undefined' ? { name:'BigInt64Array' } : BigInt64Array, Float32Array, Float64Array]\nconst typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 85, 86]\nfor (let i = 0; i < typedArrays.length; i++) {\n\tregisterTypedArray(typedArrays[i], typedArrayTags[i])\n}\nfunction registerTypedArray(TypedArray, tag) {\n\tlet dvMethod = 'get' + TypedArray.name.slice(0, -5)\n\tlet bytesPerElement;\n\tif (typeof TypedArray === 'function')\n\t\tbytesPerElement = TypedArray.BYTES_PER_ELEMENT;\n\telse\n\t\tTypedArray = null;\n\tfor (let littleEndian = 0; littleEndian < 2; littleEndian++) {\n\t\tif (!littleEndian && bytesPerElement == 1)\n\t\t\tcontinue\n\t\tlet sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : bytesPerElement == 8 ? 3 : 0\n\t\tcurrentExtensions[littleEndian ? tag : (tag - 4)] = (bytesPerElement == 1 || littleEndian == isLittleEndianMachine) ? (buffer) => {\n\t\t\tif (!TypedArray)\n\t\t\t\tthrow new Error('Could not find typed array for code ' + tag)\n\t\t\tif (!currentDecoder.copyBuffers) {\n\t\t\t\t// try provide a direct view, but will only work if we are byte-aligned\n\t\t\t\tif (bytesPerElement === 1 ||\n\t\t\t\t\tbytesPerElement === 2 && !(buffer.byteOffset & 1) ||\n\t\t\t\t\tbytesPerElement === 4 && !(buffer.byteOffset & 3) ||\n\t\t\t\t\tbytesPerElement === 8 && !(buffer.byteOffset & 7))\n\t\t\t\t\treturn new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength >> sizeShift);\n\t\t\t}\n\t\t\t// we have to slice/copy here to get a new ArrayBuffer, if we are not word/byte aligned\n\t\t\treturn new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)\n\t\t} : buffer => {\n\t\t\tif (!TypedArray)\n\t\t\t\tthrow new Error('Could not find typed array for code ' + tag)\n\t\t\tlet dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n\t\t\tlet elements = buffer.length >> sizeShift\n\t\t\tlet ta = new TypedArray(elements)\n\t\t\tlet method = dv[dvMethod]\n\t\t\tfor (let i = 0; i < elements; i++) {\n\t\t\t\tta[i] = method.call(dv, i << sizeShift, littleEndian)\n\t\t\t}\n\t\t\treturn ta\n\t\t}\n\t}\n}\n\nfunction readBundleExt() {\n\tlet length = readJustLength()\n\tlet bundlePosition = position + read()\n\tfor (let i = 2; i < length; i++) {\n\t\t// skip past bundles that were already read\n\t\tlet bundleLength = readJustLength() // this will increment position, so must add to position afterwards\n\t\tposition += bundleLength\n\t}\n\tlet dataPosition = position\n\tposition = bundlePosition\n\tbundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())]\n\tbundledStrings.position0 = 0\n\tbundledStrings.position1 = 0\n\tbundledStrings.postBundlePosition = position\n\tposition = dataPosition\n\treturn read()\n}\n\nfunction readJustLength() {\n\tlet token = src[position++] & 0x1f\n\tif (token > 0x17) {\n\t\tswitch (token) {\n\t\t\tcase 0x18:\n\t\t\t\ttoken = src[position++]\n\t\t\t\tbreak\n\t\t\tcase 0x19:\n\t\t\t\ttoken = dataView.getUint16(position)\n\t\t\t\tposition += 2\n\t\t\t\tbreak\n\t\t\tcase 0x1a:\n\t\t\t\ttoken = dataView.getUint32(position)\n\t\t\t\tposition += 4\n\t\t\t\tbreak\n\t\t}\n\t}\n\treturn token\n}\n\nfunction loadShared() {\n\tif (currentDecoder.getShared) {\n\t\tlet sharedData = saveState(() => {\n\t\t\t// save the state in case getShared modifies our buffer\n\t\t\tsrc = null\n\t\t\treturn currentDecoder.getShared()\n\t\t}) || {}\n\t\tlet updatedStructures = sharedData.structures || []\n\t\tcurrentDecoder.sharedVersion = sharedData.version\n\t\tpackedValues = currentDecoder.sharedValues = sharedData.packedValues\n\t\tif (currentStructures === true)\n\t\t\tcurrentDecoder.structures = currentStructures = updatedStructures\n\t\telse\n\t\t\tcurrentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))\n\t}\n}\n\nfunction saveState(callback) {\n\tlet savedSrcEnd = srcEnd\n\tlet savedPosition = position\n\tlet savedStringPosition = stringPosition\n\tlet savedSrcStringStart = srcStringStart\n\tlet savedSrcStringEnd = srcStringEnd\n\tlet savedSrcString = srcString\n\tlet savedStrings = strings\n\tlet savedReferenceMap = referenceMap\n\tlet savedBundledStrings = bundledStrings\n\n\t// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)\n\tlet savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed\n\tlet savedStructures = currentStructures\n\tlet savedDecoder = currentDecoder\n\tlet savedSequentialMode = sequentialMode\n\tlet value = callback()\n\tsrcEnd = savedSrcEnd\n\tposition = savedPosition\n\tstringPosition = savedStringPosition\n\tsrcStringStart = savedSrcStringStart\n\tsrcStringEnd = savedSrcStringEnd\n\tsrcString = savedSrcString\n\tstrings = savedStrings\n\treferenceMap = savedReferenceMap\n\tbundledStrings = savedBundledStrings\n\tsrc = savedSrc\n\tsequentialMode = savedSequentialMode\n\tcurrentStructures = savedStructures\n\tcurrentDecoder = savedDecoder\n\tdataView = new DataView(src.buffer, src.byteOffset, src.byteLength)\n\treturn value\n}\nexport function clearSource() {\n\tsrc = null\n\treferenceMap = null\n\tcurrentStructures = null\n}\n\nexport function addExtension(extension) {\n\tcurrentExtensions[extension.tag] = extension.decode\n}\n\nexport function setSizeLimits(limits) {\n\tif (limits.maxMapSize) maxMapSize = limits.maxMapSize;\n\tif (limits.maxArraySize) maxArraySize = limits.maxArraySize;\n\tif (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;\n}\n\nexport const mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding\nfor (let i = 0; i < 256; i++) {\n\tmult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))\n}\nlet defaultDecoder = new Decoder({ useRecords: false })\nexport const decode = defaultDecoder.decode\nexport const decodeMultiple = defaultDecoder.decodeMultiple\nexport const FLOAT32_OPTIONS = {\n\tNEVER: 0,\n\tALWAYS: 1,\n\tDECIMAL_ROUND: 3,\n\tDECIMAL_FIT: 4\n}\nexport function roundFloat32(float32Number) {\n\tf32Array[0] = float32Number\n\tlet multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]\n\treturn ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier\n}\n","import { Decoder, mult10, Tag, typedArrays, addExtension as decodeAddExtension } from './decode.js'\nlet textEncoder\ntry {\n\ttextEncoder = new TextEncoder()\n} catch (error) {}\nlet extensions, extensionClasses\nconst Buffer = typeof globalThis === 'object' && globalThis.Buffer;\nconst hasNodeBuffer = typeof Buffer !== 'undefined'\nconst ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array\nconst ByteArray = hasNodeBuffer ? Buffer : Uint8Array\nconst MAX_STRUCTURES = 0x100\nconst MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000\nlet serializationId = 1\nlet throwOnIterable\nlet target\nlet targetView\nlet position = 0\nlet safeEnd\nlet bundledStrings = null\nconst MAX_BUNDLE_SIZE = 0xf000\nconst hasNonLatin = /[\\u0080-\\uFFFF]/\nconst RECORD_SYMBOL = Symbol('record-id')\nexport class Encoder extends Decoder {\n\tconstructor(options) {\n\t\tsuper(options)\n\t\tthis.offset = 0\n\t\tlet typeBuffer\n\t\tlet start\n\t\tlet sharedStructures\n\t\tlet hasSharedUpdate\n\t\tlet structures\n\t\tlet referenceMap\n\t\toptions = options || {}\n\t\tlet encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position) {\n\t\t\treturn target.utf8Write(string, position, target.byteLength - position)\n\t\t} : (textEncoder && textEncoder.encodeInto) ?\n\t\t\tfunction(string, position) {\n\t\t\t\treturn textEncoder.encodeInto(string, target.subarray(position)).written\n\t\t\t} : false\n\n\t\tlet encoder = this\n\t\tlet hasSharedStructures = options.structures || options.saveStructures\n\t\tlet maxSharedStructures = options.maxSharedStructures\n\t\tif (maxSharedStructures == null)\n\t\t\tmaxSharedStructures = hasSharedStructures ? 128 : 0\n\t\tif (maxSharedStructures > 8190)\n\t\t\tthrow new Error('Maximum maxSharedStructure is 8190')\n\t\tlet isSequential = options.sequential\n\t\tif (isSequential) {\n\t\t\tmaxSharedStructures = 0\n\t\t}\n\t\tif (!this.structures)\n\t\t\tthis.structures = []\n\t\tif (this.saveStructures)\n\t\t\tthis.saveShared = this.saveStructures\n\t\tlet samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues\n\t\tlet sharedPackedObjectMap\n\t\tif (sharedValues) {\n\t\t\tsharedPackedObjectMap = Object.create(null)\n\t\t\tfor (let i = 0, l = sharedValues.length; i < l; i++) {\n\t\t\t\tsharedPackedObjectMap[sharedValues[i]] = i\n\t\t\t}\n\t\t}\n\t\tlet recordIdsToRemove = []\n\t\tlet transitionsCount = 0\n\t\tlet serializationsSinceTransitionRebuild = 0\n\t\t\n\t\tthis.mapEncode = function(value, encodeOptions) {\n\t\t\t// Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)\n\t\t\tif (this._keyMap && !this._mapped) {\n\t\t\t\t//console.log('encoding ', value)\n\t\t\t\tswitch (value.constructor.name) {\n\t\t\t\t\tcase 'Array': \n\t\t\t\t\t\tvalue = value.map(r => this.encodeKeys(r))\n\t\t\t\t\t\tbreak\n\t\t\t\t\t//case 'Map': \n\t\t\t\t\t//\tvalue = this.encodeKeys(value)\n\t\t\t\t\t//\tbreak\n\t\t\t\t}\n\t\t\t\t//this._mapped = true\n\t\t\t}\n\t\t\treturn this.encode(value, encodeOptions)\n\t\t}\n\t\t\n\t\tthis.encode = function(value, encodeOptions)\t{\n\t\t\tif (!target) {\n\t\t\t\ttarget = new ByteArrayAllocate(8192)\n\t\t\t\ttargetView = new DataView(target.buffer, 0, 8192)\n\t\t\t\tposition = 0\n\t\t\t}\n\t\t\tsafeEnd = target.length - 10\n\t\t\tif (safeEnd - position < 0x800) {\n\t\t\t\t// don't start too close to the end, \n\t\t\t\ttarget = new ByteArrayAllocate(target.length)\n\t\t\t\ttargetView = new DataView(target.buffer, 0, target.length)\n\t\t\t\tsafeEnd = target.length - 10\n\t\t\t\tposition = 0\n\t\t\t} else if (encodeOptions === REUSE_BUFFER_MODE)\n\t\t\t\tposition = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster\n\t\t\tstart = position\n\t\t\tif (encoder.useSelfDescribedHeader) {\n\t\t\t\ttargetView.setUint32(position, 0xd9d9f700) // tag two byte, then self-descriptive tag\n\t\t\t\tposition += 3\n\t\t\t}\n\t\t\treferenceMap = encoder.structuredClone ? new Map() : null\n\t\t\tif (encoder.bundleStrings && typeof value !== 'string') {\n\t\t\t\tbundledStrings = []\n\t\t\t\tbundledStrings.size = Infinity // force a new bundle start on first string\n\t\t\t} else\n\t\t\t\tbundledStrings = null\n\n\t\t\tsharedStructures = encoder.structures\n\t\t\tif (sharedStructures) {\n\t\t\t\tif (sharedStructures.uninitialized) {\n\t\t\t\t\tlet sharedData = encoder.getShared() || {}\n\t\t\t\t\tencoder.structures = sharedStructures = sharedData.structures || []\n\t\t\t\t\tencoder.sharedVersion = sharedData.version\n\t\t\t\t\tlet sharedValues = encoder.sharedValues = sharedData.packedValues\n\t\t\t\t\tif (sharedValues) {\n\t\t\t\t\t\tsharedPackedObjectMap = {}\n\t\t\t\t\t\tfor (let i = 0, l = sharedValues.length; i < l; i++)\n\t\t\t\t\t\t\tsharedPackedObjectMap[sharedValues[i]] = i\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlet sharedStructuresLength = sharedStructures.length\n\t\t\t\tif (sharedStructuresLength > maxSharedStructures && !isSequential)\n\t\t\t\t\tsharedStructuresLength = maxSharedStructures\n\t\t\t\tif (!sharedStructures.transitions) {\n\t\t\t\t\t// rebuild our structure transitions\n\t\t\t\t\tsharedStructures.transitions = Object.create(null)\n\t\t\t\t\tfor (let i = 0; i < sharedStructuresLength; i++) {\n\t\t\t\t\t\tlet keys = sharedStructures[i]\n\t\t\t\t\t\t//console.log('shared struct keys:', keys)\n\t\t\t\t\t\tif (!keys)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tlet nextTransition, transition = sharedStructures.transitions\n\t\t\t\t\t\tfor (let j = 0, l = keys.length; j < l; j++) {\n\t\t\t\t\t\t\tif (transition[RECORD_SYMBOL] === undefined)\n\t\t\t\t\t\t\t\ttransition[RECORD_SYMBOL] = i\n\t\t\t\t\t\t\tlet key = keys[j]\n\t\t\t\t\t\t\tnextTransition = transition[key]\n\t\t\t\t\t\t\tif (!nextTransition) {\n\t\t\t\t\t\t\t\tnextTransition = transition[key] = Object.create(null)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttransition = nextTransition\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttransition[RECORD_SYMBOL] = i | 0x100000\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!isSequential)\n\t\t\t\t\tsharedStructures.nextId = sharedStructuresLength\n\t\t\t}\n\t\t\tif (hasSharedUpdate)\n\t\t\t\thasSharedUpdate = false\n\t\t\tstructures = sharedStructures || []\n\t\t\tpackedObjectMap = sharedPackedObjectMap\n\t\t\tif (options.pack) {\n\t\t\t\tlet packedValues = new Map()\n\t\t\t\tpackedValues.values = []\n\t\t\t\tpackedValues.encoder = encoder\n\t\t\t\tpackedValues.maxValues = options.maxPrivatePackedValues || (sharedPackedObjectMap ? 16 : Infinity)\n\t\t\t\tpackedValues.objectMap = sharedPackedObjectMap || false\n\t\t\t\tpackedValues.samplingPackedValues = samplingPackedValues\n\t\t\t\tfindRepetitiveStrings(value, packedValues)\n\t\t\t\tif (packedValues.values.length > 0) {\n\t\t\t\t\ttarget[position++] = 0xd8 // one-byte tag\n\t\t\t\t\ttarget[position++] = 51 // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\t\t\twriteArrayHeader(4)\n\t\t\t\t\tlet valuesArray = packedValues.values\n\t\t\t\t\tencode(valuesArray)\n\t\t\t\t\twriteArrayHeader(0) // prefixes\n\t\t\t\t\twriteArrayHeader(0) // suffixes\n\t\t\t\t\tpackedObjectMap = Object.create(sharedPackedObjectMap || null)\n\t\t\t\t\tfor (let i = 0, l = valuesArray.length; i < l; i++) {\n\t\t\t\t\t\tpackedObjectMap[valuesArray[i]] = i\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrowOnIterable = encodeOptions & THROW_ON_ITERABLE;\n\t\t\ttry {\n\t\t\t\tif (throwOnIterable)\n\t\t\t\t\treturn;\n\t\t\t\tencode(value)\n\t\t\t\tif (bundledStrings) {\n\t\t\t\t\twriteBundles(start, encode)\n\t\t\t\t}\n\t\t\t\tencoder.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially\n\t\t\t\tif (referenceMap && referenceMap.idsToInsert) {\n\t\t\t\t\tposition += referenceMap.idsToInsert.length * 2\n\t\t\t\t\tif (position > safeEnd)\n\t\t\t\t\t\tmakeRoom(position)\n\t\t\t\t\tencoder.offset = position\n\t\t\t\t\tlet serialized = insertIds(target.subarray(start, position), referenceMap.idsToInsert)\n\t\t\t\t\treferenceMap = null\n\t\t\t\t\treturn serialized\n\t\t\t\t}\n\t\t\t\tif (encodeOptions & REUSE_BUFFER_MODE) {\n\t\t\t\t\ttarget.start = start\n\t\t\t\t\ttarget.end = position\n\t\t\t\t\treturn target\n\t\t\t\t}\n\t\t\t\treturn target.subarray(start, position) // position can change if we call encode again in saveShared, so we get the buffer now\n\t\t\t} finally {\n\t\t\t\tif (sharedStructures) {\n\t\t\t\t\tif (serializationsSinceTransitionRebuild < 10)\n\t\t\t\t\t\tserializationsSinceTransitionRebuild++\n\t\t\t\t\tif (sharedStructures.length > maxSharedStructures)\n\t\t\t\t\t\tsharedStructures.length = maxSharedStructures\n\t\t\t\t\tif (transitionsCount > 10000) {\n\t\t\t\t\t\t// force a rebuild occasionally after a lot of transitions so it can get cleaned up\n\t\t\t\t\t\tsharedStructures.transitions = null\n\t\t\t\t\t\tserializationsSinceTransitionRebuild = 0\n\t\t\t\t\t\ttransitionsCount = 0\n\t\t\t\t\t\tif (recordIdsToRemove.length > 0)\n\t\t\t\t\t\t\trecordIdsToRemove = []\n\t\t\t\t\t} else if (recordIdsToRemove.length > 0 && !isSequential) {\n\t\t\t\t\t\tfor (let i = 0, l = recordIdsToRemove.length; i < l; i++) {\n\t\t\t\t\t\t\trecordIdsToRemove[i][RECORD_SYMBOL] = undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t\trecordIdsToRemove = []\n\t\t\t\t\t\t//sharedStructures.nextId = maxSharedStructures\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (hasSharedUpdate && encoder.saveShared) {\n\t\t\t\t\tif (encoder.structures.length > maxSharedStructures) {\n\t\t\t\t\t\tencoder.structures = encoder.structures.slice(0, maxSharedStructures)\n\t\t\t\t\t}\n\t\t\t\t\t// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save\n\t\t\t\t\tlet returnBuffer = target.subarray(start, position)\n\t\t\t\t\tif (encoder.updateSharedData() === false)\n\t\t\t\t\t\treturn encoder.encode(value) // re-encode if it fails\n\t\t\t\t\treturn returnBuffer\n\t\t\t\t}\n\t\t\t\tif (encodeOptions & RESET_BUFFER_MODE)\n\t\t\t\t\tposition = start\n\t\t\t}\n\t\t}\n\t\tthis.findCommonStringsToPack = () => {\n\t\t\tsamplingPackedValues = new Map()\n\t\t\tif (!sharedPackedObjectMap)\n\t\t\t\tsharedPackedObjectMap = Object.create(null)\n\t\t\treturn (options) => {\n\t\t\t\tlet threshold = options && options.threshold || 4\n\t\t\t\tlet position = this.pack ? options.maxPrivatePackedValues || 16 : 0\n\t\t\t\tif (!sharedValues)\n\t\t\t\t\tsharedValues = this.sharedValues = []\n\t\t\t\tfor (let [ key, status ] of samplingPackedValues) {\n\t\t\t\t\tif (status.count > threshold) {\n\t\t\t\t\t\tsharedPackedObjectMap[key] = position++\n\t\t\t\t\t\tsharedValues.push(key)\n\t\t\t\t\t\thasSharedUpdate = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twhile (this.saveShared && this.updateSharedData() === false) {}\n\t\t\t\tsamplingPackedValues = null\n\t\t\t}\n\t\t}\n\t\tconst encode = (value) => {\n\t\t\tif (position > safeEnd)\n\t\t\t\ttarget = makeRoom(position)\n\n\t\t\tvar type = typeof value\n\t\t\tvar length\n\t\t\tif (type === 'string') {\n\t\t\t\tif (packedObjectMap) {\n\t\t\t\t\tlet packedPosition = packedObjectMap[value]\n\t\t\t\t\tif (packedPosition >= 0) {\n\t\t\t\t\t\tif (packedPosition < 16)\n\t\t\t\t\t\t\ttarget[position++] = packedPosition + 0xe0 // simple values, defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttarget[position++] = 0xc6 // tag 6 defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\t\t\t\t\tif (packedPosition & 1)\n\t\t\t\t\t\t\t\tencode((15 - packedPosition) >> 1)\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tencode((packedPosition - 16) >> 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n/*\t\t\t\t\t\t} else if (packedStatus.serializationId != serializationId) {\n\t\t\t\t\t\t\tpackedStatus.serializationId = serializationId\n\t\t\t\t\t\t\tpackedStatus.count = 1\n\t\t\t\t\t\t\tif (options.sharedPack) {\n\t\t\t\t\t\t\t\tlet sharedCount = packedStatus.sharedCount = (packedStatus.sharedCount || 0) + 1\n\t\t\t\t\t\t\t\tif (shareCount > (options.sharedPack.threshold || 5)) {\n\t\t\t\t\t\t\t\t\tlet sharedPosition = packedStatus.position = packedStatus.nextSharedPosition\n\t\t\t\t\t\t\t\t\thasSharedUpdate = true\n\t\t\t\t\t\t\t\t\tif (sharedPosition < 16)\n\t\t\t\t\t\t\t\t\t\ttarget[position++] = sharedPosition + 0xc0\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} // else any in-doc incrementation?*/\n\t\t\t\t\t} else if (samplingPackedValues && !options.pack) {\n\t\t\t\t\t\tlet status = samplingPackedValues.get(value)\n\t\t\t\t\t\tif (status)\n\t\t\t\t\t\t\tstatus.count++\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsamplingPackedValues.set(value, {\n\t\t\t\t\t\t\t\tcount: 1,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlet strLength = value.length\n\t\t\t\tif (bundledStrings && strLength >= 4 && strLength < 0x400) {\n\t\t\t\t\tif ((bundledStrings.size += strLength) > MAX_BUNDLE_SIZE) {\n\t\t\t\t\t\tlet extStart\n\t\t\t\t\t\tlet maxBytes = (bundledStrings[0] ? bundledStrings[0].length * 3 + bundledStrings[1].length : 0) + 10\n\t\t\t\t\t\tif (position + maxBytes > safeEnd)\n\t\t\t\t\t\t\ttarget = makeRoom(position + maxBytes)\n\t\t\t\t\t\ttarget[position++] = 0xd9 // tag 16-bit\n\t\t\t\t\t\ttarget[position++] = 0xdf // tag 0xdff9\n\t\t\t\t\t\ttarget[position++] = 0xf9\n\t\t\t\t\t\t// TODO: If we only have one bundle with any string data, only write one string bundle\n\t\t\t\t\t\ttarget[position++] = bundledStrings.position ? 0x84 : 0x82 // array of 4 or 2 elements depending on if we write bundles\n\t\t\t\t\t\ttarget[position++] = 0x1a // 32-bit unsigned int\n\t\t\t\t\t\textStart = position - start\n\t\t\t\t\t\tposition += 4 // reserve for writing bundle reference\n\t\t\t\t\t\tif (bundledStrings.position) {\n\t\t\t\t\t\t\twriteBundles(start, encode) // write the last bundles\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbundledStrings = ['', ''] // create new ones\n\t\t\t\t\t\tbundledStrings.size = 0\n\t\t\t\t\t\tbundledStrings.position = extStart\n\t\t\t\t\t}\n\t\t\t\t\tlet twoByte = hasNonLatin.test(value)\n\t\t\t\t\tbundledStrings[twoByte ? 0 : 1] += value\n\t\t\t\t\ttarget[position++] = twoByte ? 0xce : 0xcf\n\t\t\t\t\tencode(strLength);\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet headerSize\n\t\t\t\t// first we estimate the header size, so we can write to the correct location\n\t\t\t\tif (strLength < 0x20) {\n\t\t\t\t\theaderSize = 1\n\t\t\t\t} else if (strLength < 0x100) {\n\t\t\t\t\theaderSize = 2\n\t\t\t\t} else if (strLength < 0x10000) {\n\t\t\t\t\theaderSize = 3\n\t\t\t\t} else {\n\t\t\t\t\theaderSize = 5\n\t\t\t\t}\n\t\t\t\tlet maxBytes = strLength * 3\n\t\t\t\tif (position + maxBytes > safeEnd)\n\t\t\t\t\ttarget = makeRoom(position + maxBytes)\n\n\t\t\t\tif (strLength < 0x40 || !encodeUtf8) {\n\t\t\t\t\tlet i, c1, c2, strPosition = position + headerSize\n\t\t\t\t\tfor (i = 0; i < strLength; i++) {\n\t\t\t\t\t\tc1 = value.charCodeAt(i)\n\t\t\t\t\t\tif (c1 < 0x80) {\n\t\t\t\t\t\t\ttarget[strPosition++] = c1\n\t\t\t\t\t\t} else if (c1 < 0x800) {\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 6 | 0xc0\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 & 0x3f | 0x80\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t(c1 & 0xfc00) === 0xd800 &&\n\t\t\t\t\t\t\t((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tc1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff)\n\t\t\t\t\t\t\ti++\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 18 | 0xf0\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 12 & 0x3f | 0x80\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 6 & 0x3f | 0x80\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 & 0x3f | 0x80\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 12 | 0xe0\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 6 & 0x3f | 0x80\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 & 0x3f | 0x80\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlength = strPosition - position - headerSize\n\t\t\t\t} else {\n\t\t\t\t\tlength = encodeUtf8(value, position + headerSize, maxBytes)\n\t\t\t\t}\n\n\t\t\t\tif (length < 0x18) {\n\t\t\t\t\ttarget[position++] = 0x60 | length\n\t\t\t\t} else if (length < 0x100) {\n\t\t\t\t\tif (headerSize < 2) {\n\t\t\t\t\t\ttarget.copyWithin(position + 2, position + 1, position + 1 + length)\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0x78\n\t\t\t\t\ttarget[position++] = length\n\t\t\t\t} else if (length < 0x10000) {\n\t\t\t\t\tif (headerSize < 3) {\n\t\t\t\t\t\ttarget.copyWithin(position + 3, position + 2, position + 2 + length)\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0x79\n\t\t\t\t\ttarget[position++] = length >> 8\n\t\t\t\t\ttarget[position++] = length & 0xff\n\t\t\t\t} else {\n\t\t\t\t\tif (headerSize < 5) {\n\t\t\t\t\t\ttarget.copyWithin(position + 5, position + 3, position + 3 + length)\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0x7a\n\t\t\t\t\ttargetView.setUint32(position, length)\n\t\t\t\t\tposition += 4\n\t\t\t\t}\n\t\t\t\tposition += length\n\t\t\t} else if (type === 'number') {\n\t\t\t\tif (!this.alwaysUseFloat && value >>> 0 === value) {// positive integer, 32-bit or less\n\t\t\t\t\t// positive uint\n\t\t\t\t\tif (value < 0x18) {\n\t\t\t\t\t\ttarget[position++] = value\n\t\t\t\t\t} else if (value < 0x100) {\n\t\t\t\t\t\ttarget[position++] = 0x18\n\t\t\t\t\t\ttarget[position++] = value\n\t\t\t\t\t} else if (value < 0x10000) {\n\t\t\t\t\t\ttarget[position++] = 0x19\n\t\t\t\t\t\ttarget[position++] = value >> 8\n\t\t\t\t\t\ttarget[position++] = value & 0xff\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttarget[position++] = 0x1a\n\t\t\t\t\t\ttargetView.setUint32(position, value)\n\t\t\t\t\t\tposition += 4\n\t\t\t\t\t}\n\t\t\t\t} else if (!this.alwaysUseFloat && value >> 0 === value) { // negative integer, 31-bit or less\n\t\t\t\t\tif (value >= -0x18) {\n\t\t\t\t\t\ttarget[position++] = 0x1f - value\n\t\t\t\t\t} else if (value >= -0x100) {\n\t\t\t\t\t\ttarget[position++] = 0x38\n\t\t\t\t\t\ttarget[position++] = ~value\n\t\t\t\t\t} else if (value >= -0x10000) {\n\t\t\t\t\t\ttarget[position++] = 0x39\n\t\t\t\t\t\ttargetView.setUint16(position, ~value)\n\t\t\t\t\t\tposition += 2\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttarget[position++] = 0x3a\n\t\t\t\t\t\ttargetView.setUint32(position, ~value)\n\t\t\t\t\t\tposition += 4\n\t\t\t\t\t}\n\t\t\t\t} else if (!this.alwaysUseFloat && value < 0 && value >= -0x100000000 && Math.floor(value) === value) {\n\t\t\t\t\t// negative integer, 32-bit or less\n\t\t\t\t\ttarget[position++] = 0x3a\n\t\t\t\t\ttargetView.setUint32(position, -1 - value)\n\t\t\t\t\tposition += 4\n\t\t\t\t} else {\n\t\t\t\t\tlet useFloat32\n\t\t\t\t\tif ((useFloat32 = this.useFloat32) > 0 && value < 0x100000000 && value >= -0x80000000) {\n\t\t\t\t\t\ttarget[position++] = 0xfa\n\t\t\t\t\t\ttargetView.setFloat32(position, value)\n\t\t\t\t\t\tlet xShifted\n\t\t\t\t\t\tif (useFloat32 < 4 ||\n\t\t\t\t\t\t\t\t// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved\n\t\t\t\t\t\t\t\t((xShifted = value * mult10[((target[position] & 0x7f) << 1) | (target[position + 1] >> 7)]) >> 0) === xShifted) {\n\t\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t} else\n\t\t\t\t\t\t\tposition-- // move back into position for writing a double\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0xfb\n\t\t\t\t\ttargetView.setFloat64(position, value)\n\t\t\t\t\tposition += 8\n\t\t\t\t}\n\t\t\t} else if (type === 'object') {\n\t\t\t\tif (!value)\n\t\t\t\t\ttarget[position++] = 0xf6\n\t\t\t\telse {\n\t\t\t\t\tif (referenceMap) {\n\t\t\t\t\t\tlet referee = referenceMap.get(value)\n\t\t\t\t\t\tif (referee) {\n\t\t\t\t\t\t\ttarget[position++] = 0xd8\n\t\t\t\t\t\t\ttarget[position++] = 29 // http://cbor.schmorp.de/value-sharing\n\t\t\t\t\t\t\ttarget[position++] = 0x19 // 16-bit uint\n\t\t\t\t\t\t\tif (!referee.references) {\n\t\t\t\t\t\t\t\tlet idsToInsert = referenceMap.idsToInsert || (referenceMap.idsToInsert = [])\n\t\t\t\t\t\t\t\treferee.references = []\n\t\t\t\t\t\t\t\tidsToInsert.push(referee)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treferee.references.push(position - start)\n\t\t\t\t\t\t\tposition += 2 // TODO: also support 32-bit\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t} else \n\t\t\t\t\t\t\treferenceMap.set(value, { offset: position - start })\n\t\t\t\t\t}\n\t\t\t\t\tlet constructor = value.constructor\n\t\t\t\t\tif (constructor === Object) {\n\t\t\t\t\t\tif (this.skipFunction === true) {\n\t\t\t\t\t\t\tvalue = Object.fromEntries([...Object.keys(value).filter(x => typeof value[x] !== \"function\").map(x => [x, value[x]])]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\twriteObject(value)\n\t\t\t\t\t} else if (constructor === Array) {\n\t\t\t\t\t\tlength = value.length\n\t\t\t\t\t\tif (length < 0x18) {\n\t\t\t\t\t\t\ttarget[position++] = 0x80 | length\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twriteArrayHeader(length)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\t\t\tencode(value[i])\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (constructor === Map) {\n\t\t\t\t\t\tif (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {\n\t\t\t\t\t\t\t// use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way\n\t\t\t\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\t\t\t\ttarget[position++] = 1\n\t\t\t\t\t\t\ttarget[position++] = 3\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlength = value.size\n\t\t\t\t\t\tif (length < 0x18) {\n\t\t\t\t\t\t\ttarget[position++] = 0xa0 | length\n\t\t\t\t\t\t} else if (length < 0x100) {\n\t\t\t\t\t\t\ttarget[position++] = 0xb8\n\t\t\t\t\t\t\ttarget[position++] = length\n\t\t\t\t\t\t} else if (length < 0x10000) {\n\t\t\t\t\t\t\ttarget[position++] = 0xb9\n\t\t\t\t\t\t\ttarget[position++] = length >> 8\n\t\t\t\t\t\t\ttarget[position++] = length & 0xff\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttarget[position++] = 0xba\n\t\t\t\t\t\t\ttargetView.setUint32(position, length)\n\t\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (encoder.keyMap) { \n\t\t\t\t\t\t\tfor (let [ key, entryValue ] of value) {\n\t\t\t\t\t\t\t\tencode(encoder.encodeKey(key))\n\t\t\t\t\t\t\t\tencode(entryValue)\n\t\t\t\t\t\t\t} \n\t\t\t\t\t\t} else { \n\t\t\t\t\t\t\tfor (let [ key, entryValue ] of value) {\n\t\t\t\t\t\t\t\tencode(key) \n\t\t\t\t\t\t\t\tencode(entryValue)\n\t\t\t\t\t\t\t} \t\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (let i = 0, l = extensions.length; i < l; i++) {\n\t\t\t\t\t\t\tlet extensionClass = extensionClasses[i]\n\t\t\t\t\t\t\tif (value instanceof extensionClass) {\n\t\t\t\t\t\t\t\tlet extension = extensions[i]\n\t\t\t\t\t\t\t\tlet tag = extension.tag\n\t\t\t\t\t\t\t\tif (tag == undefined)\n\t\t\t\t\t\t\t\t\ttag = extension.getTag && extension.getTag.call(this, value)\n\t\t\t\t\t\t\t\tif (tag < 0x18) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xc0 | tag\n\t\t\t\t\t\t\t\t} else if (tag < 0x100) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xd8\n\t\t\t\t\t\t\t\t\ttarget[position++] = tag\n\t\t\t\t\t\t\t\t} else if (tag < 0x10000) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\t\t\t\t\t\ttarget[position++] = tag >> 8\n\t\t\t\t\t\t\t\t\ttarget[position++] = tag & 0xff\n\t\t\t\t\t\t\t\t} else if (tag > -1) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xda\n\t\t\t\t\t\t\t\t\ttargetView.setUint32(position, tag)\n\t\t\t\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\t\t\t} // else undefined, don't write tag\n\t\t\t\t\t\t\t\textension.encode.call(this, value, encode, makeRoom)\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value[Symbol.iterator]) {\n\t\t\t\t\t\t\tif (throwOnIterable) {\n\t\t\t\t\t\t\t\tlet error = new Error('Iterable should be serialized as iterator')\n\t\t\t\t\t\t\t\terror.iteratorNotHandled = true;\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttarget[position++] = 0x9f // indefinite length array\n\t\t\t\t\t\t\tfor (let entry of value) {\n\t\t\t\t\t\t\t\tencode(entry)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttarget[position++] = 0xff // stop-code\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value[Symbol.asyncIterator] || isBlob(value)) {\n\t\t\t\t\t\t\tlet error = new Error('Iterable/blob should be serialized as iterator')\n\t\t\t\t\t\t\terror.iteratorNotHandled = true;\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (this.useToJSON && value.toJSON) {\n\t\t\t\t\t\t\tconst json = value.toJSON()\n\t\t\t\t\t\t\t// if for some reason value.toJSON returns itself it'll loop forever\n\t\t\t\t\t\t\tif (json !== value)\n\t\t\t\t\t\t\t\treturn encode(json)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// no extension found, write as a plain object\n\t\t\t\t\t\twriteObject(value)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (type === 'boolean') {\n\t\t\t\ttarget[position++] = value ? 0xf5 : 0xf4\n\t\t\t} else if (type === 'bigint') {\n\t\t\t\tif (value < (BigInt(1)<= 0) {\n\t\t\t\t\t// use an unsigned int as long as it fits\n\t\t\t\t\ttarget[position++] = 0x1b\n\t\t\t\t\ttargetView.setBigUint64(position, value)\n\t\t\t\t} else if (value > -(BigInt(1)<= BigInt(0))\n\t\t\t\t\t\t\ttarget[position++] = 0xc2 // tag 2\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttarget[position++] = 0xc3 // tag 2\n\t\t\t\t\t\t\tvalue = BigInt(-1) - value;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlet bytes = [];\n\t\t\t\t\t\twhile (value) {\n\t\t\t\t\t\t\tbytes.push(Number(value & BigInt(0xff)));\n\t\t\t\t\t\t\tvalue >>= BigInt(8);\n\t\t\t\t\t\t}\n\t\t\t\t\t\twriteBuffer(new Uint8Array(bytes.reverse()), makeRoom);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tposition += 8\n\t\t\t} else if (type === 'undefined') {\n\t\t\t\ttarget[position++] = 0xf7\n\t\t\t} else {\n\t\t\t\tthrow new Error('Unknown type: ' + type)\n\t\t\t}\n\t\t}\n\n\t\tconst writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {\n\t\t\t// this method is slightly slower, but generates \"preferred serialization\" (optimally small for smaller objects)\n\t\t\tlet keys = Object.keys(object)\n\t\t\tlet vals = Object.values(object)\n\t\t\tlet length = keys.length\n\t\t\tif (length < 0x18) {\n\t\t\t\ttarget[position++] = 0xa0 | length\n\t\t\t} else if (length < 0x100) {\n\t\t\t\ttarget[position++] = 0xb8\n\t\t\t\ttarget[position++] = length\n\t\t\t} else if (length < 0x10000) {\n\t\t\t\ttarget[position++] = 0xb9\n\t\t\t\ttarget[position++] = length >> 8\n\t\t\t\ttarget[position++] = length & 0xff\n\t\t\t} else {\n\t\t\t\ttarget[position++] = 0xba\n\t\t\t\ttargetView.setUint32(position, length)\n\t\t\t\tposition += 4\n\t\t\t}\n\t\t\tlet key\n\t\t\tif (encoder.keyMap) { \n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tencode(encoder.encodeKey(keys[i]))\n\t\t\t\t\tencode(vals[i])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tencode(keys[i])\n\t\t\t\t\tencode(vals[i])\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\t\t(object) => {\n\t\t\ttarget[position++] = 0xb9 // always use map 16, so we can preallocate and set the length afterwards\n\t\t\tlet objectOffset = position - start\n\t\t\tposition += 2\n\t\t\tlet size = 0\n\t\t\tif (encoder.keyMap) {\n\t\t\t\tfor (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {\n\t\t\t\t\tencode(encoder.encodeKey(key))\n\t\t\t\t\tencode(object[key])\n\t\t\t\t\tsize++\n\t\t\t\t}\n\t\t\t} else { \n\t\t\t\tfor (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {\n\t\t\t\t\t\tencode(key)\n\t\t\t\t\t\tencode(object[key])\n\t\t\t\t\tsize++\n\t\t\t\t}\n\t\t\t}\n\t\t\ttarget[objectOffset++ + start] = size >> 8\n\t\t\ttarget[objectOffset + start] = size & 0xff\n\t\t} :\n\t\t(object, skipValues) => {\n\t\t\tlet nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))\n\t\t\tlet newTransitions = 0\n\t\t\tlet length = 0\n\t\t\tlet parentRecordId\n\t\t\tlet keys\n\t\t\tif (this.keyMap) {\n\t\t\t\tkeys = Object.keys(object).map(k => this.encodeKey(k))\n\t\t\t\tlength = keys.length\n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tlet key = keys[i]\n\t\t\t\t\tnextTransition = transition[key]\n\t\t\t\t\tif (!nextTransition) {\n\t\t\t\t\t\tnextTransition = transition[key] = Object.create(null)\n\t\t\t\t\t\tnewTransitions++\n\t\t\t\t\t}\n\t\t\t\t\ttransition = nextTransition\n\t\t\t\t}\t\t\t\t\n\t\t\t} else {\n\t\t\t\tfor (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {\n\t\t\t\t\tnextTransition = transition[key]\n\t\t\t\t\tif (!nextTransition) {\n\t\t\t\t\t\tif (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it\n\t\t\t\t\t\t\tparentRecordId = transition[RECORD_SYMBOL] & 0xffff\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnextTransition = transition[key] = Object.create(null)\n\t\t\t\t\t\tnewTransitions++\n\t\t\t\t\t}\n\t\t\t\t\ttransition = nextTransition\n\t\t\t\t\tlength++\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet recordId = transition[RECORD_SYMBOL]\n\t\t\tif (recordId !== undefined) {\n\t\t\t\trecordId &= 0xffff\n\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\ttarget[position++] = (recordId >> 8) | 0xe0\n\t\t\t\ttarget[position++] = recordId & 0xff\n\t\t\t} else {\n\t\t\t\tif (!keys)\n\t\t\t\t\tkeys = transition.__keys__ || (transition.__keys__ = Object.keys(object))\n\t\t\t\tif (parentRecordId === undefined) {\n\t\t\t\t\trecordId = structures.nextId++\n\t\t\t\t\tif (!recordId) {\n\t\t\t\t\t\trecordId = 0\n\t\t\t\t\t\tstructures.nextId = 1\n\t\t\t\t\t}\n\t\t\t\t\tif (recordId >= MAX_STRUCTURES) {// cycle back around\n\t\t\t\t\t\tstructures.nextId = (recordId = maxSharedStructures) + 1\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\trecordId = parentRecordId\n\t\t\t\t}\n\t\t\t\tstructures[recordId] = keys\n\t\t\t\tif (recordId < maxSharedStructures) {\n\t\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\t\ttarget[position++] = (recordId >> 8) | 0xe0\n\t\t\t\t\ttarget[position++] = recordId & 0xff\n\t\t\t\t\ttransition = structures.transitions\n\t\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\t\tif (transition[RECORD_SYMBOL] === undefined || (transition[RECORD_SYMBOL] & 0x100000))\n\t\t\t\t\t\t\ttransition[RECORD_SYMBOL] = recordId\n\t\t\t\t\t\ttransition = transition[keys[i]]\n\t\t\t\t\t}\n\t\t\t\t\ttransition[RECORD_SYMBOL] = recordId | 0x100000 // indicates it is a extendable terminal\n\t\t\t\t\thasSharedUpdate = true\n\t\t\t\t} else {\n\t\t\t\t\ttransition[RECORD_SYMBOL] = recordId\n\t\t\t\t\ttargetView.setUint32(position, 0xd9dfff00) // tag two byte, then record definition id\n\t\t\t\t\tposition += 3\n\t\t\t\t\tif (newTransitions)\n\t\t\t\t\t\ttransitionsCount += serializationsSinceTransitionRebuild * newTransitions\n\t\t\t\t\t// record the removal of the id, we can maintain our shared structure\n\t\t\t\t\tif (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)\n\t\t\t\t\t\trecordIdsToRemove.shift()[RECORD_SYMBOL] = undefined // we are cycling back through, and have to remove old ones\n\t\t\t\t\trecordIdsToRemove.push(transition)\n\t\t\t\t\twriteArrayHeader(length + 2)\n\t\t\t\t\tencode(0xe000 + recordId)\n\t\t\t\t\tencode(keys)\n\t\t\t\t\tif (skipValues) return; // special exit for iterator\n\t\t\t\t\tfor (let key in object)\n\t\t\t\t\t\tif (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))\n\t\t\t\t\t\t\tencode(object[key])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (length < 0x18) { // write the array header\n\t\t\t\ttarget[position++] = 0x80 | length\n\t\t\t} else {\n\t\t\t\twriteArrayHeader(length)\n\t\t\t}\n\t\t\tif (skipValues) return; // special exit for iterator\n\t\t\tfor (let key in object)\n\t\t\t\tif (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))\n\t\t\t\t\tencode(object[key])\n\t\t}\n\t\tconst makeRoom = (end) => {\n\t\t\tlet newSize\n\t\t\tif (end > 0x1000000) {\n\t\t\t\t// special handling for really large buffers\n\t\t\t\tif ((end - start) > MAX_BUFFER_SIZE)\n\t\t\t\t\tthrow new Error('Encoded buffer would be larger than maximum buffer size')\n\t\t\t\tnewSize = Math.min(MAX_BUFFER_SIZE,\n\t\t\t\t\tMath.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000)\n\t\t\t} else // faster handling for smaller buffers\n\t\t\t\tnewSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12\n\t\t\tlet newBuffer = new ByteArrayAllocate(newSize)\n\t\t\ttargetView = new DataView(newBuffer.buffer, 0, newSize)\n\t\t\tif (target.copy)\n\t\t\t\ttarget.copy(newBuffer, 0, start, end)\n\t\t\telse\n\t\t\t\tnewBuffer.set(target.slice(start, end))\n\t\t\tposition -= start\n\t\t\tstart = 0\n\t\t\tsafeEnd = newBuffer.length - 10\n\t\t\treturn target = newBuffer\n\t\t}\n\t\tlet chunkThreshold = 100;\n\t\tlet continuedChunkThreshold = 1000;\n\t\tthis.encodeAsIterable = function(value, options) {\n\t\t\treturn startEncoding(value, options, encodeObjectAsIterable);\n\t\t}\n\t\tthis.encodeAsAsyncIterable = function(value, options) {\n\t\t\treturn startEncoding(value, options, encodeObjectAsAsyncIterable);\n\t\t}\n\n\t\tfunction* encodeObjectAsIterable(object, iterateProperties, finalIterable) {\n\t\t\tlet constructor = object.constructor;\n\t\t\tif (constructor === Object) {\n\t\t\t\tlet useRecords = encoder.useRecords !== false;\n\t\t\t\tif (useRecords)\n\t\t\t\t\twriteObject(object, true); // write the record identifier\n\t\t\t\telse\n\t\t\t\t\twriteEntityLength(Object.keys(object).length, 0xa0);\n\t\t\t\tfor (let key in object) {\n\t\t\t\t\tlet value = object[key];\n\t\t\t\t\tif (!useRecords) encode(key);\n\t\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\t\tif (iterateProperties[key])\n\t\t\t\t\t\t\tyield* encodeObjectAsIterable(value, iterateProperties[key]);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyield* tryEncode(value, iterateProperties, key);\n\t\t\t\t\t} else encode(value);\n\t\t\t\t}\n\t\t\t} else if (constructor === Array) {\n\t\t\t\tlet length = object.length;\n\t\t\t\twriteArrayHeader(length);\n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tlet value = object[i];\n\t\t\t\t\tif (value && (typeof value === 'object' || position - start > chunkThreshold)) {\n\t\t\t\t\t\tif (iterateProperties.element)\n\t\t\t\t\t\t\tyield* encodeObjectAsIterable(value, iterateProperties.element);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyield* tryEncode(value, iterateProperties, 'element');\n\t\t\t\t\t} else encode(value);\n\t\t\t\t}\n\t\t\t} else if (object[Symbol.iterator] && !object.buffer) { // iterator, but exclude typed arrays\n\t\t\t\ttarget[position++] = 0x9f; // start indefinite array\n\t\t\t\tfor (let value of object) {\n\t\t\t\t\tif (value && (typeof value === 'object' || position - start > chunkThreshold)) {\n\t\t\t\t\t\tif (iterateProperties.element)\n\t\t\t\t\t\t\tyield* encodeObjectAsIterable(value, iterateProperties.element);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyield* tryEncode(value, iterateProperties, 'element');\n\t\t\t\t\t} else encode(value);\n\t\t\t\t}\n\t\t\t\ttarget[position++] = 0xff; // stop byte\n\t\t\t} else if (isBlob(object)){\n\t\t\t\twriteEntityLength(object.size, 0x40); // encode as binary data\n\t\t\t\tyield target.subarray(start, position);\n\t\t\t\tyield object; // directly return blobs, they have to be encoded asynchronously\n\t\t\t\trestartEncoding();\n\t\t\t} else if (object[Symbol.asyncIterator]) {\n\t\t\t\ttarget[position++] = 0x9f; // start indefinite array\n\t\t\t\tyield target.subarray(start, position);\n\t\t\t\tyield object; // directly return async iterators, they have to be encoded asynchronously\n\t\t\t\trestartEncoding();\n\t\t\t\ttarget[position++] = 0xff; // stop byte\n\t\t\t} else {\n\t\t\t\tencode(object);\n\t\t\t}\n\t\t\tif (finalIterable && position > start) yield target.subarray(start, position);\n\t\t\telse if (position - start > chunkThreshold) {\n\t\t\t\tyield target.subarray(start, position);\n\t\t\t\trestartEncoding();\n\t\t\t}\n\t\t}\n\t\tfunction* tryEncode(value, iterateProperties, key) {\n\t\t\tlet restart = position - start;\n\t\t\ttry {\n\t\t\t\tencode(value);\n\t\t\t\tif (position - start > chunkThreshold) {\n\t\t\t\t\tyield target.subarray(start, position);\n\t\t\t\t\trestartEncoding();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (error.iteratorNotHandled) {\n\t\t\t\t\titerateProperties[key] = {};\n\t\t\t\t\tposition = start + restart; // restart our position so we don't have partial data from last encode\n\t\t\t\t\tyield* encodeObjectAsIterable.call(this, value, iterateProperties[key]);\n\t\t\t\t} else throw error;\n\t\t\t}\n\t\t}\n\t\tfunction restartEncoding() {\n\t\t\tchunkThreshold = continuedChunkThreshold;\n\t\t\tencoder.encode(null, THROW_ON_ITERABLE); // restart encoding\n\t\t}\n\t\tfunction startEncoding(value, options, encodeIterable) {\n\t\t\tif (options && options.chunkThreshold) // explicitly specified chunk sizes\n\t\t\t\tchunkThreshold = continuedChunkThreshold = options.chunkThreshold;\n\t\t\telse // we start with a smaller threshold to get initial bytes sent quickly\n\t\t\t\tchunkThreshold = 100;\n\t\t\tif (value && typeof value === 'object') {\n\t\t\t\tencoder.encode(null, THROW_ON_ITERABLE); // start encoding\n\t\t\t\treturn encodeIterable(value, encoder.iterateProperties || (encoder.iterateProperties = {}), true);\n\t\t\t}\n\t\t\treturn [encoder.encode(value)];\n\t\t}\n\n\t\tasync function* encodeObjectAsAsyncIterable(value, iterateProperties) {\n\t\t\tfor (let encodedValue of encodeObjectAsIterable(value, iterateProperties, true)) {\n\t\t\t\tlet constructor = encodedValue.constructor;\n\t\t\t\tif (constructor === ByteArray || constructor === Uint8Array)\n\t\t\t\t\tyield encodedValue;\n\t\t\t\telse if (isBlob(encodedValue)) {\n\t\t\t\t\tlet reader = encodedValue.stream().getReader();\n\t\t\t\t\tlet next;\n\t\t\t\t\twhile (!(next = await reader.read()).done) {\n\t\t\t\t\t\tyield next.value;\n\t\t\t\t\t}\n\t\t\t\t} else if (encodedValue[Symbol.asyncIterator]) {\n\t\t\t\t\tfor await (let asyncValue of encodedValue) {\n\t\t\t\t\t\trestartEncoding();\n\t\t\t\t\t\tif (asyncValue)\n\t\t\t\t\t\t\tyield* encodeObjectAsAsyncIterable(asyncValue, iterateProperties.async || (iterateProperties.async = {}));\n\t\t\t\t\t\telse yield encoder.encode(asyncValue);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tyield encodedValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tuseBuffer(buffer) {\n\t\t// this means we are finished using our own buffer and we can write over it safely\n\t\ttarget = buffer\n\t\ttargetView = new DataView(target.buffer, target.byteOffset, target.byteLength)\n\t\tposition = 0\n\t}\n\tclearSharedData() {\n\t\tif (this.structures)\n\t\t\tthis.structures = []\n\t\tif (this.sharedValues)\n\t\t\tthis.sharedValues = undefined\n\t}\n\tupdateSharedData() {\n\t\tlet lastVersion = this.sharedVersion || 0\n\t\tthis.sharedVersion = lastVersion + 1\n\t\tlet structuresCopy = this.structures.slice(0)\n\t\tlet sharedData = new SharedData(structuresCopy, this.sharedValues, this.sharedVersion)\n\t\tlet saveResults = this.saveShared(sharedData,\n\t\t\t\texistingShared => (existingShared && existingShared.version || 0) == lastVersion)\n\t\tif (saveResults === false) {\n\t\t\t// get updated structures and try again if the update failed\n\t\t\tsharedData = this.getShared() || {}\n\t\t\tthis.structures = sharedData.structures || []\n\t\t\tthis.sharedValues = sharedData.packedValues\n\t\t\tthis.sharedVersion = sharedData.version\n\t\t\tthis.structures.nextId = this.structures.length\n\t\t} else {\n\t\t\t// restore structures\n\t\t\tstructuresCopy.forEach((structure, i) => this.structures[i] = structure)\n\t\t}\n\t\t// saveShared may fail to write and reload, or may have reloaded to check compatibility and overwrite saved data, either way load the correct shared data\n\t\treturn saveResults\n\t}\n}\nfunction writeEntityLength(length, majorValue) {\n\tif (length < 0x18)\n\t\ttarget[position++] = majorValue | length\n\telse if (length < 0x100) {\n\t\ttarget[position++] = majorValue | 0x18\n\t\ttarget[position++] = length\n\t} else if (length < 0x10000) {\n\t\ttarget[position++] = majorValue | 0x19\n\t\ttarget[position++] = length >> 8\n\t\ttarget[position++] = length & 0xff\n\t} else {\n\t\ttarget[position++] = majorValue | 0x1a\n\t\ttargetView.setUint32(position, length)\n\t\tposition += 4\n\t}\n\n}\nclass SharedData {\n\tconstructor(structures, values, version) {\n\t\tthis.structures = structures\n\t\tthis.packedValues = values\n\t\tthis.version = version\n\t}\n}\n\nfunction writeArrayHeader(length) {\n\tif (length < 0x18)\n\t\ttarget[position++] = 0x80 | length\n\telse if (length < 0x100) {\n\t\ttarget[position++] = 0x98\n\t\ttarget[position++] = length\n\t} else if (length < 0x10000) {\n\t\ttarget[position++] = 0x99\n\t\ttarget[position++] = length >> 8\n\t\ttarget[position++] = length & 0xff\n\t} else {\n\t\ttarget[position++] = 0x9a\n\t\ttargetView.setUint32(position, length)\n\t\tposition += 4\n\t}\n}\n\nconst BlobConstructor = typeof Blob === 'undefined' ? function(){} : Blob;\nfunction isBlob(object) {\n\tif (object instanceof BlobConstructor)\n\t\treturn true;\n\tlet tag = object[Symbol.toStringTag];\n\treturn tag === 'Blob' || tag === 'File';\n}\nfunction findRepetitiveStrings(value, packedValues) {\n\tswitch(typeof value) {\n\t\tcase 'string':\n\t\t\tif (value.length > 3) {\n\t\t\t\tif (packedValues.objectMap[value] > -1 || packedValues.values.length >= packedValues.maxValues)\n\t\t\t\t\treturn\n\t\t\t\tlet packedStatus = packedValues.get(value)\n\t\t\t\tif (packedStatus) {\n\t\t\t\t\tif (++packedStatus.count == 2) {\n\t\t\t\t\t\tpackedValues.values.push(value)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpackedValues.set(value, {\n\t\t\t\t\t\tcount: 1,\n\t\t\t\t\t})\n\t\t\t\t\tif (packedValues.samplingPackedValues) {\n\t\t\t\t\t\tlet status = packedValues.samplingPackedValues.get(value)\n\t\t\t\t\t\tif (status)\n\t\t\t\t\t\t\tstatus.count++\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tpackedValues.samplingPackedValues.set(value, {\n\t\t\t\t\t\t\t\tcount: 1,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'object':\n\t\t\tif (value) {\n\t\t\t\tif (value instanceof Array) {\n\t\t\t\t\tfor (let i = 0, l = value.length; i < l; i++) {\n\t\t\t\t\t\tfindRepetitiveStrings(value[i], packedValues)\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\tlet includeKeys = !packedValues.encoder.useRecords\n\t\t\t\t\tfor (var key in value) {\n\t\t\t\t\t\tif (value.hasOwnProperty(key)) {\n\t\t\t\t\t\t\tif (includeKeys)\n\t\t\t\t\t\t\t\tfindRepetitiveStrings(key, packedValues)\n\t\t\t\t\t\t\tfindRepetitiveStrings(value[key], packedValues)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'function': console.log(value)\n\t}\n}\nconst isLittleEndianMachine = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1\nextensionClasses = [ Date, Set, Error, RegExp, Tag, ArrayBuffer,\n\tUint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,\n\ttypeof BigUint64Array == 'undefined' ? function() {} : BigUint64Array, Int8Array, Int16Array, Int32Array,\n\ttypeof BigInt64Array == 'undefined' ? function() {} : BigInt64Array,\n\tFloat32Array, Float64Array, SharedData ]\n\n//Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/\nextensions = [{ // Date\n\ttag: 1,\n\tencode(date, encode) {\n\t\tlet seconds = date.getTime() / 1000\n\t\tif ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {\n\t\t\t// Timestamp 32\n\t\t\ttarget[position++] = 0x1a\n\t\t\ttargetView.setUint32(position, seconds)\n\t\t\tposition += 4\n\t\t} else {\n\t\t\t// Timestamp float64\n\t\t\ttarget[position++] = 0xfb\n\t\t\ttargetView.setFloat64(position, seconds)\n\t\t\tposition += 8\n\t\t}\n\t}\n}, { // Set\n\ttag: 258, // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md\n\tencode(set, encode) {\n\t\tlet array = Array.from(set)\n\t\tencode(array)\n\t}\n}, { // Error\n\ttag: 27, // http://cbor.schmorp.de/generic-object\n\tencode(error, encode) {\n\t\tencode([ error.name, error.message ])\n\t}\n}, { // RegExp\n\ttag: 27, // http://cbor.schmorp.de/generic-object\n\tencode(regex, encode) {\n\t\tencode([ 'RegExp', regex.source, regex.flags ])\n\t}\n}, { // Tag\n\tgetTag(tag) {\n\t\treturn tag.tag\n\t},\n\tencode(tag, encode) {\n\t\tencode(tag.value)\n\t}\n}, { // ArrayBuffer\n\tencode(arrayBuffer, encode, makeRoom) {\n\t\twriteBuffer(arrayBuffer, makeRoom)\n\t}\n}, { // Uint8Array\n\tgetTag(typedArray) {\n\t\tif (typedArray.constructor === Uint8Array) {\n\t\t\tif (this.tagUint8Array || hasNodeBuffer && this.tagUint8Array !== false)\n\t\t\t\treturn 64;\n\t\t} // else no tag\n\t},\n\tencode(typedArray, encode, makeRoom) {\n\t\twriteBuffer(typedArray, makeRoom)\n\t}\n},\n\ttypedArrayEncoder(68, 1),\n\ttypedArrayEncoder(69, 2),\n\ttypedArrayEncoder(70, 4),\n\ttypedArrayEncoder(71, 8),\n\ttypedArrayEncoder(72, 1),\n\ttypedArrayEncoder(77, 2),\n\ttypedArrayEncoder(78, 4),\n\ttypedArrayEncoder(79, 8),\n\ttypedArrayEncoder(85, 4),\n\ttypedArrayEncoder(86, 8),\n{\n\tencode(sharedData, encode) { // write SharedData\n\t\tlet packedValues = sharedData.packedValues || []\n\t\tlet sharedStructures = sharedData.structures || []\n\t\tif (packedValues.values.length > 0) {\n\t\t\ttarget[position++] = 0xd8 // one-byte tag\n\t\t\ttarget[position++] = 51 // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\twriteArrayHeader(4)\n\t\t\tlet valuesArray = packedValues.values\n\t\t\tencode(valuesArray)\n\t\t\twriteArrayHeader(0) // prefixes\n\t\t\twriteArrayHeader(0) // suffixes\n\t\t\tpackedObjectMap = Object.create(sharedPackedObjectMap || null)\n\t\t\tfor (let i = 0, l = valuesArray.length; i < l; i++) {\n\t\t\t\tpackedObjectMap[valuesArray[i]] = i\n\t\t\t}\n\t\t}\n\t\tif (sharedStructures) {\n\t\t\ttargetView.setUint32(position, 0xd9dffe00)\n\t\t\tposition += 3\n\t\t\tlet definitions = sharedStructures.slice(0)\n\t\t\tdefinitions.unshift(0xe000)\n\t\t\tdefinitions.push(new Tag(sharedData.version, 0x53687264))\n\t\t\tencode(definitions)\n\t\t} else\n\t\t\tencode(new Tag(sharedData.version, 0x53687264))\n\t\t}\n\t}]\nfunction typedArrayEncoder(tag, size) {\n\tif (!isLittleEndianMachine && size > 1)\n\t\ttag -= 4 // the big endian equivalents are 4 less\n\treturn {\n\t\ttag: tag,\n\t\tencode: function writeExtBuffer(typedArray, encode) {\n\t\t\tlet length = typedArray.byteLength\n\t\t\tlet offset = typedArray.byteOffset || 0\n\t\t\tlet buffer = typedArray.buffer || typedArray\n\t\t\tencode(hasNodeBuffer ? Buffer.from(buffer, offset, length) :\n\t\t\t\tnew Uint8Array(buffer, offset, length))\n\t\t}\n\t}\n}\nfunction writeBuffer(buffer, makeRoom) {\n\tlet length = buffer.byteLength\n\tif (length < 0x18) {\n\t\ttarget[position++] = 0x40 + length\n\t} else if (length < 0x100) {\n\t\ttarget[position++] = 0x58\n\t\ttarget[position++] = length\n\t} else if (length < 0x10000) {\n\t\ttarget[position++] = 0x59\n\t\ttarget[position++] = length >> 8\n\t\ttarget[position++] = length & 0xff\n\t} else {\n\t\ttarget[position++] = 0x5a\n\t\ttargetView.setUint32(position, length)\n\t\tposition += 4\n\t}\n\tif (position + length >= target.length) {\n\t\tmakeRoom(position + length)\n\t}\n\t// if it is already a typed array (has an ArrayBuffer), use that, but if it is an ArrayBuffer itself,\n\t// must wrap it to set it.\n\ttarget.set(buffer.buffer ? buffer : new Uint8Array(buffer), position)\n\tposition += length\n}\n\nfunction insertIds(serialized, idsToInsert) {\n\t// insert the ids that need to be referenced for structured clones\n\tlet nextId\n\tlet distanceToMove = idsToInsert.length * 2\n\tlet lastEnd = serialized.length - distanceToMove\n\tidsToInsert.sort((a, b) => a.offset > b.offset ? 1 : -1)\n\tfor (let id = 0; id < idsToInsert.length; id++) {\n\t\tlet referee = idsToInsert[id]\n\t\treferee.id = id\n\t\tfor (let position of referee.references) {\n\t\t\tserialized[position++] = id >> 8\n\t\t\tserialized[position] = id & 0xff\n\t\t}\n\t}\n\twhile (nextId = idsToInsert.pop()) {\n\t\tlet offset = nextId.offset\n\t\tserialized.copyWithin(offset + distanceToMove, offset, lastEnd)\n\t\tdistanceToMove -= 2\n\t\tlet position = offset + distanceToMove\n\t\tserialized[position++] = 0xd8\n\t\tserialized[position++] = 28 // http://cbor.schmorp.de/value-sharing\n\t\tlastEnd = offset\n\t}\n\treturn serialized\n}\nfunction writeBundles(start, encode) {\n\ttargetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start + 1) // the offset to bundle\n\tlet writeStrings = bundledStrings\n\tbundledStrings = null\n\tencode(writeStrings[0])\n\tencode(writeStrings[1])\n}\n\nexport function addExtension(extension) {\n\tif (extension.Class) {\n\t\tif (!extension.encode)\n\t\t\tthrow new Error('Extension has no encode function')\n\t\textensionClasses.unshift(extension.Class)\n\t\textensions.unshift(extension)\n\t}\n\tdecodeAddExtension(extension)\n}\nlet defaultEncoder = new Encoder({ useRecords: false })\nexport const encode = defaultEncoder.encode\nexport const encodeAsIterable = defaultEncoder.encodeAsIterable\nexport const encodeAsAsyncIterable = defaultEncoder.encodeAsAsyncIterable\nexport { FLOAT32_OPTIONS } from './decode.js'\nimport { FLOAT32_OPTIONS } from './decode.js'\nexport const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS\nexport const REUSE_BUFFER_MODE = 512\nexport const RESET_BUFFER_MODE = 1024\nexport const THROW_ON_ITERABLE = 2048\n\n\n","import { Encoder, decode } from 'cbor-x';\n\nconst encoder = new Encoder({ tagUint8Array: false });\n\n// Message types (must match client_api_wire.h)\nexport const MSG = {\n PUT_REQUEST: 1,\n PUT_DATA: 2,\n PUT_END: 3,\n PUT_RESPONSE: 4,\n GET_REQUEST: 5,\n GET_RESPONSE_START: 6,\n GET_DATA: 7,\n GET_END: 8,\n ERROR: 11,\n AUTH_REQUEST: 12,\n BLOCK_PUT_REQUEST: 13,\n BLOCK_PUT_RESPONSE: 14,\n BLOCK_GET_REQUEST: 15,\n BLOCK_GET_RESPONSE: 16,\n BLOCK_DELETE_REQUEST: 17,\n BLOCK_DELETE_RESPONSE: 18,\n HEALTH_REQUEST: 19,\n HEALTH_RESPONSE: 20,\n PEER_INFO_REQUEST: 21,\n PEER_INFO_RESPONSE: 22,\n PEER_CONNECT: 23,\n PEER_CONNECT_RESULT: 24,\n PEER_LIST_REQUEST: 25,\n PEER_LIST_RESPONSE: 26,\n FRIEND_ADD: 27,\n FRIEND_REMOVE: 28,\n FRIEND_LIST: 29,\n FRIEND_LIST_RESPONSE: 30,\n UPDATE_STATUS_REQUEST: 31,\n UPDATE_STATUS_RESPONSE: 32,\n CONFIG_SHOW_REQUEST: 33,\n CONFIG_SHOW_RESPONSE: 34,\n CONFIG_SET_REQUEST: 35,\n CONFIG_SET_RESPONSE: 36,\n CONFIG_RELOAD_REQUEST: 37,\n CONFIG_RELOAD_RESPONSE: 38\n};\n\nexport const STATUS = {\n OK: 0,\n BAD_REQUEST: 1,\n NOT_FOUND: 2,\n INTERNAL_ERROR: 3,\n RANGE_NOT_SATISFIABLE: 4,\n UNAUTHORIZED: 5\n};\n\n/**\n * @param {Uint8Array} bytes\n * @returns {number}\n */\nexport function getMessageType(bytes) {\n const arr = decode(bytes);\n return Array.isArray(arr) ? arr[0] : null;\n}\n\n// --- Auth ---\n\n/**\n * @param {string} apiKey\n * @returns {Uint8Array}\n */\nexport function encodeAuthRequest(apiKey) {\n const keyBytes = new TextEncoder().encode(apiKey);\n return encoder.encode([MSG.AUTH_REQUEST, keyBytes]);\n}\n\n// --- PUT ---\n\n/**\n * @param {import('./types.js').OffsPutOptions} options\n * @param {Uint8Array|null} data\n * @returns {Uint8Array}\n */\nexport function encodePutRequest(options, data = null) {\n const recycler = options.recyclerUrls || [];\n const payload = [\n MSG.PUT_REQUEST,\n options.contentType,\n options.fileName,\n options.streamLength,\n options.serverAddress || null,\n data || new Uint8Array(0),\n recycler,\n options.temporary ? 1 : 0\n ];\n if (options.tupleSize !== undefined) {\n payload.push(options.tupleSize);\n }\n return encoder.encode(payload);\n}\n\n/**\n * @param {Uint8Array} chunk\n * @returns {Uint8Array}\n */\nexport function encodePutData(chunk) {\n return encoder.encode([MSG.PUT_DATA, chunk]);\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodePutEnd() {\n return encoder.encode([MSG.PUT_END]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{oriString: string}}\n */\nexport function decodePutResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PUT_RESPONSE) throw new Error('Not a put response');\n return { oriString: arr[1] };\n}\n\n// --- GET ---\n\n/**\n * @param {string} oriString\n * @param {{start?: number, end?: number}} [range]\n * @returns {Uint8Array}\n */\nexport function encodeGetRequest(oriString, range) {\n const hasRange = range && (range.start !== undefined || range.end !== undefined);\n const payload = [MSG.GET_REQUEST, oriString, hasRange ? 1 : 0];\n if (hasRange) {\n payload.push(range.start || 0);\n payload.push(range.end || 0);\n }\n return encoder.encode(payload);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{contentType: string, contentLength: number, hasRange: boolean, rangeStart?: number, rangeEnd?: number}}\n */\nexport function decodeGetResponseStart(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.GET_RESPONSE_START) throw new Error('Not a get response start');\n return {\n contentType: arr[1],\n contentLength: arr[2],\n hasRange: arr[3] === 1,\n rangeStart: arr[3] ? arr[4] : undefined,\n rangeEnd: arr[3] ? arr[5] : undefined\n };\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {Uint8Array}\n */\nexport function decodeGetData(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.GET_DATA) throw new Error('Not a get data');\n return arr[1];\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {boolean}\n */\nexport function isGetEnd(bytes) {\n const arr = decode(bytes);\n return Array.isArray(arr) && arr[0] === MSG.GET_END;\n}\n\n// --- Error ---\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{statusCode: number, message: string}|null}\n */\nexport function decodeError(bytes) {\n const arr = decode(bytes);\n if (!Array.isArray(arr) || arr[0] !== MSG.ERROR) return null;\n return { statusCode: arr[1], message: arr[2] };\n}\n\n// --- Block ---\n\n/**\n * @param {Uint8Array} data\n * @param {number} encoding 0=raw, 1=base58\n * @returns {Uint8Array}\n */\nexport function encodeBlockPutRequest(data, encoding = 0) {\n return encoder.encode([MSG.BLOCK_PUT_REQUEST, data, encoding]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, hash: Uint8Array|string}}\n */\nexport function decodeBlockPutResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.BLOCK_PUT_RESPONSE) throw new Error('Not a block put response');\n return { status: arr[1], hash: arr[2] };\n}\n\n/**\n * @param {Uint8Array} hash\n * @returns {Uint8Array}\n */\nexport function encodeBlockGetRequest(hash) {\n return encoder.encode([MSG.BLOCK_GET_REQUEST, hash]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, data: Uint8Array}}\n */\nexport function decodeBlockGetResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.BLOCK_GET_RESPONSE) throw new Error('Not a block get response');\n return { status: arr[1], data: arr[2] };\n}\n\n/**\n * @param {Uint8Array} hash\n * @returns {Uint8Array}\n */\nexport function encodeBlockDeleteRequest(hash) {\n return encoder.encode([MSG.BLOCK_DELETE_REQUEST, hash]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number}}\n */\nexport function decodeBlockDeleteResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.BLOCK_DELETE_RESPONSE) throw new Error('Not a block delete response');\n return { status: arr[1] };\n}\n\n// --- Health ---\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeHealthRequest() {\n return encoder.encode([MSG.HEALTH_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{json: string}}\n */\nexport function decodeHealthResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.HEALTH_RESPONSE) throw new Error('Not a health response');\n return { json: arr[1] };\n}\n\n// --- Peer ---\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodePeerInfoRequest() {\n return encoder.encode([MSG.PEER_INFO_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{format: number, data: Uint8Array}}\n */\nexport function decodePeerInfoResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PEER_INFO_RESPONSE) throw new Error('Not a peer info response');\n return { format: arr[1], data: arr[2] };\n}\n\n/**\n * @param {number} format 0=cbor, 1=base58\n * @param {Uint8Array} data\n * @returns {Uint8Array}\n */\nexport function encodePeerConnect(format, data) {\n return encoder.encode([MSG.PEER_CONNECT, format, data]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number}}\n */\nexport function decodePeerConnectResult(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PEER_CONNECT_RESULT) throw new Error('Not a peer connect result');\n return { status: arr[1] };\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodePeerListRequest() {\n return encoder.encode([MSG.PEER_LIST_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {any[]}\n */\nexport function decodePeerListResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PEER_LIST_RESPONSE) throw new Error('Not a peer list response');\n return arr[1];\n}\n\n// --- Friend ---\n\n/**\n * @param {number} format\n * @param {Uint8Array} data\n * @returns {Uint8Array}\n */\nexport function encodeFriendAdd(format, data) {\n return encoder.encode([MSG.FRIEND_ADD, format, data]);\n}\n\n/**\n * @param {Uint8Array} nodeId\n * @returns {Uint8Array}\n */\nexport function encodeFriendRemove(nodeId) {\n return encoder.encode([MSG.FRIEND_REMOVE, nodeId]);\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeFriendListRequest() {\n return encoder.encode([MSG.FRIEND_LIST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {any[]}\n */\nexport function decodeFriendListResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.FRIEND_LIST_RESPONSE) throw new Error('Not a friend list response');\n return arr[1];\n}\n\n// --- Config ---\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeConfigShowRequest() {\n return encoder.encode([MSG.CONFIG_SHOW_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{json: string}}\n */\nexport function decodeConfigShowResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.CONFIG_SHOW_RESPONSE) throw new Error('Not a config show response');\n return { json: arr[1] };\n}\n\n/**\n * @param {string} field\n * @param {string} value\n * @returns {Uint8Array}\n */\nexport function encodeConfigSetRequest(field, value) {\n return encoder.encode([MSG.CONFIG_SET_REQUEST, field, value]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, restartRequired: boolean, message: string}}\n */\nexport function decodeConfigSetResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.CONFIG_SET_RESPONSE) throw new Error('Not a config set response');\n return { status: arr[1], restartRequired: arr[2] === 1, message: arr[3] };\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeConfigReloadRequest() {\n return encoder.encode([MSG.CONFIG_RELOAD_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, message: string}}\n */\nexport function decodeConfigReloadResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.CONFIG_RELOAD_RESPONSE) throw new Error('Not a config reload response');\n return { status: arr[1], message: arr[2] };\n}\n","import { encodeAuthRequest, getMessageType } from '../wire.js';\n\n/**\n * WebSocket transport for the OFFS client.\n * Sends CBOR messages as binary WebSocket frames.\n */\nexport class WsTransport {\n /** @type {WebSocket|null} */\n socket = null;\n /** @type {string|undefined} */\n apiKey;\n /** @type {((type: number, bytes: Uint8Array) => void)|null} */\n messageHandler = null;\n /** @type {Promise|null} */\n openPromise = null;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [_options]\n */\n constructor(url, apiKey, _options) {\n this.url = url;\n this.apiKey = apiKey;\n }\n\n /**\n * @returns {Promise}\n */\n connect() {\n if (this.socket) {\n return this.openPromise || Promise.resolve();\n }\n\n this.socket = new WebSocket(this.url);\n this.socket.binaryType = 'arraybuffer';\n\n this.openPromise = new Promise((resolve, reject) => {\n const socket = this.socket;\n if (!socket) return reject(new Error('Socket not created'));\n\n socket.onopen = () => {\n if (this.apiKey) {\n this.send(encodeAuthRequest(this.apiKey));\n }\n resolve();\n };\n socket.onerror = (event) => {\n const message = event.message || event.error?.message || 'unknown';\n reject(new Error(`WebSocket error: ${message}`));\n };\n socket.onclose = () => {\n this.socket = null;\n this.openPromise = null;\n };\n socket.onmessage = (event) => {\n const bytes = new Uint8Array(event.data);\n const type = getMessageType(bytes);\n if (type !== null) {\n this.messageHandler?.(type, bytes);\n }\n };\n });\n\n return this.openPromise;\n }\n\n disconnect() {\n if (this.socket) {\n this.socket.close();\n this.socket = null;\n }\n this.openPromise = null;\n }\n\n isConnected() {\n return this.socket !== null && this.socket.readyState === WebSocket.OPEN;\n }\n\n /**\n * @param {Uint8Array} bytes\n */\n send(bytes) {\n if (!this.isConnected()) {\n throw new Error('WebSocket not connected');\n }\n this.socket.send(bytes);\n }\n\n /**\n * @param {(type: number, bytes: Uint8Array) => void} handler\n */\n setMessageHandler(handler) {\n this.messageHandler = handler;\n }\n}\n","import { encodeAuthRequest, getMessageType } from '../wire.js';\n\n/**\n * WebTransport transport for the OFFS client.\n * Sends length-prefixed CBOR frames over an HTTP/3 bidirectional stream.\n */\nexport class WtTransport {\n /** @type {WebTransport|null} */\n transport = null;\n /** @type {WritableStreamWriter|null} */\n writer = null;\n /** @type {ReadableStreamReader|null} */\n reader = null;\n /** @type {string|undefined} */\n apiKey;\n /** @type {((type: number, bytes: Uint8Array) => void)|null} */\n messageHandler = null;\n /** @type {Promise|null} */\n openPromise = null;\n /** @type {boolean} */\n running = false;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [_options]\n */\n constructor(url, apiKey, _options) {\n this.url = url;\n this.apiKey = apiKey;\n }\n\n /**\n * @returns {Promise}\n */\n async connect() {\n if (this.transport) return this.openPromise || Promise.resolve();\n\n this.transport = new WebTransport(this.url);\n this.openPromise = this.transport.ready.then(async () => {\n const stream = await this.transport.createBidirectionalStream();\n this.writer = stream.writable.getWriter();\n this.reader = stream.readable.getReader();\n this.running = true;\n this._readLoop();\n if (this.apiKey) {\n await this.send(encodeAuthRequest(this.apiKey));\n }\n });\n\n return this.openPromise;\n }\n\n disconnect() {\n this.running = false;\n this.writer?.releaseLock();\n this.reader?.releaseLock();\n this.transport?.close();\n this.writer = null;\n this.reader = null;\n this.transport = null;\n this.openPromise = null;\n }\n\n isConnected() {\n return this.transport !== null && this.transport.state === 'connected';\n }\n\n /**\n * @param {Uint8Array} bytes\n */\n async send(bytes) {\n if (!this.writer) throw new Error('WebTransport not connected');\n const length = new Uint8Array(4);\n const view = new DataView(length.buffer);\n view.setUint32(0, bytes.length, false); // big-endian\n await this.writer.write(length);\n await this.writer.write(bytes);\n }\n\n /**\n * @param {(type: number, bytes: Uint8Array) => void} handler\n */\n setMessageHandler(handler) {\n this.messageHandler = handler;\n }\n\n async _readLoop() {\n /** @type {Uint8Array|null} */\n let pending = null;\n try {\n while (this.running) {\n const { done, value } = await this.reader.read();\n if (done) break;\n const chunk = value instanceof Uint8Array ? value : new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n pending = pending ? _concat(pending, chunk) : chunk;\n while (pending.length >= 4) {\n const view = new DataView(pending.buffer, pending.byteOffset, pending.length);\n const msgLen = view.getUint32(0, false);\n if (pending.length < 4 + msgLen) break;\n const msgBytes = pending.subarray(4, 4 + msgLen);\n const type = getMessageType(msgBytes);\n if (type !== null) {\n this.messageHandler?.(type, msgBytes);\n }\n pending = pending.subarray(4 + msgLen);\n }\n }\n } catch (_err) {\n // ignore errors after disconnect\n }\n }\n}\n\n/**\n * @param {Uint8Array} a\n * @param {Uint8Array} b\n * @returns {Uint8Array}\n */\nfunction _concat(a, b) {\n const result = new Uint8Array(a.length + b.length);\n result.set(a, 0);\n result.set(b, a.length);\n return result;\n}\n","/**\n * Bitcoin-style Base58 encoding/decoding.\n * Matches the C implementation in liboffs/src/Util/base58.c.\n */\nconst ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/** @type {Int8Array} */\nconst INDICES = new Int8Array(128);\nINDICES.fill(-1);\nfor (let index = 0; index < ALPHABET.length; index++) {\n INDICES[ALPHABET.charCodeAt(index)] = index;\n}\n\n/**\n * Decode a base58 string into a Uint8Array.\n * @param {string} input\n * @returns {Uint8Array|null}\n */\nexport function base58Decode(input) {\n if (input.length === 0) return null;\n\n let leadingZeros = 0;\n while (leadingZeros < input.length && input[leadingZeros] === '1') {\n leadingZeros++;\n }\n\n const bytes = [];\n for (let index = leadingZeros; index < input.length; index++) {\n const codeUnit = input.charCodeAt(index);\n if (codeUnit >= 128) return null;\n const digit = INDICES[codeUnit];\n if (digit < 0) return null;\n\n let carry = digit;\n for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {\n carry += bytes[byteIndex] * 58;\n bytes[byteIndex] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n for (let index = 0; index < leadingZeros; index++) {\n bytes.push(0);\n }\n\n bytes.reverse();\n return new Uint8Array(bytes);\n}\n\n/**\n * Encode a Uint8Array into a base58 string.\n * @param {Uint8Array|number[]} input\n * @returns {string}\n */\nexport function base58Encode(input) {\n if (input.length === 0) return '';\n\n const bytes = Array.from(input);\n let leadingZeros = 0;\n while (leadingZeros < bytes.length && bytes[leadingZeros] === 0) {\n leadingZeros++;\n }\n\n const resultCodes = [];\n for (let index = leadingZeros; index < bytes.length; index++) {\n let carry = bytes[index];\n for (let resultIndex = 0; resultIndex < resultCodes.length; resultIndex++) {\n carry += resultCodes[resultIndex] * 256;\n resultCodes[resultIndex] = carry % 58;\n carry = Math.floor(carry / 58);\n }\n while (carry > 0) {\n resultCodes.push(carry % 58);\n carry = Math.floor(carry / 58);\n }\n }\n\n const prefix = '1'.repeat(leadingZeros);\n return prefix + resultCodes.reverse().map((code) => ALPHABET[code]).join('');\n}\n\n/**\n * Parsed OFFS URL components.\n * @typedef {Object} ParsedOffUrl\n * @property {string} fileHashB58\n * @property {string} descriptorHashB58\n * @property {number} streamLength\n * @property {string} fileName\n */\n\n/**\n * Parse an offs:// or http(s) OFFS URL.\n * Format: .../offsystem/v3/{type}/{length}/{hash1}/{hash2}/{name}\n * @param {string} url\n * @returns {ParsedOffUrl|null}\n */\nexport function parseOffUrl(url) {\n const prefixIndex = url.indexOf('/offsystem/v3/');\n if (prefixIndex < 0) return null;\n\n const afterPrefix = url.slice(prefixIndex + '/offsystem/v3/'.length);\n const allParts = afterPrefix.split('/');\n if (allParts.length < 4) return null;\n\n const streamLengthStr = allParts[allParts.length - 4];\n const fileHashB58 = allParts[allParts.length - 3];\n const descriptorHashB58 = allParts[allParts.length - 2];\n const fileName = allParts.slice(allParts.length - 1).join('/');\n\n const streamLength = parseInt(streamLengthStr, 10);\n if (!Number.isFinite(streamLength)) return null;\n if (base58Decode(fileHashB58) === null) return null;\n if (base58Decode(descriptorHashB58) === null) return null;\n\n return {\n fileHashB58,\n descriptorHashB58,\n streamLength,\n fileName: decodeURIComponent(fileName)\n };\n}\n\n/**\n * Guess a MIME type from a filename extension.\n * @param {string} filename\n * @returns {string}\n */\nexport function mimeFromExtension(filename) {\n const map = {\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n json: 'application/json',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n webp: 'image/webp',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mkv: 'video/x-matroska',\n avi: 'video/x-msvideo',\n mov: 'video/quicktime',\n wmv: 'video/x-msvideo',\n flv: 'video/x-flv',\n mp3: 'audio/mpeg',\n ogg: 'audio/ogg',\n wav: 'audio/wav',\n flac: 'audio/flac',\n aac: 'audio/mp4',\n m4a: 'audio/mp4',\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n pdf: 'application/pdf',\n zip: 'application/zip',\n gz: 'application/gzip',\n tar: 'application/x-tar',\n rar: 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n csv: 'text/csv',\n xml: 'application/xml',\n md: 'text/markdown',\n ofd: 'application/cbor'\n };\n const dotIndex = filename.lastIndexOf('.');\n if (dotIndex < 0 || dotIndex === filename.length - 1) return 'application/octet-stream';\n const extension = filename.slice(dotIndex + 1).toLowerCase();\n return map[extension] || 'application/octet-stream';\n}\n\n/**\n * Read a browser File or Blob into a Uint8Array.\n * @param {Blob} file\n * @returns {Promise}\n */\nexport function readFileBytes(file) {\n if (typeof file.arrayBuffer === 'function') {\n return file.arrayBuffer().then((buffer) => new Uint8Array(buffer));\n }\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(new Uint8Array(reader.result));\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(file);\n });\n}\n\n/**\n * Return the last path segment, stripping any directory separators or parent\n * references so the value is safe to use as a `file-name` header.\n * @param {string} path\n * @returns {string}\n */\nexport function basename(path) {\n const normalized = path.replace(/\\\\\\\\/g, '/');\n const parts = normalized.split('/').filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : 'file';\n}\n\n/**\n * Create a ReadableStream from a browser File.\n * @param {File} file\n * @param {number} [chunkSize=65536]\n * @returns {ReadableStream}\n */\nexport function fileToReadableStream(file, chunkSize = 65536) {\n let offset = 0;\n return new ReadableStream({\n pull(controller) {\n if (offset >= file.size) {\n controller.close();\n return;\n }\n const end = Math.min(offset + chunkSize, file.size);\n const slice = file.slice(offset, end);\n return readFileBytes(slice).then((bytes) => {\n controller.enqueue(bytes);\n offset = end;\n });\n }\n });\n}\n\n/**\n * A file-like entry with a relative path.\n * @typedef {Object} FolderEntry\n * @property {string} path\n * @property {File|Blob} file\n */\n\n/**\n * Normalize various folder input shapes into a flat list of {path, file}.\n * Accepts FileList (from ), Array,\n * Array<{path, file}>, or Record.\n * @param {FileList|File[]|FolderEntry[]|Record} items\n * @returns {FolderEntry[]}\n */\nexport function normalizeFolderEntries(items) {\n if (typeof FileList !== 'undefined' && items instanceof FileList) {\n const entries = [];\n for (let index = 0; index < items.length; index++) {\n const file = items[index];\n /** @type {string} */\n let path = file.webkitRelativePath || file.name;\n entries.push({ path, file });\n }\n return entries;\n }\n\n if (Array.isArray(items)) {\n return items.map((item) => {\n if (item instanceof File || item instanceof Blob) {\n return { path: item.webkitRelativePath || item.name, file: item };\n }\n return { path: item.path, file: item.file };\n });\n }\n\n return Object.entries(items).map(([path, file]) => ({ path, file }));\n}\n\n/**\n * Ensure an OFF URL points at an HTTP endpoint so a browser can fetch it.\n * @param {string} oriString\n * @param {string} [baseUrl='http://localhost:23402']\n * @returns {string}\n */\nexport function offUrlToHttpUrl(oriString, baseUrl = 'http://localhost:23402') {\n if (!oriString) return oriString;\n if (/^https?:\\/\\//i.test(oriString)) return oriString;\n\n let path = oriString;\n if (path.startsWith('offs://')) {\n path = path.slice('offs://'.length);\n }\n\n const prefix = '/offsystem/v3/';\n const index = path.indexOf(prefix);\n if (index >= 0) {\n path = path.slice(index);\n }\n\n if (path.startsWith(prefix)) {\n const base = baseUrl.replace(/\\/$/, '');\n return `${base}${path}`;\n }\n\n return oriString;\n}\n","import { encode, decode } from 'cbor-x';\n\n/**\n * @typedef {Object} OfdFileEntry\n * @property {string} name\n * @property {boolean} isDirectory\n * @property {Uint8Array} fileHash\n * @property {Uint8Array} descriptorHash\n * @property {number} finalByte\n * @property {number} blockType\n * @property {number} tupleSize\n * @property {number} fileOffset\n */\n\n/**\n * @typedef {Object} OfdDirectoryEntry\n * @property {string} name\n * @property {boolean} isDirectory\n * @property {Uint8Array} dirHash\n */\n\n/**\n * @typedef {OfdFileEntry|OfdDirectoryEntry} OfdEntry\n */\n\nconst DEFAULT_BLOCK_TYPE = 128000;\nconst DEFAULT_TUPLE_SIZE = 3;\n\n/**\n * Create a file OFD entry.\n * @param {Object} params\n * @param {string} params.name\n * @param {Uint8Array} params.fileHash\n * @param {Uint8Array} params.descriptorHash\n * @param {number} params.finalByte\n * @param {number} [params.blockType=128000]\n * @param {number} [params.tupleSize=3]\n * @param {number} [params.fileOffset=0]\n * @returns {OfdEntry}\n */\nexport function ofdFile({\n name,\n fileHash,\n descriptorHash,\n finalByte,\n blockType = DEFAULT_BLOCK_TYPE,\n tupleSize = DEFAULT_TUPLE_SIZE,\n fileOffset = 0\n}) {\n return {\n name,\n isDirectory: false,\n fileHash,\n descriptorHash,\n finalByte,\n blockType,\n tupleSize,\n fileOffset\n };\n}\n\n/**\n * Create a directory OFD entry.\n * @param {Object} params\n * @param {string} params.name\n * @param {Uint8Array} params.dirHash\n * @returns {OfdEntry}\n */\nexport function ofdDirectory({ name, dirHash }) {\n return { name, isDirectory: true, dirHash };\n}\n\n/**\n * Build CBOR-encoded OFD bytes from a list of entries.\n * Format matches the Dart example client (examples/off_client/lib/services/ofd.dart).\n * @param {OfdEntry[]} entries\n * @returns {Uint8Array}\n */\nexport function buildOfdCbor(entries) {\n const entryMaps = entries.map((entry) => {\n const map = {\n n: entry.name,\n t: entry.isDirectory ? 1 : 0\n };\n if (entry.isDirectory) {\n map.d = entry.dirHash;\n } else {\n map.f = entry.fileHash;\n map.D = entry.descriptorHash;\n map.s = entry.finalByte;\n map.B = entry.blockType;\n map.T = entry.tupleSize;\n map.o = entry.fileOffset;\n }\n return map;\n });\n\n return encode({ v: 1, entries: entryMaps });\n}\n\n/**\n * Parse CBOR-encoded OFD bytes into a list of entries.\n * @param {Uint8Array} data\n * @returns {OfdEntry[]}\n */\nexport function parseOfdCbor(data) {\n const decoded = decode(data);\n if (!decoded || typeof decoded !== 'object') return [];\n\n const entries = decoded.entries;\n if (!Array.isArray(entries)) return [];\n\n return entries.map((entry) => {\n const isDirectory = entry.t === 1;\n if (isDirectory) {\n return ofdDirectory({\n name: String(entry.n),\n dirHash: asUint8Array(entry.d)\n });\n }\n return ofdFile({\n name: String(entry.n),\n fileHash: asUint8Array(entry.f),\n descriptorHash: asUint8Array(entry.D),\n finalByte: safeInt(entry.s),\n blockType: safeInt(entry.B),\n tupleSize: safeInt(entry.T),\n fileOffset: safeInt(entry.o)\n });\n }).filter(Boolean);\n}\n\n/**\n * @param {any} value\n * @returns {number}\n */\nfunction safeInt(value) {\n if (typeof value === 'number') return value;\n if (typeof value === 'bigint') return Number(value);\n return 0;\n}\n\n/**\n * @param {any} value\n * @returns {Uint8Array}\n */\nfunction asUint8Array(value) {\n if (value instanceof Uint8Array) return value;\n if (Array.isArray(value)) return new Uint8Array(value);\n if (value instanceof ArrayBuffer) return new Uint8Array(value);\n if (value && typeof value === 'object' && ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n return new Uint8Array(0);\n}\n","import { HttpTransport } from './transports/http-transport.js';\nimport { WsTransport } from './transports/ws-transport.js';\nimport { WtTransport } from './transports/wt-transport.js';\nimport * as wire from './wire.js';\nimport {\n base58Decode,\n base58Encode,\n parseOffUrl,\n offUrlToHttpUrl,\n mimeFromExtension,\n fileToReadableStream,\n normalizeFolderEntries,\n basename\n} from './util.js';\nimport { buildOfdCbor, ofdFile, ofdDirectory } from './ofd.js';\n\n/**\n * @typedef {import('./types.js').OffsClientConfig} OffsClientConfig\n * @typedef {import('./types.js').OffsPutOptions} OffsPutOptions\n * @typedef {import('./types.js').OffsGetCallbacks} OffsGetCallbacks\n */\n\n/**\n * @typedef {Object} PendingRequest\n * @property {number} id\n * @property {number} type\n * @property {(value: any) => void} resolve\n * @property {(reason: any) => void} reject\n * @property {any} [ctx]\n */\n\n/**\n * Default configuration.\n * @returns {OffsClientConfig}\n */\nfunction defaultConfig() {\n return {\n connectTimeoutMs: 5000,\n requestTimeoutMs: 30000\n };\n}\n\n/**\n * Create a transport by URL scheme.\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [options]\n * @returns {HttpTransport|WsTransport|WtTransport}\n */\nfunction createTransport(url, apiKey, options) {\n if (url.startsWith('ws://') || url.startsWith('wss://')) {\n return new WsTransport(url, apiKey, options);\n }\n if (url.startsWith('wt://') || url.startsWith('wts://')) {\n return new WtTransport(url, apiKey, options);\n }\n return new HttpTransport(url, apiKey, options);\n}\n\n/**\n * Browser-only OFFS client supporting HTTP, WebSocket, and WebTransport.\n */\nexport class OffsClient {\n /** @type {string} */\n url;\n /** @type {string|undefined} */\n apiKey;\n /** @type {OffsClientConfig} */\n config;\n /** @type {HttpTransport|WsTransport|WtTransport} */\n transport;\n /** @type {Map} */\n pending = new Map();\n /** @type {{type: number, bytes: Uint8Array}[]} */\n inboundQueue = [];\n /** @type {number} */\n nextRequestId = 1;\n /** @type {boolean} */\n streamingPut = false;\n /** @type {OffsPutOptions|null} */\n streamOptions = null;\n /** @type {boolean} */\n connected = false;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {OffsClientConfig & {transport?: any}} [config]\n */\n constructor(url, apiKey, config) {\n this.url = url;\n this.apiKey = apiKey;\n this.config = { ...defaultConfig(), ...config };\n this.transport = config?.transport || createTransport(url, apiKey, config);\n this.transport.setMessageHandler(this._onMessage.bind(this));\n }\n\n /**\n * @returns {Promise}\n */\n async connect() {\n await this.transport.connect();\n this.connected = true;\n }\n\n disconnect() {\n this.transport.disconnect();\n this.connected = false;\n for (const pending of this.pending.values()) {\n pending.reject(new Error('Client disconnected'));\n }\n this.pending.clear();\n }\n\n isConnected() {\n return this.transport.isConnected();\n }\n\n /**\n * @param {number} id\n * @param {number} type\n * @param {number} [timeoutMs]\n * @returns {Promise}\n */\n _request(id, type, timeoutMs) {\n return new Promise((resolve, reject) => {\n const pending = {\n id,\n type,\n resolve,\n reject,\n timer: setTimeout(() => {\n this.pending.delete(id);\n reject(new Error('Request timeout'));\n }, timeoutMs || this.config.requestTimeoutMs)\n };\n this.pending.set(id, pending);\n });\n }\n\n /**\n * @param {number|number[]} type\n * @param {number} [timeoutMs]\n * @returns {Promise}\n */\n _waitForResponse(type, timeoutMs) {\n const id = this.nextRequestId++;\n const promise = this._request(id, type, timeoutMs);\n const queued = this._dequeueMatching(type);\n if (queued !== null) {\n this._resolve(id, queued);\n }\n return promise;\n }\n\n /**\n * @param {number} id\n * @param {any} value\n */\n _resolve(id, value) {\n const pending = this.pending.get(id);\n if (!pending) return;\n if (pending.timer) clearTimeout(pending.timer);\n this.pending.delete(id);\n pending.resolve(value);\n }\n\n /**\n * @param {number} id\n * @param {any} reason\n */\n _reject(id, reason) {\n const pending = this.pending.get(id);\n if (!pending) return;\n if (pending.timer) clearTimeout(pending.timer);\n this.pending.delete(id);\n pending.reject(reason);\n }\n\n /**\n * @param {number} type\n * @param {Uint8Array} bytes\n */\n _onMessage(type, bytes) {\n if (type === wire.MSG.ERROR) {\n const error = wire.decodeError(bytes);\n if (error) {\n for (const pending of this.pending.values()) {\n this._reject(pending.id, new Error(`Server error ${error.statusCode}: ${error.message}`));\n }\n }\n return;\n }\n\n for (const pending of this.pending.values()) {\n const matches = Array.isArray(pending.type)\n ? pending.type.includes(type)\n : pending.type === type;\n if (matches) {\n this._resolve(pending.id, bytes);\n return;\n }\n }\n this.inboundQueue.push({ type, bytes });\n }\n\n /**\n * @param {number|number[]} type\n * @returns {Uint8Array|null}\n */\n _dequeueMatching(type) {\n const types = Array.isArray(type) ? type : [type];\n const index = this.inboundQueue.findIndex((item) => types.includes(item.type));\n if (index === -1) return null;\n const item = this.inboundQueue[index];\n this.inboundQueue.splice(index, 1);\n return item.bytes;\n }\n\n /**\n * Send a CBOR message and wait for a matching response type.\n * @param {Uint8Array} bytes\n * @param {number} responseType\n * @param {number} [timeoutMs]\n * @returns {Promise}\n */\n async _sendAndWait(bytes, responseType, timeoutMs) {\n const id = this.nextRequestId++;\n const promise = this._request(id, responseType, timeoutMs);\n await this.transport.send(bytes);\n return promise;\n }\n\n /**\n * @param {string|OffsPutOptions} options\n * @param {Uint8Array|undefined} data\n * @returns {Promise<{oriString: string}>}\n */\n async put(options, data) {\n if (typeof options === 'string') {\n throw new Error('Use object options (contentType, fileName, streamLength)');\n }\n\n const safeOptions = {\n ...options,\n fileName: basename(options.fileName)\n };\n\n if (this.transport instanceof HttpTransport) {\n const body = data || new Uint8Array(0);\n return this.transport.put(safeOptions, body);\n }\n\n const requestBytes = wire.encodePutRequest(safeOptions, data);\n\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PUT_RESPONSE);\n return wire.decodePutResponse(responseBytes);\n }\n\n /**\n * @param {OffsPutOptions} options\n * @returns {Promise}\n */\n async putStreamStart(options) {\n this.streamingPut = true;\n this.streamOptions = options;\n\n if (this.transport instanceof HttpTransport) {\n return;\n }\n\n const requestBytes = wire.encodePutRequest(options);\n await this.transport.send(requestBytes);\n }\n\n /**\n * @param {Uint8Array} chunk\n * @returns {Promise}\n */\n async putStreamData(chunk) {\n if (this.transport instanceof HttpTransport) {\n throw new Error('HTTP transport does not support putStreamData; use put with ReadableStream');\n }\n await this.transport.send(wire.encodePutData(chunk));\n }\n\n /**\n * @returns {Promise<{oriString: string}>}\n */\n async putStreamEnd() {\n this.streamingPut = false;\n const options = this.streamOptions;\n this.streamOptions = null;\n\n if (this.transport instanceof HttpTransport) {\n if (!options) throw new Error('No stream in progress');\n return this.transport.put(options, new Uint8Array(0));\n }\n\n await this.transport.send(wire.encodePutEnd());\n const responseBytes = await this._request(this.nextRequestId - 1, wire.MSG.PUT_RESPONSE);\n return wire.decodePutResponse(responseBytes);\n }\n\n /**\n * @param {string} oriString\n * @param {OffsGetCallbacks} callbacks\n * @param {{start?: number, end?: number}} [range]\n */\n async get(oriString, callbacks, range) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.get(oriString, callbacks);\n }\n\n const requestBytes = wire.encodeGetRequest(oriString, range);\n\n const startBytes = await this._sendAndWait(requestBytes, wire.MSG.GET_RESPONSE_START);\n const start = wire.decodeGetResponseStart(startBytes);\n callbacks.onStart?.(start.contentType, start.contentLength, start.hasRange, start.rangeStart, start.rangeEnd);\n\n while (true) {\n const dataBytes = await this._waitForResponse([wire.MSG.GET_DATA, wire.MSG.GET_END]);\n if (wire.isGetEnd(dataBytes)) break;\n const chunk = wire.decodeGetData(dataBytes);\n callbacks.onData(chunk);\n }\n\n callbacks.onEnd?.();\n }\n\n /**\n * @param {Uint8Array} data\n * @param {number} [encoding=0]\n * @returns {Promise<{status: number, hash: Uint8Array|string}>}\n */\n async blockPut(data, encoding = 0) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.blockPut(data, encoding);\n }\n\n const requestBytes = wire.encodeBlockPutRequest(data, encoding);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.BLOCK_PUT_RESPONSE);\n return wire.decodeBlockPutResponse(responseBytes);\n }\n\n /**\n * @param {string|Uint8Array} hash\n * @returns {Promise<{status: number, data: Uint8Array}>}\n */\n async blockGet(hash) {\n if (typeof hash === 'string') return this.transport.blockGet(hash);\n\n if (this.transport instanceof HttpTransport) {\n return this.transport.blockGet(base58Encode(hash));\n }\n\n const requestBytes = wire.encodeBlockGetRequest(hash);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.BLOCK_GET_RESPONSE);\n return wire.decodeBlockGetResponse(responseBytes);\n }\n\n /**\n * @param {string|Uint8Array} hash\n * @returns {Promise<{status: number}>}\n */\n async blockDelete(hash) {\n if (typeof hash === 'string') return this.transport.blockDelete(hash);\n\n if (this.transport instanceof HttpTransport) {\n return this.transport.blockDelete(base58Encode(hash));\n }\n\n const requestBytes = wire.encodeBlockDeleteRequest(hash);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.BLOCK_DELETE_RESPONSE);\n return wire.decodeBlockDeleteResponse(responseBytes);\n }\n\n /**\n * @returns {Promise}\n */\n async health() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.health();\n }\n\n const requestBytes = wire.encodeHealthRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.HEALTH_RESPONSE);\n const { json } = wire.decodeHealthResponse(responseBytes);\n return JSON.parse(json);\n }\n\n /**\n * @param {string} [format='cbor']\n * @returns {Promise<{format: number, data: Uint8Array}>}\n */\n async peerInfo(format = 'cbor') {\n if (this.transport instanceof HttpTransport) {\n return this.transport.peerInfo(format);\n }\n\n const requestBytes = wire.encodePeerInfoRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_INFO_RESPONSE);\n return wire.decodePeerInfoResponse(responseBytes);\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise<{status: number}>}\n */\n async peerConnect(peerInfo, format = 0) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.peerConnect(peerInfo, format);\n }\n\n const requestBytes = wire.encodePeerConnect(format, peerInfo);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_CONNECT_RESULT);\n return wire.decodePeerConnectResult(responseBytes);\n }\n\n /**\n * Convert an OFF URL/URI string into an HTTP URL usable by a browser.\n * @param {string} oriString\n * @param {string} [baseUrl]\n * @returns {string}\n */\n static offUrlToHttpUrl(oriString, baseUrl) {\n return offUrlToHttpUrl(oriString, baseUrl);\n }\n\n /**\n * @returns {Promise}\n */\n async peerList() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.peerList();\n }\n\n const requestBytes = wire.encodePeerListRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_LIST_RESPONSE);\n return wire.decodePeerListResponse(responseBytes);\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise}\n */\n async friendAdd(peerInfo, format = 0) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.friendAdd(peerInfo, format);\n }\n\n const requestBytes = wire.encodeFriendAdd(format, peerInfo);\n await this.transport.send(requestBytes);\n }\n\n /**\n * @param {string|Uint8Array} nodeId\n * @returns {Promise}\n */\n async friendRemove(nodeId) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.friendRemove(typeof nodeId === 'string' ? nodeId : base58Encode(nodeId));\n }\n\n const idBytes = typeof nodeId === 'string' ? new TextEncoder().encode(nodeId) : nodeId;\n const requestBytes = wire.encodeFriendRemove(idBytes);\n await this.transport.send(requestBytes);\n }\n\n /**\n * @returns {Promise}\n */\n async friendList() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.friendList();\n }\n\n const requestBytes = wire.encodeFriendListRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.FRIEND_LIST_RESPONSE);\n return wire.decodeFriendListResponse(responseBytes);\n }\n\n /**\n * @returns {Promise}\n */\n async configShow() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.configShow();\n }\n\n const requestBytes = wire.encodeConfigShowRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.CONFIG_SHOW_RESPONSE);\n const { json } = wire.decodeConfigShowResponse(responseBytes);\n return JSON.parse(json);\n }\n\n /**\n * @param {string} field\n * @param {string} value\n * @returns {Promise<{status: number, restartRequired: boolean, message: string}>}\n */\n async configSet(field, value) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.configSet(field, value);\n }\n\n const requestBytes = wire.encodeConfigSetRequest(field, value);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.CONFIG_SET_RESPONSE);\n return wire.decodeConfigSetResponse(responseBytes);\n }\n\n /**\n * @returns {Promise<{status: number, message: string}>}\n */\n async configReload() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.configReload();\n }\n\n const requestBytes = wire.encodeConfigReloadRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.CONFIG_RELOAD_RESPONSE);\n return wire.decodeConfigReloadResponse(responseBytes);\n }\n\n /**\n * Upload a folder recursively and return the root directory's ORI URL.\n * Matches the algorithm used by the Flutter example client in\n * examples/off_client/lib/screens/import_screen.dart.\n *\n * @param {FileList|File[]|import('./util.js').FolderEntry[]|Record} items\n * @param {Object} [options]\n * @param {string[]} [options.recyclerUrls]\n * @param {string} [options.serverAddress]\n * @param {boolean} [options.temporary=false]\n * @param {(name: string, uploaded: number, total: number) => void} [options.onProgress]\n * @returns {Promise<{oriString: string}>}\n */\n async putFolder(items, options = {}) {\n const entries = normalizeFolderEntries(items);\n if (entries.length === 0) {\n throw new Error('No files to upload');\n }\n\n const recyclerUrls = options.recyclerUrls || [];\n const totalFiles = entries.length;\n let uploadedCount = 0;\n\n const updateProgress = (name) => {\n uploadedCount++;\n options.onProgress?.(name, uploadedCount, totalFiles);\n };\n\n const rootDir = _commonDirectory(entries.map((entry) => entry.path));\n\n /**\n * @param {string} dirPath\n * @returns {Promise<{oriString: string}>}\n */\n const uploadDirectory = async (dirPath) => {\n const dirName = basename(dirPath ? dirPath : rootDir || 'root');\n const childEntries = _children(entries, dirPath);\n const fileEntries = childEntries;\n const subdirs = _childDirectories(entries, dirPath);\n\n /** @type {import('./ofd.js').OfdEntry[]} */\n const ofdEntries = [];\n\n // Recursively upload subdirectories first.\n for (const subdir of subdirs) {\n const subResult = await uploadDirectory(subdir);\n const subUrl = subResult.oriString;\n const parsed = parseOffUrl(subUrl);\n if (!parsed) {\n throw new Error(`Failed to parse subdirectory URL: ${subUrl}`);\n }\n const dirHash = base58Decode(parsed.fileHashB58);\n if (!dirHash) {\n throw new Error(`Invalid directory hash in URL: ${subUrl}`);\n }\n ofdEntries.push(ofdDirectory({\n name: basename(subdir),\n dirHash\n }));\n }\n\n // Upload files in this directory.\n for (const fileEntry of fileEntries) {\n const fileName = basename(fileEntry.path);\n const contentType = mimeFromExtension(fileName);\n const streamLength = fileEntry.file.size;\n\n let url;\n if (this.transport instanceof HttpTransport) {\n const body = fileToReadableStream(fileEntry.file);\n const result = await this.put({\n contentType,\n fileName,\n streamLength,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n }, body);\n url = result.oriString;\n } else {\n await this.putStreamStart({\n contentType,\n fileName,\n streamLength,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n });\n\n const reader = fileToReadableStream(fileEntry.file).getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n await this.putStreamData(value);\n }\n\n const result = await this.putStreamEnd();\n url = result.oriString;\n }\n\n const parsed = parseOffUrl(url);\n if (!parsed) {\n throw new Error(`Failed to parse file URL: ${url}`);\n }\n const fileHash = base58Decode(parsed.fileHashB58);\n const descriptorHash = base58Decode(parsed.descriptorHashB58);\n if (!fileHash || !descriptorHash) {\n throw new Error(`Invalid hash in file URL: ${url}`);\n }\n\n ofdEntries.push(ofdFile({\n name: fileName,\n fileHash,\n descriptorHash,\n finalByte: parsed.streamLength\n }));\n\n updateProgress(fileName);\n }\n\n if (ofdEntries.length === 0) {\n throw new Error(`Empty directory: ${dirPath || rootDir}`);\n }\n\n const ofdBytes = buildOfdCbor(ofdEntries);\n const dirFileName = `${dirName}.ofd`;\n\n if (this.transport instanceof HttpTransport) {\n return this.put({\n contentType: 'offsystem/directory',\n fileName: dirFileName,\n streamLength: ofdBytes.length,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n }, ofdBytes);\n }\n\n await this.putStreamStart({\n contentType: 'offsystem/directory',\n fileName: dirFileName,\n streamLength: ofdBytes.length,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n });\n await this.putStreamData(ofdBytes);\n return this.putStreamEnd();\n };\n\n return uploadDirectory(rootDir);\n }\n}\n\n/**\n * Find the common root directory for a set of file paths.\n * @param {string[]} paths\n * @returns {string}\n */\nfunction _commonDirectory(paths) {\n if (paths.length === 0) return '';\n const segments = paths.map((path) => path.split('/').filter(Boolean));\n const first = segments[0];\n let commonLength = first.length;\n for (let index = 1; index < segments.length; index++) {\n const other = segments[index];\n let match = 0;\n while (match < Math.min(commonLength, other.length) && first[match] === other[match]) {\n match++;\n }\n commonLength = match;\n if (commonLength === 0) break;\n }\n // The common prefix must end at a directory boundary, not inside a filename.\n const prefixLength = Math.min(commonLength, first.length - 1);\n return first.slice(0, prefixLength).join('/');\n}\n\n/**\n * Get direct child files of a directory path.\n * @param {import('./util.js').FolderEntry[]} entries\n * @param {string} dirPath\n * @returns {import('./util.js').FolderEntry[]}\n */\nfunction _children(entries, dirPath) {\n const prefix = dirPath ? `${dirPath}/` : '';\n return entries.filter((entry) => {\n if (!entry.path.startsWith(prefix)) return false;\n const rest = entry.path.slice(prefix.length);\n return rest.length > 0 && !rest.includes('/');\n });\n}\n\n/**\n * Get direct child directory paths of a directory path.\n * @param {import('./util.js').FolderEntry[]} entries\n * @param {string} dirPath\n * @returns {string[]}\n */\nfunction _childDirectories(entries, dirPath) {\n const prefix = dirPath ? `${dirPath}/` : '';\n const seen = new Set();\n for (const entry of entries) {\n if (!entry.path.startsWith(prefix)) continue;\n const rest = entry.path.slice(prefix.length);\n if (!rest) continue;\n const slashIndex = rest.indexOf('/');\n if (slashIndex > 0) {\n seen.add(prefix + rest.slice(0, slashIndex));\n }\n }\n return Array.from(seen);\n}\n\nexport { wire, base58Decode, base58Encode, parseOffUrl, offUrlToHttpUrl, mimeFromExtension };\n"],"names":["HttpTransport","url","apiKey","_options","__publicField","path","headers","_handler","_bytes","options","body","_a","_b","requestBody","response","text","stream","reader","chunks","totalLength","done","value","result","offset","chunk","offUrl","callbacks","_c","_d","_e","_f","_g","contentType","contentLength","hasRange","rangeHeader","rangeStart","rangeEnd","match","err","data","encoding","query","hash","base58Hash","format","fmt","peerInfo","nodeId","field","decoder","src","srcEnd","position","LEGACY_RECORD_INLINE_ID","RECORD_DEFINITIONS_ID","RECORD_INLINE_ID","BUNDLED_STRINGS_ID","PACKED_REFERENCE_TAG_ID","STOP_CODE","maxArraySize","maxMapSize","currentDecoder","currentStructures","srcString","srcStringStart","srcStringEnd","bundledStrings","referenceMap","currentExtensions","currentExtensionRanges","packedValues","dataView","restoreMapsAsObject","defaultOptions","sequentialMode","inlineObjectReadThreshold","Decoder","k","v","key","rec","map","res","safeKey","source","end","r","saveState","clearSource","error","checkedRead","forEach","values","lastPosition","size","defaultDecoder","read","token","majorType","getFloat16","multiplier","mult10","array","i","object","readBin","string","shortStringInJS","longStringInJS","readFixedString","structure","createStructureReader","length","readJustLength","id","recordDefinition","readBundleExt","loadShared","extension","input","Tag","packedValue","getPackedValues","validName","readObject","compiledReader","readStringJS","units","byte1","byte2","byte3","byte4","unit","fromCharCode","start","bytes","byte","a","b","c","d","e","f","g","h","j","l","m","n","o","f32Array","u8Array","byte0","exponent","abs","tag","dateString","epochSec","buffer","fraction","existingStructure","glbl","packedTable","newPackedValues","startingPosition","target","refEntry","targetProperties","combine","SHARED_DATA_TAG_ID","isLittleEndianMachine","typedArrays","typedArrayTags","registerTypedArray","TypedArray","dvMethod","bytesPerElement","littleEndian","sizeShift","dv","elements","ta","method","bundlePosition","bundleLength","dataPosition","sharedData","updatedStructures","callback","savedSrcEnd","savedPosition","savedSrcStringStart","savedSrcStringEnd","savedSrcString","savedReferenceMap","savedBundledStrings","savedSrc","savedStructures","savedDecoder","savedSequentialMode","decode","textEncoder","extensions","extensionClasses","Buffer","hasNodeBuffer","ByteArrayAllocate","ByteArray","MAX_STRUCTURES","MAX_BUFFER_SIZE","throwOnIterable","targetView","safeEnd","MAX_BUNDLE_SIZE","hasNonLatin","RECORD_SYMBOL","Encoder","sharedStructures","hasSharedUpdate","structures","encodeUtf8","encoder","hasSharedStructures","maxSharedStructures","isSequential","samplingPackedValues","packedObjectMap","sharedValues","sharedPackedObjectMap","recordIdsToRemove","transitionsCount","serializationsSinceTransitionRebuild","encodeOptions","REUSE_BUFFER_MODE","sharedStructuresLength","keys","nextTransition","transition","findRepetitiveStrings","writeArrayHeader","valuesArray","encode","THROW_ON_ITERABLE","writeBundles","makeRoom","serialized","insertIds","returnBuffer","RESET_BUFFER_MODE","threshold","status","type","packedPosition","strLength","extStart","maxBytes","twoByte","headerSize","c1","c2","strPosition","useFloat32","xShifted","referee","idsToInsert","constructor","x","writeObject","entryValue","extensionClass","entry","isBlob","json","writeBuffer","vals","objectOffset","skipValues","newTransitions","parentRecordId","recordId","newSize","newBuffer","chunkThreshold","continuedChunkThreshold","startEncoding","encodeObjectAsIterable","encodeObjectAsAsyncIterable","iterateProperties","finalIterable","useRecords","writeEntityLength","tryEncode","restartEncoding","restart","encodeIterable","encodedValue","next","asyncValue","lastVersion","structuresCopy","SharedData","saveResults","existingShared","majorValue","version","BlobConstructor","packedStatus","includeKeys","date","seconds","set","regex","arrayBuffer","typedArray","typedArrayEncoder","definitions","nextId","distanceToMove","lastEnd","writeStrings","defaultEncoder","MSG","STATUS","getMessageType","arr","encodeAuthRequest","keyBytes","encodePutRequest","recycler","payload","encodePutData","encodePutEnd","decodePutResponse","encodeGetRequest","oriString","range","decodeGetResponseStart","decodeGetData","isGetEnd","decodeError","encodeBlockPutRequest","decodeBlockPutResponse","encodeBlockGetRequest","decodeBlockGetResponse","encodeBlockDeleteRequest","decodeBlockDeleteResponse","encodeHealthRequest","decodeHealthResponse","encodePeerInfoRequest","decodePeerInfoResponse","encodePeerConnect","decodePeerConnectResult","encodePeerListRequest","decodePeerListResponse","encodeFriendAdd","encodeFriendRemove","encodeFriendListRequest","decodeFriendListResponse","encodeConfigShowRequest","decodeConfigShowResponse","encodeConfigSetRequest","decodeConfigSetResponse","encodeConfigReloadRequest","decodeConfigReloadResponse","WsTransport","resolve","reject","socket","event","message","handler","WtTransport","pending","_concat","msgLen","msgBytes","ALPHABET","INDICES","index","base58Decode","leadingZeros","codeUnit","digit","carry","byteIndex","base58Encode","resultCodes","resultIndex","code","parseOffUrl","prefixIndex","allParts","streamLengthStr","fileHashB58","descriptorHashB58","fileName","streamLength","mimeFromExtension","filename","dotIndex","readFileBytes","file","basename","parts","fileToReadableStream","chunkSize","controller","slice","normalizeFolderEntries","items","entries","item","offUrlToHttpUrl","baseUrl","prefix","DEFAULT_BLOCK_TYPE","DEFAULT_TUPLE_SIZE","ofdFile","name","fileHash","descriptorHash","finalByte","blockType","tupleSize","fileOffset","ofdDirectory","dirHash","buildOfdCbor","entryMaps","defaultConfig","createTransport","OffsClient","config","timeoutMs","promise","queued","reason","wire.MSG","wire.decodeError","types","responseType","safeOptions","requestBytes","wire.encodePutRequest","responseBytes","wire.decodePutResponse","wire.encodePutData","wire.encodePutEnd","wire.encodeGetRequest","startBytes","wire.decodeGetResponseStart","dataBytes","wire.isGetEnd","wire.decodeGetData","wire.encodeBlockPutRequest","wire.decodeBlockPutResponse","wire.encodeBlockGetRequest","wire.decodeBlockGetResponse","wire.encodeBlockDeleteRequest","wire.decodeBlockDeleteResponse","wire.encodeHealthRequest","wire.decodeHealthResponse","wire.encodePeerInfoRequest","wire.decodePeerInfoResponse","wire.encodePeerConnect","wire.decodePeerConnectResult","wire.encodePeerListRequest","wire.decodePeerListResponse","wire.encodeFriendAdd","idBytes","wire.encodeFriendRemove","wire.encodeFriendListRequest","wire.decodeFriendListResponse","wire.encodeConfigShowRequest","wire.decodeConfigShowResponse","wire.encodeConfigSetRequest","wire.decodeConfigSetResponse","wire.encodeConfigReloadRequest","wire.decodeConfigReloadResponse","recyclerUrls","totalFiles","uploadedCount","updateProgress","rootDir","_commonDirectory","uploadDirectory","dirPath","dirName","fileEntries","_children","subdirs","_childDirectories","ofdEntries","subdir","subUrl","parsed","fileEntry","ofdBytes","dirFileName","paths","segments","first","commonLength","other","prefixLength","rest","seen","slashIndex"],"mappings":"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","x_google_ignoreList":[1,2]}
\ No newline at end of file
+{"version":3,"file":"offs-client.esm.js","sources":["../node_modules/cbor-x/decode.js","../node_modules/cbor-x/encode.js","../src/wire.js","../src/transports/http-transport.js","../src/transports/ws-transport.js","../src/transports/wt-transport.js","../src/util.js","../src/ofd.js","../src/index.js"],"sourcesContent":["let decoder\ntry {\n\tdecoder = new TextDecoder()\n} catch(error) {}\nlet src\nlet srcEnd\nlet position = 0\nlet alreadySet\nconst EMPTY_ARRAY = []\nconst LEGACY_RECORD_INLINE_ID = 105\nconst RECORD_DEFINITIONS_ID = 0xdffe\nconst RECORD_INLINE_ID = 0xdfff // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'\nconst BUNDLED_STRINGS_ID = 0xdff9\nconst PACKED_TABLE_TAG_ID = 51\nconst PACKED_REFERENCE_TAG_ID = 6\nconst STOP_CODE = {}\nlet maxArraySize = 112810000 // This is the maximum array size in V8. We would potentially detect and set it higher\n// for JSC, but this is pretty large and should be sufficient for most use cases\nlet maxMapSize = 16810000 // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,\n// so we don't need to\n\nlet maxObjectSize = 16710000; // This is the maximum number of keys in a Map. It takes over a minute to create this\n// many keys in an object, so also probably a reasonable choice there.\nlet strings = EMPTY_ARRAY\nlet stringPosition = 0\nlet currentDecoder = {}\nlet currentStructures\nlet srcString\nlet srcStringStart = 0\nlet srcStringEnd = 0\nlet bundledStrings\nlet referenceMap\nlet currentExtensions = []\nlet currentExtensionRanges = []\nlet packedValues\nlet dataView\nlet restoreMapsAsObject\nlet defaultOptions = {\n\tuseRecords: false,\n\tmapsAsObjects: true\n}\nlet sequentialMode = false\nlet inlineObjectReadThreshold = 2;\nvar BlockedFunction // we use search and replace to change the next call to BlockedFunction to avoid CSP issues for\n// no-eval build\ntry {\n\tnew Function('')\n} catch(error) {\n\t// if eval variants are not supported, do not create inline object readers ever\n\tinlineObjectReadThreshold = Infinity\n}\n\n\n\nexport class Decoder {\n\tconstructor(options) {\n\t\tif (options) {\n\t\t\tif ((options.keyMap || options._keyMap) && !options.useRecords) {\n\t\t\t\toptions.useRecords = false\n\t\t\t\toptions.mapsAsObjects = true\n\t\t\t}\n\t\t\tif (options.useRecords === false && options.mapsAsObjects === undefined)\n\t\t\t\toptions.mapsAsObjects = true\n\t\t\tif (options.getStructures)\n\t\t\t\toptions.getShared = options.getStructures\n\t\t\tif (options.getShared && !options.structures)\n\t\t\t\t(options.structures = []).uninitialized = true // this is what we use to denote an uninitialized structures\n\t\t\tif (options.keyMap) {\n\t\t\t\tthis.mapKey = new Map()\n\t\t\t\tfor (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k)\n\t\t\t}\n\t\t}\n\t\tObject.assign(this, options)\n\t}\n\t/*\n\tdecodeKey(key) {\n\t\treturn this.keyMap\n\t\t\t? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key\n\t\t\t: key\n\t}\n\t*/\n\tdecodeKey(key) {\n\t\treturn this.keyMap ? this.mapKey.get(key) || key : key\n\t}\n\t\n\tencodeKey(key) {\n\t\treturn this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key\n\t}\n\n\tencodeKeys(rec) {\n\t\tif (!this._keyMap) return rec\n\t\tlet map = new Map()\n\t\tfor (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v)\n\t\treturn map\n\t}\n\n\tdecodeKeys(map) {\n\t\tif (!this._keyMap || map.constructor.name != 'Map') return map\n\t\tif (!this._mapKey) {\n\t\t\tthis._mapKey = new Map()\n\t\t\tfor (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k)\n\t\t}\n\t\tlet res = {}\n\t\t//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)\n\t\tmap.forEach((v,k) => res[safeKey(this._mapKey.has(k) ? this._mapKey.get(k) : k)] = v)\n\t\treturn res\n\t}\n\t\n\tmapDecode(source, end) {\n\t\n\t\tlet res = this.decode(source)\n\t\tif (this._keyMap) { \n\t\t\t//Experiemntal support for Optimised KeyMap decoding \n\t\t\tswitch (res.constructor.name) {\n\t\t\t\tcase 'Array': return res.map(r => this.decodeKeys(r))\n\t\t\t\t//case 'Map': return this.decodeKeys(res)\n\t\t\t}\n\t\t}\n\t\treturn res\n\t}\n\n\tdecode(source, end) {\n\t\tif (src) {\n\t\t\t// re-entrant execution, save the state and restore it after we do this decode\n\t\t\treturn saveState(() => {\n\t\t\t\tclearSource()\n\t\t\t\treturn this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)\n\t\t\t})\n\t\t}\n\t\tsrcEnd = end > -1 ? end : source.length\n\t\tposition = 0\n\t\tstringPosition = 0\n\t\tsrcStringEnd = 0\n\t\tsrcString = null\n\t\tstrings = EMPTY_ARRAY\n\t\tbundledStrings = null\n\t\tsrc = source\n\t\t// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend\n\t\t// technique for getting data from a database where it can be copied into an existing buffer instead of creating\n\t\t// new ones\n\t\ttry {\n\t\t\tdataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))\n\t\t} catch(error) {\n\t\t\t// if it doesn't have a buffer, maybe it is the wrong type of object\n\t\t\tsrc = null\n\t\t\tif (source instanceof Uint8Array)\n\t\t\t\tthrow error\n\t\t\tthrow new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))\n\t\t}\n\t\tif (this instanceof Decoder) {\n\t\t\tcurrentDecoder = this\n\t\t\tpackedValues = this.sharedValues &&\n\t\t\t\t(this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :\n\t\t\t\tthis.sharedValues)\n\t\t\tif (this.structures) {\n\t\t\t\tcurrentStructures = this.structures\n\t\t\t\treturn checkedRead()\n\t\t\t} else if (!currentStructures || currentStructures.length > 0) {\n\t\t\t\tcurrentStructures = []\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentDecoder = defaultOptions\n\t\t\tif (!currentStructures || currentStructures.length > 0)\n\t\t\t\tcurrentStructures = []\n\t\t\tpackedValues = null\n\t\t}\n\t\treturn checkedRead()\n\t}\n\tdecodeMultiple(source, forEach) {\n\t\tlet values, lastPosition = 0\n\t\ttry {\n\t\t\tlet size = source.length\n\t\t\tsequentialMode = true\n\t\t\tlet value = this ? this.decode(source, size) : defaultDecoder.decode(source, size)\n\t\t\tif (forEach) {\n\t\t\t\tif (forEach(value) === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\twhile(position < size) {\n\t\t\t\t\tlastPosition = position\n\t\t\t\t\tif (forEach(checkedRead()) === false) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvalues = [ value ]\n\t\t\t\twhile(position < size) {\n\t\t\t\t\tlastPosition = position\n\t\t\t\t\tvalues.push(checkedRead())\n\t\t\t\t}\n\t\t\t\treturn values\n\t\t\t}\n\t\t} catch(error) {\n\t\t\terror.lastPosition = lastPosition\n\t\t\terror.values = values\n\t\t\tthrow error\n\t\t} finally {\n\t\t\tsequentialMode = false\n\t\t\tclearSource()\n\t\t}\n\t}\n}\nexport function getPosition() {\n\treturn position\n}\nexport function checkedRead() {\n\ttry {\n\t\tlet result = read()\n\t\tif (bundledStrings) {\n\t\t\tif (position >= bundledStrings.postBundlePosition) {\n\t\t\t\tlet error = new Error('Unexpected bundle position');\n\t\t\t\terror.incomplete = true;\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\t// bundled strings to skip past\n\t\t\tposition = bundledStrings.postBundlePosition;\n\t\t\tbundledStrings = null;\n\t\t}\n\n\t\tif (position == srcEnd) {\n\t\t\t// finished reading this source, cleanup references\n\t\t\tcurrentStructures = null\n\t\t\tsrc = null\n\t\t\tif (referenceMap)\n\t\t\t\treferenceMap = null\n\t\t} else if (position > srcEnd) {\n\t\t\t// over read\n\t\t\tlet error = new Error('Unexpected end of CBOR data')\n\t\t\terror.incomplete = true\n\t\t\tthrow error\n\t\t} else if (!sequentialMode) {\n\t\t\tthrow new Error('Data read, but end of buffer not reached')\n\t\t}\n\t\t// else more to read, but we are reading sequentially, so don't clear source yet\n\t\treturn result\n\t} catch(error) {\n\t\tclearSource()\n\t\tif (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {\n\t\t\terror.incomplete = true\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport function read() {\n\tlet token = src[position++]\n\tlet majorType = token >> 5\n\ttoken = token & 0x1f\n\tif (token > 0x17) {\n\t\tswitch (token) {\n\t\t\tcase 0x18:\n\t\t\t\ttoken = src[position++]\n\t\t\t\tbreak\n\t\t\tcase 0x19:\n\t\t\t\tif (majorType == 7) {\n\t\t\t\t\treturn getFloat16()\n\t\t\t\t}\n\t\t\t\ttoken = dataView.getUint16(position)\n\t\t\t\tposition += 2\n\t\t\t\tbreak\n\t\t\tcase 0x1a:\n\t\t\t\tif (majorType == 7) {\n\t\t\t\t\tlet value = dataView.getFloat32(position)\n\t\t\t\t\tif (currentDecoder.useFloat32 > 2) {\n\t\t\t\t\t\t// this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved\n\t\t\t\t\t\tlet multiplier = mult10[((src[position] & 0x7f) << 1) | (src[position + 1] >> 7)]\n\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\treturn ((multiplier * value + (value > 0 ? 0.5 : -0.5)) >> 0) / multiplier\n\t\t\t\t\t}\n\t\t\t\t\tposition += 4\n\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\ttoken = dataView.getUint32(position)\n\t\t\t\tposition += 4\n\t\t\t\tif (majorType === 1) return -1 - token; // can't safely use negation operator here\n\t\t\t\tbreak\n\t\t\tcase 0x1b:\n\t\t\t\tif (majorType == 7) {\n\t\t\t\t\tlet value = dataView.getFloat64(position)\n\t\t\t\t\tposition += 8\n\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\tif (majorType > 1) {\n\t\t\t\t\tif (dataView.getUint32(position) > 0)\n\t\t\t\t\t\tthrow new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')\n\t\t\t\t\ttoken = dataView.getUint32(position + 4)\n\t\t\t\t} else if (currentDecoder.int64AsNumber) {\n\t\t\t\t\ttoken = dataView.getUint32(position) * 0x100000000\n\t\t\t\t\ttoken += dataView.getUint32(position + 4)\n\t\t\t\t} else token = dataView.getBigUint64(position)\n\t\t\t\tposition += 8\n\t\t\t\tbreak\n\t\t\tcase 0x1f: \n\t\t\t\t// indefinite length\n\t\t\t\tswitch(majorType) {\n\t\t\t\t\tcase 2: // byte string\n\t\t\t\t\tcase 3: // text string\n\t\t\t\t\t\tthrow new Error('Indefinite length not supported for byte or text strings')\n\t\t\t\t\tcase 4: // array\n\t\t\t\t\t\tlet array = []\n\t\t\t\t\t\tlet value, i = 0\n\t\t\t\t\t\twhile ((value = read()) != STOP_CODE) {\n\t\t\t\t\t\t\tif (i >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)\n\t\t\t\t\t\t\tarray[i++] = value\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn majorType == 4 ? array : majorType == 3 ? array.join('') : Buffer.concat(array)\n\t\t\t\t\tcase 5: // map\n\t\t\t\t\t\tlet key\n\t\t\t\t\t\tif (currentDecoder.mapsAsObjects) {\n\t\t\t\t\t\t\tlet object = {}\n\t\t\t\t\t\t\tlet i = 0;\n\t\t\t\t\t\t\tif (currentDecoder.keyMap) {\n\t\t\t\t\t\t\t\twhile((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)\n\t\t\t\t\t\t\t\t\tobject[safeKey(currentDecoder.decodeKey(key))] = read()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\twhile ((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)\n\t\t\t\t\t\t\t\t\tobject[safeKey(key)] = read()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn object\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (restoreMapsAsObject) {\n\t\t\t\t\t\t\t\tcurrentDecoder.mapsAsObjects = true\n\t\t\t\t\t\t\t\trestoreMapsAsObject = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet map = new Map()\n\t\t\t\t\t\t\tif (currentDecoder.keyMap) {\n\t\t\t\t\t\t\t\tlet i = 0;\n\t\t\t\t\t\t\t\twhile((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(`Map size exceeds ${maxMapSize}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tmap.set(currentDecoder.decodeKey(key), read())\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tlet i = 0;\n\t\t\t\t\t\t\t\twhile ((key = read()) != STOP_CODE) {\n\t\t\t\t\t\t\t\t\tif (i++ >= maxMapSize) {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(`Map size exceeds ${maxMapSize}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tmap.set(key, read())\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn map\n\t\t\t\t\t\t}\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\treturn STOP_CODE\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new Error('Invalid major type for indefinite length ' + majorType)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error('Unknown token ' + token)\n\t\t}\n\t}\n\tswitch (majorType) {\n\t\tcase 0: // positive int\n\t\t\treturn token\n\t\tcase 1: // negative int\n\t\t\treturn ~token\n\t\tcase 2: // buffer\n\t\t\treturn readBin(token)\n\t\tcase 3: // string\n\t\t\tif (srcStringEnd >= position) {\n\t\t\t\treturn srcString.slice(position - srcStringStart, (position += token) - srcStringStart)\n\t\t\t}\n\t\t\tif (srcStringEnd == 0 && srcEnd < 140 && token < 32) {\n\t\t\t\t// for small blocks, avoiding the overhead of the extract call is helpful\n\t\t\t\tlet string = token < 16 ? shortStringInJS(token) : longStringInJS(token)\n\t\t\t\tif (string != null)\n\t\t\t\t\treturn string\n\t\t\t}\n\t\t\treturn readFixedString(token)\n\t\tcase 4: // array\n\t\t\tif (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)\n\t\t\tlet array = new Array(token)\n\t\t //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())\t\n\t\t\t//else \n\t\t\tfor (let i = 0; i < token; i++) array[i] = read()\n\t\t\treturn array\n\t\tcase 5: // map\n\t\t\tif (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)\n\t\t\tif (currentDecoder.mapsAsObjects) {\n\t\t\t\tlet object = {}\n\t\t\t\tif (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read()\n\t\t\t\telse for (let i = 0; i < token; i++) object[safeKey(read())] = read()\n\t\t\t\treturn object\n\t\t\t} else {\n\t\t\t\tif (restoreMapsAsObject) {\n\t\t\t\t\tcurrentDecoder.mapsAsObjects = true\n\t\t\t\t\trestoreMapsAsObject = false\n\t\t\t\t}\n\t\t\t\tlet map = new Map()\n\t\t\t\tif (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read())\n\t\t\t\telse for (let i = 0; i < token; i++) map.set(read(), read())\n\t\t\t\treturn map\n\t\t\t}\n\t\tcase 6: // extension\n\t\t\tif (token >= BUNDLED_STRINGS_ID) {\n\t\t\t\tlet structure = currentStructures[token & 0x1fff] // check record structures first\n\t\t\t\t// At some point we may provide an option for dynamic tag assignment with a range like token >= 8 && (token < 16 || (token > 0x80 && token < 0xc0) || (token > 0x130 && token < 0x4000))\n\t\t\t\tif (structure) {\n\t\t\t\t\tif (!structure.read) structure.read = createStructureReader(structure)\n\t\t\t\t\treturn structure.read()\n\t\t\t\t}\n\t\t\t\tif (token < 0x10000) {\n\t\t\t\t\tif (token == RECORD_INLINE_ID) { // we do a special check for this so that we can keep the\n\t\t\t\t\t\t// currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)\n\t\t\t\t\t\tlet length = readJustLength()\n\t\t\t\t\t\tlet id = read()\n\t\t\t\t\t\tlet structure = read()\n\t\t\t\t\t\trecordDefinition(id, structure)\n\t\t\t\t\t\tlet object = {}\n\t\t\t\t\t\tif (currentDecoder.keyMap) for (let i = 2; i < length; i++) {\n\t\t\t\t\t\t\tlet key = currentDecoder.decodeKey(structure[i - 2])\n\t\t\t\t\t\t\tobject[safeKey(key)] = read()\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse for (let i = 2; i < length; i++) {\n\t\t\t\t\t\t\tlet key = structure[i - 2]\n\t\t\t\t\t\t\tobject[safeKey(key)] = read()\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn object\n\t\t\t\t\t}\n\t\t\t\t\telse if (token == RECORD_DEFINITIONS_ID) {\n\t\t\t\t\t\tlet length = readJustLength()\n\t\t\t\t\t\tlet id = read()\n\t\t\t\t\t\tfor (let i = 2; i < length; i++) {\n\t\t\t\t\t\t\trecordDefinition(id++, read())\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn read()\n\t\t\t\t\t} else if (token == BUNDLED_STRINGS_ID) {\n\t\t\t\t\t\treturn readBundleExt()\n\t\t\t\t\t}\n\t\t\t\t\tif (currentDecoder.getShared) {\n\t\t\t\t\t\tloadShared()\n\t\t\t\t\t\tstructure = currentStructures[token & 0x1fff]\n\t\t\t\t\t\tif (structure) {\n\t\t\t\t\t\t\tif (!structure.read)\n\t\t\t\t\t\t\t\tstructure.read = createStructureReader(structure)\n\t\t\t\t\t\t\treturn structure.read()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet extension = currentExtensions[token]\n\t\t\tif (extension) {\n\t\t\t\tif (extension.handlesRead)\n\t\t\t\t\treturn extension(read)\n\t\t\t\telse\n\t\t\t\t\treturn extension(read())\n\t\t\t} else {\n\t\t\t\tlet input = read()\n\t\t\t\tfor (let i = 0; i < currentExtensionRanges.length; i++) {\n\t\t\t\t\tlet value = currentExtensionRanges[i](token, input)\n\t\t\t\t\tif (value !== undefined)\n\t\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\treturn new Tag(input, token)\n\t\t\t}\n\t\tcase 7: // fixed value\n\t\t\tswitch (token) {\n\t\t\t\tcase 0x14: return false\n\t\t\t\tcase 0x15: return true\n\t\t\t\tcase 0x16: return null\n\t\t\t\tcase 0x17: return; // undefined\n\t\t\t\tcase 0x1f:\n\t\t\t\tdefault:\n\t\t\t\t\tlet packedValue = (packedValues || getPackedValues())[token]\n\t\t\t\t\tif (packedValue !== undefined)\n\t\t\t\t\t\treturn packedValue\n\t\t\t\t\tthrow new Error('Unknown token ' + token)\n\t\t\t}\n\t\tdefault: // negative int\n\t\t\tif (isNaN(token)) {\n\t\t\t\tlet error = new Error('Unexpected end of CBOR data')\n\t\t\t\terror.incomplete = true\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new Error('Unknown CBOR token ' + token)\n\t}\n}\nconst validName = /^[a-zA-Z_$][a-zA-Z\\d_$]*$/\nfunction createStructureReader(structure) {\n\tif (!structure) throw new Error('Structure is required in record definition');\n\tfunction readObject() {\n\t\t// get the array size from the header\n\t\tlet length = src[position++]\n\t\t//let majorType = token >> 5\n\t\tlength = length & 0x1f\n\t\tif (length > 0x17) {\n\t\t\tswitch (length) {\n\t\t\t\tcase 0x18:\n\t\t\t\t\tlength = src[position++]\n\t\t\t\t\tbreak\n\t\t\t\tcase 0x19:\n\t\t\t\t\tlength = dataView.getUint16(position)\n\t\t\t\t\tposition += 2\n\t\t\t\t\tbreak\n\t\t\t\tcase 0x1a:\n\t\t\t\t\tlength = dataView.getUint32(position)\n\t\t\t\t\tposition += 4\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error('Expected array header, but got ' + src[position - 1])\n\t\t\t}\n\t\t}\n\t\t// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function\n\t\tlet compiledReader = this.compiledReader // first look to see if we have the fast compiled function\n\t\twhile(compiledReader) {\n\t\t\t// we have a fast compiled object literal reader\n\t\t\tif (compiledReader.propertyCount === length)\n\t\t\t\treturn compiledReader(read) // with the right length, so we use it\n\t\t\tcompiledReader = compiledReader.next // see if there is another reader with the right length\n\t\t}\n\t\tif (this.slowReads++ >= inlineObjectReadThreshold) { // create a fast compiled reader\n\t\t\tlet array = this.length == length ? this : this.slice(0, length)\n\t\t\tcompiledReader = currentDecoder.keyMap \n\t\t\t? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? safeKey(k) + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')\n\t\t\t: new Function('r', 'return {' + array.map(key => validName.test(key) ? safeKey(key) + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}')\n\t\t\tif (this.compiledReader)\n\t\t\t\tcompiledReader.next = this.compiledReader // if there is an existing one, we store multiple readers as a linked list because it is usually pretty rare to have multiple readers (of different length) for the same structure\n\t\t\tcompiledReader.propertyCount = length\n\t\t\tthis.compiledReader = compiledReader\n\t\t\treturn compiledReader(read)\n\t\t}\n\t\tlet object = {}\n\t\tif (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[safeKey(currentDecoder.decodeKey(this[i]))] = read()\n\t\telse for (let i = 0; i < length; i++) {\n\t\t\tobject[safeKey(this[i])] = read();\n\t\t}\n\t\treturn object\n\t}\n\tstructure.slowReads = 0\n\treturn readObject\n}\n\nfunction safeKey(key) {\n\t// protect against prototype pollution\n\tif (typeof key === 'string') return key === '__proto__' ? '__proto_' : key\n\tif (typeof key === 'number' || typeof key === 'boolean' || typeof key === 'bigint') return key.toString();\n\tif (key == null) return key + '';\n\t// protect against expensive (DoS) string conversions\n\tthrow new Error('Invalid property name type ' + typeof key);\n}\n\nlet readFixedString = readStringJS\nlet readString8 = readStringJS\nlet readString16 = readStringJS\nlet readString32 = readStringJS\n\nexport let isNativeAccelerationEnabled = false\nexport function setExtractor(extractStrings) {\n\tisNativeAccelerationEnabled = true\n\treadFixedString = readString(1)\n\treadString8 = readString(2)\n\treadString16 = readString(3)\n\treadString32 = readString(5)\n\tfunction readString(headerLength) {\n\t\treturn function readString(length) {\n\t\t\tlet string = strings[stringPosition++]\n\t\t\tif (string == null) {\n\t\t\t\tif (bundledStrings)\n\t\t\t\t\treturn readStringJS(length)\n\t\t\t\tlet extraction = extractStrings(position, srcEnd, length, src)\n\t\t\t\tif (typeof extraction == 'string') {\n\t\t\t\t\tstring = extraction\n\t\t\t\t\tstrings = EMPTY_ARRAY\n\t\t\t\t} else {\n\t\t\t\t\tstrings = extraction\n\t\t\t\t\tstringPosition = 1\n\t\t\t\t\tsrcStringEnd = 1 // even if a utf-8 string was decoded, must indicate we are in the midst of extracted strings and can't skip strings\n\t\t\t\t\tstring = strings[0]\n\t\t\t\t\tif (string === undefined)\n\t\t\t\t\t\tthrow new Error('Unexpected end of buffer')\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet srcStringLength = string.length\n\t\t\tif (srcStringLength <= length) {\n\t\t\t\tposition += length\n\t\t\t\treturn string\n\t\t\t}\n\t\t\tsrcString = string\n\t\t\tsrcStringStart = position\n\t\t\tsrcStringEnd = position + srcStringLength\n\t\t\tposition += length\n\t\t\treturn string.slice(0, length) // we know we just want the beginning\n\t\t}\n\t}\n}\nfunction readStringJS(length) {\n\tlet result\n\tif (length < 16) {\n\t\tif (result = shortStringInJS(length))\n\t\t\treturn result\n\t}\n\tif (length > 64 && decoder)\n\t\treturn decoder.decode(src.subarray(position, position += length))\n\tconst end = position + length\n\tconst units = []\n\tresult = ''\n\twhile (position < end) {\n\t\tconst byte1 = src[position++]\n\t\tif ((byte1 & 0x80) === 0) {\n\t\t\t// 1 byte\n\t\t\tunits.push(byte1)\n\t\t} else if ((byte1 & 0xe0) === 0xc0) {\n\t\t\t// 2 bytes\n\t\t\tif (byte1 < 0xc2 || position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\tunits.push(0xFFFD)\n\t\t\t} else {\n\t\t\t\tconst byte2 = src[position++] & 0x3f\n\t\t\t\tunits.push(((byte1 & 0x1f) << 6) | byte2)\n\t\t\t}\n\t\t} else if ((byte1 & 0xf0) === 0xe0) {\n\t\t\t// 3 bytes\n\t\t\tconst byte2 = position < end ? src[position] : 0\n\t\t\tif (position >= end || (byte2 & 0xc0) !== 0x80 ||\n\t\t\t\t(byte1 === 0xe0 && byte2 < 0xa0) || (byte1 === 0xed && byte2 >= 0xa0)) {\n\t\t\t\tunits.push(0xFFFD)\n\t\t\t} else {\n\t\t\t\tposition++\n\t\t\t\tif (position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\t\tunits.push(0xFFFD)\n\t\t\t\t} else {\n\t\t\t\t\tconst byte3 = src[position++] & 0x3f\n\t\t\t\t\tunits.push(((byte1 & 0x1f) << 12) | ((byte2 & 0x3f) << 6) | byte3)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ((byte1 & 0xf8) === 0xf0) {\n\t\t\t// 4 bytes\n\t\t\tconst byte2 = position < end ? src[position] : 0\n\t\t\tif (byte1 > 0xf4 || position >= end || (byte2 & 0xc0) !== 0x80 ||\n\t\t\t\t(byte1 === 0xf0 && byte2 < 0x90) || (byte1 === 0xf4 && byte2 >= 0x90)) {\n\t\t\t\tunits.push(0xFFFD)\n\t\t\t} else {\n\t\t\t\tposition++\n\t\t\t\tif (position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\t\tunits.push(0xFFFD)\n\t\t\t\t} else {\n\t\t\t\t\tconst byte3 = src[position++] & 0x3f\n\t\t\t\t\tif (position >= end || (src[position] & 0xc0) !== 0x80) {\n\t\t\t\t\t\tunits.push(0xFFFD)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst byte4 = src[position++] & 0x3f\n\t\t\t\t\t\tlet unit = ((byte1 & 0x07) << 0x12) | ((byte2 & 0x3f) << 0x0c) | (byte3 << 0x06) | byte4\n\t\t\t\t\t\tunit -= 0x10000\n\t\t\t\t\t\tunits.push(((unit >>> 10) & 0x3ff) | 0xd800)\n\t\t\t\t\t\tunits.push(0xdc00 | (unit & 0x3ff))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tunits.push(0xFFFD) // replacement character for invalid lead byte\n\t\t}\n\n\t\tif (units.length >= 0x1000) {\n\t\t\tresult += fromCharCode.apply(String, units)\n\t\t\tunits.length = 0\n\t\t}\n\t}\n\n\tif (units.length > 0) {\n\t\tresult += fromCharCode.apply(String, units)\n\t}\n\n\treturn result\n}\nlet fromCharCode = String.fromCharCode\nfunction longStringInJS(length) {\n\tlet start = position\n\tlet bytes = new Array(length)\n\tfor (let i = 0; i < length; i++) {\n\t\tconst byte = src[position++];\n\t\tif ((byte & 0x80) > 0) {\n\t\t\tposition = start\n \t\t\treturn\n \t\t}\n \t\tbytes[i] = byte\n \t}\n \treturn fromCharCode.apply(String, bytes)\n}\nfunction shortStringInJS(length) {\n\tif (length < 4) {\n\t\tif (length < 2) {\n\t\t\tif (length === 0)\n\t\t\t\treturn ''\n\t\t\telse {\n\t\t\t\tlet a = src[position++]\n\t\t\t\tif ((a & 0x80) > 1) {\n\t\t\t\t\tposition -= 1\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn fromCharCode(a)\n\t\t\t}\n\t\t} else {\n\t\t\tlet a = src[position++]\n\t\t\tlet b = src[position++]\n\t\t\tif ((a & 0x80) > 0 || (b & 0x80) > 0) {\n\t\t\t\tposition -= 2\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (length < 3)\n\t\t\t\treturn fromCharCode(a, b)\n\t\t\tlet c = src[position++]\n\t\t\tif ((c & 0x80) > 0) {\n\t\t\t\tposition -= 3\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn fromCharCode(a, b, c)\n\t\t}\n\t} else {\n\t\tlet a = src[position++]\n\t\tlet b = src[position++]\n\t\tlet c = src[position++]\n\t\tlet d = src[position++]\n\t\tif ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) {\n\t\t\tposition -= 4\n\t\t\treturn\n\t\t}\n\t\tif (length < 6) {\n\t\t\tif (length === 4)\n\t\t\t\treturn fromCharCode(a, b, c, d)\n\t\t\telse {\n\t\t\t\tlet e = src[position++]\n\t\t\t\tif ((e & 0x80) > 0) {\n\t\t\t\t\tposition -= 5\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn fromCharCode(a, b, c, d, e)\n\t\t\t}\n\t\t} else if (length < 8) {\n\t\t\tlet e = src[position++]\n\t\t\tlet f = src[position++]\n\t\t\tif ((e & 0x80) > 0 || (f & 0x80) > 0) {\n\t\t\t\tposition -= 6\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (length < 7)\n\t\t\t\treturn fromCharCode(a, b, c, d, e, f)\n\t\t\tlet g = src[position++]\n\t\t\tif ((g & 0x80) > 0) {\n\t\t\t\tposition -= 7\n\t\t\t\treturn\n\t\t\t}\n\t\t\treturn fromCharCode(a, b, c, d, e, f, g)\n\t\t} else {\n\t\t\tlet e = src[position++]\n\t\t\tlet f = src[position++]\n\t\t\tlet g = src[position++]\n\t\t\tlet h = src[position++]\n\t\t\tif ((e & 0x80) > 0 || (f & 0x80) > 0 || (g & 0x80) > 0 || (h & 0x80) > 0) {\n\t\t\t\tposition -= 8\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (length < 10) {\n\t\t\t\tif (length === 8)\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h)\n\t\t\t\telse {\n\t\t\t\t\tlet i = src[position++]\n\t\t\t\t\tif ((i & 0x80) > 0) {\n\t\t\t\t\t\tposition -= 9\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i)\n\t\t\t\t}\n\t\t\t} else if (length < 12) {\n\t\t\t\tlet i = src[position++]\n\t\t\t\tlet j = src[position++]\n\t\t\t\tif ((i & 0x80) > 0 || (j & 0x80) > 0) {\n\t\t\t\t\tposition -= 10\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (length < 11)\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j)\n\t\t\t\tlet k = src[position++]\n\t\t\t\tif ((k & 0x80) > 0) {\n\t\t\t\t\tposition -= 11\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k)\n\t\t\t} else {\n\t\t\t\tlet i = src[position++]\n\t\t\t\tlet j = src[position++]\n\t\t\t\tlet k = src[position++]\n\t\t\t\tlet l = src[position++]\n\t\t\t\tif ((i & 0x80) > 0 || (j & 0x80) > 0 || (k & 0x80) > 0 || (l & 0x80) > 0) {\n\t\t\t\t\tposition -= 12\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (length < 14) {\n\t\t\t\t\tif (length === 12)\n\t\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l)\n\t\t\t\t\telse {\n\t\t\t\t\t\tlet m = src[position++]\n\t\t\t\t\t\tif ((m & 0x80) > 0) {\n\t\t\t\t\t\t\tposition -= 13\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlet m = src[position++]\n\t\t\t\t\tlet n = src[position++]\n\t\t\t\t\tif ((m & 0x80) > 0 || (n & 0x80) > 0) {\n\t\t\t\t\t\tposition -= 14\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif (length < 15)\n\t\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n)\n\t\t\t\t\tlet o = src[position++]\n\t\t\t\t\tif ((o & 0x80) > 0) {\n\t\t\t\t\t\tposition -= 15\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\treturn fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction readBin(length) {\n\treturn currentDecoder.copyBuffers ?\n\t\t// specifically use the copying slice (not the node one)\n\t\tUint8Array.prototype.slice.call(src, position, position += length) :\n\t\tsrc.subarray(position, position += length)\n}\nfunction readExt(length) {\n\tlet type = src[position++]\n\tif (currentExtensions[type]) {\n\t\treturn currentExtensions[type](src.subarray(position, position += length))\n\t}\n\telse\n\t\tthrow new Error('Unknown extension type ' + type)\n}\nlet f32Array = new Float32Array(1)\nlet u8Array = new Uint8Array(f32Array.buffer, 0, 4)\nfunction getFloat16() {\n\tlet byte0 = src[position++]\n\tlet byte1 = src[position++]\n\tlet exponent = (byte0 & 0x7f) >> 2;\n\tif (exponent === 0x1f) { // specials\n\t\tif (byte1 || (byte0 & 3))\n\t\t\treturn NaN;\n\t\treturn (byte0 & 0x80) ? -Infinity : Infinity;\n\t}\n\tif (exponent === 0) { // sub-normals\n\t\t// significand with 10 fractional bits and divided by 2^14\n\t\tlet abs = (((byte0 & 3) << 8) | byte1) / (1 << 24)\n\t\treturn (byte0 & 0x80) ? -abs : abs\n\t}\n\n\tu8Array[3] = (byte0 & 0x80) | // sign bit\n\t\t((exponent >> 1) + 56) // 4 of 5 of the exponent bits, re-offset-ed\n\tu8Array[2] = ((byte0 & 7) << 5) | // last exponent bit and first two mantissa bits\n\t\t(byte1 >> 3) // next 5 bits of mantissa\n\tu8Array[1] = byte1 << 5; // last three bits of mantissa\n\tu8Array[0] = 0;\n\treturn f32Array[0];\n}\n\nlet keyCache = new Array(4096)\nfunction readKey() {\n\tlet length = src[position++]\n\tif (length >= 0x60 && length < 0x78) {\n\t\t// fixstr, potentially use key cache\n\t\tlength = length - 0x60\n\t\tif (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)\n\t\t\treturn srcString.slice(position - srcStringStart, (position += length) - srcStringStart)\n\t\telse if (!(srcStringEnd == 0 && srcEnd < 180))\n\t\t\treturn readFixedString(length)\n\t} else { // not cacheable, go back and do a standard read\n\t\tposition--\n\t\treturn read()\n\t}\n\tlet key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff\n\tlet entry = keyCache[key]\n\tlet checkPosition = position\n\tlet end = position + length - 3\n\tlet chunk\n\tlet i = 0\n\tif (entry && entry.bytes == length) {\n\t\twhile (checkPosition < end) {\n\t\t\tchunk = dataView.getUint32(checkPosition)\n\t\t\tif (chunk != entry[i++]) {\n\t\t\t\tcheckPosition = 0x70000000\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcheckPosition += 4\n\t\t}\n\t\tend += 3\n\t\twhile (checkPosition < end) {\n\t\t\tchunk = src[checkPosition++]\n\t\t\tif (chunk != entry[i++]) {\n\t\t\t\tcheckPosition = 0x70000000\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (checkPosition === end) {\n\t\t\tposition = checkPosition\n\t\t\treturn entry.string\n\t\t}\n\t\tend -= 3\n\t\tcheckPosition = position\n\t}\n\tentry = []\n\tkeyCache[key] = entry\n\tentry.bytes = length\n\twhile (checkPosition < end) {\n\t\tchunk = dataView.getUint32(checkPosition)\n\t\tentry.push(chunk)\n\t\tcheckPosition += 4\n\t}\n\tend += 3\n\twhile (checkPosition < end) {\n\t\tchunk = src[checkPosition++]\n\t\tentry.push(chunk)\n\t}\n\t// for small blocks, avoiding the overhead of the extract call is helpful\n\tlet string = length < 16 ? shortStringInJS(length) : longStringInJS(length)\n\tif (string != null)\n\t\treturn entry.string = string\n\treturn entry.string = readFixedString(length)\n}\n\nexport class Tag {\n\tconstructor(value, tag) {\n\t\tthis.value = value\n\t\tthis.tag = tag\n\t}\n}\n\ncurrentExtensions[0] = (dateString) => {\n\t// string date extension\n\treturn new Date(dateString)\n}\n\ncurrentExtensions[1] = (epochSec) => {\n\t// numeric date extension\n\treturn new Date(Math.round(epochSec * 1000))\n}\n\ncurrentExtensions[2] = (buffer) => {\n\t// bigint extension\n\tlet value = BigInt(0)\n\tfor (let i = 0, l = buffer.byteLength; i < l; i++) {\n\t\tvalue = BigInt(buffer[i]) + (value << BigInt(8))\n\t}\n\treturn value\n}\n\ncurrentExtensions[3] = (buffer) => {\n\t// negative bigint extension\n\treturn BigInt(-1) - currentExtensions[2](buffer)\n}\ncurrentExtensions[4] = (fraction) => {\n\t// best to reparse to maintain accuracy\n\treturn +(fraction[1] + 'e' + fraction[0])\n}\n\ncurrentExtensions[5] = (fraction) => {\n\t// probably not sufficiently accurate\n\treturn fraction[1] * Math.exp(fraction[0] * Math.log(2))\n}\n\n// the registration of the record definition extension\nconst recordDefinition = (id, structure) => {\n\tid = id - 0xe000\n\tlet existingStructure = currentStructures[id]\n\tif (existingStructure && existingStructure.isShared) {\n\t\t(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure\n\t}\n\tcurrentStructures[id] = structure\n\n\tstructure.read = createStructureReader(structure)\n}\ncurrentExtensions[LEGACY_RECORD_INLINE_ID] = (data) => {\n\tlet length = data.length\n\tlet structure = data[1]\n\trecordDefinition(data[0], structure)\n\tlet object = {}\n\tfor (let i = 2; i < length; i++) {\n\t\tlet key = structure[i - 2]\n\t\tobject[safeKey(key)] = data[i]\n\t}\n\treturn object\n}\ncurrentExtensions[14] = (value) => {\n\tif (bundledStrings)\n\t\treturn bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)\n\treturn new Tag(value, 14)\n}\ncurrentExtensions[15] = (value) => {\n\tif (bundledStrings)\n\t\treturn bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)\n\treturn new Tag(value, 15)\n}\nlet glbl = { Error, RegExp }\ncurrentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object\n\treturn (glbl[data[0]] || Error)(data[1], data[2])\n}\nconst packedTable = (read) => {\n\tif (src[position++] != 0x84) {\n\t\tlet error = new Error('Packed values structure must be followed by a 4 element array')\n\t\tif (src.length < position)\n\t\t\terror.incomplete = true\n\t\tthrow error\n\t}\n\tlet newPackedValues = read() // packed values\n\tif (!newPackedValues || !newPackedValues.length) {\n\t\tlet error = new Error('Packed values structure must be followed by a 4 element array')\n\t\terror.incomplete = true\n\t\tthrow error\n\t}\n\tpackedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues\n\tpackedValues.prefixes = read()\n\tpackedValues.suffixes = read()\n\treturn read() // read the rump\n}\npackedTable.handlesRead = true\ncurrentExtensions[51] = packedTable\n\ncurrentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference\n\tif (!packedValues) {\n\t\tif (currentDecoder.getShared)\n\t\t\tloadShared()\n\t\telse\n\t\t\treturn new Tag(data, PACKED_REFERENCE_TAG_ID)\n\t}\n\tif (typeof data == 'number')\n\t\treturn packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]\n\tlet error = new Error('No support for non-integer packed references yet')\n\tif (data === undefined)\n\t\terror.incomplete = true\n\tthrow error\n}\n\n// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref\n// the real thing would need to implemennt more logic to populate the stringRefs table and\n// maintain a stack of stringRef \"namespaces\".\n//\n// currentExtensions[25] = (id) => {\n// \treturn stringRefs[id]\n// }\n// currentExtensions[256] = (read) => {\n// \tstringRefs = []\n// \ttry {\n// \t\treturn read()\n// \t} finally {\n// \t\tstringRefs = null\n// \t}\n// }\n// currentExtensions[256].handlesRead = true\n\ncurrentExtensions[28] = (read) => { \n\t// shareable http://cbor.schmorp.de/value-sharing (for structured clones)\n\tif (!referenceMap) {\n\t\treferenceMap = new Map()\n\t\treferenceMap.id = 0\n\t}\n\tlet id = referenceMap.id++\n\tlet startingPosition = position\n\tlet token = src[position]\n\tlet target\n\t// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read\n\t// ahead past references to record structure definitions\n\tif ((token >> 5) == 4)\n\t\ttarget = []\n\telse\n\t\ttarget = {}\n\n\tlet refEntry = { target } // a placeholder object\n\treferenceMap.set(id, refEntry)\n\tlet targetProperties = read() // read the next value as the target object to id\n\tif (refEntry.used) {// there is a cycle, so we have to assign properties to original target\n\t\tif (Object.getPrototypeOf(target) !== Object.getPrototypeOf(targetProperties)) {\n\t\t\t// this means that the returned target does not match the targetProperties, so we need rerun the read to\n\t\t\t// have the correctly create instance be assigned as a reference, then we do the copy the properties back to the\n\t\t\t// target\n\t\t\t// reset the position so that the read can be repeated\n\t\t\tposition = startingPosition\n\t\t\t// the returned instance is our new target for references\n\t\t\ttarget = targetProperties\n\t\t\treferenceMap.set(id, { target })\n\t\t\ttargetProperties = read()\n\t\t}\n\t\treturn Object.assign(target, targetProperties)\n\t}\n\trefEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one\n\treturn targetProperties // no cycle, can just use the returned read object\n}\ncurrentExtensions[28].handlesRead = true\n\ncurrentExtensions[29] = (id) => {\n\t// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)\n\tlet refEntry = referenceMap.get(id)\n\trefEntry.used = true\n\treturn refEntry.target\n}\n\ncurrentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md\n(currentExtensions[259] = (read) => {\n\t// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec\n\t// for decoding as a standard Map\n\tif (currentDecoder.mapsAsObjects) {\n\t\tcurrentDecoder.mapsAsObjects = false\n\t\trestoreMapsAsObject = true\n\t}\n\treturn read()\n}).handlesRead = true\nfunction combine(a, b) {\n\tif (typeof a === 'string')\n\t\treturn a + b\n\tif (a instanceof Array)\n\t\treturn a.concat(b)\n\treturn Object.assign({}, a, b)\n}\nfunction getPackedValues() {\n\tif (!packedValues) {\n\t\tif (currentDecoder.getShared)\n\t\t\tloadShared()\n\t\telse\n\t\t\tthrow new Error('No packed values available')\n\t}\n\treturn packedValues\n}\nconst SHARED_DATA_TAG_ID = 0x53687264 // ascii 'Shrd'\ncurrentExtensionRanges.push((tag, input) => {\n\tif (tag >= 225 && tag <= 255)\n\t\treturn combine(getPackedValues().prefixes[tag - 224], input)\n\tif (tag >= 28704 && tag <= 32767)\n\t\treturn combine(getPackedValues().prefixes[tag - 28672], input)\n\tif (tag >= 1879052288 && tag <= 2147483647)\n\t\treturn combine(getPackedValues().prefixes[tag - 1879048192], input)\n\tif (tag >= 216 && tag <= 223)\n\t\treturn combine(input, getPackedValues().suffixes[tag - 216])\n\tif (tag >= 27647 && tag <= 28671)\n\t\treturn combine(input, getPackedValues().suffixes[tag - 27639])\n\tif (tag >= 1811940352 && tag <= 1879048191)\n\t\treturn combine(input, getPackedValues().suffixes[tag - 1811939328])\n\tif (tag == SHARED_DATA_TAG_ID) {// we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)\n\t\treturn {\n\t\t\tpackedValues: packedValues,\n\t\t\tstructures: currentStructures.slice(0),\n\t\t\tversion: input,\n\t\t}\n\t}\n\tif (tag == 55799) // self-descriptive CBOR tag, just return input value\n\t\treturn input\n})\n\nconst isLittleEndianMachine = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1\nexport const typedArrays = [Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,\n\ttypeof BigUint64Array == 'undefined' ? { name:'BigUint64Array' } : BigUint64Array, Int8Array, Int16Array, Int32Array,\n\ttypeof BigInt64Array == 'undefined' ? { name:'BigInt64Array' } : BigInt64Array, Float32Array, Float64Array]\nconst typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 85, 86]\nfor (let i = 0; i < typedArrays.length; i++) {\n\tregisterTypedArray(typedArrays[i], typedArrayTags[i])\n}\nfunction registerTypedArray(TypedArray, tag) {\n\tlet dvMethod = 'get' + TypedArray.name.slice(0, -5)\n\tlet bytesPerElement;\n\tif (typeof TypedArray === 'function')\n\t\tbytesPerElement = TypedArray.BYTES_PER_ELEMENT;\n\telse\n\t\tTypedArray = null;\n\tfor (let littleEndian = 0; littleEndian < 2; littleEndian++) {\n\t\tif (!littleEndian && bytesPerElement == 1)\n\t\t\tcontinue\n\t\tlet sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : bytesPerElement == 8 ? 3 : 0\n\t\tcurrentExtensions[littleEndian ? tag : (tag - 4)] = (bytesPerElement == 1 || littleEndian == isLittleEndianMachine) ? (buffer) => {\n\t\t\tif (!TypedArray)\n\t\t\t\tthrow new Error('Could not find typed array for code ' + tag)\n\t\t\tif (!currentDecoder.copyBuffers) {\n\t\t\t\t// try provide a direct view, but will only work if we are byte-aligned\n\t\t\t\tif (bytesPerElement === 1 ||\n\t\t\t\t\tbytesPerElement === 2 && !(buffer.byteOffset & 1) ||\n\t\t\t\t\tbytesPerElement === 4 && !(buffer.byteOffset & 3) ||\n\t\t\t\t\tbytesPerElement === 8 && !(buffer.byteOffset & 7))\n\t\t\t\t\treturn new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength >> sizeShift);\n\t\t\t}\n\t\t\t// we have to slice/copy here to get a new ArrayBuffer, if we are not word/byte aligned\n\t\t\treturn new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)\n\t\t} : buffer => {\n\t\t\tif (!TypedArray)\n\t\t\t\tthrow new Error('Could not find typed array for code ' + tag)\n\t\t\tlet dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n\t\t\tlet elements = buffer.length >> sizeShift\n\t\t\tlet ta = new TypedArray(elements)\n\t\t\tlet method = dv[dvMethod]\n\t\t\tfor (let i = 0; i < elements; i++) {\n\t\t\t\tta[i] = method.call(dv, i << sizeShift, littleEndian)\n\t\t\t}\n\t\t\treturn ta\n\t\t}\n\t}\n}\n\nfunction readBundleExt() {\n\tlet length = readJustLength()\n\tlet bundlePosition = position + read()\n\tfor (let i = 2; i < length; i++) {\n\t\t// skip past bundles that were already read\n\t\tlet bundleLength = readJustLength() // this will increment position, so must add to position afterwards\n\t\tposition += bundleLength\n\t}\n\tlet dataPosition = position\n\tposition = bundlePosition\n\tbundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())]\n\tbundledStrings.position0 = 0\n\tbundledStrings.position1 = 0\n\tbundledStrings.postBundlePosition = position\n\tposition = dataPosition\n\treturn read()\n}\n\nfunction readJustLength() {\n\tlet token = src[position++] & 0x1f\n\tif (token > 0x17) {\n\t\tswitch (token) {\n\t\t\tcase 0x18:\n\t\t\t\ttoken = src[position++]\n\t\t\t\tbreak\n\t\t\tcase 0x19:\n\t\t\t\ttoken = dataView.getUint16(position)\n\t\t\t\tposition += 2\n\t\t\t\tbreak\n\t\t\tcase 0x1a:\n\t\t\t\ttoken = dataView.getUint32(position)\n\t\t\t\tposition += 4\n\t\t\t\tbreak\n\t\t}\n\t}\n\treturn token\n}\n\nfunction loadShared() {\n\tif (currentDecoder.getShared) {\n\t\tlet sharedData = saveState(() => {\n\t\t\t// save the state in case getShared modifies our buffer\n\t\t\tsrc = null\n\t\t\treturn currentDecoder.getShared()\n\t\t}) || {}\n\t\tlet updatedStructures = sharedData.structures || []\n\t\tcurrentDecoder.sharedVersion = sharedData.version\n\t\tpackedValues = currentDecoder.sharedValues = sharedData.packedValues\n\t\tif (currentStructures === true)\n\t\t\tcurrentDecoder.structures = currentStructures = updatedStructures\n\t\telse\n\t\t\tcurrentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))\n\t}\n}\n\nfunction saveState(callback) {\n\tlet savedSrcEnd = srcEnd\n\tlet savedPosition = position\n\tlet savedStringPosition = stringPosition\n\tlet savedSrcStringStart = srcStringStart\n\tlet savedSrcStringEnd = srcStringEnd\n\tlet savedSrcString = srcString\n\tlet savedStrings = strings\n\tlet savedReferenceMap = referenceMap\n\tlet savedBundledStrings = bundledStrings\n\n\t// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)\n\tlet savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed\n\tlet savedStructures = currentStructures\n\tlet savedDecoder = currentDecoder\n\tlet savedSequentialMode = sequentialMode\n\tlet value = callback()\n\tsrcEnd = savedSrcEnd\n\tposition = savedPosition\n\tstringPosition = savedStringPosition\n\tsrcStringStart = savedSrcStringStart\n\tsrcStringEnd = savedSrcStringEnd\n\tsrcString = savedSrcString\n\tstrings = savedStrings\n\treferenceMap = savedReferenceMap\n\tbundledStrings = savedBundledStrings\n\tsrc = savedSrc\n\tsequentialMode = savedSequentialMode\n\tcurrentStructures = savedStructures\n\tcurrentDecoder = savedDecoder\n\tdataView = new DataView(src.buffer, src.byteOffset, src.byteLength)\n\treturn value\n}\nexport function clearSource() {\n\tsrc = null\n\treferenceMap = null\n\tcurrentStructures = null\n}\n\nexport function addExtension(extension) {\n\tcurrentExtensions[extension.tag] = extension.decode\n}\n\nexport function setSizeLimits(limits) {\n\tif (limits.maxMapSize) maxMapSize = limits.maxMapSize;\n\tif (limits.maxArraySize) maxArraySize = limits.maxArraySize;\n\tif (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize;\n}\n\nexport const mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding\nfor (let i = 0; i < 256; i++) {\n\tmult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))\n}\nlet defaultDecoder = new Decoder({ useRecords: false })\nexport const decode = defaultDecoder.decode\nexport const decodeMultiple = defaultDecoder.decodeMultiple\nexport const FLOAT32_OPTIONS = {\n\tNEVER: 0,\n\tALWAYS: 1,\n\tDECIMAL_ROUND: 3,\n\tDECIMAL_FIT: 4\n}\nexport function roundFloat32(float32Number) {\n\tf32Array[0] = float32Number\n\tlet multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]\n\treturn ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier\n}\n","import { Decoder, mult10, Tag, typedArrays, addExtension as decodeAddExtension } from './decode.js'\nlet textEncoder\ntry {\n\ttextEncoder = new TextEncoder()\n} catch (error) {}\nlet extensions, extensionClasses\nconst Buffer = typeof globalThis === 'object' && globalThis.Buffer;\nconst hasNodeBuffer = typeof Buffer !== 'undefined'\nconst ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array\nconst ByteArray = hasNodeBuffer ? Buffer : Uint8Array\nconst MAX_STRUCTURES = 0x100\nconst MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000\nlet serializationId = 1\nlet throwOnIterable\nlet target\nlet targetView\nlet position = 0\nlet safeEnd\nlet bundledStrings = null\nconst MAX_BUNDLE_SIZE = 0xf000\nconst hasNonLatin = /[\\u0080-\\uFFFF]/\nconst RECORD_SYMBOL = Symbol('record-id')\nexport class Encoder extends Decoder {\n\tconstructor(options) {\n\t\tsuper(options)\n\t\tthis.offset = 0\n\t\tlet typeBuffer\n\t\tlet start\n\t\tlet sharedStructures\n\t\tlet hasSharedUpdate\n\t\tlet structures\n\t\tlet referenceMap\n\t\toptions = options || {}\n\t\tlet encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position) {\n\t\t\treturn target.utf8Write(string, position, target.byteLength - position)\n\t\t} : (textEncoder && textEncoder.encodeInto) ?\n\t\t\tfunction(string, position) {\n\t\t\t\treturn textEncoder.encodeInto(string, target.subarray(position)).written\n\t\t\t} : false\n\n\t\tlet encoder = this\n\t\tlet hasSharedStructures = options.structures || options.saveStructures\n\t\tlet maxSharedStructures = options.maxSharedStructures\n\t\tif (maxSharedStructures == null)\n\t\t\tmaxSharedStructures = hasSharedStructures ? 128 : 0\n\t\tif (maxSharedStructures > 8190)\n\t\t\tthrow new Error('Maximum maxSharedStructure is 8190')\n\t\tlet isSequential = options.sequential\n\t\tif (isSequential) {\n\t\t\tmaxSharedStructures = 0\n\t\t}\n\t\tif (!this.structures)\n\t\t\tthis.structures = []\n\t\tif (this.saveStructures)\n\t\t\tthis.saveShared = this.saveStructures\n\t\tlet samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues\n\t\tlet sharedPackedObjectMap\n\t\tif (sharedValues) {\n\t\t\tsharedPackedObjectMap = Object.create(null)\n\t\t\tfor (let i = 0, l = sharedValues.length; i < l; i++) {\n\t\t\t\tsharedPackedObjectMap[sharedValues[i]] = i\n\t\t\t}\n\t\t}\n\t\tlet recordIdsToRemove = []\n\t\tlet transitionsCount = 0\n\t\tlet serializationsSinceTransitionRebuild = 0\n\t\t\n\t\tthis.mapEncode = function(value, encodeOptions) {\n\t\t\t// Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)\n\t\t\tif (this._keyMap && !this._mapped) {\n\t\t\t\t//console.log('encoding ', value)\n\t\t\t\tswitch (value.constructor.name) {\n\t\t\t\t\tcase 'Array': \n\t\t\t\t\t\tvalue = value.map(r => this.encodeKeys(r))\n\t\t\t\t\t\tbreak\n\t\t\t\t\t//case 'Map': \n\t\t\t\t\t//\tvalue = this.encodeKeys(value)\n\t\t\t\t\t//\tbreak\n\t\t\t\t}\n\t\t\t\t//this._mapped = true\n\t\t\t}\n\t\t\treturn this.encode(value, encodeOptions)\n\t\t}\n\t\t\n\t\tthis.encode = function(value, encodeOptions)\t{\n\t\t\tif (!target) {\n\t\t\t\ttarget = new ByteArrayAllocate(8192)\n\t\t\t\ttargetView = new DataView(target.buffer, 0, 8192)\n\t\t\t\tposition = 0\n\t\t\t}\n\t\t\tsafeEnd = target.length - 10\n\t\t\tif (safeEnd - position < 0x800) {\n\t\t\t\t// don't start too close to the end, \n\t\t\t\ttarget = new ByteArrayAllocate(target.length)\n\t\t\t\ttargetView = new DataView(target.buffer, 0, target.length)\n\t\t\t\tsafeEnd = target.length - 10\n\t\t\t\tposition = 0\n\t\t\t} else if (encodeOptions === REUSE_BUFFER_MODE)\n\t\t\t\tposition = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster\n\t\t\tstart = position\n\t\t\tif (encoder.useSelfDescribedHeader) {\n\t\t\t\ttargetView.setUint32(position, 0xd9d9f700) // tag two byte, then self-descriptive tag\n\t\t\t\tposition += 3\n\t\t\t}\n\t\t\treferenceMap = encoder.structuredClone ? new Map() : null\n\t\t\tif (encoder.bundleStrings && typeof value !== 'string') {\n\t\t\t\tbundledStrings = []\n\t\t\t\tbundledStrings.size = Infinity // force a new bundle start on first string\n\t\t\t} else\n\t\t\t\tbundledStrings = null\n\n\t\t\tsharedStructures = encoder.structures\n\t\t\tif (sharedStructures) {\n\t\t\t\tif (sharedStructures.uninitialized) {\n\t\t\t\t\tlet sharedData = encoder.getShared() || {}\n\t\t\t\t\tencoder.structures = sharedStructures = sharedData.structures || []\n\t\t\t\t\tencoder.sharedVersion = sharedData.version\n\t\t\t\t\tlet sharedValues = encoder.sharedValues = sharedData.packedValues\n\t\t\t\t\tif (sharedValues) {\n\t\t\t\t\t\tsharedPackedObjectMap = {}\n\t\t\t\t\t\tfor (let i = 0, l = sharedValues.length; i < l; i++)\n\t\t\t\t\t\t\tsharedPackedObjectMap[sharedValues[i]] = i\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlet sharedStructuresLength = sharedStructures.length\n\t\t\t\tif (sharedStructuresLength > maxSharedStructures && !isSequential)\n\t\t\t\t\tsharedStructuresLength = maxSharedStructures\n\t\t\t\tif (!sharedStructures.transitions) {\n\t\t\t\t\t// rebuild our structure transitions\n\t\t\t\t\tsharedStructures.transitions = Object.create(null)\n\t\t\t\t\tfor (let i = 0; i < sharedStructuresLength; i++) {\n\t\t\t\t\t\tlet keys = sharedStructures[i]\n\t\t\t\t\t\t//console.log('shared struct keys:', keys)\n\t\t\t\t\t\tif (!keys)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tlet nextTransition, transition = sharedStructures.transitions\n\t\t\t\t\t\tfor (let j = 0, l = keys.length; j < l; j++) {\n\t\t\t\t\t\t\tif (transition[RECORD_SYMBOL] === undefined)\n\t\t\t\t\t\t\t\ttransition[RECORD_SYMBOL] = i\n\t\t\t\t\t\t\tlet key = keys[j]\n\t\t\t\t\t\t\tnextTransition = transition[key]\n\t\t\t\t\t\t\tif (!nextTransition) {\n\t\t\t\t\t\t\t\tnextTransition = transition[key] = Object.create(null)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttransition = nextTransition\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttransition[RECORD_SYMBOL] = i | 0x100000\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!isSequential)\n\t\t\t\t\tsharedStructures.nextId = sharedStructuresLength\n\t\t\t}\n\t\t\tif (hasSharedUpdate)\n\t\t\t\thasSharedUpdate = false\n\t\t\tstructures = sharedStructures || []\n\t\t\tpackedObjectMap = sharedPackedObjectMap\n\t\t\tif (options.pack) {\n\t\t\t\tlet packedValues = new Map()\n\t\t\t\tpackedValues.values = []\n\t\t\t\tpackedValues.encoder = encoder\n\t\t\t\tpackedValues.maxValues = options.maxPrivatePackedValues || (sharedPackedObjectMap ? 16 : Infinity)\n\t\t\t\tpackedValues.objectMap = sharedPackedObjectMap || false\n\t\t\t\tpackedValues.samplingPackedValues = samplingPackedValues\n\t\t\t\tfindRepetitiveStrings(value, packedValues)\n\t\t\t\tif (packedValues.values.length > 0) {\n\t\t\t\t\ttarget[position++] = 0xd8 // one-byte tag\n\t\t\t\t\ttarget[position++] = 51 // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\t\t\twriteArrayHeader(4)\n\t\t\t\t\tlet valuesArray = packedValues.values\n\t\t\t\t\tencode(valuesArray)\n\t\t\t\t\twriteArrayHeader(0) // prefixes\n\t\t\t\t\twriteArrayHeader(0) // suffixes\n\t\t\t\t\tpackedObjectMap = Object.create(sharedPackedObjectMap || null)\n\t\t\t\t\tfor (let i = 0, l = valuesArray.length; i < l; i++) {\n\t\t\t\t\t\tpackedObjectMap[valuesArray[i]] = i\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrowOnIterable = encodeOptions & THROW_ON_ITERABLE;\n\t\t\ttry {\n\t\t\t\tif (throwOnIterable)\n\t\t\t\t\treturn;\n\t\t\t\tencode(value)\n\t\t\t\tif (bundledStrings) {\n\t\t\t\t\twriteBundles(start, encode)\n\t\t\t\t}\n\t\t\t\tencoder.offset = position // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially\n\t\t\t\tif (referenceMap && referenceMap.idsToInsert) {\n\t\t\t\t\tposition += referenceMap.idsToInsert.length * 2\n\t\t\t\t\tif (position > safeEnd)\n\t\t\t\t\t\tmakeRoom(position)\n\t\t\t\t\tencoder.offset = position\n\t\t\t\t\tlet serialized = insertIds(target.subarray(start, position), referenceMap.idsToInsert)\n\t\t\t\t\treferenceMap = null\n\t\t\t\t\treturn serialized\n\t\t\t\t}\n\t\t\t\tif (encodeOptions & REUSE_BUFFER_MODE) {\n\t\t\t\t\ttarget.start = start\n\t\t\t\t\ttarget.end = position\n\t\t\t\t\treturn target\n\t\t\t\t}\n\t\t\t\treturn target.subarray(start, position) // position can change if we call encode again in saveShared, so we get the buffer now\n\t\t\t} finally {\n\t\t\t\tif (sharedStructures) {\n\t\t\t\t\tif (serializationsSinceTransitionRebuild < 10)\n\t\t\t\t\t\tserializationsSinceTransitionRebuild++\n\t\t\t\t\tif (sharedStructures.length > maxSharedStructures)\n\t\t\t\t\t\tsharedStructures.length = maxSharedStructures\n\t\t\t\t\tif (transitionsCount > 10000) {\n\t\t\t\t\t\t// force a rebuild occasionally after a lot of transitions so it can get cleaned up\n\t\t\t\t\t\tsharedStructures.transitions = null\n\t\t\t\t\t\tserializationsSinceTransitionRebuild = 0\n\t\t\t\t\t\ttransitionsCount = 0\n\t\t\t\t\t\tif (recordIdsToRemove.length > 0)\n\t\t\t\t\t\t\trecordIdsToRemove = []\n\t\t\t\t\t} else if (recordIdsToRemove.length > 0 && !isSequential) {\n\t\t\t\t\t\tfor (let i = 0, l = recordIdsToRemove.length; i < l; i++) {\n\t\t\t\t\t\t\trecordIdsToRemove[i][RECORD_SYMBOL] = undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t\trecordIdsToRemove = []\n\t\t\t\t\t\t//sharedStructures.nextId = maxSharedStructures\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (hasSharedUpdate && encoder.saveShared) {\n\t\t\t\t\tif (encoder.structures.length > maxSharedStructures) {\n\t\t\t\t\t\tencoder.structures = encoder.structures.slice(0, maxSharedStructures)\n\t\t\t\t\t}\n\t\t\t\t\t// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save\n\t\t\t\t\tlet returnBuffer = target.subarray(start, position)\n\t\t\t\t\tif (encoder.updateSharedData() === false)\n\t\t\t\t\t\treturn encoder.encode(value) // re-encode if it fails\n\t\t\t\t\treturn returnBuffer\n\t\t\t\t}\n\t\t\t\tif (encodeOptions & RESET_BUFFER_MODE)\n\t\t\t\t\tposition = start\n\t\t\t}\n\t\t}\n\t\tthis.findCommonStringsToPack = () => {\n\t\t\tsamplingPackedValues = new Map()\n\t\t\tif (!sharedPackedObjectMap)\n\t\t\t\tsharedPackedObjectMap = Object.create(null)\n\t\t\treturn (options) => {\n\t\t\t\tlet threshold = options && options.threshold || 4\n\t\t\t\tlet position = this.pack ? options.maxPrivatePackedValues || 16 : 0\n\t\t\t\tif (!sharedValues)\n\t\t\t\t\tsharedValues = this.sharedValues = []\n\t\t\t\tfor (let [ key, status ] of samplingPackedValues) {\n\t\t\t\t\tif (status.count > threshold) {\n\t\t\t\t\t\tsharedPackedObjectMap[key] = position++\n\t\t\t\t\t\tsharedValues.push(key)\n\t\t\t\t\t\thasSharedUpdate = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twhile (this.saveShared && this.updateSharedData() === false) {}\n\t\t\t\tsamplingPackedValues = null\n\t\t\t}\n\t\t}\n\t\tconst encode = (value) => {\n\t\t\tif (position > safeEnd)\n\t\t\t\ttarget = makeRoom(position)\n\n\t\t\tvar type = typeof value\n\t\t\tvar length\n\t\t\tif (type === 'string') {\n\t\t\t\tif (packedObjectMap) {\n\t\t\t\t\tlet packedPosition = packedObjectMap[value]\n\t\t\t\t\tif (packedPosition >= 0) {\n\t\t\t\t\t\tif (packedPosition < 16)\n\t\t\t\t\t\t\ttarget[position++] = packedPosition + 0xe0 // simple values, defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttarget[position++] = 0xc6 // tag 6 defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\t\t\t\t\tif (packedPosition & 1)\n\t\t\t\t\t\t\t\tencode((15 - packedPosition) >> 1)\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tencode((packedPosition - 16) >> 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n/*\t\t\t\t\t\t} else if (packedStatus.serializationId != serializationId) {\n\t\t\t\t\t\t\tpackedStatus.serializationId = serializationId\n\t\t\t\t\t\t\tpackedStatus.count = 1\n\t\t\t\t\t\t\tif (options.sharedPack) {\n\t\t\t\t\t\t\t\tlet sharedCount = packedStatus.sharedCount = (packedStatus.sharedCount || 0) + 1\n\t\t\t\t\t\t\t\tif (shareCount > (options.sharedPack.threshold || 5)) {\n\t\t\t\t\t\t\t\t\tlet sharedPosition = packedStatus.position = packedStatus.nextSharedPosition\n\t\t\t\t\t\t\t\t\thasSharedUpdate = true\n\t\t\t\t\t\t\t\t\tif (sharedPosition < 16)\n\t\t\t\t\t\t\t\t\t\ttarget[position++] = sharedPosition + 0xc0\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} // else any in-doc incrementation?*/\n\t\t\t\t\t} else if (samplingPackedValues && !options.pack) {\n\t\t\t\t\t\tlet status = samplingPackedValues.get(value)\n\t\t\t\t\t\tif (status)\n\t\t\t\t\t\t\tstatus.count++\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsamplingPackedValues.set(value, {\n\t\t\t\t\t\t\t\tcount: 1,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlet strLength = value.length\n\t\t\t\tif (bundledStrings && strLength >= 4 && strLength < 0x400) {\n\t\t\t\t\tif ((bundledStrings.size += strLength) > MAX_BUNDLE_SIZE) {\n\t\t\t\t\t\tlet extStart\n\t\t\t\t\t\tlet maxBytes = (bundledStrings[0] ? bundledStrings[0].length * 3 + bundledStrings[1].length : 0) + 10\n\t\t\t\t\t\tif (position + maxBytes > safeEnd)\n\t\t\t\t\t\t\ttarget = makeRoom(position + maxBytes)\n\t\t\t\t\t\ttarget[position++] = 0xd9 // tag 16-bit\n\t\t\t\t\t\ttarget[position++] = 0xdf // tag 0xdff9\n\t\t\t\t\t\ttarget[position++] = 0xf9\n\t\t\t\t\t\t// TODO: If we only have one bundle with any string data, only write one string bundle\n\t\t\t\t\t\ttarget[position++] = bundledStrings.position ? 0x84 : 0x82 // array of 4 or 2 elements depending on if we write bundles\n\t\t\t\t\t\ttarget[position++] = 0x1a // 32-bit unsigned int\n\t\t\t\t\t\textStart = position - start\n\t\t\t\t\t\tposition += 4 // reserve for writing bundle reference\n\t\t\t\t\t\tif (bundledStrings.position) {\n\t\t\t\t\t\t\twriteBundles(start, encode) // write the last bundles\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbundledStrings = ['', ''] // create new ones\n\t\t\t\t\t\tbundledStrings.size = 0\n\t\t\t\t\t\tbundledStrings.position = extStart\n\t\t\t\t\t}\n\t\t\t\t\tlet twoByte = hasNonLatin.test(value)\n\t\t\t\t\tbundledStrings[twoByte ? 0 : 1] += value\n\t\t\t\t\ttarget[position++] = twoByte ? 0xce : 0xcf\n\t\t\t\t\tencode(strLength);\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet headerSize\n\t\t\t\t// first we estimate the header size, so we can write to the correct location\n\t\t\t\tif (strLength < 0x20) {\n\t\t\t\t\theaderSize = 1\n\t\t\t\t} else if (strLength < 0x100) {\n\t\t\t\t\theaderSize = 2\n\t\t\t\t} else if (strLength < 0x10000) {\n\t\t\t\t\theaderSize = 3\n\t\t\t\t} else {\n\t\t\t\t\theaderSize = 5\n\t\t\t\t}\n\t\t\t\tlet maxBytes = strLength * 3\n\t\t\t\tif (position + maxBytes > safeEnd)\n\t\t\t\t\ttarget = makeRoom(position + maxBytes)\n\n\t\t\t\tif (strLength < 0x40 || !encodeUtf8) {\n\t\t\t\t\tlet i, c1, c2, strPosition = position + headerSize\n\t\t\t\t\tfor (i = 0; i < strLength; i++) {\n\t\t\t\t\t\tc1 = value.charCodeAt(i)\n\t\t\t\t\t\tif (c1 < 0x80) {\n\t\t\t\t\t\t\ttarget[strPosition++] = c1\n\t\t\t\t\t\t} else if (c1 < 0x800) {\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 6 | 0xc0\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 & 0x3f | 0x80\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t(c1 & 0xfc00) === 0xd800 &&\n\t\t\t\t\t\t\t((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tc1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff)\n\t\t\t\t\t\t\ti++\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 18 | 0xf0\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 12 & 0x3f | 0x80\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 6 & 0x3f | 0x80\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 & 0x3f | 0x80\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 12 | 0xe0\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 >> 6 & 0x3f | 0x80\n\t\t\t\t\t\t\ttarget[strPosition++] = c1 & 0x3f | 0x80\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlength = strPosition - position - headerSize\n\t\t\t\t} else {\n\t\t\t\t\tlength = encodeUtf8(value, position + headerSize, maxBytes)\n\t\t\t\t}\n\n\t\t\t\tif (length < 0x18) {\n\t\t\t\t\ttarget[position++] = 0x60 | length\n\t\t\t\t} else if (length < 0x100) {\n\t\t\t\t\tif (headerSize < 2) {\n\t\t\t\t\t\ttarget.copyWithin(position + 2, position + 1, position + 1 + length)\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0x78\n\t\t\t\t\ttarget[position++] = length\n\t\t\t\t} else if (length < 0x10000) {\n\t\t\t\t\tif (headerSize < 3) {\n\t\t\t\t\t\ttarget.copyWithin(position + 3, position + 2, position + 2 + length)\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0x79\n\t\t\t\t\ttarget[position++] = length >> 8\n\t\t\t\t\ttarget[position++] = length & 0xff\n\t\t\t\t} else {\n\t\t\t\t\tif (headerSize < 5) {\n\t\t\t\t\t\ttarget.copyWithin(position + 5, position + 3, position + 3 + length)\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0x7a\n\t\t\t\t\ttargetView.setUint32(position, length)\n\t\t\t\t\tposition += 4\n\t\t\t\t}\n\t\t\t\tposition += length\n\t\t\t} else if (type === 'number') {\n\t\t\t\tif (!this.alwaysUseFloat && value >>> 0 === value) {// positive integer, 32-bit or less\n\t\t\t\t\t// positive uint\n\t\t\t\t\tif (value < 0x18) {\n\t\t\t\t\t\ttarget[position++] = value\n\t\t\t\t\t} else if (value < 0x100) {\n\t\t\t\t\t\ttarget[position++] = 0x18\n\t\t\t\t\t\ttarget[position++] = value\n\t\t\t\t\t} else if (value < 0x10000) {\n\t\t\t\t\t\ttarget[position++] = 0x19\n\t\t\t\t\t\ttarget[position++] = value >> 8\n\t\t\t\t\t\ttarget[position++] = value & 0xff\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttarget[position++] = 0x1a\n\t\t\t\t\t\ttargetView.setUint32(position, value)\n\t\t\t\t\t\tposition += 4\n\t\t\t\t\t}\n\t\t\t\t} else if (!this.alwaysUseFloat && value >> 0 === value) { // negative integer, 31-bit or less\n\t\t\t\t\tif (value >= -0x18) {\n\t\t\t\t\t\ttarget[position++] = 0x1f - value\n\t\t\t\t\t} else if (value >= -0x100) {\n\t\t\t\t\t\ttarget[position++] = 0x38\n\t\t\t\t\t\ttarget[position++] = ~value\n\t\t\t\t\t} else if (value >= -0x10000) {\n\t\t\t\t\t\ttarget[position++] = 0x39\n\t\t\t\t\t\ttargetView.setUint16(position, ~value)\n\t\t\t\t\t\tposition += 2\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttarget[position++] = 0x3a\n\t\t\t\t\t\ttargetView.setUint32(position, ~value)\n\t\t\t\t\t\tposition += 4\n\t\t\t\t\t}\n\t\t\t\t} else if (!this.alwaysUseFloat && value < 0 && value >= -0x100000000 && Math.floor(value) === value) {\n\t\t\t\t\t// negative integer, 32-bit or less\n\t\t\t\t\ttarget[position++] = 0x3a\n\t\t\t\t\ttargetView.setUint32(position, -1 - value)\n\t\t\t\t\tposition += 4\n\t\t\t\t} else {\n\t\t\t\t\tlet useFloat32\n\t\t\t\t\tif ((useFloat32 = this.useFloat32) > 0 && value < 0x100000000 && value >= -0x80000000) {\n\t\t\t\t\t\ttarget[position++] = 0xfa\n\t\t\t\t\t\ttargetView.setFloat32(position, value)\n\t\t\t\t\t\tlet xShifted\n\t\t\t\t\t\tif (useFloat32 < 4 ||\n\t\t\t\t\t\t\t\t// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved\n\t\t\t\t\t\t\t\t((xShifted = value * mult10[((target[position] & 0x7f) << 1) | (target[position + 1] >> 7)]) >> 0) === xShifted) {\n\t\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t} else\n\t\t\t\t\t\t\tposition-- // move back into position for writing a double\n\t\t\t\t\t}\n\t\t\t\t\ttarget[position++] = 0xfb\n\t\t\t\t\ttargetView.setFloat64(position, value)\n\t\t\t\t\tposition += 8\n\t\t\t\t}\n\t\t\t} else if (type === 'object') {\n\t\t\t\tif (!value)\n\t\t\t\t\ttarget[position++] = 0xf6\n\t\t\t\telse {\n\t\t\t\t\tif (referenceMap) {\n\t\t\t\t\t\tlet referee = referenceMap.get(value)\n\t\t\t\t\t\tif (referee) {\n\t\t\t\t\t\t\ttarget[position++] = 0xd8\n\t\t\t\t\t\t\ttarget[position++] = 29 // http://cbor.schmorp.de/value-sharing\n\t\t\t\t\t\t\ttarget[position++] = 0x19 // 16-bit uint\n\t\t\t\t\t\t\tif (!referee.references) {\n\t\t\t\t\t\t\t\tlet idsToInsert = referenceMap.idsToInsert || (referenceMap.idsToInsert = [])\n\t\t\t\t\t\t\t\treferee.references = []\n\t\t\t\t\t\t\t\tidsToInsert.push(referee)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treferee.references.push(position - start)\n\t\t\t\t\t\t\tposition += 2 // TODO: also support 32-bit\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t} else \n\t\t\t\t\t\t\treferenceMap.set(value, { offset: position - start })\n\t\t\t\t\t}\n\t\t\t\t\tlet constructor = value.constructor\n\t\t\t\t\tif (constructor === Object) {\n\t\t\t\t\t\tif (this.skipFunction === true) {\n\t\t\t\t\t\t\tvalue = Object.fromEntries([...Object.keys(value).filter(x => typeof value[x] !== \"function\").map(x => [x, value[x]])]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\twriteObject(value)\n\t\t\t\t\t} else if (constructor === Array) {\n\t\t\t\t\t\tlength = value.length\n\t\t\t\t\t\tif (length < 0x18) {\n\t\t\t\t\t\t\ttarget[position++] = 0x80 | length\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twriteArrayHeader(length)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\t\t\tencode(value[i])\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (constructor === Map) {\n\t\t\t\t\t\tif (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {\n\t\t\t\t\t\t\t// use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way\n\t\t\t\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\t\t\t\ttarget[position++] = 1\n\t\t\t\t\t\t\ttarget[position++] = 3\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlength = value.size\n\t\t\t\t\t\tif (length < 0x18) {\n\t\t\t\t\t\t\ttarget[position++] = 0xa0 | length\n\t\t\t\t\t\t} else if (length < 0x100) {\n\t\t\t\t\t\t\ttarget[position++] = 0xb8\n\t\t\t\t\t\t\ttarget[position++] = length\n\t\t\t\t\t\t} else if (length < 0x10000) {\n\t\t\t\t\t\t\ttarget[position++] = 0xb9\n\t\t\t\t\t\t\ttarget[position++] = length >> 8\n\t\t\t\t\t\t\ttarget[position++] = length & 0xff\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttarget[position++] = 0xba\n\t\t\t\t\t\t\ttargetView.setUint32(position, length)\n\t\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (encoder.keyMap) { \n\t\t\t\t\t\t\tfor (let [ key, entryValue ] of value) {\n\t\t\t\t\t\t\t\tencode(encoder.encodeKey(key))\n\t\t\t\t\t\t\t\tencode(entryValue)\n\t\t\t\t\t\t\t} \n\t\t\t\t\t\t} else { \n\t\t\t\t\t\t\tfor (let [ key, entryValue ] of value) {\n\t\t\t\t\t\t\t\tencode(key) \n\t\t\t\t\t\t\t\tencode(entryValue)\n\t\t\t\t\t\t\t} \t\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (let i = 0, l = extensions.length; i < l; i++) {\n\t\t\t\t\t\t\tlet extensionClass = extensionClasses[i]\n\t\t\t\t\t\t\tif (value instanceof extensionClass) {\n\t\t\t\t\t\t\t\tlet extension = extensions[i]\n\t\t\t\t\t\t\t\tlet tag = extension.tag\n\t\t\t\t\t\t\t\tif (tag == undefined)\n\t\t\t\t\t\t\t\t\ttag = extension.getTag && extension.getTag.call(this, value)\n\t\t\t\t\t\t\t\tif (tag < 0x18) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xc0 | tag\n\t\t\t\t\t\t\t\t} else if (tag < 0x100) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xd8\n\t\t\t\t\t\t\t\t\ttarget[position++] = tag\n\t\t\t\t\t\t\t\t} else if (tag < 0x10000) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\t\t\t\t\t\ttarget[position++] = tag >> 8\n\t\t\t\t\t\t\t\t\ttarget[position++] = tag & 0xff\n\t\t\t\t\t\t\t\t} else if (tag > -1) {\n\t\t\t\t\t\t\t\t\ttarget[position++] = 0xda\n\t\t\t\t\t\t\t\t\ttargetView.setUint32(position, tag)\n\t\t\t\t\t\t\t\t\tposition += 4\n\t\t\t\t\t\t\t\t} // else undefined, don't write tag\n\t\t\t\t\t\t\t\textension.encode.call(this, value, encode, makeRoom)\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value[Symbol.iterator]) {\n\t\t\t\t\t\t\tif (throwOnIterable) {\n\t\t\t\t\t\t\t\tlet error = new Error('Iterable should be serialized as iterator')\n\t\t\t\t\t\t\t\terror.iteratorNotHandled = true;\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttarget[position++] = 0x9f // indefinite length array\n\t\t\t\t\t\t\tfor (let entry of value) {\n\t\t\t\t\t\t\t\tencode(entry)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttarget[position++] = 0xff // stop-code\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value[Symbol.asyncIterator] || isBlob(value)) {\n\t\t\t\t\t\t\tlet error = new Error('Iterable/blob should be serialized as iterator')\n\t\t\t\t\t\t\terror.iteratorNotHandled = true;\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (this.useToJSON && value.toJSON) {\n\t\t\t\t\t\t\tconst json = value.toJSON()\n\t\t\t\t\t\t\t// if for some reason value.toJSON returns itself it'll loop forever\n\t\t\t\t\t\t\tif (json !== value)\n\t\t\t\t\t\t\t\treturn encode(json)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// no extension found, write as a plain object\n\t\t\t\t\t\twriteObject(value)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (type === 'boolean') {\n\t\t\t\ttarget[position++] = value ? 0xf5 : 0xf4\n\t\t\t} else if (type === 'bigint') {\n\t\t\t\tif (value < (BigInt(1)<= 0) {\n\t\t\t\t\t// use an unsigned int as long as it fits\n\t\t\t\t\ttarget[position++] = 0x1b\n\t\t\t\t\ttargetView.setBigUint64(position, value)\n\t\t\t\t} else if (value > -(BigInt(1)<= BigInt(0))\n\t\t\t\t\t\t\ttarget[position++] = 0xc2 // tag 2\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttarget[position++] = 0xc3 // tag 2\n\t\t\t\t\t\t\tvalue = BigInt(-1) - value;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlet bytes = [];\n\t\t\t\t\t\twhile (value) {\n\t\t\t\t\t\t\tbytes.push(Number(value & BigInt(0xff)));\n\t\t\t\t\t\t\tvalue >>= BigInt(8);\n\t\t\t\t\t\t}\n\t\t\t\t\t\twriteBuffer(new Uint8Array(bytes.reverse()), makeRoom);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tposition += 8\n\t\t\t} else if (type === 'undefined') {\n\t\t\t\ttarget[position++] = 0xf7\n\t\t\t} else {\n\t\t\t\tthrow new Error('Unknown type: ' + type)\n\t\t\t}\n\t\t}\n\n\t\tconst writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {\n\t\t\t// this method is slightly slower, but generates \"preferred serialization\" (optimally small for smaller objects)\n\t\t\tlet keys = Object.keys(object)\n\t\t\tlet vals = Object.values(object)\n\t\t\tlet length = keys.length\n\t\t\tif (length < 0x18) {\n\t\t\t\ttarget[position++] = 0xa0 | length\n\t\t\t} else if (length < 0x100) {\n\t\t\t\ttarget[position++] = 0xb8\n\t\t\t\ttarget[position++] = length\n\t\t\t} else if (length < 0x10000) {\n\t\t\t\ttarget[position++] = 0xb9\n\t\t\t\ttarget[position++] = length >> 8\n\t\t\t\ttarget[position++] = length & 0xff\n\t\t\t} else {\n\t\t\t\ttarget[position++] = 0xba\n\t\t\t\ttargetView.setUint32(position, length)\n\t\t\t\tposition += 4\n\t\t\t}\n\t\t\tlet key\n\t\t\tif (encoder.keyMap) { \n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tencode(encoder.encodeKey(keys[i]))\n\t\t\t\t\tencode(vals[i])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tencode(keys[i])\n\t\t\t\t\tencode(vals[i])\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\t\t(object) => {\n\t\t\ttarget[position++] = 0xb9 // always use map 16, so we can preallocate and set the length afterwards\n\t\t\tlet objectOffset = position - start\n\t\t\tposition += 2\n\t\t\tlet size = 0\n\t\t\tif (encoder.keyMap) {\n\t\t\t\tfor (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {\n\t\t\t\t\tencode(encoder.encodeKey(key))\n\t\t\t\t\tencode(object[key])\n\t\t\t\t\tsize++\n\t\t\t\t}\n\t\t\t} else { \n\t\t\t\tfor (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {\n\t\t\t\t\t\tencode(key)\n\t\t\t\t\t\tencode(object[key])\n\t\t\t\t\tsize++\n\t\t\t\t}\n\t\t\t}\n\t\t\ttarget[objectOffset++ + start] = size >> 8\n\t\t\ttarget[objectOffset + start] = size & 0xff\n\t\t} :\n\t\t(object, skipValues) => {\n\t\t\tlet nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))\n\t\t\tlet newTransitions = 0\n\t\t\tlet length = 0\n\t\t\tlet parentRecordId\n\t\t\tlet keys\n\t\t\tif (this.keyMap) {\n\t\t\t\tkeys = Object.keys(object).map(k => this.encodeKey(k))\n\t\t\t\tlength = keys.length\n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tlet key = keys[i]\n\t\t\t\t\tnextTransition = transition[key]\n\t\t\t\t\tif (!nextTransition) {\n\t\t\t\t\t\tnextTransition = transition[key] = Object.create(null)\n\t\t\t\t\t\tnewTransitions++\n\t\t\t\t\t}\n\t\t\t\t\ttransition = nextTransition\n\t\t\t\t}\t\t\t\t\n\t\t\t} else {\n\t\t\t\tfor (let key in object) if (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key)) {\n\t\t\t\t\tnextTransition = transition[key]\n\t\t\t\t\tif (!nextTransition) {\n\t\t\t\t\t\tif (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it\n\t\t\t\t\t\t\tparentRecordId = transition[RECORD_SYMBOL] & 0xffff\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnextTransition = transition[key] = Object.create(null)\n\t\t\t\t\t\tnewTransitions++\n\t\t\t\t\t}\n\t\t\t\t\ttransition = nextTransition\n\t\t\t\t\tlength++\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet recordId = transition[RECORD_SYMBOL]\n\t\t\tif (recordId !== undefined) {\n\t\t\t\trecordId &= 0xffff\n\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\ttarget[position++] = (recordId >> 8) | 0xe0\n\t\t\t\ttarget[position++] = recordId & 0xff\n\t\t\t} else {\n\t\t\t\tif (!keys)\n\t\t\t\t\tkeys = transition.__keys__ || (transition.__keys__ = Object.keys(object))\n\t\t\t\tif (parentRecordId === undefined) {\n\t\t\t\t\trecordId = structures.nextId++\n\t\t\t\t\tif (!recordId) {\n\t\t\t\t\t\trecordId = 0\n\t\t\t\t\t\tstructures.nextId = 1\n\t\t\t\t\t}\n\t\t\t\t\tif (recordId >= MAX_STRUCTURES) {// cycle back around\n\t\t\t\t\t\tstructures.nextId = (recordId = maxSharedStructures) + 1\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\trecordId = parentRecordId\n\t\t\t\t}\n\t\t\t\tstructures[recordId] = keys\n\t\t\t\tif (recordId < maxSharedStructures) {\n\t\t\t\t\ttarget[position++] = 0xd9\n\t\t\t\t\ttarget[position++] = (recordId >> 8) | 0xe0\n\t\t\t\t\ttarget[position++] = recordId & 0xff\n\t\t\t\t\ttransition = structures.transitions\n\t\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\t\tif (transition[RECORD_SYMBOL] === undefined || (transition[RECORD_SYMBOL] & 0x100000))\n\t\t\t\t\t\t\ttransition[RECORD_SYMBOL] = recordId\n\t\t\t\t\t\ttransition = transition[keys[i]]\n\t\t\t\t\t}\n\t\t\t\t\ttransition[RECORD_SYMBOL] = recordId | 0x100000 // indicates it is a extendable terminal\n\t\t\t\t\thasSharedUpdate = true\n\t\t\t\t} else {\n\t\t\t\t\ttransition[RECORD_SYMBOL] = recordId\n\t\t\t\t\ttargetView.setUint32(position, 0xd9dfff00) // tag two byte, then record definition id\n\t\t\t\t\tposition += 3\n\t\t\t\t\tif (newTransitions)\n\t\t\t\t\t\ttransitionsCount += serializationsSinceTransitionRebuild * newTransitions\n\t\t\t\t\t// record the removal of the id, we can maintain our shared structure\n\t\t\t\t\tif (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)\n\t\t\t\t\t\trecordIdsToRemove.shift()[RECORD_SYMBOL] = undefined // we are cycling back through, and have to remove old ones\n\t\t\t\t\trecordIdsToRemove.push(transition)\n\t\t\t\t\twriteArrayHeader(length + 2)\n\t\t\t\t\tencode(0xe000 + recordId)\n\t\t\t\t\tencode(keys)\n\t\t\t\t\tif (skipValues) return; // special exit for iterator\n\t\t\t\t\tfor (let key in object)\n\t\t\t\t\t\tif (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))\n\t\t\t\t\t\t\tencode(object[key])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (length < 0x18) { // write the array header\n\t\t\t\ttarget[position++] = 0x80 | length\n\t\t\t} else {\n\t\t\t\twriteArrayHeader(length)\n\t\t\t}\n\t\t\tif (skipValues) return; // special exit for iterator\n\t\t\tfor (let key in object)\n\t\t\t\tif (typeof object.hasOwnProperty !== 'function' || object.hasOwnProperty(key))\n\t\t\t\t\tencode(object[key])\n\t\t}\n\t\tconst makeRoom = (end) => {\n\t\t\tlet newSize\n\t\t\tif (end > 0x1000000) {\n\t\t\t\t// special handling for really large buffers\n\t\t\t\tif ((end - start) > MAX_BUFFER_SIZE)\n\t\t\t\t\tthrow new Error('Encoded buffer would be larger than maximum buffer size')\n\t\t\t\tnewSize = Math.min(MAX_BUFFER_SIZE,\n\t\t\t\t\tMath.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000)\n\t\t\t} else // faster handling for smaller buffers\n\t\t\t\tnewSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12\n\t\t\tlet newBuffer = new ByteArrayAllocate(newSize)\n\t\t\ttargetView = new DataView(newBuffer.buffer, 0, newSize)\n\t\t\tif (target.copy)\n\t\t\t\ttarget.copy(newBuffer, 0, start, end)\n\t\t\telse\n\t\t\t\tnewBuffer.set(target.slice(start, end))\n\t\t\tposition -= start\n\t\t\tstart = 0\n\t\t\tsafeEnd = newBuffer.length - 10\n\t\t\treturn target = newBuffer\n\t\t}\n\t\tlet chunkThreshold = 100;\n\t\tlet continuedChunkThreshold = 1000;\n\t\tthis.encodeAsIterable = function(value, options) {\n\t\t\treturn startEncoding(value, options, encodeObjectAsIterable);\n\t\t}\n\t\tthis.encodeAsAsyncIterable = function(value, options) {\n\t\t\treturn startEncoding(value, options, encodeObjectAsAsyncIterable);\n\t\t}\n\n\t\tfunction* encodeObjectAsIterable(object, iterateProperties, finalIterable) {\n\t\t\tlet constructor = object.constructor;\n\t\t\tif (constructor === Object) {\n\t\t\t\tlet useRecords = encoder.useRecords !== false;\n\t\t\t\tif (useRecords)\n\t\t\t\t\twriteObject(object, true); // write the record identifier\n\t\t\t\telse\n\t\t\t\t\twriteEntityLength(Object.keys(object).length, 0xa0);\n\t\t\t\tfor (let key in object) {\n\t\t\t\t\tlet value = object[key];\n\t\t\t\t\tif (!useRecords) encode(key);\n\t\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\t\tif (iterateProperties[key])\n\t\t\t\t\t\t\tyield* encodeObjectAsIterable(value, iterateProperties[key]);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyield* tryEncode(value, iterateProperties, key);\n\t\t\t\t\t} else encode(value);\n\t\t\t\t}\n\t\t\t} else if (constructor === Array) {\n\t\t\t\tlet length = object.length;\n\t\t\t\twriteArrayHeader(length);\n\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\tlet value = object[i];\n\t\t\t\t\tif (value && (typeof value === 'object' || position - start > chunkThreshold)) {\n\t\t\t\t\t\tif (iterateProperties.element)\n\t\t\t\t\t\t\tyield* encodeObjectAsIterable(value, iterateProperties.element);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyield* tryEncode(value, iterateProperties, 'element');\n\t\t\t\t\t} else encode(value);\n\t\t\t\t}\n\t\t\t} else if (object[Symbol.iterator] && !object.buffer) { // iterator, but exclude typed arrays\n\t\t\t\ttarget[position++] = 0x9f; // start indefinite array\n\t\t\t\tfor (let value of object) {\n\t\t\t\t\tif (value && (typeof value === 'object' || position - start > chunkThreshold)) {\n\t\t\t\t\t\tif (iterateProperties.element)\n\t\t\t\t\t\t\tyield* encodeObjectAsIterable(value, iterateProperties.element);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyield* tryEncode(value, iterateProperties, 'element');\n\t\t\t\t\t} else encode(value);\n\t\t\t\t}\n\t\t\t\ttarget[position++] = 0xff; // stop byte\n\t\t\t} else if (isBlob(object)){\n\t\t\t\twriteEntityLength(object.size, 0x40); // encode as binary data\n\t\t\t\tyield target.subarray(start, position);\n\t\t\t\tyield object; // directly return blobs, they have to be encoded asynchronously\n\t\t\t\trestartEncoding();\n\t\t\t} else if (object[Symbol.asyncIterator]) {\n\t\t\t\ttarget[position++] = 0x9f; // start indefinite array\n\t\t\t\tyield target.subarray(start, position);\n\t\t\t\tyield object; // directly return async iterators, they have to be encoded asynchronously\n\t\t\t\trestartEncoding();\n\t\t\t\ttarget[position++] = 0xff; // stop byte\n\t\t\t} else {\n\t\t\t\tencode(object);\n\t\t\t}\n\t\t\tif (finalIterable && position > start) yield target.subarray(start, position);\n\t\t\telse if (position - start > chunkThreshold) {\n\t\t\t\tyield target.subarray(start, position);\n\t\t\t\trestartEncoding();\n\t\t\t}\n\t\t}\n\t\tfunction* tryEncode(value, iterateProperties, key) {\n\t\t\tlet restart = position - start;\n\t\t\ttry {\n\t\t\t\tencode(value);\n\t\t\t\tif (position - start > chunkThreshold) {\n\t\t\t\t\tyield target.subarray(start, position);\n\t\t\t\t\trestartEncoding();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (error.iteratorNotHandled) {\n\t\t\t\t\titerateProperties[key] = {};\n\t\t\t\t\tposition = start + restart; // restart our position so we don't have partial data from last encode\n\t\t\t\t\tyield* encodeObjectAsIterable.call(this, value, iterateProperties[key]);\n\t\t\t\t} else throw error;\n\t\t\t}\n\t\t}\n\t\tfunction restartEncoding() {\n\t\t\tchunkThreshold = continuedChunkThreshold;\n\t\t\tencoder.encode(null, THROW_ON_ITERABLE); // restart encoding\n\t\t}\n\t\tfunction startEncoding(value, options, encodeIterable) {\n\t\t\tif (options && options.chunkThreshold) // explicitly specified chunk sizes\n\t\t\t\tchunkThreshold = continuedChunkThreshold = options.chunkThreshold;\n\t\t\telse // we start with a smaller threshold to get initial bytes sent quickly\n\t\t\t\tchunkThreshold = 100;\n\t\t\tif (value && typeof value === 'object') {\n\t\t\t\tencoder.encode(null, THROW_ON_ITERABLE); // start encoding\n\t\t\t\treturn encodeIterable(value, encoder.iterateProperties || (encoder.iterateProperties = {}), true);\n\t\t\t}\n\t\t\treturn [encoder.encode(value)];\n\t\t}\n\n\t\tasync function* encodeObjectAsAsyncIterable(value, iterateProperties) {\n\t\t\tfor (let encodedValue of encodeObjectAsIterable(value, iterateProperties, true)) {\n\t\t\t\tlet constructor = encodedValue.constructor;\n\t\t\t\tif (constructor === ByteArray || constructor === Uint8Array)\n\t\t\t\t\tyield encodedValue;\n\t\t\t\telse if (isBlob(encodedValue)) {\n\t\t\t\t\tlet reader = encodedValue.stream().getReader();\n\t\t\t\t\tlet next;\n\t\t\t\t\twhile (!(next = await reader.read()).done) {\n\t\t\t\t\t\tyield next.value;\n\t\t\t\t\t}\n\t\t\t\t} else if (encodedValue[Symbol.asyncIterator]) {\n\t\t\t\t\tfor await (let asyncValue of encodedValue) {\n\t\t\t\t\t\trestartEncoding();\n\t\t\t\t\t\tif (asyncValue)\n\t\t\t\t\t\t\tyield* encodeObjectAsAsyncIterable(asyncValue, iterateProperties.async || (iterateProperties.async = {}));\n\t\t\t\t\t\telse yield encoder.encode(asyncValue);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tyield encodedValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tuseBuffer(buffer) {\n\t\t// this means we are finished using our own buffer and we can write over it safely\n\t\ttarget = buffer\n\t\ttargetView = new DataView(target.buffer, target.byteOffset, target.byteLength)\n\t\tposition = 0\n\t}\n\tclearSharedData() {\n\t\tif (this.structures)\n\t\t\tthis.structures = []\n\t\tif (this.sharedValues)\n\t\t\tthis.sharedValues = undefined\n\t}\n\tupdateSharedData() {\n\t\tlet lastVersion = this.sharedVersion || 0\n\t\tthis.sharedVersion = lastVersion + 1\n\t\tlet structuresCopy = this.structures.slice(0)\n\t\tlet sharedData = new SharedData(structuresCopy, this.sharedValues, this.sharedVersion)\n\t\tlet saveResults = this.saveShared(sharedData,\n\t\t\t\texistingShared => (existingShared && existingShared.version || 0) == lastVersion)\n\t\tif (saveResults === false) {\n\t\t\t// get updated structures and try again if the update failed\n\t\t\tsharedData = this.getShared() || {}\n\t\t\tthis.structures = sharedData.structures || []\n\t\t\tthis.sharedValues = sharedData.packedValues\n\t\t\tthis.sharedVersion = sharedData.version\n\t\t\tthis.structures.nextId = this.structures.length\n\t\t} else {\n\t\t\t// restore structures\n\t\t\tstructuresCopy.forEach((structure, i) => this.structures[i] = structure)\n\t\t}\n\t\t// saveShared may fail to write and reload, or may have reloaded to check compatibility and overwrite saved data, either way load the correct shared data\n\t\treturn saveResults\n\t}\n}\nfunction writeEntityLength(length, majorValue) {\n\tif (length < 0x18)\n\t\ttarget[position++] = majorValue | length\n\telse if (length < 0x100) {\n\t\ttarget[position++] = majorValue | 0x18\n\t\ttarget[position++] = length\n\t} else if (length < 0x10000) {\n\t\ttarget[position++] = majorValue | 0x19\n\t\ttarget[position++] = length >> 8\n\t\ttarget[position++] = length & 0xff\n\t} else {\n\t\ttarget[position++] = majorValue | 0x1a\n\t\ttargetView.setUint32(position, length)\n\t\tposition += 4\n\t}\n\n}\nclass SharedData {\n\tconstructor(structures, values, version) {\n\t\tthis.structures = structures\n\t\tthis.packedValues = values\n\t\tthis.version = version\n\t}\n}\n\nfunction writeArrayHeader(length) {\n\tif (length < 0x18)\n\t\ttarget[position++] = 0x80 | length\n\telse if (length < 0x100) {\n\t\ttarget[position++] = 0x98\n\t\ttarget[position++] = length\n\t} else if (length < 0x10000) {\n\t\ttarget[position++] = 0x99\n\t\ttarget[position++] = length >> 8\n\t\ttarget[position++] = length & 0xff\n\t} else {\n\t\ttarget[position++] = 0x9a\n\t\ttargetView.setUint32(position, length)\n\t\tposition += 4\n\t}\n}\n\nconst BlobConstructor = typeof Blob === 'undefined' ? function(){} : Blob;\nfunction isBlob(object) {\n\tif (object instanceof BlobConstructor)\n\t\treturn true;\n\tlet tag = object[Symbol.toStringTag];\n\treturn tag === 'Blob' || tag === 'File';\n}\nfunction findRepetitiveStrings(value, packedValues) {\n\tswitch(typeof value) {\n\t\tcase 'string':\n\t\t\tif (value.length > 3) {\n\t\t\t\tif (packedValues.objectMap[value] > -1 || packedValues.values.length >= packedValues.maxValues)\n\t\t\t\t\treturn\n\t\t\t\tlet packedStatus = packedValues.get(value)\n\t\t\t\tif (packedStatus) {\n\t\t\t\t\tif (++packedStatus.count == 2) {\n\t\t\t\t\t\tpackedValues.values.push(value)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpackedValues.set(value, {\n\t\t\t\t\t\tcount: 1,\n\t\t\t\t\t})\n\t\t\t\t\tif (packedValues.samplingPackedValues) {\n\t\t\t\t\t\tlet status = packedValues.samplingPackedValues.get(value)\n\t\t\t\t\t\tif (status)\n\t\t\t\t\t\t\tstatus.count++\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tpackedValues.samplingPackedValues.set(value, {\n\t\t\t\t\t\t\t\tcount: 1,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'object':\n\t\t\tif (value) {\n\t\t\t\tif (value instanceof Array) {\n\t\t\t\t\tfor (let i = 0, l = value.length; i < l; i++) {\n\t\t\t\t\t\tfindRepetitiveStrings(value[i], packedValues)\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\tlet includeKeys = !packedValues.encoder.useRecords\n\t\t\t\t\tfor (var key in value) {\n\t\t\t\t\t\tif (value.hasOwnProperty(key)) {\n\t\t\t\t\t\t\tif (includeKeys)\n\t\t\t\t\t\t\t\tfindRepetitiveStrings(key, packedValues)\n\t\t\t\t\t\t\tfindRepetitiveStrings(value[key], packedValues)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'function': console.log(value)\n\t}\n}\nconst isLittleEndianMachine = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1\nextensionClasses = [ Date, Set, Error, RegExp, Tag, ArrayBuffer,\n\tUint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,\n\ttypeof BigUint64Array == 'undefined' ? function() {} : BigUint64Array, Int8Array, Int16Array, Int32Array,\n\ttypeof BigInt64Array == 'undefined' ? function() {} : BigInt64Array,\n\tFloat32Array, Float64Array, SharedData ]\n\n//Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/\nextensions = [{ // Date\n\ttag: 1,\n\tencode(date, encode) {\n\t\tlet seconds = date.getTime() / 1000\n\t\tif ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {\n\t\t\t// Timestamp 32\n\t\t\ttarget[position++] = 0x1a\n\t\t\ttargetView.setUint32(position, seconds)\n\t\t\tposition += 4\n\t\t} else {\n\t\t\t// Timestamp float64\n\t\t\ttarget[position++] = 0xfb\n\t\t\ttargetView.setFloat64(position, seconds)\n\t\t\tposition += 8\n\t\t}\n\t}\n}, { // Set\n\ttag: 258, // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md\n\tencode(set, encode) {\n\t\tlet array = Array.from(set)\n\t\tencode(array)\n\t}\n}, { // Error\n\ttag: 27, // http://cbor.schmorp.de/generic-object\n\tencode(error, encode) {\n\t\tencode([ error.name, error.message ])\n\t}\n}, { // RegExp\n\ttag: 27, // http://cbor.schmorp.de/generic-object\n\tencode(regex, encode) {\n\t\tencode([ 'RegExp', regex.source, regex.flags ])\n\t}\n}, { // Tag\n\tgetTag(tag) {\n\t\treturn tag.tag\n\t},\n\tencode(tag, encode) {\n\t\tencode(tag.value)\n\t}\n}, { // ArrayBuffer\n\tencode(arrayBuffer, encode, makeRoom) {\n\t\twriteBuffer(arrayBuffer, makeRoom)\n\t}\n}, { // Uint8Array\n\tgetTag(typedArray) {\n\t\tif (typedArray.constructor === Uint8Array) {\n\t\t\tif (this.tagUint8Array || hasNodeBuffer && this.tagUint8Array !== false)\n\t\t\t\treturn 64;\n\t\t} // else no tag\n\t},\n\tencode(typedArray, encode, makeRoom) {\n\t\twriteBuffer(typedArray, makeRoom)\n\t}\n},\n\ttypedArrayEncoder(68, 1),\n\ttypedArrayEncoder(69, 2),\n\ttypedArrayEncoder(70, 4),\n\ttypedArrayEncoder(71, 8),\n\ttypedArrayEncoder(72, 1),\n\ttypedArrayEncoder(77, 2),\n\ttypedArrayEncoder(78, 4),\n\ttypedArrayEncoder(79, 8),\n\ttypedArrayEncoder(85, 4),\n\ttypedArrayEncoder(86, 8),\n{\n\tencode(sharedData, encode) { // write SharedData\n\t\tlet packedValues = sharedData.packedValues || []\n\t\tlet sharedStructures = sharedData.structures || []\n\t\tif (packedValues.values.length > 0) {\n\t\t\ttarget[position++] = 0xd8 // one-byte tag\n\t\t\ttarget[position++] = 51 // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt\n\t\t\twriteArrayHeader(4)\n\t\t\tlet valuesArray = packedValues.values\n\t\t\tencode(valuesArray)\n\t\t\twriteArrayHeader(0) // prefixes\n\t\t\twriteArrayHeader(0) // suffixes\n\t\t\tpackedObjectMap = Object.create(sharedPackedObjectMap || null)\n\t\t\tfor (let i = 0, l = valuesArray.length; i < l; i++) {\n\t\t\t\tpackedObjectMap[valuesArray[i]] = i\n\t\t\t}\n\t\t}\n\t\tif (sharedStructures) {\n\t\t\ttargetView.setUint32(position, 0xd9dffe00)\n\t\t\tposition += 3\n\t\t\tlet definitions = sharedStructures.slice(0)\n\t\t\tdefinitions.unshift(0xe000)\n\t\t\tdefinitions.push(new Tag(sharedData.version, 0x53687264))\n\t\t\tencode(definitions)\n\t\t} else\n\t\t\tencode(new Tag(sharedData.version, 0x53687264))\n\t\t}\n\t}]\nfunction typedArrayEncoder(tag, size) {\n\tif (!isLittleEndianMachine && size > 1)\n\t\ttag -= 4 // the big endian equivalents are 4 less\n\treturn {\n\t\ttag: tag,\n\t\tencode: function writeExtBuffer(typedArray, encode) {\n\t\t\tlet length = typedArray.byteLength\n\t\t\tlet offset = typedArray.byteOffset || 0\n\t\t\tlet buffer = typedArray.buffer || typedArray\n\t\t\tencode(hasNodeBuffer ? Buffer.from(buffer, offset, length) :\n\t\t\t\tnew Uint8Array(buffer, offset, length))\n\t\t}\n\t}\n}\nfunction writeBuffer(buffer, makeRoom) {\n\tlet length = buffer.byteLength\n\tif (length < 0x18) {\n\t\ttarget[position++] = 0x40 + length\n\t} else if (length < 0x100) {\n\t\ttarget[position++] = 0x58\n\t\ttarget[position++] = length\n\t} else if (length < 0x10000) {\n\t\ttarget[position++] = 0x59\n\t\ttarget[position++] = length >> 8\n\t\ttarget[position++] = length & 0xff\n\t} else {\n\t\ttarget[position++] = 0x5a\n\t\ttargetView.setUint32(position, length)\n\t\tposition += 4\n\t}\n\tif (position + length >= target.length) {\n\t\tmakeRoom(position + length)\n\t}\n\t// if it is already a typed array (has an ArrayBuffer), use that, but if it is an ArrayBuffer itself,\n\t// must wrap it to set it.\n\ttarget.set(buffer.buffer ? buffer : new Uint8Array(buffer), position)\n\tposition += length\n}\n\nfunction insertIds(serialized, idsToInsert) {\n\t// insert the ids that need to be referenced for structured clones\n\tlet nextId\n\tlet distanceToMove = idsToInsert.length * 2\n\tlet lastEnd = serialized.length - distanceToMove\n\tidsToInsert.sort((a, b) => a.offset > b.offset ? 1 : -1)\n\tfor (let id = 0; id < idsToInsert.length; id++) {\n\t\tlet referee = idsToInsert[id]\n\t\treferee.id = id\n\t\tfor (let position of referee.references) {\n\t\t\tserialized[position++] = id >> 8\n\t\t\tserialized[position] = id & 0xff\n\t\t}\n\t}\n\twhile (nextId = idsToInsert.pop()) {\n\t\tlet offset = nextId.offset\n\t\tserialized.copyWithin(offset + distanceToMove, offset, lastEnd)\n\t\tdistanceToMove -= 2\n\t\tlet position = offset + distanceToMove\n\t\tserialized[position++] = 0xd8\n\t\tserialized[position++] = 28 // http://cbor.schmorp.de/value-sharing\n\t\tlastEnd = offset\n\t}\n\treturn serialized\n}\nfunction writeBundles(start, encode) {\n\ttargetView.setUint32(bundledStrings.position + start, position - bundledStrings.position - start + 1) // the offset to bundle\n\tlet writeStrings = bundledStrings\n\tbundledStrings = null\n\tencode(writeStrings[0])\n\tencode(writeStrings[1])\n}\n\nexport function addExtension(extension) {\n\tif (extension.Class) {\n\t\tif (!extension.encode)\n\t\t\tthrow new Error('Extension has no encode function')\n\t\textensionClasses.unshift(extension.Class)\n\t\textensions.unshift(extension)\n\t}\n\tdecodeAddExtension(extension)\n}\nlet defaultEncoder = new Encoder({ useRecords: false })\nexport const encode = defaultEncoder.encode\nexport const encodeAsIterable = defaultEncoder.encodeAsIterable\nexport const encodeAsAsyncIterable = defaultEncoder.encodeAsAsyncIterable\nexport { FLOAT32_OPTIONS } from './decode.js'\nimport { FLOAT32_OPTIONS } from './decode.js'\nexport const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS\nexport const REUSE_BUFFER_MODE = 512\nexport const RESET_BUFFER_MODE = 1024\nexport const THROW_ON_ITERABLE = 2048\n\n\n","import { Encoder, decode } from 'cbor-x';\n\nconst encoder = new Encoder({ tagUint8Array: false });\n\n// Message types (must match client_api_wire.h)\nexport const MSG = {\n PUT_REQUEST: 1,\n PUT_DATA: 2,\n PUT_END: 3,\n PUT_RESPONSE: 4,\n GET_REQUEST: 5,\n GET_RESPONSE_START: 6,\n GET_DATA: 7,\n GET_END: 8,\n ERROR: 11,\n AUTH_REQUEST: 12,\n BLOCK_PUT_REQUEST: 13,\n BLOCK_PUT_RESPONSE: 14,\n BLOCK_GET_REQUEST: 15,\n BLOCK_GET_RESPONSE: 16,\n BLOCK_DELETE_REQUEST: 17,\n BLOCK_DELETE_RESPONSE: 18,\n HEALTH_REQUEST: 19,\n HEALTH_RESPONSE: 20,\n PEER_INFO_REQUEST: 21,\n PEER_INFO_RESPONSE: 22,\n PEER_CONNECT: 23,\n PEER_CONNECT_RESULT: 24,\n PEER_LIST_REQUEST: 25,\n PEER_LIST_RESPONSE: 26,\n FRIEND_ADD: 27,\n FRIEND_REMOVE: 28,\n FRIEND_LIST: 29,\n FRIEND_LIST_RESPONSE: 30,\n UPDATE_STATUS_REQUEST: 31,\n UPDATE_STATUS_RESPONSE: 32,\n CONFIG_SHOW_REQUEST: 33,\n CONFIG_SHOW_RESPONSE: 34,\n CONFIG_SET_REQUEST: 35,\n CONFIG_SET_RESPONSE: 36,\n CONFIG_RELOAD_REQUEST: 37,\n CONFIG_RELOAD_RESPONSE: 38,\n LOAD_REQUEST: 39,\n LOAD_PROGRESS: 40,\n LOAD_END: 41\n};\n\n/**\n * Load terminal status. CBOR LOAD_END frames carry these as numbers;\n * the HTTP ?load=1 ndjson terminal line uses the string form\n * (\"loaded\"/\"partial\"/\"failed\").\n */\nexport const LOAD_STATUS = {\n loaded: 0,\n partial: 1,\n failed: 2\n};\n\n/**\n * Peer-info wire format bytes shared by PEER_INFO_REQUEST/RESPONSE,\n * PEER_CONNECT and FRIEND_ADD: 0 = raw CBOR, 1 = base58 text,\n * 2 = PPM QR image.\n */\nexport const PEER_FORMATS = { cbor: 0, base58: 1, qrcode: 2 };\n\n/** HTTP Content-Type for each peer-info wire format (request bodies). */\nexport const PEER_CONTENT_TYPES = {\n [PEER_FORMATS.cbor]: 'application/cbor',\n [PEER_FORMATS.base58]: 'text/plain',\n [PEER_FORMATS.qrcode]: 'image/x-portable-pixmap',\n};\n\nexport const STATUS = {\n OK: 0,\n BAD_REQUEST: 1,\n NOT_FOUND: 2,\n INTERNAL_ERROR: 3,\n RANGE_NOT_SATISFIABLE: 4,\n UNAUTHORIZED: 5\n};\n\n/**\n * @param {Uint8Array} bytes\n * @returns {number}\n */\nexport function getMessageType(bytes) {\n const arr = decode(bytes);\n return Array.isArray(arr) ? arr[0] : null;\n}\n\n// --- Auth ---\n\n/**\n * @param {string} apiKey\n * @returns {Uint8Array}\n */\nexport function encodeAuthRequest(apiKey) {\n const keyBytes = new TextEncoder().encode(apiKey);\n return encoder.encode([MSG.AUTH_REQUEST, keyBytes]);\n}\n\n// --- PUT ---\n\n/**\n * @param {import('./types.js').OffsPutOptions} options\n * @param {Uint8Array|null} data\n * @returns {Uint8Array}\n */\nexport function encodePutRequest(options, data = null) {\n const recycler = options.recyclerUrls || [];\n const payload = [\n MSG.PUT_REQUEST,\n options.contentType,\n options.fileName,\n options.streamLength,\n options.serverAddress || null,\n data || new Uint8Array(0),\n recycler,\n options.temporary ? 1 : 0\n ];\n if (options.tupleSize !== undefined) {\n payload.push(options.tupleSize);\n }\n return encoder.encode(payload);\n}\n\n/**\n * @param {Uint8Array} chunk\n * @returns {Uint8Array}\n */\nexport function encodePutData(chunk) {\n return encoder.encode([MSG.PUT_DATA, chunk]);\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodePutEnd() {\n return encoder.encode([MSG.PUT_END]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{oriString: string}}\n */\nexport function decodePutResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PUT_RESPONSE) throw new Error('Not a put response');\n return { oriString: arr[1] };\n}\n\n// --- GET ---\n\n/**\n * @param {string} oriString\n * @param {{start?: number, end?: number}} [range]\n * @returns {Uint8Array}\n */\nexport function encodeGetRequest(oriString, range) {\n const hasRange = range && (range.start !== undefined || range.end !== undefined);\n const payload = [MSG.GET_REQUEST, oriString, hasRange ? 1 : 0];\n if (hasRange) {\n payload.push(range.start || 0);\n payload.push(range.end || 0);\n }\n return encoder.encode(payload);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{contentType: string, contentLength: number, hasRange: boolean, rangeStart?: number, rangeEnd?: number}}\n */\nexport function decodeGetResponseStart(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.GET_RESPONSE_START) throw new Error('Not a get response start');\n return {\n contentType: arr[1],\n contentLength: arr[2],\n hasRange: arr[3] === 1,\n rangeStart: arr[3] ? arr[4] : undefined,\n rangeEnd: arr[3] ? arr[5] : undefined\n };\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {Uint8Array}\n */\nexport function decodeGetData(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.GET_DATA) throw new Error('Not a get data');\n return arr[1];\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {boolean}\n */\nexport function isGetEnd(bytes) {\n const arr = decode(bytes);\n return Array.isArray(arr) && arr[0] === MSG.GET_END;\n}\n\n// --- Load ---\n\n/**\n * Ask the daemon to pull a file's blocks into its block cache without\n * sending the file data. Uses the same optional-range shape as the C-side\n * client_api_load_request_encode: an unranged request is\n * `[LOAD_REQUEST, oriString]`, a ranged request is\n * `[LOAD_REQUEST, oriString, 1, start, end]` (literal flag 1 in position 2).\n * @param {string} oriString\n * @param {{start?: number, end?: number}} [range]\n * @returns {Uint8Array}\n */\nexport function encodeLoadRequest(oriString, range) {\n const hasRange = range && (range.start !== undefined || range.end !== undefined);\n if (!hasRange) {\n return encoder.encode([MSG.LOAD_REQUEST, oriString]);\n }\n return encoder.encode([\n MSG.LOAD_REQUEST,\n oriString,\n 1,\n range.start || 0,\n range.end || 0\n ]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{tuplesLoaded: number, tuplesTotal: number}}\n */\nexport function decodeLoadProgress(bytes) {\n const arr = decode(bytes);\n if (!(Array.isArray(arr) && arr[0] === MSG.LOAD_PROGRESS)) {\n throw new Error('Not a load progress');\n }\n return { tuplesLoaded: arr[1], tuplesTotal: arr[2] };\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {boolean}\n */\nexport function isLoadEnd(bytes) {\n const arr = decode(bytes);\n return Array.isArray(arr) && arr[0] === MSG.LOAD_END;\n}\n\n/**\n * Terminal frame of a load operation: [LOAD_END, status, tuplesLoaded, tuplesTotal].\n * @param {Uint8Array} bytes\n * @returns {{status: number, tuplesLoaded: number, tuplesTotal: number}}\n * status: 0=loaded, 1=partial (some tuples skipped), 2=failed\n */\nexport function decodeLoadEnd(bytes) {\n const arr = decode(bytes);\n if (!(Array.isArray(arr) && arr[0] === MSG.LOAD_END)) {\n throw new Error('Not a load end');\n }\n return { status: arr[1], tuplesLoaded: arr[2], tuplesTotal: arr[3] };\n}\n\n// --- Error ---\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{statusCode: number, message: string}|null}\n */\nexport function decodeError(bytes) {\n const arr = decode(bytes);\n if (!Array.isArray(arr) || arr[0] !== MSG.ERROR) return null;\n return { statusCode: arr[1], message: arr[2] };\n}\n\n// --- Block ---\n\n/**\n * @param {Uint8Array} data\n * @param {number} encoding 0=raw, 1=base58\n * @returns {Uint8Array}\n */\nexport function encodeBlockPutRequest(data, encoding = 0) {\n return encoder.encode([MSG.BLOCK_PUT_REQUEST, data, encoding]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, hash: Uint8Array|string}}\n */\nexport function decodeBlockPutResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.BLOCK_PUT_RESPONSE) throw new Error('Not a block put response');\n return { status: arr[1], hash: arr[2] };\n}\n\n/**\n * @param {Uint8Array} hash\n * @returns {Uint8Array}\n */\nexport function encodeBlockGetRequest(hash) {\n return encoder.encode([MSG.BLOCK_GET_REQUEST, hash]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, data: Uint8Array}}\n */\nexport function decodeBlockGetResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.BLOCK_GET_RESPONSE) throw new Error('Not a block get response');\n return { status: arr[1], data: arr[2] };\n}\n\n/**\n * @param {Uint8Array} hash\n * @returns {Uint8Array}\n */\nexport function encodeBlockDeleteRequest(hash) {\n return encoder.encode([MSG.BLOCK_DELETE_REQUEST, hash]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number}}\n */\nexport function decodeBlockDeleteResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.BLOCK_DELETE_RESPONSE) throw new Error('Not a block delete response');\n return { status: arr[1] };\n}\n\n// --- Health ---\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeHealthRequest() {\n return encoder.encode([MSG.HEALTH_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{json: string}}\n */\nexport function decodeHealthResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.HEALTH_RESPONSE) throw new Error('Not a health response');\n return { json: arr[1] };\n}\n\n// --- Peer ---\n\n/**\n * @param {number} [format=0] 0=cbor, 1=base58, 2=qrcode (PPM image)\n * @returns {Uint8Array}\n */\nexport function encodePeerInfoRequest(format = 0) {\n if (format === 0) {\n return encoder.encode([MSG.PEER_INFO_REQUEST]); // 1-element shape, unchanged\n }\n return encoder.encode([MSG.PEER_INFO_REQUEST, format]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{format: number, data: Uint8Array}}\n */\nexport function decodePeerInfoResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PEER_INFO_RESPONSE) throw new Error('Not a peer info response');\n return { format: arr[1], data: arr[2] };\n}\n\n/**\n * @param {number} format 0=cbor, 1=base58, 2=qrcode (PPM image)\n * @param {Uint8Array} data\n * @returns {Uint8Array}\n */\nexport function encodePeerConnect(format, data) {\n return encoder.encode([MSG.PEER_CONNECT, format, data]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number}}\n */\nexport function decodePeerConnectResult(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PEER_CONNECT_RESULT) throw new Error('Not a peer connect result');\n return { status: arr[1] };\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodePeerListRequest() {\n return encoder.encode([MSG.PEER_LIST_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {any[]}\n */\nexport function decodePeerListResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.PEER_LIST_RESPONSE) throw new Error('Not a peer list response');\n return arr[1];\n}\n\n// --- Friend ---\n\n/**\n * @param {number} format 0=cbor, 1=base58, 2=qrcode (PPM image)\n * @param {Uint8Array} data\n * @returns {Uint8Array}\n */\nexport function encodeFriendAdd(format, data) {\n return encoder.encode([MSG.FRIEND_ADD, format, data]);\n}\n\n/**\n * @param {Uint8Array} nodeId\n * @returns {Uint8Array}\n */\nexport function encodeFriendRemove(nodeId) {\n return encoder.encode([MSG.FRIEND_REMOVE, nodeId]);\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeFriendListRequest() {\n return encoder.encode([MSG.FRIEND_LIST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {any[]}\n */\nexport function decodeFriendListResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.FRIEND_LIST_RESPONSE) throw new Error('Not a friend list response');\n return arr[1];\n}\n\n// --- Config ---\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeConfigShowRequest() {\n return encoder.encode([MSG.CONFIG_SHOW_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{json: string}}\n */\nexport function decodeConfigShowResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.CONFIG_SHOW_RESPONSE) throw new Error('Not a config show response');\n return { json: arr[1] };\n}\n\n/**\n * @param {string} field\n * @param {string} value\n * @returns {Uint8Array}\n */\nexport function encodeConfigSetRequest(field, value) {\n return encoder.encode([MSG.CONFIG_SET_REQUEST, field, value]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, restartRequired: boolean, message: string}}\n */\nexport function decodeConfigSetResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.CONFIG_SET_RESPONSE) throw new Error('Not a config set response');\n return { status: arr[1], restartRequired: arr[2] === 1, message: arr[3] };\n}\n\n/**\n * @returns {Uint8Array}\n */\nexport function encodeConfigReloadRequest() {\n return encoder.encode([MSG.CONFIG_RELOAD_REQUEST]);\n}\n\n/**\n * @param {Uint8Array} bytes\n * @returns {{status: number, message: string}}\n */\nexport function decodeConfigReloadResponse(bytes) {\n const arr = decode(bytes);\n if (arr[0] !== MSG.CONFIG_RELOAD_RESPONSE) throw new Error('Not a config reload response');\n return { status: arr[1], message: arr[2] };\n}\n","\nimport { PEER_CONTENT_TYPES, PEER_FORMATS } from '../wire.js';\n\n/**\n * HTTP REST transport for the OFFS client.\n * Maps wire messages to the HTTP routes in src/ClientAPI/HTTP/.\n */\nexport class HttpTransport {\n /** @type {string} */\n baseUrl;\n /** @type {string|undefined} */\n apiKey;\n /** @type {AbortController|null} */\n abortController = null;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [_options]\n */\n constructor(url, apiKey, _options) {\n this.baseUrl = url.replace(/\\/$/, '');\n this.apiKey = apiKey;\n }\n\n /**\n * @returns {Promise}\n */\n async connect() {\n this.abortController = new AbortController();\n }\n\n disconnect() {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n isConnected() {\n return this.abortController !== null;\n }\n\n /**\n * @param {string} path\n * @returns {string}\n */\n url(path) {\n return `${this.baseUrl}${path}`;\n }\n\n /**\n * @returns {Record}\n */\n authHeaders() {\n const headers = {};\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return headers;\n }\n\n /**\n * @param {(type: number, bytes: Uint8Array) => void} _handler\n */\n setMessageHandler(_handler) {\n // HTTP is request/response; no async messages.\n }\n\n /**\n * Send raw bytes — not used directly for HTTP; use the typed methods.\n * @param {Uint8Array} _bytes\n */\n send(_bytes) {\n throw new Error('HttpTransport does not support raw send; use OffsClient methods');\n }\n\n /**\n * Upload a file to PUT /offsystem.\n * @param {import('../types.js').OffsPutOptions} options\n * @param {ReadableStream|Uint8Array} body\n * @returns {Promise<{oriString: string}>}\n */\n async put(options, body) {\n const headers = {\n ...this.authHeaders(),\n 'type': options.contentType,\n 'file-name': options.fileName,\n 'stream-length': String(options.streamLength),\n };\n if (options.serverAddress) headers['server-address'] = options.serverAddress;\n if (options.recyclerUrls?.length) headers['recycler'] = JSON.stringify(options.recyclerUrls);\n if (options.temporary) headers['temporary'] = 'true';\n if (options.tupleSize !== undefined) headers['tuple-size'] = String(options.tupleSize);\n\n let requestBody = body;\n if (body && typeof body.getReader === 'function') {\n requestBody = await this._readStream(body);\n }\n\n const response = await fetch(this.url('/offsystem'), {\n method: 'PUT',\n headers,\n body: requestBody,\n signal: this.abortController?.signal\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Upload failed: ${response.status} ${text}`);\n }\n const oriString = await response.text();\n return { oriString };\n }\n\n /**\n * Read a ReadableStream into a Uint8Array.\n * The OFFS HTTP server is HTTP/1.1, so request streaming via duplex: 'half'\n * causes ERR_ALPN_NEGOTIATION_FAILED. Buffering the body avoids that.\n * @param {ReadableStream} stream\n * @returns {Promise}\n */\n async _readStream(stream) {\n const reader = stream.getReader();\n const chunks = [];\n let totalLength = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n }\n\n /**\n * Download from GET /offsystem/v3/...\n * @param {string} offUrl\n * @param {import('../types.js').OffsGetCallbacks} callbacks\n */\n async get(offUrl, callbacks) {\n const response = await fetch(offUrl, {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n callbacks.onError?.(response.status, text);\n return;\n }\n\n const contentType = response.headers.get('content-type') || 'application/octet-stream';\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10);\n const hasRange = response.status === 206;\n const rangeHeader = response.headers.get('content-range');\n let rangeStart, rangeEnd;\n if (rangeHeader) {\n const match = rangeHeader.match(/bytes (\\d+)-(\\d+)\\//);\n if (match) {\n rangeStart = parseInt(match[1], 10);\n rangeEnd = parseInt(match[2], 10);\n }\n }\n callbacks.onStart?.(contentType, contentLength, hasRange, rangeStart, rangeEnd);\n\n const reader = response.body?.getReader();\n if (!reader) {\n callbacks.onEnd?.();\n return;\n }\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) callbacks.onData(value);\n }\n callbacks.onEnd?.();\n } catch (err) {\n callbacks.onError?.(0, String(err));\n }\n }\n\n /**\n * Cache-only load: GET offUrl + '?load=1'. The daemon pulls the file's\n * blocks into its block cache without serving file data and streams\n * application/x-ndjson progress, one JSON object per line:\n * {\"tuples_loaded\":n,\"tuples_total\":m} — per resolved tuple\n * {\"status\":\"loaded|partial|failed\",...} — terminal line\n * The terminal line is also reported through onEnd.\n * @param {string} offUrl\n * @param {import('../types.js').OffsGetCallbacks} callbacks\n * @param {{start?: number, end?: number}} [range]\n * @returns {Promise}\n */\n async load(offUrl, callbacks = {}, range) {\n const separator = offUrl.includes('?') ? '&' : '?';\n const response = await fetch(`${offUrl}${separator}load=1`, {\n method: 'GET',\n headers: range\n ? { ...this.authHeaders(), 'Range': `bytes=${range.start || 0}-${range.end || 0}` }\n : this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Load failed: ${response.status} ${text}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) return;\n\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let newlineIndex;\n while ((newlineIndex = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newlineIndex).trim();\n buffer = buffer.slice(newlineIndex + 1);\n if (line) this._handleLoadLine(line, callbacks);\n }\n }\n buffer += decoder.decode();\n const line = buffer.trim();\n if (line) this._handleLoadLine(line, callbacks);\n } catch (err) {\n callbacks.onError?.(0, String(err));\n }\n }\n\n /**\n * Parse one ndjson progress/status line and dispatch to callbacks.\n * @param {string} line\n * @param {import('../types.js').OffsGetCallbacks} callbacks\n */\n _handleLoadLine(line, callbacks) {\n let message;\n try {\n message = JSON.parse(line);\n } catch (_err) {\n throw new Error(`Bad ndjson line: ${line}`);\n }\n if (message.status !== undefined) {\n callbacks.onEnd?.(message.status, message.tuples_loaded || 0, message.tuples_total || 0);\n } else {\n callbacks.onProgress?.(message.tuples_loaded || 0, message.tuples_total || 0);\n }\n }\n\n /**\n * Delete content.\n * @param {string} offUrl\n * @returns {Promise}\n */\n async delete(offUrl) {\n const response = await fetch(offUrl, {\n method: 'DELETE',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Delete failed: ${response.status} ${text}`);\n }\n }\n\n /**\n * @param {Uint8Array} data\n * @param {number} [encoding]\n * @returns {Promise<{status: number, hash: Uint8Array|string}>}\n */\n async blockPut(data, encoding = 0) {\n const query = encoding === 1 ? '?encoding=base58' : '';\n const response = await fetch(this.url(`/blocks${query}`), {\n method: 'PUT',\n headers: { ...this.authHeaders(), 'Content-Type': 'application/octet-stream' },\n body: data,\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Block put failed: ${response.status} ${text}`);\n }\n const hash = await response.arrayBuffer();\n return { status: 0, hash: new Uint8Array(hash) };\n }\n\n /**\n * @param {string} base58Hash\n * @returns {Promise<{status: number, data: Uint8Array}>}\n */\n async blockGet(base58Hash) {\n const response = await fetch(this.url(`/blocks/${base58Hash}`), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n return { status: 2, data: new Uint8Array(0) }; // NOT_FOUND\n }\n const data = await response.arrayBuffer();\n return { status: 0, data: new Uint8Array(data) };\n }\n\n /**\n * @param {string} base58Hash\n * @returns {Promise<{status: number}>}\n */\n async blockDelete(base58Hash) {\n const response = await fetch(this.url(`/blocks/${base58Hash}`), {\n method: 'DELETE',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n return { status: response.ok ? 0 : 2 };\n }\n\n /**\n * @returns {Promise}\n */\n async health() {\n const response = await fetch(this.url('/health'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) {\n throw new Error(`Health check failed: ${response.status}`);\n }\n return response.json();\n }\n\n /**\n * @param {string} [format='cbor']\n * @returns {Promise<{format: number, data: Uint8Array}>}\n */\n async peerInfo(format = 'cbor') {\n const fmt = PEER_FORMATS[format] ?? 0;\n const response = await fetch(this.url(`/peer/info?format=${format}`), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Peer info failed: ${response.status}`);\n const data = await response.arrayBuffer();\n return { format: fmt, data: new Uint8Array(data) };\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise<{status: number}>}\n */\n async peerConnect(peerInfo, format = 0) {\n const response = await fetch(this.url('/peer/connect'), {\n method: 'POST',\n headers: { ...this.authHeaders(), 'Content-Type': PEER_CONTENT_TYPES[format] ?? 'application/cbor' },\n body: format === PEER_FORMATS.base58 ? new TextDecoder().decode(peerInfo) : peerInfo,\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Peer connect failed: ${response.status}`);\n return { status: 0 };\n }\n\n /**\n * @returns {Promise}\n */\n async peerList() {\n const response = await fetch(this.url('/peers'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Peer list failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise}\n */\n async friendAdd(peerInfo, format = 0) {\n const response = await fetch(this.url('/friends'), {\n method: 'POST',\n headers: { ...this.authHeaders(), 'Content-Type': PEER_CONTENT_TYPES[format] ?? 'application/cbor' },\n body: format === PEER_FORMATS.base58 ? new TextDecoder().decode(peerInfo) : peerInfo,\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Friend add failed: ${response.status}`);\n }\n\n /**\n * @param {string} nodeId\n * @returns {Promise}\n */\n async friendRemove(nodeId) {\n const response = await fetch(this.url(`/friends/${nodeId}`), {\n method: 'DELETE',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Friend remove failed: ${response.status}`);\n }\n\n /**\n * @returns {Promise}\n */\n async friendList() {\n const response = await fetch(this.url('/friends'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Friend list failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @returns {Promise}\n */\n async configShow() {\n const response = await fetch(this.url('/config'), {\n method: 'GET',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Config show failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @param {string} field\n * @param {string} value\n * @returns {Promise<{staged: any, rejected: any, restart_required: boolean}>}\n */\n async configSet(field, value) {\n const response = await fetch(this.url('/config'), {\n method: 'PUT',\n headers: { ...this.authHeaders(), 'Content-Type': 'application/json' },\n body: JSON.stringify({ [field]: value }),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Config set failed: ${response.status}`);\n return response.json();\n }\n\n /**\n * @returns {Promise}\n */\n async configReload() {\n const response = await fetch(this.url('/config/restart'), {\n method: 'POST',\n headers: this.authHeaders(),\n signal: this.abortController?.signal,\n });\n if (!response.ok) throw new Error(`Config reload failed: ${response.status}`);\n }\n}\n","import { encodeAuthRequest, getMessageType } from '../wire.js';\n\n/**\n * WebSocket transport for the OFFS client.\n * Sends CBOR messages as binary WebSocket frames.\n */\nexport class WsTransport {\n /** @type {WebSocket|null} */\n socket = null;\n /** @type {string|undefined} */\n apiKey;\n /** @type {((type: number, bytes: Uint8Array) => void)|null} */\n messageHandler = null;\n /** @type {Promise|null} */\n openPromise = null;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [_options]\n */\n constructor(url, apiKey, _options) {\n this.url = url;\n this.apiKey = apiKey;\n }\n\n /**\n * @returns {Promise}\n */\n connect() {\n if (this.socket) {\n return this.openPromise || Promise.resolve();\n }\n\n this.socket = new WebSocket(this.url);\n this.socket.binaryType = 'arraybuffer';\n\n this.openPromise = new Promise((resolve, reject) => {\n const socket = this.socket;\n if (!socket) return reject(new Error('Socket not created'));\n\n socket.onopen = () => {\n if (this.apiKey) {\n this.send(encodeAuthRequest(this.apiKey));\n }\n resolve();\n };\n socket.onerror = (event) => {\n const message = event.message || event.error?.message || 'unknown';\n reject(new Error(`WebSocket error: ${message}`));\n };\n socket.onclose = () => {\n this.socket = null;\n this.openPromise = null;\n };\n socket.onmessage = (event) => {\n const bytes = new Uint8Array(event.data);\n const type = getMessageType(bytes);\n if (type !== null) {\n this.messageHandler?.(type, bytes);\n }\n };\n });\n\n return this.openPromise;\n }\n\n disconnect() {\n if (this.socket) {\n this.socket.close();\n this.socket = null;\n }\n this.openPromise = null;\n }\n\n isConnected() {\n return this.socket !== null && this.socket.readyState === WebSocket.OPEN;\n }\n\n /**\n * @param {Uint8Array} bytes\n */\n send(bytes) {\n if (!this.isConnected()) {\n throw new Error('WebSocket not connected');\n }\n this.socket.send(bytes);\n }\n\n /**\n * @param {(type: number, bytes: Uint8Array) => void} handler\n */\n setMessageHandler(handler) {\n this.messageHandler = handler;\n }\n}\n","import { encodeAuthRequest, getMessageType } from '../wire.js';\n\n/**\n * WebTransport transport for the OFFS client.\n * Sends length-prefixed CBOR frames over an HTTP/3 bidirectional stream.\n */\nexport class WtTransport {\n /** @type {WebTransport|null} */\n transport = null;\n /** @type {WritableStreamWriter|null} */\n writer = null;\n /** @type {ReadableStreamReader|null} */\n reader = null;\n /** @type {string|undefined} */\n apiKey;\n /** @type {((type: number, bytes: Uint8Array) => void)|null} */\n messageHandler = null;\n /** @type {Promise|null} */\n openPromise = null;\n /** @type {boolean} */\n running = false;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [_options]\n */\n constructor(url, apiKey, _options) {\n this.url = url;\n this.apiKey = apiKey;\n }\n\n /**\n * @returns {Promise}\n */\n async connect() {\n if (this.transport) return this.openPromise || Promise.resolve();\n\n this.transport = new WebTransport(this.url);\n this.openPromise = this.transport.ready.then(async () => {\n const stream = await this.transport.createBidirectionalStream();\n this.writer = stream.writable.getWriter();\n this.reader = stream.readable.getReader();\n this.running = true;\n this._readLoop();\n if (this.apiKey) {\n await this.send(encodeAuthRequest(this.apiKey));\n }\n });\n\n return this.openPromise;\n }\n\n disconnect() {\n this.running = false;\n this.writer?.releaseLock();\n this.reader?.releaseLock();\n this.transport?.close();\n this.writer = null;\n this.reader = null;\n this.transport = null;\n this.openPromise = null;\n }\n\n isConnected() {\n return this.transport !== null && this.transport.state === 'connected';\n }\n\n /**\n * @param {Uint8Array} bytes\n */\n async send(bytes) {\n if (!this.writer) throw new Error('WebTransport not connected');\n const length = new Uint8Array(4);\n const view = new DataView(length.buffer);\n view.setUint32(0, bytes.length, false); // big-endian\n await this.writer.write(length);\n await this.writer.write(bytes);\n }\n\n /**\n * @param {(type: number, bytes: Uint8Array) => void} handler\n */\n setMessageHandler(handler) {\n this.messageHandler = handler;\n }\n\n async _readLoop() {\n /** @type {Uint8Array|null} */\n let pending = null;\n try {\n while (this.running) {\n const { done, value } = await this.reader.read();\n if (done) break;\n const chunk = value instanceof Uint8Array ? value : new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n pending = pending ? _concat(pending, chunk) : chunk;\n while (pending.length >= 4) {\n const view = new DataView(pending.buffer, pending.byteOffset, pending.length);\n const msgLen = view.getUint32(0, false);\n if (pending.length < 4 + msgLen) break;\n const msgBytes = pending.subarray(4, 4 + msgLen);\n const type = getMessageType(msgBytes);\n if (type !== null) {\n this.messageHandler?.(type, msgBytes);\n }\n pending = pending.subarray(4 + msgLen);\n }\n }\n } catch (_err) {\n // ignore errors after disconnect\n }\n }\n}\n\n/**\n * @param {Uint8Array} a\n * @param {Uint8Array} b\n * @returns {Uint8Array}\n */\nfunction _concat(a, b) {\n const result = new Uint8Array(a.length + b.length);\n result.set(a, 0);\n result.set(b, a.length);\n return result;\n}\n","/**\n * Bitcoin-style Base58 encoding/decoding.\n * Matches the C implementation in liboffs/src/Util/base58.c.\n */\nconst ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/** @type {Int8Array} */\nconst INDICES = new Int8Array(128);\nINDICES.fill(-1);\nfor (let index = 0; index < ALPHABET.length; index++) {\n INDICES[ALPHABET.charCodeAt(index)] = index;\n}\n\n/**\n * Decode a base58 string into a Uint8Array.\n * @param {string} input\n * @returns {Uint8Array|null}\n */\nexport function base58Decode(input) {\n if (input.length === 0) return null;\n\n let leadingZeros = 0;\n while (leadingZeros < input.length && input[leadingZeros] === '1') {\n leadingZeros++;\n }\n\n const bytes = [];\n for (let index = leadingZeros; index < input.length; index++) {\n const codeUnit = input.charCodeAt(index);\n if (codeUnit >= 128) return null;\n const digit = INDICES[codeUnit];\n if (digit < 0) return null;\n\n let carry = digit;\n for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {\n carry += bytes[byteIndex] * 58;\n bytes[byteIndex] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n for (let index = 0; index < leadingZeros; index++) {\n bytes.push(0);\n }\n\n bytes.reverse();\n return new Uint8Array(bytes);\n}\n\n/**\n * Encode a Uint8Array into a base58 string.\n * @param {Uint8Array|number[]} input\n * @returns {string}\n */\nexport function base58Encode(input) {\n if (input.length === 0) return '';\n\n const bytes = Array.from(input);\n let leadingZeros = 0;\n while (leadingZeros < bytes.length && bytes[leadingZeros] === 0) {\n leadingZeros++;\n }\n\n const resultCodes = [];\n for (let index = leadingZeros; index < bytes.length; index++) {\n let carry = bytes[index];\n for (let resultIndex = 0; resultIndex < resultCodes.length; resultIndex++) {\n carry += resultCodes[resultIndex] * 256;\n resultCodes[resultIndex] = carry % 58;\n carry = Math.floor(carry / 58);\n }\n while (carry > 0) {\n resultCodes.push(carry % 58);\n carry = Math.floor(carry / 58);\n }\n }\n\n const prefix = '1'.repeat(leadingZeros);\n return prefix + resultCodes.reverse().map((code) => ALPHABET[code]).join('');\n}\n\n/**\n * Parsed OFFS URL components.\n * @typedef {Object} ParsedOffUrl\n * @property {string} fileHashB58\n * @property {string} descriptorHashB58\n * @property {number} streamLength\n * @property {string} fileName\n */\n\n/**\n * Parse an offs:// or http(s) OFFS URL.\n * Format: .../offsystem/v3/{type}/{length}/{hash1}/{hash2}/{name}\n * @param {string} url\n * @returns {ParsedOffUrl|null}\n */\nexport function parseOffUrl(url) {\n const prefixIndex = url.indexOf('/offsystem/v3/');\n if (prefixIndex < 0) return null;\n\n const afterPrefix = url.slice(prefixIndex + '/offsystem/v3/'.length);\n const allParts = afterPrefix.split('/');\n if (allParts.length < 4) return null;\n\n const streamLengthStr = allParts[allParts.length - 4];\n const fileHashB58 = allParts[allParts.length - 3];\n const descriptorHashB58 = allParts[allParts.length - 2];\n const fileName = allParts.slice(allParts.length - 1).join('/');\n\n const streamLength = parseInt(streamLengthStr, 10);\n if (!Number.isFinite(streamLength)) return null;\n if (base58Decode(fileHashB58) === null) return null;\n if (base58Decode(descriptorHashB58) === null) return null;\n\n return {\n fileHashB58,\n descriptorHashB58,\n streamLength,\n fileName: decodeURIComponent(fileName)\n };\n}\n\n/**\n * Guess a MIME type from a filename extension.\n * @param {string} filename\n * @returns {string}\n */\nexport function mimeFromExtension(filename) {\n const map = {\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n json: 'application/json',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n webp: 'image/webp',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mkv: 'video/x-matroska',\n avi: 'video/x-msvideo',\n mov: 'video/quicktime',\n wmv: 'video/x-msvideo',\n flv: 'video/x-flv',\n mp3: 'audio/mpeg',\n ogg: 'audio/ogg',\n wav: 'audio/wav',\n flac: 'audio/flac',\n aac: 'audio/mp4',\n m4a: 'audio/mp4',\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n pdf: 'application/pdf',\n zip: 'application/zip',\n gz: 'application/gzip',\n tar: 'application/x-tar',\n rar: 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n csv: 'text/csv',\n xml: 'application/xml',\n md: 'text/markdown',\n ofd: 'application/cbor'\n };\n const dotIndex = filename.lastIndexOf('.');\n if (dotIndex < 0 || dotIndex === filename.length - 1) return 'application/octet-stream';\n const extension = filename.slice(dotIndex + 1).toLowerCase();\n return map[extension] || 'application/octet-stream';\n}\n\n/**\n * Read a browser File or Blob into a Uint8Array.\n * @param {Blob} file\n * @returns {Promise}\n */\nexport function readFileBytes(file) {\n if (typeof file.arrayBuffer === 'function') {\n return file.arrayBuffer().then((buffer) => new Uint8Array(buffer));\n }\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(new Uint8Array(reader.result));\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(file);\n });\n}\n\n/**\n * Return the last path segment, stripping any directory separators or parent\n * references so the value is safe to use as a `file-name` header.\n * @param {string} path\n * @returns {string}\n */\nexport function basename(path) {\n const normalized = path.replace(/\\\\\\\\/g, '/');\n const parts = normalized.split('/').filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : 'file';\n}\n\n/**\n * Create a ReadableStream from a browser File.\n * @param {File} file\n * @param {number} [chunkSize=65536]\n * @returns {ReadableStream}\n */\nexport function fileToReadableStream(file, chunkSize = 65536) {\n let offset = 0;\n return new ReadableStream({\n pull(controller) {\n if (offset >= file.size) {\n controller.close();\n return;\n }\n const end = Math.min(offset + chunkSize, file.size);\n const slice = file.slice(offset, end);\n return readFileBytes(slice).then((bytes) => {\n controller.enqueue(bytes);\n offset = end;\n });\n }\n });\n}\n\n/**\n * A file-like entry with a relative path.\n * @typedef {Object} FolderEntry\n * @property {string} path\n * @property {File|Blob} file\n */\n\n/**\n * Normalize various folder input shapes into a flat list of {path, file}.\n * Accepts FileList (from ), Array,\n * Array<{path, file}>, or Record.\n * @param {FileList|File[]|FolderEntry[]|Record} items\n * @returns {FolderEntry[]}\n */\nexport function normalizeFolderEntries(items) {\n if (typeof FileList !== 'undefined' && items instanceof FileList) {\n const entries = [];\n for (let index = 0; index < items.length; index++) {\n const file = items[index];\n /** @type {string} */\n let path = file.webkitRelativePath || file.name;\n entries.push({ path, file });\n }\n return entries;\n }\n\n if (Array.isArray(items)) {\n return items.map((item) => {\n if (item instanceof File || item instanceof Blob) {\n return { path: item.webkitRelativePath || item.name, file: item };\n }\n return { path: item.path, file: item.file };\n });\n }\n\n return Object.entries(items).map(([path, file]) => ({ path, file }));\n}\n\n/**\n * Ensure an OFF URL points at an HTTP endpoint so a browser can fetch it.\n * @param {string} oriString\n * @param {string} [baseUrl='http://localhost:23402']\n * @returns {string}\n */\nexport function offUrlToHttpUrl(oriString, baseUrl = 'http://localhost:23402') {\n if (!oriString) return oriString;\n if (/^https?:\\/\\//i.test(oriString)) return oriString;\n\n let path = oriString;\n if (path.startsWith('offs://')) {\n path = path.slice('offs://'.length);\n }\n\n const prefix = '/offsystem/v3/';\n const index = path.indexOf(prefix);\n if (index >= 0) {\n path = path.slice(index);\n }\n\n if (path.startsWith(prefix)) {\n const base = baseUrl.replace(/\\/$/, '');\n return `${base}${path}`;\n }\n\n return oriString;\n}\n","import { encode, decode } from 'cbor-x';\n\n/**\n * @typedef {Object} OfdFileEntry\n * @property {string} name\n * @property {boolean} isDirectory\n * @property {Uint8Array} fileHash\n * @property {Uint8Array} descriptorHash\n * @property {number} finalByte\n * @property {number} blockType\n * @property {number} tupleSize\n * @property {number} fileOffset\n */\n\n/**\n * @typedef {Object} OfdDirectoryEntry\n * @property {string} name\n * @property {boolean} isDirectory\n * @property {Uint8Array} dirHash\n */\n\n/**\n * @typedef {OfdFileEntry|OfdDirectoryEntry} OfdEntry\n */\n\nconst DEFAULT_BLOCK_TYPE = 128000;\nconst DEFAULT_TUPLE_SIZE = 3;\n\n/**\n * Create a file OFD entry.\n * @param {Object} params\n * @param {string} params.name\n * @param {Uint8Array} params.fileHash\n * @param {Uint8Array} params.descriptorHash\n * @param {number} params.finalByte\n * @param {number} [params.blockType=128000]\n * @param {number} [params.tupleSize=3]\n * @param {number} [params.fileOffset=0]\n * @returns {OfdEntry}\n */\nexport function ofdFile({\n name,\n fileHash,\n descriptorHash,\n finalByte,\n blockType = DEFAULT_BLOCK_TYPE,\n tupleSize = DEFAULT_TUPLE_SIZE,\n fileOffset = 0\n}) {\n return {\n name,\n isDirectory: false,\n fileHash,\n descriptorHash,\n finalByte,\n blockType,\n tupleSize,\n fileOffset\n };\n}\n\n/**\n * Create a directory OFD entry.\n * @param {Object} params\n * @param {string} params.name\n * @param {Uint8Array} params.dirHash\n * @returns {OfdEntry}\n */\nexport function ofdDirectory({ name, dirHash }) {\n return { name, isDirectory: true, dirHash };\n}\n\n/**\n * Build CBOR-encoded OFD bytes from a list of entries.\n * Format matches the Dart example client (examples/off_client/lib/services/ofd.dart).\n * @param {OfdEntry[]} entries\n * @returns {Uint8Array}\n */\nexport function buildOfdCbor(entries) {\n const entryMaps = entries.map((entry) => {\n const map = {\n n: entry.name,\n t: entry.isDirectory ? 1 : 0\n };\n if (entry.isDirectory) {\n map.d = entry.dirHash;\n } else {\n map.f = entry.fileHash;\n map.D = entry.descriptorHash;\n map.s = entry.finalByte;\n map.B = entry.blockType;\n map.T = entry.tupleSize;\n map.o = entry.fileOffset;\n }\n return map;\n });\n\n return encode({ v: 1, entries: entryMaps });\n}\n\n/**\n * Parse CBOR-encoded OFD bytes into a list of entries.\n * @param {Uint8Array} data\n * @returns {OfdEntry[]}\n */\nexport function parseOfdCbor(data) {\n const decoded = decode(data);\n if (!decoded || typeof decoded !== 'object') return [];\n\n const entries = decoded.entries;\n if (!Array.isArray(entries)) return [];\n\n return entries.map((entry) => {\n const isDirectory = entry.t === 1;\n if (isDirectory) {\n return ofdDirectory({\n name: String(entry.n),\n dirHash: asUint8Array(entry.d)\n });\n }\n return ofdFile({\n name: String(entry.n),\n fileHash: asUint8Array(entry.f),\n descriptorHash: asUint8Array(entry.D),\n finalByte: safeInt(entry.s),\n blockType: safeInt(entry.B),\n tupleSize: safeInt(entry.T),\n fileOffset: safeInt(entry.o)\n });\n }).filter(Boolean);\n}\n\n/**\n * @param {any} value\n * @returns {number}\n */\nfunction safeInt(value) {\n if (typeof value === 'number') return value;\n if (typeof value === 'bigint') return Number(value);\n return 0;\n}\n\n/**\n * @param {any} value\n * @returns {Uint8Array}\n */\nfunction asUint8Array(value) {\n if (value instanceof Uint8Array) return value;\n if (Array.isArray(value)) return new Uint8Array(value);\n if (value instanceof ArrayBuffer) return new Uint8Array(value);\n if (value && typeof value === 'object' && ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n return new Uint8Array(0);\n}\n","import { HttpTransport } from './transports/http-transport.js';\nimport { WsTransport } from './transports/ws-transport.js';\nimport { WtTransport } from './transports/wt-transport.js';\nimport * as wire from './wire.js';\nimport {\n base58Decode,\n base58Encode,\n parseOffUrl,\n offUrlToHttpUrl,\n mimeFromExtension,\n fileToReadableStream,\n normalizeFolderEntries,\n basename\n} from './util.js';\nimport { buildOfdCbor, ofdFile, ofdDirectory } from './ofd.js';\n\n/**\n * @typedef {import('./types.js').OffsClientConfig} OffsClientConfig\n * @typedef {import('./types.js').OffsPutOptions} OffsPutOptions\n * @typedef {import('./types.js').OffsGetCallbacks} OffsGetCallbacks\n */\n\n/**\n * @typedef {Object} PendingRequest\n * @property {number} id\n * @property {number} type\n * @property {(value: any) => void} resolve\n * @property {(reason: any) => void} reject\n * @property {any} [ctx]\n */\n\n/**\n * Default configuration.\n * @returns {OffsClientConfig}\n */\nfunction defaultConfig() {\n return {\n connectTimeoutMs: 5000,\n requestTimeoutMs: 30000\n };\n}\n\n/**\n * Create a transport by URL scheme.\n * @param {string} url\n * @param {string} [apiKey]\n * @param {any} [options]\n * @returns {HttpTransport|WsTransport|WtTransport}\n */\nfunction createTransport(url, apiKey, options) {\n if (url.startsWith('ws://') || url.startsWith('wss://')) {\n return new WsTransport(url, apiKey, options);\n }\n if (url.startsWith('wt://') || url.startsWith('wts://')) {\n return new WtTransport(url, apiKey, options);\n }\n return new HttpTransport(url, apiKey, options);\n}\n\n/**\n * Browser-only OFFS client supporting HTTP, WebSocket, and WebTransport.\n */\nexport class OffsClient {\n /** @type {string} */\n url;\n /** @type {string|undefined} */\n apiKey;\n /** @type {OffsClientConfig} */\n config;\n /** @type {HttpTransport|WsTransport|WtTransport} */\n transport;\n /** @type {Map} */\n pending = new Map();\n /** @type {{type: number, bytes: Uint8Array}[]} */\n inboundQueue = [];\n /** @type {number} */\n nextRequestId = 1;\n /** @type {boolean} */\n streamingPut = false;\n /** @type {OffsPutOptions|null} */\n streamOptions = null;\n /** @type {boolean} */\n connected = false;\n\n /**\n * @param {string} url\n * @param {string} [apiKey]\n * @param {OffsClientConfig & {transport?: any}} [config]\n */\n constructor(url, apiKey, config) {\n this.url = url;\n this.apiKey = apiKey;\n this.config = { ...defaultConfig(), ...config };\n this.transport = config?.transport || createTransport(url, apiKey, config);\n this.transport.setMessageHandler(this._onMessage.bind(this));\n }\n\n /**\n * @returns {Promise}\n */\n async connect() {\n await this.transport.connect();\n this.connected = true;\n }\n\n disconnect() {\n this.transport.disconnect();\n this.connected = false;\n for (const pending of this.pending.values()) {\n pending.reject(new Error('Client disconnected'));\n }\n this.pending.clear();\n }\n\n isConnected() {\n return this.transport.isConnected();\n }\n\n /**\n * @param {number} id\n * @param {number} type\n * @param {number} [timeoutMs]\n * @returns {Promise}\n */\n _request(id, type, timeoutMs) {\n return new Promise((resolve, reject) => {\n const pending = {\n id,\n type,\n resolve,\n reject,\n timer: setTimeout(() => {\n this.pending.delete(id);\n reject(new Error('Request timeout'));\n }, timeoutMs || this.config.requestTimeoutMs)\n };\n this.pending.set(id, pending);\n });\n }\n\n /**\n * @param {number|number[]} type\n * @param {number} [timeoutMs]\n * @returns {Promise}\n */\n _waitForResponse(type, timeoutMs) {\n const id = this.nextRequestId++;\n const promise = this._request(id, type, timeoutMs);\n const queued = this._dequeueMatching(type);\n if (queued !== null) {\n this._resolve(id, queued);\n }\n return promise;\n }\n\n /**\n * @param {number} id\n * @param {any} value\n */\n _resolve(id, value) {\n const pending = this.pending.get(id);\n if (!pending) return;\n if (pending.timer) clearTimeout(pending.timer);\n this.pending.delete(id);\n pending.resolve(value);\n }\n\n /**\n * @param {number} id\n * @param {any} reason\n */\n _reject(id, reason) {\n const pending = this.pending.get(id);\n if (!pending) return;\n if (pending.timer) clearTimeout(pending.timer);\n this.pending.delete(id);\n pending.reject(reason);\n }\n\n /**\n * @param {number} type\n * @param {Uint8Array} bytes\n */\n _onMessage(type, bytes) {\n if (type === wire.MSG.ERROR) {\n const error = wire.decodeError(bytes);\n if (error) {\n for (const pending of this.pending.values()) {\n this._reject(pending.id, new Error(`Server error ${error.statusCode}: ${error.message}`));\n }\n }\n return;\n }\n\n for (const pending of this.pending.values()) {\n const matches = Array.isArray(pending.type)\n ? pending.type.includes(type)\n : pending.type === type;\n if (matches) {\n this._resolve(pending.id, bytes);\n return;\n }\n }\n this.inboundQueue.push({ type, bytes });\n }\n\n /**\n * @param {number|number[]} type\n * @returns {Uint8Array|null}\n */\n _dequeueMatching(type) {\n const types = Array.isArray(type) ? type : [type];\n const index = this.inboundQueue.findIndex((item) => types.includes(item.type));\n if (index === -1) return null;\n const item = this.inboundQueue[index];\n this.inboundQueue.splice(index, 1);\n return item.bytes;\n }\n\n /**\n * Send a CBOR message and wait for a matching response type.\n * @param {Uint8Array} bytes\n * @param {number} responseType\n * @param {number} [timeoutMs]\n * @returns {Promise}\n */\n async _sendAndWait(bytes, responseType, timeoutMs) {\n const id = this.nextRequestId++;\n const promise = this._request(id, responseType, timeoutMs);\n await this.transport.send(bytes);\n return promise;\n }\n\n /**\n * @param {string|OffsPutOptions} options\n * @param {Uint8Array|undefined} data\n * @returns {Promise<{oriString: string}>}\n */\n async put(options, data) {\n if (typeof options === 'string') {\n throw new Error('Use object options (contentType, fileName, streamLength)');\n }\n\n const safeOptions = {\n ...options,\n fileName: basename(options.fileName)\n };\n\n if (this.transport instanceof HttpTransport) {\n const body = data || new Uint8Array(0);\n return this.transport.put(safeOptions, body);\n }\n\n const requestBytes = wire.encodePutRequest(safeOptions, data);\n\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PUT_RESPONSE);\n return wire.decodePutResponse(responseBytes);\n }\n\n /**\n * @param {OffsPutOptions} options\n * @returns {Promise}\n */\n async putStreamStart(options) {\n this.streamingPut = true;\n this.streamOptions = options;\n\n if (this.transport instanceof HttpTransport) {\n return;\n }\n\n const requestBytes = wire.encodePutRequest(options);\n await this.transport.send(requestBytes);\n }\n\n /**\n * @param {Uint8Array} chunk\n * @returns {Promise}\n */\n async putStreamData(chunk) {\n if (this.transport instanceof HttpTransport) {\n throw new Error('HTTP transport does not support putStreamData; use put with ReadableStream');\n }\n await this.transport.send(wire.encodePutData(chunk));\n }\n\n /**\n * @returns {Promise<{oriString: string}>}\n */\n async putStreamEnd() {\n this.streamingPut = false;\n const options = this.streamOptions;\n this.streamOptions = null;\n\n if (this.transport instanceof HttpTransport) {\n if (!options) throw new Error('No stream in progress');\n return this.transport.put(options, new Uint8Array(0));\n }\n\n await this.transport.send(wire.encodePutEnd());\n const responseBytes = await this._request(this.nextRequestId - 1, wire.MSG.PUT_RESPONSE);\n return wire.decodePutResponse(responseBytes);\n }\n\n /**\n * @param {string} oriString\n * @param {OffsGetCallbacks} callbacks\n * @param {{start?: number, end?: number}} [range]\n */\n async get(oriString, callbacks, range) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.get(oriString, callbacks);\n }\n\n const requestBytes = wire.encodeGetRequest(oriString, range);\n\n const startBytes = await this._sendAndWait(requestBytes, wire.MSG.GET_RESPONSE_START);\n const start = wire.decodeGetResponseStart(startBytes);\n callbacks.onStart?.(start.contentType, start.contentLength, start.hasRange, start.rangeStart, start.rangeEnd);\n\n while (true) {\n const dataBytes = await this._waitForResponse([wire.MSG.GET_DATA, wire.MSG.GET_END]);\n if (wire.isGetEnd(dataBytes)) break;\n const chunk = wire.decodeGetData(dataBytes);\n callbacks.onData(chunk);\n }\n\n callbacks.onEnd?.();\n }\n\n /**\n * Load a file's blocks into the daemon's block cache without downloading\n * the file data. Progress is reported per resolved tuple; the operation\n * ends with a terminal status.\n *\n * HTTP transports stream an application/x-ndjson body whose progress lines\n * are {\"tuples_loaded\":n,\"tuples_total\":m} objects and whose terminal line\n * carries a status string (\"loaded\"|\"partial\"|\"failed\"). CBOR transports\n * use LOAD_PROGRESS/LOAD_END frames whose status is numeric\n * (0=loaded, 1=partial, 2=failed) — see wire.LOAD_STATUS.\n *\n * @param {string} oriString\n * @param {Object} [callbacks]\n * @param {(tuplesLoaded: number, tuplesTotal: number) => void} [callbacks.onProgress]\n * @param {(status: string|number, tuplesLoaded: number, tuplesTotal: number) => void} [callbacks.onEnd]\n * @param {(statusCode: number, message: string) => void} [callbacks.onError]\n * @param {{start?: number, end?: number}} [range]\n * @returns {Promise}\n */\n async load(oriString, callbacks = {}, range) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.load(oriString, callbacks, range);\n }\n\n const requestBytes = wire.encodeLoadRequest(oriString, range);\n await this.transport.send(requestBytes);\n\n let endBytes = null;\n while (true) {\n const bytes = await this._waitForResponse([wire.MSG.LOAD_PROGRESS, wire.MSG.LOAD_END]);\n if (wire.isLoadEnd(bytes)) {\n endBytes = bytes;\n break;\n }\n const progress = wire.decodeLoadProgress(bytes);\n callbacks.onProgress?.(progress.tuplesLoaded, progress.tuplesTotal);\n }\n\n const end = wire.decodeLoadEnd(endBytes);\n callbacks.onEnd?.(end.status, end.tuplesLoaded, end.tuplesTotal);\n }\n\n /**\n * @param {Uint8Array} data\n * @param {number} [encoding=0]\n * @returns {Promise<{status: number, hash: Uint8Array|string}>}\n */\n async blockPut(data, encoding = 0) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.blockPut(data, encoding);\n }\n\n const requestBytes = wire.encodeBlockPutRequest(data, encoding);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.BLOCK_PUT_RESPONSE);\n return wire.decodeBlockPutResponse(responseBytes);\n }\n\n /**\n * @param {string|Uint8Array} hash\n * @returns {Promise<{status: number, data: Uint8Array}>}\n */\n async blockGet(hash) {\n if (typeof hash === 'string') return this.transport.blockGet(hash);\n\n if (this.transport instanceof HttpTransport) {\n return this.transport.blockGet(base58Encode(hash));\n }\n\n const requestBytes = wire.encodeBlockGetRequest(hash);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.BLOCK_GET_RESPONSE);\n return wire.decodeBlockGetResponse(responseBytes);\n }\n\n /**\n * @param {string|Uint8Array} hash\n * @returns {Promise<{status: number}>}\n */\n async blockDelete(hash) {\n if (typeof hash === 'string') return this.transport.blockDelete(hash);\n\n if (this.transport instanceof HttpTransport) {\n return this.transport.blockDelete(base58Encode(hash));\n }\n\n const requestBytes = wire.encodeBlockDeleteRequest(hash);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.BLOCK_DELETE_RESPONSE);\n return wire.decodeBlockDeleteResponse(responseBytes);\n }\n\n /**\n * @returns {Promise}\n */\n async health() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.health();\n }\n\n const requestBytes = wire.encodeHealthRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.HEALTH_RESPONSE);\n const { json } = wire.decodeHealthResponse(responseBytes);\n return JSON.parse(json);\n }\n\n /**\n * @param {string} [format='cbor']\n * @returns {Promise<{format: number, data: Uint8Array}>}\n */\n async peerInfo(format = 'cbor') {\n if (this.transport instanceof HttpTransport) {\n return this.transport.peerInfo(format);\n }\n\n const requestBytes = wire.encodePeerInfoRequest(wire.PEER_FORMATS[format] ?? 0);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_INFO_RESPONSE);\n return wire.decodePeerInfoResponse(responseBytes);\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise<{status: number}>}\n */\n async peerConnect(peerInfo, format = 0) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.peerConnect(peerInfo, format);\n }\n\n const requestBytes = wire.encodePeerConnect(format, peerInfo);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_CONNECT_RESULT);\n return wire.decodePeerConnectResult(responseBytes);\n }\n\n /**\n * Connect to a peer from a QR image (binary P6 PPM bytes).\n * @param {Uint8Array} ppmBytes\n * @returns {Promise<{status: number}>}\n */\n async peerConnectQr(ppmBytes) {\n return this.peerConnect(ppmBytes, wire.PEER_FORMATS.qrcode);\n }\n\n /**\n * Add a friend from a QR image (binary P6 PPM bytes).\n * @param {Uint8Array} ppmBytes\n * @returns {Promise}\n */\n async friendAddQr(ppmBytes) {\n return this.friendAdd(ppmBytes, wire.PEER_FORMATS.qrcode);\n }\n\n /**\n * Convert an OFF URL/URI string into an HTTP URL usable by a browser.\n * @param {string} oriString\n * @param {string} [baseUrl]\n * @returns {string}\n */\n static offUrlToHttpUrl(oriString, baseUrl) {\n return offUrlToHttpUrl(oriString, baseUrl);\n }\n\n /**\n * @returns {Promise}\n */\n async peerList() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.peerList();\n }\n\n const requestBytes = wire.encodePeerListRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.PEER_LIST_RESPONSE);\n return wire.decodePeerListResponse(responseBytes);\n }\n\n /**\n * @param {Uint8Array} peerInfo\n * @param {number} [format=0]\n * @returns {Promise}\n */\n async friendAdd(peerInfo, format = 0) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.friendAdd(peerInfo, format);\n }\n\n const requestBytes = wire.encodeFriendAdd(format, peerInfo);\n await this.transport.send(requestBytes);\n }\n\n /**\n * @param {string|Uint8Array} nodeId\n * @returns {Promise}\n */\n async friendRemove(nodeId) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.friendRemove(typeof nodeId === 'string' ? nodeId : base58Encode(nodeId));\n }\n\n const idBytes = typeof nodeId === 'string' ? new TextEncoder().encode(nodeId) : nodeId;\n const requestBytes = wire.encodeFriendRemove(idBytes);\n await this.transport.send(requestBytes);\n }\n\n /**\n * @returns {Promise}\n */\n async friendList() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.friendList();\n }\n\n const requestBytes = wire.encodeFriendListRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.FRIEND_LIST_RESPONSE);\n return wire.decodeFriendListResponse(responseBytes);\n }\n\n /**\n * @returns {Promise}\n */\n async configShow() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.configShow();\n }\n\n const requestBytes = wire.encodeConfigShowRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.CONFIG_SHOW_RESPONSE);\n const { json } = wire.decodeConfigShowResponse(responseBytes);\n return JSON.parse(json);\n }\n\n /**\n * @param {string} field\n * @param {string} value\n * @returns {Promise<{status: number, restartRequired: boolean, message: string}>}\n */\n async configSet(field, value) {\n if (this.transport instanceof HttpTransport) {\n return this.transport.configSet(field, value);\n }\n\n const requestBytes = wire.encodeConfigSetRequest(field, value);\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.CONFIG_SET_RESPONSE);\n return wire.decodeConfigSetResponse(responseBytes);\n }\n\n /**\n * @returns {Promise<{status: number, message: string}>}\n */\n async configReload() {\n if (this.transport instanceof HttpTransport) {\n return this.transport.configReload();\n }\n\n const requestBytes = wire.encodeConfigReloadRequest();\n const responseBytes = await this._sendAndWait(requestBytes, wire.MSG.CONFIG_RELOAD_RESPONSE);\n return wire.decodeConfigReloadResponse(responseBytes);\n }\n\n /**\n * Upload a folder recursively and return the root directory's ORI URL.\n * Matches the algorithm used by the Flutter example client in\n * examples/off_client/lib/screens/import_screen.dart.\n *\n * @param {FileList|File[]|import('./util.js').FolderEntry[]|Record} items\n * @param {Object} [options]\n * @param {string[]} [options.recyclerUrls]\n * @param {string} [options.serverAddress]\n * @param {boolean} [options.temporary=false]\n * @param {(name: string, uploaded: number, total: number) => void} [options.onProgress]\n * @returns {Promise<{oriString: string}>}\n */\n async putFolder(items, options = {}) {\n const entries = normalizeFolderEntries(items);\n if (entries.length === 0) {\n throw new Error('No files to upload');\n }\n\n const recyclerUrls = options.recyclerUrls || [];\n const totalFiles = entries.length;\n let uploadedCount = 0;\n\n const updateProgress = (name) => {\n uploadedCount++;\n options.onProgress?.(name, uploadedCount, totalFiles);\n };\n\n const rootDir = _commonDirectory(entries.map((entry) => entry.path));\n\n /**\n * @param {string} dirPath\n * @returns {Promise<{oriString: string}>}\n */\n const uploadDirectory = async (dirPath) => {\n const dirName = basename(dirPath ? dirPath : rootDir || 'root');\n const childEntries = _children(entries, dirPath);\n const fileEntries = childEntries;\n const subdirs = _childDirectories(entries, dirPath);\n\n /** @type {import('./ofd.js').OfdEntry[]} */\n const ofdEntries = [];\n\n // Recursively upload subdirectories first.\n for (const subdir of subdirs) {\n const subResult = await uploadDirectory(subdir);\n const subUrl = subResult.oriString;\n const parsed = parseOffUrl(subUrl);\n if (!parsed) {\n throw new Error(`Failed to parse subdirectory URL: ${subUrl}`);\n }\n const dirHash = base58Decode(parsed.fileHashB58);\n if (!dirHash) {\n throw new Error(`Invalid directory hash in URL: ${subUrl}`);\n }\n ofdEntries.push(ofdDirectory({\n name: basename(subdir),\n dirHash\n }));\n }\n\n // Upload files in this directory.\n for (const fileEntry of fileEntries) {\n const fileName = basename(fileEntry.path);\n const contentType = mimeFromExtension(fileName);\n const streamLength = fileEntry.file.size;\n\n let url;\n if (this.transport instanceof HttpTransport) {\n const body = fileToReadableStream(fileEntry.file);\n const result = await this.put({\n contentType,\n fileName,\n streamLength,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n }, body);\n url = result.oriString;\n } else {\n await this.putStreamStart({\n contentType,\n fileName,\n streamLength,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n });\n\n const reader = fileToReadableStream(fileEntry.file).getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n await this.putStreamData(value);\n }\n\n const result = await this.putStreamEnd();\n url = result.oriString;\n }\n\n const parsed = parseOffUrl(url);\n if (!parsed) {\n throw new Error(`Failed to parse file URL: ${url}`);\n }\n const fileHash = base58Decode(parsed.fileHashB58);\n const descriptorHash = base58Decode(parsed.descriptorHashB58);\n if (!fileHash || !descriptorHash) {\n throw new Error(`Invalid hash in file URL: ${url}`);\n }\n\n ofdEntries.push(ofdFile({\n name: fileName,\n fileHash,\n descriptorHash,\n finalByte: parsed.streamLength\n }));\n\n updateProgress(fileName);\n }\n\n if (ofdEntries.length === 0) {\n throw new Error(`Empty directory: ${dirPath || rootDir}`);\n }\n\n const ofdBytes = buildOfdCbor(ofdEntries);\n const dirFileName = `${dirName}.ofd`;\n\n if (this.transport instanceof HttpTransport) {\n return this.put({\n contentType: 'offsystem/directory',\n fileName: dirFileName,\n streamLength: ofdBytes.length,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n }, ofdBytes);\n }\n\n await this.putStreamStart({\n contentType: 'offsystem/directory',\n fileName: dirFileName,\n streamLength: ofdBytes.length,\n serverAddress: options.serverAddress,\n recyclerUrls,\n temporary: options.temporary\n });\n await this.putStreamData(ofdBytes);\n return this.putStreamEnd();\n };\n\n return uploadDirectory(rootDir);\n }\n}\n\n/**\n * Find the common root directory for a set of file paths.\n * @param {string[]} paths\n * @returns {string}\n */\nfunction _commonDirectory(paths) {\n if (paths.length === 0) return '';\n const segments = paths.map((path) => path.split('/').filter(Boolean));\n const first = segments[0];\n let commonLength = first.length;\n for (let index = 1; index < segments.length; index++) {\n const other = segments[index];\n let match = 0;\n while (match < Math.min(commonLength, other.length) && first[match] === other[match]) {\n match++;\n }\n commonLength = match;\n if (commonLength === 0) break;\n }\n // The common prefix must end at a directory boundary, not inside a filename.\n const prefixLength = Math.min(commonLength, first.length - 1);\n return first.slice(0, prefixLength).join('/');\n}\n\n/**\n * Get direct child files of a directory path.\n * @param {import('./util.js').FolderEntry[]} entries\n * @param {string} dirPath\n * @returns {import('./util.js').FolderEntry[]}\n */\nfunction _children(entries, dirPath) {\n const prefix = dirPath ? `${dirPath}/` : '';\n return entries.filter((entry) => {\n if (!entry.path.startsWith(prefix)) return false;\n const rest = entry.path.slice(prefix.length);\n return rest.length > 0 && !rest.includes('/');\n });\n}\n\n/**\n * Get direct child directory paths of a directory path.\n * @param {import('./util.js').FolderEntry[]} entries\n * @param {string} dirPath\n * @returns {string[]}\n */\nfunction _childDirectories(entries, dirPath) {\n const prefix = dirPath ? `${dirPath}/` : '';\n const seen = new Set();\n for (const entry of entries) {\n if (!entry.path.startsWith(prefix)) continue;\n const rest = entry.path.slice(prefix.length);\n if (!rest) continue;\n const slashIndex = rest.indexOf('/');\n if (slashIndex > 0) {\n seen.add(prefix + rest.slice(0, slashIndex));\n }\n }\n return Array.from(seen);\n}\n\nexport { wire, base58Decode, base58Encode, parseOffUrl, offUrlToHttpUrl, mimeFromExtension };\n"],"names":["decoder","src","srcEnd","position","LEGACY_RECORD_INLINE_ID","RECORD_DEFINITIONS_ID","RECORD_INLINE_ID","BUNDLED_STRINGS_ID","PACKED_REFERENCE_TAG_ID","STOP_CODE","maxArraySize","maxMapSize","currentDecoder","currentStructures","srcString","srcStringStart","srcStringEnd","bundledStrings","referenceMap","currentExtensions","currentExtensionRanges","packedValues","dataView","restoreMapsAsObject","defaultOptions","sequentialMode","inlineObjectReadThreshold","Decoder","options","k","v","key","rec","map","res","safeKey","source","end","r","saveState","clearSource","error","checkedRead","forEach","values","lastPosition","size","value","defaultDecoder","result","read","token","majorType","getFloat16","multiplier","mult10","array","i","object","readBin","string","shortStringInJS","longStringInJS","readFixedString","structure","createStructureReader","length","readJustLength","id","recordDefinition","readBundleExt","loadShared","extension","input","Tag","packedValue","getPackedValues","validName","readObject","compiledReader","readStringJS","units","byte1","byte2","byte3","byte4","unit","fromCharCode","start","bytes","byte","a","b","c","d","e","f","g","h","j","l","m","n","o","f32Array","u8Array","byte0","exponent","abs","tag","dateString","epochSec","buffer","fraction","existingStructure","data","glbl","packedTable","newPackedValues","startingPosition","target","refEntry","targetProperties","combine","SHARED_DATA_TAG_ID","isLittleEndianMachine","typedArrays","typedArrayTags","registerTypedArray","TypedArray","dvMethod","bytesPerElement","littleEndian","sizeShift","dv","elements","ta","method","bundlePosition","bundleLength","dataPosition","sharedData","updatedStructures","callback","savedSrcEnd","savedPosition","savedSrcStringStart","savedSrcStringEnd","savedSrcString","savedReferenceMap","savedBundledStrings","savedSrc","savedStructures","savedDecoder","savedSequentialMode","decode","textEncoder","extensions","extensionClasses","Buffer","hasNodeBuffer","ByteArrayAllocate","ByteArray","MAX_STRUCTURES","MAX_BUFFER_SIZE","throwOnIterable","targetView","safeEnd","MAX_BUNDLE_SIZE","hasNonLatin","RECORD_SYMBOL","Encoder","sharedStructures","hasSharedUpdate","structures","encodeUtf8","encoder","hasSharedStructures","maxSharedStructures","isSequential","samplingPackedValues","packedObjectMap","sharedValues","sharedPackedObjectMap","recordIdsToRemove","transitionsCount","serializationsSinceTransitionRebuild","encodeOptions","REUSE_BUFFER_MODE","sharedStructuresLength","keys","nextTransition","transition","findRepetitiveStrings","writeArrayHeader","valuesArray","encode","THROW_ON_ITERABLE","writeBundles","makeRoom","serialized","insertIds","returnBuffer","RESET_BUFFER_MODE","threshold","status","type","packedPosition","strLength","extStart","maxBytes","twoByte","headerSize","c1","c2","strPosition","useFloat32","xShifted","referee","idsToInsert","constructor","x","writeObject","entryValue","extensionClass","entry","isBlob","json","writeBuffer","vals","objectOffset","skipValues","newTransitions","parentRecordId","recordId","newSize","newBuffer","chunkThreshold","continuedChunkThreshold","startEncoding","encodeObjectAsIterable","encodeObjectAsAsyncIterable","iterateProperties","finalIterable","useRecords","writeEntityLength","tryEncode","restartEncoding","restart","encodeIterable","encodedValue","reader","next","asyncValue","lastVersion","structuresCopy","SharedData","saveResults","existingShared","majorValue","version","BlobConstructor","packedStatus","includeKeys","date","seconds","set","regex","arrayBuffer","typedArray","typedArrayEncoder","definitions","offset","nextId","distanceToMove","lastEnd","writeStrings","defaultEncoder","MSG","LOAD_STATUS","PEER_FORMATS","PEER_CONTENT_TYPES","STATUS","getMessageType","arr","encodeAuthRequest","apiKey","keyBytes","encodePutRequest","recycler","payload","encodePutData","chunk","encodePutEnd","decodePutResponse","encodeGetRequest","oriString","range","hasRange","decodeGetResponseStart","decodeGetData","isGetEnd","encodeLoadRequest","decodeLoadProgress","isLoadEnd","decodeLoadEnd","decodeError","encodeBlockPutRequest","encoding","decodeBlockPutResponse","encodeBlockGetRequest","hash","decodeBlockGetResponse","encodeBlockDeleteRequest","decodeBlockDeleteResponse","encodeHealthRequest","decodeHealthResponse","encodePeerInfoRequest","format","decodePeerInfoResponse","encodePeerConnect","decodePeerConnectResult","encodePeerListRequest","decodePeerListResponse","encodeFriendAdd","encodeFriendRemove","nodeId","encodeFriendListRequest","decodeFriendListResponse","encodeConfigShowRequest","decodeConfigShowResponse","encodeConfigSetRequest","field","decodeConfigSetResponse","encodeConfigReloadRequest","decodeConfigReloadResponse","HttpTransport","url","_options","__publicField","path","headers","_handler","_bytes","body","_a","_b","requestBody","response","text","stream","chunks","totalLength","done","offUrl","callbacks","_c","_d","_e","_f","_g","contentType","contentLength","rangeHeader","rangeStart","rangeEnd","match","err","separator","newlineIndex","line","message","query","base58Hash","fmt","peerInfo","WsTransport","resolve","reject","socket","event","handler","WtTransport","pending","_concat","msgLen","msgBytes","ALPHABET","INDICES","index","base58Decode","leadingZeros","codeUnit","digit","carry","byteIndex","base58Encode","resultCodes","resultIndex","code","parseOffUrl","prefixIndex","allParts","streamLengthStr","fileHashB58","descriptorHashB58","fileName","streamLength","mimeFromExtension","filename","dotIndex","readFileBytes","file","basename","parts","fileToReadableStream","chunkSize","controller","slice","normalizeFolderEntries","items","entries","item","offUrlToHttpUrl","baseUrl","prefix","DEFAULT_BLOCK_TYPE","DEFAULT_TUPLE_SIZE","ofdFile","name","fileHash","descriptorHash","finalByte","blockType","tupleSize","fileOffset","ofdDirectory","dirHash","buildOfdCbor","entryMaps","defaultConfig","createTransport","OffsClient","config","timeoutMs","promise","queued","reason","wire.MSG","wire.decodeError","types","responseType","safeOptions","requestBytes","wire.encodePutRequest","responseBytes","wire.decodePutResponse","wire.encodePutData","wire.encodePutEnd","wire.encodeGetRequest","startBytes","wire.decodeGetResponseStart","dataBytes","wire.isGetEnd","wire.decodeGetData","wire.encodeLoadRequest","endBytes","wire.isLoadEnd","progress","wire.decodeLoadProgress","wire.decodeLoadEnd","wire.encodeBlockPutRequest","wire.decodeBlockPutResponse","wire.encodeBlockGetRequest","wire.decodeBlockGetResponse","wire.encodeBlockDeleteRequest","wire.decodeBlockDeleteResponse","wire.encodeHealthRequest","wire.decodeHealthResponse","wire.encodePeerInfoRequest","wire.PEER_FORMATS","wire.decodePeerInfoResponse","wire.encodePeerConnect","wire.decodePeerConnectResult","ppmBytes","wire.encodePeerListRequest","wire.decodePeerListResponse","wire.encodeFriendAdd","idBytes","wire.encodeFriendRemove","wire.encodeFriendListRequest","wire.decodeFriendListResponse","wire.encodeConfigShowRequest","wire.decodeConfigShowResponse","wire.encodeConfigSetRequest","wire.decodeConfigSetResponse","wire.encodeConfigReloadRequest","wire.decodeConfigReloadResponse","recyclerUrls","totalFiles","uploadedCount","updateProgress","rootDir","_commonDirectory","uploadDirectory","dirPath","dirName","fileEntries","_children","subdirs","_childDirectories","ofdEntries","subdir","subUrl","parsed","fileEntry","ofdBytes","dirFileName","paths","segments","first","commonLength","other","prefixLength","rest","seen","slashIndex"],"mappings":"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","x_google_ignoreList":[0,1]}
\ No newline at end of file
diff --git a/src/ClientLibs/js/offs-client/dist/offs-client.umd.js b/src/ClientLibs/js/offs-client/dist/offs-client.umd.js
index a0cc2a1f..aeb6f069 100644
--- a/src/ClientLibs/js/offs-client/dist/offs-client.umd.js
+++ b/src/ClientLibs/js/offs-client/dist/offs-client.umd.js
@@ -1,2 +1,3 @@
-(function(j,P){typeof exports=="object"&&typeof module<"u"?P(exports):typeof define=="function"&&define.amd?define(["exports"],P):(j=typeof globalThis<"u"?globalThis:j||self,P(j.OffsClient={}))})(this,function(j){"use strict";var Kr=Object.defineProperty;var Gr=(j,P,ae)=>P in j?Kr(j,P,{enumerable:!0,configurable:!0,writable:!0,value:ae}):j[P]=ae;var C=(j,P,ae)=>Gr(j,typeof P!="symbol"?P+"":P,ae);class P{constructor(e,r,n){C(this,"baseUrl");C(this,"apiKey");C(this,"abortController",null);this.baseUrl=e.replace(/\/$/,""),this.apiKey=r}async connect(){this.abortController=new AbortController}disconnect(){this.abortController&&(this.abortController.abort(),this.abortController=null)}isConnected(){return this.abortController!==null}url(e){return`${this.baseUrl}${e}`}authHeaders(){const e={};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}setMessageHandler(e){}send(e){throw new Error("HttpTransport does not support raw send; use OffsClient methods")}async put(e,r){var p,y;const n={...this.authHeaders(),type:e.contentType,"file-name":e.fileName,"stream-length":String(e.streamLength)};e.serverAddress&&(n["server-address"]=e.serverAddress),(p=e.recyclerUrls)!=null&&p.length&&(n.recycler=JSON.stringify(e.recyclerUrls)),e.temporary&&(n.temporary="true"),e.tupleSize!==void 0&&(n["tuple-size"]=String(e.tupleSize));let s=r;r&&typeof r.getReader=="function"&&(s=await this._readStream(r));const o=await fetch(this.url("/offsystem"),{method:"PUT",headers:n,body:s,signal:(y=this.abortController)==null?void 0:y.signal});if(!o.ok){const _=await o.text();throw new Error(`Upload failed: ${o.status} ${_}`)}return{oriString:await o.text()}}async _readStream(e){const r=e.getReader(),n=[];let s=0;for(;;){const{done:p,value:y}=await r.read();if(p)break;n.push(y),s+=y.length}const o=new Uint8Array(s);let l=0;for(const p of n)o.set(p,l),l+=p.length;return o}async get(e,r){var N,H,$,z,k,v,se;const n=await fetch(e,{method:"GET",headers:this.authHeaders(),signal:(N=this.abortController)==null?void 0:N.signal});if(!n.ok){const D=await n.text();(H=r.onError)==null||H.call(r,n.status,D);return}const s=n.headers.get("content-type")||"application/octet-stream",o=parseInt(n.headers.get("content-length")||"0",10),l=n.status===206,p=n.headers.get("content-range");let y,_;if(p){const D=p.match(/bytes (\d+)-(\d+)\//);D&&(y=parseInt(D[1],10),_=parseInt(D[2],10))}($=r.onStart)==null||$.call(r,s,o,l,y,_);const x=(z=n.body)==null?void 0:z.getReader();if(!x){(k=r.onEnd)==null||k.call(r);return}try{for(;;){const{done:D,value:S}=await x.read();if(D)break;S&&r.onData(S)}(v=r.onEnd)==null||v.call(r)}catch(D){(se=r.onError)==null||se.call(r,0,String(D))}}async delete(e){var n;const r=await fetch(e,{method:"DELETE",headers:this.authHeaders(),signal:(n=this.abortController)==null?void 0:n.signal});if(!r.ok){const s=await r.text();throw new Error(`Delete failed: ${r.status} ${s}`)}}async blockPut(e,r=0){var l;const n=r===1?"?encoding=base58":"",s=await fetch(this.url(`/blocks${n}`),{method:"PUT",headers:{...this.authHeaders(),"Content-Type":"application/octet-stream"},body:e,signal:(l=this.abortController)==null?void 0:l.signal});if(!s.ok){const p=await s.text();throw new Error(`Block put failed: ${s.status} ${p}`)}const o=await s.arrayBuffer();return{status:0,hash:new Uint8Array(o)}}async blockGet(e){var s;const r=await fetch(this.url(`/blocks/${e}`),{method:"GET",headers:this.authHeaders(),signal:(s=this.abortController)==null?void 0:s.signal});if(!r.ok)return{status:2,data:new Uint8Array(0)};const n=await r.arrayBuffer();return{status:0,data:new Uint8Array(n)}}async blockDelete(e){var n;return{status:(await fetch(this.url(`/blocks/${e}`),{method:"DELETE",headers:this.authHeaders(),signal:(n=this.abortController)==null?void 0:n.signal})).ok?0:2}}async health(){var r;const e=await fetch(this.url("/health"),{method:"GET",headers:this.authHeaders(),signal:(r=this.abortController)==null?void 0:r.signal});if(!e.ok)throw new Error(`Health check failed: ${e.status}`);return e.json()}async peerInfo(e="cbor"){var o;const r=e==="base58"?1:0,n=await fetch(this.url(`/peer/info?format=${e}`),{method:"GET",headers:this.authHeaders(),signal:(o=this.abortController)==null?void 0:o.signal});if(!n.ok)throw new Error(`Peer info failed: ${n.status}`);const s=await n.arrayBuffer();return{format:r,data:new Uint8Array(s)}}async peerConnect(e,r=0){var s;const n=await fetch(this.url("/peer/connect"),{method:"POST",headers:{...this.authHeaders(),"Content-Type":r===1?"text/plain":"application/cbor"},body:r===1?new TextDecoder().decode(e):e,signal:(s=this.abortController)==null?void 0:s.signal});if(!n.ok)throw new Error(`Peer connect failed: ${n.status}`);return{status:0}}async peerList(){var r;const e=await fetch(this.url("/peers"),{method:"GET",headers:this.authHeaders(),signal:(r=this.abortController)==null?void 0:r.signal});if(!e.ok)throw new Error(`Peer list failed: ${e.status}`);return e.json()}async friendAdd(e,r=0){var s;const n=await fetch(this.url("/friends"),{method:"POST",headers:{...this.authHeaders(),"Content-Type":r===1?"text/plain":"application/cbor"},body:r===1?new TextDecoder().decode(e):e,signal:(s=this.abortController)==null?void 0:s.signal});if(!n.ok)throw new Error(`Friend add failed: ${n.status}`)}async friendRemove(e){var n;const r=await fetch(this.url(`/friends/${e}`),{method:"DELETE",headers:this.authHeaders(),signal:(n=this.abortController)==null?void 0:n.signal});if(!r.ok)throw new Error(`Friend remove failed: ${r.status}`)}async friendList(){var r;const e=await fetch(this.url("/friends"),{method:"GET",headers:this.authHeaders(),signal:(r=this.abortController)==null?void 0:r.signal});if(!e.ok)throw new Error(`Friend list failed: ${e.status}`);return e.json()}async configShow(){var r;const e=await fetch(this.url("/config"),{method:"GET",headers:this.authHeaders(),signal:(r=this.abortController)==null?void 0:r.signal});if(!e.ok)throw new Error(`Config show failed: ${e.status}`);return e.json()}async configSet(e,r){var s;const n=await fetch(this.url("/config"),{method:"PUT",headers:{...this.authHeaders(),"Content-Type":"application/json"},body:JSON.stringify({[e]:r}),signal:(s=this.abortController)==null?void 0:s.signal});if(!n.ok)throw new Error(`Config set failed: ${n.status}`);return n.json()}async configReload(){var r;const e=await fetch(this.url("/config/restart"),{method:"POST",headers:this.authHeaders(),signal:(r=this.abortController)==null?void 0:r.signal});if(!e.ok)throw new Error(`Config reload failed: ${e.status}`)}}let ae;try{ae=new TextDecoder}catch{}let w,le,c=0;const nr=105,sr=57342,ir=57343,nt=57337,st=6,he={};let ge=11281e4,ne=1681e4,T={},I,Re,Oe=0,xe=0,L,Z,F=[],De=[],Q,W,me,it={useRecords:!1,mapsAsObjects:!0},Se=!1,ot=2;try{new Function("")}catch{ot=1/0}class be{constructor(e){if(e&&((e.keyMap||e._keyMap)&&!e.useRecords&&(e.useRecords=!1,e.mapsAsObjects=!0),e.useRecords===!1&&e.mapsAsObjects===void 0&&(e.mapsAsObjects=!0),e.getStructures&&(e.getShared=e.getStructures),e.getShared&&!e.structures&&((e.structures=[]).uninitialized=!0),e.keyMap)){this.mapKey=new Map;for(let[r,n]of Object.entries(e.keyMap))this.mapKey.set(n,r)}Object.assign(this,e)}decodeKey(e){return this.keyMap&&this.mapKey.get(e)||e}encodeKey(e){return this.keyMap&&this.keyMap.hasOwnProperty(e)?this.keyMap[e]:e}encodeKeys(e){if(!this._keyMap)return e;let r=new Map;for(let[n,s]of Object.entries(e))r.set(this._keyMap.hasOwnProperty(n)?this._keyMap[n]:n,s);return r}decodeKeys(e){if(!this._keyMap||e.constructor.name!="Map")return e;if(!this._mapKey){this._mapKey=new Map;for(let[n,s]of Object.entries(this._keyMap))this._mapKey.set(s,n)}let r={};return e.forEach((n,s)=>r[Y(this._mapKey.has(s)?this._mapKey.get(s):s)]=n),r}mapDecode(e,r){let n=this.decode(e);if(this._keyMap)switch(n.constructor.name){case"Array":return n.map(s=>this.decodeKeys(s))}return n}decode(e,r){if(w)return dt(()=>(je(),this?this.decode(e,r):be.prototype.decode.call(it,e,r)));le=r>-1?r:e.length,c=0,xe=0,Re=null,L=null,w=e;try{W=e.dataView||(e.dataView=new DataView(e.buffer,e.byteOffset,e.byteLength))}catch(n){throw w=null,e instanceof Uint8Array?n:new Error("Source must be a Uint8Array or Buffer but was a "+(e&&typeof e=="object"?e.constructor.name:typeof e))}if(this instanceof be){if(T=this,Q=this.sharedValues&&(this.pack?new Array(this.maxPrivatePackedValues||16).concat(this.sharedValues):this.sharedValues),this.structures)return I=this.structures,Te();(!I||I.length>0)&&(I=[])}else T=it,(!I||I.length>0)&&(I=[]),Q=null;return Te()}decodeMultiple(e,r){let n,s=0;try{let o=e.length;Se=!0;let l=this?this.decode(e,o):Ge.decode(e,o);if(r){if(r(l)===!1)return;for(;c=L.postBundlePosition){let e=new Error("Unexpected bundle position");throw e.incomplete=!0,e}c=L.postBundlePosition,L=null}if(c==le)I=null,w=null,Z&&(Z=null);else if(c>le){let e=new Error("Unexpected end of CBOR data");throw e.incomplete=!0,e}else if(!Se)throw new Error("Data read, but end of buffer not reached");return t}catch(t){throw je(),(t instanceof RangeError||t.message.startsWith("Unexpected end of buffer"))&&(t.incomplete=!0),t}}function A(){let t=w[c++],e=t>>5;if(t=t&31,t>23)switch(t){case 24:t=w[c++];break;case 25:if(e==7)return lr();t=W.getUint16(c),c+=2;break;case 26:if(e==7){let r=W.getFloat32(c);if(T.useFloat32>2){let n=Ke[(w[c]&127)<<1|w[c+1]>>7];return c+=4,(n*r+(r>0?.5:-.5)>>0)/n}return c+=4,r}if(t=W.getUint32(c),c+=4,e===1)return-1-t;break;case 27:if(e==7){let r=W.getFloat64(c);return c+=8,r}if(e>1){if(W.getUint32(c)>0)throw new Error("JavaScript does not support arrays, maps, or strings with length over 4294967295");t=W.getUint32(c+4)}else T.int64AsNumber?(t=W.getUint32(c)*4294967296,t+=W.getUint32(c+4)):t=W.getBigUint64(c);c+=8;break;case 31:switch(e){case 2:case 3:throw new Error("Indefinite length not supported for byte or text strings");case 4:let r=[],n,s=0;for(;(n=A())!=he;){if(s>=ge)throw new Error(`Array length exceeds ${ge}`);r[s++]=n}return e==4?r:e==3?r.join(""):Buffer.concat(r);case 5:let o;if(T.mapsAsObjects){let l={},p=0;if(T.keyMap)for(;(o=A())!=he;){if(p++>=ne)throw new Error(`Property count exceeds ${ne}`);l[Y(T.decodeKey(o))]=A()}else for(;(o=A())!=he;){if(p++>=ne)throw new Error(`Property count exceeds ${ne}`);l[Y(o)]=A()}return l}else{me&&(T.mapsAsObjects=!0,me=!1);let l=new Map;if(T.keyMap){let p=0;for(;(o=A())!=he;){if(p++>=ne)throw new Error(`Map size exceeds ${ne}`);l.set(T.decodeKey(o),A())}}else{let p=0;for(;(o=A())!=he;){if(p++>=ne)throw new Error(`Map size exceeds ${ne}`);l.set(o,A())}}return l}case 7:return he;default:throw new Error("Invalid major type for indefinite length "+e)}default:throw new Error("Unknown token "+t)}switch(e){case 0:return t;case 1:return~t;case 2:return fr(t);case 3:if(xe>=c)return Re.slice(c-Oe,(c+=t)-Oe);if(xe==0&&le<140&&t<32){let s=t<16?ft(t):ar(t);if(s!=null)return s}return or(t);case 4:if(t>=ge)throw new Error(`Array length exceeds ${ge}`);let r=new Array(t);for(let s=0;s=ne)throw new Error(`Map size exceeds ${ge}`);if(T.mapsAsObjects){let s={};if(T.keyMap)for(let o=0;o=nt){let s=I[t&8191];if(s)return s.read||(s.read=Fe(s)),s.read();if(t<65536){if(t==ir){let o=ye(),l=A(),p=A();Me(l,p);let y={};if(T.keyMap)for(let _=2;_23)switch(r){case 24:r=w[c++];break;case 25:r=W.getUint16(c),c+=2;break;case 26:r=W.getUint32(c),c+=4;break;default:throw new Error("Expected array header, but got "+w[c-1])}let n=this.compiledReader;for(;n;){if(n.propertyCount===r)return n(A);n=n.next}if(this.slowReads++>=ot){let o=this.length==r?this:this.slice(0,r);return n=T.keyMap?new Function("r","return {"+o.map(l=>T.decodeKey(l)).map(l=>at.test(l)?Y(l)+":r()":"["+JSON.stringify(l)+"]:r()").join(",")+"}"):new Function("r","return {"+o.map(l=>at.test(l)?Y(l)+":r()":"["+JSON.stringify(l)+"]:r()").join(",")+"}"),this.compiledReader&&(n.next=this.compiledReader),n.propertyCount=r,this.compiledReader=n,n(A)}let s={};if(T.keyMap)for(let o=0;o64&&ae)return ae.decode(w.subarray(c,c+=t));const r=c+t,n=[];for(e="";c=r||(w[c]&192)!==128)n.push(65533);else{const o=w[c++]&63;n.push((s&31)<<6|o)}else if((s&240)===224){const o=c=r||(o&192)!==128||s===224&&o<160||s===237&&o>=160)n.push(65533);else if(c++,c>=r||(w[c]&192)!==128)n.push(65533);else{const l=w[c++]&63;n.push((s&31)<<12|(o&63)<<6|l)}}else if((s&248)===240){const o=c244||c>=r||(o&192)!==128||s===240&&o<144||s===244&&o>=144)n.push(65533);else if(c++,c>=r||(w[c]&192)!==128)n.push(65533);else{const l=w[c++]&63;if(c>=r||(w[c]&192)!==128)n.push(65533);else{const p=w[c++]&63;let y=(s&7)<<18|(o&63)<<12|l<<6|p;y-=65536,n.push(y>>>10&1023|55296),n.push(56320|y&1023)}}}else n.push(65533);n.length>=4096&&(e+=K.apply(String,n),n.length=0)}return n.length>0&&(e+=K.apply(String,n)),e}let K=String.fromCharCode;function ar(t){let e=c,r=new Array(t);for(let n=0;n0){c=e;return}r[n]=s}return K.apply(String,r)}function ft(t){if(t<4)if(t<2){if(t===0)return"";{let e=w[c++];if((e&128)>1){c-=1;return}return K(e)}}else{let e=w[c++],r=w[c++];if((e&128)>0||(r&128)>0){c-=2;return}if(t<3)return K(e,r);let n=w[c++];if((n&128)>0){c-=3;return}return K(e,r,n)}else{let e=w[c++],r=w[c++],n=w[c++],s=w[c++];if((e&128)>0||(r&128)>0||(n&128)>0||(s&128)>0){c-=4;return}if(t<6){if(t===4)return K(e,r,n,s);{let o=w[c++];if((o&128)>0){c-=5;return}return K(e,r,n,s,o)}}else if(t<8){let o=w[c++],l=w[c++];if((o&128)>0||(l&128)>0){c-=6;return}if(t<7)return K(e,r,n,s,o,l);let p=w[c++];if((p&128)>0){c-=7;return}return K(e,r,n,s,o,l,p)}else{let o=w[c++],l=w[c++],p=w[c++],y=w[c++];if((o&128)>0||(l&128)>0||(p&128)>0||(y&128)>0){c-=8;return}if(t<10){if(t===8)return K(e,r,n,s,o,l,p,y);{let _=w[c++];if((_&128)>0){c-=9;return}return K(e,r,n,s,o,l,p,y,_)}}else if(t<12){let _=w[c++],x=w[c++];if((_&128)>0||(x&128)>0){c-=10;return}if(t<11)return K(e,r,n,s,o,l,p,y,_,x);let N=w[c++];if((N&128)>0){c-=11;return}return K(e,r,n,s,o,l,p,y,_,x,N)}else{let _=w[c++],x=w[c++],N=w[c++],H=w[c++];if((_&128)>0||(x&128)>0||(N&128)>0||(H&128)>0){c-=12;return}if(t<14){if(t===12)return K(e,r,n,s,o,l,p,y,_,x,N,H);{let $=w[c++];if(($&128)>0){c-=13;return}return K(e,r,n,s,o,l,p,y,_,x,N,H,$)}}else{let $=w[c++],z=w[c++];if(($&128)>0||(z&128)>0){c-=14;return}if(t<15)return K(e,r,n,s,o,l,p,y,_,x,N,H,$,z);let k=w[c++];if((k&128)>0){c-=15;return}return K(e,r,n,s,o,l,p,y,_,x,N,H,$,z,k)}}}}}function fr(t){return T.copyBuffers?Uint8Array.prototype.slice.call(w,c,c+=t):w.subarray(c,c+=t)}let lt=new Float32Array(1),Ae=new Uint8Array(lt.buffer,0,4);function lr(){let t=w[c++],e=w[c++],r=(t&127)>>2;if(r===31)return e||t&3?NaN:t&128?-1/0:1/0;if(r===0){let n=((t&3)<<8|e)/16777216;return t&128?-n:n}return Ae[3]=t&128|(r>>1)+56,Ae[2]=(t&7)<<5|e>>3,Ae[1]=e<<5,Ae[0]=0,lt[0]}new Array(4096);class ce{constructor(e,r){this.value=e,this.tag=r}}F[0]=t=>new Date(t),F[1]=t=>new Date(Math.round(t*1e3)),F[2]=t=>{let e=BigInt(0);for(let r=0,n=t.byteLength;rBigInt(-1)-F[2](t),F[4]=t=>+(t[1]+"e"+t[0]),F[5]=t=>t[1]*Math.exp(t[0]*Math.log(2));const Me=(t,e)=>{t=t-57344;let r=I[t];r&&r.isShared&&((I.restoreStructures||(I.restoreStructures=[]))[t]=r),I[t]=e,e.read=Fe(e)};F[nr]=t=>{let e=t.length,r=t[1];Me(t[0],r);let n={};for(let s=2;sL?L[0].slice(L.position0,L.position0+=t):new ce(t,14),F[15]=t=>L?L[1].slice(L.position1,L.position1+=t):new ce(t,15);let cr={Error,RegExp};F[27]=t=>(cr[t[0]]||Error)(t[1],t[2]);const ct=t=>{if(w[c++]!=132){let r=new Error("Packed values structure must be followed by a 4 element array");throw w.length{if(!Q)if(T.getShared)He();else return new ce(t,st);if(typeof t=="number")return Q[16+(t>=0?2*t:-2*t-1)];let e=new Error("No support for non-integer packed references yet");throw t===void 0&&(e.incomplete=!0),e},F[28]=t=>{Z||(Z=new Map,Z.id=0);let e=Z.id++,r=c,n=w[c],s;n>>5==4?s=[]:s={};let o={target:s};Z.set(e,o);let l=t();return o.used?(Object.getPrototypeOf(s)!==Object.getPrototypeOf(l)&&(c=r,s=l,Z.set(e,{target:s}),l=t()),Object.assign(s,l)):(o.target=l,l)},F[28].handlesRead=!0,F[29]=t=>{let e=Z.get(t);return e.used=!0,e.target},F[258]=t=>new Set(t),(F[259]=t=>(T.mapsAsObjects&&(T.mapsAsObjects=!1,me=!0),t())).handlesRead=!0;function pe(t,e){return typeof t=="string"?t+e:t instanceof Array?t.concat(e):Object.assign({},t,e)}function ue(){if(!Q)if(T.getShared)He();else throw new Error("No packed values available");return Q}const ur=1399353956;De.push((t,e)=>{if(t>=225&&t<=255)return pe(ue().prefixes[t-224],e);if(t>=28704&&t<=32767)return pe(ue().prefixes[t-28672],e);if(t>=1879052288&&t<=2147483647)return pe(ue().prefixes[t-1879048192],e);if(t>=216&&t<=223)return pe(e,ue().suffixes[t-216]);if(t>=27647&&t<=28671)return pe(e,ue().suffixes[t-27639]);if(t>=1811940352&&t<=1879048191)return pe(e,ue().suffixes[t-1811939328]);if(t==ur)return{packedValues:Q,structures:I.slice(0),version:e};if(t==55799)return e});const dr=new Uint8Array(new Uint16Array([1]).buffer)[0]==1,ut=[Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array,typeof BigUint64Array>"u"?{name:"BigUint64Array"}:BigUint64Array,Int8Array,Int16Array,Int32Array,typeof BigInt64Array>"u"?{name:"BigInt64Array"}:BigInt64Array,Float32Array,Float64Array],hr=[64,68,69,70,71,72,77,78,79,85,86];for(let t=0;t{if(!t)throw new Error("Could not find typed array for code "+e);return!T.copyBuffers&&(n===1||n===2&&!(l.byteOffset&1)||n===4&&!(l.byteOffset&3)||n===8&&!(l.byteOffset&7))?new t(l.buffer,l.byteOffset,l.byteLength>>o):new t(Uint8Array.prototype.slice.call(l,0).buffer)}:l=>{if(!t)throw new Error("Could not find typed array for code "+e);let p=new DataView(l.buffer,l.byteOffset,l.byteLength),y=l.length>>o,_=new t(y),x=p[r];for(let N=0;N23)switch(t){case 24:t=w[c++];break;case 25:t=W.getUint16(c),c+=2;break;case 26:t=W.getUint32(c),c+=4;break}return t}function He(){if(T.getShared){let t=dt(()=>(w=null,T.getShared()))||{},e=t.structures||[];T.sharedVersion=t.version,Q=T.sharedValues=t.packedValues,I===!0?T.structures=I=e:I.splice.apply(I,[0,e.length].concat(e))}}function dt(t){let e=le,r=c,n=Oe,s=xe,o=Re,l=Z,p=L,y=new Uint8Array(w.slice(0,le)),_=I,x=T,N=Se,H=t();return le=e,c=r,Oe=n,xe=s,Re=o,Z=l,L=p,w=y,Se=N,I=_,T=x,W=new DataView(w.buffer,w.byteOffset,w.byteLength),H}function je(){w=null,Z=null,I=null}const Ke=new Array(147);for(let t=0;t<256;t++)Ke[t]=+("1e"+Math.floor(45.15-t*.30103));let Ge=new be({useRecords:!1});const q=Ge.decode;Ge.decodeMultiple;let Ue;try{Ue=new TextEncoder}catch{}let qe,ht;const Pe=typeof globalThis=="object"&&globalThis.Buffer,_e=typeof Pe<"u",$e=_e?Pe.allocUnsafeSlow:Uint8Array,pt=_e?Pe:Uint8Array,yt=256,wt=_e?4294967296:2144337920;let ve,f,B,i=0,fe,M=null;const wr=61440,Er=/[\u0080-\uFFFF]/,J=Symbol("record-id");class Et extends be{constructor(e){super(e),this.offset=0;let r,n,s,o,l;e=e||{};let p=pt.prototype.utf8Write?function(a,E){return f.utf8Write(a,E,f.byteLength-E)}:Ue&&Ue.encodeInto?function(a,E){return Ue.encodeInto(a,f.subarray(E)).written}:!1,y=this,_=e.structures||e.saveStructures,x=e.maxSharedStructures;if(x==null&&(x=_?128:0),x>8190)throw new Error("Maximum maxSharedStructure is 8190");let N=e.sequential;N&&(x=0),this.structures||(this.structures=[]),this.saveStructures&&(this.saveShared=this.saveStructures);let H,$,z=e.sharedValues,k;if(z){k=Object.create(null);for(let a=0,E=z.length;athis.encodeKeys(d));break}return this.encode(a,E)},this.encode=function(a,E){if(f||(f=new $e(8192),B=new DataView(f.buffer,0,8192),i=0),fe=f.length-10,fe-i<2048?(f=new $e(f.length),B=new DataView(f.buffer,0,f.length),fe=f.length-10,i=0):E===St&&(i=i+7&2147483640),r=i,y.useSelfDescribedHeader&&(B.setUint32(i,3654940416),i+=3),l=y.structuredClone?new Map:null,y.bundleStrings&&typeof a!="string"?(M=[],M.size=1/0):M=null,n=y.structures,n){if(n.uninitialized){let h=y.getShared()||{};y.structures=n=h.structures||[],y.sharedVersion=h.version;let u=y.sharedValues=h.packedValues;if(u){k={};for(let m=0,b=u.length;mx&&!N&&(d=x),!n.transitions){n.transitions=Object.create(null);for(let h=0;h0){f[i++]=216,f[i++]=51,ee(4);let h=d.values;S(h),ee(0),ee(0),$=Object.create(k||null);for(let u=0,m=h.length;ufe&&X(i),y.offset=i;let d=mr(f.subarray(r,i),l.idsToInsert);return l=null,d}return E&St?(f.start=r,f.end=i,f):f.subarray(r,i)}finally{if(n){if(D<10&&D++,n.length>x&&(n.length=x),se>1e4)n.transitions=null,D=0,se=0,v.length>0&&(v=[]);else if(v.length>0&&!N){for(let d=0,h=v.length;dx&&(y.structures=y.structures.slice(0,x));let d=f.subarray(r,i);return y.updateSharedData()===!1?y.encode(a):d}E&br&&(i=r)}},this.findCommonStringsToPack=()=>(H=new Map,k||(k=Object.create(null)),a=>{let E=a&&a.threshold||4,d=this.pack?a.maxPrivatePackedValues||16:0;z||(z=this.sharedValues=[]);for(let[h,u]of H)u.count>E&&(k[h]=d++,z.push(h),s=!0);for(;this.saveShared&&this.updateSharedData()===!1;);H=null});const S=a=>{i>fe&&(f=X(i));var E=typeof a,d;if(E==="string"){if($){let b=$[a];if(b>=0){b<16?f[i++]=b+224:(f[i++]=198,b&1?S(15-b>>1):S(b-16>>1));return}else if(H&&!e.pack){let R=H.get(a);R?R.count++:H.set(a,{count:1})}}let h=a.length;if(M&&h>=4&&h<1024){if((M.size+=h)>wr){let R,O=(M[0]?M[0].length*3+M[1].length:0)+10;i+O>fe&&(f=X(i+O)),f[i++]=217,f[i++]=223,f[i++]=249,f[i++]=M.position?132:130,f[i++]=26,R=i-r,i+=4,M.position&&mt(r,S),M=["",""],M.size=0,M.position=R}let b=Er.test(a);M[b?0:1]+=a,f[i++]=b?206:207,S(h);return}let u;h<32?u=1:h<256?u=2:h<65536?u=3:u=5;let m=h*3;if(i+m>fe&&(f=X(i+m)),h<64||!p){let b,R,O,U=i+u;for(b=0;b>6|192,f[U++]=R&63|128):(R&64512)===55296&&((O=a.charCodeAt(b+1))&64512)===56320?(R=65536+((R&1023)<<10)+(O&1023),b++,f[U++]=R>>18|240,f[U++]=R>>12&63|128,f[U++]=R>>6&63|128,f[U++]=R&63|128):(f[U++]=R>>12|224,f[U++]=R>>6&63|128,f[U++]=R&63|128);d=U-i-u}else d=p(a,i+u,m);d<24?f[i++]=96|d:d<256?(u<2&&f.copyWithin(i+2,i+1,i+1+d),f[i++]=120,f[i++]=d):d<65536?(u<3&&f.copyWithin(i+3,i+2,i+2+d),f[i++]=121,f[i++]=d>>8,f[i++]=d&255):(u<5&&f.copyWithin(i+5,i+3,i+3+d),f[i++]=122,B.setUint32(i,d),i+=4),i+=d}else if(E==="number")if(!this.alwaysUseFloat&&a>>>0===a)a<24?f[i++]=a:a<256?(f[i++]=24,f[i++]=a):a<65536?(f[i++]=25,f[i++]=a>>8,f[i++]=a&255):(f[i++]=26,B.setUint32(i,a),i+=4);else if(!this.alwaysUseFloat&&a>>0===a)a>=-24?f[i++]=31-a:a>=-256?(f[i++]=56,f[i++]=~a):a>=-65536?(f[i++]=57,B.setUint16(i,~a),i+=2):(f[i++]=58,B.setUint32(i,~a),i+=4);else if(!this.alwaysUseFloat&&a<0&&a>=-4294967296&&Math.floor(a)===a)f[i++]=58,B.setUint32(i,-1-a),i+=4;else{let h;if((h=this.useFloat32)>0&&a<4294967296&&a>=-2147483648){f[i++]=250,B.setFloat32(i,a);let u;if(h<4||(u=a*Ke[(f[i]&127)<<1|f[i+1]>>7])>>0===u){i+=4;return}else i--}f[i++]=251,B.setFloat64(i,a),i+=8}else if(E==="object")if(!a)f[i++]=246;else{if(l){let u=l.get(a);if(u){if(f[i++]=216,f[i++]=29,f[i++]=25,!u.references){let m=l.idsToInsert||(l.idsToInsert=[]);u.references=[],m.push(u)}u.references.push(i-r),i+=2;return}else l.set(a,{offset:i-r})}let h=a.constructor;if(h===Object)this.skipFunction===!0&&(a=Object.fromEntries([...Object.keys(a).filter(u=>typeof a[u]!="function").map(u=>[u,a[u]])])),re(a);else if(h===Array){d=a.length,d<24?f[i++]=128|d:ee(d);for(let u=0;u>8,f[i++]=d&255):(f[i++]=186,B.setUint32(i,d),i+=4),y.keyMap)for(let[u,m]of a)S(y.encodeKey(u)),S(m);else for(let[u,m]of a)S(u),S(m);else{for(let u=0,m=qe.length;u>8,f[i++]=O&255):O>-1&&(f[i++]=218,B.setUint32(i,O),i+=4),R.encode.call(this,a,S,X);return}}if(a[Symbol.iterator]){if(ve){let u=new Error("Iterable should be serialized as iterator");throw u.iteratorNotHandled=!0,u}f[i++]=159;for(let u of a)S(u);f[i++]=255;return}if(a[Symbol.asyncIterator]||Ve(a)){let u=new Error("Iterable/blob should be serialized as iterator");throw u.iteratorNotHandled=!0,u}if(this.useToJSON&&a.toJSON){const u=a.toJSON();if(u!==a)return S(u)}re(a)}}else if(E==="boolean")f[i++]=a?245:244;else if(E==="bigint"){if(a=0)f[i++]=27,B.setBigUint64(i,a);else if(a>-(BigInt(1)<=BigInt(0)?f[i++]=194:(f[i++]=195,a=BigInt(-1)-a);let h=[];for(;a;)h.push(Number(a&BigInt(255))),a>>=BigInt(8);We(new Uint8Array(h.reverse()),X);return}i+=8}else if(E==="undefined")f[i++]=247;else throw new Error("Unknown type: "+E)},re=this.useRecords===!1?this.variableMapSize?a=>{let E=Object.keys(a),d=Object.values(a),h=E.length;if(h<24?f[i++]=160|h:h<256?(f[i++]=184,f[i++]=h):h<65536?(f[i++]=185,f[i++]=h>>8,f[i++]=h&255):(f[i++]=186,B.setUint32(i,h),i+=4),y.keyMap)for(let u=0;u{f[i++]=185;let E=i-r;i+=2;let d=0;if(y.keyMap)for(let h in a)(typeof a.hasOwnProperty!="function"||a.hasOwnProperty(h))&&(S(y.encodeKey(h)),S(a[h]),d++);else for(let h in a)(typeof a.hasOwnProperty!="function"||a.hasOwnProperty(h))&&(S(h),S(a[h]),d++);f[E+++r]=d>>8,f[E+r]=d&255}:(a,E)=>{let d,h=o.transitions||(o.transitions=Object.create(null)),u=0,m=0,b,R;if(this.keyMap){R=Object.keys(a).map(U=>this.encodeKey(U)),m=R.length;for(let U=0;U>8|224,f[i++]=O&255;else if(R||(R=h.__keys__||(h.__keys__=Object.keys(a))),b===void 0?(O=o.nextId++,O||(O=0,o.nextId=1),O>=yt&&(o.nextId=(O=x)+1)):O=b,o[O]=R,O>8|224,f[i++]=O&255,h=o.transitions;for(let U=0;U=yt-x&&(v.shift()[J]=void 0),v.push(h),ee(m+2),S(57344+O),S(R),E)return;for(let U in a)(typeof a.hasOwnProperty!="function"||a.hasOwnProperty(U))&&S(a[U]);return}if(m<24?f[i++]=128|m:ee(m),!E)for(let U in a)(typeof a.hasOwnProperty!="function"||a.hasOwnProperty(U))&&S(a[U])},X=a=>{let E;if(a>16777216){if(a-r>wt)throw new Error("Encoded buffer would be larger than maximum buffer size");E=Math.min(wt,Math.round(Math.max((a-r)*(a>67108864?1.25:2),4194304)/4096)*4096)}else E=(Math.max(a-r<<2,f.length-1)>>12)+1<<12;let d=new $e(E);return B=new DataView(d.buffer,0,E),f.copy?f.copy(d,0,r,a):d.set(f.slice(r,a)),i-=r,r=0,fe=d.length-10,f=d};let V=100,de=1e3;this.encodeAsIterable=function(a,E){return Ie(a,E,ie)},this.encodeAsAsyncIterable=function(a,E){return Ie(a,E,ke)};function*ie(a,E,d){let h=a.constructor;if(h===Object){let u=y.useRecords!==!1;u?re(a,!0):gt(Object.keys(a).length,160);for(let m in a){let b=a[m];u||S(m),b&&typeof b=="object"?E[m]?yield*ie(b,E[m]):yield*Ee(b,E,m):S(b)}}else if(h===Array){let u=a.length;ee(u);for(let m=0;mV)?E.element?yield*ie(b,E.element):yield*Ee(b,E,"element"):S(b)}}else if(a[Symbol.iterator]&&!a.buffer){f[i++]=159;for(let u of a)u&&(typeof u=="object"||i-r>V)?E.element?yield*ie(u,E.element):yield*Ee(u,E,"element"):S(u);f[i++]=255}else Ve(a)?(gt(a.size,64),yield f.subarray(r,i),yield a,oe()):a[Symbol.asyncIterator]?(f[i++]=159,yield f.subarray(r,i),yield a,oe(),f[i++]=255):S(a);d&&i>r?yield f.subarray(r,i):i-r>V&&(yield f.subarray(r,i),oe())}function*Ee(a,E,d){let h=i-r;try{S(a),i-r>V&&(yield f.subarray(r,i),oe())}catch(u){if(u.iteratorNotHandled)E[d]={},i=r+h,yield*ie.call(this,a,E[d]);else throw u}}function oe(){V=de,y.encode(null,Qe)}function Ie(a,E,d){return E&&E.chunkThreshold?V=de=E.chunkThreshold:V=100,a&&typeof a=="object"?(y.encode(null,Qe),d(a,y.iterateProperties||(y.iterateProperties={}),!0)):[y.encode(a)]}async function*ke(a,E){for(let d of ie(a,E,!0)){let h=d.constructor;if(h===pt||h===Uint8Array)yield d;else if(Ve(d)){let u=d.stream().getReader(),m;for(;!(m=await u.read()).done;)yield m.value}else if(d[Symbol.asyncIterator])for await(let u of d)oe(),u?yield*ke(u,E.async||(E.async={})):yield y.encode(u);else yield d}}}useBuffer(e){f=e,B=new DataView(f.buffer,f.byteOffset,f.byteLength),i=0}clearSharedData(){this.structures&&(this.structures=[]),this.sharedValues&&(this.sharedValues=void 0)}updateSharedData(){let e=this.sharedVersion||0;this.sharedVersion=e+1;let r=this.structures.slice(0),n=new xt(r,this.sharedValues,this.sharedVersion),s=this.saveShared(n,o=>(o&&o.version||0)==e);return s===!1?(n=this.getShared()||{},this.structures=n.structures||[],this.sharedValues=n.packedValues,this.sharedVersion=n.version,this.structures.nextId=this.structures.length):r.forEach((o,l)=>this.structures[l]=o),s}}function gt(t,e){t<24?f[i++]=e|t:t<256?(f[i++]=e|24,f[i++]=t):t<65536?(f[i++]=e|25,f[i++]=t>>8,f[i++]=t&255):(f[i++]=e|26,B.setUint32(i,t),i+=4)}class xt{constructor(e,r,n){this.structures=e,this.packedValues=r,this.version=n}}function ee(t){t<24?f[i++]=128|t:t<256?(f[i++]=152,f[i++]=t):t<65536?(f[i++]=153,f[i++]=t>>8,f[i++]=t&255):(f[i++]=154,B.setUint32(i,t),i+=4)}const gr=typeof Blob>"u"?function(){}:Blob;function Ve(t){if(t instanceof gr)return!0;let e=t[Symbol.toStringTag];return e==="Blob"||e==="File"}function Ne(t,e){switch(typeof t){case"string":if(t.length>3){if(e.objectMap[t]>-1||e.values.length>=e.maxValues)return;let n=e.get(t);if(n)++n.count==2&&e.values.push(t);else if(e.set(t,{count:1}),e.samplingPackedValues){let s=e.samplingPackedValues.get(t);s?s.count++:e.samplingPackedValues.set(t,{count:1})}}break;case"object":if(t)if(t instanceof Array)for(let n=0,s=t.length;n"u"?function(){}:BigUint64Array,Int8Array,Int16Array,Int32Array,typeof BigInt64Array>"u"?function(){}:BigInt64Array,Float32Array,Float64Array,xt],qe=[{tag:1,encode(t,e){let r=t.getTime()/1e3;(this.useTimestamp32||t.getMilliseconds()===0)&&r>=0&&r<4294967296?(f[i++]=26,B.setUint32(i,r),i+=4):(f[i++]=251,B.setFloat64(i,r),i+=8)}},{tag:258,encode(t,e){let r=Array.from(t);e(r)}},{tag:27,encode(t,e){e([t.name,t.message])}},{tag:27,encode(t,e){e(["RegExp",t.source,t.flags])}},{getTag(t){return t.tag},encode(t,e){e(t.value)}},{encode(t,e,r){We(t,r)}},{getTag(t){if(t.constructor===Uint8Array&&(this.tagUint8Array||_e&&this.tagUint8Array!==!1))return 64},encode(t,e,r){We(t,r)}},te(68,1),te(69,2),te(70,4),te(71,8),te(72,1),te(77,2),te(78,4),te(79,8),te(85,4),te(86,8),{encode(t,e){let r=t.packedValues||[],n=t.structures||[];if(r.values.length>0){f[i++]=216,f[i++]=51,ee(4);let s=r.values;e(s),ee(0),ee(0),packedObjectMap=Object.create(sharedPackedObjectMap||null);for(let o=0,l=s.length;o