@parix/cli 0.1.5
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 +123 -0
- package/dist/cli.cjs +30 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +28 -0
- package/dist/commands/api.cjs +81 -0
- package/dist/commands/api.d.cts +2 -0
- package/dist/commands/api.d.ts +2 -0
- package/dist/commands/api.js +78 -0
- package/dist/commands/auth.cjs +128 -0
- package/dist/commands/auth.d.cts +2 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +125 -0
- package/dist/commands/database.cjs +259 -0
- package/dist/commands/database.d.cts +2 -0
- package/dist/commands/database.d.ts +2 -0
- package/dist/commands/database.js +256 -0
- package/dist/commands/tb.cjs +242 -0
- package/dist/commands/tb.d.cts +2 -0
- package/dist/commands/tb.d.ts +2 -0
- package/dist/commands/tb.js +239 -0
- package/dist/lib/api-client.cjs +44 -0
- package/dist/lib/api-client.d.cts +10 -0
- package/dist/lib/api-client.d.ts +10 -0
- package/dist/lib/api-client.js +40 -0
- package/dist/lib/config.cjs +24 -0
- package/dist/lib/config.d.cts +10 -0
- package/dist/lib/config.d.ts +10 -0
- package/dist/lib/config.js +18 -0
- package/dist/lib/loopback-server.cjs +158 -0
- package/dist/lib/loopback-server.d.cts +20 -0
- package/dist/lib/loopback-server.d.ts +20 -0
- package/dist/lib/loopback-server.js +155 -0
- package/dist/lib/oauth-api.cjs +73 -0
- package/dist/lib/oauth-api.d.cts +31 -0
- package/dist/lib/oauth-api.d.ts +31 -0
- package/dist/lib/oauth-api.js +68 -0
- package/dist/lib/oauth-session.cjs +108 -0
- package/dist/lib/oauth-session.d.cts +32 -0
- package/dist/lib/oauth-session.d.ts +32 -0
- package/dist/lib/oauth-session.js +103 -0
- package/dist/lib/oauth.cjs +58 -0
- package/dist/lib/oauth.d.cts +19 -0
- package/dist/lib/oauth.d.ts +19 -0
- package/dist/lib/oauth.js +49 -0
- package/dist/lib/open-url.cjs +38 -0
- package/dist/lib/open-url.d.cts +1 -0
- package/dist/lib/open-url.d.ts +1 -0
- package/dist/lib/open-url.js +32 -0
- package/dist/lib/output.cjs +20 -0
- package/dist/lib/output.d.cts +6 -0
- package/dist/lib/output.d.ts +6 -0
- package/dist/lib/output.js +15 -0
- package/dist/lib/parix-api.cjs +59 -0
- package/dist/lib/parix-api.d.cts +12 -0
- package/dist/lib/parix-api.d.ts +12 -0
- package/dist/lib/parix-api.js +55 -0
- package/dist/lib/session.cjs +80 -0
- package/dist/lib/session.d.cts +28 -0
- package/dist/lib/session.d.ts +28 -0
- package/dist/lib/session.js +74 -0
- package/dist/lib/tb-payloads.cjs +153 -0
- package/dist/lib/tb-payloads.d.cts +61 -0
- package/dist/lib/tb-payloads.d.ts +61 -0
- package/dist/lib/tb-payloads.js +144 -0
- package/package.json +74 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface StoredSession {
|
|
2
|
+
version: 2;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
accessToken: string;
|
|
5
|
+
accessTokenExpiresAt: string;
|
|
6
|
+
refreshToken: string | null;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
tokenType: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
user: {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string | null;
|
|
14
|
+
emailVerified: boolean | null;
|
|
15
|
+
name: string | null;
|
|
16
|
+
image: string | null;
|
|
17
|
+
};
|
|
18
|
+
organization: {
|
|
19
|
+
id: string | null;
|
|
20
|
+
memberRole: string | null;
|
|
21
|
+
name: string | null;
|
|
22
|
+
slug: string | null;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare const SESSION_FILE_PATH: string;
|
|
26
|
+
export declare function readStoredSession(): Promise<StoredSession | null>;
|
|
27
|
+
export declare function writeStoredSession(session: StoredSession): Promise<void>;
|
|
28
|
+
export declare function clearStoredSession(): Promise<void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface StoredSession {
|
|
2
|
+
version: 2;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
accessToken: string;
|
|
5
|
+
accessTokenExpiresAt: string;
|
|
6
|
+
refreshToken: string | null;
|
|
7
|
+
scopes: string[];
|
|
8
|
+
tokenType: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
user: {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string | null;
|
|
14
|
+
emailVerified: boolean | null;
|
|
15
|
+
name: string | null;
|
|
16
|
+
image: string | null;
|
|
17
|
+
};
|
|
18
|
+
organization: {
|
|
19
|
+
id: string | null;
|
|
20
|
+
memberRole: string | null;
|
|
21
|
+
name: string | null;
|
|
22
|
+
slug: string | null;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare const SESSION_FILE_PATH: string;
|
|
26
|
+
export declare function readStoredSession(): Promise<StoredSession | null>;
|
|
27
|
+
export declare function writeStoredSession(session: StoredSession): Promise<void>;
|
|
28
|
+
export declare function clearStoredSession(): Promise<void>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
export const SESSION_FILE_PATH = join(homedir(), '.config', 'parix', 'session.json');
|
|
5
|
+
export async function readStoredSession() {
|
|
6
|
+
try {
|
|
7
|
+
const raw = await readFile(SESSION_FILE_PATH, 'utf8');
|
|
8
|
+
return parseStoredSession(JSON.parse(raw));
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (isMissingFileError(error)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (error instanceof SyntaxError) {
|
|
15
|
+
throw new TypeError(`Failed to parse ${SESSION_FILE_PATH}`);
|
|
16
|
+
}
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function writeStoredSession(session) {
|
|
21
|
+
await mkdir(dirname(SESSION_FILE_PATH), { recursive: true });
|
|
22
|
+
await writeFile(SESSION_FILE_PATH, `${JSON.stringify(session, null, 2)}\n`, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
export async function clearStoredSession() {
|
|
25
|
+
await rm(SESSION_FILE_PATH, { force: true });
|
|
26
|
+
}
|
|
27
|
+
function parseStoredSession(value) {
|
|
28
|
+
if (!value || typeof value !== 'object') {
|
|
29
|
+
throw new Error(`Invalid session data in ${SESSION_FILE_PATH}`);
|
|
30
|
+
}
|
|
31
|
+
const row = value;
|
|
32
|
+
const user = row.user;
|
|
33
|
+
const organization = row.organization;
|
|
34
|
+
if (row.version !== 2 ||
|
|
35
|
+
typeof row.baseUrl !== 'string' ||
|
|
36
|
+
typeof row.accessToken !== 'string' ||
|
|
37
|
+
typeof row.accessTokenExpiresAt !== 'string' ||
|
|
38
|
+
typeof row.createdAt !== 'string' ||
|
|
39
|
+
!Array.isArray(row.scopes) ||
|
|
40
|
+
typeof row.tokenType !== 'string' ||
|
|
41
|
+
typeof row.updatedAt !== 'string' ||
|
|
42
|
+
!user ||
|
|
43
|
+
typeof user.id !== 'string' ||
|
|
44
|
+
!organization) {
|
|
45
|
+
throw new Error(`Invalid session data in ${SESSION_FILE_PATH}`);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
version: 2,
|
|
49
|
+
accessToken: row.accessToken,
|
|
50
|
+
accessTokenExpiresAt: row.accessTokenExpiresAt,
|
|
51
|
+
baseUrl: row.baseUrl,
|
|
52
|
+
createdAt: row.createdAt,
|
|
53
|
+
refreshToken: typeof row.refreshToken === 'string' ? row.refreshToken : null,
|
|
54
|
+
scopes: row.scopes.filter((scope) => typeof scope === 'string'),
|
|
55
|
+
tokenType: row.tokenType,
|
|
56
|
+
updatedAt: row.updatedAt,
|
|
57
|
+
user: {
|
|
58
|
+
id: user.id,
|
|
59
|
+
email: typeof user.email === 'string' ? user.email : null,
|
|
60
|
+
emailVerified: typeof user.emailVerified === 'boolean' ? user.emailVerified : null,
|
|
61
|
+
name: typeof user.name === 'string' ? user.name : null,
|
|
62
|
+
image: typeof user.image === 'string' ? user.image : null,
|
|
63
|
+
},
|
|
64
|
+
organization: {
|
|
65
|
+
id: typeof organization.id === 'string' ? organization.id : null,
|
|
66
|
+
memberRole: typeof organization.memberRole === 'string' ? organization.memberRole : null,
|
|
67
|
+
name: typeof organization.name === 'string' ? organization.name : null,
|
|
68
|
+
slug: typeof organization.slug === 'string' ? organization.slug : null,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function isMissingFileError(error) {
|
|
73
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
74
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tbOperationNames = void 0;
|
|
4
|
+
exports.resolveTbPayload = resolveTbPayload;
|
|
5
|
+
exports.buildCreateAccountsPayload = buildCreateAccountsPayload;
|
|
6
|
+
exports.buildCreateTransfersPayload = buildCreateTransfersPayload;
|
|
7
|
+
exports.buildLookupPayload = buildLookupPayload;
|
|
8
|
+
exports.buildAccountFilterPayload = buildAccountFilterPayload;
|
|
9
|
+
exports.buildQueryPayload = buildQueryPayload;
|
|
10
|
+
const promises_1 = require("node:fs/promises");
|
|
11
|
+
const SPLIT_IDS_REGEX = /[\s,]+/;
|
|
12
|
+
const FLAG_NAME_TO_BIT = new Map([
|
|
13
|
+
['linked', 1 << 0],
|
|
14
|
+
['debits_must_not_exceed_credits', 1 << 1],
|
|
15
|
+
['credits_must_not_exceed_debits', 1 << 2],
|
|
16
|
+
['history', 1 << 3],
|
|
17
|
+
['imported', 1 << 4],
|
|
18
|
+
['closed', 1 << 5],
|
|
19
|
+
['pending', 1 << 1],
|
|
20
|
+
['post_pending_transfer', 1 << 2],
|
|
21
|
+
['void_pending_transfer', 1 << 3],
|
|
22
|
+
['balancing_debit', 1 << 4],
|
|
23
|
+
['balancing_credit', 1 << 5],
|
|
24
|
+
['closing_debit', 1 << 6],
|
|
25
|
+
['closing_credit', 1 << 7],
|
|
26
|
+
['debits', 1 << 0],
|
|
27
|
+
['credits', 1 << 1],
|
|
28
|
+
['reversed', 1 << 2],
|
|
29
|
+
]);
|
|
30
|
+
exports.tbOperationNames = [
|
|
31
|
+
'create_accounts',
|
|
32
|
+
'create_transfers',
|
|
33
|
+
'lookup_accounts',
|
|
34
|
+
'lookup_transfers',
|
|
35
|
+
'get_account_transfers',
|
|
36
|
+
'get_account_balances',
|
|
37
|
+
'query_accounts',
|
|
38
|
+
'query_transfers',
|
|
39
|
+
];
|
|
40
|
+
async function resolveTbPayload(options, buildFromFlags) {
|
|
41
|
+
if (options.file) {
|
|
42
|
+
return JSON.parse(await (0, promises_1.readFile)(options.file, 'utf8'));
|
|
43
|
+
}
|
|
44
|
+
if (options.payload) {
|
|
45
|
+
return JSON.parse(options.payload);
|
|
46
|
+
}
|
|
47
|
+
return buildFromFlags();
|
|
48
|
+
}
|
|
49
|
+
function buildCreateAccountsPayload(options) {
|
|
50
|
+
return [
|
|
51
|
+
omitEmpty({
|
|
52
|
+
code: requiredValue(options.code, '--code'),
|
|
53
|
+
flags: flagsBitfield(options.flags),
|
|
54
|
+
id: options.id ?? randomTbId(),
|
|
55
|
+
ledger: requiredValue(options.ledger, '--ledger'),
|
|
56
|
+
user_data_128: options.userData128,
|
|
57
|
+
user_data_32: options.userData32,
|
|
58
|
+
user_data_64: options.userData64,
|
|
59
|
+
}),
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
function buildCreateTransfersPayload(options) {
|
|
63
|
+
return [
|
|
64
|
+
omitEmpty({
|
|
65
|
+
amount: requiredValue(options.amount, '--amount'),
|
|
66
|
+
code: requiredValue(options.code, '--code'),
|
|
67
|
+
credit_account_id: requiredValue(options.creditAccountId, '--to'),
|
|
68
|
+
debit_account_id: requiredValue(options.debitAccountId, '--from'),
|
|
69
|
+
flags: flagsBitfield(options.flags),
|
|
70
|
+
id: options.id ?? randomTbId(),
|
|
71
|
+
ledger: requiredValue(options.ledger, '--ledger'),
|
|
72
|
+
pending_id: options.pendingId,
|
|
73
|
+
timeout: options.timeout,
|
|
74
|
+
}),
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
function buildLookupPayload(options) {
|
|
78
|
+
const ids = [...(options.id ?? []), ...splitIds(options.ids)];
|
|
79
|
+
if (ids.length === 0) {
|
|
80
|
+
throw new Error('Provide at least one `--id` or `--ids` value.');
|
|
81
|
+
}
|
|
82
|
+
return ids;
|
|
83
|
+
}
|
|
84
|
+
function buildAccountFilterPayload(options) {
|
|
85
|
+
return omitEmpty({
|
|
86
|
+
account_id: requiredValue(options.accountId, '--account-id'),
|
|
87
|
+
code: options.code,
|
|
88
|
+
flags: flagsBitfield(options.flags),
|
|
89
|
+
limit: requiredValue(options.limit, '--limit'),
|
|
90
|
+
timestamp_max: options.timestampMax,
|
|
91
|
+
timestamp_min: options.timestampMin,
|
|
92
|
+
user_data_128: options.userData128,
|
|
93
|
+
user_data_32: options.userData32,
|
|
94
|
+
user_data_64: options.userData64,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function buildQueryPayload(options) {
|
|
98
|
+
return omitEmpty({
|
|
99
|
+
code: options.code,
|
|
100
|
+
flags: flagsBitfield(options.flags),
|
|
101
|
+
ledger: options.ledger,
|
|
102
|
+
limit: requiredValue(options.limit, '--limit'),
|
|
103
|
+
timestamp_max: options.timestampMax,
|
|
104
|
+
timestamp_min: options.timestampMin,
|
|
105
|
+
user_data_128: options.userData128,
|
|
106
|
+
user_data_32: options.userData32,
|
|
107
|
+
user_data_64: options.userData64,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function flagsBitfield(flags) {
|
|
111
|
+
if (!flags || flags.length === 0) {
|
|
112
|
+
return '0';
|
|
113
|
+
}
|
|
114
|
+
let bitfield = 0;
|
|
115
|
+
for (const flag of flags) {
|
|
116
|
+
const normalized = flag.trim();
|
|
117
|
+
if (!normalized) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const direct = Number.parseInt(normalized, 10);
|
|
121
|
+
if (Number.isInteger(direct) && direct >= 0) {
|
|
122
|
+
bitfield |= direct;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const bit = FLAG_NAME_TO_BIT.get(normalized);
|
|
126
|
+
if (bit === undefined) {
|
|
127
|
+
throw new Error(`Unsupported flag: ${flag}`);
|
|
128
|
+
}
|
|
129
|
+
bitfield |= bit;
|
|
130
|
+
}
|
|
131
|
+
return bitfield.toString();
|
|
132
|
+
}
|
|
133
|
+
function omitEmpty(input) {
|
|
134
|
+
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined && value.trim().length > 0));
|
|
135
|
+
}
|
|
136
|
+
function randomTbId() {
|
|
137
|
+
return BigInt(`0x${crypto.getRandomValues(new Uint8Array(16)).reduce((value, byte) => value + byte.toString(16).padStart(2, '0'), '')}`).toString();
|
|
138
|
+
}
|
|
139
|
+
function requiredValue(value, flagName) {
|
|
140
|
+
if (!value || value.trim().length === 0) {
|
|
141
|
+
throw new Error(`${flagName} is required unless --payload or --file is used.`);
|
|
142
|
+
}
|
|
143
|
+
return value.trim();
|
|
144
|
+
}
|
|
145
|
+
function splitIds(value) {
|
|
146
|
+
if (!value) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
return value
|
|
150
|
+
.split(SPLIT_IDS_REGEX)
|
|
151
|
+
.map((item) => item.trim())
|
|
152
|
+
.filter(Boolean);
|
|
153
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export declare const tbOperationNames: readonly ["create_accounts", "create_transfers", "lookup_accounts", "lookup_transfers", "get_account_transfers", "get_account_balances", "query_accounts", "query_transfers"];
|
|
2
|
+
export type TbOperationName = (typeof tbOperationNames)[number];
|
|
3
|
+
export interface PayloadOverrideOptions {
|
|
4
|
+
file?: string;
|
|
5
|
+
payload?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveTbPayload<T>(options: PayloadOverrideOptions, buildFromFlags: () => T): Promise<T>;
|
|
8
|
+
export declare function buildCreateAccountsPayload(options: {
|
|
9
|
+
code?: string;
|
|
10
|
+
flags?: string[];
|
|
11
|
+
id?: string;
|
|
12
|
+
ledger?: string;
|
|
13
|
+
userData128?: string;
|
|
14
|
+
userData32?: string;
|
|
15
|
+
userData64?: string;
|
|
16
|
+
}): {
|
|
17
|
+
[k: string]: string | undefined;
|
|
18
|
+
}[];
|
|
19
|
+
export declare function buildCreateTransfersPayload(options: {
|
|
20
|
+
amount?: string;
|
|
21
|
+
code?: string;
|
|
22
|
+
creditAccountId?: string;
|
|
23
|
+
debitAccountId?: string;
|
|
24
|
+
flags?: string[];
|
|
25
|
+
id?: string;
|
|
26
|
+
ledger?: string;
|
|
27
|
+
pendingId?: string;
|
|
28
|
+
timeout?: string;
|
|
29
|
+
}): {
|
|
30
|
+
[k: string]: string | undefined;
|
|
31
|
+
}[];
|
|
32
|
+
export declare function buildLookupPayload(options: {
|
|
33
|
+
id?: string[];
|
|
34
|
+
ids?: string;
|
|
35
|
+
}): string[];
|
|
36
|
+
export declare function buildAccountFilterPayload(options: {
|
|
37
|
+
accountId?: string;
|
|
38
|
+
code?: string;
|
|
39
|
+
flags?: string[];
|
|
40
|
+
limit?: string;
|
|
41
|
+
timestampMax?: string;
|
|
42
|
+
timestampMin?: string;
|
|
43
|
+
userData128?: string;
|
|
44
|
+
userData32?: string;
|
|
45
|
+
userData64?: string;
|
|
46
|
+
}): {
|
|
47
|
+
[k: string]: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
export declare function buildQueryPayload(options: {
|
|
50
|
+
code?: string;
|
|
51
|
+
flags?: string[];
|
|
52
|
+
ledger?: string;
|
|
53
|
+
limit?: string;
|
|
54
|
+
timestampMax?: string;
|
|
55
|
+
timestampMin?: string;
|
|
56
|
+
userData128?: string;
|
|
57
|
+
userData32?: string;
|
|
58
|
+
userData64?: string;
|
|
59
|
+
}): {
|
|
60
|
+
[k: string]: string | undefined;
|
|
61
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export declare const tbOperationNames: readonly ["create_accounts", "create_transfers", "lookup_accounts", "lookup_transfers", "get_account_transfers", "get_account_balances", "query_accounts", "query_transfers"];
|
|
2
|
+
export type TbOperationName = (typeof tbOperationNames)[number];
|
|
3
|
+
export interface PayloadOverrideOptions {
|
|
4
|
+
file?: string;
|
|
5
|
+
payload?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveTbPayload<T>(options: PayloadOverrideOptions, buildFromFlags: () => T): Promise<T>;
|
|
8
|
+
export declare function buildCreateAccountsPayload(options: {
|
|
9
|
+
code?: string;
|
|
10
|
+
flags?: string[];
|
|
11
|
+
id?: string;
|
|
12
|
+
ledger?: string;
|
|
13
|
+
userData128?: string;
|
|
14
|
+
userData32?: string;
|
|
15
|
+
userData64?: string;
|
|
16
|
+
}): {
|
|
17
|
+
[k: string]: string | undefined;
|
|
18
|
+
}[];
|
|
19
|
+
export declare function buildCreateTransfersPayload(options: {
|
|
20
|
+
amount?: string;
|
|
21
|
+
code?: string;
|
|
22
|
+
creditAccountId?: string;
|
|
23
|
+
debitAccountId?: string;
|
|
24
|
+
flags?: string[];
|
|
25
|
+
id?: string;
|
|
26
|
+
ledger?: string;
|
|
27
|
+
pendingId?: string;
|
|
28
|
+
timeout?: string;
|
|
29
|
+
}): {
|
|
30
|
+
[k: string]: string | undefined;
|
|
31
|
+
}[];
|
|
32
|
+
export declare function buildLookupPayload(options: {
|
|
33
|
+
id?: string[];
|
|
34
|
+
ids?: string;
|
|
35
|
+
}): string[];
|
|
36
|
+
export declare function buildAccountFilterPayload(options: {
|
|
37
|
+
accountId?: string;
|
|
38
|
+
code?: string;
|
|
39
|
+
flags?: string[];
|
|
40
|
+
limit?: string;
|
|
41
|
+
timestampMax?: string;
|
|
42
|
+
timestampMin?: string;
|
|
43
|
+
userData128?: string;
|
|
44
|
+
userData32?: string;
|
|
45
|
+
userData64?: string;
|
|
46
|
+
}): {
|
|
47
|
+
[k: string]: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
export declare function buildQueryPayload(options: {
|
|
50
|
+
code?: string;
|
|
51
|
+
flags?: string[];
|
|
52
|
+
ledger?: string;
|
|
53
|
+
limit?: string;
|
|
54
|
+
timestampMax?: string;
|
|
55
|
+
timestampMin?: string;
|
|
56
|
+
userData128?: string;
|
|
57
|
+
userData32?: string;
|
|
58
|
+
userData64?: string;
|
|
59
|
+
}): {
|
|
60
|
+
[k: string]: string | undefined;
|
|
61
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
const SPLIT_IDS_REGEX = /[\s,]+/;
|
|
3
|
+
const FLAG_NAME_TO_BIT = new Map([
|
|
4
|
+
['linked', 1 << 0],
|
|
5
|
+
['debits_must_not_exceed_credits', 1 << 1],
|
|
6
|
+
['credits_must_not_exceed_debits', 1 << 2],
|
|
7
|
+
['history', 1 << 3],
|
|
8
|
+
['imported', 1 << 4],
|
|
9
|
+
['closed', 1 << 5],
|
|
10
|
+
['pending', 1 << 1],
|
|
11
|
+
['post_pending_transfer', 1 << 2],
|
|
12
|
+
['void_pending_transfer', 1 << 3],
|
|
13
|
+
['balancing_debit', 1 << 4],
|
|
14
|
+
['balancing_credit', 1 << 5],
|
|
15
|
+
['closing_debit', 1 << 6],
|
|
16
|
+
['closing_credit', 1 << 7],
|
|
17
|
+
['debits', 1 << 0],
|
|
18
|
+
['credits', 1 << 1],
|
|
19
|
+
['reversed', 1 << 2],
|
|
20
|
+
]);
|
|
21
|
+
export const tbOperationNames = [
|
|
22
|
+
'create_accounts',
|
|
23
|
+
'create_transfers',
|
|
24
|
+
'lookup_accounts',
|
|
25
|
+
'lookup_transfers',
|
|
26
|
+
'get_account_transfers',
|
|
27
|
+
'get_account_balances',
|
|
28
|
+
'query_accounts',
|
|
29
|
+
'query_transfers',
|
|
30
|
+
];
|
|
31
|
+
export async function resolveTbPayload(options, buildFromFlags) {
|
|
32
|
+
if (options.file) {
|
|
33
|
+
return JSON.parse(await readFile(options.file, 'utf8'));
|
|
34
|
+
}
|
|
35
|
+
if (options.payload) {
|
|
36
|
+
return JSON.parse(options.payload);
|
|
37
|
+
}
|
|
38
|
+
return buildFromFlags();
|
|
39
|
+
}
|
|
40
|
+
export function buildCreateAccountsPayload(options) {
|
|
41
|
+
return [
|
|
42
|
+
omitEmpty({
|
|
43
|
+
code: requiredValue(options.code, '--code'),
|
|
44
|
+
flags: flagsBitfield(options.flags),
|
|
45
|
+
id: options.id ?? randomTbId(),
|
|
46
|
+
ledger: requiredValue(options.ledger, '--ledger'),
|
|
47
|
+
user_data_128: options.userData128,
|
|
48
|
+
user_data_32: options.userData32,
|
|
49
|
+
user_data_64: options.userData64,
|
|
50
|
+
}),
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
export function buildCreateTransfersPayload(options) {
|
|
54
|
+
return [
|
|
55
|
+
omitEmpty({
|
|
56
|
+
amount: requiredValue(options.amount, '--amount'),
|
|
57
|
+
code: requiredValue(options.code, '--code'),
|
|
58
|
+
credit_account_id: requiredValue(options.creditAccountId, '--to'),
|
|
59
|
+
debit_account_id: requiredValue(options.debitAccountId, '--from'),
|
|
60
|
+
flags: flagsBitfield(options.flags),
|
|
61
|
+
id: options.id ?? randomTbId(),
|
|
62
|
+
ledger: requiredValue(options.ledger, '--ledger'),
|
|
63
|
+
pending_id: options.pendingId,
|
|
64
|
+
timeout: options.timeout,
|
|
65
|
+
}),
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
export function buildLookupPayload(options) {
|
|
69
|
+
const ids = [...(options.id ?? []), ...splitIds(options.ids)];
|
|
70
|
+
if (ids.length === 0) {
|
|
71
|
+
throw new Error('Provide at least one `--id` or `--ids` value.');
|
|
72
|
+
}
|
|
73
|
+
return ids;
|
|
74
|
+
}
|
|
75
|
+
export function buildAccountFilterPayload(options) {
|
|
76
|
+
return omitEmpty({
|
|
77
|
+
account_id: requiredValue(options.accountId, '--account-id'),
|
|
78
|
+
code: options.code,
|
|
79
|
+
flags: flagsBitfield(options.flags),
|
|
80
|
+
limit: requiredValue(options.limit, '--limit'),
|
|
81
|
+
timestamp_max: options.timestampMax,
|
|
82
|
+
timestamp_min: options.timestampMin,
|
|
83
|
+
user_data_128: options.userData128,
|
|
84
|
+
user_data_32: options.userData32,
|
|
85
|
+
user_data_64: options.userData64,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
export function buildQueryPayload(options) {
|
|
89
|
+
return omitEmpty({
|
|
90
|
+
code: options.code,
|
|
91
|
+
flags: flagsBitfield(options.flags),
|
|
92
|
+
ledger: options.ledger,
|
|
93
|
+
limit: requiredValue(options.limit, '--limit'),
|
|
94
|
+
timestamp_max: options.timestampMax,
|
|
95
|
+
timestamp_min: options.timestampMin,
|
|
96
|
+
user_data_128: options.userData128,
|
|
97
|
+
user_data_32: options.userData32,
|
|
98
|
+
user_data_64: options.userData64,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function flagsBitfield(flags) {
|
|
102
|
+
if (!flags || flags.length === 0) {
|
|
103
|
+
return '0';
|
|
104
|
+
}
|
|
105
|
+
let bitfield = 0;
|
|
106
|
+
for (const flag of flags) {
|
|
107
|
+
const normalized = flag.trim();
|
|
108
|
+
if (!normalized) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const direct = Number.parseInt(normalized, 10);
|
|
112
|
+
if (Number.isInteger(direct) && direct >= 0) {
|
|
113
|
+
bitfield |= direct;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const bit = FLAG_NAME_TO_BIT.get(normalized);
|
|
117
|
+
if (bit === undefined) {
|
|
118
|
+
throw new Error(`Unsupported flag: ${flag}`);
|
|
119
|
+
}
|
|
120
|
+
bitfield |= bit;
|
|
121
|
+
}
|
|
122
|
+
return bitfield.toString();
|
|
123
|
+
}
|
|
124
|
+
function omitEmpty(input) {
|
|
125
|
+
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined && value.trim().length > 0));
|
|
126
|
+
}
|
|
127
|
+
function randomTbId() {
|
|
128
|
+
return BigInt(`0x${crypto.getRandomValues(new Uint8Array(16)).reduce((value, byte) => value + byte.toString(16).padStart(2, '0'), '')}`).toString();
|
|
129
|
+
}
|
|
130
|
+
function requiredValue(value, flagName) {
|
|
131
|
+
if (!value || value.trim().length === 0) {
|
|
132
|
+
throw new Error(`${flagName} is required unless --payload or --file is used.`);
|
|
133
|
+
}
|
|
134
|
+
return value.trim();
|
|
135
|
+
}
|
|
136
|
+
function splitIds(value) {
|
|
137
|
+
if (!value) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
return value
|
|
141
|
+
.split(SPLIT_IDS_REGEX)
|
|
142
|
+
.map((item) => item.trim())
|
|
143
|
+
.filter(Boolean);
|
|
144
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@parix/cli",
|
|
3
|
+
"description": "Parix command line interface",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.1.5",
|
|
6
|
+
"bin": {
|
|
7
|
+
"parix": "dist/cli.cjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"packageManager": "bun@1.3.12",
|
|
13
|
+
"homepage": "https://github.com/parixtech/parix-cli#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/parixtech/parix-cli/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/parixtech/parix-cli.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"parix",
|
|
23
|
+
"cli",
|
|
24
|
+
"parix",
|
|
25
|
+
"database",
|
|
26
|
+
"tigerbeetle"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "zshy && node scripts/normalize-package-bin.mjs && chmod +x dist/cli.cjs",
|
|
33
|
+
"build:link": "bun run build && bun link",
|
|
34
|
+
"fmt": "oxfmt --write src test scripts package.json tsconfig.json .oxlintrc.json .oxfmtrc.json commitlint.config.js",
|
|
35
|
+
"fmt:check": "oxfmt --check src test scripts package.json tsconfig.json .oxlintrc.json .oxfmtrc.json commitlint.config.js",
|
|
36
|
+
"lint": "oxlint src test scripts",
|
|
37
|
+
"lint:fix": "oxlint --fix src test scripts",
|
|
38
|
+
"test": "bun test",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"cli": "node ./dist/cli.cjs",
|
|
41
|
+
"pack:dry-run": "npm pack --dry-run --cache .npm-cache",
|
|
42
|
+
"publish:check": "bun run fmt:check && bun run lint && bun run test && bun run typecheck && bun run build && bun run pack:dry-run",
|
|
43
|
+
"prepublishOnly": "bun run publish:check",
|
|
44
|
+
"publish:npm": "npm publish --access public --cache .npm-cache",
|
|
45
|
+
"prepare": "husky"
|
|
46
|
+
},
|
|
47
|
+
"zshy": {
|
|
48
|
+
"bin": {
|
|
49
|
+
"parix": "./src/cli.ts"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@clack/prompts": "^0.8.2",
|
|
54
|
+
"commander": "^14.0.3"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
58
|
+
"@types/node": "^25.3.0",
|
|
59
|
+
"husky": "^9.1.7",
|
|
60
|
+
"lint-staged": "^16.4.0",
|
|
61
|
+
"oxfmt": "^0.46.0",
|
|
62
|
+
"oxlint": "^1.61.0",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"zshy": "^0.7.0"
|
|
65
|
+
},
|
|
66
|
+
"lint-staged": {
|
|
67
|
+
"*.{js,ts,json}": [
|
|
68
|
+
"oxfmt --write"
|
|
69
|
+
],
|
|
70
|
+
"*.{js,ts}": [
|
|
71
|
+
"oxlint --fix src test scripts"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|