tigerbeetle-node 0.16.51 → 0.16.53
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 +2 -1
- package/dist/bin/aarch64-linux-gnu/client.node +0 -0
- package/dist/bin/aarch64-linux-musl/client.node +0 -0
- package/dist/bin/aarch64-macos/client.node +0 -0
- package/dist/bin/x86_64-linux-gnu/client.node +0 -0
- package/dist/bin/x86_64-linux-musl/client.node +0 -0
- package/dist/bin/x86_64-macos/client.node +0 -0
- package/dist/bin/x86_64-windows/client.node +0 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +9 -2
package/README.md
CHANGED
|
@@ -65,7 +65,8 @@ ID and replica addresses are both chosen by the system that
|
|
|
65
65
|
starts the TigerBeetle cluster.
|
|
66
66
|
|
|
67
67
|
Clients are thread-safe and a single instance should be shared
|
|
68
|
-
between multiple concurrent tasks.
|
|
68
|
+
between multiple concurrent tasks. This allows events to be
|
|
69
|
+
[automatically batched](https://docs.tigerbeetle.com/coding/requests/#batching-events).
|
|
69
70
|
|
|
70
71
|
Multiple clients are useful when connecting to more than
|
|
71
72
|
one TigerBeetle cluster.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -94,7 +94,8 @@ function createClient(args) {
|
|
|
94
94
|
}
|
|
95
95
|
exports.createClient = createClient;
|
|
96
96
|
let idLastTimestamp = 0;
|
|
97
|
-
|
|
97
|
+
const idLastBuffer = new DataView(new ArrayBuffer(16));
|
|
98
|
+
const idLastBufferArray = new Uint8Array(idLastBuffer.buffer, idLastBuffer.byteOffset, idLastBuffer.byteLength);
|
|
98
99
|
function id() {
|
|
99
100
|
let timestamp = Date.now();
|
|
100
101
|
if (timestamp <= idLastTimestamp) {
|
|
@@ -102,7 +103,7 @@ function id() {
|
|
|
102
103
|
}
|
|
103
104
|
else {
|
|
104
105
|
idLastTimestamp = timestamp;
|
|
105
|
-
(0, node_crypto_1.randomFillSync)(
|
|
106
|
+
(0, node_crypto_1.randomFillSync)(idLastBufferArray);
|
|
106
107
|
}
|
|
107
108
|
const littleEndian = true;
|
|
108
109
|
const randomLo32 = idLastBuffer.getUint32(0, littleEndian) + 1;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export * from './bindings'\nimport {\n Account,\n Transfer,\n CreateAccountsError,\n CreateTransfersError,\n Operation,\n AccountFilter,\n AccountBalance,\n QueryFilter,\n} from './bindings'\nimport { randomFillSync } from 'node:crypto'\n\nconst binding: Binding = (() => {\n const { arch, platform } = process\n\n const archMap = {\n \"arm64\": \"aarch64\",\n \"x64\": \"x86_64\"\n }\n\n const platformMap = {\n \"linux\": \"linux\",\n \"darwin\": \"macos\",\n \"win32\" : \"windows\",\n }\n\n if (! (arch in archMap)) {\n throw new Error(`Unsupported arch: ${arch}`)\n }\n\n if (! (platform in platformMap)) {\n throw new Error(`Unsupported platform: ${platform}`)\n }\n\n let extra = ''\n\n /**\n * We need to detect during runtime which libc we're running on to load the correct NAPI.\n * binary.\n *\n * Rationale: The /proc/self/map_files/ subdirectory contains entries corresponding to\n * memory-mapped files loaded by Node.\n * https://man7.org/linux/man-pages/man5/proc.5.html: We detect a musl-based distro by\n * checking if any library contains the name \"musl\".\n *\n * Prior art: https://github.com/xerial/sqlite-jdbc/issues/623\n */\n\n const fs = require('fs')\n const path = require('path')\n\n if (platform === 'linux') {\n extra = '-gnu'\n\n for (const file of fs.readdirSync(\"/proc/self/map_files/\")) {\n const realPath = fs.readlinkSync(path.join(\"/proc/self/map_files/\", file))\n if (realPath.includes('musl')) {\n extra = '-musl'\n break\n }\n }\n }\n\n const filename = `./bin/${archMap[arch]}-${platformMap[platform]}${extra}/client.node`\n return require(filename)\n})()\n\nexport type Context = object // tb_client\nexport type AccountID = bigint // u128\nexport type TransferID = bigint // u128\nexport type Event = Account | Transfer | AccountID | TransferID | AccountFilter | QueryFilter\nexport type Result = CreateAccountsError | CreateTransfersError | Account | Transfer | AccountBalance\nexport type ResultCallback = (error: Error | null, results: Result[] | null) => void\n\nexport const amount_max: bigint = (2n ** 128n) - 1n\n\ninterface BindingInitArgs {\n cluster_id: bigint, // u128\n replica_addresses: Buffer,\n}\n\ninterface Binding {\n init: (args: BindingInitArgs) => Context\n submit: (context: Context, operation: Operation, batch: Event[], callback: ResultCallback) => void\n deinit: (context: Context) => void,\n}\n\nexport interface ClientInitArgs {\n cluster_id: bigint, // u128\n replica_addresses: Array<string | number>,\n}\n\nexport interface Client {\n createAccounts: (batch: Account[]) => Promise<CreateAccountsError[]>\n createTransfers: (batch: Transfer[]) => Promise<CreateTransfersError[]>\n lookupAccounts: (batch: AccountID[]) => Promise<Account[]>\n lookupTransfers: (batch: TransferID[]) => Promise<Transfer[]>\n getAccountTransfers: (filter: AccountFilter) => Promise<Transfer[]>\n getAccountBalances: (filter: AccountFilter) => Promise<AccountBalance[]>\n queryAccounts: (filter: QueryFilter) => Promise<Account[]>\n queryTransfers: (filter: QueryFilter) => Promise<Transfer[]>\n destroy: () => void\n}\n\nexport function createClient (args: ClientInitArgs): Client {\n // Context becomes null when `destroy` is called. After that point, further `request` Promises\n // throw a shutdown Error. This prevents tb_client calls from happening after tb_client_deinit().\n let context: Context | null = binding.init({\n cluster_id: args.cluster_id,\n replica_addresses: Buffer.from(args.replica_addresses.join(',')),\n })\n\n const destroy = () => {\n if (context) binding.deinit(context)\n context = null;\n }\n\n const request = <T extends Result>(operation: Operation, batch: Event[]): Promise<T[]> => {\n return new Promise((resolve, reject) => {\n try {\n if (!context) throw new Error('Client was shutdown.');\n binding.submit(context, operation, batch, (error, result) => {\n if (error) {\n reject(error)\n } else if (result) {\n resolve(result as T[])\n } else {\n throw new Error(\"UB: Binding invoked callback without error or result\")\n }\n })\n } catch (err) {\n reject(err)\n }\n })\n }\n\n return {\n createAccounts(batch) { return request(Operation.create_accounts, batch) },\n createTransfers(batch) { return request(Operation.create_transfers, batch) },\n lookupAccounts(batch) { return request(Operation.lookup_accounts, batch) },\n lookupTransfers(batch) { return request(Operation.lookup_transfers, batch) },\n getAccountTransfers(filter) { return request(Operation.get_account_transfers, [filter]) },\n getAccountBalances(filter) { return request(Operation.get_account_balances, [filter]) },\n queryAccounts(filter) { return request(Operation.query_accounts, [filter]) },\n queryTransfers(filter) { return request(Operation.query_transfers, [filter]) },\n destroy,\n }\n}\n\nlet idLastTimestamp = 0;\nlet idLastBuffer = new DataView(new ArrayBuffer(16));\n\n/**\n * Generates a Universally Unique and Sortable Identifier as a u128 bigint.\n *\n * @remarks\n * Based on {@link https://github.com/ulid/spec}, IDs returned are guaranteed to be monotonically\n * increasing.\n */\nexport function id(): bigint {\n // Ensure timestamp monotonically increases and generate a new random on each new timestamp.\n let timestamp = Date.now()\n if (timestamp <= idLastTimestamp) {\n timestamp = idLastTimestamp\n } else {\n idLastTimestamp = timestamp\n randomFillSync(idLastBuffer)\n }\n\n // Increment the u80 in idLastBuffer using carry arithmetic on u32s (as JS doesn't have fast u64).\n const littleEndian = true\n const randomLo32 = idLastBuffer.getUint32(0, littleEndian) + 1\n const randomHi32 = idLastBuffer.getUint32(4, littleEndian) + (randomLo32 > 0xFFFFFFFF ? 1 : 0)\n const randomHi16 = idLastBuffer.getUint16(8, littleEndian) + (randomHi32 > 0xFFFFFFFF ? 1 : 0)\n if (randomHi16 > 0xFFFF) {\n throw new Error('random bits overflow on monotonic increment')\n }\n\n // Store the incremented random monotonic and the timestamp into the buffer.\n idLastBuffer.setUint32(0, randomLo32 & 0xFFFFFFFF, littleEndian)\n idLastBuffer.setUint32(4, randomHi32 & 0xFFFFFFFF, littleEndian)\n idLastBuffer.setUint16(8, randomHi16, littleEndian) // No need to mask since checked above.\n idLastBuffer.setUint16(10, timestamp & 0xFFFF, littleEndian) // timestamp lo.\n idLastBuffer.setUint32(12, (timestamp >>> 16) & 0xFFFFFFFF, littleEndian) // timestamp hi.\n\n // Then return the buffer's contents as a little-endian u128 bigint.\n const lo = idLastBuffer.getBigUint64(0, littleEndian)\n const hi = idLastBuffer.getBigUint64(8, littleEndian)\n return (hi << 64n) | lo\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export * from './bindings'\nimport {\n Account,\n Transfer,\n CreateAccountsError,\n CreateTransfersError,\n Operation,\n AccountFilter,\n AccountBalance,\n QueryFilter,\n} from './bindings'\nimport { randomFillSync } from 'node:crypto'\n\nconst binding: Binding = (() => {\n const { arch, platform } = process\n\n const archMap = {\n \"arm64\": \"aarch64\",\n \"x64\": \"x86_64\"\n }\n\n const platformMap = {\n \"linux\": \"linux\",\n \"darwin\": \"macos\",\n \"win32\" : \"windows\",\n }\n\n if (! (arch in archMap)) {\n throw new Error(`Unsupported arch: ${arch}`)\n }\n\n if (! (platform in platformMap)) {\n throw new Error(`Unsupported platform: ${platform}`)\n }\n\n let extra = ''\n\n /**\n * We need to detect during runtime which libc we're running on to load the correct NAPI.\n * binary.\n *\n * Rationale: The /proc/self/map_files/ subdirectory contains entries corresponding to\n * memory-mapped files loaded by Node.\n * https://man7.org/linux/man-pages/man5/proc.5.html: We detect a musl-based distro by\n * checking if any library contains the name \"musl\".\n *\n * Prior art: https://github.com/xerial/sqlite-jdbc/issues/623\n */\n\n const fs = require('fs')\n const path = require('path')\n\n if (platform === 'linux') {\n extra = '-gnu'\n\n for (const file of fs.readdirSync(\"/proc/self/map_files/\")) {\n const realPath = fs.readlinkSync(path.join(\"/proc/self/map_files/\", file))\n if (realPath.includes('musl')) {\n extra = '-musl'\n break\n }\n }\n }\n\n const filename = `./bin/${archMap[arch]}-${platformMap[platform]}${extra}/client.node`\n return require(filename)\n})()\n\nexport type Context = object // tb_client\nexport type AccountID = bigint // u128\nexport type TransferID = bigint // u128\nexport type Event = Account | Transfer | AccountID | TransferID | AccountFilter | QueryFilter\nexport type Result = CreateAccountsError | CreateTransfersError | Account | Transfer | AccountBalance\nexport type ResultCallback = (error: Error | null, results: Result[] | null) => void\n\nexport const amount_max: bigint = (2n ** 128n) - 1n\n\ninterface BindingInitArgs {\n cluster_id: bigint, // u128\n replica_addresses: Buffer,\n}\n\ninterface Binding {\n init: (args: BindingInitArgs) => Context\n submit: (context: Context, operation: Operation, batch: Event[], callback: ResultCallback) => void\n deinit: (context: Context) => void,\n}\n\nexport interface ClientInitArgs {\n cluster_id: bigint, // u128\n replica_addresses: Array<string | number>,\n}\n\nexport interface Client {\n createAccounts: (batch: Account[]) => Promise<CreateAccountsError[]>\n createTransfers: (batch: Transfer[]) => Promise<CreateTransfersError[]>\n lookupAccounts: (batch: AccountID[]) => Promise<Account[]>\n lookupTransfers: (batch: TransferID[]) => Promise<Transfer[]>\n getAccountTransfers: (filter: AccountFilter) => Promise<Transfer[]>\n getAccountBalances: (filter: AccountFilter) => Promise<AccountBalance[]>\n queryAccounts: (filter: QueryFilter) => Promise<Account[]>\n queryTransfers: (filter: QueryFilter) => Promise<Transfer[]>\n destroy: () => void\n}\n\nexport function createClient (args: ClientInitArgs): Client {\n // Context becomes null when `destroy` is called. After that point, further `request` Promises\n // throw a shutdown Error. This prevents tb_client calls from happening after tb_client_deinit().\n let context: Context | null = binding.init({\n cluster_id: args.cluster_id,\n replica_addresses: Buffer.from(args.replica_addresses.join(',')),\n })\n\n const destroy = () => {\n if (context) binding.deinit(context)\n context = null;\n }\n\n const request = <T extends Result>(operation: Operation, batch: Event[]): Promise<T[]> => {\n return new Promise((resolve, reject) => {\n try {\n if (!context) throw new Error('Client was shutdown.');\n binding.submit(context, operation, batch, (error, result) => {\n if (error) {\n reject(error)\n } else if (result) {\n resolve(result as T[])\n } else {\n throw new Error(\"UB: Binding invoked callback without error or result\")\n }\n })\n } catch (err) {\n reject(err)\n }\n })\n }\n\n return {\n createAccounts(batch) { return request(Operation.create_accounts, batch) },\n createTransfers(batch) { return request(Operation.create_transfers, batch) },\n lookupAccounts(batch) { return request(Operation.lookup_accounts, batch) },\n lookupTransfers(batch) { return request(Operation.lookup_transfers, batch) },\n getAccountTransfers(filter) { return request(Operation.get_account_transfers, [filter]) },\n getAccountBalances(filter) { return request(Operation.get_account_balances, [filter]) },\n queryAccounts(filter) { return request(Operation.query_accounts, [filter]) },\n queryTransfers(filter) { return request(Operation.query_transfers, [filter]) },\n destroy,\n }\n}\n\nlet idLastTimestamp = 0;\n\n// These are two references to the same buffer.\n// We only need the `Uint8Array` because in Node 24, but not earlier, `crypto.randomFillSync`\n// rejects `DataView` typed arguments.\nconst idLastBuffer = new DataView(new ArrayBuffer(16));\nconst idLastBufferArray = new Uint8Array(\n idLastBuffer.buffer, idLastBuffer.byteOffset, idLastBuffer.byteLength\n);\n\n/**\n * Generates a Universally Unique and Sortable Identifier as a u128 bigint.\n *\n * @remarks\n * Based on {@link https://github.com/ulid/spec}, IDs returned are guaranteed to be monotonically\n * increasing.\n */\nexport function id(): bigint {\n // Ensure timestamp monotonically increases and generate a new random on each new timestamp.\n let timestamp = Date.now()\n if (timestamp <= idLastTimestamp) {\n timestamp = idLastTimestamp\n } else {\n idLastTimestamp = timestamp\n randomFillSync(idLastBufferArray)\n }\n\n // Increment the u80 in idLastBuffer using carry arithmetic on u32s (as JS doesn't have fast u64).\n const littleEndian = true\n const randomLo32 = idLastBuffer.getUint32(0, littleEndian) + 1\n const randomHi32 = idLastBuffer.getUint32(4, littleEndian) + (randomLo32 > 0xFFFFFFFF ? 1 : 0)\n const randomHi16 = idLastBuffer.getUint16(8, littleEndian) + (randomHi32 > 0xFFFFFFFF ? 1 : 0)\n if (randomHi16 > 0xFFFF) {\n throw new Error('random bits overflow on monotonic increment')\n }\n\n // Store the incremented random monotonic and the timestamp into the buffer.\n idLastBuffer.setUint32(0, randomLo32 & 0xFFFFFFFF, littleEndian)\n idLastBuffer.setUint32(4, randomHi32 & 0xFFFFFFFF, littleEndian)\n idLastBuffer.setUint16(8, randomHi16, littleEndian) // No need to mask since checked above.\n idLastBuffer.setUint16(10, timestamp & 0xFFFF, littleEndian) // timestamp lo.\n idLastBuffer.setUint32(12, (timestamp >>> 16) & 0xFFFFFFFF, littleEndian) // timestamp hi.\n\n // Then return the buffer's contents as a little-endian u128 bigint.\n const lo = idLastBuffer.getBigUint64(0, littleEndian)\n const hi = idLastBuffer.getBigUint64(8, littleEndian)\n return (hi << 64n) | lo\n}\n"]}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -149,7 +149,14 @@ export function createClient (args: ClientInitArgs): Client {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
let idLastTimestamp = 0;
|
|
152
|
-
|
|
152
|
+
|
|
153
|
+
// These are two references to the same buffer.
|
|
154
|
+
// We only need the `Uint8Array` because in Node 24, but not earlier, `crypto.randomFillSync`
|
|
155
|
+
// rejects `DataView` typed arguments.
|
|
156
|
+
const idLastBuffer = new DataView(new ArrayBuffer(16));
|
|
157
|
+
const idLastBufferArray = new Uint8Array(
|
|
158
|
+
idLastBuffer.buffer, idLastBuffer.byteOffset, idLastBuffer.byteLength
|
|
159
|
+
);
|
|
153
160
|
|
|
154
161
|
/**
|
|
155
162
|
* Generates a Universally Unique and Sortable Identifier as a u128 bigint.
|
|
@@ -165,7 +172,7 @@ export function id(): bigint {
|
|
|
165
172
|
timestamp = idLastTimestamp
|
|
166
173
|
} else {
|
|
167
174
|
idLastTimestamp = timestamp
|
|
168
|
-
randomFillSync(
|
|
175
|
+
randomFillSync(idLastBufferArray)
|
|
169
176
|
}
|
|
170
177
|
|
|
171
178
|
// Increment the u80 in idLastBuffer using carry arithmetic on u32s (as JS doesn't have fast u64).
|