run402 1.57.3 → 1.57.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/lib/projects.mjs CHANGED
@@ -41,7 +41,7 @@ Examples:
41
41
  run402 projects sql prj_abc123 --file setup.sql
42
42
  run402 projects rest prj_abc123 users "limit=10&select=id,name"
43
43
  run402 projects usage prj_abc123
44
- RUN402_ADMIN_COOKIE='run402_admin=...' run402 projects costs prj_abc123 --window 30d
44
+ run402 projects costs prj_abc123 --window 30d
45
45
  run402 projects schema prj_abc123
46
46
  run402 projects apply-expose prj_abc123 --file manifest.json
47
47
  run402 projects get-expose prj_abc123
@@ -122,15 +122,17 @@ Options:
122
122
  --window <w> Finance window (default: 30d). One of: 24h, 7d, 30d, 90d
123
123
 
124
124
  Environment:
125
- RUN402_ADMIN_COOKIE Admin OAuth cookie header, e.g. "run402_admin=..."
125
+ RUN402_ADMIN_COOKIE Optional admin OAuth cookie header, e.g. "run402_admin=..."
126
126
 
127
127
  Notes:
128
- - Platform-admin only. Project service keys and normal allowance auth are
129
- not enough for this endpoint.
128
+ - Platform-admin only. The configured allowance wallet must be an admin
129
+ wallet, or RUN402_ADMIN_COOKIE must contain an admin OAuth cookie.
130
+ - Project service keys are not enough for this endpoint.
130
131
  - Output is the gateway's per-project finance JSON: revenue, direct cost,
131
132
  direct margin, and direct_cost_breakdown rows.
132
133
 
133
134
  Examples:
135
+ run402 projects costs prj_abc123
134
136
  RUN402_ADMIN_COOKIE='run402_admin=...' run402 projects costs prj_abc123
135
137
  RUN402_ADMIN_COOKIE='run402_admin=...' run402 projects costs --window 7d
136
138
  `,
@@ -344,14 +346,7 @@ async function usage(projectId) {
344
346
 
345
347
  function adminCookieFromEnv() {
346
348
  const raw = process.env.RUN402_ADMIN_COOKIE?.trim();
347
- if (!raw) {
348
- fail({
349
- code: "ADMIN_COOKIE_REQUIRED",
350
- message: "run402 projects costs requires RUN402_ADMIN_COOKIE.",
351
- hint: "Sign in to /admin, then set RUN402_ADMIN_COOKIE to the run402_admin cookie header.",
352
- details: { env: "RUN402_ADMIN_COOKIE" },
353
- });
354
- }
349
+ if (!raw) return undefined;
355
350
  return raw.includes("=") ? raw : `run402_admin=${raw}`;
356
351
  }
357
352
 
@@ -368,7 +363,7 @@ async function costs(projectId, args = []) {
368
363
  try {
369
364
  const data = await getSdk().admin.getProjectFinance(projectId, {
370
365
  window,
371
- cookie,
366
+ ...(cookie ? { cookie } : {}),
372
367
  });
373
368
  console.log(JSON.stringify(data, null, 2));
374
369
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.57.3",
3
+ "version": "1.57.5",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,8 +27,8 @@ export interface AdminProjectFinanceOptions {
27
27
  window?: AdminFinanceWindow;
28
28
  /**
29
29
  * Optional admin session cookie header. Node operators can pass the value of
30
- * RUN402_ADMIN_COOKIE; custom credential providers may instead inject auth
31
- * headers through getAuth().
30
+ * RUN402_ADMIN_COOKIE when they want browser-session auth; otherwise the
31
+ * credential provider's normal auth headers are used.
32
32
  */
33
33
  cookie?: string;
34
34
  }
@@ -63,9 +63,10 @@ export declare class Admin {
63
63
  * Fetch per-project finance for platform operators.
64
64
  *
65
65
  * This is the same admin-only surface used by the Run402 Finance tab. It is
66
- * gated by the gateway's admin OAuth session; project service keys are not
67
- * sufficient. Pass `cookie` when using the Node SDK directly, or provide a
68
- * credential provider whose `getAuth()` returns suitable admin headers.
66
+ * gated by platform-admin auth; project service keys are not sufficient.
67
+ * Use the Node SDK with an admin allowance wallet, pass `cookie` for browser
68
+ * session auth, or provide a credential provider whose `getAuth()` returns
69
+ * suitable admin headers.
69
70
  */
70
71
  getProjectFinance(projectId: string, opts?: AdminProjectFinanceOptions): Promise<AdminProjectFinanceResult>;
71
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/namespaces/admin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;AAE9D,MAAM,WAAW,0BAA0B;IACzC,6DAA6D;IAC7D,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wBAAwB,EAAE,MAAM,CAAC;IACjC,iBAAiB,EAAE;QACjB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,sBAAsB,EAAE,MAAM,CAAC;QAC/B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,wBAAwB,EAAE,MAAM,CAAC;QACjC,uBAAuB,EAAE,MAAM,CAAC;KACjC,CAAC;IACF,qBAAqB,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,KAAK,EAAE,MAAM,CAAC;CACf;AAID,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,wEAAwE;IAClE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAQ9D,0DAA0D;IACpD,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAYzE;;;;;;;OAOG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,0BAA+B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CAoBtC"}
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/namespaces/admin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;AAE9D,MAAM,WAAW,0BAA0B;IACzC,6DAA6D;IAC7D,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wBAAwB,EAAE,MAAM,CAAC;IACjC,iBAAiB,EAAE;QACjB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,sBAAsB,EAAE,MAAM,CAAC;QAC/B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,wBAAwB,EAAE,MAAM,CAAC;QACjC,uBAAuB,EAAE,MAAM,CAAC;KACjC,CAAC;IACF,qBAAqB,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,KAAK,EAAE,MAAM,CAAC;CACf;AAID,qBAAa,KAAK;IACJ,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,wEAAwE;IAClE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAQ9D,0DAA0D;IACpD,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAYzE;;;;;;;;OAQG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,0BAA+B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CAoBtC"}
@@ -37,16 +37,17 @@ export class Admin {
37
37
  * Fetch per-project finance for platform operators.
38
38
  *
39
39
  * This is the same admin-only surface used by the Run402 Finance tab. It is
40
- * gated by the gateway's admin OAuth session; project service keys are not
41
- * sufficient. Pass `cookie` when using the Node SDK directly, or provide a
42
- * credential provider whose `getAuth()` returns suitable admin headers.
40
+ * gated by platform-admin auth; project service keys are not sufficient.
41
+ * Use the Node SDK with an admin allowance wallet, pass `cookie` for browser
42
+ * session auth, or provide a credential provider whose `getAuth()` returns
43
+ * suitable admin headers.
43
44
  */
44
45
  async getProjectFinance(projectId, opts = {}) {
45
46
  const window = opts.window ?? "30d";
46
47
  if (!FINANCE_WINDOWS.has(window)) {
47
48
  throw new LocalError(`Invalid finance window: ${String(window)}. Expected one of: 24h, 7d, 30d, 90d.`, "fetching project finance");
48
49
  }
49
- const headers = {};
50
+ const headers = { "X-Admin-Mode": "1" };
50
51
  if (opts.cookie)
51
52
  headers.Cookie = opts.cookie;
52
53
  return this.client.request(`/admin/api/finance/project/${encodeURIComponent(projectId)}?window=${encodeURIComponent(window)}`, {
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/namespaces/admin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAmD1C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAEjF,MAAM,OAAO,KAAK;IACa;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C,wEAAwE;IACxE,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAoB,aAAa,EAAE;YAC3D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,OAAO,EAAE;YACjB,OAAO,EAAE,iBAAiB;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,0DAA0D;IAC1D,KAAK,CAAC,eAAe,CAAC,OAAqB;QACzC,MAAM,IAAI,GAA2B,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9C,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAEpD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAqB,mBAAmB,EAAE;YAClE,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,OAAO,EAAE,uBAAuB;SACjC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,iBAAiB,CACrB,SAAiB,EACjB,OAAmC,EAAE;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;QACpC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,UAAU,CAClB,2BAA2B,MAAM,CAAC,MAAM,CAAC,uCAAuC,EAChF,0BAA0B,CAC3B,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE9C,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CACxB,8BAA8B,kBAAkB,CAAC,SAAS,CAAC,WAAW,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAClG;YACE,OAAO;YACP,OAAO,EAAE,0BAA0B;SACpC,CACF,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/namespaces/admin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAmD1C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAEjF,MAAM,OAAO,KAAK;IACa;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C,wEAAwE;IACxE,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAoB,aAAa,EAAE;YAC3D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,OAAO,EAAE;YACjB,OAAO,EAAE,iBAAiB;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,0DAA0D;IAC1D,KAAK,CAAC,eAAe,CAAC,OAAqB;QACzC,MAAM,IAAI,GAA2B,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9C,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAEpD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAqB,mBAAmB,EAAE;YAClE,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,OAAO,EAAE,uBAAuB;SACjC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,iBAAiB,CACrB,SAAiB,EACjB,OAAmC,EAAE;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;QACpC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,UAAU,CAClB,2BAA2B,MAAM,CAAC,MAAM,CAAC,uCAAuC,EAChF,0BAA0B,CAC3B,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC;QAChE,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE9C,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CACxB,8BAA8B,kBAAkB,CAAC,SAAS,CAAC,WAAW,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAClG;YACE,OAAO;YACP,OAAO,EAAE,0BAA0B;SACpC,CACF,CAAC;IACJ,CAAC;CACF"}
@@ -1,62 +0,0 @@
1
- /**
2
- * Wallet auth helper — generates EIP-191 signature headers for Run402 API.
3
- * Uses @noble/curves (lighter than viem) for signing.
4
- */
5
- import { secp256k1 } from "@noble/curves/secp256k1.js";
6
- import { keccak_256 } from "@noble/hashes/sha3.js";
7
- import { bytesToHex } from "@noble/hashes/utils.js";
8
- import { readWallet } from "./wallet.js";
9
- /**
10
- * EIP-191 personal_sign: sign a message with the wallet's private key.
11
- */
12
- function personalSign(privateKeyHex, address, message) {
13
- const msgBytes = new TextEncoder().encode(message);
14
- const prefix = new TextEncoder().encode(`\x19Ethereum Signed Message:\n${msgBytes.length}`);
15
- const prefixed = new Uint8Array(prefix.length + msgBytes.length);
16
- prefixed.set(prefix);
17
- prefixed.set(msgBytes, prefix.length);
18
- const hash = keccak_256(prefixed);
19
- const pkHex = privateKeyHex.startsWith("0x")
20
- ? privateKeyHex.slice(2)
21
- : privateKeyHex;
22
- const pkBytes = Uint8Array.from(Buffer.from(pkHex, "hex"));
23
- const rawSig = secp256k1.sign(hash, pkBytes);
24
- const sig = secp256k1.Signature.fromBytes(rawSig);
25
- // Determine recovery bit by trying both and matching the address
26
- let recovery = 0;
27
- for (const v of [0, 1]) {
28
- try {
29
- const recovered = sig.addRecoveryBit(v).recoverPublicKey(hash);
30
- const pubBytes = recovered.toBytes(false).slice(1); // uncompressed, drop 04 prefix
31
- const addrBytes = keccak_256(pubBytes).slice(-20);
32
- if ("0x" + bytesToHex(addrBytes) === address.toLowerCase()) {
33
- recovery = v;
34
- break;
35
- }
36
- }
37
- catch {
38
- continue;
39
- }
40
- }
41
- const r = sig.r.toString(16).padStart(64, "0");
42
- const s = sig.s.toString(16).padStart(64, "0");
43
- const vHex = (recovery + 27).toString(16).padStart(2, "0");
44
- return "0x" + r + s + vHex;
45
- }
46
- /**
47
- * Get wallet auth headers for the Run402 API.
48
- * Returns null if no wallet is configured.
49
- */
50
- export function getWalletAuthHeaders(walletPath) {
51
- const wallet = readWallet(walletPath);
52
- if (!wallet || !wallet.address || !wallet.privateKey)
53
- return null;
54
- const timestamp = Math.floor(Date.now() / 1000).toString();
55
- const signature = personalSign(wallet.privateKey, wallet.address, `run402:${timestamp}`);
56
- return {
57
- "X-Run402-Wallet": wallet.address,
58
- "X-Run402-Signature": signature,
59
- "X-Run402-Timestamp": timestamp,
60
- };
61
- }
62
- //# sourceMappingURL=wallet-auth.js.map
@@ -1,25 +0,0 @@
1
- import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, renameSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { randomBytes } from "node:crypto";
4
- import { getWalletPath } from "./config.js";
5
- export function readWallet(path) {
6
- const p = path ?? getWalletPath();
7
- if (!existsSync(p))
8
- return null;
9
- try {
10
- return JSON.parse(readFileSync(p, "utf-8"));
11
- }
12
- catch {
13
- return null;
14
- }
15
- }
16
- export function saveWallet(data, path) {
17
- const p = path ?? getWalletPath();
18
- const dir = dirname(p);
19
- mkdirSync(dir, { recursive: true });
20
- const tmp = join(dir, `.wallet.${randomBytes(4).toString("hex")}.tmp`);
21
- writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
22
- renameSync(tmp, p);
23
- chmodSync(p, 0o600);
24
- }
25
- //# sourceMappingURL=wallet.js.map
@@ -1,62 +0,0 @@
1
- /**
2
- * Wallet auth helper — generates EIP-191 signature headers for Run402 API.
3
- * Uses @noble/curves (lighter than viem) for signing.
4
- */
5
- import { secp256k1 } from "@noble/curves/secp256k1.js";
6
- import { keccak_256 } from "@noble/hashes/sha3.js";
7
- import { bytesToHex } from "@noble/hashes/utils.js";
8
- import { readWallet } from "./wallet.js";
9
- /**
10
- * EIP-191 personal_sign: sign a message with the wallet's private key.
11
- */
12
- function personalSign(privateKeyHex, address, message) {
13
- const msgBytes = new TextEncoder().encode(message);
14
- const prefix = new TextEncoder().encode(`\x19Ethereum Signed Message:\n${msgBytes.length}`);
15
- const prefixed = new Uint8Array(prefix.length + msgBytes.length);
16
- prefixed.set(prefix);
17
- prefixed.set(msgBytes, prefix.length);
18
- const hash = keccak_256(prefixed);
19
- const pkHex = privateKeyHex.startsWith("0x")
20
- ? privateKeyHex.slice(2)
21
- : privateKeyHex;
22
- const pkBytes = Uint8Array.from(Buffer.from(pkHex, "hex"));
23
- const rawSig = secp256k1.sign(hash, pkBytes);
24
- const sig = secp256k1.Signature.fromBytes(rawSig);
25
- // Determine recovery bit by trying both and matching the address
26
- let recovery = 0;
27
- for (const v of [0, 1]) {
28
- try {
29
- const recovered = sig.addRecoveryBit(v).recoverPublicKey(hash);
30
- const pubBytes = recovered.toBytes(false).slice(1); // uncompressed, drop 04 prefix
31
- const addrBytes = keccak_256(pubBytes).slice(-20);
32
- if ("0x" + bytesToHex(addrBytes) === address.toLowerCase()) {
33
- recovery = v;
34
- break;
35
- }
36
- }
37
- catch {
38
- continue;
39
- }
40
- }
41
- const r = sig.r.toString(16).padStart(64, "0");
42
- const s = sig.s.toString(16).padStart(64, "0");
43
- const vHex = (recovery + 27).toString(16).padStart(2, "0");
44
- return "0x" + r + s + vHex;
45
- }
46
- /**
47
- * Get wallet auth headers for the Run402 API.
48
- * Returns null if no wallet is configured.
49
- */
50
- export function getWalletAuthHeaders(walletPath) {
51
- const wallet = readWallet(walletPath);
52
- if (!wallet || !wallet.address || !wallet.privateKey)
53
- return null;
54
- const timestamp = Math.floor(Date.now() / 1000).toString();
55
- const signature = personalSign(wallet.privateKey, wallet.address, `run402:${timestamp}`);
56
- return {
57
- "X-Run402-Wallet": wallet.address,
58
- "X-Run402-Signature": signature,
59
- "X-Run402-Timestamp": timestamp,
60
- };
61
- }
62
- //# sourceMappingURL=wallet-auth.js.map
@@ -1,25 +0,0 @@
1
- import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, renameSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { randomBytes } from "node:crypto";
4
- import { getWalletPath } from "./config.js";
5
- export function readWallet(path) {
6
- const p = path ?? getWalletPath();
7
- if (!existsSync(p))
8
- return null;
9
- try {
10
- return JSON.parse(readFileSync(p, "utf-8"));
11
- }
12
- catch {
13
- return null;
14
- }
15
- }
16
- export function saveWallet(data, path) {
17
- const p = path ?? getWalletPath();
18
- const dir = dirname(p);
19
- mkdirSync(dir, { recursive: true });
20
- const tmp = join(dir, `.wallet.${randomBytes(4).toString("hex")}.tmp`);
21
- writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
22
- renameSync(tmp, p);
23
- chmodSync(p, 0o600);
24
- }
25
- //# sourceMappingURL=wallet.js.map