tenjin-cli 0.1.0-alpha.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/NOTICE.md +52 -0
- package/README.md +124 -0
- package/dist/_esm-ZH2J4QEH.js +3737 -0
- package/dist/_esm-ZH2J4QEH.js.map +1 -0
- package/dist/ccip-FXWZDDF5.js +17 -0
- package/dist/ccip-FXWZDDF5.js.map +1 -0
- package/dist/chunk-376LHMK2.js +100 -0
- package/dist/chunk-376LHMK2.js.map +1 -0
- package/dist/chunk-3IMLRUZE.js +44 -0
- package/dist/chunk-3IMLRUZE.js.map +1 -0
- package/dist/chunk-CPUZRZ2A.js +410 -0
- package/dist/chunk-CPUZRZ2A.js.map +1 -0
- package/dist/chunk-F5DZJLU3.js +2058 -0
- package/dist/chunk-F5DZJLU3.js.map +1 -0
- package/dist/chunk-FIYZLITH.js +14577 -0
- package/dist/chunk-FIYZLITH.js.map +1 -0
- package/dist/chunk-LTTRND4A.js +135 -0
- package/dist/chunk-LTTRND4A.js.map +1 -0
- package/dist/chunk-PAAL45FJ.js +7307 -0
- package/dist/chunk-PAAL45FJ.js.map +1 -0
- package/dist/chunk-QHIEYBLV.js +320 -0
- package/dist/chunk-QHIEYBLV.js.map +1 -0
- package/dist/chunk-SXQQ2ZSR.js +887 -0
- package/dist/chunk-SXQQ2ZSR.js.map +1 -0
- package/dist/chunk-TX5T3LKJ.js +2249 -0
- package/dist/chunk-TX5T3LKJ.js.map +1 -0
- package/dist/chunk-WOHCAMDQ.js +4474 -0
- package/dist/chunk-WOHCAMDQ.js.map +1 -0
- package/dist/chunk-ZPZFPVDN.js +67 -0
- package/dist/chunk-ZPZFPVDN.js.map +1 -0
- package/dist/cli-LMHGCZ5S.js +3763 -0
- package/dist/cli-LMHGCZ5S.js.map +1 -0
- package/dist/config-XVXZ3V2Q.js +206 -0
- package/dist/config-XVXZ3V2Q.js.map +1 -0
- package/dist/doctor-MVLZRVPU.js +338 -0
- package/dist/doctor-MVLZRVPU.js.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/mine.wasm-GQECMSGN.js +11 -0
- package/dist/mine.wasm-GQECMSGN.js.map +1 -0
- package/dist/secp256k1-35YNNB6F.js +18 -0
- package/dist/secp256k1-35YNNB6F.js.map +1 -0
- package/dist/usdc-OQUOFF6R.js +18 -0
- package/dist/usdc-OQUOFF6R.js.map +1 -0
- package/dist/wallet-NRKWLKHX.js +153 -0
- package/dist/wallet-NRKWLKHX.js.map +1 -0
- package/dist/wallet-QUWK2PA4.js +22 -0
- package/dist/wallet-QUWK2PA4.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createRequire as __tenjinCreateRequire } from 'node:module'; const require = __tenjinCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
CliError,
|
|
4
|
+
configPath,
|
|
5
|
+
external_exports
|
|
6
|
+
} from "./chunk-FIYZLITH.js";
|
|
7
|
+
|
|
8
|
+
// src/lib/config.ts
|
|
9
|
+
import { readFile } from "fs/promises";
|
|
10
|
+
var atomicString = external_exports.string().regex(/^\d+$/, "expected an atomic USDC integer string");
|
|
11
|
+
var ConfigSchema = external_exports.object({
|
|
12
|
+
maxAutoSpend: atomicString,
|
|
13
|
+
sessionBudget: atomicString,
|
|
14
|
+
confirm: external_exports.union([external_exports.literal("always"), external_exports.string().regex(/^above:\d+$/)]),
|
|
15
|
+
allowlistCreators: external_exports.array(external_exports.string()),
|
|
16
|
+
baseUrl: external_exports.url(),
|
|
17
|
+
rpcUrl: external_exports.url()
|
|
18
|
+
});
|
|
19
|
+
var RawConfigSchema = ConfigSchema.partial();
|
|
20
|
+
var CONFIG_DEFAULTS = {
|
|
21
|
+
maxAutoSpend: "0",
|
|
22
|
+
sessionBudget: "0",
|
|
23
|
+
confirm: "always",
|
|
24
|
+
allowlistCreators: [],
|
|
25
|
+
baseUrl: "https://tenjin.blog",
|
|
26
|
+
rpcUrl: "https://mainnet.base.org"
|
|
27
|
+
};
|
|
28
|
+
var CONFIG_KEYS = Object.keys(CONFIG_DEFAULTS);
|
|
29
|
+
async function loadRawConfig(dir) {
|
|
30
|
+
const path = configPath(dir);
|
|
31
|
+
let raw;
|
|
32
|
+
try {
|
|
33
|
+
raw = await readFile(path, "utf8");
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (isNotFound(err)) return {};
|
|
36
|
+
throw new CliError("CONFIG_INVALID", `Could not read config at ${path}`, {
|
|
37
|
+
fix: `Check file permissions on ${path}.`,
|
|
38
|
+
cause: err
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
let json;
|
|
42
|
+
try {
|
|
43
|
+
json = JSON.parse(raw);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
throw new CliError("CONFIG_INVALID", `Config at ${path} is not valid JSON`, {
|
|
46
|
+
fix: `Fix the JSON syntax in ${path}, or delete it to restore defaults.`,
|
|
47
|
+
cause: err
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const parsed = RawConfigSchema.safeParse(json);
|
|
51
|
+
if (!parsed.success) {
|
|
52
|
+
throw new CliError("CONFIG_INVALID", `Config at ${path} is invalid`, {
|
|
53
|
+
fix: `Correct the reported keys in ${path}, or delete it to restore defaults.`,
|
|
54
|
+
details: parsed.error.issues
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return parsed.data;
|
|
58
|
+
}
|
|
59
|
+
function resolveSettings(input) {
|
|
60
|
+
const { config, flags, env } = input;
|
|
61
|
+
return {
|
|
62
|
+
maxAutoSpend: fileOrDefault("maxAutoSpend", config),
|
|
63
|
+
sessionBudget: fileOrDefault("sessionBudget", config),
|
|
64
|
+
confirm: fileOrDefault("confirm", config),
|
|
65
|
+
allowlistCreators: fileOrDefault("allowlistCreators", config),
|
|
66
|
+
baseUrl: resolveBaseUrl(config, flags, env),
|
|
67
|
+
rpcUrl: fileOrDefault("rpcUrl", config)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function fileOrDefault(key, config) {
|
|
71
|
+
const fromFile = config[key];
|
|
72
|
+
if (fromFile !== void 0) return { value: fromFile, source: "file" };
|
|
73
|
+
return { value: CONFIG_DEFAULTS[key], source: "default" };
|
|
74
|
+
}
|
|
75
|
+
function resolveBaseUrl(config, flags, env) {
|
|
76
|
+
if (flags.baseUrl !== void 0 && flags.baseUrl.length > 0) {
|
|
77
|
+
return { value: flags.baseUrl, source: "flag" };
|
|
78
|
+
}
|
|
79
|
+
const fromEnv = env.TENJIN_BASE_URL;
|
|
80
|
+
if (fromEnv !== void 0 && fromEnv.length > 0) {
|
|
81
|
+
return { value: fromEnv, source: "env" };
|
|
82
|
+
}
|
|
83
|
+
if (config.baseUrl !== void 0) return { value: config.baseUrl, source: "file" };
|
|
84
|
+
return { value: CONFIG_DEFAULTS.baseUrl, source: "default" };
|
|
85
|
+
}
|
|
86
|
+
function isNotFound(err) {
|
|
87
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/lib/money.ts
|
|
91
|
+
var USDC_DECIMALS = 6;
|
|
92
|
+
function parseUsdToAtomic(input) {
|
|
93
|
+
const trimmed = input.trim();
|
|
94
|
+
if (!/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
95
|
+
throw new CliError("USAGE", `Invalid USD amount: ${JSON.stringify(input)}`, {
|
|
96
|
+
fix: "Pass a non-negative decimal like 0.25 or 5."
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const [whole, frac = ""] = trimmed.split(".");
|
|
100
|
+
if (frac.length > USDC_DECIMALS) {
|
|
101
|
+
throw new CliError(
|
|
102
|
+
"USAGE",
|
|
103
|
+
`USD amount ${JSON.stringify(input)} has more than 6 decimal places`,
|
|
104
|
+
{
|
|
105
|
+
fix: "USDC supports at most 6 decimal places (micro-dollars)."
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const atomic = BigInt(`${whole}${frac.padEnd(USDC_DECIMALS, "0")}`);
|
|
110
|
+
return atomic.toString();
|
|
111
|
+
}
|
|
112
|
+
function atomicToUsd(atomic) {
|
|
113
|
+
const trimmed = atomic.trim();
|
|
114
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
115
|
+
throw new CliError("INTERNAL", `Malformed atomic amount: ${JSON.stringify(atomic)}`);
|
|
116
|
+
}
|
|
117
|
+
const value = BigInt(trimmed);
|
|
118
|
+
const base = 10n ** BigInt(USDC_DECIMALS);
|
|
119
|
+
const whole = value / base;
|
|
120
|
+
const frac = (value % base).toString().padStart(USDC_DECIMALS, "0").replace(/0+$/, "");
|
|
121
|
+
return frac.length > 0 ? `${whole}.${frac}` : whole.toString();
|
|
122
|
+
}
|
|
123
|
+
function toMoney(atomic) {
|
|
124
|
+
return { atomic, usd: atomicToUsd(atomic) };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
RawConfigSchema,
|
|
129
|
+
CONFIG_KEYS,
|
|
130
|
+
loadRawConfig,
|
|
131
|
+
resolveSettings,
|
|
132
|
+
parseUsdToAtomic,
|
|
133
|
+
toMoney
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=chunk-LTTRND4A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/config.ts","../src/lib/money.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { z } from 'zod';\nimport { CliError } from './errors';\nimport { configPath } from './paths';\nimport { writeFileAtomic } from './atomic-json';\n\n/** A non-negative integer string in USDC atomic units (6-decimal base). */\nconst atomicString = z.string().regex(/^\\d+$/, 'expected an atomic USDC integer string');\n\n/**\n * The persisted config shape. Spend keys are stored atomic (accepted as decimal\n * USD at the command edge, see lib/money); `confirm` is the stored form\n * \"always\" | \"above:<atomic>\". These are client-enforced guardrails, not a\n * security boundary — any process that runs the CLI can also edit this file.\n */\nexport const ConfigSchema = z.object({\n maxAutoSpend: atomicString,\n sessionBudget: atomicString,\n confirm: z.union([z.literal('always'), z.string().regex(/^above:\\d+$/)]),\n allowlistCreators: z.array(z.string()),\n baseUrl: z.url(),\n rpcUrl: z.url(),\n});\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Values as they may appear in config.json — every key optional; absent = default. */\nexport const RawConfigSchema = ConfigSchema.partial();\nexport type PartialConfig = z.infer<typeof RawConfigSchema>;\n\nexport const CONFIG_DEFAULTS: Config = {\n maxAutoSpend: '0',\n sessionBudget: '0',\n confirm: 'always',\n allowlistCreators: [],\n baseUrl: 'https://tenjin.blog',\n rpcUrl: 'https://mainnet.base.org',\n};\n\nexport const CONFIG_KEYS = Object.keys(CONFIG_DEFAULTS) as Array<keyof Config>;\n\n/**\n * Read and validate config.json WITHOUT applying defaults, so provenance can\n * distinguish \"present in file\" from \"absent\". Missing file is fine (returns\n * {}); malformed JSON or a failed schema is CONFIG_INVALID with a fix.\n */\nexport async function loadRawConfig(dir: string): Promise<PartialConfig> {\n const path = configPath(dir);\n let raw: string;\n try {\n raw = await readFile(path, 'utf8');\n } catch (err) {\n if (isNotFound(err)) return {};\n throw new CliError('CONFIG_INVALID', `Could not read config at ${path}`, {\n fix: `Check file permissions on ${path}.`,\n cause: err,\n });\n }\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch (err) {\n throw new CliError('CONFIG_INVALID', `Config at ${path} is not valid JSON`, {\n fix: `Fix the JSON syntax in ${path}, or delete it to restore defaults.`,\n cause: err,\n });\n }\n const parsed = RawConfigSchema.safeParse(json);\n if (!parsed.success) {\n throw new CliError('CONFIG_INVALID', `Config at ${path} is invalid`, {\n fix: `Correct the reported keys in ${path}, or delete it to restore defaults.`,\n details: parsed.error.issues,\n });\n }\n return parsed.data;\n}\n\n/** File values merged over defaults — the effective persisted config. */\nexport async function loadConfig(dir: string): Promise<Config> {\n return { ...CONFIG_DEFAULTS, ...(await loadRawConfig(dir)) };\n}\n\nexport type Provenance = 'default' | 'file' | 'env' | 'flag';\n\nexport interface ResolvedSetting<T> {\n value: T;\n source: Provenance;\n}\n\n/** Effective value + where it came from, per key. What `config` (bare) renders. */\nexport interface EffectiveSettings {\n maxAutoSpend: ResolvedSetting<string>;\n sessionBudget: ResolvedSetting<string>;\n confirm: ResolvedSetting<string>;\n allowlistCreators: ResolvedSetting<string[]>;\n baseUrl: ResolvedSetting<string>;\n rpcUrl: ResolvedSetting<string>;\n}\n\n/** CLI flags that participate in settings precedence (global `--base-url`). */\nexport interface SettingsFlags {\n baseUrl?: string;\n}\n\nexport interface ResolveSettingsInput {\n /** Raw file values (present keys only) — from loadRawConfig, not loadConfig. */\n config: PartialConfig;\n flags: SettingsFlags;\n env: NodeJS.ProcessEnv;\n}\n\n/**\n * Apply precedence flag > env > file > default per key, returning each effective\n * value with its source. In B1 only baseUrl has flag/env overrides\n * (`--base-url`, TENJIN_BASE_URL); the rest resolve file-or-default.\n */\nexport function resolveSettings(input: ResolveSettingsInput): EffectiveSettings {\n const { config, flags, env } = input;\n return {\n maxAutoSpend: fileOrDefault('maxAutoSpend', config),\n sessionBudget: fileOrDefault('sessionBudget', config),\n confirm: fileOrDefault('confirm', config),\n allowlistCreators: fileOrDefault('allowlistCreators', config),\n baseUrl: resolveBaseUrl(config, flags, env),\n rpcUrl: fileOrDefault('rpcUrl', config),\n };\n}\n\n/** Persist a full, validated config via the atomic writer (0700 dir, 0644 file). */\nexport async function writeConfig(dir: string, config: Config): Promise<void> {\n const validated = ConfigSchema.parse(config);\n await writeFileAtomic(configPath(dir), `${JSON.stringify(validated, null, 2)}\\n`, {\n mode: 0o644,\n dirMode: 0o700,\n });\n}\n\nfunction fileOrDefault<K extends keyof Config>(\n key: K,\n config: PartialConfig,\n): ResolvedSetting<Config[K]> {\n const fromFile = config[key];\n // PartialConfig[K] is Config[K] | undefined; narrowing an indexed access of a\n // type parameter doesn't refine K, so assert the excluded-undefined type.\n if (fromFile !== undefined) return { value: fromFile as Config[K], source: 'file' };\n return { value: CONFIG_DEFAULTS[key], source: 'default' };\n}\n\nfunction resolveBaseUrl(\n config: PartialConfig,\n flags: SettingsFlags,\n env: NodeJS.ProcessEnv,\n): ResolvedSetting<string> {\n if (flags.baseUrl !== undefined && flags.baseUrl.length > 0) {\n return { value: flags.baseUrl, source: 'flag' };\n }\n const fromEnv = env.TENJIN_BASE_URL;\n if (fromEnv !== undefined && fromEnv.length > 0) {\n return { value: fromEnv, source: 'env' };\n }\n if (config.baseUrl !== undefined) return { value: config.baseUrl, source: 'file' };\n return { value: CONFIG_DEFAULTS.baseUrl, source: 'default' };\n}\n\nfunction isNotFound(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'code' in err &&\n (err as { code?: unknown }).code === 'ENOENT'\n );\n}\n","import { CliError } from './errors';\nimport type { Money } from '../schemas';\n\n/** USDC is a 6-decimal token; one dollar is 1_000_000 atomic units. */\nconst USDC_DECIMALS = 6;\n\n/**\n * Decimal USD at the CLI edge -> atomic USDC string (O1). Accepts \"0\", \"0.25\",\n * \"5\"; rejects negatives, non-numeric input, and more than 6 decimal places as\n * USAGE so a fat-fingered amount fails loudly instead of truncating money.\n * String math throughout — a float would lose precision at the 6th decimal.\n */\nexport function parseUsdToAtomic(input: string): string {\n const trimmed = input.trim();\n if (!/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n throw new CliError('USAGE', `Invalid USD amount: ${JSON.stringify(input)}`, {\n fix: 'Pass a non-negative decimal like 0.25 or 5.',\n });\n }\n const [whole, frac = ''] = trimmed.split('.');\n if (frac.length > USDC_DECIMALS) {\n throw new CliError(\n 'USAGE',\n `USD amount ${JSON.stringify(input)} has more than 6 decimal places`,\n {\n fix: 'USDC supports at most 6 decimal places (micro-dollars).',\n },\n );\n }\n const atomic = BigInt(`${whole}${frac.padEnd(USDC_DECIMALS, '0')}`);\n return atomic.toString();\n}\n\n/**\n * Atomic USDC string -> decimal USD string, trailing zeros trimmed (\"250000\" ->\n * \"0.25\", \"5000000\" -> \"5\", \"0\" -> \"0\"). Throws INTERNAL on a malformed atomic\n * value: atomic strings come from validated config or on-chain reads, so a bad\n * one is a bug, not user input.\n */\nexport function atomicToUsd(atomic: string): string {\n const trimmed = atomic.trim();\n if (!/^\\d+$/.test(trimmed)) {\n throw new CliError('INTERNAL', `Malformed atomic amount: ${JSON.stringify(atomic)}`);\n }\n const value = BigInt(trimmed);\n const base = 10n ** BigInt(USDC_DECIMALS);\n const whole = value / base;\n const frac = (value % base).toString().padStart(USDC_DECIMALS, '0').replace(/0+$/, '');\n return frac.length > 0 ? `${whole}.${frac}` : whole.toString();\n}\n\n/** Dual-form money object for machine output. */\nexport function toMoney(atomic: string): Money {\n return { atomic, usd: atomicToUsd(atomic) };\n}\n"],"mappings":"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","names":[]}
|