neozip-cli 0.95.0 → 0.95.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.95.1] - 2026-07-07
13
+
14
+ ### Documentation
15
+
16
+ - **[README.md](README.md)** — v0.95.1 release: expanded AI agent integration guide (CLI + JSON, Skills, neozip-mcp), NeoZip Token Service (`connect refresh`, `connect fund`), advanced-feature matrix, and agent workflow documentation.
17
+
12
18
  ## [0.95.0] - 2026-07-03
13
19
 
14
20
  ### Added
@@ -38,6 +44,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
38
44
  - **Blockchain tokenization (`-b`) blocked by an expired Token Service token** — `-b` and on-chain `mint` sign locally with the wallet key and never use the Token Service access token, but the readiness gate required a non-expired token for them. The gate now distinguishes on-chain abilities (wallet only) from Token Service abilities (`-ts`, which still require a current token), and expired-token errors now point to `neozip connect refresh`.
39
45
  - **`pack:dry-run` script** — use `npm pack --dry-run` (pnpm has no `--dry-run` flag).
40
46
 
47
+ ### Documentation
48
+
49
+ - **[README.md](README.md)** — updated for v0.95: NeoZip Token Service (`connect refresh`, `connect fund`, silent wallet-login renewal), AI agent integration guide (CLI + JSON, bundled Skills via `neozip skills install`, neozip-mcp), advanced-feature matrix for agents (encryption, compression, blockchain, legacy mode), and agent workflow (schema → dry-run → execute → recover via `nextCommand`).
50
+ - **[AGENTS.md](AGENTS.md)** — engagement rules for machine-readable I/O, schema introspection, dry-run, exit codes, and safety rails.
51
+ - **[skills/](skills/)** — six bundled Agent Skills (`neozip-shared`, `neozip-create`, `neozip-extract`, `neozip-list`, `neozip-connect`, `neozip-legacy`) with per-command guidance for autonomous agents.
52
+
41
53
  ## [0.90.0] - 2026-03-18
42
54
 
43
55
  ### Added
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ## Release Notice
10
10
 
11
- **Current version: v0.90.0.** This release adds full AES-256 encryption support. See [CHANGELOG.md](CHANGELOG.md) for details.
11
+ **Current version: v0.95.1.** This release adds first-class **AI agent** support (JSON I/O, schema introspection, bundled Skills with `neozip skills install`), deep **NeoZip Token Service** integration (silent token refresh, wallet funding), and `--legacy` InfoZip compatibility. See [CHANGELOG.md](CHANGELOG.md) for details.
12
12
 
13
13
  - **API Stability**: Command-line interface is becoming more stable but may still change
14
14
  - **Testing**: Please test thoroughly and report any issues
@@ -18,8 +18,10 @@
18
18
 
19
19
  NeoZip CLI is a modern, full-featured ZIP utility that provides:
20
20
 
21
- - **Standard ZIP Compatibility**: ~99% compatible with InfoZip utilities
21
+ - **Standard ZIP Compatibility**: ~99% compatible with InfoZip utilities (`--legacy` for stock `unzip`)
22
22
  - **Blockchain Integration**: Tokenize archives and verify integrity on-chain
23
+ - **NeoZip Token Service**: Email-verified timestamps, wallet-linked identity, and testnet gas grants
24
+ - **AI Agent Ready**: Machine-readable JSON I/O, schema introspection, dry-run, and bundled [Skills](skills/)
23
25
  - **Advanced Compression**: Zstd, Deflate, and Store compression methods
24
26
  - **Encryption Support**: AES-256 (default) and PKZIP encryption
25
27
  - **Cross-Platform**: Works on macOS, Linux, and Windows
@@ -48,10 +50,11 @@ NeoZip CLI is a modern, full-featured ZIP utility that provides:
48
50
  - Auto-detection of encryption method during extraction
49
51
 
50
52
  ### Blockchain Features
51
- - **Tokenization**: Create on-chain tokens for archives
52
- - **OpenTimestamp**: Bitcoin blockchain timestamping
53
- - **Token Service**: Ethereum blockchain timestamping (NeoZip Token Service)
54
- - **Integrity Verification**: Verify archive integrity on-chain
53
+ - **Tokenization (`-b`)**: Create on-chain tokens for archives (signs locally with the Data Wallet)
54
+ - **OpenTimestamp (`-ots`)**: Bitcoin blockchain timestamping
55
+ - **Token Service (`-ts`)**: Ethereum timestamping via the NeoZip Token Service (requires a verified account)
56
+ - **Integrity Verification**: Verify archive integrity on-chain during extract (`neounzip --pre-verify`)
57
+ - **Wallet funding**: Request testnet gas grants via `neozip connect fund`
55
58
  - **Network Support**: Base Sepolia, Base Mainnet, Arbitrum, and more
56
59
 
57
60
  ### Advanced Features
@@ -303,7 +306,7 @@ neolist -1 archive.nzip
303
306
 
304
307
  ### Account and wallet setup
305
308
 
306
- All wallet identity and Token Service credentials live in the shared connection store (`~/.neozip/connection/`). Use the same profile as NeoZip Desktop and MCP.
309
+ All wallet identity and Token Service credentials live in the shared connection store (`~/.neozip/connection/`). Use the same profile as NeoZip Desktop and the [neozip-mcp](https://github.com/NeoWareInc/neozip-mcp) server.
307
310
 
308
311
  ```bash
309
312
  neozip connect # Interactive setup (alias: neozip init)
@@ -315,6 +318,38 @@ neozip config # Connection dashboard (status, prefs, migrate)
315
318
 
316
319
  On-chain preferences (`defaultNetwork`, custom RPC URLs, gas) are stored in each connection's `public.json`.
317
320
 
321
+ ### NeoZip Token Service
322
+
323
+ The Token Service provides email-verified identity, Ethereum timestamps (`-ts`), and optional testnet gas grants. Configuration is read **only** from the connection store — not from env vars or CLI flags.
324
+
325
+ **Setup (interactive or scripted):**
326
+
327
+ ```bash
328
+ neozip connect register --email you@example.com --json
329
+ neozip connect verify --email you@example.com --code 123456 --json
330
+ neozip connect wallet create --ack-backup --json
331
+ neozip connect finish --json
332
+ ```
333
+
334
+ **Token refresh** — access tokens expire. Renewal prefers a **silent wallet-signature login** (no email round-trip); falls back to email OTP on older deployments:
335
+
336
+ ```bash
337
+ neozip connect refresh --json # silent wallet login (preferred)
338
+ neozip connect refresh --email you@example.com --json # send OTP code
339
+ neozip connect refresh --email you@example.com --code 123456 --json
340
+ ```
341
+
342
+ `-ts` auto-renews an expired token before failing, so timestamping usually needs no manual step. `-b` tokenization and `mint` sign on-chain with the local wallet key and do **not** require a current access token.
343
+
344
+ **Wallet funding** — on-chain operations need native gas. The Token Service can send a small fixed grant to your primary linked wallet (recipient is server-authoritative):
345
+
346
+ ```bash
347
+ neozip connect fund policy --json # grant size + cooldown (no auth)
348
+ neozip connect fund status --json # eligibility and recent grants
349
+ neozip connect fund --json # request a grant (default action)
350
+ neozip connect fund --network base-sepolia --json
351
+ ```
352
+
318
353
  Optional overrides:
319
354
 
320
355
  ```bash
@@ -383,14 +418,17 @@ neounzip -P "secure-password" secret.nzip decrypted/
383
418
  ### Blockchain Features
384
419
 
385
420
  ```bash
386
- # Tokenize archive
421
+ # Tokenize archive (on-chain mint; needs gas — run neozip connect fund if low)
387
422
  neozip -b tokenized.nzip important-file.txt
388
423
 
389
- # Tokenize with OpenTimestamp
424
+ # Token Service timestamp (needs verified account + current access token)
425
+ neozip -ts timestamped.nzip document.pdf
426
+
427
+ # OpenTimestamp (Bitcoin)
390
428
  neozip -ots timestamped.nzip document.pdf
391
429
 
392
- # Extract and verify
393
- neounzip tokenized.nzip verified/
430
+ # Extract and verify on-chain integrity
431
+ neounzip --pre-verify tokenized.nzip verified/
394
432
  ```
395
433
 
396
434
  ### Advanced Operations
@@ -414,14 +452,49 @@ neozip -y archive.nzip ./symlinks/
414
452
 
415
453
  ## For AI agents
416
454
 
417
- NeoZip ships an agent-friendly surface. See [AGENTS.md](AGENTS.md) and the
418
- [skills/](skills/) directory for the full guide.
455
+ NeoZip is designed for autonomous AI/LLM agents. Every command exposes a stable,
456
+ machine-readable surface alongside its human interface. Agents can integrate via
457
+ three paths:
458
+
459
+ | Path | When to use |
460
+ |------|-------------|
461
+ | **CLI + JSON** | Direct shell invocation from any agent runtime |
462
+ | **Bundled Skills** | Cursor, Claude Code, or other skill-aware hosts — load from [skills/](skills/) |
463
+ | **neozip-mcp** | MCP-native agents — same `~/.neozip/connection/` store, tool-based API |
464
+
465
+ Start with [AGENTS.md](AGENTS.md) for engagement rules, then load the relevant
466
+ skill for each task.
467
+
468
+ ### Agent workflow
469
+
470
+ 1. **Introspect** — `neozip schema <neozip|neounzip|neolist|connect>` returns accepted fields, types, defaults, and exit codes.
471
+ 2. **Preview** — add `--dry-run` to `neozip`/`neounzip` to resolve the full plan as JSON without writing.
472
+ 3. **Execute** — run with `--format json`; parse stdout only (stderr is hints).
473
+ 4. **Recover** — on failure, check `error.exitCode` and run `error.nextCommand` when present.
474
+
475
+ ```bash
476
+ neozip schema neozip
477
+ neozip --format json --dry-run \
478
+ --params '{"level":9,"encrypt":true,"password":"s3cret"}' \
479
+ --json '{"archive":"out.zip","files":["src/","README.md"]}'
480
+ neozip --format json \
481
+ --params '{"level":9,"encrypt":true,"password":"s3cret"}' \
482
+ --json '{"archive":"out.zip","files":["src/","README.md"]}'
483
+ ```
419
484
 
420
485
  ### Install Agent Skills
421
486
 
422
- Six bundled skills (`neozip-shared`, `neozip-create`, `neozip-extract`, `neozip-list`,
423
- `neozip-connect`, `neozip-legacy`) ship inside the npm package. Install them into
424
- Claude Code or Cursor after `npm install -g neozip-cli`:
487
+ Six bundled skills ship inside the npm package. Install them into Claude Code or
488
+ Cursor after `npm install -g neozip-cli`:
489
+
490
+ | Skill | Covers |
491
+ |-------|--------|
492
+ | [neozip-shared](skills/neozip-shared/SKILL.md) | JSON output, `--params`/`--json`, schema, dry-run, exit codes |
493
+ | [neozip-create](skills/neozip-create/SKILL.md) | Archive creation: compression, encryption, blockchain flags |
494
+ | [neozip-extract](skills/neozip-extract/SKILL.md) | Extract, test, verify; zip-slip protection; `--pre-verify` |
495
+ | [neozip-list](skills/neozip-list/SKILL.md) | List archive contents as JSON |
496
+ | [neozip-connect](skills/neozip-connect/SKILL.md) | Token Service setup, refresh, funding |
497
+ | [neozip-legacy](skills/neozip-legacy/SKILL.md) | InfoZip/PKZIP-compatible archives (`--legacy`) |
425
498
 
426
499
  ```bash
427
500
  # Symlink bundled skills into ~/.claude/skills and ~/.cursor/skills
@@ -438,46 +511,75 @@ neozip skills list
438
511
  neozip skills pack --output-dir ./neozip-skills-zips
439
512
  ```
440
513
 
441
- Alternative (skills registry, same format as Google Workspace CLI):
514
+ Alternative (skills registry):
442
515
 
443
516
  ```bash
444
517
  npx skills add https://github.com/NeoWareInc/neozip-cli
445
518
  npx skills add https://github.com/NeoWareInc/neozip-cli/tree/main/skills/neozip-create
446
519
  ```
447
520
 
448
- ### CLI conventions
521
+ ### JSON I/O conventions
522
+
523
+ - **Output:** `--format json` writes a single object to stdout:
524
+ - Success: `{ "ok": true, ... }`
525
+ - Failure: `{ "ok": false, "error": { "code", "exitCode", "message", "nextCommand"? } }`
526
+ - **Input:** `--params '<JSON>'` (control options) and `--json '<JSON>'` (payload: archive + files/targets). Either accepts `-` to read from stdin. Explicit CLI flags override JSON input.
527
+ - **Exit codes:** InfoZip-compatible; echoed in `error.exitCode`. Branch on codes, not message text.
528
+
529
+ ### Advanced features for agents
449
530
 
450
- - **Machine-readable output:** add `--format json` to any command to get a
451
- single JSON object on stdout (`{ "ok": true, ... }` or
452
- `{ "ok": false, "error": { ... } }`). Human hints go to stderr.
453
- - **JSON input:** `--params '<JSON>'` (options) and `--json '<JSON>'` (payload:
454
- archive + files/targets). Either accepts `-` to read from stdin. Explicit CLI
455
- flags override JSON input.
456
- - **Schema introspection:** `neozip schema <neozip|neounzip|neolist|connect>`
457
- emits the accepted fields, types, defaults, and exit codes.
458
- - **Dry-run:** `neozip`/`neounzip` accept `--dry-run` to resolve and print the
459
- plan as JSON without writing anything.
460
- - **Safety:** archive names and extraction dirs are validated for control
461
- characters; `neounzip` refuses zip-slip (entries escaping the target dir).
462
- - **Exit codes:** InfoZip-compatible and echoed in `error.exitCode`.
531
+ | Feature | Agent params / flags | Prerequisites |
532
+ |---------|---------------------|---------------|
533
+ | AES-256 encryption | `"encrypt": true`, `"password": "…"` | None |
534
+ | PKZIP encryption | `"encryptionMethod": "pkzip"` | None |
535
+ | Zstd compression (default) | `"compression": "zstd"`, `"level": 0–9` | None |
536
+ | InfoZip compatibility | `"legacy": true` | Disables blockchain extensions |
537
+ | On-chain tokenization | `"blockchain": true` | `neozip connect` + gas (`connect fund`) |
538
+ | Token Service timestamp | `"blockchainTokenService": true` | Verified account + access token |
539
+ | OpenTimestamp | `"blockchainOts": true` | None |
540
+ | Pre-verify on extract | `"preVerify": true` | Archive must be tokenized |
541
+ | Network selection | `"network": "base-sepolia"` | Connection `defaultNetwork` or override |
542
+
543
+ **Blockchain from JSON:**
463
544
 
464
545
  ```bash
465
- # Introspect, then create fully from JSON
466
- neozip schema neozip
546
+ # Tokenize with Token Service timestamp
467
547
  neozip --format json \
468
- --params '{"level":9,"encrypt":true,"password":"s3cret"}' \
469
- --json '{"archive":"out.zip","files":["src/","README.md"]}'
548
+ --params '{"blockchain":true,"blockchainTokenService":true,"network":"base-sepolia"}' \
549
+ --json '{"archive":"tokenized.nzip","files":["contract.pdf"]}'
550
+
551
+ # Extract with on-chain integrity check
552
+ neounzip --format json \
553
+ --params '{"exdir":"out","preVerify":true}' \
554
+ --json '{"archive":"tokenized.nzip"}'
555
+ ```
470
556
 
471
- # Preview an extraction, then run it
472
- neounzip --format json --dry-run --params '{"exdir":"out"}' in.zip
473
- neounzip --format json --params '{"exdir":"out","overwrite":true}' in.zip
557
+ **Token Service from an agent** use explicit `connect` subcommands (not the interactive wizard):
474
558
 
475
- # List as JSON
476
- neolist --format json in.zip
559
+ ```bash
560
+ neozip connect status --json
561
+ neozip connect refresh --json # silent wallet-signature renewal
562
+ neozip connect fund status --json # check gas eligibility
563
+ neozip connect fund --json # request testnet gas
477
564
  ```
478
565
 
479
- For an archive that stock InfoZip `unzip` can read, add `--legacy` (forces
480
- deflate/store + PKZIP, disables NeoZip extensions).
566
+ On config errors, archive commands return `error.nextCommand: "neozip connect"` so the agent can run setup and retry.
567
+
568
+ ### Safety rails
569
+
570
+ - Archive names and extraction dirs are validated for control characters and dangerous Unicode.
571
+ - `neounzip` refuses zip-slip (entries whose resolved path escapes the target directory).
572
+ - `--dry-run` never touches the filesystem.
573
+ - Treat all agent-supplied paths and IDs as potentially adversarial.
574
+
575
+ ### InfoZip / PKZIP compatibility
576
+
577
+ Default compression is **zstd**, which stock InfoZip `unzip` cannot read. For consumers that need standard ZIP, pass `--legacy` (forces deflate/store + PKZIP encryption, disables zstd and all NeoZip extensions). Combining `--legacy` with blockchain features is a hard error (exit 10). See [neozip-legacy](skills/neozip-legacy/SKILL.md).
578
+
579
+ ```bash
580
+ neozip --format json --params '{"legacy":true,"level":9}' \
581
+ --json '{"archive":"compat.zip","files":["src/"]}'
582
+ ```
481
583
 
482
584
  ## Requirements
483
585
 
@@ -490,6 +592,8 @@ deflate/store + PKZIP, disables NeoZip extensions).
490
592
  The following documentation is included with this package:
491
593
 
492
594
  - **[README.md](README.md)** - This file, containing installation, usage, and examples
595
+ - **[AGENTS.md](AGENTS.md)** - AI agent engagement rules (JSON I/O, schema, dry-run, exit codes)
596
+ - **[skills/](skills/)** - Bundled agent Skills for create, extract, list, connect, and legacy mode
493
597
  - **[WHY_NEOZIP.md](WHY_NEOZIP.md)** - Introduction to NeoZip and its blockchain integration
494
598
  - **[CHANGELOG.md](CHANGELOG.md)** - Version history and release notes
495
599
  - **[DOCUMENTATION.md](DOCUMENTATION.md)** - Complete documentation index and reference
@@ -585,6 +689,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
585
689
 
586
690
  ---
587
691
 
588
- **Version**: 0.90.0
692
+ **Version**: 0.95.1
589
693
  **Status**: Release (see [CHANGELOG.md](CHANGELOG.md) for latest changes)
590
- **Last Updated**: March 18, 2026
694
+ **Last Updated**: July 7, 2026
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FundingUnavailableError = void 0;
4
+ exports.getFundingPolicy = getFundingPolicy;
5
+ exports.getFundingStatus = getFundingStatus;
6
+ exports.requestFundingGrant = requestFundingGrant;
7
+ /**
8
+ * Token Service funding API client.
9
+ *
10
+ * The Token Service can disburse small native-gas grants to the user's primary
11
+ * linked Data Wallet so on-chain operations (-b tokenization, -ts timestamp,
12
+ * -ots) can pay for gas. The recipient is server-authoritative — a client may
13
+ * only request a grant, never redirect it.
14
+ *
15
+ * GET /funding/policy?chainId=<id> (no auth)
16
+ * GET /funding/status?chainId=<id> (Bearer)
17
+ * POST /funding/request (Bearer, optional Idempotency-Key)
18
+ */
19
+ const recipient_lookup_1 = require("../archive/recipient-lookup");
20
+ const token_service_fetch_1 = require("../util/token-service-fetch");
21
+ const token_auth_1 = require("../connection/token-auth");
22
+ /** Thrown when the Token Service does not expose the funding endpoints (older deployment). */
23
+ class FundingUnavailableError extends Error {
24
+ constructor(message = "Token Service does not support funding") {
25
+ super(message);
26
+ this.name = "FundingUnavailableError";
27
+ }
28
+ }
29
+ exports.FundingUnavailableError = FundingUnavailableError;
30
+ async function safeJson(response) {
31
+ const ct = response.headers.get("content-type") || "";
32
+ if (!ct.includes("json"))
33
+ return null;
34
+ try {
35
+ return (await response.json());
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ function extractError(parsed, fallback, options) {
42
+ const authHint = options?.status != null
43
+ ? (0, token_auth_1.tokenServiceAuthErrorMessage)(options.status, options.email)
44
+ : null;
45
+ if (authHint)
46
+ return authHint;
47
+ if (parsed && typeof parsed === "object") {
48
+ const p = parsed;
49
+ if (typeof p.error === "string")
50
+ return p.error;
51
+ if (typeof p.message === "string")
52
+ return p.message;
53
+ }
54
+ return fallback;
55
+ }
56
+ function baseUrlFor(baseUrl) {
57
+ return (0, recipient_lookup_1.resolveTokenServiceBaseUrl)({ tokenServiceUrl: baseUrl });
58
+ }
59
+ async function getFundingPolicy(baseUrl, chainId) {
60
+ const url = baseUrlFor(baseUrl);
61
+ let res;
62
+ try {
63
+ res = await fetch(`${url}/funding/policy?chainId=${encodeURIComponent(String(chainId))}`, {
64
+ method: "GET",
65
+ });
66
+ }
67
+ catch (err) {
68
+ throw new Error((0, token_service_fetch_1.formatTokenServiceFetchError)(url, err));
69
+ }
70
+ if (res.status === 404) {
71
+ throw new FundingUnavailableError();
72
+ }
73
+ const parsed = await safeJson(res);
74
+ if (!res.ok || !parsed || parsed.success !== true) {
75
+ throw new Error(extractError(parsed, `Funding policy lookup failed (HTTP ${res.status})`));
76
+ }
77
+ const policy = parsed.policy;
78
+ if (!policy) {
79
+ throw new Error("Funding policy response missing policy");
80
+ }
81
+ return {
82
+ chainId: typeof parsed.chainId === "number" ? parsed.chainId : chainId,
83
+ network: typeof parsed.network === "string" ? parsed.network : "",
84
+ policy,
85
+ };
86
+ }
87
+ async function getFundingStatus(baseUrl, accessToken, chainId) {
88
+ const url = baseUrlFor(baseUrl);
89
+ let res;
90
+ try {
91
+ res = await fetch(`${url}/funding/status?chainId=${encodeURIComponent(String(chainId))}`, {
92
+ method: "GET",
93
+ headers: { Authorization: `Bearer ${accessToken}` },
94
+ });
95
+ }
96
+ catch (err) {
97
+ throw new Error((0, token_service_fetch_1.formatTokenServiceFetchError)(url, err));
98
+ }
99
+ if (res.status === 404) {
100
+ throw new FundingUnavailableError();
101
+ }
102
+ const parsed = await safeJson(res);
103
+ if (!res.ok || !parsed || parsed.success !== true) {
104
+ throw new Error(extractError(parsed, `Funding status lookup failed (HTTP ${res.status})`, {
105
+ status: res.status,
106
+ }));
107
+ }
108
+ return {
109
+ chainId: typeof parsed.chainId === "number" ? parsed.chainId : chainId,
110
+ recipientAddress: typeof parsed.recipientAddress === "string" ? parsed.recipientAddress : null,
111
+ enabled: parsed.enabled === true,
112
+ requiresPayment: parsed.requiresPayment === true,
113
+ lastGrantAt: typeof parsed.lastGrantAt === "string" ? parsed.lastGrantAt : null,
114
+ nextEligibleAt: typeof parsed.nextEligibleAt === "string" ? parsed.nextEligibleAt : null,
115
+ recentGrants: Array.isArray(parsed.recentGrants)
116
+ ? parsed.recentGrants
117
+ : [],
118
+ };
119
+ }
120
+ async function requestFundingGrant(baseUrl, accessToken, chainId, idempotencyKey) {
121
+ const url = baseUrlFor(baseUrl);
122
+ const headers = {
123
+ Authorization: `Bearer ${accessToken}`,
124
+ "content-type": "application/json",
125
+ };
126
+ if (idempotencyKey) {
127
+ headers["Idempotency-Key"] = idempotencyKey;
128
+ }
129
+ let res;
130
+ try {
131
+ res = await fetch(`${url}/funding/request`, {
132
+ method: "POST",
133
+ headers,
134
+ body: JSON.stringify({ chainId }),
135
+ });
136
+ }
137
+ catch (err) {
138
+ throw new Error((0, token_service_fetch_1.formatTokenServiceFetchError)(url, err));
139
+ }
140
+ if (res.status === 404) {
141
+ throw new FundingUnavailableError();
142
+ }
143
+ const parsed = await safeJson(res);
144
+ if (!parsed) {
145
+ // Auth failures and other non-JSON responses.
146
+ throw new Error((0, token_auth_1.tokenServiceAuthErrorMessage)(res.status, null) ??
147
+ `Funding request failed (HTTP ${res.status})`);
148
+ }
149
+ return parsed;
150
+ }
151
+ //# sourceMappingURL=token-service-funding.js.map