@envarai/envarpay 0.2.0-alpha.14 → 0.2.0-alpha.16
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/dist/commerce/chain.js
CHANGED
|
@@ -8,6 +8,17 @@ const officialUsdc = {
|
|
|
8
8
|
'eip155:84532': '0x036cbd53842c5426634e7929541ec2318f3dcf7e',
|
|
9
9
|
'eip155:8453': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
10
10
|
};
|
|
11
|
+
function transientRpcRead(error) {
|
|
12
|
+
for (let cause = error, depth = 0; cause && typeof cause === 'object' && depth < 8; depth++) {
|
|
13
|
+
const value = cause;
|
|
14
|
+
if (value.name === 'TimeoutError' || [408, 429, 500, 502, 503, 504].includes(value.status ?? 0) || [-32005, -32011].includes(value.code ?? 0))
|
|
15
|
+
return true;
|
|
16
|
+
if (value.name === 'HttpRequestError' && value.status === undefined)
|
|
17
|
+
return true;
|
|
18
|
+
cause = value.cause;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
11
22
|
/** Checks the canonical chain receipt and exact official-token Transfer. */
|
|
12
23
|
export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitMs = 12000) {
|
|
13
24
|
if (!Number.isInteger(confirmations) || confirmations < 1)
|
|
@@ -23,8 +34,6 @@ export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitM
|
|
|
23
34
|
if (!Number.isSafeInteger(chainId) || !/^0x[0-9a-fA-F]{64}$/.test(receipt.transaction) || receipt.network !== requirements.network)
|
|
24
35
|
return false;
|
|
25
36
|
const client = createPublicClient({ transport: http(rpc, { timeout: 15000, retryCount: 0 }) });
|
|
26
|
-
if (await client.getChainId() !== chainId)
|
|
27
|
-
return false;
|
|
28
37
|
const deadline = Date.now() + confirmationWaitMs;
|
|
29
38
|
const wait = async () => {
|
|
30
39
|
const remaining = deadline - Date.now();
|
|
@@ -33,10 +42,25 @@ export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitM
|
|
|
33
42
|
await new Promise(resolve => setTimeout(resolve, Math.min(1000, remaining)));
|
|
34
43
|
return Date.now() < deadline;
|
|
35
44
|
};
|
|
45
|
+
// All retries read the original transaction on the configured RPC. A rate
|
|
46
|
+
// limit at any verification stage must not be mistaken for chain evidence.
|
|
47
|
+
const read = async (operation) => {
|
|
48
|
+
for (;;) {
|
|
49
|
+
try {
|
|
50
|
+
return await operation();
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!transientRpcRead(error) || !await wait())
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
if (await read(() => client.getChainId()) !== chainId)
|
|
59
|
+
return false;
|
|
36
60
|
let mined;
|
|
37
61
|
for (;;) {
|
|
38
62
|
try {
|
|
39
|
-
mined = await client.getTransactionReceipt({ hash: receipt.transaction });
|
|
63
|
+
mined = await read(() => client.getTransactionReceipt({ hash: receipt.transaction }));
|
|
40
64
|
}
|
|
41
65
|
catch (error) {
|
|
42
66
|
if (error instanceof TransactionReceiptNotFoundError) {
|
|
@@ -48,10 +72,10 @@ export function evmReceiptVerifier(rpcUrls, confirmations = 2, confirmationWaitM
|
|
|
48
72
|
}
|
|
49
73
|
if (mined.status !== 'success' || mined.transactionHash.toLowerCase() !== receipt.transaction.toLowerCase())
|
|
50
74
|
return false;
|
|
51
|
-
const block = await client.getBlock({ blockNumber: mined.blockNumber });
|
|
75
|
+
const block = await read(() => client.getBlock({ blockNumber: mined.blockNumber }));
|
|
52
76
|
if (block.hash !== mined.blockHash)
|
|
53
77
|
return false;
|
|
54
|
-
const latest = await client.getBlockNumber({ cacheTime: 0 });
|
|
78
|
+
const latest = await read(() => client.getBlockNumber({ cacheTime: 0 }));
|
|
55
79
|
if (latest - mined.blockNumber + 1n >= BigInt(confirmations))
|
|
56
80
|
break;
|
|
57
81
|
if (!await wait())
|
|
@@ -4,6 +4,9 @@ import { extname, join, resolve } from 'node:path';
|
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { parse } from 'yaml';
|
|
6
6
|
const namePattern = /^[a-z][a-z0-9-]{0,63}$/;
|
|
7
|
+
// Native installer provenance is included in the source digest, but never
|
|
8
|
+
// copied into the executable service package or supplied to the model.
|
|
9
|
+
export const isSkillInstallerMetadata = (path) => path === '.clawhub/origin.json';
|
|
7
10
|
export function readSkillInventory(roots) {
|
|
8
11
|
const found = [];
|
|
9
12
|
const seen = new Set();
|
|
@@ -54,7 +57,7 @@ export function readSkillInventory(roots) {
|
|
|
54
57
|
supported = false;
|
|
55
58
|
continue;
|
|
56
59
|
}
|
|
57
|
-
if (!['.md', '.txt'].includes(extname(name).toLowerCase()) && name !== 'LICENSE')
|
|
60
|
+
if (!['.md', '.txt'].includes(extname(name).toLowerCase()) && name !== 'LICENSE' && !isSkillInstallerMetadata(prefix + name))
|
|
58
61
|
supported = false;
|
|
59
62
|
files.push([prefix + name, createHash('sha256').update(readFileSync(file)).digest('hex')]);
|
|
60
63
|
}
|
package/dist/commerce/setup.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Guided local installation. Platform input is data, never a shell command or wallet policy. */
|
|
2
2
|
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync, cpSync, mkdtempSync, renameSync, rmSync, } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { join, resolve } from "node:path";
|
|
4
|
+
import { join, resolve, relative, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { randomBytes } from "node:crypto";
|
|
7
7
|
import { execFileSync } from "node:child_process";
|
|
@@ -10,6 +10,7 @@ import { probeOpenClaw } from "./openclaw-setup.js";
|
|
|
10
10
|
import { readInstalledSkills } from "./native-skills.js";
|
|
11
11
|
import { loadCommerceConfig, validateUrl } from "./config.js";
|
|
12
12
|
import { CommerceError } from "./types.js";
|
|
13
|
+
import { isSkillInstallerMetadata } from './native-inventory.js';
|
|
13
14
|
const ID = /^[a-z][a-z0-9-]{0,63}$/, CONTAINER = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
|
|
14
15
|
export function parseSetupBundle(raw) {
|
|
15
16
|
const v = raw;
|
|
@@ -40,6 +41,8 @@ export function prepareTextSkill(source, destination, name) {
|
|
|
40
41
|
const item = lstatSync(path);
|
|
41
42
|
if (item.isSymbolicLink())
|
|
42
43
|
throw new CommerceError("setup_skill", "Skill symlinks are unsupported");
|
|
44
|
+
if (item.isFile() && isSkillInstallerMetadata(relative(source, path).split(sep).join('/')))
|
|
45
|
+
return false;
|
|
43
46
|
if (item.isFile() &&
|
|
44
47
|
!/\.(md|txt)$/i.test(path) &&
|
|
45
48
|
!path.endsWith("/LICENSE"))
|
|
@@ -73,7 +73,8 @@ def inventory(home):
|
|
|
73
73
|
if size > 1024 * 1024 or len(package) >= 128:
|
|
74
74
|
supported = False
|
|
75
75
|
break
|
|
76
|
-
if file.suffix.lower() not in {".md", ".txt"} and file.name != "LICENSE"
|
|
76
|
+
if (file.suffix.lower() not in {".md", ".txt"} and file.name != "LICENSE"
|
|
77
|
+
and str(file.relative_to(entry.parent)) != ".clawhub/origin.json"):
|
|
77
78
|
supported = False
|
|
78
79
|
package.append(
|
|
79
80
|
[
|