starkfi 0.3.0 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starkfi",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Starknet DeFi CLI + MCP Server — Swaps, multi-swap, batch (multicall), staking, lending, simulation, portfolio, gasless transactions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "files": [
17
17
  "dist",
18
+ "scripts",
18
19
  "skills",
19
20
  "README.md",
20
21
  "MCP.md",
@@ -30,7 +31,8 @@
30
31
  "format:check": "prettier --check src/",
31
32
  "start": "node dist/index.js",
32
33
  "mcp-start": "node dist/index.js mcp-start",
33
- "prepublishOnly": "pnpm run build"
34
+ "prepublishOnly": "pnpm run build",
35
+ "postinstall": "node scripts/patch-esm.mjs"
34
36
  },
35
37
  "keywords": [
36
38
  "starknet",
@@ -0,0 +1,151 @@
1
+ /**
2
+ * patch-esm.mjs — Postinstall ESM compatibility fix for starkzap
3
+ *
4
+ * starkzap@1.0.0 publishes compiled JS files with extensionless relative
5
+ * imports (e.g. `from "./sdk"` instead of `from "./sdk.js"`). This is
6
+ * invalid under Node.js ESM resolution which requires explicit file
7
+ * extensions. The `tsx` runtime tolerates it, but bare `node` does not,
8
+ * causing `npx starkfi` to hang silently.
9
+ *
10
+ * This script runs as a postinstall hook and patches all relative imports
11
+ * inside `node_modules/starkzap/dist/` to include the correct `.js` or
12
+ * `/index.js` suffix. It is idempotent — running it multiple times
13
+ * produces the same result.
14
+ */
15
+
16
+ import { readdir, readFile, writeFile, stat } from "node:fs/promises";
17
+ import { join, dirname } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+
20
+ /**
21
+ * Dynamically locate starkzap's dist directory.
22
+ * Works both in local dev (`node scripts/patch-esm.mjs`) and when
23
+ * starkfi is installed as a dependency (`npm install starkfi`).
24
+ */
25
+ async function findStarkzapDist() {
26
+ try {
27
+ // Use Node.js module resolution to find starkzap's entry point
28
+ const resolved = import.meta.resolve("starkzap");
29
+ const entryFile = fileURLToPath(resolved);
30
+ // starkzap entry is at .../starkzap/dist/src/index.js
31
+ // We need .../starkzap/dist
32
+ const distDir = dirname(dirname(entryFile));
33
+ return distDir;
34
+ } catch {
35
+ // Fallback: relative path from scripts/ directory (local dev)
36
+ const __dirname = dirname(fileURLToPath(import.meta.url));
37
+ return join(__dirname, "..", "node_modules", "starkzap", "dist");
38
+ }
39
+ }
40
+
41
+ const STARKZAP_DIST = await findStarkzapDist();
42
+
43
+ /**
44
+ * Resolves a bare relative import to its correct ESM-compliant form.
45
+ * "./sdk" → "./sdk.js" (if sdk.js exists)
46
+ * "./account" → "./account/index.js" (if account/index.js exists)
47
+ * "./foo.js" → "./foo.js" (already has extension, skip)
48
+ */
49
+ async function resolveImport(baseDir, importPath) {
50
+ // Already has a known JS file extension — leave it alone
51
+ if (/\.(?:js|mjs|cjs|json)$/.test(importPath)) return null;
52
+
53
+ // 1) Try <importPath>.js
54
+ try {
55
+ const asFile = join(baseDir, importPath + ".js");
56
+ const s = await stat(asFile);
57
+ if (s.isFile()) return importPath + ".js";
58
+ } catch {
59
+ /* not a file */
60
+ }
61
+
62
+ // 2) Try <importPath>/index.js
63
+ try {
64
+ const asDir = join(baseDir, importPath, "index.js");
65
+ const s = await stat(asDir);
66
+ if (s.isFile()) return importPath + "/index.js";
67
+ } catch {
68
+ /* not a directory with index */
69
+ }
70
+
71
+ return null; // Can't resolve — leave original
72
+ }
73
+
74
+ /**
75
+ * Patches a single JS file, replacing extensionless relative imports.
76
+ * Returns true if the file was modified.
77
+ */
78
+ async function patchFile(filePath) {
79
+ const content = await readFile(filePath, "utf-8");
80
+ const baseDir = dirname(filePath);
81
+ let modified = false;
82
+
83
+ // Collect all relative import specifiers
84
+ const importRegex = /((?:from|import)\s*["'])(\.\.?\/[^"']+)(["'])/g;
85
+ const replacements = [];
86
+ let match;
87
+
88
+ while ((match = importRegex.exec(content)) !== null) {
89
+ const [full, prefix, importPath, suffix] = match;
90
+ const resolved = await resolveImport(baseDir, importPath);
91
+ if (resolved) {
92
+ replacements.push({
93
+ start: match.index,
94
+ end: match.index + full.length,
95
+ replacement: `${prefix}${resolved}${suffix}`,
96
+ });
97
+ modified = true;
98
+ }
99
+ }
100
+
101
+ if (!modified) return false;
102
+
103
+ // Apply replacements from end to start to preserve indices
104
+ let patched = content;
105
+ for (let i = replacements.length - 1; i >= 0; i--) {
106
+ const r = replacements[i];
107
+ patched = patched.slice(0, r.start) + r.replacement + patched.slice(r.end);
108
+ }
109
+
110
+ await writeFile(filePath, patched);
111
+ return true;
112
+ }
113
+
114
+ /**
115
+ * Recursively walks a directory and patches all .js files.
116
+ */
117
+ async function walkAndPatch(dir) {
118
+ let count = 0;
119
+ const entries = await readdir(dir, { withFileTypes: true });
120
+
121
+ for (const entry of entries) {
122
+ const fullPath = join(dir, entry.name);
123
+ if (entry.isDirectory()) {
124
+ count += await walkAndPatch(fullPath);
125
+ } else if (entry.name.endsWith(".js") && !entry.name.endsWith(".map")) {
126
+ if (await patchFile(fullPath)) count++;
127
+ }
128
+ }
129
+
130
+ return count;
131
+ }
132
+
133
+ // ── Main ──────────────────────────────────────────────────────────────
134
+ try {
135
+ await stat(STARKZAP_DIST);
136
+ } catch {
137
+ // starkzap not installed or dist missing — nothing to patch
138
+ process.exit(0);
139
+ }
140
+
141
+ try {
142
+ const count = await walkAndPatch(STARKZAP_DIST);
143
+ if (count > 0) {
144
+ console.log(
145
+ `[starkfi] Patched ${count} starkzap file${count > 1 ? "s" : ""} for ESM compatibility`
146
+ );
147
+ }
148
+ } catch (err) {
149
+ console.warn("[starkfi] ESM patch warning:", err.message);
150
+ // Don't fail the install — the CLI will still work via tsx
151
+ }