@zktx.io/sui-move-builder 0.1.3 → 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 CHANGED
@@ -1,6 +1,16 @@
1
1
  # @zktx.io/sui-move-builder
2
2
 
3
- Build Move packages in web or Node.js with dependency fetching and dump outputs.
3
+ Build Move packages in web or Node.js with Sui CLI-compatible dependency resolution and compilation.
4
+
5
+ ## Features
6
+
7
+ - ✅ **Sui CLI Compatible**: Identical dependency resolution algorithm as Sui CLI
8
+ - ✅ **Lockfile Support**: Reads `Move.lock` for faster, deterministic builds
9
+ - ✅ **Per-Package Editions**: Each package can use its own Move edition (legacy, 2024.alpha, 2024.beta)
10
+ - ✅ **Monorepo Support**: Handles local dependencies in monorepo structures
11
+ - ✅ **Version Conflict Resolution**: Automatically resolves dependency version conflicts
12
+ - ✅ **Browser & Node.js**: Works in both environments with WASM-based compilation
13
+ - ✅ **GitHub Integration**: Fetches dependencies directly from git repositories
4
14
 
5
15
  ## Install
6
16
 
@@ -34,62 +44,117 @@ module hello_world::hello_world {
34
44
  };
35
45
 
36
46
  // 3) Compile
37
- const result = await buildMovePackage({
38
- files,
39
- dependencies: {},
40
- autoSystemDeps: true, // Sui CLI-like defaults for std/Sui packages
41
- });
47
+ const result = await buildMovePackage({ files });
42
48
 
43
49
  if (result.success) {
44
- console.log(result.digest);
45
- console.log(result.modules); // Base64-encoded Move modules
50
+ console.log("Digest:", result.digest);
51
+ console.log("Modules:", result.modules); // Base64-encoded bytecode
46
52
  } else {
47
- console.error(result.error);
53
+ console.error("Build failed:", result.error);
48
54
  }
49
55
  ```
50
56
 
51
- ## Resolving dependencies from GitHub (optional)
57
+ ## Fetching packages from GitHub
52
58
 
53
59
  ```ts
54
- import { resolve, GitHubFetcher } from "@zktx.io/sui-move-builder";
60
+ import {
61
+ fetchPackageFromGitHub,
62
+ buildMovePackage,
63
+ initMoveCompiler,
64
+ } from "@zktx.io/sui-move-builder";
55
65
 
56
- const resolution = await resolve(
57
- files["Move.toml"],
58
- files,
59
- new GitHubFetcher()
66
+ await initMoveCompiler();
67
+
68
+ // Fetch a package from GitHub URL
69
+ const files = await fetchPackageFromGitHub(
70
+ "https://github.com/MystenLabs/sui/tree/framework/mainnet/crates/sui-framework/packages/sui-framework"
60
71
  );
61
72
 
62
- const filesJson =
63
- typeof resolution.files === "string"
64
- ? JSON.parse(resolution.files)
65
- : resolution.files;
66
- const depsJson =
67
- typeof resolution.dependencies === "string"
68
- ? JSON.parse(resolution.dependencies)
69
- : resolution.dependencies;
70
-
71
- const result = await buildMovePackage({
72
- files: filesJson,
73
- dependencies: depsJson,
74
- autoSystemDeps: true,
73
+ // Compile directly
74
+ const result = await buildMovePackage({ files });
75
+ ```
76
+
77
+ ## How it works
78
+
79
+ Dependencies are automatically resolved from `Move.toml`:
80
+
81
+ 1. **Tries Move.lock first**: If a valid `Move.lock` exists, dependencies are loaded from it (faster, deterministic)
82
+ 2. **Falls back to manifests**: If lockfile is missing/invalid, resolves dependencies from `Move.toml` files
83
+ 3. **Validates digests**: Checks manifest digests to detect changes
84
+ 4. **Handles monorepos**: Converts local dependencies to git dependencies automatically
85
+ 5. **Injects system packages**: Automatically adds Sui, MoveStdlib, SuiSystem, and Bridge packages if missing
86
+
87
+ ```ts
88
+ import { initMoveCompiler, buildMovePackage } from "@zktx.io/sui-move-builder";
89
+
90
+ await initMoveCompiler();
91
+
92
+ const files = {
93
+ "Move.toml": `
94
+ [package]
95
+ name = "my_package"
96
+ edition = "2024.beta"
97
+
98
+ [dependencies]
99
+ deepbook = { git = "https://github.com/MystenLabs/deepbookv3.git", subdir = "packages/deepbook", rev = "main" }
100
+ `,
101
+ "sources/main.move": "...",
102
+ };
103
+
104
+ const result = await buildMovePackage({ files });
105
+
106
+ if (result.success) {
107
+ console.log("Modules:", result.modules); // Base64-encoded bytecode
108
+ console.log("Dependencies:", result.dependencies); // Hex-encoded IDs
109
+ console.log("Digest:", result.digest); // Package digest
110
+ } else {
111
+ console.error("Build failed:", result.error);
112
+ }
113
+ ```
114
+
115
+ ## Dependency caching and reuse
116
+
117
+ For faster builds when compiling multiple times with the same dependencies, you can resolve dependencies once and reuse them:
118
+
119
+ ```ts
120
+ import {
121
+ initMoveCompiler,
122
+ resolveDependencies,
123
+ buildMovePackage
124
+ } from "@zktx.io/sui-move-builder";
125
+
126
+ await initMoveCompiler();
127
+
128
+ const files = {
129
+ "Move.toml": `...`,
130
+ "sources/main.move": "...",
131
+ };
132
+
133
+ // 1. Resolve dependencies once
134
+ const deps = await resolveDependencies({ files, network: "mainnet" });
135
+
136
+ // 2. Build multiple times without re-resolving dependencies
137
+ const result1 = await buildMovePackage({
138
+ files,
139
+ network: "mainnet",
140
+ resolvedDependencies: deps, // Skip dependency resolution
75
141
  });
76
142
 
77
- // If autoSystemDeps is enabled and std/Sui packages are missing,
78
- // the builder fetches them from GitHub using the Sui framework snapshot.
143
+ // Modify source code
144
+ files["sources/main.move"] = "// updated code...";
79
145
 
80
- // Enable ANSI-colored diagnostics (CLI-like output)
81
- const resultWithColor = await buildMovePackage({
82
- files: filesJson,
83
- dependencies: depsJson,
84
- ansiColor: true,
146
+ // 3. Build again with cached dependencies (much faster!)
147
+ const result2 = await buildMovePackage({
148
+ files,
149
+ network: "mainnet",
150
+ resolvedDependencies: deps, // Reuse same dependencies
85
151
  });
86
152
  ```
87
153
 
88
- `buildMovePackage` returns:
89
-
90
- - `success: true | false`
91
- - on success: `modules` (Base64), `dependencies`, `digest`
92
- - on failure: `error` with compiler logs
154
+ **Benefits:**
155
+ - ⚡ Faster builds when dependencies haven't changed
156
+ - 🔄 Useful for watch mode or iterative development
157
+ - 💾 Reduce network requests by caching dependency resolution
93
158
 
94
159
  ## Local test page
95
160
 
package/dist/index.cjs CHANGED
@@ -1,15 +1,28 @@
1
- "use strict";var j=Object.create;var v=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,B=Object.prototype.hasOwnProperty;var A=(s,e)=>{for(var t in e)v(s,t,{get:e[t],enumerable:!0})},M=(s,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of W(e))!B.call(s,i)&&i!==t&&v(s,i,{get:()=>e[i],enumerable:!(n=L(e,i))||n.enumerable});return s};var O=(s,e,t)=>(t=s!=null?j(U(s)):{},M(e||!s||!s.__esModule?v(t,"default",{value:s,enumerable:!0}):t,s)),T=s=>M(v({},"__esModule",{value:!0}),s);var Z={};A(Z,{Fetcher:()=>g,GitHubFetcher:()=>p,Resolver:()=>y,buildMovePackage:()=>J,compileRaw:()=>Q,getSuiMoveVersion:()=>q,getSuiVersion:()=>V,getWasmBindings:()=>K,initMoveCompiler:()=>G,parseToml:()=>h,resolve:()=>b});module.exports=T(Z);var g=class{async fetch(e,t,n){throw new Error("Not implemented")}async fetchFile(e,t,n){throw new Error("Not implemented")}},p=class extends g{constructor(){super(),this.cache=new Map}async fetch(e,t,n){let{owner:i,repo:o}=this.parseGitUrl(e);if(!i||!o)throw new Error(`Invalid git URL: ${e}`);let c=`https://api.github.com/repos/${i}/${o}/git/trees/${t}?recursive=1`,l;try{let d=await fetch(c);if(!d.ok)throw d.status===403||d.status===429?new Error("GitHub API rate limit exceeded."):new Error(`Failed to fetch tree: ${d.statusText}`);l=await d.json()}catch{return{}}let r={},a=[];for(let d of l.tree){if(d.type!=="blob")continue;let u=d.path;if(n){if(!d.path.startsWith(n))continue;u=d.path.slice(n.length),u.startsWith("/")&&(u=u.slice(1))}if(!u.endsWith(".move")&&u!=="Move.toml")continue;let f=`https://raw.githubusercontent.com/${i}/${o}/${t}/${d.path}`,k=this.fetchContent(f).then(x=>{x&&(r[u]=x)});a.push(k)}return await Promise.all(a),r}async fetchFile(e,t,n){let{owner:i,repo:o}=this.parseGitUrl(e);if(!i||!o)throw new Error(`Invalid git URL: ${e}`);let c=`https://raw.githubusercontent.com/${i}/${o}/${t}/${n}`;return this.fetchContent(c)}async fetchContent(e){if(this.cache.has(e))return this.cache.get(e)??null;try{let t=await fetch(e);if(!t.ok)return null;let n=await t.text();return this.cache.set(e,n),n}catch{return null}}parseGitUrl(e){try{let n=new URL(e).pathname.split("/").filter(i=>i);if(n.length>=2){let i=n[1];return i.endsWith(".git")&&(i=i.slice(0,-4)),{owner:n[0],repo:i}}}catch{}return{owner:null,repo:null}}};function N(s){let e=!1,t="";for(let n=0;n<s.length;n++){let i=s[n];if((i==='"'||i==="'")&&(!e||i===t)&&(e=!e,t=i),!e&&i==="#")return s.slice(0,n)}return s}function w(s){let e=s.trim();if(!e)return"";if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(e==="true")return!0;if(e==="false")return!1;let t=Number(e);return Number.isNaN(t)?e:t}function E(s){let e={},t=s.trim().replace(/^\{/,"").replace(/\}$/,""),n="",i=!1,o="",c=[];for(let l=0;l<t.length;l++){let r=t[l];if((r==='"'||r==="'")&&(!i||r===o)&&(i=!i,o=r),!i&&r===","){c.push(n),n="";continue}n+=r}n.trim()&&c.push(n);for(let l of c){let r=l.indexOf("=");if(r===-1)continue;let a=l.slice(0,r).trim(),d=l.slice(r+1).trim();e[a]=w(d)}return e}function h(s){let e={package:{},dependencies:{},addresses:{}},t=null,n=s.split(/\r?\n/);for(let i of n){let o=N(i).trim();if(!o)continue;let c=o.match(/^\[([^\]]+)\]$/);if(c){t=c[1].trim();continue}let l=o.indexOf("=");if(l===-1||!t)continue;let r=o.slice(0,l).trim(),a=o.slice(l+1).trim();t==="package"?e.package[r.replace(/-/g,"_")]=w(a):t==="dependencies"?a.startsWith("{")?e.dependencies[r]=E(a):e.dependencies[r]=w(a):t==="addresses"&&(e.addresses[r]=w(a))}return e}var y=class{constructor(e){this.fetcher=e,this.globalAddresses={},this.visited=new Set,this.dependencyFiles={},this.systemDepsLoaded=new Set}async resolve(e,t){let n=h(e);n.addresses&&this.mergeAddresses(n.addresses),n.dependencies&&await this.resolveDeps(n.dependencies),await this.injectSystemDeps(n.dependencies);let i=this.reconstructMoveToml(n,this.globalAddresses),o={...t,"Move.toml":i};return{files:JSON.stringify(o),dependencies:JSON.stringify(this.dependencyFiles)}}mergeAddresses(e){for(let[t,n]of Object.entries(e))this.globalAddresses[t]=this.normalizeAddress(n)}normalizeAddress(e){if(!e)return e;let t=e;return t.startsWith("0x")&&(t=t.slice(2)),/^[0-9a-fA-F]+$/.test(t)?"0x"+t.padStart(64,"0"):e}async resolveDeps(e,t=null){for(let[n,i]of Object.entries(e)){let o,c,l;if(i.git)o=i.git,c=i.rev,l=i.subdir;else if(i.local){if(!t)continue;o=t.git,c=t.rev,l=this.resolvePath(t.subdir||"",i.local)}else continue;let r=`${o}|${c}|${l||""}`;if(this.visited.has(r))continue;this.visited.add(r);let a=await this.fetcher.fetch(o,c,l),d=null;for(let[u,f]of Object.entries(a))if(u.endsWith("Move.toml")){d=f;break}if(d){let u=h(d);u.addresses&&this.mergeAddresses(u.addresses),u.dependencies&&await this.resolveDeps(u.dependencies,{git:o,rev:c,subdir:l})}for(let[u,f]of Object.entries(a))if(u.endsWith(".move")||u.endsWith("Move.toml")){let k=`dependencies/${n}/${u}`;this.dependencyFiles[k]=f}}}resolvePath(e,t){let n=e.split("/").filter(o=>o&&o!=="."),i=t.split("/").filter(o=>o&&o!==".");for(let o of i)o===".."?n.pop():n.push(o);return n.join("/")}reconstructMoveToml(e,t){let n=`[package]
1
+ "use strict";var U=Object.create;var b=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var W=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var E=(a,e)=>{for(var t in e)b(a,t,{get:e[t],enumerable:!0})},L=(a,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of O(e))!j.call(a,n)&&n!==t&&b(a,n,{get:()=>e[n],enumerable:!(i=B(e,n))||i.enumerable});return a};var H=(a,e,t)=>(t=a!=null?U(W(a)):{},L(e||!a||!a.__esModule?b(t,"default",{value:a,enumerable:!0}):t,a)),V=a=>L(b({},"__esModule",{value:!0}),a);var ie={};E(ie,{buildMovePackage:()=>X,compileRaw:()=>ne,fetchPackageFromGitHub:()=>C,getSuiMoveVersion:()=>Y,getSuiVersion:()=>ee,getWasmBindings:()=>te,initMoveCompiler:()=>Z,resolveDependencies:()=>_});module.exports=V(ie);var M=class{async fetch(e,t,i){throw new Error("Not implemented")}async fetchFile(e,t,i){throw new Error("Not implemented")}},k=class extends M{constructor(){super(),this.cache=new Map}async fetch(e,t,i){let{owner:n,repo:s}=this.parseGitUrl(e);if(!n||!s)throw new Error(`Invalid git URL: ${e}`);let o=`https://api.github.com/repos/${n}/${s}/git/trees/${t}?recursive=1`,d;try{let c=await fetch(o);if(!c.ok)throw c.status===403||c.status===429?new Error("GitHub API rate limit exceeded."):new Error(`Failed to fetch tree: ${c.statusText}`);d=await c.json()}catch{return{}}let r={},l=[];for(let c of d.tree){if(c.type!=="blob")continue;let p=c.path;if(i){if(!c.path.startsWith(i))continue;p=c.path.slice(i.length),p.startsWith("/")&&(p=p.slice(1))}if(!p.endsWith(".move")&&p!=="Move.toml"&&p!=="Move.lock"&&!p.match(/^Move\.(mainnet|testnet|devnet)\.toml$/))continue;let m=`https://raw.githubusercontent.com/${n}/${s}/${t}/${c.path}`,g=this.fetchContent(m).then(u=>{u&&(r[p]=u)});l.push(g)}return await Promise.all(l),r}async fetchFile(e,t,i){let{owner:n,repo:s}=this.parseGitUrl(e);if(!n||!s)throw new Error(`Invalid git URL: ${e}`);let o=`https://raw.githubusercontent.com/${n}/${s}/${t}/${i}`;return this.fetchContent(o)}async fetchContent(e){if(this.cache.has(e))return this.cache.get(e)??null;try{let t=await fetch(e);if(!t.ok)return null;let i=await t.text();return this.cache.set(e,i),i}catch{return null}}parseGitUrl(e){try{let i=new URL(e).pathname.split("/").filter(n=>n);if(i.length>=2){let n=i[1];return n.endsWith(".git")&&(n=n.slice(0,-4)),{owner:i[0],repo:n}}}catch{}return{owner:null,repo:null}}};function z(a){let e=!1,t="";for(let i=0;i<a.length;i++){let n=a[i];if((n==='"'||n==="'")&&(!e||n===t)&&(e=!e,t=n),!e&&n==="#")return a.slice(0,i)}return a}function x(a){let e=a.trim();if(!e)return"";if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(e==="true")return!0;if(e==="false")return!1;let t=Number(e);return Number.isNaN(t)?e:t}function G(a){let e={},t=a.trim().replace(/^\{/,"").replace(/\}$/,""),i="",n=!1,s="",o=[];for(let d=0;d<t.length;d++){let r=t[d];if((r==='"'||r==="'")&&(!n||r===s)&&(n=!n,s=r),!n&&r===","){o.push(i),i="";continue}i+=r}i.trim()&&o.push(i);for(let d of o){let r=d.indexOf("=");if(r===-1)continue;let l=d.slice(0,r).trim(),c=d.slice(r+1).trim();e[l]=x(c)}return e}function q(a){let e=[],t=a.trim().replace(/^\[/,"").replace(/\]$/,""),i="",n=!1,s="",o=0;for(let d=0;d<t.length;d++){let r=t[d];if((r==='"'||r==="'")&&(!n||r===s)&&(n=!n,s=n?r:""),!n&&(r==="{"&&o++,r==="}"&&o--,r===","&&o===0)){i.trim()&&e.push(F(i.trim())),i="";continue}i+=r}return i.trim()&&e.push(F(i.trim())),e}function F(a){return a.startsWith("{")?G(a):x(a)}function y(a){let e={},t=null,i=!1,n=a.split(/\r?\n/);function s(o,d){let r=o;for(let l of d){if(!(l in r))return;r=r[l]}return r}for(let o of n){let d=z(o).trim();if(!d)continue;let r=d.match(/^\[\[([^\]]+)\]\]$/);if(r){t=r[1].trim(),i=!0;let u=t.split("."),f=e;for(let v=0;v<u.length-1;v++){let D=u[v];D in f||(f[D]={}),f=f[D]}let h=u[u.length-1];Array.isArray(f[h])||(f[h]=[]),f[h].push({});continue}let l=d.match(/^\[([^\]]+)\]$/);if(l){t=l[1].trim(),i=!1;continue}let c=d.indexOf("=");if(c===-1||!t)continue;let p=d.slice(0,c).trim(),m=d.slice(c+1).trim(),g;if(m.startsWith("{")?g=G(m):m.startsWith("[")?g=q(m):g=x(m),i){let u=t.split("."),f=s(e,u);if(Array.isArray(f)&&f.length>0){let h=f[f.length-1];h[p]=g}}else{let u=t.split("."),f=e;for(let v of u)v in f||(f[v]={}),f=f[v];let h=t==="package"?p.replace(/-/g,"_"):p;f[h]=g}}return e}var P=class{constructor(e){this.packageTable=new Map;this.graph=new Map;this.alwaysDeps=new Set(["Sui","MoveStdlib"]);this.root=e}addPackage(e){this.packageTable.set(e.id.name,e),this.graph.has(e.id.name)||this.graph.set(e.id.name,new Set)}addDependency(e,t,i){this.graph.has(e)||this.graph.set(e,new Set),this.graph.get(e).add(t)}getPackage(e){return this.packageTable.get(e)}getAllPackages(){return Array.from(this.packageTable.values())}getImmediateDependencies(e){return this.graph.get(e)||new Set}getTransitiveDependencies(e){let t=new Set,i=new Set,n=s=>{if(i.has(s))return;i.add(s),t.add(s);let o=this.graph.get(s);if(o)for(let d of o)n(d)};return n(e),t.delete(e),t}topologicalOrder(){let e=new Set,t=[],i=n=>{if(e.has(n))return;e.add(n);let s=this.graph.get(n);if(s)for(let o of s)i(o);t.push(n)};i(this.root);for(let n of this.packageTable.keys())i(n);return t}detectCycle(){let e=new Set,t=new Set,i=new Map,n=s=>{e.add(s),t.add(s);let o=this.graph.get(s);if(o)for(let d of o)if(e.has(d)){if(t.has(d)){let r=[d],l=s;for(;l!==d;)r.unshift(l),l=i.get(l);return r.unshift(d),r}}else{i.set(d,s);let r=n(d);if(r)return r}return t.delete(s),null};for(let s of this.packageTable.keys())if(!e.has(s)){let o=n(s);if(o)return o}return null}getRootPackage(){return this.packageTable.get(this.root)}getRootName(){return this.root}isAlwaysDep(e){return this.alwaysDeps.has(e)}};var S=class{constructor(e,t={}){this.unifiedAddressTable=new Map;this.packageResolvedTables=new Map;this.graph=e,this.buildConfig=t}async resolve(){let e=this.graph.topologicalOrder();for(let t of e){let i=this.graph.getPackage(t);if(i)for(let[n,s]of Object.entries(i.manifest.addresses)){let o=this.normalizeAddress(s);this.unifiedAddressTable.has(n)&&this.unifiedAddressTable.get(n)!==o||this.unifiedAddressTable.set(n,o)}}for(let t of this.graph.getAllPackages()){let i={};for(let[n,s]of this.unifiedAddressTable.entries())i[n]=s;this.packageResolvedTables.set(t.id.name,i),t.resolvedTable=i}}normalizeAddress(e){if(!e)return e;let t=e.trim();return t.startsWith("0x")&&(t=t.slice(2)),/^[0-9a-fA-F]+$/.test(t)?"0x"+t.padStart(64,"0"):e}getUnifiedAddressTable(){let e={};for(let[t,i]of this.unifiedAddressTable.entries())e[t]=i;return e}getPackageResolvedTable(e){return this.packageResolvedTables.get(e)}getGraph(){return this.graph}topologicalOrder(){return this.graph.topologicalOrder()}getRootName(){return this.graph.getRootName()}getPackage(e){return this.graph.getPackage(e)}getImmediateDependencies(e){return this.graph.getImmediateDependencies(e)}};var R=class{constructor(e){this.dependencies=[];this.resolvedGraph=e,this.rootPackageName=e.getRootName()}async compute(e){if(!this.resolvedGraph.getPackage(this.rootPackageName))throw new Error(`Root package '${this.rootPackageName}' not found`);let i=this.resolvedGraph.getImmediateDependencies(this.rootPackageName),n=this.resolvedGraph.topologicalOrder();for(let s of n){if(s===this.rootPackageName)continue;let o=this.resolvedGraph.getPackage(s);if(!o)continue;let d=e.get(s)||{},r=this.extractSourcePaths(s,d),l=o.manifest.edition||"legacy",c={name:s,isImmediate:i.has(s),sourcePaths:r,addressMapping:o.resolvedTable||{},compilerConfig:{edition:l,flavor:"sui"},moduleFormat:r.length>0?"Source":"Bytecode",edition:l};this.dependencies.push(c)}}extractSourcePaths(e,t){let i=[];for(let n of Object.keys(t))n.endsWith("Move.toml")||n.endsWith("Move.lock")||n.endsWith(".move")&&i.push(n);return i}toPackageGroupedFormat(e){let t=[];for(let i of this.dependencies){let n=e.get(i.name)||{},s={};for(let[o,d]of Object.entries(n)){if(o.endsWith("Move.lock"))continue;let r=`dependencies/${i.name}/${o}`;if(o.endsWith("Move.toml")){let l=this.reconstructDependencyMoveToml(i.name,d,i.edition,i.addressMapping);s[r]=l}else s[r]=d}t.push({name:i.name,files:s,edition:i.edition})}return t}reconstructDependencyMoveToml(e,t,i,n){let s=t.split(`
2
+ `),o=[],d=[],r=!1,l=!1;for(let g of s){let u=g.trim();if(u.startsWith("[package]")){r=!0,l=!1;continue}if(u.startsWith("[dependencies]")){r=!1,l=!0;continue}if(u.startsWith("[")){r=!1,l=!1;continue}r&&u&&o.push(g),l&&u&&d.push(g)}let c=`[package]
3
+ `,p=!1,m=!1;for(let g of o)if(g.includes("name ="))c+=g+`
4
+ `,p=!0;else if(g.includes("version ="))c+=g+`
5
+ `,m=!0;else{if(g.includes("edition ="))continue;c+=g+`
6
+ `}p||(c+=`name = "${e}"
7
+ `),m||(c+=`version = "0.0.0"
8
+ `),c+=`edition = "${i}"
9
+ `,c+=`
10
+ [dependencies]
11
+ `;for(let g of d)c+=g+`
12
+ `;c+=`
13
+ [addresses]
14
+ `;for(let[g,u]of Object.entries(n))c+=`${g} = "${u}"
15
+ `;return c}getUnifiedAddressTable(){return this.resolvedGraph.getUnifiedAddressTable()}};var $=class{constructor(e,t="mainnet"){this.visited=new Set;this.packageNameCache=new Map;this.packageFiles=new Map;this.fetcher=e,this.network=t}async resolve(e,t){let i=y(e),n=i.package?.name||"RootPackage",s=i.package?.edition;if(t["Move.lock"]){let h=y(t["Move.lock"]);h.move?.["toolchain-version"]?.edition&&(s=h.move["toolchain-version"].edition)}let o=s||"2024.beta",d=new P(n),r=await this.buildPackage(n,null,e,t);s&&(r.manifest.edition=s),d.addPackage(r),this.packageFiles.set(n,t),await this.loadFromLockfile(d,r,t)||await this.buildDependencyGraph(d,r);let c=d.detectCycle();if(c)throw new Error(`Dependency cycle detected: ${c.join(" \u2192 ")}`);let p=new S(d,{});await p.resolve();let m=new R(p);await m.compute(this.packageFiles);let g=this.reconstructMoveToml(i,p.getUnifiedAddressTable(),!0,o),u={...t};delete u["Move.lock"],u["Move.toml"]=g;let f=m.toPackageGroupedFormat(this.packageFiles);return{files:JSON.stringify(u),dependencies:JSON.stringify(f)}}async buildPackage(e,t,i,n){let s=y(i),o={name:s.package?.name||e,version:s.package?.version||"0.0.0",edition:s.package?.edition,publishedAt:s.package?.published_at,addresses:s.addresses||{},dependencies:s.dependencies||{},devDependencies:s["dev-dependencies"]},d=new Map;if(o.dependencies)for(let[l,c]of Object.entries(o.dependencies)){let p=this.parseDependencyInfo(c);p&&d.set(l,p)}return{id:{name:o.name,version:o.version,source:t||{type:"local"}},manifest:o,dependencies:d,devDependencies:new Map}}parseDependencyInfo(e){return e?e.git&&e.rev?{source:{type:"git",git:e.git,rev:e.rev,subdir:e.subdir}}:e.local?{source:{type:"local",local:e.local}}:null:null}async buildDependencyGraph(e,t){for(let[i,n]of t.dependencies.entries()){if(n.source.type==="local")if(t.id.source.type==="git"&&n.source.local){let g=t.id.source.subdir||"",u=n.source.local,f=this.resolveRelativePath(g,u);n.source={type:"git",git:t.id.source.git,rev:t.id.source.rev,subdir:f}}else continue;if(n.source.type!=="git")continue;let s=`${n.source.git}|${n.source.rev}|${n.source.subdir||""}`;if(this.visited.has(s)){let g=this.findPackageBySource(e,n.source);g&&e.addDependency(t.id.name,g.id.name,n);continue}this.visited.add(s);let o=n.source.subdir;!o&&n.source.git&&this.isSuiRepo(n.source.git)&&(o=this.inferSuiFrameworkSubdir(i),o&&(n.source.subdir=o));let d=await this.fetcher.fetch(n.source.git,n.source.rev,o),r=null,l=`Move.${this.network}.toml`;for(let[g,u]of Object.entries(d))if(g.endsWith(l)){r=u;break}if(!r){for(let[g,u]of Object.entries(d))if(g.endsWith("Move.toml")){r=u;break}}if(!r)continue;let c=await this.buildPackage(i,n.source,r,d),p=this.packageNameCache.get(c.manifest.name);if(p){let g=this.findPackageBySource(e,p);g&&e.addDependency(t.id.name,g.id.name,n);continue}this.packageNameCache.set(c.manifest.name,n.source);let m=d["Move.lock"];if(m){let g=y(m);if(g.env?.[this.network]){let u=g.env[this.network]["latest-published-id"]||g.env[this.network]["original-published-id"];u&&(c.manifest.publishedAt=u,c.manifest.addresses[c.manifest.name]=this.normalizeAddress(u))}c.manifest.edition||(c.manifest.edition="legacy")}if(!c.manifest.publishedAt){let g={Sui:"0x2",MoveStdlib:"0x1",SuiSystem:"0x3",Bridge:"0xb"};g[i]&&(c.manifest.publishedAt=g[i])}e.addPackage(c),e.addDependency(t.id.name,c.id.name,n),this.packageFiles.set(c.id.name,d),await this.buildDependencyGraph(e,c)}}findPackageBySource(e,t){for(let i of e.getAllPackages()){let n=i.id.source;if(n.type===t.type&&n.git===t.git&&n.rev===t.rev&&n.subdir===t.subdir)return i}}resolveRelativePath(e,t){let i=e?e.split("/").filter(Boolean):[],n=t.split("/").filter(Boolean),s=[...i];for(let o of n)o===".."?s.length>0&&s.pop():o!=="."&&s.push(o);return s.join("/")}async computeManifestDigest(e){let i=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(n)).map(d=>d.toString(16).padStart(2,"0")).join("").toUpperCase()}async loadFromLockfile(e,t,i){let n=i["Move.lock"];if(!n)return!1;let s=y(n),o=s.pinned?.[this.network];if(!o)return!1;let d=i["Move.toml"];if(d&&s.move?.manifest_digest&&await this.computeManifestDigest(d)!==s.move.manifest_digest)return!1;let r=new Map;for(let[l,c]of Object.entries(o)){let p=this.lockfileSourceToDependencySource(c.source);if(!p)continue;let m=await this.fetchFromSource(p);if(!m)return!1;let g=m["Move.toml"];if(!g||c["manifest-digest"]&&await this.computeManifestDigest(g)!==c["manifest-digest"])return!1;let u=await this.buildPackage(l,p,g,m);r.set(l,u),this.packageFiles.set(u.manifest.name,m),(p.type!=="local"||!("root"in c.source))&&e.addPackage(u)}for(let[l,c]of Object.entries(o)){let p=r.get(l);if(p&&c.deps)for(let[m,g]of Object.entries(c.deps)){let u=r.get(g);if(u){let f=p.dependencies.get(m);f&&e.addDependency(p.id.name,u.id.name,f)}}}return!0}lockfileSourceToDependencySource(e){return"git"in e?{type:"git",git:e.git,rev:e.rev,subdir:e.subdir}:"local"in e?{type:"local",local:e.local}:"root"in e?{type:"local"}:null}async fetchFromSource(e){if(e.type==="git"&&e.git&&e.rev)try{return await this.fetcher.fetch(e.git,e.rev,e.subdir)}catch{return null}return null}reconstructMoveToml(e,t,i,n){let o=`[package]
2
16
  name = "${e.package.name}"
3
17
  version = "${e.package.version}"
4
- `;if(e.package.edition&&(n+=`edition = "${e.package.edition}"
5
- `),n+=`
18
+ `,d=n||e.package.edition;if(d&&(o+=`edition = "${d}"
19
+ `),o+=`
6
20
  [dependencies]
7
- `,e.dependencies)for(let[i,o]of Object.entries(e.dependencies))n+=`${i} = { git = "${o.git}", rev = "${o.rev}" }
8
- `;n+=`
21
+ `,e.dependencies)for(let[r,l]of Object.entries(e.dependencies)){let c=l;c.local?o+=`${r} = { local = "${c.local}" }
22
+ `:c.git&&c.rev&&(c.subdir?o+=`${r} = { git = "${c.git}", subdir = "${c.subdir}", rev = "${c.rev}" }
23
+ `:o+=`${r} = { git = "${c.git}", rev = "${c.rev}" }
24
+ `)}o+=`
9
25
  [addresses]
10
- `;for(let[i,o]of Object.entries(t))n+=`${i} = "${o}"
11
- `;return n}async injectSystemDeps(e){if(e){for(let n of Object.values(e))if(!(!n||!n.git||!n.rev)&&this.isSuiRepo(n.git)){await this.addImplicitSystemDepsForRepo(n.git,n.rev);break}}this.dependencyFiles["dependencies/MoveStdlib/Move.toml"]||this.addFallbackSystemDeps()}async addImplicitSystemDepsForRepo(e,t){if(!this.isSuiRepo(e))return;let n=`${e}|${t}`;if(this.systemDepsLoaded.has(n))return;this.systemDepsLoaded.add(n);let i="crates/sui-framework-snapshot/manifest.json";if(!this.fetcher.fetchFile)return;let o=null;try{let c=await this.fetcher.fetchFile(e,t,i);if(c){let l=JSON.parse(c),r=Object.keys(l).map(u=>Number(u)).filter(u=>!Number.isNaN(u)).sort((u,f)=>u-f),a=r[r.length-1],d=l[String(a)];d&&d.packages&&(o=d.packages)}}catch{}o||(o=this.fallbackSystemPackages());for(let c of o)!c||!c.name||!c.id||c.name!=="DeepBook"&&this.addSystemDep(c.name,c.id)}addFallbackSystemDeps(){for(let e of this.fallbackSystemPackages())!e||!e.name||!e.id||e.name!=="DeepBook"&&this.addSystemDep(e.name,e.id)}addSystemDep(e,t){let n=`dependencies/${e}/Move.toml`;if(this.dependencyFiles[n])return;let i=["[package]",`name = "${e}"`,'version = "0.0.0"',`published-at = "${this.normalizeAddress(t)}"`,""].join(`
12
- `);this.dependencyFiles[n]=i}fallbackSystemPackages(){return[{name:"MoveStdlib",id:"0x1"},{name:"Sui",id:"0x2"},{name:"SuiSystem",id:"0x3"},{name:"Bridge",id:"0xb"}]}isSuiRepo(e){return e.includes("github.com/MystenLabs/sui")}};async function b(s,e,t){return new y(t).resolve(s,e)}var X={},oe=(()=>{try{return new URL("./sui_move_wasm_bg.wasm",X.url)}catch{return"./sui_move_wasm_bg.wasm"}})(),R;async function m(s){return R||(R=import("./sui_move_wasm.js").then(async e=>(s?await e.default({module_or_path:s}):await e.default(),e))),R}function S(s){return JSON.stringify(s??{})}function $(s){return{success:!1,error:s instanceof Error?s.message:typeof s=="string"?s:"Unknown error"}}function D(s){if(typeof s!="object"||s===null)throw new Error("Unexpected compile result shape from wasm");let e=s;if(typeof e.success=="function"&&typeof e.output=="function")return e;if(typeof e.success=="boolean"&&typeof e.output=="string")return{success:()=>e.success,output:()=>e.output};throw new Error("Unexpected compile result shape from wasm")}function I(s){let e=t=>t.map(n=>n.toString(16).padStart(2,"0")).join("");try{let t=JSON.parse(s);if(!t.modules||!t.dependencies||!t.digest)throw new Error("missing fields in compiler output");let n=typeof t.digest=="string"?t.digest:e(t.digest);return{success:!0,modules:t.modules,dependencies:t.dependencies,digest:n}}catch(t){return $(t)}}function P(s){if(!s)return s;let e=s;return e.startsWith("0x")&&(e=e.slice(2)),/^[0-9a-fA-F]+$/.test(e)?"0x"+e.padStart(64,"0"):s}function C(s){let e={std:"0x1",sui:"0x2",sui_system:"0x3",bridge:"0xb"},t=s.split(/\r?\n/),n=/^\s*\[[^\]]+\]\s*$/,i=-1,o=t.length;for(let r=0;r<t.length;r++)if(/^\s*\[addresses\]\s*$/.test(t[r])){i=r;for(let a=r+1;a<t.length;a++)if(n.test(t[a])){o=a;break}break}let c=new Set;if(i>=0)for(let r=i+1;r<o;r++){let a=t[r].trim();if(!a||a.startsWith("#"))continue;let d=a.match(/^([A-Za-z0-9_.-]+)\s*=/);d&&c.add(d[1])}let l=Object.entries(e).filter(([r])=>!c.has(r)).map(([r,a])=>`${r} = "${P(a)}"`);return l.length===0?s:(i>=0?t.splice(o,0,...l):t.push("","[addresses]",...l),t.join(`
13
- `))}function z(s){let e=[{name:"Sui",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/sui-framework",rev:"framework/mainnet"},{name:"MoveStdlib",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/move-stdlib",rev:"framework/mainnet"}],t=s.split(/\r?\n/),n=/^\s*\[[^\]]+\]\s*$/,i=-1,o=t.length;for(let r=0;r<t.length;r++)if(/^\s*\[dependencies\]\s*$/.test(t[r])){i=r;for(let a=r+1;a<t.length;a++)if(n.test(t[a])){o=a;break}break}let c=new Set;if(i>=0)for(let r=i+1;r<o;r++){let a=t[r].trim();if(!a||a.startsWith("#"))continue;let d=a.match(/^([A-Za-z0-9_.-]+)\s*=/);d&&c.add(d[1])}let l=e.filter(r=>!c.has(r.name)).map(r=>`${r.name} = { git = "${r.git}", subdir = "${r.subdir}", rev = "${r.rev}" }`);return l.length===0?s:(i>=0?t.splice(o,0,...l):t.push("","[dependencies]",...l),t.join(`
14
- `))}function H(s){let e={...s??{}};if(e["dependencies/MoveStdlib/Move.toml"])return e;let t=[{name:"MoveStdlib",id:"0x1"},{name:"Sui",id:"0x2"},{name:"SuiSystem",id:"0x3"},{name:"Bridge",id:"0xb"}];for(let n of t){let i=`dependencies/${n.name}/Move.toml`;e[i]||(e[i]=["[package]",`name = "${n.name}"`,'version = "0.0.0"',`published-at = "${P(n.id)}"`,""].join(`
15
- `))}return e}function F(s){return!!(s?.["dependencies/MoveStdlib/Move.toml"]&&s?.["dependencies/Sui/Move.toml"])}function _(s){return typeof s=="string"?JSON.parse(s):s}async function G(s){await m(s?.wasm)}async function J(s){try{let e=s.dependencies??{},t={...s.files},n=typeof t["Move.toml"]=="string";if(s.autoSystemDeps&&n){let a=C(t["Move.toml"]);F(e)||(a=z(a)),t["Move.toml"]=a}if(s.autoSystemDeps&&!F(e)&&n){let a=await b(t["Move.toml"],t,new p);t=_(a.files),e=_(a.dependencies)}else s.autoSystemDeps&&(e=H(e));let i=await m(s.wasm),o=s.ansiColor&&typeof i.compile_with_color=="function"?i.compile_with_color(S(t),S(e),!0):i.compile(S(t),S(e)),c=D(o),l=c.success(),r=c.output();return l?I(r):$(r)}catch(e){return $(e)}}async function q(s){return(await m(s?.wasm)).sui_move_version()}async function V(s){return(await m(s?.wasm)).sui_version()}async function K(s){return m(s?.wasm)}async function Q(s,e,t){let n=await m(t?.wasm),i=t?.ansiColor&&typeof n.compile_with_color=="function"?n.compile_with_color(s,e,!0):n.compile(s,e),o=D(i);return{success:o.success(),output:o.output()}}0&&(module.exports={Fetcher,GitHubFetcher,Resolver,buildMovePackage,compileRaw,getSuiMoveVersion,getSuiVersion,getWasmBindings,initMoveCompiler,parseToml,resolve});
26
+ `;for(let[r,l]of Object.entries(t))o+=`${r} = "${l}"
27
+ `;return o}normalizeAddress(e){if(!e)return e;let t=e.trim();return t.startsWith("0x")&&(t=t.slice(2)),/^[0-9a-fA-F]+$/.test(t)?"0x"+t.padStart(64,"0"):e}isSuiRepo(e){return e.includes("github.com/MystenLabs/sui")}inferSuiFrameworkSubdir(e){let t={Sui:"crates/sui-framework/packages/sui-framework",MoveStdlib:"crates/sui-framework/packages/move-stdlib",SuiSystem:"crates/sui-framework/packages/sui-system",Bridge:"crates/sui-framework/packages/bridge",DeepBook:"crates/sui-framework/packages/deepbook",SuiFramework:"crates/sui-framework/packages/sui-framework"};return t[e]||t[e.toLowerCase()]}};async function I(a,e,t,i="mainnet"){return new $(t,i).resolve(a,e)}function K(a){try{let e=new URL(a);if(e.hostname!=="github.com")return null;let t=e.pathname.split("/").filter(Boolean);if(t.length<2)return null;let i=t[0],n=t[1],s="main",o;return t.length>=4&&t[2]==="tree"&&(s=t[3],t.length>4&&(o=t.slice(4).join("/"))),{owner:i,repo:n,ref:s,subdir:o}}catch{return null}}async function C(a,e){let t=K(a);if(!t)throw new Error(`Invalid GitHub URL: ${a}`);let i=e?.fetcher||new k,n=e?.includeLock!==!1,s=`https://github.com/${t.owner}/${t.repo}.git`,o=await i.fetch(s,t.ref,t.subdir);if(!n&&o["Move.lock"]){let{"Move.lock":d,...r}=o;return r}return o}var A;async function w(a){return A||(A=import("./sui_move_wasm.js").then(async e=>(a?await e.default({module_or_path:a}):await e.default(),e))),A}function T(a){return{success:!1,error:a instanceof Error?a.message:typeof a=="string"?a:"Unknown error"}}function N(a){if(typeof a!="object"||a===null)throw new Error("Unexpected compile result shape from wasm");let e=a;if(typeof e.success=="function"&&typeof e.output=="function")return e;if(typeof e.success=="boolean"&&typeof e.output=="string")return{success:()=>e.success,output:()=>e.output};throw new Error("Unexpected compile result shape from wasm")}function Q(a){let e=t=>t.map(i=>i.toString(16).padStart(2,"0")).join("");try{let t=JSON.parse(a);if(!t.modules||!t.dependencies||!t.digest)throw new Error("missing fields in compiler output");let i=typeof t.digest=="string"?t.digest:e(t.digest);return{success:!0,modules:t.modules,dependencies:t.dependencies,digest:i}}catch(t){return T(t)}}function J(a){let e=[{name:"Sui",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/sui-framework",rev:"framework/mainnet"},{name:"MoveStdlib",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/move-stdlib",rev:"framework/mainnet"}],t=a.split(/\r?\n/),i=/^\s*\[[^\]]+\]\s*$/,n=-1,s=t.length;for(let r=0;r<t.length;r++)if(/^\s*\[dependencies\]\s*$/.test(t[r])){n=r;for(let l=r+1;l<t.length;l++)if(i.test(t[l])){s=l;break}break}let o=new Set;if(n>=0)for(let r=n+1;r<s;r++){let l=t[r].trim();if(!l||l.startsWith("#"))continue;let c=l.match(/^([A-Za-z0-9_.-]+)\s*=/);c&&o.add(c[1])}let d=e.filter(r=>!o.has(r.name)).map(r=>`${r.name} = { git = "${r.git}", subdir = "${r.subdir}", rev = "${r.rev}" }`);return d.length===0?a:(n>=0?t.splice(s,0,...d):t.push("","[dependencies]",...d),t.join(`
28
+ `))}async function Z(a){await w(a?.wasm)}async function _(a){let e=a.files["Move.toml"]||"";e&&(e=J(e));let t=await I(e,{...a.files,"Move.toml":e},new k,a.network);return{files:t.files,dependencies:t.dependencies}}async function X(a){try{let e=a.resolvedDependencies?a.resolvedDependencies:await _(a),t=await w(a.wasm),i=a.ansiColor&&typeof t.compile_with_color=="function"?t.compile_with_color(e.files,e.dependencies,!0):t.compile(e.files,e.dependencies),n=N(i),s=n.success(),o=n.output();return s?Q(o):T(o)}catch(e){return T(e)}}async function Y(a){return(await w(a?.wasm)).sui_move_version()}async function ee(a){return(await w(a?.wasm)).sui_version()}async function te(a){return w(a?.wasm)}async function ne(a,e,t){let i=await w(t?.wasm),n=t?.ansiColor&&typeof i.compile_with_color=="function"?i.compile_with_color(a,e,!0):i.compile(a,e),s=N(n);return{success:s.success(),output:s.output()}}0&&(module.exports={buildMovePackage,compileRaw,fetchPackageFromGitHub,getSuiMoveVersion,getSuiVersion,getWasmBindings,initMoveCompiler,resolveDependencies});
package/dist/index.d.cts CHANGED
@@ -17,51 +17,55 @@ declare class GitHubFetcher extends Fetcher {
17
17
  private parseGitUrl;
18
18
  }
19
19
 
20
- declare class Resolver {
21
- private fetcher;
22
- private globalAddresses;
23
- private visited;
24
- private dependencyFiles;
25
- private systemDepsLoaded;
26
- constructor(fetcher: Fetcher);
27
- resolve(rootMoveToml: string, rootFiles: Record<string, string>): Promise<{
28
- files: string;
29
- dependencies: string;
30
- }>;
31
- private mergeAddresses;
32
- private normalizeAddress;
33
- private resolveDeps;
34
- private resolvePath;
35
- private reconstructMoveToml;
36
- private injectSystemDeps;
37
- private addImplicitSystemDepsForRepo;
38
- private addFallbackSystemDeps;
39
- private addSystemDep;
40
- private fallbackSystemPackages;
41
- private isSuiRepo;
42
- }
43
- declare function resolve(rootMoveTomlContent: string, rootSourceFiles: Record<string, string>, fetcher: Fetcher): Promise<{
44
- files: string;
45
- dependencies: string;
46
- }>;
20
+ /**
21
+ * Utility functions for fetching Move packages from GitHub
22
+ */
47
23
 
48
- declare function parseToml(content: string): {
49
- package: Record<string, any>;
50
- dependencies: Record<string, any>;
51
- addresses: Record<string, any>;
52
- };
24
+ /**
25
+ * Fetch a Move package from GitHub URL
26
+ *
27
+ * @param url - GitHub repository URL (e.g., "https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/sui-framework")
28
+ * @param options - Optional configuration
29
+ * @returns Object with Move.toml and source files
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const files = await fetchPackageFromGitHub(
34
+ * 'https://github.com/MystenLabs/deepbookv3/tree/main/packages/deepbook'
35
+ * );
36
+ *
37
+ * // files = {
38
+ * // 'Move.toml': '...',
39
+ * // 'Move.lock': '...',
40
+ * // 'sources/pool.move': '...',
41
+ * // ...
42
+ * // }
43
+ * ```
44
+ */
45
+ declare function fetchPackageFromGitHub(url: string, options?: {
46
+ /** Custom fetcher instance (default: GitHubFetcher) */
47
+ fetcher?: GitHubFetcher;
48
+ /** Include Move.lock file (default: true) */
49
+ includeLock?: boolean;
50
+ }): Promise<Record<string, string>>;
53
51
 
52
+ interface ResolvedDependencies {
53
+ /** JSON string of resolved files for the root package */
54
+ files: string;
55
+ /** JSON string of resolved dependencies */
56
+ dependencies: string;
57
+ }
54
58
  interface BuildInput {
55
59
  /** Virtual file system contents. Keys are paths (e.g. "Move.toml", "sources/Module.move"). */
56
60
  files: Record<string, string>;
57
- /** Optional dependency files keyed by path. */
58
- dependencies?: Record<string, string>;
59
61
  /** Optional custom URL for the wasm binary. Defaults to bundled wasm next to this module. */
60
62
  wasm?: string | URL;
61
63
  /** Emit ANSI color codes in diagnostics when available. */
62
64
  ansiColor?: boolean;
63
- /** Inject standard Sui system packages when missing (CLI-like behavior). */
64
- autoSystemDeps?: boolean;
65
+ /** Network environment (mainnet, testnet, devnet). Defaults to mainnet. */
66
+ network?: "mainnet" | "testnet" | "devnet";
67
+ /** Optional pre-resolved dependencies. If provided, dependency resolution will be skipped. */
68
+ resolvedDependencies?: ResolvedDependencies;
65
69
  }
66
70
  interface BuildSuccess {
67
71
  success: true;
@@ -81,6 +85,11 @@ type WasmModule = typeof __sui_move_wasm_js;
81
85
  declare function initMoveCompiler(options?: {
82
86
  wasm?: string | URL;
83
87
  }): Promise<void>;
88
+ /**
89
+ * Resolve dependencies for a Move package without compiling.
90
+ * This function can be used to resolve dependencies once and reuse them across multiple builds.
91
+ */
92
+ declare function resolveDependencies(input: Omit<BuildInput, "resolvedDependencies">): Promise<ResolvedDependencies>;
84
93
  /** Compile a Move package in memory using the bundled Move compiler wasm. */
85
94
  declare function buildMovePackage(input: BuildInput): Promise<BuildSuccess | BuildFailure>;
86
95
  /** Sui Move version baked into the wasm (e.g. from Cargo.lock). */
@@ -105,4 +114,4 @@ declare function compileRaw(filesJson: string, depsJson: string, options?: {
105
114
  }>;
106
115
  type BuildResult = BuildSuccess | BuildFailure;
107
116
 
108
- export { type BuildFailure, type BuildInput, type BuildResult, type BuildSuccess, Fetcher, GitHubFetcher, Resolver, buildMovePackage, compileRaw, getSuiMoveVersion, getSuiVersion, getWasmBindings, initMoveCompiler, parseToml, resolve };
117
+ export { type BuildFailure, type BuildInput, type BuildResult, type BuildSuccess, type ResolvedDependencies, buildMovePackage, compileRaw, fetchPackageFromGitHub, getSuiMoveVersion, getSuiVersion, getWasmBindings, initMoveCompiler, resolveDependencies };
package/dist/index.d.ts CHANGED
@@ -17,51 +17,55 @@ declare class GitHubFetcher extends Fetcher {
17
17
  private parseGitUrl;
18
18
  }
19
19
 
20
- declare class Resolver {
21
- private fetcher;
22
- private globalAddresses;
23
- private visited;
24
- private dependencyFiles;
25
- private systemDepsLoaded;
26
- constructor(fetcher: Fetcher);
27
- resolve(rootMoveToml: string, rootFiles: Record<string, string>): Promise<{
28
- files: string;
29
- dependencies: string;
30
- }>;
31
- private mergeAddresses;
32
- private normalizeAddress;
33
- private resolveDeps;
34
- private resolvePath;
35
- private reconstructMoveToml;
36
- private injectSystemDeps;
37
- private addImplicitSystemDepsForRepo;
38
- private addFallbackSystemDeps;
39
- private addSystemDep;
40
- private fallbackSystemPackages;
41
- private isSuiRepo;
42
- }
43
- declare function resolve(rootMoveTomlContent: string, rootSourceFiles: Record<string, string>, fetcher: Fetcher): Promise<{
44
- files: string;
45
- dependencies: string;
46
- }>;
20
+ /**
21
+ * Utility functions for fetching Move packages from GitHub
22
+ */
47
23
 
48
- declare function parseToml(content: string): {
49
- package: Record<string, any>;
50
- dependencies: Record<string, any>;
51
- addresses: Record<string, any>;
52
- };
24
+ /**
25
+ * Fetch a Move package from GitHub URL
26
+ *
27
+ * @param url - GitHub repository URL (e.g., "https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/sui-framework")
28
+ * @param options - Optional configuration
29
+ * @returns Object with Move.toml and source files
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const files = await fetchPackageFromGitHub(
34
+ * 'https://github.com/MystenLabs/deepbookv3/tree/main/packages/deepbook'
35
+ * );
36
+ *
37
+ * // files = {
38
+ * // 'Move.toml': '...',
39
+ * // 'Move.lock': '...',
40
+ * // 'sources/pool.move': '...',
41
+ * // ...
42
+ * // }
43
+ * ```
44
+ */
45
+ declare function fetchPackageFromGitHub(url: string, options?: {
46
+ /** Custom fetcher instance (default: GitHubFetcher) */
47
+ fetcher?: GitHubFetcher;
48
+ /** Include Move.lock file (default: true) */
49
+ includeLock?: boolean;
50
+ }): Promise<Record<string, string>>;
53
51
 
52
+ interface ResolvedDependencies {
53
+ /** JSON string of resolved files for the root package */
54
+ files: string;
55
+ /** JSON string of resolved dependencies */
56
+ dependencies: string;
57
+ }
54
58
  interface BuildInput {
55
59
  /** Virtual file system contents. Keys are paths (e.g. "Move.toml", "sources/Module.move"). */
56
60
  files: Record<string, string>;
57
- /** Optional dependency files keyed by path. */
58
- dependencies?: Record<string, string>;
59
61
  /** Optional custom URL for the wasm binary. Defaults to bundled wasm next to this module. */
60
62
  wasm?: string | URL;
61
63
  /** Emit ANSI color codes in diagnostics when available. */
62
64
  ansiColor?: boolean;
63
- /** Inject standard Sui system packages when missing (CLI-like behavior). */
64
- autoSystemDeps?: boolean;
65
+ /** Network environment (mainnet, testnet, devnet). Defaults to mainnet. */
66
+ network?: "mainnet" | "testnet" | "devnet";
67
+ /** Optional pre-resolved dependencies. If provided, dependency resolution will be skipped. */
68
+ resolvedDependencies?: ResolvedDependencies;
65
69
  }
66
70
  interface BuildSuccess {
67
71
  success: true;
@@ -81,6 +85,11 @@ type WasmModule = typeof __sui_move_wasm_js;
81
85
  declare function initMoveCompiler(options?: {
82
86
  wasm?: string | URL;
83
87
  }): Promise<void>;
88
+ /**
89
+ * Resolve dependencies for a Move package without compiling.
90
+ * This function can be used to resolve dependencies once and reuse them across multiple builds.
91
+ */
92
+ declare function resolveDependencies(input: Omit<BuildInput, "resolvedDependencies">): Promise<ResolvedDependencies>;
84
93
  /** Compile a Move package in memory using the bundled Move compiler wasm. */
85
94
  declare function buildMovePackage(input: BuildInput): Promise<BuildSuccess | BuildFailure>;
86
95
  /** Sui Move version baked into the wasm (e.g. from Cargo.lock). */
@@ -105,4 +114,4 @@ declare function compileRaw(filesJson: string, depsJson: string, options?: {
105
114
  }>;
106
115
  type BuildResult = BuildSuccess | BuildFailure;
107
116
 
108
- export { type BuildFailure, type BuildInput, type BuildResult, type BuildSuccess, Fetcher, GitHubFetcher, Resolver, buildMovePackage, compileRaw, getSuiMoveVersion, getSuiVersion, getWasmBindings, initMoveCompiler, parseToml, resolve };
117
+ export { type BuildFailure, type BuildInput, type BuildResult, type BuildSuccess, type ResolvedDependencies, buildMovePackage, compileRaw, fetchPackageFromGitHub, getSuiMoveVersion, getSuiVersion, getWasmBindings, initMoveCompiler, resolveDependencies };
package/dist/index.js CHANGED
@@ -1,15 +1,28 @@
1
- var g=class{async fetch(e,t,s){throw new Error("Not implemented")}async fetchFile(e,t,s){throw new Error("Not implemented")}},m=class extends g{constructor(){super(),this.cache=new Map}async fetch(e,t,s){let{owner:i,repo:o}=this.parseGitUrl(e);if(!i||!o)throw new Error(`Invalid git URL: ${e}`);let c=`https://api.github.com/repos/${i}/${o}/git/trees/${t}?recursive=1`,l;try{let d=await fetch(c);if(!d.ok)throw d.status===403||d.status===429?new Error("GitHub API rate limit exceeded."):new Error(`Failed to fetch tree: ${d.statusText}`);l=await d.json()}catch{return{}}let r={},a=[];for(let d of l.tree){if(d.type!=="blob")continue;let u=d.path;if(s){if(!d.path.startsWith(s))continue;u=d.path.slice(s.length),u.startsWith("/")&&(u=u.slice(1))}if(!u.endsWith(".move")&&u!=="Move.toml")continue;let f=`https://raw.githubusercontent.com/${i}/${o}/${t}/${d.path}`,b=this.fetchContent(f).then($=>{$&&(r[u]=$)});a.push(b)}return await Promise.all(a),r}async fetchFile(e,t,s){let{owner:i,repo:o}=this.parseGitUrl(e);if(!i||!o)throw new Error(`Invalid git URL: ${e}`);let c=`https://raw.githubusercontent.com/${i}/${o}/${t}/${s}`;return this.fetchContent(c)}async fetchContent(e){if(this.cache.has(e))return this.cache.get(e)??null;try{let t=await fetch(e);if(!t.ok)return null;let s=await t.text();return this.cache.set(e,s),s}catch{return null}}parseGitUrl(e){try{let s=new URL(e).pathname.split("/").filter(i=>i);if(s.length>=2){let i=s[1];return i.endsWith(".git")&&(i=i.slice(0,-4)),{owner:s[0],repo:i}}}catch{}return{owner:null,repo:null}}};function D(n){let e=!1,t="";for(let s=0;s<n.length;s++){let i=n[s];if((i==='"'||i==="'")&&(!e||i===t)&&(e=!e,t=i),!e&&i==="#")return n.slice(0,s)}return n}function h(n){let e=n.trim();if(!e)return"";if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(e==="true")return!0;if(e==="false")return!1;let t=Number(e);return Number.isNaN(t)?e:t}function P(n){let e={},t=n.trim().replace(/^\{/,"").replace(/\}$/,""),s="",i=!1,o="",c=[];for(let l=0;l<t.length;l++){let r=t[l];if((r==='"'||r==="'")&&(!i||r===o)&&(i=!i,o=r),!i&&r===","){c.push(s),s="";continue}s+=r}s.trim()&&c.push(s);for(let l of c){let r=l.indexOf("=");if(r===-1)continue;let a=l.slice(0,r).trim(),d=l.slice(r+1).trim();e[a]=h(d)}return e}function y(n){let e={package:{},dependencies:{},addresses:{}},t=null,s=n.split(/\r?\n/);for(let i of s){let o=D(i).trim();if(!o)continue;let c=o.match(/^\[([^\]]+)\]$/);if(c){t=c[1].trim();continue}let l=o.indexOf("=");if(l===-1||!t)continue;let r=o.slice(0,l).trim(),a=o.slice(l+1).trim();t==="package"?e.package[r.replace(/-/g,"_")]=h(a):t==="dependencies"?a.startsWith("{")?e.dependencies[r]=P(a):e.dependencies[r]=h(a):t==="addresses"&&(e.addresses[r]=h(a))}return e}var v=class{constructor(e){this.fetcher=e,this.globalAddresses={},this.visited=new Set,this.dependencyFiles={},this.systemDepsLoaded=new Set}async resolve(e,t){let s=y(e);s.addresses&&this.mergeAddresses(s.addresses),s.dependencies&&await this.resolveDeps(s.dependencies),await this.injectSystemDeps(s.dependencies);let i=this.reconstructMoveToml(s,this.globalAddresses),o={...t,"Move.toml":i};return{files:JSON.stringify(o),dependencies:JSON.stringify(this.dependencyFiles)}}mergeAddresses(e){for(let[t,s]of Object.entries(e))this.globalAddresses[t]=this.normalizeAddress(s)}normalizeAddress(e){if(!e)return e;let t=e;return t.startsWith("0x")&&(t=t.slice(2)),/^[0-9a-fA-F]+$/.test(t)?"0x"+t.padStart(64,"0"):e}async resolveDeps(e,t=null){for(let[s,i]of Object.entries(e)){let o,c,l;if(i.git)o=i.git,c=i.rev,l=i.subdir;else if(i.local){if(!t)continue;o=t.git,c=t.rev,l=this.resolvePath(t.subdir||"",i.local)}else continue;let r=`${o}|${c}|${l||""}`;if(this.visited.has(r))continue;this.visited.add(r);let a=await this.fetcher.fetch(o,c,l),d=null;for(let[u,f]of Object.entries(a))if(u.endsWith("Move.toml")){d=f;break}if(d){let u=y(d);u.addresses&&this.mergeAddresses(u.addresses),u.dependencies&&await this.resolveDeps(u.dependencies,{git:o,rev:c,subdir:l})}for(let[u,f]of Object.entries(a))if(u.endsWith(".move")||u.endsWith("Move.toml")){let b=`dependencies/${s}/${u}`;this.dependencyFiles[b]=f}}}resolvePath(e,t){let s=e.split("/").filter(o=>o&&o!=="."),i=t.split("/").filter(o=>o&&o!==".");for(let o of i)o===".."?s.pop():s.push(o);return s.join("/")}reconstructMoveToml(e,t){let s=`[package]
1
+ var D=class{async fetch(e,t,i){throw new Error("Not implemented")}async fetchFile(e,t,i){throw new Error("Not implemented")}},k=class extends D{constructor(){super(),this.cache=new Map}async fetch(e,t,i){let{owner:n,repo:s}=this.parseGitUrl(e);if(!n||!s)throw new Error(`Invalid git URL: ${e}`);let o=`https://api.github.com/repos/${n}/${s}/git/trees/${t}?recursive=1`,c;try{let a=await fetch(o);if(!a.ok)throw a.status===403||a.status===429?new Error("GitHub API rate limit exceeded."):new Error(`Failed to fetch tree: ${a.statusText}`);c=await a.json()}catch{return{}}let r={},l=[];for(let a of c.tree){if(a.type!=="blob")continue;let p=a.path;if(i){if(!a.path.startsWith(i))continue;p=a.path.slice(i.length),p.startsWith("/")&&(p=p.slice(1))}if(!p.endsWith(".move")&&p!=="Move.toml"&&p!=="Move.lock"&&!p.match(/^Move\.(mainnet|testnet|devnet)\.toml$/))continue;let m=`https://raw.githubusercontent.com/${n}/${s}/${t}/${a.path}`,g=this.fetchContent(m).then(u=>{u&&(r[p]=u)});l.push(g)}return await Promise.all(l),r}async fetchFile(e,t,i){let{owner:n,repo:s}=this.parseGitUrl(e);if(!n||!s)throw new Error(`Invalid git URL: ${e}`);let o=`https://raw.githubusercontent.com/${n}/${s}/${t}/${i}`;return this.fetchContent(o)}async fetchContent(e){if(this.cache.has(e))return this.cache.get(e)??null;try{let t=await fetch(e);if(!t.ok)return null;let i=await t.text();return this.cache.set(e,i),i}catch{return null}}parseGitUrl(e){try{let i=new URL(e).pathname.split("/").filter(n=>n);if(i.length>=2){let n=i[1];return n.endsWith(".git")&&(n=n.slice(0,-4)),{owner:i[0],repo:n}}}catch{}return{owner:null,repo:null}}};function I(d){let e=!1,t="";for(let i=0;i<d.length;i++){let n=d[i];if((n==='"'||n==="'")&&(!e||n===t)&&(e=!e,t=n),!e&&n==="#")return d.slice(0,i)}return d}function M(d){let e=d.trim();if(!e)return"";if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(e==="true")return!0;if(e==="false")return!1;let t=Number(e);return Number.isNaN(t)?e:t}function L(d){let e={},t=d.trim().replace(/^\{/,"").replace(/\}$/,""),i="",n=!1,s="",o=[];for(let c=0;c<t.length;c++){let r=t[c];if((r==='"'||r==="'")&&(!n||r===s)&&(n=!n,s=r),!n&&r===","){o.push(i),i="";continue}i+=r}i.trim()&&o.push(i);for(let c of o){let r=c.indexOf("=");if(r===-1)continue;let l=c.slice(0,r).trim(),a=c.slice(r+1).trim();e[l]=M(a)}return e}function C(d){let e=[],t=d.trim().replace(/^\[/,"").replace(/\]$/,""),i="",n=!1,s="",o=0;for(let c=0;c<t.length;c++){let r=t[c];if((r==='"'||r==="'")&&(!n||r===s)&&(n=!n,s=n?r:""),!n&&(r==="{"&&o++,r==="}"&&o--,r===","&&o===0)){i.trim()&&e.push(T(i.trim())),i="";continue}i+=r}return i.trim()&&e.push(T(i.trim())),e}function T(d){return d.startsWith("{")?L(d):M(d)}function y(d){let e={},t=null,i=!1,n=d.split(/\r?\n/);function s(o,c){let r=o;for(let l of c){if(!(l in r))return;r=r[l]}return r}for(let o of n){let c=I(o).trim();if(!c)continue;let r=c.match(/^\[\[([^\]]+)\]\]$/);if(r){t=r[1].trim(),i=!0;let u=t.split("."),f=e;for(let v=0;v<u.length-1;v++){let R=u[v];R in f||(f[R]={}),f=f[R]}let h=u[u.length-1];Array.isArray(f[h])||(f[h]=[]),f[h].push({});continue}let l=c.match(/^\[([^\]]+)\]$/);if(l){t=l[1].trim(),i=!1;continue}let a=c.indexOf("=");if(a===-1||!t)continue;let p=c.slice(0,a).trim(),m=c.slice(a+1).trim(),g;if(m.startsWith("{")?g=L(m):m.startsWith("[")?g=C(m):g=M(m),i){let u=t.split("."),f=s(e,u);if(Array.isArray(f)&&f.length>0){let h=f[f.length-1];h[p]=g}}else{let u=t.split("."),f=e;for(let v of u)v in f||(f[v]={}),f=f[v];let h=t==="package"?p.replace(/-/g,"_"):p;f[h]=g}}return e}var b=class{constructor(e){this.packageTable=new Map;this.graph=new Map;this.alwaysDeps=new Set(["Sui","MoveStdlib"]);this.root=e}addPackage(e){this.packageTable.set(e.id.name,e),this.graph.has(e.id.name)||this.graph.set(e.id.name,new Set)}addDependency(e,t,i){this.graph.has(e)||this.graph.set(e,new Set),this.graph.get(e).add(t)}getPackage(e){return this.packageTable.get(e)}getAllPackages(){return Array.from(this.packageTable.values())}getImmediateDependencies(e){return this.graph.get(e)||new Set}getTransitiveDependencies(e){let t=new Set,i=new Set,n=s=>{if(i.has(s))return;i.add(s),t.add(s);let o=this.graph.get(s);if(o)for(let c of o)n(c)};return n(e),t.delete(e),t}topologicalOrder(){let e=new Set,t=[],i=n=>{if(e.has(n))return;e.add(n);let s=this.graph.get(n);if(s)for(let o of s)i(o);t.push(n)};i(this.root);for(let n of this.packageTable.keys())i(n);return t}detectCycle(){let e=new Set,t=new Set,i=new Map,n=s=>{e.add(s),t.add(s);let o=this.graph.get(s);if(o)for(let c of o)if(e.has(c)){if(t.has(c)){let r=[c],l=s;for(;l!==c;)r.unshift(l),l=i.get(l);return r.unshift(c),r}}else{i.set(c,s);let r=n(c);if(r)return r}return t.delete(s),null};for(let s of this.packageTable.keys())if(!e.has(s)){let o=n(s);if(o)return o}return null}getRootPackage(){return this.packageTable.get(this.root)}getRootName(){return this.root}isAlwaysDep(e){return this.alwaysDeps.has(e)}};var P=class{constructor(e,t={}){this.unifiedAddressTable=new Map;this.packageResolvedTables=new Map;this.graph=e,this.buildConfig=t}async resolve(){let e=this.graph.topologicalOrder();for(let t of e){let i=this.graph.getPackage(t);if(i)for(let[n,s]of Object.entries(i.manifest.addresses)){let o=this.normalizeAddress(s);this.unifiedAddressTable.has(n)&&this.unifiedAddressTable.get(n)!==o||this.unifiedAddressTable.set(n,o)}}for(let t of this.graph.getAllPackages()){let i={};for(let[n,s]of this.unifiedAddressTable.entries())i[n]=s;this.packageResolvedTables.set(t.id.name,i),t.resolvedTable=i}}normalizeAddress(e){if(!e)return e;let t=e.trim();return t.startsWith("0x")&&(t=t.slice(2)),/^[0-9a-fA-F]+$/.test(t)?"0x"+t.padStart(64,"0"):e}getUnifiedAddressTable(){let e={};for(let[t,i]of this.unifiedAddressTable.entries())e[t]=i;return e}getPackageResolvedTable(e){return this.packageResolvedTables.get(e)}getGraph(){return this.graph}topologicalOrder(){return this.graph.topologicalOrder()}getRootName(){return this.graph.getRootName()}getPackage(e){return this.graph.getPackage(e)}getImmediateDependencies(e){return this.graph.getImmediateDependencies(e)}};var S=class{constructor(e){this.dependencies=[];this.resolvedGraph=e,this.rootPackageName=e.getRootName()}async compute(e){if(!this.resolvedGraph.getPackage(this.rootPackageName))throw new Error(`Root package '${this.rootPackageName}' not found`);let i=this.resolvedGraph.getImmediateDependencies(this.rootPackageName),n=this.resolvedGraph.topologicalOrder();for(let s of n){if(s===this.rootPackageName)continue;let o=this.resolvedGraph.getPackage(s);if(!o)continue;let c=e.get(s)||{},r=this.extractSourcePaths(s,c),l=o.manifest.edition||"legacy",a={name:s,isImmediate:i.has(s),sourcePaths:r,addressMapping:o.resolvedTable||{},compilerConfig:{edition:l,flavor:"sui"},moduleFormat:r.length>0?"Source":"Bytecode",edition:l};this.dependencies.push(a)}}extractSourcePaths(e,t){let i=[];for(let n of Object.keys(t))n.endsWith("Move.toml")||n.endsWith("Move.lock")||n.endsWith(".move")&&i.push(n);return i}toPackageGroupedFormat(e){let t=[];for(let i of this.dependencies){let n=e.get(i.name)||{},s={};for(let[o,c]of Object.entries(n)){if(o.endsWith("Move.lock"))continue;let r=`dependencies/${i.name}/${o}`;if(o.endsWith("Move.toml")){let l=this.reconstructDependencyMoveToml(i.name,c,i.edition,i.addressMapping);s[r]=l}else s[r]=c}t.push({name:i.name,files:s,edition:i.edition})}return t}reconstructDependencyMoveToml(e,t,i,n){let s=t.split(`
2
+ `),o=[],c=[],r=!1,l=!1;for(let g of s){let u=g.trim();if(u.startsWith("[package]")){r=!0,l=!1;continue}if(u.startsWith("[dependencies]")){r=!1,l=!0;continue}if(u.startsWith("[")){r=!1,l=!1;continue}r&&u&&o.push(g),l&&u&&c.push(g)}let a=`[package]
3
+ `,p=!1,m=!1;for(let g of o)if(g.includes("name ="))a+=g+`
4
+ `,p=!0;else if(g.includes("version ="))a+=g+`
5
+ `,m=!0;else{if(g.includes("edition ="))continue;a+=g+`
6
+ `}p||(a+=`name = "${e}"
7
+ `),m||(a+=`version = "0.0.0"
8
+ `),a+=`edition = "${i}"
9
+ `,a+=`
10
+ [dependencies]
11
+ `;for(let g of c)a+=g+`
12
+ `;a+=`
13
+ [addresses]
14
+ `;for(let[g,u]of Object.entries(n))a+=`${g} = "${u}"
15
+ `;return a}getUnifiedAddressTable(){return this.resolvedGraph.getUnifiedAddressTable()}};var x=class{constructor(e,t="mainnet"){this.visited=new Set;this.packageNameCache=new Map;this.packageFiles=new Map;this.fetcher=e,this.network=t}async resolve(e,t){let i=y(e),n=i.package?.name||"RootPackage",s=i.package?.edition;if(t["Move.lock"]){let h=y(t["Move.lock"]);h.move?.["toolchain-version"]?.edition&&(s=h.move["toolchain-version"].edition)}let o=s||"2024.beta",c=new b(n),r=await this.buildPackage(n,null,e,t);s&&(r.manifest.edition=s),c.addPackage(r),this.packageFiles.set(n,t),await this.loadFromLockfile(c,r,t)||await this.buildDependencyGraph(c,r);let a=c.detectCycle();if(a)throw new Error(`Dependency cycle detected: ${a.join(" \u2192 ")}`);let p=new P(c,{});await p.resolve();let m=new S(p);await m.compute(this.packageFiles);let g=this.reconstructMoveToml(i,p.getUnifiedAddressTable(),!0,o),u={...t};delete u["Move.lock"],u["Move.toml"]=g;let f=m.toPackageGroupedFormat(this.packageFiles);return{files:JSON.stringify(u),dependencies:JSON.stringify(f)}}async buildPackage(e,t,i,n){let s=y(i),o={name:s.package?.name||e,version:s.package?.version||"0.0.0",edition:s.package?.edition,publishedAt:s.package?.published_at,addresses:s.addresses||{},dependencies:s.dependencies||{},devDependencies:s["dev-dependencies"]},c=new Map;if(o.dependencies)for(let[l,a]of Object.entries(o.dependencies)){let p=this.parseDependencyInfo(a);p&&c.set(l,p)}return{id:{name:o.name,version:o.version,source:t||{type:"local"}},manifest:o,dependencies:c,devDependencies:new Map}}parseDependencyInfo(e){return e?e.git&&e.rev?{source:{type:"git",git:e.git,rev:e.rev,subdir:e.subdir}}:e.local?{source:{type:"local",local:e.local}}:null:null}async buildDependencyGraph(e,t){for(let[i,n]of t.dependencies.entries()){if(n.source.type==="local")if(t.id.source.type==="git"&&n.source.local){let g=t.id.source.subdir||"",u=n.source.local,f=this.resolveRelativePath(g,u);n.source={type:"git",git:t.id.source.git,rev:t.id.source.rev,subdir:f}}else continue;if(n.source.type!=="git")continue;let s=`${n.source.git}|${n.source.rev}|${n.source.subdir||""}`;if(this.visited.has(s)){let g=this.findPackageBySource(e,n.source);g&&e.addDependency(t.id.name,g.id.name,n);continue}this.visited.add(s);let o=n.source.subdir;!o&&n.source.git&&this.isSuiRepo(n.source.git)&&(o=this.inferSuiFrameworkSubdir(i),o&&(n.source.subdir=o));let c=await this.fetcher.fetch(n.source.git,n.source.rev,o),r=null,l=`Move.${this.network}.toml`;for(let[g,u]of Object.entries(c))if(g.endsWith(l)){r=u;break}if(!r){for(let[g,u]of Object.entries(c))if(g.endsWith("Move.toml")){r=u;break}}if(!r)continue;let a=await this.buildPackage(i,n.source,r,c),p=this.packageNameCache.get(a.manifest.name);if(p){let g=this.findPackageBySource(e,p);g&&e.addDependency(t.id.name,g.id.name,n);continue}this.packageNameCache.set(a.manifest.name,n.source);let m=c["Move.lock"];if(m){let g=y(m);if(g.env?.[this.network]){let u=g.env[this.network]["latest-published-id"]||g.env[this.network]["original-published-id"];u&&(a.manifest.publishedAt=u,a.manifest.addresses[a.manifest.name]=this.normalizeAddress(u))}a.manifest.edition||(a.manifest.edition="legacy")}if(!a.manifest.publishedAt){let g={Sui:"0x2",MoveStdlib:"0x1",SuiSystem:"0x3",Bridge:"0xb"};g[i]&&(a.manifest.publishedAt=g[i])}e.addPackage(a),e.addDependency(t.id.name,a.id.name,n),this.packageFiles.set(a.id.name,c),await this.buildDependencyGraph(e,a)}}findPackageBySource(e,t){for(let i of e.getAllPackages()){let n=i.id.source;if(n.type===t.type&&n.git===t.git&&n.rev===t.rev&&n.subdir===t.subdir)return i}}resolveRelativePath(e,t){let i=e?e.split("/").filter(Boolean):[],n=t.split("/").filter(Boolean),s=[...i];for(let o of n)o===".."?s.length>0&&s.pop():o!=="."&&s.push(o);return s.join("/")}async computeManifestDigest(e){let i=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(n)).map(c=>c.toString(16).padStart(2,"0")).join("").toUpperCase()}async loadFromLockfile(e,t,i){let n=i["Move.lock"];if(!n)return!1;let s=y(n),o=s.pinned?.[this.network];if(!o)return!1;let c=i["Move.toml"];if(c&&s.move?.manifest_digest&&await this.computeManifestDigest(c)!==s.move.manifest_digest)return!1;let r=new Map;for(let[l,a]of Object.entries(o)){let p=this.lockfileSourceToDependencySource(a.source);if(!p)continue;let m=await this.fetchFromSource(p);if(!m)return!1;let g=m["Move.toml"];if(!g||a["manifest-digest"]&&await this.computeManifestDigest(g)!==a["manifest-digest"])return!1;let u=await this.buildPackage(l,p,g,m);r.set(l,u),this.packageFiles.set(u.manifest.name,m),(p.type!=="local"||!("root"in a.source))&&e.addPackage(u)}for(let[l,a]of Object.entries(o)){let p=r.get(l);if(p&&a.deps)for(let[m,g]of Object.entries(a.deps)){let u=r.get(g);if(u){let f=p.dependencies.get(m);f&&e.addDependency(p.id.name,u.id.name,f)}}}return!0}lockfileSourceToDependencySource(e){return"git"in e?{type:"git",git:e.git,rev:e.rev,subdir:e.subdir}:"local"in e?{type:"local",local:e.local}:"root"in e?{type:"local"}:null}async fetchFromSource(e){if(e.type==="git"&&e.git&&e.rev)try{return await this.fetcher.fetch(e.git,e.rev,e.subdir)}catch{return null}return null}reconstructMoveToml(e,t,i,n){let o=`[package]
2
16
  name = "${e.package.name}"
3
17
  version = "${e.package.version}"
4
- `;if(e.package.edition&&(s+=`edition = "${e.package.edition}"
5
- `),s+=`
18
+ `,c=n||e.package.edition;if(c&&(o+=`edition = "${c}"
19
+ `),o+=`
6
20
  [dependencies]
7
- `,e.dependencies)for(let[i,o]of Object.entries(e.dependencies))s+=`${i} = { git = "${o.git}", rev = "${o.rev}" }
8
- `;s+=`
21
+ `,e.dependencies)for(let[r,l]of Object.entries(e.dependencies)){let a=l;a.local?o+=`${r} = { local = "${a.local}" }
22
+ `:a.git&&a.rev&&(a.subdir?o+=`${r} = { git = "${a.git}", subdir = "${a.subdir}", rev = "${a.rev}" }
23
+ `:o+=`${r} = { git = "${a.git}", rev = "${a.rev}" }
24
+ `)}o+=`
9
25
  [addresses]
10
- `;for(let[i,o]of Object.entries(t))s+=`${i} = "${o}"
11
- `;return s}async injectSystemDeps(e){if(e){for(let s of Object.values(e))if(!(!s||!s.git||!s.rev)&&this.isSuiRepo(s.git)){await this.addImplicitSystemDepsForRepo(s.git,s.rev);break}}this.dependencyFiles["dependencies/MoveStdlib/Move.toml"]||this.addFallbackSystemDeps()}async addImplicitSystemDepsForRepo(e,t){if(!this.isSuiRepo(e))return;let s=`${e}|${t}`;if(this.systemDepsLoaded.has(s))return;this.systemDepsLoaded.add(s);let i="crates/sui-framework-snapshot/manifest.json";if(!this.fetcher.fetchFile)return;let o=null;try{let c=await this.fetcher.fetchFile(e,t,i);if(c){let l=JSON.parse(c),r=Object.keys(l).map(u=>Number(u)).filter(u=>!Number.isNaN(u)).sort((u,f)=>u-f),a=r[r.length-1],d=l[String(a)];d&&d.packages&&(o=d.packages)}}catch{}o||(o=this.fallbackSystemPackages());for(let c of o)!c||!c.name||!c.id||c.name!=="DeepBook"&&this.addSystemDep(c.name,c.id)}addFallbackSystemDeps(){for(let e of this.fallbackSystemPackages())!e||!e.name||!e.id||e.name!=="DeepBook"&&this.addSystemDep(e.name,e.id)}addSystemDep(e,t){let s=`dependencies/${e}/Move.toml`;if(this.dependencyFiles[s])return;let i=["[package]",`name = "${e}"`,'version = "0.0.0"',`published-at = "${this.normalizeAddress(t)}"`,""].join(`
12
- `);this.dependencyFiles[s]=i}fallbackSystemPackages(){return[{name:"MoveStdlib",id:"0x1"},{name:"Sui",id:"0x2"},{name:"SuiSystem",id:"0x3"},{name:"Bridge",id:"0xb"}]}isSuiRepo(e){return e.includes("github.com/MystenLabs/sui")}};async function S(n,e,t){return new v(t).resolve(n,e)}var I=(()=>{try{return new URL("./sui_move_wasm_bg.wasm",import.meta.url)}catch{return"./sui_move_wasm_bg.wasm"}})(),k;async function p(n){return k||(k=import("./sui_move_wasm.js").then(async e=>(n?await e.default({module_or_path:n}):await e.default(),e))),k}function w(n){return JSON.stringify(n??{})}function R(n){return{success:!1,error:n instanceof Error?n.message:typeof n=="string"?n:"Unknown error"}}function F(n){if(typeof n!="object"||n===null)throw new Error("Unexpected compile result shape from wasm");let e=n;if(typeof e.success=="function"&&typeof e.output=="function")return e;if(typeof e.success=="boolean"&&typeof e.output=="string")return{success:()=>e.success,output:()=>e.output};throw new Error("Unexpected compile result shape from wasm")}function j(n){let e=t=>t.map(s=>s.toString(16).padStart(2,"0")).join("");try{let t=JSON.parse(n);if(!t.modules||!t.dependencies||!t.digest)throw new Error("missing fields in compiler output");let s=typeof t.digest=="string"?t.digest:e(t.digest);return{success:!0,modules:t.modules,dependencies:t.dependencies,digest:s}}catch(t){return R(t)}}function _(n){if(!n)return n;let e=n;return e.startsWith("0x")&&(e=e.slice(2)),/^[0-9a-fA-F]+$/.test(e)?"0x"+e.padStart(64,"0"):n}function L(n){let e={std:"0x1",sui:"0x2",sui_system:"0x3",bridge:"0xb"},t=n.split(/\r?\n/),s=/^\s*\[[^\]]+\]\s*$/,i=-1,o=t.length;for(let r=0;r<t.length;r++)if(/^\s*\[addresses\]\s*$/.test(t[r])){i=r;for(let a=r+1;a<t.length;a++)if(s.test(t[a])){o=a;break}break}let c=new Set;if(i>=0)for(let r=i+1;r<o;r++){let a=t[r].trim();if(!a||a.startsWith("#"))continue;let d=a.match(/^([A-Za-z0-9_.-]+)\s*=/);d&&c.add(d[1])}let l=Object.entries(e).filter(([r])=>!c.has(r)).map(([r,a])=>`${r} = "${_(a)}"`);return l.length===0?n:(i>=0?t.splice(o,0,...l):t.push("","[addresses]",...l),t.join(`
13
- `))}function W(n){let e=[{name:"Sui",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/sui-framework",rev:"framework/mainnet"},{name:"MoveStdlib",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/move-stdlib",rev:"framework/mainnet"}],t=n.split(/\r?\n/),s=/^\s*\[[^\]]+\]\s*$/,i=-1,o=t.length;for(let r=0;r<t.length;r++)if(/^\s*\[dependencies\]\s*$/.test(t[r])){i=r;for(let a=r+1;a<t.length;a++)if(s.test(t[a])){o=a;break}break}let c=new Set;if(i>=0)for(let r=i+1;r<o;r++){let a=t[r].trim();if(!a||a.startsWith("#"))continue;let d=a.match(/^([A-Za-z0-9_.-]+)\s*=/);d&&c.add(d[1])}let l=e.filter(r=>!c.has(r.name)).map(r=>`${r.name} = { git = "${r.git}", subdir = "${r.subdir}", rev = "${r.rev}" }`);return l.length===0?n:(i>=0?t.splice(o,0,...l):t.push("","[dependencies]",...l),t.join(`
14
- `))}function U(n){let e={...n??{}};if(e["dependencies/MoveStdlib/Move.toml"])return e;let t=[{name:"MoveStdlib",id:"0x1"},{name:"Sui",id:"0x2"},{name:"SuiSystem",id:"0x3"},{name:"Bridge",id:"0xb"}];for(let s of t){let i=`dependencies/${s.name}/Move.toml`;e[i]||(e[i]=["[package]",`name = "${s.name}"`,'version = "0.0.0"',`published-at = "${_(s.id)}"`,""].join(`
15
- `))}return e}function x(n){return!!(n?.["dependencies/MoveStdlib/Move.toml"]&&n?.["dependencies/Sui/Move.toml"])}function M(n){return typeof n=="string"?JSON.parse(n):n}async function C(n){await p(n?.wasm)}async function z(n){try{let e=n.dependencies??{},t={...n.files},s=typeof t["Move.toml"]=="string";if(n.autoSystemDeps&&s){let a=L(t["Move.toml"]);x(e)||(a=W(a)),t["Move.toml"]=a}if(n.autoSystemDeps&&!x(e)&&s){let a=await S(t["Move.toml"],t,new m);t=M(a.files),e=M(a.dependencies)}else n.autoSystemDeps&&(e=U(e));let i=await p(n.wasm),o=n.ansiColor&&typeof i.compile_with_color=="function"?i.compile_with_color(w(t),w(e),!0):i.compile(w(t),w(e)),c=F(o),l=c.success(),r=c.output();return l?j(r):R(r)}catch(e){return R(e)}}async function H(n){return(await p(n?.wasm)).sui_move_version()}async function G(n){return(await p(n?.wasm)).sui_version()}async function J(n){return p(n?.wasm)}async function q(n,e,t){let s=await p(t?.wasm),i=t?.ansiColor&&typeof s.compile_with_color=="function"?s.compile_with_color(n,e,!0):s.compile(n,e),o=F(i);return{success:o.success(),output:o.output()}}export{g as Fetcher,m as GitHubFetcher,v as Resolver,z as buildMovePackage,q as compileRaw,H as getSuiMoveVersion,G as getSuiVersion,J as getWasmBindings,C as initMoveCompiler,y as parseToml,S as resolve};
26
+ `;for(let[r,l]of Object.entries(t))o+=`${r} = "${l}"
27
+ `;return o}normalizeAddress(e){if(!e)return e;let t=e.trim();return t.startsWith("0x")&&(t=t.slice(2)),/^[0-9a-fA-F]+$/.test(t)?"0x"+t.padStart(64,"0"):e}isSuiRepo(e){return e.includes("github.com/MystenLabs/sui")}inferSuiFrameworkSubdir(e){let t={Sui:"crates/sui-framework/packages/sui-framework",MoveStdlib:"crates/sui-framework/packages/move-stdlib",SuiSystem:"crates/sui-framework/packages/sui-system",Bridge:"crates/sui-framework/packages/bridge",DeepBook:"crates/sui-framework/packages/deepbook",SuiFramework:"crates/sui-framework/packages/sui-framework"};return t[e]||t[e.toLowerCase()]}};async function F(d,e,t,i="mainnet"){return new x(t,i).resolve(d,e)}function N(d){try{let e=new URL(d);if(e.hostname!=="github.com")return null;let t=e.pathname.split("/").filter(Boolean);if(t.length<2)return null;let i=t[0],n=t[1],s="main",o;return t.length>=4&&t[2]==="tree"&&(s=t[3],t.length>4&&(o=t.slice(4).join("/"))),{owner:i,repo:n,ref:s,subdir:o}}catch{return null}}async function _(d,e){let t=N(d);if(!t)throw new Error(`Invalid GitHub URL: ${d}`);let i=e?.fetcher||new k,n=e?.includeLock!==!1,s=`https://github.com/${t.owner}/${t.repo}.git`,o=await i.fetch(s,t.ref,t.subdir);if(!n&&o["Move.lock"]){let{"Move.lock":c,...r}=o;return r}return o}var $;async function w(d){return $||($=import("./sui_move_wasm.js").then(async e=>(d?await e.default({module_or_path:d}):await e.default(),e))),$}function A(d){return{success:!1,error:d instanceof Error?d.message:typeof d=="string"?d:"Unknown error"}}function G(d){if(typeof d!="object"||d===null)throw new Error("Unexpected compile result shape from wasm");let e=d;if(typeof e.success=="function"&&typeof e.output=="function")return e;if(typeof e.success=="boolean"&&typeof e.output=="string")return{success:()=>e.success,output:()=>e.output};throw new Error("Unexpected compile result shape from wasm")}function U(d){let e=t=>t.map(i=>i.toString(16).padStart(2,"0")).join("");try{let t=JSON.parse(d);if(!t.modules||!t.dependencies||!t.digest)throw new Error("missing fields in compiler output");let i=typeof t.digest=="string"?t.digest:e(t.digest);return{success:!0,modules:t.modules,dependencies:t.dependencies,digest:i}}catch(t){return A(t)}}function B(d){let e=[{name:"Sui",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/sui-framework",rev:"framework/mainnet"},{name:"MoveStdlib",git:"https://github.com/MystenLabs/sui.git",subdir:"crates/sui-framework/packages/move-stdlib",rev:"framework/mainnet"}],t=d.split(/\r?\n/),i=/^\s*\[[^\]]+\]\s*$/,n=-1,s=t.length;for(let r=0;r<t.length;r++)if(/^\s*\[dependencies\]\s*$/.test(t[r])){n=r;for(let l=r+1;l<t.length;l++)if(i.test(t[l])){s=l;break}break}let o=new Set;if(n>=0)for(let r=n+1;r<s;r++){let l=t[r].trim();if(!l||l.startsWith("#"))continue;let a=l.match(/^([A-Za-z0-9_.-]+)\s*=/);a&&o.add(a[1])}let c=e.filter(r=>!o.has(r.name)).map(r=>`${r.name} = { git = "${r.git}", subdir = "${r.subdir}", rev = "${r.rev}" }`);return c.length===0?d:(n>=0?t.splice(s,0,...c):t.push("","[dependencies]",...c),t.join(`
28
+ `))}async function ce(d){await w(d?.wasm)}async function O(d){let e=d.files["Move.toml"]||"";e&&(e=B(e));let t=await F(e,{...d.files,"Move.toml":e},new k,d.network);return{files:t.files,dependencies:t.dependencies}}async function de(d){try{let e=d.resolvedDependencies?d.resolvedDependencies:await O(d),t=await w(d.wasm),i=d.ansiColor&&typeof t.compile_with_color=="function"?t.compile_with_color(e.files,e.dependencies,!0):t.compile(e.files,e.dependencies),n=G(i),s=n.success(),o=n.output();return s?U(o):A(o)}catch(e){return A(e)}}async function le(d){return(await w(d?.wasm)).sui_move_version()}async function ge(d){return(await w(d?.wasm)).sui_version()}async function ue(d){return w(d?.wasm)}async function pe(d,e,t){let i=await w(t?.wasm),n=t?.ansiColor&&typeof i.compile_with_color=="function"?i.compile_with_color(d,e,!0):i.compile(d,e),s=G(n);return{success:s.success(),output:s.output()}}export{de as buildMovePackage,pe as compileRaw,_ as fetchPackageFromGitHub,le as getSuiMoveVersion,ge as getSuiVersion,ue as getWasmBindings,ce as initMoveCompiler,O as resolveDependencies};
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zktx.io/sui-move-builder",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Build Move packages in web or Node.js with dependency fetching and dump outputs.",
5
5
  "keywords": [
6
6
  "sui",