@obbyx/x402-obyte 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +65 -2
- package/dist/batch/client-store.d.ts +50 -0
- package/dist/batch/client-store.d.ts.map +1 -0
- package/dist/batch/client-store.js +93 -0
- package/dist/batch/client-store.js.map +1 -0
- package/dist/batch/client.d.ts +63 -0
- package/dist/batch/client.d.ts.map +1 -0
- package/dist/batch/client.js +222 -0
- package/dist/batch/client.js.map +1 -0
- package/dist/batch/facilitator.d.ts +73 -0
- package/dist/batch/facilitator.d.ts.map +1 -0
- package/dist/batch/facilitator.js +350 -0
- package/dist/batch/facilitator.js.map +1 -0
- package/dist/batch/gateway.d.ts +19 -0
- package/dist/batch/gateway.d.ts.map +1 -0
- package/dist/batch/gateway.js +2 -0
- package/dist/batch/gateway.js.map +1 -0
- package/dist/batch/requirements.d.ts +52 -0
- package/dist/batch/requirements.d.ts.map +1 -0
- package/dist/batch/requirements.js +80 -0
- package/dist/batch/requirements.js.map +1 -0
- package/dist/batch/store.d.ts +104 -0
- package/dist/batch/store.d.ts.map +1 -0
- package/dist/batch/store.js +192 -0
- package/dist/batch/store.js.map +1 -0
- package/dist/batch/watcher-protocol.d.ts +89 -0
- package/dist/batch/watcher-protocol.d.ts.map +1 -0
- package/dist/batch/watcher-protocol.js +80 -0
- package/dist/batch/watcher-protocol.js.map +1 -0
- package/dist/binding/binding.d.ts +32 -0
- package/dist/binding/binding.d.ts.map +1 -0
- package/dist/binding/binding.js +19 -0
- package/dist/binding/binding.js.map +1 -0
- package/dist/coins/composer.d.ts +58 -0
- package/dist/coins/composer.d.ts.map +1 -0
- package/dist/coins/composer.js +102 -0
- package/dist/coins/composer.js.map +1 -0
- package/dist/coins/index.d.ts +4 -0
- package/dist/coins/index.d.ts.map +1 -0
- package/dist/coins/index.js +4 -0
- package/dist/coins/index.js.map +1 -0
- package/dist/coins/reservations.d.ts +37 -0
- package/dist/coins/reservations.d.ts.map +1 -0
- package/dist/coins/reservations.js +102 -0
- package/dist/coins/reservations.js.map +1 -0
- package/dist/coins/selection.d.ts +42 -0
- package/dist/coins/selection.d.ts.map +1 -0
- package/dist/coins/selection.js +60 -0
- package/dist/coins/selection.js.map +1 -0
- package/dist/exact/client.d.ts +33 -0
- package/dist/exact/client.d.ts.map +1 -0
- package/dist/exact/client.js +93 -0
- package/dist/exact/client.js.map +1 -0
- package/dist/exact/facilitator-v1.d.ts +48 -0
- package/dist/exact/facilitator-v1.d.ts.map +1 -0
- package/dist/exact/facilitator-v1.js +81 -0
- package/dist/exact/facilitator-v1.js.map +1 -0
- package/dist/exact/facilitator.d.ts +77 -0
- package/dist/exact/facilitator.d.ts.map +1 -0
- package/dist/exact/facilitator.js +331 -0
- package/dist/exact/facilitator.js.map +1 -0
- package/dist/exact/finality.d.ts +18 -0
- package/dist/exact/finality.d.ts.map +1 -0
- package/dist/exact/finality.js +45 -0
- package/dist/exact/finality.js.map +1 -0
- package/dist/exact/ledger-checks.d.ts +15 -0
- package/dist/exact/ledger-checks.d.ts.map +1 -0
- package/dist/exact/ledger-checks.js +85 -0
- package/dist/exact/ledger-checks.js.map +1 -0
- package/dist/exact/reasons.d.ts +29 -0
- package/dist/exact/reasons.d.ts.map +1 -0
- package/dist/exact/reasons.js +21 -0
- package/dist/exact/reasons.js.map +1 -0
- package/dist/exact/requirements.d.ts +37 -0
- package/dist/exact/requirements.d.ts.map +1 -0
- package/dist/exact/requirements.js +80 -0
- package/dist/exact/requirements.js.map +1 -0
- package/dist/exact/store.d.ts +133 -0
- package/dist/exact/store.d.ts.map +1 -0
- package/dist/exact/store.js +212 -0
- package/dist/exact/store.js.map +1 -0
- package/dist/hub/heartbeat.d.ts +12 -0
- package/dist/hub/heartbeat.d.ts.map +1 -0
- package/dist/hub/heartbeat.js +17 -0
- package/dist/hub/heartbeat.js.map +1 -0
- package/dist/hub/hub-call.d.ts +20 -0
- package/dist/hub/hub-call.d.ts.map +1 -0
- package/dist/hub/hub-call.js +30 -0
- package/dist/hub/hub-call.js.map +1 -0
- package/dist/hub/schemas.d.ts +41 -0
- package/dist/hub/schemas.d.ts.map +1 -0
- package/dist/hub/schemas.js +71 -0
- package/dist/hub/schemas.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -3
- package/src/batch/client-store.ts +167 -0
- package/src/batch/client.ts +314 -0
- package/src/batch/facilitator.ts +469 -0
- package/src/batch/gateway.ts +20 -0
- package/src/batch/requirements.ts +108 -0
- package/src/batch/store.ts +343 -0
- package/src/batch/watcher-protocol.ts +87 -0
- package/src/binding/binding.ts +50 -0
- package/src/coins/composer.ts +159 -0
- package/src/coins/index.ts +9 -0
- package/src/coins/reservations.ts +139 -0
- package/src/coins/selection.ts +93 -0
- package/src/exact/client.ts +144 -0
- package/src/exact/facilitator-v1.ts +137 -0
- package/src/exact/facilitator.ts +451 -0
- package/src/exact/finality.ts +56 -0
- package/src/exact/ledger-checks.ts +113 -0
- package/src/exact/reasons.ts +25 -0
- package/src/exact/requirements.ts +109 -0
- package/src/exact/store.ts +391 -0
- package/src/hub/heartbeat.ts +18 -0
- package/src/hub/hub-call.ts +46 -0
- package/src/hub/schemas.ts +89 -0
- package/src/index.ts +110 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type obyte from 'obyte';
|
|
2
|
+
/**
|
|
3
|
+
* Keeps an obyte.js hub connection alive. obyte.js does not schedule
|
|
4
|
+
* heartbeats itself: the application must call `client.api.heartbeat()`
|
|
5
|
+
* periodically (its WSClient then skips the call if traffic was recent,
|
|
6
|
+
* and closes a connection whose heartbeat goes unanswered, letting
|
|
7
|
+
* `reconnect: true` re-establish it). Hubs drop idle peers without this.
|
|
8
|
+
*
|
|
9
|
+
* Returns a function that stops the timer.
|
|
10
|
+
*/
|
|
11
|
+
export declare function startHeartbeat(client: obyte.Client, intervalMs?: number): () => void;
|
|
12
|
+
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../src/hub/heartbeat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,SAAS,GAAG,MAAM,IAAI,CAMpF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps an obyte.js hub connection alive. obyte.js does not schedule
|
|
3
|
+
* heartbeats itself: the application must call `client.api.heartbeat()`
|
|
4
|
+
* periodically (its WSClient then skips the call if traffic was recent,
|
|
5
|
+
* and closes a connection whose heartbeat goes unanswered, letting
|
|
6
|
+
* `reconnect: true` re-establish it). Hubs drop idle peers without this.
|
|
7
|
+
*
|
|
8
|
+
* Returns a function that stops the timer.
|
|
9
|
+
*/
|
|
10
|
+
export function startHeartbeat(client, intervalMs = 10_000) {
|
|
11
|
+
const timer = setInterval(() => {
|
|
12
|
+
client.api.heartbeat().catch(() => undefined); // closed/reconnecting: the next tick retries
|
|
13
|
+
}, intervalMs);
|
|
14
|
+
timer.unref();
|
|
15
|
+
return () => clearInterval(timer);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/hub/heartbeat.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,MAAoB,EAAE,UAAU,GAAG,MAAM;IACtE,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,6CAA6C;IAC9F,CAAC,EAAE,UAAU,CAAC,CAAC;IACf,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome of one obyte.js hub request (ADR-0006, invariant I7).
|
|
3
|
+
*
|
|
4
|
+
* obyte.js requests have no timeout. It rejects with the hub's error value
|
|
5
|
+
* (usually a string) for definite hub errors, and with an `Error` for transport
|
|
6
|
+
* failures. A timeout or transport failure is an UNKNOWN outcome — for
|
|
7
|
+
* `postJoint` the unit may have been accepted.
|
|
8
|
+
*/
|
|
9
|
+
export type HubOutcome<T> = {
|
|
10
|
+
readonly kind: 'ok';
|
|
11
|
+
readonly value: T;
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: 'hub_error';
|
|
14
|
+
readonly error: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'unknown';
|
|
17
|
+
readonly error: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function hubCall<T>(request: () => Promise<T>, timeoutMs: number): Promise<HubOutcome<T>>;
|
|
20
|
+
//# sourceMappingURL=hub-call.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-call.d.ts","sourceRoot":"","sources":["../../src/hub/hub-call.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC1C;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,wBAAsB,OAAO,CAAC,CAAC,EAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAqBxB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export async function hubCall(request, timeoutMs) {
|
|
2
|
+
let timer;
|
|
3
|
+
try {
|
|
4
|
+
const value = await Promise.race([
|
|
5
|
+
request(),
|
|
6
|
+
new Promise((_, rejectTimeout) => {
|
|
7
|
+
timer = setTimeout(() => rejectTimeout(new Error(`hub request timed out after ${timeoutMs} ms`)), timeoutMs);
|
|
8
|
+
}),
|
|
9
|
+
]);
|
|
10
|
+
return { kind: 'ok', value };
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
if (err instanceof Error || err === null || err === undefined) {
|
|
14
|
+
return { kind: 'unknown', error: err instanceof Error ? err.message : 'no error value' };
|
|
15
|
+
}
|
|
16
|
+
return { kind: 'hub_error', error: typeof err === 'string' ? err : safeJson(err) };
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function safeJson(value) {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.stringify(value);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return String(value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=hub-call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-call.js","sourceRoot":"","sources":["../../src/hub/hub-call.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAyB,EACzB,SAAiB;IAEjB,IAAI,KAAiC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YAC/B,OAAO,EAAE;YACT,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,aAAa,EAAE,EAAE;gBACtC,KAAK,GAAG,UAAU,CAChB,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,+BAA+B,SAAS,KAAK,CAAC,CAAC,EAC7E,SAAS,CACV,CAAC;YACJ,CAAC,CAAC;SACH,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC9D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC3F,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;IACrF,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { HistoryJoint } from '../coins/index.js';
|
|
3
|
+
export declare const paymentPayloadSchema: z.ZodObject<{
|
|
4
|
+
asset: z.ZodOptional<z.ZodString>;
|
|
5
|
+
inputs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
6
|
+
unit: z.ZodOptional<z.ZodString>;
|
|
7
|
+
message_index: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
output_index: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
}, z.core.$loose>>>;
|
|
10
|
+
outputs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
11
|
+
address: z.ZodString;
|
|
12
|
+
amount: z.ZodNumber;
|
|
13
|
+
}, z.core.$loose>>>;
|
|
14
|
+
}, z.core.$loose>;
|
|
15
|
+
export declare const ledgerUnitSchema: z.ZodObject<{
|
|
16
|
+
unit: z.ZodString;
|
|
17
|
+
timestamp: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
main_chain_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
19
|
+
authors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
20
|
+
address: z.ZodString;
|
|
21
|
+
}, z.core.$loose>>>;
|
|
22
|
+
messages: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
23
|
+
app: z.ZodString;
|
|
24
|
+
payload: z.ZodOptional<z.ZodUnknown>;
|
|
25
|
+
}, z.core.$loose>>>;
|
|
26
|
+
}, z.core.$loose>;
|
|
27
|
+
export type LedgerUnit = HistoryJoint['unit'];
|
|
28
|
+
/** A unit from `get_joint` (undefined when malformed). */
|
|
29
|
+
export declare function parseLedgerUnit(raw: unknown): LedgerUnit | undefined;
|
|
30
|
+
export interface ProofchainBall {
|
|
31
|
+
readonly unit: string;
|
|
32
|
+
readonly is_nonserial?: boolean | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** `light/get_history` (undefined when malformed). */
|
|
35
|
+
export declare function parseHistory(raw: unknown): {
|
|
36
|
+
joints: HistoryJoint[];
|
|
37
|
+
proofchainBalls: ProofchainBall[];
|
|
38
|
+
} | undefined;
|
|
39
|
+
/** `light/get_aa_state_vars`: a plain record (undefined when malformed). */
|
|
40
|
+
export declare function parseStateVars(raw: unknown): Record<string, unknown> | undefined;
|
|
41
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/hub/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAStD,eAAO,MAAM,oBAAoB;;;;;;;;;;;iBAgBvB,CAAC;AAYX,eAAO,MAAM,gBAAgB;;;;;;;;;;;iBAQnB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAa9C,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAGpE;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7C;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAC1B,GAAG,EAAE,OAAO,GACX;IAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAAC,eAAe,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG,SAAS,CAO3E;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAGhF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Shapes of the hub (light vendor) answers we rely on. The hub is trusted for
|
|
4
|
+
* ledger reads (ADR-0001), but a malformed or unexpected answer must fail
|
|
5
|
+
* closed ("ledger unavailable"), never crash or be half-read.
|
|
6
|
+
*/
|
|
7
|
+
const safeAmount = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
8
|
+
export const paymentPayloadSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
asset: z.string().optional(),
|
|
11
|
+
inputs: z
|
|
12
|
+
.array(z
|
|
13
|
+
.object({
|
|
14
|
+
unit: z.string().optional(),
|
|
15
|
+
message_index: z.number().int().optional(),
|
|
16
|
+
output_index: z.number().int().optional(),
|
|
17
|
+
})
|
|
18
|
+
.loose())
|
|
19
|
+
.optional(),
|
|
20
|
+
outputs: z.array(z.object({ address: z.string(), amount: safeAmount }).loose()).optional(),
|
|
21
|
+
})
|
|
22
|
+
.loose();
|
|
23
|
+
/** A message; payment payloads are validated (positions of messages/outputs are kept). */
|
|
24
|
+
const messageSchema = z
|
|
25
|
+
.object({ app: z.string(), payload: z.unknown().optional() })
|
|
26
|
+
.loose()
|
|
27
|
+
.superRefine((m, ctx) => {
|
|
28
|
+
if (m.app === 'payment' && !paymentPayloadSchema.safeParse(m.payload).success) {
|
|
29
|
+
ctx.addIssue({ code: 'custom', message: 'malformed payment payload' });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
export const ledgerUnitSchema = z
|
|
33
|
+
.object({
|
|
34
|
+
unit: z.string(),
|
|
35
|
+
timestamp: z.number().optional(),
|
|
36
|
+
main_chain_index: z.number().nullable().optional(),
|
|
37
|
+
authors: z.array(z.object({ address: z.string() }).loose()).optional(),
|
|
38
|
+
messages: z.array(messageSchema).default([]),
|
|
39
|
+
})
|
|
40
|
+
.loose();
|
|
41
|
+
const historySchema = z
|
|
42
|
+
.object({
|
|
43
|
+
joints: z
|
|
44
|
+
.array(z.object({ unit: ledgerUnitSchema, ball: z.string().optional() }).loose())
|
|
45
|
+
.default([]),
|
|
46
|
+
proofchain_balls: z
|
|
47
|
+
.array(z.object({ unit: z.string(), is_nonserial: z.boolean().optional() }).loose())
|
|
48
|
+
.default([]),
|
|
49
|
+
})
|
|
50
|
+
.loose();
|
|
51
|
+
/** A unit from `get_joint` (undefined when malformed). */
|
|
52
|
+
export function parseLedgerUnit(raw) {
|
|
53
|
+
const parsed = ledgerUnitSchema.safeParse(raw);
|
|
54
|
+
return parsed.success ? parsed.data : undefined;
|
|
55
|
+
}
|
|
56
|
+
/** `light/get_history` (undefined when malformed). */
|
|
57
|
+
export function parseHistory(raw) {
|
|
58
|
+
const parsed = historySchema.safeParse(raw);
|
|
59
|
+
if (!parsed.success)
|
|
60
|
+
return undefined;
|
|
61
|
+
return {
|
|
62
|
+
joints: parsed.data.joints,
|
|
63
|
+
proofchainBalls: parsed.data.proofchain_balls,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** `light/get_aa_state_vars`: a plain record (undefined when malformed). */
|
|
67
|
+
export function parseStateVars(raw) {
|
|
68
|
+
const parsed = z.record(z.string(), z.unknown()).safeParse(raw);
|
|
69
|
+
return parsed.success ? parsed.data : undefined;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/hub/schemas.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { type HubOutcome, hubCall } from './hub/hub-call.js';
|
|
2
|
+
export { EXACT_SCHEME, type ExactExtra, type ParsedExactRequirements, acceptedMatches, canonical, exactExtraSchema, parseExactRequirements, } from './exact/requirements.js';
|
|
3
|
+
export { type NewSettlement, type SettlementEvent, type SettlementRecord, type SettlementState, type SettlementStore, SqliteSettlementStore, type TransitionPatch, StoreLockedError, TERMINAL_STATES, } from './exact/store.js';
|
|
4
|
+
export { EXACT_SETTLE_REASONS, HISTORY_PROBE_ADDRESS, ExactObyteFacilitator, type ExactObyteFacilitatorOptions, type FinalityPolicy, } from './exact/facilitator.js';
|
|
5
|
+
export { ExactObyteClient, type ExactObyteClientOptions } from './exact/client.js';
|
|
6
|
+
export { type WatcherGateway, type WatcherHealth } from './batch/gateway.js';
|
|
7
|
+
export { BATCH_REASONS, BATCH_SCHEME, type BatchExtra, type ParsedBatchRequirements, type VoucherMessage, batchExtraSchema, parseBatchRequirements, voucherMessageSchema, } from './batch/requirements.js';
|
|
8
|
+
export { type AppendInput, type AppendResult, type BatchStore, SqliteBatchStore, type ChannelRow, type CommitmentRow, type CommitmentState, } from './batch/store.js';
|
|
9
|
+
export { BatchObyteFacilitator, type BatchObyteFacilitatorOptions } from './batch/facilitator.js';
|
|
10
|
+
export { type ClientMessage, type CommitmentMessage, type ServerMessage, WATCHER_LOGIN_PURPOSE, clientMessageSchema, commitmentMessageSchema, loginMessage, serverMessageSchema, verifyWatcherLogin, } from './batch/watcher-protocol.js';
|
|
11
|
+
export { startHeartbeat } from './hub/heartbeat.js';
|
|
12
|
+
export { ClientChannelStore, type ClientChannel, type PendingVoucher, } from './batch/client-store.js';
|
|
13
|
+
export { BatchObyteClient, type BatchClientOptions, MIN_DEPOSIT, TRIGGER_FEE, addressOfKey, closeChannel, confirmClose, deposit, openChannel, } from './batch/client.js';
|
|
14
|
+
export { CoinReservations, type HistoryJoint, type ReservationRow, ReservingComposer, type ReservingComposerOptions, type Utxo, inputKey, selectCoins, unspentOutputs, } from './coins/index.js';
|
|
15
|
+
export { type BindingInput, bindingsEqual, computeBinding, newQuoteId, sha256Hex, } from './binding/binding.js';
|
|
16
|
+
export { ExactObyteFacilitatorV1, type PaymentPayloadV1, type PaymentRequirementsV1, requirementsV1ToV2, requirementsV2ToV1, } from './exact/facilitator-v1.js';
|
|
17
|
+
export { type LedgerUnit, type ProofchainBall, parseHistory, parseLedgerUnit, parseStateVars, } from './hub/schemas.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,eAAe,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,cAAc,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EACL,aAAa,EACb,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,IAAI,EACT,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,YAAY,EACjB,aAAa,EACb,cAAc,EACd,UAAU,EACV,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { hubCall } from './hub/hub-call.js';
|
|
2
|
+
export { EXACT_SCHEME, acceptedMatches, canonical, exactExtraSchema, parseExactRequirements, } from './exact/requirements.js';
|
|
3
|
+
export { SqliteSettlementStore, StoreLockedError, TERMINAL_STATES, } from './exact/store.js';
|
|
4
|
+
export { EXACT_SETTLE_REASONS, HISTORY_PROBE_ADDRESS, ExactObyteFacilitator, } from './exact/facilitator.js';
|
|
5
|
+
export { ExactObyteClient } from './exact/client.js';
|
|
6
|
+
export {} from './batch/gateway.js';
|
|
7
|
+
export { BATCH_REASONS, BATCH_SCHEME, batchExtraSchema, parseBatchRequirements, voucherMessageSchema, } from './batch/requirements.js';
|
|
8
|
+
export { SqliteBatchStore, } from './batch/store.js';
|
|
9
|
+
export { BatchObyteFacilitator } from './batch/facilitator.js';
|
|
10
|
+
export { WATCHER_LOGIN_PURPOSE, clientMessageSchema, commitmentMessageSchema, loginMessage, serverMessageSchema, verifyWatcherLogin, } from './batch/watcher-protocol.js';
|
|
11
|
+
export { startHeartbeat } from './hub/heartbeat.js';
|
|
12
|
+
export { ClientChannelStore, } from './batch/client-store.js';
|
|
13
|
+
export { BatchObyteClient, MIN_DEPOSIT, TRIGGER_FEE, addressOfKey, closeChannel, confirmClose, deposit, openChannel, } from './batch/client.js';
|
|
14
|
+
export { CoinReservations, ReservingComposer, inputKey, selectCoins, unspentOutputs, } from './coins/index.js';
|
|
15
|
+
export { bindingsEqual, computeBinding, newQuoteId, sha256Hex, } from './binding/binding.js';
|
|
16
|
+
export { ExactObyteFacilitatorV1, requirementsV1ToV2, requirementsV2ToV1, } from './exact/facilitator-v1.js';
|
|
17
|
+
export { parseHistory, parseLedgerUnit, parseStateVars, } from './hub/schemas.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,YAAY,EAGZ,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAML,qBAAqB,EAErB,gBAAgB,EAChB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GAGtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAgC,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAA2C,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EACL,aAAa,EACb,YAAY,EAIZ,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAIL,gBAAgB,GAIjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAqC,MAAM,wBAAwB,CAAC;AAClG,OAAO,EAIL,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,kBAAkB,GAGnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAEhB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAGhB,iBAAiB,EAGjB,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,aAAa,EACb,cAAc,EACd,UAAU,EACV,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,uBAAuB,EAGvB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obbyx/x402-obyte",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "x402 payment mechanisms for the Obyte network: exact (on-chain unit) and batch-settlement (AA payment channels)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"x402",
|
|
7
|
+
"obyte",
|
|
8
|
+
"payments",
|
|
9
|
+
"micropayments",
|
|
10
|
+
"payment-channels",
|
|
11
|
+
"http-402"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Alexander Ponomarev",
|
|
15
|
+
"homepage": "https://github.com/Taump/obbyx/tree/master/packages/x402-obyte#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/Taump/obbyx.git",
|
|
19
|
+
"directory": "packages/x402-obyte"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Taump/obbyx/issues"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"src",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@obbyx/obyte": "^0.1.0",
|
|
46
|
+
"@x402/core": "^2.29.0",
|
|
47
|
+
"obyte": "0.2.1",
|
|
48
|
+
"zod": "^4.6.7"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc -p tsconfig.build.json",
|
|
52
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
53
|
+
}
|
|
6
54
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Buyer-side channel state (node:sqlite, lightweight; used by the SDK/CLI).
|
|
5
|
+
*
|
|
6
|
+
* Per channel: the AA params, the current period, the last amount the
|
|
7
|
+
* facilitator confirmed (`committed`) and at most ONE pending voucher whose
|
|
8
|
+
* outcome is unknown. While a voucher is pending, no new voucher is signed
|
|
9
|
+
* (invariant I7); retrying the same operation resends the same voucher.
|
|
10
|
+
*/
|
|
11
|
+
export interface ClientChannel {
|
|
12
|
+
readonly network: string;
|
|
13
|
+
readonly aa: string;
|
|
14
|
+
readonly payTo: string;
|
|
15
|
+
readonly asset: string;
|
|
16
|
+
readonly timeout: number;
|
|
17
|
+
readonly salt: string;
|
|
18
|
+
readonly period: number;
|
|
19
|
+
readonly committed: bigint;
|
|
20
|
+
readonly pending: PendingVoucher | null;
|
|
21
|
+
readonly openedUnit: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PendingVoucher {
|
|
25
|
+
readonly binding: string;
|
|
26
|
+
readonly period: number;
|
|
27
|
+
readonly amountSpent: string;
|
|
28
|
+
readonly signedPackage: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface Row {
|
|
32
|
+
network: string;
|
|
33
|
+
aa: string;
|
|
34
|
+
pay_to: string;
|
|
35
|
+
asset: string;
|
|
36
|
+
timeout: number;
|
|
37
|
+
salt: string;
|
|
38
|
+
period: number;
|
|
39
|
+
committed: string;
|
|
40
|
+
pending_json: string | null;
|
|
41
|
+
opened_unit: string | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class ClientChannelStore {
|
|
45
|
+
private readonly db: DatabaseSync;
|
|
46
|
+
|
|
47
|
+
constructor(path: string) {
|
|
48
|
+
this.db = new DatabaseSync(path);
|
|
49
|
+
this.db.exec(`
|
|
50
|
+
PRAGMA journal_mode = WAL;
|
|
51
|
+
PRAGMA synchronous = FULL;
|
|
52
|
+
PRAGMA busy_timeout = 5000;
|
|
53
|
+
CREATE TABLE IF NOT EXISTS client_channels (
|
|
54
|
+
aa TEXT PRIMARY KEY,
|
|
55
|
+
network TEXT NOT NULL,
|
|
56
|
+
pay_to TEXT NOT NULL,
|
|
57
|
+
asset TEXT NOT NULL,
|
|
58
|
+
timeout INTEGER NOT NULL,
|
|
59
|
+
salt TEXT NOT NULL,
|
|
60
|
+
period INTEGER NOT NULL,
|
|
61
|
+
committed TEXT NOT NULL,
|
|
62
|
+
pending_json TEXT,
|
|
63
|
+
opened_unit TEXT,
|
|
64
|
+
created_at INTEGER NOT NULL
|
|
65
|
+
) STRICT;
|
|
66
|
+
`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
close(): void {
|
|
70
|
+
this.db.close();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
add(c: Omit<ClientChannel, 'pending' | 'committed' | 'period'> & { period?: number }): void {
|
|
74
|
+
this.db
|
|
75
|
+
.prepare(
|
|
76
|
+
`INSERT INTO client_channels (aa, network, pay_to, asset, timeout, salt, period, committed, opened_unit, created_at)
|
|
77
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, '0', ?, ?) ON CONFLICT(aa) DO NOTHING`,
|
|
78
|
+
)
|
|
79
|
+
.run(
|
|
80
|
+
c.aa,
|
|
81
|
+
c.network,
|
|
82
|
+
c.payTo,
|
|
83
|
+
c.asset,
|
|
84
|
+
c.timeout,
|
|
85
|
+
c.salt,
|
|
86
|
+
c.period ?? 1,
|
|
87
|
+
c.openedUnit,
|
|
88
|
+
Math.floor(Date.now() / 1000),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get(aa: string): ClientChannel | undefined {
|
|
93
|
+
const row = this.db.prepare('SELECT * FROM client_channels WHERE aa = ?').get(aa) as
|
|
94
|
+
Row | undefined;
|
|
95
|
+
return row === undefined ? undefined : toChannel(row);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The newest channel to `payTo` in `asset` on `network`. */
|
|
99
|
+
find(network: string, payTo: string, asset: string): ClientChannel | undefined {
|
|
100
|
+
const row = this.db
|
|
101
|
+
.prepare(
|
|
102
|
+
'SELECT * FROM client_channels WHERE network = ? AND pay_to = ? AND asset = ? ORDER BY created_at DESC LIMIT 1',
|
|
103
|
+
)
|
|
104
|
+
.get(network, payTo, asset) as Row | undefined;
|
|
105
|
+
return row === undefined ? undefined : toChannel(row);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
list(): ClientChannel[] {
|
|
109
|
+
return (
|
|
110
|
+
this.db.prepare('SELECT * FROM client_channels ORDER BY created_at').all() as unknown as Row[]
|
|
111
|
+
).map(toChannel);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Records a signed voucher BEFORE it is sent (compare-and-set: fails if one is pending). */
|
|
115
|
+
setPending(aa: string, pending: PendingVoucher): boolean {
|
|
116
|
+
const res = this.db
|
|
117
|
+
.prepare('UPDATE client_channels SET pending_json = ? WHERE aa = ? AND pending_json IS NULL')
|
|
118
|
+
.run(JSON.stringify(pending), aa);
|
|
119
|
+
return Number(res.changes) === 1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** The facilitator confirmed `amountSpent` for `period`. */
|
|
123
|
+
confirm(aa: string, period: number, amountSpent: bigint): void {
|
|
124
|
+
this.db
|
|
125
|
+
.prepare(
|
|
126
|
+
'UPDATE client_channels SET period = ?, committed = ?, pending_json = NULL WHERE aa = ?',
|
|
127
|
+
)
|
|
128
|
+
.run(period, amountSpent.toString(), aa);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The voucher was definitely refused; optionally resync to the facilitator's committed amount. */
|
|
132
|
+
dropPending(aa: string, resync?: { period: number; committed: bigint }): void {
|
|
133
|
+
if (resync === undefined) {
|
|
134
|
+
this.db.prepare('UPDATE client_channels SET pending_json = NULL WHERE aa = ?').run(aa);
|
|
135
|
+
} else {
|
|
136
|
+
this.db
|
|
137
|
+
.prepare(
|
|
138
|
+
'UPDATE client_channels SET pending_json = NULL, period = ?, committed = ? WHERE aa = ?',
|
|
139
|
+
)
|
|
140
|
+
.run(resync.period, resync.committed.toString(), aa);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** A new period started on-chain (the channel was closed and reopened). */
|
|
145
|
+
newPeriod(aa: string, period: number): void {
|
|
146
|
+
this.db
|
|
147
|
+
.prepare(
|
|
148
|
+
"UPDATE client_channels SET period = ?, committed = '0', pending_json = NULL WHERE aa = ? AND period < ?",
|
|
149
|
+
)
|
|
150
|
+
.run(period, aa, period);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function toChannel(r: Row): ClientChannel {
|
|
155
|
+
return {
|
|
156
|
+
network: r.network,
|
|
157
|
+
aa: r.aa,
|
|
158
|
+
payTo: r.pay_to,
|
|
159
|
+
asset: r.asset,
|
|
160
|
+
timeout: r.timeout,
|
|
161
|
+
salt: r.salt,
|
|
162
|
+
period: r.period,
|
|
163
|
+
committed: BigInt(r.committed),
|
|
164
|
+
pending: r.pending_json === null ? null : (JSON.parse(r.pending_json) as PendingVoucher),
|
|
165
|
+
openedUnit: r.opened_unit,
|
|
166
|
+
};
|
|
167
|
+
}
|