@0xdivyanshh/tab-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/client.d.ts +48 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +140 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +62 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/receipts.d.ts +81 -0
- package/dist/receipts.d.ts.map +1 -0
- package/dist/receipts.js +309 -0
- package/dist/receipts.js.map +1 -0
- package/dist/spend.d.ts +22 -0
- package/dist/spend.d.ts.map +1 -0
- package/dist/spend.js +185 -0
- package/dist/spend.js.map +1 -0
- package/dist/types.d.ts +324 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @0xdivyanshh/tab-sdk
|
|
2
|
+
|
|
3
|
+
**Tier 3 · PUBLISHED to npm · thin HTTP client · browser-safe**
|
|
4
|
+
|
|
5
|
+
The TypeScript client every other surface is built on: `agentkit-plugin`, `mcp`, `cli`,
|
|
6
|
+
`dashboard`, and both demo agents.
|
|
7
|
+
|
|
8
|
+
## Thin on purpose
|
|
9
|
+
|
|
10
|
+
`boundaries.json` forbids `@hiero-ledger/sdk`, `ioredis` and `drizzle-orm` here. This package
|
|
11
|
+
speaks HTTP to the gateway and nothing else.
|
|
12
|
+
|
|
13
|
+
That constraint carries the product claim. The agent holds no key and signs nothing — so the
|
|
14
|
+
library it installs should not even be *able* to sign. If the SDK bundled the Hedera SDK, the
|
|
15
|
+
claim would rest on us not having used it. This way it rests on a check anyone can run.
|
|
16
|
+
|
|
17
|
+
Browser-safe matters too: `apps/web` imports this, and a browser bundle must not be able to
|
|
18
|
+
reach a signing path or a database driver.
|
|
19
|
+
|
|
20
|
+
## Surface
|
|
21
|
+
|
|
22
|
+
`spend` · `quote` · `balance` · `ceiling` · `receipts` · `register`
|
|
23
|
+
|
|
24
|
+
The same five verbs appear in the Agent Kit plugin and the MCP server. Define them once here.
|
|
25
|
+
|
|
26
|
+
## Contents
|
|
27
|
+
|
|
28
|
+
| File | Holds |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `src/client.ts` | constructor, auth, retry, timeouts |
|
|
31
|
+
| `src/spend.ts` | the spend call, including the refusal shape |
|
|
32
|
+
| `src/quote.ts` | pre-flight quote without reserving |
|
|
33
|
+
| `src/state.ts` | balance, ceiling, available, pending holds, window countdown |
|
|
34
|
+
| `src/receipts.ts` | receipt history and the SSE stream the dashboard consumes |
|
|
35
|
+
| `src/errors.ts` | typed errors — refusal, unavailable, invalid |
|
|
36
|
+
| `src/types.ts` | re-exported from `@0xdivyanshh/tab-protocol`. One definition, not two |
|
|
37
|
+
|
|
38
|
+
## Invariants
|
|
39
|
+
|
|
40
|
+
- **A refusal is a value, not an exception.** `spend()` returns a discriminated result carrying
|
|
41
|
+
the rule that fired. Throwing on refusal pushes every consumer into `try/catch` and makes the
|
|
42
|
+
Refusals view harder to build — and refusal is the demo, so it deserves a first-class type.
|
|
43
|
+
Throw only for transport and protocol failures.
|
|
44
|
+
- **Amounts cross the wire as decimal strings**, parsed to `MicroUsdc` on the way in. `bigint`
|
|
45
|
+
does not survive `JSON.stringify`.
|
|
46
|
+
- **Types are re-exported from `@0xdivyanshh/tab-protocol`, never redefined.** A second copy will drift.
|
|
47
|
+
- **Retries are safe.** `spend` carries an idempotency key so a network retry cannot double-spend.
|
|
48
|
+
- **No key material in the constructor.** If the SDK ever accepts a private key, the whole claim
|
|
49
|
+
is gone.
|
|
50
|
+
|
|
51
|
+
## Publishing
|
|
52
|
+
|
|
53
|
+
Versioned with changesets. Once an agent depends on this, breaking changes cost someone a
|
|
54
|
+
redeploy — so treat exports as a contract from the first release.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HTTP client.
|
|
3
|
+
*
|
|
4
|
+
* Thin on purpose. `boundaries.json` forbids `@hiero-ledger/sdk`, `ioredis` and
|
|
5
|
+
* `drizzle-orm` here, and that constraint carries the product claim: the agent
|
|
6
|
+
* holds no key and signs nothing, so the library it installs should not even be
|
|
7
|
+
* ABLE to sign. If this bundled the Hedera SDK the claim would rest on us not
|
|
8
|
+
* having used it; this way it rests on a check anyone can run.
|
|
9
|
+
*
|
|
10
|
+
* Browser-safe for the same reason — `apps/web` imports this, and a browser
|
|
11
|
+
* bundle must not be able to reach a signing path or a database driver.
|
|
12
|
+
*/
|
|
13
|
+
export interface TabClientConfig {
|
|
14
|
+
/** The gateway's base URL. */
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
/**
|
|
17
|
+
* Bearer token, if the deployment requires one.
|
|
18
|
+
*
|
|
19
|
+
* NOT a private key, and there is deliberately no way to pass one. If this
|
|
20
|
+
* constructor ever accepts key material the whole claim is gone.
|
|
21
|
+
*/
|
|
22
|
+
token?: string;
|
|
23
|
+
/** Per-request timeout. Default 120s — a spend waits on x402 settlement. */
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
/** Retries for transport failures only. Default 2. */
|
|
26
|
+
maxRetries?: number;
|
|
27
|
+
/** Injectable for tests and for runtimes with a non-global fetch. */
|
|
28
|
+
fetch?: typeof globalThis.fetch;
|
|
29
|
+
}
|
|
30
|
+
export declare class TabClient {
|
|
31
|
+
private readonly baseUrl;
|
|
32
|
+
private readonly token?;
|
|
33
|
+
private readonly timeoutMs;
|
|
34
|
+
private readonly maxRetries;
|
|
35
|
+
private readonly doFetch;
|
|
36
|
+
constructor(config: TabClientConfig);
|
|
37
|
+
/**
|
|
38
|
+
* One request, with retries for transport failures only.
|
|
39
|
+
*
|
|
40
|
+
* A 4xx or 5xx is NOT retried. The gateway answered — retrying an answer we
|
|
41
|
+
* did not like is how a refused spend becomes six refused spends, and how a
|
|
42
|
+
* 500 mid-settlement becomes a double payment. Only a thrown fetch (DNS,
|
|
43
|
+
* connection reset, timeout) is retried, and only because in that case the
|
|
44
|
+
* caller has no answer at all.
|
|
45
|
+
*/
|
|
46
|
+
request<T>(method: 'GET' | 'POST', path: string, body?: unknown): Promise<T>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAChC;AAeD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;gBAErC,MAAM,EAAE,eAAe;IA4BnC;;;;;;;;OAQG;IACG,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;CA+FnF"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { TabProtocolError, TabUnavailableError } from "./errors.js";
|
|
2
|
+
const DEFAULTS = {
|
|
3
|
+
/*
|
|
4
|
+
* 120 seconds, which looks absurd for an HTTP client and is not.
|
|
5
|
+
*
|
|
6
|
+
* A spend waits on an x402 HTS settlement, measured at 25-39s end to end,
|
|
7
|
+
* plus a hold write awaiting consensus. A 30s default would time out on
|
|
8
|
+
* perfectly healthy spends and the caller would retry — against a gateway
|
|
9
|
+
* that had already taken the hold.
|
|
10
|
+
*/
|
|
11
|
+
timeoutMs: 120_000,
|
|
12
|
+
maxRetries: 2,
|
|
13
|
+
};
|
|
14
|
+
export class TabClient {
|
|
15
|
+
baseUrl;
|
|
16
|
+
token;
|
|
17
|
+
timeoutMs;
|
|
18
|
+
maxRetries;
|
|
19
|
+
doFetch;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
// Trailing slash removed once, here, so every path can be written `/v1/...`
|
|
22
|
+
// without a caller having to know whether it will be doubled.
|
|
23
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, '');
|
|
24
|
+
if (config.token)
|
|
25
|
+
this.token = config.token;
|
|
26
|
+
this.timeoutMs = config.timeoutMs ?? DEFAULTS.timeoutMs;
|
|
27
|
+
this.maxRetries = config.maxRetries ?? DEFAULTS.maxRetries;
|
|
28
|
+
/*
|
|
29
|
+
* BOUND to globalThis, and that bind is load-bearing in a browser.
|
|
30
|
+
*
|
|
31
|
+
* `fetch` is a method on Window, and the spec requires it to be called with
|
|
32
|
+
* a Window receiver. Stored bare and invoked as `this.doFetch(...)`, the
|
|
33
|
+
* receiver becomes this client instance and the browser throws
|
|
34
|
+
*
|
|
35
|
+
* TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
36
|
+
*
|
|
37
|
+
* before a single byte leaves the machine. Node's fetch has no such
|
|
38
|
+
* requirement, so every test here and every server-side caller passed while
|
|
39
|
+
* the console failed on EVERY request — and failed as a transport error,
|
|
40
|
+
* which reads exactly like an unreachable gateway. It cost hours of
|
|
41
|
+
* chasing CORS and cold starts that were never involved.
|
|
42
|
+
*
|
|
43
|
+
* An INJECTED fetch is used as given: it is the caller's function and
|
|
44
|
+
* binding it to globalThis would be us rewriting their receiver.
|
|
45
|
+
*/
|
|
46
|
+
this.doFetch = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One request, with retries for transport failures only.
|
|
50
|
+
*
|
|
51
|
+
* A 4xx or 5xx is NOT retried. The gateway answered — retrying an answer we
|
|
52
|
+
* did not like is how a refused spend becomes six refused spends, and how a
|
|
53
|
+
* 500 mid-settlement becomes a double payment. Only a thrown fetch (DNS,
|
|
54
|
+
* connection reset, timeout) is retried, and only because in that case the
|
|
55
|
+
* caller has no answer at all.
|
|
56
|
+
*/
|
|
57
|
+
async request(method, path, body) {
|
|
58
|
+
const url = `${this.baseUrl}${path}`;
|
|
59
|
+
let lastError;
|
|
60
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
63
|
+
try {
|
|
64
|
+
const response = await this.doFetch(url, {
|
|
65
|
+
method,
|
|
66
|
+
headers: {
|
|
67
|
+
'content-type': 'application/json',
|
|
68
|
+
...(this.token ? { authorization: `Bearer ${this.token}` } : {}),
|
|
69
|
+
},
|
|
70
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
71
|
+
signal: controller.signal,
|
|
72
|
+
});
|
|
73
|
+
const text = await response.text();
|
|
74
|
+
let parsed;
|
|
75
|
+
try {
|
|
76
|
+
parsed = text.length > 0 ? JSON.parse(text) : null;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new TabProtocolError(`The gateway returned ${response.status} with a body that is not JSON`, response.status, text.slice(0, 512));
|
|
80
|
+
}
|
|
81
|
+
/*
|
|
82
|
+
* A REFUSAL comes back 200 with `{ refused: ... }`, so it lands here as
|
|
83
|
+
* a normal response and the caller gets a value. A non-2xx really is a
|
|
84
|
+
* protocol failure — the gateway could not answer the question.
|
|
85
|
+
*/
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new TabProtocolError(`The gateway returned ${response.status}`, response.status, parsed);
|
|
88
|
+
}
|
|
89
|
+
return parsed;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error instanceof TabProtocolError)
|
|
93
|
+
throw error;
|
|
94
|
+
lastError = error;
|
|
95
|
+
// Backoff only between attempts, never after the last one.
|
|
96
|
+
if (attempt < this.maxRetries) {
|
|
97
|
+
await new Promise((resolve) => setTimeout(resolve, 250 * 2 ** attempt));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/*
|
|
105
|
+
* The outcome is UNKNOWN, and saying so is the whole point of this message.
|
|
106
|
+
*
|
|
107
|
+
* The first draft said "nothing was spent", which is false and dangerously
|
|
108
|
+
* reassuring: a timeout can mean the gateway took the hold, paid the seller,
|
|
109
|
+
* and the RESPONSE was lost. A client that tells a caller it is safe to
|
|
110
|
+
* retry blindly is how one spend becomes two.
|
|
111
|
+
*
|
|
112
|
+
* The idempotency key is what makes a retry safe, so the caller is told to
|
|
113
|
+
* reuse it rather than told not to worry.
|
|
114
|
+
*/
|
|
115
|
+
/*
|
|
116
|
+
* The CAUSE is named in the message, not only attached as `cause`.
|
|
117
|
+
*
|
|
118
|
+
* "Could not reach the gateway" is true of a CORS rejection, a DNS
|
|
119
|
+
* failure, a refused connection and a timeout alike — and those have
|
|
120
|
+
* completely different fixes. The distinguishing detail was being carried
|
|
121
|
+
* on a property nothing displays, so a console showing this error sent us
|
|
122
|
+
* hunting the wrong problem more than once.
|
|
123
|
+
*
|
|
124
|
+
* An AbortError here is always OUR timeout firing, so it is named as one:
|
|
125
|
+
* "aborted" reads like a cancelled request and hides the fact that a
|
|
126
|
+
* deadline was exceeded.
|
|
127
|
+
*/
|
|
128
|
+
const because = lastError instanceof Error
|
|
129
|
+
? lastError.name === 'AbortError' || lastError.name === 'TimeoutError'
|
|
130
|
+
? `timed out after ${this.timeoutMs}ms`
|
|
131
|
+
: `${lastError.name}: ${lastError.message}`
|
|
132
|
+
: String(lastError);
|
|
133
|
+
throw new TabUnavailableError(`Could not reach the Tab gateway at ${url} after ${this.maxRetries + 1} attempt(s) ` +
|
|
134
|
+
`(${because}). ` +
|
|
135
|
+
'The outcome is UNKNOWN — a transport failure cannot distinguish "never arrived" from ' +
|
|
136
|
+
'"succeeded and the response was lost". Retry with the SAME idempotencyKey: the gateway ' +
|
|
137
|
+
'treats it as the hold id, so a repeat cannot double-spend. Do not retry with a new key.', lastError);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors — and the one thing that is deliberately NOT an error.
|
|
3
|
+
*
|
|
4
|
+
* **A refusal is a value, not an exception.** `spend()` returns a discriminated
|
|
5
|
+
* result carrying the rule that fired. Throwing on refusal would push every
|
|
6
|
+
* consumer into `try/catch`, and refusal is the product demonstrating that
|
|
7
|
+
* underwriting works — it deserves a first-class type, not a control-flow
|
|
8
|
+
* escape.
|
|
9
|
+
*
|
|
10
|
+
* These throw only for transport and protocol failures: the gateway was
|
|
11
|
+
* unreachable, or it answered something this client cannot interpret.
|
|
12
|
+
*/
|
|
13
|
+
/** The gateway could not be reached, or did not answer in time. */
|
|
14
|
+
export declare class TabUnavailableError extends Error {
|
|
15
|
+
readonly kind: "unavailable";
|
|
16
|
+
readonly reason: unknown;
|
|
17
|
+
constructor(message: string, reason?: unknown);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The gateway answered, but not with something this client understands.
|
|
21
|
+
*
|
|
22
|
+
* Carries the status and the raw body. A caller debugging a version mismatch
|
|
23
|
+
* needs to see what actually came back — "invalid response" with the evidence
|
|
24
|
+
* discarded is the least useful error a client can raise.
|
|
25
|
+
*/
|
|
26
|
+
export declare class TabProtocolError extends Error {
|
|
27
|
+
readonly kind: "protocol";
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly body: unknown;
|
|
30
|
+
constructor(message: string, status: number, body: unknown);
|
|
31
|
+
}
|
|
32
|
+
/** A caller mistake — a malformed amount, a missing tab id. */
|
|
33
|
+
export declare class TabInvalidError extends Error {
|
|
34
|
+
readonly kind: "invalid";
|
|
35
|
+
constructor(message: string);
|
|
36
|
+
}
|
|
37
|
+
export type TabError = TabUnavailableError | TabProtocolError | TabInvalidError;
|
|
38
|
+
export declare function isTabError(error: unknown): error is TabError;
|
|
39
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mEAAmE;AACnE,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAG,aAAa,CAAS;IAStC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;gBACZ,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO;CAK9C;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAS;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;gBACV,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;CAM3D;AAED,+DAA+D;AAC/D,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAS;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,QAAQ,GAAG,mBAAmB,GAAG,gBAAgB,GAAG,eAAe,CAAA;AAE/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAM5D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors — and the one thing that is deliberately NOT an error.
|
|
3
|
+
*
|
|
4
|
+
* **A refusal is a value, not an exception.** `spend()` returns a discriminated
|
|
5
|
+
* result carrying the rule that fired. Throwing on refusal would push every
|
|
6
|
+
* consumer into `try/catch`, and refusal is the product demonstrating that
|
|
7
|
+
* underwriting works — it deserves a first-class type, not a control-flow
|
|
8
|
+
* escape.
|
|
9
|
+
*
|
|
10
|
+
* These throw only for transport and protocol failures: the gateway was
|
|
11
|
+
* unreachable, or it answered something this client cannot interpret.
|
|
12
|
+
*/
|
|
13
|
+
/** The gateway could not be reached, or did not answer in time. */
|
|
14
|
+
export class TabUnavailableError extends Error {
|
|
15
|
+
kind = 'unavailable';
|
|
16
|
+
/*
|
|
17
|
+
* Fields declared and assigned, not TS parameter properties.
|
|
18
|
+
*
|
|
19
|
+
* `erasableSyntaxOnly` is on across the repo so Node can run the TypeScript
|
|
20
|
+
* directly with `--experimental-strip-types`, and parameter properties are
|
|
21
|
+
* not erasable — they generate assignments. The constraint is repo-wide; see
|
|
22
|
+
* HANDOFF.
|
|
23
|
+
*/
|
|
24
|
+
reason;
|
|
25
|
+
constructor(message, reason) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = 'TabUnavailableError';
|
|
28
|
+
this.reason = reason;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The gateway answered, but not with something this client understands.
|
|
33
|
+
*
|
|
34
|
+
* Carries the status and the raw body. A caller debugging a version mismatch
|
|
35
|
+
* needs to see what actually came back — "invalid response" with the evidence
|
|
36
|
+
* discarded is the least useful error a client can raise.
|
|
37
|
+
*/
|
|
38
|
+
export class TabProtocolError extends Error {
|
|
39
|
+
kind = 'protocol';
|
|
40
|
+
status;
|
|
41
|
+
body;
|
|
42
|
+
constructor(message, status, body) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'TabProtocolError';
|
|
45
|
+
this.status = status;
|
|
46
|
+
this.body = body;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** A caller mistake — a malformed amount, a missing tab id. */
|
|
50
|
+
export class TabInvalidError extends Error {
|
|
51
|
+
kind = 'invalid';
|
|
52
|
+
constructor(message) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.name = 'TabInvalidError';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function isTabError(error) {
|
|
58
|
+
return (error instanceof TabUnavailableError ||
|
|
59
|
+
error instanceof TabProtocolError ||
|
|
60
|
+
error instanceof TabInvalidError);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mEAAmE;AACnE,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,IAAI,GAAG,aAAsB,CAAA;IACtC;;;;;;;OAOG;IACM,MAAM,CAAS;IACxB,YAAY,OAAe,EAAE,MAAgB;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,GAAG,UAAmB,CAAA;IAC1B,MAAM,CAAQ;IACd,IAAI,CAAS;IACtB,YAAY,OAAe,EAAE,MAAc,EAAE,IAAa;QACxD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AAED,+DAA+D;AAC/D,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,IAAI,GAAG,SAAkB,CAAA;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;IAC/B,CAAC;CACF;AAID,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,CACL,KAAK,YAAY,mBAAmB;QACpC,KAAK,YAAY,gBAAgB;QACjC,KAAK,YAAY,eAAe,CACjC,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @0xdivyanshh/tab-sdk — the client every other surface is built on.
|
|
3
|
+
*
|
|
4
|
+
* Tier 3. Published, thin, browser-safe. `boundaries.json` forbids
|
|
5
|
+
* `@hiero-ledger/sdk`, `ioredis` and `drizzle-orm` here, and that constraint
|
|
6
|
+
* carries the product claim: the agent holds no key and signs nothing, so the
|
|
7
|
+
* library it installs should not even be ABLE to sign.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const tab = createTab({ baseUrl: 'http://localhost:8080' })
|
|
11
|
+
* const result = await tab.spend({ tab: '0.0.x', url: seller, max: usdc('0.040000') })
|
|
12
|
+
* if (result.outcome === 'refused') console.log(result.rule, result.guidance)
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* **A refusal is a value, not an exception.** That is the one thing to know
|
|
16
|
+
* before using this.
|
|
17
|
+
*/
|
|
18
|
+
import type { MicroUsdc } from '@0xdivyanshh/tab-money';
|
|
19
|
+
import { type TabClientConfig } from './client.ts';
|
|
20
|
+
import { health } from './receipts.ts';
|
|
21
|
+
import type { CeilingView, CounterpartyWeight, Hold, Quote, ReceiptRow, SettlementView, SpendRequest, SpendResult, TabList, TabState } from './types.ts';
|
|
22
|
+
export interface Tab {
|
|
23
|
+
spend(request: SpendRequest): Promise<SpendResult>;
|
|
24
|
+
quote(params: {
|
|
25
|
+
tab: string;
|
|
26
|
+
max: MicroUsdc;
|
|
27
|
+
}): Promise<Quote>;
|
|
28
|
+
state(tab: string): Promise<TabState>;
|
|
29
|
+
holds(tab: string): Promise<Hold[]>;
|
|
30
|
+
receipts(tab: string): Promise<ReceiptRow[]>;
|
|
31
|
+
counterparties(tab: string): Promise<CounterpartyWeight[]>;
|
|
32
|
+
/** The ceiling in force, its arithmetic, and the series behind it. */
|
|
33
|
+
ceiling(tab: string): Promise<CeilingView>;
|
|
34
|
+
/** Settled windows, ascending by window. */
|
|
35
|
+
settlements(tab: string): Promise<SettlementView[]>;
|
|
36
|
+
/** The tabs this gateway knows about. NOT a registry — see `TabList`. */
|
|
37
|
+
tabs(): Promise<TabList>;
|
|
38
|
+
health(): Promise<Awaited<ReturnType<typeof health>>>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The ten verbs, bound to one client.
|
|
42
|
+
*
|
|
43
|
+
* Object-with-methods rather than loose functions because the same surface
|
|
44
|
+
* appears in the Agent Kit plugin, the MCP server and the CLI — defining it
|
|
45
|
+
* once, here, is what stops those three drifting apart.
|
|
46
|
+
*
|
|
47
|
+
* Two of the ten (`spend`, `quote`) act. The other eight only read, and every
|
|
48
|
+
* one of them reads what was PUBLISHED rather than recomputing it: this package
|
|
49
|
+
* cannot import `@0xdivyanshh/tab-scoring` or `@0xdivyanshh/tab-graph`, so it is structurally incapable
|
|
50
|
+
* of offering a second opinion about a ceiling or a weight. That is the point.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createTab(config: TabClientConfig): Tab;
|
|
53
|
+
export type { WeightReason } from '@0xdivyanshh/tab-protocol';
|
|
54
|
+
export { TabClient, type TabClientConfig } from './client.ts';
|
|
55
|
+
export { isTabError, type TabError, TabInvalidError, TabProtocolError, TabUnavailableError, } from './errors.ts';
|
|
56
|
+
export { ceiling, counterparties, health, holds, receipts, settlements, tabs } from './receipts.ts';
|
|
57
|
+
export { parseAmount, quote, spend, state } from './spend.ts';
|
|
58
|
+
export type { CeilingInputsView, CeilingView, CounterpartyWeight, Hold, PublishedCeilingView, Quote, ReceiptLeg, ReceiptRow, RefusalCode, SettlementView, SpendFailed, SpendPaid, SpendRefused, SpendRequest, SpendResult, TabList, TabState, TabSummary, } from './types.ts';
|
|
59
|
+
export { BLOCKING_REASONS, isBlocking, isRetryable, REFUSAL_CODES, REFUSAL_GUIDANCE, WEIGHT_REASON_DETAIL, WEIGHT_REASONS, } from './types.ts';
|
|
60
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAA2B,MAAM,EAAsC,MAAM,eAAe,CAAA;AAEnG,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,IAAI,EACJ,KAAK,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,OAAO,EACP,QAAQ,EACT,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,GAAG;IAClB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAClD,KAAK,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IAC9D,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACrC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;IAC5C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAA;IAC1D,sEAAsE;IACtE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAC1C,4CAA4C;IAC5C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;IACnD,yEAAyE;IACzE,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACxB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAA;CACtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,GAAG,CActD;AAID,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EACL,UAAU,EACV,KAAK,QAAQ,EACb,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACnG,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC7D,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,kBAAkB,EAClB,IAAI,EACJ,oBAAoB,EACpB,KAAK,EACL,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,OAAO,EACP,QAAQ,EACR,UAAU,GACX,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,GACf,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @0xdivyanshh/tab-sdk — the client every other surface is built on.
|
|
3
|
+
*
|
|
4
|
+
* Tier 3. Published, thin, browser-safe. `boundaries.json` forbids
|
|
5
|
+
* `@hiero-ledger/sdk`, `ioredis` and `drizzle-orm` here, and that constraint
|
|
6
|
+
* carries the product claim: the agent holds no key and signs nothing, so the
|
|
7
|
+
* library it installs should not even be ABLE to sign.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const tab = createTab({ baseUrl: 'http://localhost:8080' })
|
|
11
|
+
* const result = await tab.spend({ tab: '0.0.x', url: seller, max: usdc('0.040000') })
|
|
12
|
+
* if (result.outcome === 'refused') console.log(result.rule, result.guidance)
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* **A refusal is a value, not an exception.** That is the one thing to know
|
|
16
|
+
* before using this.
|
|
17
|
+
*/
|
|
18
|
+
import { TabClient } from "./client.js";
|
|
19
|
+
import { ceiling, counterparties, health, holds, receipts, settlements, tabs } from "./receipts.js";
|
|
20
|
+
import { quote, spend, state } from "./spend.js";
|
|
21
|
+
/**
|
|
22
|
+
* The ten verbs, bound to one client.
|
|
23
|
+
*
|
|
24
|
+
* Object-with-methods rather than loose functions because the same surface
|
|
25
|
+
* appears in the Agent Kit plugin, the MCP server and the CLI — defining it
|
|
26
|
+
* once, here, is what stops those three drifting apart.
|
|
27
|
+
*
|
|
28
|
+
* Two of the ten (`spend`, `quote`) act. The other eight only read, and every
|
|
29
|
+
* one of them reads what was PUBLISHED rather than recomputing it: this package
|
|
30
|
+
* cannot import `@0xdivyanshh/tab-scoring` or `@0xdivyanshh/tab-graph`, so it is structurally incapable
|
|
31
|
+
* of offering a second opinion about a ceiling or a weight. That is the point.
|
|
32
|
+
*/
|
|
33
|
+
export function createTab(config) {
|
|
34
|
+
const client = new TabClient(config);
|
|
35
|
+
return {
|
|
36
|
+
spend: (request) => spend(client, request),
|
|
37
|
+
quote: (params) => quote(client, params),
|
|
38
|
+
state: (tab) => state(client, tab),
|
|
39
|
+
holds: (tab) => holds(client, tab),
|
|
40
|
+
receipts: (tab) => receipts(client, tab),
|
|
41
|
+
counterparties: (tab) => counterparties(client, tab),
|
|
42
|
+
ceiling: (tab) => ceiling(client, tab),
|
|
43
|
+
settlements: (tab) => settlements(client, tab),
|
|
44
|
+
tabs: () => tabs(client),
|
|
45
|
+
health: () => health(client),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export { TabClient } from "./client.js";
|
|
49
|
+
export { isTabError, TabInvalidError, TabProtocolError, TabUnavailableError, } from "./errors.js";
|
|
50
|
+
export { ceiling, counterparties, health, holds, receipts, settlements, tabs } from "./receipts.js";
|
|
51
|
+
export { parseAmount, quote, spend, state } from "./spend.js";
|
|
52
|
+
export { BLOCKING_REASONS, isBlocking, isRetryable, REFUSAL_CODES, REFUSAL_GUIDANCE, WEIGHT_REASON_DETAIL, WEIGHT_REASONS, } from "./types.js";
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,SAAS,EAAwB,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACnG,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AA8BhD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,MAAuB;IAC/C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAA;IACpC,OAAO;QACL,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;QAC1C,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;QACxC,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;QAClC,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;QAClC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;QACxC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC;QACpD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;QACtC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC;QAC9C,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;QACxB,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;KAC7B,CAAA;AACH,CAAC;AAKD,OAAO,EAAE,SAAS,EAAwB,MAAM,aAAa,CAAA;AAC7D,OAAO,EACL,UAAU,EAEV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACnG,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAqB7D,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,GACf,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { TabClient } from './client.ts';
|
|
2
|
+
import type { CeilingView, CounterpartyWeight, Hold, ReceiptRow, SettlementView, TabList } from './types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Receipt history and pending holds.
|
|
5
|
+
*
|
|
6
|
+
* Both read the gateway's projection rather than HCS directly, because this
|
|
7
|
+
* package must stay browser-safe and a browser has no business walking a topic.
|
|
8
|
+
* A consumer that wants to verify rather than display should run
|
|
9
|
+
* `pnpm verify-tab`, which replays the topic itself and trusts nothing we say.
|
|
10
|
+
*/
|
|
11
|
+
export declare function holds(client: TabClient, tab: string): Promise<Hold[]>;
|
|
12
|
+
export declare function receipts(client: TabClient, tab: string): Promise<ReceiptRow[]>;
|
|
13
|
+
/** Is the gateway up, and which network and window is it on? */
|
|
14
|
+
export declare function health(client: TabClient): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
network: string;
|
|
17
|
+
token: string;
|
|
18
|
+
window: number;
|
|
19
|
+
demoMode: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The HCS topics this gateway is actually reading.
|
|
22
|
+
*
|
|
23
|
+
* Served so a reader can go and check for themselves, and taken from the
|
|
24
|
+
* gateway rather than from the consumer's own config so the two cannot
|
|
25
|
+
* disagree — a "view on HashScan" link that points somewhere other than the
|
|
26
|
+
* data it sits beside is worse than no link.
|
|
27
|
+
*
|
|
28
|
+
* Absent from an older gateway that did not serve them, in which case a
|
|
29
|
+
* caller should show no link rather than guess at one.
|
|
30
|
+
*/
|
|
31
|
+
topics?: {
|
|
32
|
+
receipts: string;
|
|
33
|
+
ceilings: string;
|
|
34
|
+
settlements: string;
|
|
35
|
+
};
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* Published independence weights for a tab's counterparties.
|
|
39
|
+
*
|
|
40
|
+
* Reason codes are VALIDATED against `WEIGHT_REASONS`, not cast — an unknown
|
|
41
|
+
* reason from a newer server is dropped rather than typed as a real one, for
|
|
42
|
+
* the same reason an unknown refusal code is: the console would otherwise
|
|
43
|
+
* render a rule that does not exist, and `isBlocking` would answer confidently
|
|
44
|
+
* about it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function counterparties(client: TabClient, tab: string): Promise<CounterpartyWeight[]>;
|
|
47
|
+
/**
|
|
48
|
+
* The ceiling in force, its arithmetic, and the series behind it.
|
|
49
|
+
*
|
|
50
|
+
* Read from what the ENGINE published, never recomputed — the SDK is
|
|
51
|
+
* browser-safe and cannot import `@0xdivyanshh/tab-scoring`, and that is the right
|
|
52
|
+
* constraint. A client that recomputed the ceiling would hand a viewer a second
|
|
53
|
+
* answer to compare against the topic, and two answers is worse than one even
|
|
54
|
+
* when they agree.
|
|
55
|
+
*
|
|
56
|
+
* `published: false` is not an error. It means the engine has not run for this
|
|
57
|
+
* tab yet and the starter ceiling is in force — `enforced` says what that is.
|
|
58
|
+
*/
|
|
59
|
+
export declare function ceiling(client: TabClient, tab: string): Promise<CeilingView>;
|
|
60
|
+
/**
|
|
61
|
+
* Settled windows, ascending by window.
|
|
62
|
+
*
|
|
63
|
+
* Ordered by WINDOW rather than by arrival: a repaired or late settlement lands
|
|
64
|
+
* on the topic after the windows that follow it, and a table sorted by
|
|
65
|
+
* timestamp would put window 41 above window 39 with no explanation.
|
|
66
|
+
*
|
|
67
|
+
* The gross legs come through as absent when the topic did not carry them. A
|
|
68
|
+
* caller must render that as "not published", never as zero.
|
|
69
|
+
*/
|
|
70
|
+
export declare function settlements(client: TabClient, tab: string): Promise<SettlementView[]>;
|
|
71
|
+
/**
|
|
72
|
+
* The tabs this gateway knows about.
|
|
73
|
+
*
|
|
74
|
+
* Named `tabs`, not `registry`, and the response carries
|
|
75
|
+
* `registrationEnforced: false` so a caller cannot mistake it for one. Nothing
|
|
76
|
+
* writes a `register` message yet — one Starter Tab per funding root is
|
|
77
|
+
* unenforced and the README labels it OPEN — so a tab appears here the first
|
|
78
|
+
* time it spends or earns, and there is no registration time to report.
|
|
79
|
+
*/
|
|
80
|
+
export declare function tabs(client: TabClient): Promise<TabList>;
|
|
81
|
+
//# sourceMappingURL=receipts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipts.d.ts","sourceRoot":"","sources":["../src/receipts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAG5C,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,IAAI,EAEJ,UAAU,EACV,cAAc,EACd,OAAO,EAER,MAAM,YAAY,CAAA;AAenB;;;;;;;GAOG;AAEH,wBAAsB,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAW3E;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CA+BpF;AAED,gEAAgE;AAChE,wBAAsB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IACvD,EAAE,EAAE,OAAO,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CACrE,CAAC,CAmBD;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA0C/B;AAqDD;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBlF;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA6B3F;AAED;;;;;;;;GAQG;AACH,wBAAsB,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CA8C9D"}
|