@bankofai/x402-evm 1.0.0-beta.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 +172 -0
- package/dist/cjs/auth-capture/client/index.d.ts +44 -0
- package/dist/cjs/auth-capture/client/index.js +298 -0
- package/dist/cjs/auth-capture/client/index.js.map +1 -0
- package/dist/cjs/batch-settlement/client/file-storage.d.ts +47 -0
- package/dist/cjs/batch-settlement/client/file-storage.js +116 -0
- package/dist/cjs/batch-settlement/client/file-storage.js.map +1 -0
- package/dist/cjs/batch-settlement/client/index.d.ts +111 -0
- package/dist/cjs/batch-settlement/client/index.js +1565 -0
- package/dist/cjs/batch-settlement/client/index.js.map +1 -0
- package/dist/cjs/batch-settlement/facilitator/index.d.ts +72 -0
- package/dist/cjs/batch-settlement/facilitator/index.js +2102 -0
- package/dist/cjs/batch-settlement/facilitator/index.js.map +1 -0
- package/dist/cjs/batch-settlement/server/file-storage.d.ts +53 -0
- package/dist/cjs/batch-settlement/server/file-storage.js +181 -0
- package/dist/cjs/batch-settlement/server/file-storage.js.map +1 -0
- package/dist/cjs/batch-settlement/server/index.d.ts +491 -0
- package/dist/cjs/batch-settlement/server/index.js +1978 -0
- package/dist/cjs/batch-settlement/server/index.js.map +1 -0
- package/dist/cjs/batch-settlement/server/redis-storage.d.ts +87 -0
- package/dist/cjs/batch-settlement/server/redis-storage.js +181 -0
- package/dist/cjs/batch-settlement/server/redis-storage.js.map +1 -0
- package/dist/cjs/client/agent-wallet.d.ts +69 -0
- package/dist/cjs/client/agent-wallet.js +84 -0
- package/dist/cjs/client/agent-wallet.js.map +1 -0
- package/dist/cjs/exact/client/index.d.ts +63 -0
- package/dist/cjs/exact/client/index.js +739 -0
- package/dist/cjs/exact/client/index.js.map +1 -0
- package/dist/cjs/exact/facilitator/index.d.ts +141 -0
- package/dist/cjs/exact/facilitator/index.js +1989 -0
- package/dist/cjs/exact/facilitator/index.js.map +1 -0
- package/dist/cjs/exact/server/index.d.ts +118 -0
- package/dist/cjs/exact/server/index.js +326 -0
- package/dist/cjs/exact/server/index.js.map +1 -0
- package/dist/cjs/exact/v1/client/index.d.ts +38 -0
- package/dist/cjs/exact/v1/client/index.js +193 -0
- package/dist/cjs/exact/v1/client/index.js.map +1 -0
- package/dist/cjs/exact/v1/facilitator/index.d.ts +84 -0
- package/dist/cjs/exact/v1/facilitator/index.js +739 -0
- package/dist/cjs/exact/v1/facilitator/index.js.map +1 -0
- package/dist/cjs/facilitator/agent-wallet.d.ts +109 -0
- package/dist/cjs/facilitator/agent-wallet.js +105 -0
- package/dist/cjs/facilitator/agent-wallet.js.map +1 -0
- package/dist/cjs/index.d.ts +338 -0
- package/dist/cjs/index.js +2860 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/permit2-DK5A8alk.d.ts +729 -0
- package/dist/cjs/permit2-DhJRUcgY.d.ts +729 -0
- package/dist/cjs/rpc-DULZzRne.d.ts +13 -0
- package/dist/cjs/scheme-7ehldYoO.d.ts +307 -0
- package/dist/cjs/scheme-BjBJzHF7.d.ts +307 -0
- package/dist/cjs/scheme-DWgpkDgz.d.ts +47 -0
- package/dist/cjs/signer-BFelv8DL.d.ts +170 -0
- package/dist/cjs/storage-6W5MO46W.d.ts +50 -0
- package/dist/cjs/storage-CHNote8s.d.ts +81 -0
- package/dist/cjs/storage-DjCv5IPh.d.ts +81 -0
- package/dist/cjs/types-CKd3Xoi1.d.ts +180 -0
- package/dist/cjs/types-DIt9uAUy.d.ts +180 -0
- package/dist/cjs/upto/client/index.d.ts +34 -0
- package/dist/cjs/upto/client/index.js +509 -0
- package/dist/cjs/upto/client/index.js.map +1 -0
- package/dist/cjs/upto/facilitator/index.d.ts +54 -0
- package/dist/cjs/upto/facilitator/index.js +1313 -0
- package/dist/cjs/upto/facilitator/index.js.map +1 -0
- package/dist/cjs/upto/server/index.d.ts +69 -0
- package/dist/cjs/upto/server/index.js +296 -0
- package/dist/cjs/upto/server/index.js.map +1 -0
- package/dist/cjs/v1/index.d.ts +40 -0
- package/dist/cjs/v1/index.js +199 -0
- package/dist/cjs/v1/index.js.map +1 -0
- package/dist/esm/auth-capture/client/index.d.mts +44 -0
- package/dist/esm/auth-capture/client/index.mjs +8 -0
- package/dist/esm/auth-capture/client/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/client/file-storage.d.mts +47 -0
- package/dist/esm/batch-settlement/client/file-storage.mjs +63 -0
- package/dist/esm/batch-settlement/client/file-storage.mjs.map +1 -0
- package/dist/esm/batch-settlement/client/index.d.mts +111 -0
- package/dist/esm/batch-settlement/client/index.mjs +58 -0
- package/dist/esm/batch-settlement/client/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/facilitator/index.d.mts +72 -0
- package/dist/esm/batch-settlement/facilitator/index.mjs +1252 -0
- package/dist/esm/batch-settlement/facilitator/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/file-storage.d.mts +53 -0
- package/dist/esm/batch-settlement/server/file-storage.mjs +128 -0
- package/dist/esm/batch-settlement/server/file-storage.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/index.d.mts +491 -0
- package/dist/esm/batch-settlement/server/index.mjs +1640 -0
- package/dist/esm/batch-settlement/server/index.mjs.map +1 -0
- package/dist/esm/batch-settlement/server/redis-storage.d.mts +87 -0
- package/dist/esm/batch-settlement/server/redis-storage.mjs +156 -0
- package/dist/esm/batch-settlement/server/redis-storage.mjs.map +1 -0
- package/dist/esm/chunk-2EUQTNJO.mjs +38 -0
- package/dist/esm/chunk-2EUQTNJO.mjs.map +1 -0
- package/dist/esm/chunk-3WZF6722.mjs +36 -0
- package/dist/esm/chunk-3WZF6722.mjs.map +1 -0
- package/dist/esm/chunk-E4Z7PNXC.mjs +275 -0
- package/dist/esm/chunk-E4Z7PNXC.mjs.map +1 -0
- package/dist/esm/chunk-GQVMVP4N.mjs +911 -0
- package/dist/esm/chunk-GQVMVP4N.mjs.map +1 -0
- package/dist/esm/chunk-H2EYJIZL.mjs +489 -0
- package/dist/esm/chunk-H2EYJIZL.mjs.map +1 -0
- package/dist/esm/chunk-H3KPLYGI.mjs +152 -0
- package/dist/esm/chunk-H3KPLYGI.mjs.map +1 -0
- package/dist/esm/chunk-HYABYUBD.mjs +432 -0
- package/dist/esm/chunk-HYABYUBD.mjs.map +1 -0
- package/dist/esm/chunk-I2DVUHM5.mjs +123 -0
- package/dist/esm/chunk-I2DVUHM5.mjs.map +1 -0
- package/dist/esm/chunk-JK7SLLF7.mjs +34 -0
- package/dist/esm/chunk-JK7SLLF7.mjs.map +1 -0
- package/dist/esm/chunk-JNT7C46S.mjs +352 -0
- package/dist/esm/chunk-JNT7C46S.mjs.map +1 -0
- package/dist/esm/chunk-MACPBXCT.mjs +415 -0
- package/dist/esm/chunk-MACPBXCT.mjs.map +1 -0
- package/dist/esm/chunk-P3QOX3QZ.mjs +113 -0
- package/dist/esm/chunk-P3QOX3QZ.mjs.map +1 -0
- package/dist/esm/chunk-QVATVA3J.mjs +47 -0
- package/dist/esm/chunk-QVATVA3J.mjs.map +1 -0
- package/dist/esm/chunk-SHJFA25H.mjs +159 -0
- package/dist/esm/chunk-SHJFA25H.mjs.map +1 -0
- package/dist/esm/chunk-TW7Z65AO.mjs +34 -0
- package/dist/esm/chunk-TW7Z65AO.mjs.map +1 -0
- package/dist/esm/chunk-U4HCGTLU.mjs +35 -0
- package/dist/esm/chunk-U4HCGTLU.mjs.map +1 -0
- package/dist/esm/chunk-VS3RYAYE.mjs +80 -0
- package/dist/esm/chunk-VS3RYAYE.mjs.map +1 -0
- package/dist/esm/chunk-W6ON4LG2.mjs +39 -0
- package/dist/esm/chunk-W6ON4LG2.mjs.map +1 -0
- package/dist/esm/chunk-XG2JLZVJ.mjs +627 -0
- package/dist/esm/chunk-XG2JLZVJ.mjs.map +1 -0
- package/dist/esm/chunk-ZCJRY5LQ.mjs +162 -0
- package/dist/esm/chunk-ZCJRY5LQ.mjs.map +1 -0
- package/dist/esm/client/agent-wallet.d.mts +69 -0
- package/dist/esm/client/agent-wallet.mjs +36 -0
- package/dist/esm/client/agent-wallet.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +63 -0
- package/dist/esm/exact/client/index.mjs +25 -0
- package/dist/esm/exact/client/index.mjs.map +1 -0
- package/dist/esm/exact/facilitator/index.d.mts +141 -0
- package/dist/esm/exact/facilitator/index.mjs +694 -0
- package/dist/esm/exact/facilitator/index.mjs.map +1 -0
- package/dist/esm/exact/server/index.d.mts +118 -0
- package/dist/esm/exact/server/index.mjs +153 -0
- package/dist/esm/exact/server/index.mjs.map +1 -0
- package/dist/esm/exact/v1/client/index.d.mts +38 -0
- package/dist/esm/exact/v1/client/index.mjs +12 -0
- package/dist/esm/exact/v1/client/index.mjs.map +1 -0
- package/dist/esm/exact/v1/facilitator/index.d.mts +84 -0
- package/dist/esm/exact/v1/facilitator/index.mjs +12 -0
- package/dist/esm/exact/v1/facilitator/index.mjs.map +1 -0
- package/dist/esm/facilitator/agent-wallet.d.mts +109 -0
- package/dist/esm/facilitator/agent-wallet.mjs +74 -0
- package/dist/esm/facilitator/agent-wallet.mjs.map +1 -0
- package/dist/esm/index.d.mts +338 -0
- package/dist/esm/index.mjs +144 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/permit2-DhJRUcgY.d.mts +729 -0
- package/dist/esm/rpc-DULZzRne.d.mts +13 -0
- package/dist/esm/scheme-CkNhpXrG.d.mts +307 -0
- package/dist/esm/scheme-D8ZbykGV.d.mts +47 -0
- package/dist/esm/signer-BFelv8DL.d.mts +170 -0
- package/dist/esm/storage-6W5MO46W.d.mts +50 -0
- package/dist/esm/storage-BEzTEiUr.d.mts +81 -0
- package/dist/esm/types-DIt9uAUy.d.mts +180 -0
- package/dist/esm/upto/client/index.d.mts +34 -0
- package/dist/esm/upto/client/index.mjs +22 -0
- package/dist/esm/upto/client/index.mjs.map +1 -0
- package/dist/esm/upto/facilitator/index.d.mts +54 -0
- package/dist/esm/upto/facilitator/index.mjs +507 -0
- package/dist/esm/upto/facilitator/index.mjs.map +1 -0
- package/dist/esm/upto/server/index.d.mts +69 -0
- package/dist/esm/upto/server/index.mjs +124 -0
- package/dist/esm/upto/server/index.mjs.map +1 -0
- package/dist/esm/v1/index.d.mts +40 -0
- package/dist/esm/v1/index.mjs +18 -0
- package/dist/esm/v1/index.mjs.map +1 -0
- package/package.json +250 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { F as FileChannelStorageOptions } from '../../types-DIt9uAUy.js';
|
|
2
|
+
import { C as ChannelStorage, a as Channel, b as ChannelUpdateResult } from '../../storage-DjCv5IPh.js';
|
|
3
|
+
import 'viem';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Node.js file-backed {@link ChannelStorage} for the batched server scheme.
|
|
7
|
+
*/
|
|
8
|
+
declare class FileChannelStorage implements ChannelStorage {
|
|
9
|
+
private readonly root;
|
|
10
|
+
/**
|
|
11
|
+
* Creates file-backed server channel storage under the given root directory.
|
|
12
|
+
*
|
|
13
|
+
* @param options - Configuration including the storage root directory.
|
|
14
|
+
*/
|
|
15
|
+
constructor(options: FileChannelStorageOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Loads a persisted channel record, if present.
|
|
18
|
+
*
|
|
19
|
+
* @param channelId - The channel identifier (path segment is lowercased).
|
|
20
|
+
* @returns Parsed channel record or `undefined` when the file is missing.
|
|
21
|
+
*/
|
|
22
|
+
get(channelId: string): Promise<Channel | undefined>;
|
|
23
|
+
/**
|
|
24
|
+
* Lists all stored channel records by reading the server directory.
|
|
25
|
+
*
|
|
26
|
+
* @returns Channel records sorted by channelId; empty array if the directory is missing.
|
|
27
|
+
*/
|
|
28
|
+
list(): Promise<Channel[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Atomically inspects and mutates a channel record under a cross-process file lock.
|
|
31
|
+
*
|
|
32
|
+
* @param channelId - The channel identifier.
|
|
33
|
+
* @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged.
|
|
34
|
+
* @returns The final stored channel and whether storage updated, stayed unchanged, or deleted.
|
|
35
|
+
*/
|
|
36
|
+
updateChannel(channelId: string, update: (current: Channel | undefined) => Channel | undefined): Promise<ChannelUpdateResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Absolute path to the JSON file for a channel.
|
|
39
|
+
*
|
|
40
|
+
* @param channelId - The channel identifier.
|
|
41
|
+
* @returns Filesystem path under `{root}/server/...`.
|
|
42
|
+
*/
|
|
43
|
+
private filePath;
|
|
44
|
+
/**
|
|
45
|
+
* Creates an exclusive lock file, polling until no other process holds it.
|
|
46
|
+
*
|
|
47
|
+
* @param lockPath - Absolute path for the lock file (created with `O_EXCL`).
|
|
48
|
+
* @returns Writable file handle for the lock file; caller must close it to release.
|
|
49
|
+
*/
|
|
50
|
+
private acquireLock;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { FileChannelStorage, FileChannelStorageOptions };
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/batch-settlement/server/fileStorage.ts
|
|
21
|
+
var fileStorage_exports = {};
|
|
22
|
+
__export(fileStorage_exports, {
|
|
23
|
+
FileChannelStorage: () => FileChannelStorage
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(fileStorage_exports);
|
|
26
|
+
var import_promises2 = require("fs/promises");
|
|
27
|
+
var import_node_fs = require("fs");
|
|
28
|
+
var import_node_path2 = require("path");
|
|
29
|
+
|
|
30
|
+
// src/batch-settlement/storage-utils.ts
|
|
31
|
+
var import_promises = require("fs/promises");
|
|
32
|
+
var import_node_path = require("path");
|
|
33
|
+
function isNodeEnoent(err) {
|
|
34
|
+
if (!err || typeof err !== "object" || !("code" in err)) return false;
|
|
35
|
+
return err.code === "ENOENT";
|
|
36
|
+
}
|
|
37
|
+
async function readJsonFile(filePath) {
|
|
38
|
+
try {
|
|
39
|
+
const raw = await (0, import_promises.readFile)(filePath, "utf8");
|
|
40
|
+
return JSON.parse(raw);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (isNodeEnoent(err)) return void 0;
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function writeJsonAtomic(filePath, value) {
|
|
47
|
+
const dir = (0, import_node_path.dirname)(filePath);
|
|
48
|
+
await (0, import_promises.mkdir)(dir, { recursive: true });
|
|
49
|
+
const tmp = (0, import_node_path.join)(dir, `.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);
|
|
50
|
+
const body = `${JSON.stringify(value, null, 2)}
|
|
51
|
+
`;
|
|
52
|
+
await (0, import_promises.writeFile)(tmp, body, "utf8");
|
|
53
|
+
try {
|
|
54
|
+
await (0, import_promises.rename)(tmp, filePath);
|
|
55
|
+
} catch {
|
|
56
|
+
await (0, import_promises.unlink)(filePath).catch(() => {
|
|
57
|
+
});
|
|
58
|
+
await (0, import_promises.rename)(tmp, filePath);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/batch-settlement/server/fileStorage.ts
|
|
63
|
+
var FileChannelStorage = class {
|
|
64
|
+
/**
|
|
65
|
+
* Creates file-backed server channel storage under the given root directory.
|
|
66
|
+
*
|
|
67
|
+
* @param options - Configuration including the storage root directory.
|
|
68
|
+
*/
|
|
69
|
+
constructor(options) {
|
|
70
|
+
this.root = options.directory;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Loads a persisted channel record, if present.
|
|
74
|
+
*
|
|
75
|
+
* @param channelId - The channel identifier (path segment is lowercased).
|
|
76
|
+
* @returns Parsed channel record or `undefined` when the file is missing.
|
|
77
|
+
*/
|
|
78
|
+
async get(channelId) {
|
|
79
|
+
return readJsonFile(this.filePath(channelId));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Lists all stored channel records by reading the server directory.
|
|
83
|
+
*
|
|
84
|
+
* @returns Channel records sorted by channelId; empty array if the directory is missing.
|
|
85
|
+
*/
|
|
86
|
+
async list() {
|
|
87
|
+
const dir = (0, import_node_path2.join)(this.root, "server");
|
|
88
|
+
let names;
|
|
89
|
+
try {
|
|
90
|
+
names = await (0, import_promises2.readdir)(dir);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (isNodeEnoent(err)) return [];
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
const channels = [];
|
|
96
|
+
for (const name of names) {
|
|
97
|
+
if (!name.endsWith(".json")) continue;
|
|
98
|
+
const path = (0, import_node_path2.join)(dir, name);
|
|
99
|
+
try {
|
|
100
|
+
const raw = await (0, import_promises2.readFile)(path, "utf8");
|
|
101
|
+
channels.push(JSON.parse(raw));
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (isNodeEnoent(err)) continue;
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return channels.sort((a, b) => a.channelId.localeCompare(b.channelId));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Atomically inspects and mutates a channel record under a cross-process file lock.
|
|
111
|
+
*
|
|
112
|
+
* @param channelId - The channel identifier.
|
|
113
|
+
* @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged.
|
|
114
|
+
* @returns The final stored channel and whether storage updated, stayed unchanged, or deleted.
|
|
115
|
+
*/
|
|
116
|
+
async updateChannel(channelId, update) {
|
|
117
|
+
const lockPath = this.filePath(channelId) + ".lock";
|
|
118
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(lockPath), { recursive: true });
|
|
119
|
+
const lockHandle = await this.acquireLock(lockPath);
|
|
120
|
+
try {
|
|
121
|
+
const path = this.filePath(channelId);
|
|
122
|
+
let current;
|
|
123
|
+
try {
|
|
124
|
+
const raw = await (0, import_promises2.readFile)(path, "utf8");
|
|
125
|
+
current = JSON.parse(raw);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
if (!isNodeEnoent(err)) throw err;
|
|
128
|
+
}
|
|
129
|
+
const next = update(current);
|
|
130
|
+
if (next === current) {
|
|
131
|
+
return { channel: current, status: "unchanged" };
|
|
132
|
+
}
|
|
133
|
+
if (!next) {
|
|
134
|
+
try {
|
|
135
|
+
await (0, import_promises2.unlink)(path);
|
|
136
|
+
} catch (err) {
|
|
137
|
+
if (!isNodeEnoent(err)) throw err;
|
|
138
|
+
}
|
|
139
|
+
return { channel: void 0, status: current ? "deleted" : "unchanged" };
|
|
140
|
+
}
|
|
141
|
+
await writeJsonAtomic(path, next);
|
|
142
|
+
return { channel: next, status: "updated" };
|
|
143
|
+
} finally {
|
|
144
|
+
await lockHandle.close();
|
|
145
|
+
await (0, import_promises2.unlink)(lockPath).catch(() => {
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Absolute path to the JSON file for a channel.
|
|
151
|
+
*
|
|
152
|
+
* @param channelId - The channel identifier.
|
|
153
|
+
* @returns Filesystem path under `{root}/server/...`.
|
|
154
|
+
*/
|
|
155
|
+
filePath(channelId) {
|
|
156
|
+
return (0, import_node_path2.join)(this.root, "server", `${channelId.toLowerCase()}.json`);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Creates an exclusive lock file, polling until no other process holds it.
|
|
160
|
+
*
|
|
161
|
+
* @param lockPath - Absolute path for the lock file (created with `O_EXCL`).
|
|
162
|
+
* @returns Writable file handle for the lock file; caller must close it to release.
|
|
163
|
+
*/
|
|
164
|
+
async acquireLock(lockPath) {
|
|
165
|
+
while (true) {
|
|
166
|
+
try {
|
|
167
|
+
return await (0, import_promises2.open)(lockPath, import_node_fs.constants.O_CREAT | import_node_fs.constants.O_EXCL | import_node_fs.constants.O_WRONLY);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (err.code !== "EEXIST") {
|
|
170
|
+
throw err;
|
|
171
|
+
}
|
|
172
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
FileChannelStorage
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=file-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/batch-settlement/server/fileStorage.ts","../../../../src/batch-settlement/storage-utils.ts"],"sourcesContent":["import { mkdir, open, readdir, readFile, unlink } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { isNodeEnoent, readJsonFile, writeJsonAtomic } from \"../storage-utils\";\nimport type { FileChannelStorageOptions } from \"../types\";\nimport type { ChannelStorage, Channel, ChannelUpdateResult } from \"./storage\";\n\nexport type { FileChannelStorageOptions };\n\n/**\n * Node.js file-backed {@link ChannelStorage} for the batched server scheme.\n */\nexport class FileChannelStorage implements ChannelStorage {\n private readonly root: string;\n\n /**\n * Creates file-backed server channel storage under the given root directory.\n *\n * @param options - Configuration including the storage root directory.\n */\n constructor(options: FileChannelStorageOptions) {\n this.root = options.directory;\n }\n\n /**\n * Loads a persisted channel record, if present.\n *\n * @param channelId - The channel identifier (path segment is lowercased).\n * @returns Parsed channel record or `undefined` when the file is missing.\n */\n async get(channelId: string): Promise<Channel | undefined> {\n return readJsonFile<Channel>(this.filePath(channelId));\n }\n\n /**\n * Lists all stored channel records by reading the server directory.\n *\n * @returns Channel records sorted by channelId; empty array if the directory is missing.\n */\n async list(): Promise<Channel[]> {\n const dir = join(this.root, \"server\");\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err: unknown) {\n if (isNodeEnoent(err)) return [];\n throw err;\n }\n\n const channels: Channel[] = [];\n for (const name of names) {\n if (!name.endsWith(\".json\")) continue;\n const path = join(dir, name);\n try {\n const raw = await readFile(path, \"utf8\");\n channels.push(JSON.parse(raw) as Channel);\n } catch (err: unknown) {\n // Skip files that disappeared between readdir and readFile (e.g. concurrent delete).\n // Rethrow other failures (corrupt JSON, permission denied) so callers see them.\n if (isNodeEnoent(err)) continue;\n throw err;\n }\n }\n return channels.sort((a, b) => a.channelId.localeCompare(b.channelId));\n }\n\n /**\n * Atomically inspects and mutates a channel record under a cross-process file lock.\n *\n * @param channelId - The channel identifier.\n * @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged.\n * @returns The final stored channel and whether storage updated, stayed unchanged, or deleted.\n */\n async updateChannel(\n channelId: string,\n update: (current: Channel | undefined) => Channel | undefined,\n ): Promise<ChannelUpdateResult> {\n const lockPath = this.filePath(channelId) + \".lock\";\n await mkdir(dirname(lockPath), { recursive: true });\n const lockHandle = await this.acquireLock(lockPath);\n\n try {\n const path = this.filePath(channelId);\n let current: Channel | undefined;\n try {\n const raw = await readFile(path, \"utf8\");\n current = JSON.parse(raw) as Channel;\n } catch (err: unknown) {\n if (!isNodeEnoent(err)) throw err;\n }\n\n const next = update(current);\n if (next === current) {\n return { channel: current, status: \"unchanged\" };\n }\n\n if (!next) {\n try {\n await unlink(path);\n } catch (err: unknown) {\n if (!isNodeEnoent(err)) throw err;\n }\n return { channel: undefined, status: current ? \"deleted\" : \"unchanged\" };\n }\n\n await writeJsonAtomic(path, next);\n return { channel: next, status: \"updated\" };\n } finally {\n await lockHandle.close();\n await unlink(lockPath).catch(() => {});\n }\n }\n\n /**\n * Absolute path to the JSON file for a channel.\n *\n * @param channelId - The channel identifier.\n * @returns Filesystem path under `{root}/server/...`.\n */\n private filePath(channelId: string): string {\n return join(this.root, \"server\", `${channelId.toLowerCase()}.json`);\n }\n\n /**\n * Creates an exclusive lock file, polling until no other process holds it.\n *\n * @param lockPath - Absolute path for the lock file (created with `O_EXCL`).\n * @returns Writable file handle for the lock file; caller must close it to release.\n */\n private async acquireLock(lockPath: string) {\n while (true) {\n try {\n return await open(lockPath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw err;\n }\n await new Promise(resolve => setTimeout(resolve, 10));\n }\n }\n }\n}\n","import { mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * Returns true when `err` is a Node.js `ENOENT` filesystem error (file does not exist).\n *\n * @param err - The thrown value to inspect.\n * @returns `true` for `ENOENT`, `false` for any other value or error code.\n */\nexport function isNodeEnoent(err: unknown): boolean {\n if (!err || typeof err !== \"object\" || !(\"code\" in err)) return false;\n return (err as NodeJS.ErrnoException).code === \"ENOENT\";\n}\n\n/**\n * Reads a JSON file and parses it. Returns `undefined` if the file does not exist.\n * Other errors (permission, malformed JSON) are rethrown.\n *\n * @param filePath - Path to the JSON file.\n * @returns Parsed value, or `undefined` for `ENOENT`.\n */\nexport async function readJsonFile<T>(filePath: string): Promise<T | undefined> {\n try {\n const raw = await readFile(filePath, \"utf8\");\n return JSON.parse(raw) as T;\n } catch (err: unknown) {\n if (isNodeEnoent(err)) return undefined;\n throw err;\n }\n}\n\n/**\n * Writes JSON to `filePath` atomically (temp file in the same directory, then rename).\n * Creates parent directories as needed.\n *\n * @param filePath - Destination file path; parent dirs are created if missing.\n * @param value - JSON-serializable value to persist.\n */\nexport async function writeJsonAtomic(filePath: string, value: unknown): Promise<void> {\n const dir = dirname(filePath);\n await mkdir(dir, { recursive: true });\n const tmp = join(dir, `.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);\n const body = `${JSON.stringify(value, null, 2)}\\n`;\n await writeFile(tmp, body, \"utf8\");\n try {\n await rename(tmp, filePath);\n } catch {\n // On Windows, rename() onto an existing file throws EEXIST; unlink + rename is intentional.\n await unlink(filePath).catch(() => {});\n await rename(tmp, filePath);\n }\n}\n"],"mappings":"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","names":["import_promises","import_node_path"]}
|