@latticexyz/cli 2.0.0-main-e667ee80 → 2.0.0-main-61c6ab70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mud.js +11 -11
- package/dist/mud.js.map +1 -1
- package/package.json +13 -12
- package/src/deploy/common.ts +8 -8
- package/src/deploy/deploy.ts +26 -2
- package/src/deploy/ensureContract.ts +18 -5
- package/src/deploy/ensureFunctions.ts +40 -16
- package/src/deploy/ensureModules.ts +41 -27
- package/src/deploy/ensureSystems.ts +60 -37
- package/src/deploy/ensureTables.ts +28 -15
- package/src/runDeploy.ts +1 -1
package/dist/mud.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
gracefully shutting down from SIGINT (Crtl-C)`),r.kill(),process.exit()}),await r}},
|
|
2
|
+
import Fn from"yargs";import{hideBin as Rn}from"yargs/helpers";import Wn from"@latticexyz/gas-report";import jn from"@latticexyz/abi-ts";import{rmSync as So}from"fs";import{homedir as vo}from"os";import Co from"path";import{execa as To}from"execa";var ko={command:"devnode",describe:"Start a local Ethereum node for development",builder(e){return e.options({blocktime:{type:"number",default:1,decs:"Interval in which new blocks are produced"}})},async handler({blocktime:e}){console.log("Clearing devnode history");let o=vo();So(Co.join(o,".foundry","anvil","tmp"),{recursive:!0,force:!0});let t=["-b",String(e),"--block-base-fee-per-gas","0"];console.log(`Running: anvil ${t.join(" ")}`);let r=To("anvil",t,{stdio:["inherit","inherit","inherit"]});process.on("SIGINT",()=>{console.log(`
|
|
3
|
+
gracefully shutting down from SIGINT (Crtl-C)`),r.kill(),process.exit()}),await r}},ne=ko;import{FaucetServiceDefinition as Do}from"@latticexyz/services/faucet";import{createChannel as Ao,createClient as Io}from"nice-grpc-web";import se from"chalk";import{NodeHttpTransport as Oo}from"@improbable-eng/grpc-web-node-http-transport";function Po(e){return Io(Do,Ao(e,Oo()))}var Mo={command:"faucet",describe:"Interact with a MUD faucet",builder(e){return e.options({dripDev:{type:"boolean",desc:"Request a drip from the dev endpoint (requires faucet to have dev mode enabled)",default:!0},faucetUrl:{type:"string",desc:"URL of the MUD faucet",default:"https://faucet.testnet-mud-services.linfra.xyz"},address:{type:"string",desc:"Ethereum address to fund",required:!0}})},async handler({dripDev:e,faucetUrl:o,address:t}){let r=Po(o);e&&(console.log(se.yellow("Dripping to",t)),await r.dripDev({address:t}),console.log(se.yellow("Success"))),process.exit(0)}},ie=Mo;var Wo={command:"hello <name>",describe:"Greet <name> with Hello",builder(e){return e.options({upper:{type:"boolean"}}).positional("name",{type:"string",demandOption:!0})},handler({name:e}){let o=`Gm, ${e}!`;console.log(o),process.exit(0)}},ae=Wo;import jo from"path";import{loadConfig as Fo}from"@latticexyz/config/node";import{tablegen as Ro}from"@latticexyz/store/codegen";import{getRemappings as $o,getSrcDirectory as Eo}from"@latticexyz/common/foundry";var No={command:"tablegen",describe:"Autogenerate MUD Store table libraries based on the config file",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"}})},async handler({configPath:e}){let o=await Fo(e),t=await Eo(),r=await $o();await Ro(o,jo.join(t,o.codegenDirectory),r),process.exit(0)}},ce=No;import N from"chalk";import{ZodError as Ho}from"zod";import{fromZodError as Bo,ValidationError as Uo}from"zod-validation-error";import{NotInsideProjectError as Vo}from"@latticexyz/config";import{MUDError as _o}from"@latticexyz/common/errors";function M(e){if(e instanceof Uo)console.log(N.redBright(e.message));else if(e instanceof Ho){let o=Bo(e,{prefixSeparator:`
|
|
4
4
|
- `,issueSeparator:`
|
|
5
|
-
- `});console.log(H.redBright(o.message))}else e instanceof Eo?(console.log(H.red(e.message)),console.log(""),console.log(H.blue("To learn more about MUD's configuration, please go to https://mud.dev/packages/cli/"))):e instanceof Fo?console.log(H.red(e)):console.log(e)}import J from"node:path";import{existsSync as cr,mkdirSync as lr,readFileSync as dr,writeFileSync as Z}from"node:fs";import{getBytecode as Ho,sendRawTransaction as Bo,sendTransaction as No,waitForTransactionReceipt as ce}from"viem/actions";var O={gasPrice:1e11,gasLimit:1e5,signerAddress:"3fab184622dc19b6109349b94811493bf2a45362",transaction:"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",address:"4e59b44847b379578588920ca78fbf26c0b4956c"};import $o from"debug";var ae=$o("mud:cli");var d=ae.extend("deploy");var C=`0x${O.address}`;async function le(e){if(await Ho(e,{address:C})){d("found create2 deployer at",C);return}d("sending gas for create2 deployer to signer at",O.signerAddress);let t=await No(e,{chain:e.chain??null,to:`0x${O.signerAddress}`,value:BigInt(O.gasLimit)*BigInt(O.gasPrice)}),r=await ce(e,{hash:t});if(r.status!=="success")throw console.error("failed to send gas to deployer signer",r),new Error("failed to send gas to deployer signer");d("deploying create2 deployer at",C);let n=await Bo(e,{serializedTransaction:`0x${O.transaction}`}),s=await ce(e,{hash:n});if(s.contractAddress!==C)throw console.error("unexpected contract address for deployer",s),new Error("unexpected contract address for deployer")}import{waitForTransactionReceipt as it}from"viem/actions";import Qo from"@latticexyz/world/out/CoreModule.sol/CoreModule.json"assert{type:"json"};import Xo from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.json"assert{type:"json"};import{parseAbi as et,getCreate2Address as fe,encodeDeployData as ue}from"viem";import{concatHex as qo,getCreate2Address as Go}from"viem";import{getBytecode as Yo}from"viem/actions";import{padHex as Vo}from"viem";import _o from"@latticexyz/store/mud.config.js";import Lo from"@latticexyz/world/mud.config.js";import Ko from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import{resourceToHex as Uo}from"@latticexyz/common";import{resolveUserTypes as de}from"@latticexyz/store";function B(e){let o={...e.userTypes,...Object.fromEntries(Object.entries(e.enums).map(([t])=>[t,{internalType:"uint8"}]))};return Object.fromEntries(Object.entries(e.tables).map(([t,r])=>[`${e.namespace}_${t}`,{namespace:e.namespace,name:r.name,tableId:Uo({type:r.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:r.name}),keySchema:de(r.keySchema,o),valueSchema:de(r.valueSchema,o)}]))}import{helloStoreEvent as zo}from"@latticexyz/store";import{helloWorldEvent as Jo}from"@latticexyz/world";var D=Vo("0x",{size:32}),j=B(_o),k=B(Lo),U=[zo,Jo],S=Ko,me=["1.0.0-unaudited"],pe=["1.0.0-unaudited"];import{sendTransaction as Zo}from"@latticexyz/common";async function P({client:e,bytecode:o,label:t="contract"}){let r=Go({from:C,salt:D,bytecode:o});return await Yo(e,{address:r,blockTag:"pending"})?(d("found",t,"at",r),[]):(d("deploying",t,"at",r),[await Zo(e,{chain:e.chain??null,to:C,data:qo([D,o])})])}var ye=ue({bytecode:Qo.bytecode.object,abi:[]}),ot=fe({from:C,bytecode:ye,salt:D}),ge=ue({bytecode:Xo.bytecode.object,abi:et(["constructor(address)"]),args:[ot]}),be=fe({from:C,bytecode:ge,salt:D});async function he(e){return(await Promise.all([P({client:e,bytecode:ye,label:"core module"}),P({client:e,bytecode:ge,label:"world factory"})])).flat()}import at from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{writeContract as ct}from"@latticexyz/common";import{AbiEventSignatureNotFoundError as tt,decodeEventLog as rt,hexToString as we,parseAbi as nt,trim as xe}from"viem";import{isDefined as st}from"@latticexyz/common/utils";function V(e){let o=e.map(c=>{try{return{...c,...rt({strict:!0,abi:nt(U),topics:c.topics,data:c.data})}}catch(i){if(i instanceof tt)return;throw i}}).filter(st),{address:t,deployBlock:r,worldVersion:n,storeVersion:s}=o.reduce((c,i)=>({...c,address:i.address,deployBlock:i.blockNumber,...i.eventName==="HelloWorld"?{worldVersion:we(xe(i.args.worldVersion,{dir:"right"}))}:null,...i.eventName==="HelloStore"?{storeVersion:we(xe(i.args.storeVersion,{dir:"right"}))}:null}),{});if(t==null)throw new Error("could not find world address");if(r==null)throw new Error("could not find world deploy block number");if(n==null)throw new Error("could not find world version");if(s==null)throw new Error("could not find store version");return{address:t,deployBlock:r,worldVersion:n,storeVersion:s}}async function Se(e){await he(e),d("deploying world");let o=await ct(e,{chain:e.chain??null,address:be,abi:at,functionName:"deployWorld"});d("waiting for world deploy");let t=await it(e,{hash:o});if(t.status!=="success")throw console.error("world deploy failed",t),new Error("world deploy failed");let r=V(t.logs.map(n=>n));return d("deployed world to",r.address,"at block",r.deployBlock),{...r,stateBlock:r.deployBlock}}import{writeContract as yt}from"@latticexyz/common";import{valueSchemaToFieldLayoutHex as gt,keySchemaToHex as bt,valueSchemaToHex as ht}from"@latticexyz/protocol-parser";function T({namespace:e,name:o}){return`${e}:${o}`}import{parseAbiItem as lt,decodeAbiParameters as ve,parseAbiParameters as Ce}from"viem";import{hexToResource as dt}from"@latticexyz/common";import{storeSetRecordEvent as mt}from"@latticexyz/store";import{getLogs as pt}from"viem/actions";import{decodeKey as ft,decodeValueArgs as ut,hexToSchema as Te}from"@latticexyz/protocol-parser";async function ke({client:e,worldDeploy:o}){d("looking up tables for",o.address);let r=(await pt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:lt(mt),args:{tableId:j.store_Tables.tableId}})).map(n=>{let{tableId:s}=ft(j.store_Tables.keySchema,n.args.keyTuple),{namespace:c,name:i}=dt(s),p=ut(j.store_Tables.valueSchema,n.args),a=Te(p.keySchema),f=Te(p.valueSchema),u=ve(Ce("string[]"),p.abiEncodedKeyNames)[0],v=ve(Ce("string[]"),p.abiEncodedFieldNames)[0],m=[...f.staticFields,...f.dynamicFields],y=Object.fromEntries(a.staticFields.map((g,b)=>[u[b],g])),h=Object.fromEntries(m.map((g,b)=>[v[b],g]));return{namespace:c,name:i,tableId:s,keySchema:y,valueSchema:h}});return d("found",r.length,"tables for",o.address),r}async function De({client:e,worldDeploy:o,tables:t}){let n=(await ke({client:e,worldDeploy:o})).map(i=>i.tableId),s=t.filter(i=>n.includes(i.tableId));s.length&&d("existing tables",s.map(T).join(", "));let c=t.filter(i=>!n.includes(i.tableId));return c.length?(d("registering tables",c.map(T).join(", ")),await Promise.all(c.map(i=>yt(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerTable",args:[i.tableId,gt(i.valueSchema),bt(i.keySchema),ht(i.valueSchema),Object.keys(i.keySchema),Object.keys(i.valueSchema)]})))):[]}import{getAddress as I}from"viem";import{writeContract as q}from"@latticexyz/common";import{parseAbiItem as wt}from"viem";import{getLogs as xt}from"viem/actions";import{storeSpliceStaticDataEvent as St}from"@latticexyz/store";async function _({client:e,worldDeploy:o}){d("looking up resource IDs for",o.address);let r=(await xt(e,{strict:!0,address:o.address,fromBlock:o.deployBlock,toBlock:o.stateBlock,event:wt(St),args:{tableId:j.store_ResourceIds.tableId}})).map(n=>n.args.keyTuple[0]);return d("found",r.length,"resource IDs for",o.address),r}import{hexToResource as Rt}from"@latticexyz/common";import{decodeValueArgs as vt,encodeKey as Ct}from"@latticexyz/protocol-parser";import{readContract as Tt}from"viem/actions";async function A({client:e,worldDeploy:o,table:t,key:r}){let[n,s,c]=await Tt(e,{blockNumber:o.stateBlock,address:o.address,abi:S,functionName:"getRecord",args:[t.tableId,Ct(t.keySchema,r)]});return vt(t.valueSchema,{staticData:n,encodedLengths:s,dynamicData:c})}import{getFunctionSelector as kt,parseAbiItem as Dt}from"viem";import{storeSetRecordEvent as At}from"@latticexyz/store";import{getLogs as It}from"viem/actions";import{decodeValueArgs as Ot}from"@latticexyz/protocol-parser";import{hexToResource as Pt}from"@latticexyz/common";async function L({client:e,worldDeploy:o}){d("looking up function signatures for",o.address);let r=(await It(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Dt(At),args:{tableId:k.world_FunctionSignatures.tableId}})).map(s=>Ot(k.world_FunctionSignatures.valueSchema,s.args).functionSignature);return d("found",r.length,"function signatures for",o.address),await Promise.all(r.map(async s=>{let c=kt(s),{systemId:i,systemFunctionSelector:p}=await A({client:e,worldDeploy:o,table:k.world_FunctionSelectors,key:{functionSelector:c}}),{namespace:a,name:f}=Pt(i),u=a===""?s:s.replace(`${a}_${f}_`,"");return{signature:s,selector:c,systemId:i,systemFunctionSignature:u,systemFunctionSelector:p}}))}import{parseAbiItem as Mt,getAddress as Wt}from"viem";import{storeSpliceStaticDataEvent as jt}from"@latticexyz/store";import{getLogs as Et}from"viem/actions";import{decodeKey as Ft}from"@latticexyz/protocol-parser";async function K({client:e,worldDeploy:o}){d("looking up resource access for",o.address);let r=(await Et(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Mt(jt),args:{tableId:k.world_ResourceAccess.tableId}})).map(s=>Ft(k.world_ResourceAccess.keySchema,s.args.keyTuple)),n=(await Promise.all(r.map(async s=>[s,await A({client:e,worldDeploy:o,table:k.world_ResourceAccess,key:s})]))).filter(([,s])=>s.access).map(([s])=>({resourceId:s.resourceId,address:Wt(s.caller)}));return d("found",n.length,"resource<>address access pairs"),n}async function Ae({client:e,worldDeploy:o}){let[t,r,n]=await Promise.all([_({client:e,worldDeploy:o}),L({client:e,worldDeploy:o}),K({client:e,worldDeploy:o})]),s=t.map(Rt).filter(c=>c.type==="system");return d("looking up systems",s.map(T).join(", ")),await Promise.all(s.map(async c=>{let{system:i,publicAccess:p}=await A({client:e,worldDeploy:o,table:k.world_Systems,key:{systemId:c.resourceId}}),a=r.filter(f=>f.systemId===c.resourceId);return{address:i,namespace:c.namespace,name:c.name,systemId:c.resourceId,allowAll:p,allowedAddresses:n.filter(({resourceId:f})=>f===c.resourceId).map(({address:f})=>f),functions:a}}))}import{uniqueBy as $t}from"@latticexyz/common/utils";async function Ie({client:e,worldDeploy:o,systems:t}){let[r,n]=await Promise.all([Ae({client:e,worldDeploy:o}),K({client:e,worldDeploy:o})]),s=t.map(l=>l.systemId),c=n.filter(({resourceId:l})=>s.includes(l)),i=t.flatMap(l=>l.allowedAddresses.map(w=>({resourceId:l.systemId,address:w}))),p=i.filter(l=>!c.some(({resourceId:w,address:x})=>w===l.resourceId&&I(x)===I(l.address))),a=c.filter(l=>!i.some(({resourceId:w,address:x})=>w===l.resourceId&&I(x)===I(l.address)));a.length&&d("revoking",a.length,"access grants"),p.length&&d("adding",p.length,"access grants");let f=await Promise.all([...a.map(l=>q(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"revokeAccess",args:[l.resourceId,l.address]})),...p.map(l=>q(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"grantAccess",args:[l.resourceId,l.address]}))]),u=t.filter(l=>r.some(w=>w.systemId===l.systemId&&I(w.address)===I(l.address)));u.length&&d("existing systems",u.map(T).join(", "));let v=u.map(l=>l.systemId),m=t.filter(l=>!v.includes(l.systemId));if(!m.length)return[];let y=m.filter(l=>r.some(w=>w.systemId===l.systemId&&I(w.address)!==I(l.address)));y.length&&d("upgrading systems",y.map(T).join(", "));let h=m.filter(l=>!r.some(w=>w.systemId===l.systemId));h.length&&d("registering new systems",h.map(T).join(", "));let g=await Promise.all($t(m,l=>l.address).map(l=>P({client:e,bytecode:l.bytecode,label:`${T(l)} system`}))),b=await Promise.all(m.map(l=>q(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerSystem",args:[l.systemId,l.address,l.allowAll]})));return(await Promise.all([...f,...g,...b])).flat()}import{waitForTransactionReceipt as Kt}from"viem/actions";import{getAddress as Ht,parseAbi as Bt}from"viem";import{getBlockNumber as Nt,getLogs as Ut}from"viem/actions";var Oe=new Map;async function Pe(e,o){let t=Ht(o),r=Oe.get(t);if(r!=null)return r;d("looking up world deploy for",t);let n=await Nt(e),s=await Ut(e,{strict:!0,address:t,events:Bt(U),fromBlock:"earliest",toBlock:n});return r={...V(s),stateBlock:n},Oe.set(t,r),d("found world deploy for",t,"at block",r.deployBlock),r}import{hexToResource as Vt,writeContract as Me}from"@latticexyz/common";async function We({client:e,worldDeploy:o,functions:t}){let r=await L({client:e,worldDeploy:o}),n=Object.fromEntries(r.map(i=>[i.selector,i])),s=t.filter(i=>n[i.selector]),c=t.filter(i=>!s.includes(i));if(s.length){d("functions already registered:",s.map(p=>p.signature).join(", "));let i=s.filter(p=>p.systemId!==n[p.selector]?.systemId);i.length&&console.warn("found",i.length,"functions already registered but pointing at a different system ID:",i.map(p=>p.signature).join(", "))}return c.length?(d("registering functions:",c.map(i=>i.signature).join(", ")),Promise.all(c.map(i=>{let{namespace:p}=Vt(i.systemId);return p===""?Me(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerRootFunctionSelector",args:[i.systemId,i.systemFunctionSignature,i.systemFunctionSelector]}):Me(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerFunctionSelector",args:[i.systemId,i.systemFunctionSignature]})}))):[]}import{writeContract as je}from"@latticexyz/common";import{uniqueBy as _t}from"@latticexyz/common/utils";async function Ee({client:e,worldDeploy:o,modules:t}){if(!t.length)return[];let r=await Promise.all(_t(t,s=>s.address).map(s=>P({client:e,bytecode:s.bytecode,label:`${s.name} module`})));d("installing modules:",t.map(s=>s.name).join(", "));let n=await Promise.all(t.map(s=>s.installAsRoot?je(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"installRootModule",args:[s.address,s.installData]}):je(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"installModule",args:[s.address,s.installData]})));return(await Promise.all([...r,...n])).flat()}import{getAddress as Fe}from"viem";import{hexToResource as Re,resourceToHex as Lt}from"@latticexyz/common";async function $e({client:e,worldDeploy:o,resourceIds:t}){let r=Array.from(new Set(t.map(a=>Re(a).namespace))),n=await _({client:e,worldDeploy:o}),s=Array.from(new Set(n.map(a=>Re(a).namespace))),c=r.filter(a=>s.includes(a)),p=(await Promise.all(c.map(async a=>{let{owner:f}=await A({client:e,worldDeploy:o,table:k.world_NamespaceOwner,key:{namespaceId:Lt({type:"namespace",namespace:a,name:""})}});return[a,f]}))).filter(([,a])=>Fe(a)!==Fe(e.account.address)).map(([a])=>a);if(p.length)throw new Error(`You are attempting to deploy to namespaces you do not own: ${p.join(", ")}`)}async function He({client:e,config:o,worldAddress:t}){await le(e);let r=t?await Pe(e,t):await Se(e);if(!me.includes(r.storeVersion))throw new Error(`Unsupported Store version: ${r.storeVersion}`);if(!pe.includes(r.worldVersion))throw new Error(`Unsupported World version: ${r.worldVersion}`);let n=Object.values(o.tables),s=Object.values(o.systems);await $e({client:e,worldDeploy:r,resourceIds:[...n.map(u=>u.tableId),...s.map(u=>u.systemId)]});let c=await De({client:e,worldDeploy:r,tables:n}),i=await Ie({client:e,worldDeploy:r,systems:s}),p=await We({client:e,worldDeploy:r,functions:s.flatMap(u=>u.functions)}),a=await Ee({client:e,worldDeploy:r,modules:o.modules}),f=[...c,...i,...p,...a];d("waiting for transactions to confirm");for(let u of f)await Kt(e,{hash:u});return d("deploy complete"),r}import{createWalletClient as mr,http as pr}from"viem";import{privateKeyToAccount as fr}from"viem/accounts";import{loadConfig as ur}from"@latticexyz/config/node";import{forge as yr,getOutDirectory as gr,getRemappings as br,getRpcUrl as hr,getSrcDirectory as wr}from"@latticexyz/common/foundry";import F from"chalk";import{execa as xr}from"execa";import{MUDError as Sr}from"@latticexyz/common/errors";import{resolveWorldConfig as Yt}from"@latticexyz/world";import{resourceToHex as Y,hexToResource as Zt}from"@latticexyz/common";import{resolveWithContext as Qt}from"@latticexyz/config";import{encodeField as Xt}from"@latticexyz/protocol-parser";import{getFunctionSelector as _e,getCreate2Address as Le,getAddress as er,hexToBytes as or,bytesToHex as tr,getFunctionSignature as Ke}from"viem";import zt from"glob";import{basename as Jt}from"path";function E(e){return zt.sync(`${e}/**/*.sol`).map(o=>({path:o,basename:Jt(o,".sol")}))}import Be from"@latticexyz/world-modules/out/KeysWithValueModule.sol/KeysWithValueModule.json"assert{type:"json"};import Ne from"@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json"assert{type:"json"};import Ue from"@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json"assert{type:"json"};var Ve=[{name:"KeysWithValueModule",abi:Be.abi,bytecode:Be.bytecode},{name:"KeysInTableModule",abi:Ne.abi,bytecode:Ne.bytecode},{name:"UniqueEntityModule",abi:Ue.abi,bytecode:Ue.bytecode}];import{readFileSync as qt}from"fs";import Gt from"path";import{MUDError as G}from"@latticexyz/common/errors";function z(e,o){let t,r=Gt.join(o,e+".sol",e+".json");try{t=JSON.parse(qt(r,"utf8"))}catch{throw new G(`Error reading file at ${r}`)}let n=t?.bytecode?.object;if(!n)throw new G(`No bytecode found in ${r}`);let s=t?.abi;if(!s)throw new G(`No ABI found in ${r}`);return{abi:s,bytecode:n}}function ze({config:e,forgeSourceDir:o,forgeOutDir:t}){let r=B(e),n=E(o).map(({basename:m})=>m),s=Yt(e,n),i=z("System",t).abi.filter(m=>m.type==="function").map(Ke),p=Object.entries(s.systems).map(([m,y])=>{let h=e.namespace,g=y.name,b=Y({type:"system",namespace:h,name:g}),l=z(m,t),w=l.abi.filter(x=>x.type==="function").map(Ke).filter(x=>!i.includes(x)).map(x=>{let oe=h===""?x:`${h}_${g}_${x}`;return{signature:oe,selector:_e(oe),systemId:b,systemFunctionSignature:x,systemFunctionSelector:_e(x)}});return{namespace:h,name:g,systemId:b,allowAll:y.openAccess,allowedAddresses:y.accessListAddresses,allowedSystemIds:y.accessListSystems.map(x=>Y({type:"system",namespace:h,name:s.systems[x].name})),address:Le({from:C,bytecode:l.bytecode,salt:D}),bytecode:l.bytecode,abi:l.abi,functions:w}}),a=p.map(({allowedAddresses:m,allowedSystemIds:y,...h})=>{let g=y.map(b=>{let l=p.find(w=>w.systemId===b);if(!l)throw new Error(`System ${T(h)} wanted access to ${T(Zt(b))}, but it wasn't found in the config.`);return l.address});return{...h,allowedAddresses:Array.from(new Set([...m,...g].map(b=>er(b))))}}),f={tableIds:Object.fromEntries(Object.entries(e.tables).map(([m,y])=>[m,or(Y({type:y.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:y.name}))]))},u=Ve.map(m=>({name:m.name,bytecode:typeof m.bytecode=="string"?m.bytecode:m.bytecode.object,abi:m.abi})),v=e.modules.map(m=>{let y=u.find(g=>g.name===m.name)??z(m.name,t),h=m.args.map(g=>Qt(g,f)).map(g=>{let b=g.value instanceof Uint8Array?tr(g.value):g.value;return Xt(g.type,b)});if(h.length>1)throw new Error(`${m.name} module should only have 0-1 args, but had ${h.length} args.`);return{name:m.name,installAsRoot:m.root,installData:h.length===0?"0x":h[0],address:Le({from:C,bytecode:y.bytecode,salt:D}),bytecode:y.bytecode,abi:y.abi}});return{tables:r,systems:a,modules:v}}import{getChainId as vr}from"viem/actions";import{existsSync as rr}from"fs";import nr from"path";import sr from"chalk";import{getScriptDirectory as ir,forge as ar}from"@latticexyz/common/foundry";async function Je(e,o,t,r){let n=nr.join(await ir(),e+".s.sol");rr(n)?(console.log(sr.blue(`Executing post deploy script at ${n}`)),await ar(["script",e,"--sig","run(address)",o,"--broadcast","--rpc-url",t,"-vvv"],{profile:r})):console.log(`No script at ${n}, skipping post deploy hook`)}import{tablegen as Cr}from"@latticexyz/store/codegen";var M={configPath:{type:"string",desc:"Path to the config file"},printConfig:{type:"boolean",desc:"Print the resolved config"},profile:{type:"string",desc:"The foundry profile to use"},saveDeployment:{type:"boolean",desc:"Save the deployment info to a file",default:!0},rpc:{type:"string",desc:"The RPC URL to use. Defaults to the RPC url from the local foundry.toml"},worldAddress:{type:"string",desc:"Deploy to an existing World at the given address"},srcDir:{type:"string",desc:"Source directory. Defaults to foundry src directory."},skipBuild:{type:"boolean",desc:"Skip rebuilding the contracts before deploying"}};async function R(e){let o=e.profile??process.env.FOUNDRY_PROFILE,t=await ur(e.configPath);e.printConfig&&console.log(F.green(`
|
|
5
|
+
- `});console.log(N.redBright(o.message))}else e instanceof Vo?(console.log(N.red(e.message)),console.log(""),console.log(N.blue("To learn more about MUD's configuration, please go to https://mud.dev/packages/cli/"))):e instanceof _o?console.log(N.red(e)):console.log(e)}import J from"node:path";import{existsSync as br,mkdirSync as hr,readFileSync as wr,writeFileSync as X}from"node:fs";import{getBytecode as zo,sendRawTransaction as Jo,sendTransaction as qo,waitForTransactionReceipt as de}from"viem/actions";var O={gasPrice:1e11,gasLimit:1e5,signerAddress:"3fab184622dc19b6109349b94811493bf2a45362",transaction:"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",address:"4e59b44847b379578588920ca78fbf26c0b4956c"};import Ko from"debug";var le=Ko("mud:cli");var d=le.extend("deploy");var C=`0x${O.address}`;async function me(e){if(await zo(e,{address:C})){d("found create2 deployer at",C);return}d("sending gas for create2 deployer to signer at",O.signerAddress);let t=await qo(e,{chain:e.chain??null,to:`0x${O.signerAddress}`,value:BigInt(O.gasLimit)*BigInt(O.gasPrice)}),r=await de(e,{hash:t});if(r.status!=="success")throw console.error("failed to send gas to deployer signer",r),new Error("failed to send gas to deployer signer");d("deploying create2 deployer at",C);let n=await Jo(e,{serializedTransaction:`0x${O.transaction}`}),s=await de(e,{hash:n});if(s.contractAddress!==C)throw console.error("unexpected contract address for deployer",s),new Error("unexpected contract address for deployer")}import{waitForTransactionReceipt as gt}from"viem/actions";import ct from"@latticexyz/world/out/CoreModule.sol/CoreModule.json"assert{type:"json"};import lt from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.json"assert{type:"json"};import{parseAbi as dt,getCreate2Address as ye,encodeDeployData as ge}from"viem";import{concatHex as tt,getCreate2Address as rt}from"viem";import{getBytecode as nt}from"viem/actions";import{padHex as Yo}from"viem";import Zo from"@latticexyz/store/mud.config.js";import Qo from"@latticexyz/world/mud.config.js";import Xo from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import{resourceToHex as Go}from"@latticexyz/common";import{resolveUserTypes as pe}from"@latticexyz/store";function H(e){let o={...e.userTypes,...Object.fromEntries(Object.entries(e.enums).map(([t])=>[t,{internalType:"uint8"}]))};return Object.fromEntries(Object.entries(e.tables).map(([t,r])=>[`${e.namespace}_${t}`,{namespace:e.namespace,name:r.name,tableId:Go({type:r.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:r.name}),keySchema:pe(r.keySchema,o),valueSchema:pe(r.valueSchema,o)}]))}import{helloStoreEvent as et}from"@latticexyz/store";import{helloWorldEvent as ot}from"@latticexyz/world";var D=Yo("0x",{size:32}),W=H(Zo),T=H(Qo),U=[et,ot],v=Xo,fe=["1.0.0-unaudited"],ue=["1.0.0-unaudited"];import{sendTransaction as st}from"@latticexyz/common";import it from"p-retry";import{wait as at}from"@latticexyz/common/utils";async function j({client:e,bytecode:o,label:t="contract"}){let r=rt({from:C,salt:D,bytecode:o});return await nt(e,{address:r,blockTag:"pending"})?(d("found",t,"at",r),[]):(d("deploying",t,"at",r),[await it(()=>st(e,{chain:e.chain??null,to:C,data:tt([D,o])}),{retries:3,onFailedAttempt:async s=>{let a=s.attemptNumber*500;d(`failed to deploy ${t}, retrying in ${a}ms...`),await at(a)}})])}var be=ge({bytecode:ct.bytecode.object,abi:[]}),mt=ye({from:C,bytecode:be,salt:D}),he=ge({bytecode:lt.bytecode.object,abi:dt(["constructor(address)"]),args:[mt]}),we=ye({from:C,bytecode:he,salt:D});async function xe(e){return(await Promise.all([j({client:e,bytecode:be,label:"core module"}),j({client:e,bytecode:he,label:"world factory"})])).flat()}import bt from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{writeContract as ht}from"@latticexyz/common";import{AbiEventSignatureNotFoundError as pt,decodeEventLog as ft,hexToString as Se,parseAbi as ut,trim as ve}from"viem";import{isDefined as yt}from"@latticexyz/common/utils";function V(e){let o=e.map(a=>{try{return{...a,...ft({strict:!0,abi:ut(U),topics:a.topics,data:a.data})}}catch(i){if(i instanceof pt)return;throw i}}).filter(yt),{address:t,deployBlock:r,worldVersion:n,storeVersion:s}=o.reduce((a,i)=>({...a,address:i.address,deployBlock:i.blockNumber,...i.eventName==="HelloWorld"?{worldVersion:Se(ve(i.args.worldVersion,{dir:"right"}))}:null,...i.eventName==="HelloStore"?{storeVersion:Se(ve(i.args.storeVersion,{dir:"right"}))}:null}),{});if(t==null)throw new Error("could not find world address");if(r==null)throw new Error("could not find world deploy block number");if(n==null)throw new Error("could not find world version");if(s==null)throw new Error("could not find store version");return{address:t,deployBlock:r,worldVersion:n,storeVersion:s}}async function Ce(e){await xe(e),d("deploying world");let o=await ht(e,{chain:e.chain??null,address:we,abi:bt,functionName:"deployWorld"});d("waiting for world deploy");let t=await gt(e,{hash:o});if(t.status!=="success")throw console.error("world deploy failed",t),new Error("world deploy failed");let r=V(t.logs.map(n=>n));return d("deployed world to",r.address,"at block",r.deployBlock),{...r,stateBlock:r.deployBlock}}import{writeContract as kt}from"@latticexyz/common";import{valueSchemaToFieldLayoutHex as Dt,keySchemaToHex as At,valueSchemaToHex as It}from"@latticexyz/protocol-parser";function S({namespace:e,name:o}){return`${e}:${o}`}import{parseAbiItem as wt,decodeAbiParameters as Te,parseAbiParameters as ke}from"viem";import{hexToResource as xt}from"@latticexyz/common";import{storeSetRecordEvent as St}from"@latticexyz/store";import{getLogs as vt}from"viem/actions";import{decodeKey as Ct,decodeValueArgs as Tt,hexToSchema as De}from"@latticexyz/protocol-parser";async function Ae({client:e,worldDeploy:o}){d("looking up tables for",o.address);let r=(await vt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:wt(St),args:{tableId:W.store_Tables.tableId}})).map(n=>{let{tableId:s}=Ct(W.store_Tables.keySchema,n.args.keyTuple),{namespace:a,name:i}=xt(s),m=Tt(W.store_Tables.valueSchema,n.args),c=De(m.keySchema),p=De(m.valueSchema),w=Te(ke("string[]"),m.abiEncodedKeyNames)[0],u=Te(ke("string[]"),m.abiEncodedFieldNames)[0],f=[...p.staticFields,...p.dynamicFields],g=Object.fromEntries(c.staticFields.map((b,l)=>[w[l],b])),h=Object.fromEntries(f.map((b,l)=>[u[l],b]));return{namespace:a,name:i,tableId:s,keySchema:g,valueSchema:h}});return d("found",r.length,"tables for",o.address),r}import Ot from"p-retry";import{wait as Pt}from"@latticexyz/common/utils";async function Ie({client:e,worldDeploy:o,tables:t}){let n=(await Ae({client:e,worldDeploy:o})).map(i=>i.tableId),s=t.filter(i=>n.includes(i.tableId));s.length&&d("existing tables",s.map(S).join(", "));let a=t.filter(i=>!n.includes(i.tableId));return a.length?(d("registering tables",a.map(S).join(", ")),await Promise.all(a.map(i=>Ot(()=>kt(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"registerTable",args:[i.tableId,Dt(i.valueSchema),At(i.keySchema),It(i.valueSchema),Object.keys(i.keySchema),Object.keys(i.valueSchema)]}),{retries:3,onFailedAttempt:async m=>{let c=m.attemptNumber*500;d(`failed to register table ${S(i)}, retrying in ${c}ms...`),await Pt(c)}})))):[]}import{getAddress as I}from"viem";import{writeContract as q}from"@latticexyz/common";import{parseAbiItem as Mt}from"viem";import{getLogs as Wt}from"viem/actions";import{storeSpliceStaticDataEvent as jt}from"@latticexyz/store";async function _({client:e,worldDeploy:o}){d("looking up resource IDs for",o.address);let r=(await Wt(e,{strict:!0,address:o.address,fromBlock:o.deployBlock,toBlock:o.stateBlock,event:Mt(jt),args:{tableId:W.store_ResourceIds.tableId}})).map(n=>n.args.keyTuple[0]);return d("found",r.length,"resource IDs for",o.address),r}import{hexToResource as qt}from"@latticexyz/common";import{decodeValueArgs as Ft,encodeKey as Rt}from"@latticexyz/protocol-parser";import{readContract as $t}from"viem/actions";async function A({client:e,worldDeploy:o,table:t,key:r}){let[n,s,a]=await $t(e,{blockNumber:o.stateBlock,address:o.address,abi:v,functionName:"getRecord",args:[t.tableId,Rt(t.keySchema,r)]});return Ft(t.valueSchema,{staticData:n,encodedLengths:s,dynamicData:a})}import{getFunctionSelector as Et,parseAbiItem as Nt}from"viem";import{storeSetRecordEvent as Ht}from"@latticexyz/store";import{getLogs as Bt}from"viem/actions";import{decodeValueArgs as Ut}from"@latticexyz/protocol-parser";import{hexToResource as Vt}from"@latticexyz/common";async function L({client:e,worldDeploy:o}){d("looking up function signatures for",o.address);let r=(await Bt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Nt(Ht),args:{tableId:T.world_FunctionSignatures.tableId}})).map(s=>Ut(T.world_FunctionSignatures.valueSchema,s.args).functionSignature);return d("found",r.length,"function signatures for",o.address),await Promise.all(r.map(async s=>{let a=Et(s),{systemId:i,systemFunctionSelector:m}=await A({client:e,worldDeploy:o,table:T.world_FunctionSelectors,key:{functionSelector:a}}),{namespace:c,name:p}=Vt(i),w=c===""?s:s.replace(`${c}_${p}_`,"");return{signature:s,selector:a,systemId:i,systemFunctionSignature:w,systemFunctionSelector:m}}))}import{parseAbiItem as _t,getAddress as Lt}from"viem";import{storeSpliceStaticDataEvent as Kt}from"@latticexyz/store";import{getLogs as zt}from"viem/actions";import{decodeKey as Jt}from"@latticexyz/protocol-parser";async function K({client:e,worldDeploy:o}){d("looking up resource access for",o.address);let r=(await zt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:_t(Kt),args:{tableId:T.world_ResourceAccess.tableId}})).map(s=>Jt(T.world_ResourceAccess.keySchema,s.args.keyTuple)),n=(await Promise.all(r.map(async s=>[s,await A({client:e,worldDeploy:o,table:T.world_ResourceAccess,key:s})]))).filter(([,s])=>s.access).map(([s])=>({resourceId:s.resourceId,address:Lt(s.caller)}));return d("found",n.length,"resource<>address access pairs"),n}async function Oe({client:e,worldDeploy:o}){let[t,r,n]=await Promise.all([_({client:e,worldDeploy:o}),L({client:e,worldDeploy:o}),K({client:e,worldDeploy:o})]),s=t.map(qt).filter(a=>a.type==="system");return d("looking up systems",s.map(S).join(", ")),await Promise.all(s.map(async a=>{let{system:i,publicAccess:m}=await A({client:e,worldDeploy:o,table:T.world_Systems,key:{systemId:a.resourceId}}),c=r.filter(p=>p.systemId===a.resourceId);return{address:i,namespace:a.namespace,name:a.name,systemId:a.resourceId,allowAll:m,allowedAddresses:n.filter(({resourceId:p})=>p===a.resourceId).map(({address:p})=>p),functions:c}}))}import{wait as G}from"@latticexyz/common/utils";import Y from"p-retry";async function Pe({client:e,worldDeploy:o,systems:t}){let[r,n]=await Promise.all([Oe({client:e,worldDeploy:o}),K({client:e,worldDeploy:o})]),s=t.map(l=>l.systemId),a=n.filter(({resourceId:l})=>s.includes(l)),i=t.flatMap(l=>l.allowedAddresses.map(y=>({resourceId:l.systemId,address:y}))),m=i.filter(l=>!a.some(({resourceId:y,address:x})=>y===l.resourceId&&I(x)===I(l.address))),c=a.filter(l=>!i.some(({resourceId:y,address:x})=>y===l.resourceId&&I(x)===I(l.address)));c.length&&d("revoking",c.length,"access grants"),m.length&&d("adding",m.length,"access grants");let p=[...c.map(l=>Y(()=>q(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"revokeAccess",args:[l.resourceId,l.address]}),{retries:3,onFailedAttempt:async y=>{let x=y.attemptNumber*500;d(`failed to revoke access, retrying in ${x}ms...`),await G(x)}})),...m.map(l=>Y(()=>q(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"grantAccess",args:[l.resourceId,l.address]}),{retries:3,onFailedAttempt:async y=>{let x=y.attemptNumber*500;d(`failed to grant access, retrying in ${x}ms...`),await G(x)}}))],w=t.filter(l=>r.some(y=>y.systemId===l.systemId&&I(y.address)===I(l.address)));w.length&&d("existing systems",w.map(S).join(", "));let u=w.map(l=>l.systemId),f=t.filter(l=>!u.includes(l.systemId));if(!f.length)return[];let g=f.filter(l=>r.some(y=>y.systemId===l.systemId&&I(y.address)!==I(l.address)));g.length&&d("upgrading systems",g.map(S).join(", "));let h=f.filter(l=>!r.some(y=>y.systemId===l.systemId));h.length&&d("registering new systems",h.map(S).join(", "));let b=f.map(l=>Y(()=>q(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"registerSystem",args:[l.systemId,l.address,l.allowAll]}),{retries:3,onFailedAttempt:async y=>{let x=y.attemptNumber*500;d(`failed to register system ${S(l)}, retrying in ${x}ms...`),await G(x)}}));return await Promise.all([...p,...b])}import{waitForTransactionReceipt as Le}from"viem/actions";import{getAddress as Gt,parseAbi as Yt}from"viem";import{getBlockNumber as Zt,getLogs as Qt}from"viem/actions";var Me=new Map;async function We(e,o){let t=Gt(o),r=Me.get(t);if(r!=null)return r;d("looking up world deploy for",t);let n=await Zt(e),s=await Qt(e,{strict:!0,address:t,events:Yt(U),fromBlock:"earliest",toBlock:n});return r={...V(s),stateBlock:n},Me.set(t,r),d("found world deploy for",t,"at block",r.deployBlock),r}import{hexToResource as Xt,writeContract as je}from"@latticexyz/common";import Fe from"p-retry";import{wait as Re}from"@latticexyz/common/utils";async function $e({client:e,worldDeploy:o,functions:t}){let r=await L({client:e,worldDeploy:o}),n=Object.fromEntries(r.map(i=>[i.selector,i])),s=t.filter(i=>n[i.selector]),a=t.filter(i=>!s.includes(i));if(s.length){d("functions already registered:",s.map(m=>m.signature).join(", "));let i=s.filter(m=>m.systemId!==n[m.selector]?.systemId);i.length&&console.warn("found",i.length,"functions already registered but pointing at a different system ID:",i.map(m=>m.signature).join(", "))}return a.length?(d("registering functions:",a.map(i=>i.signature).join(", ")),Promise.all(a.map(i=>{let{namespace:m}=Xt(i.systemId);return m===""?Fe(()=>je(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"registerRootFunctionSelector",args:[i.systemId,i.systemFunctionSignature,i.systemFunctionSelector]}),{retries:3,onFailedAttempt:async c=>{let p=c.attemptNumber*500;d(`failed to register function ${i.signature}, retrying in ${p}ms...`),await Re(p)}}):Fe(()=>je(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"registerFunctionSelector",args:[i.systemId,i.systemFunctionSignature]}),{retries:3,onFailedAttempt:async c=>{let p=c.attemptNumber*500;d(`failed to register function ${i.signature}, retrying in ${p}ms...`),await Re(p)}})}))):[]}import{writeContract as Ee}from"@latticexyz/common";import{wait as Ne}from"@latticexyz/common/utils";import He from"p-retry";async function Be({client:e,worldDeploy:o,modules:t}){if(!t.length)return[];d("installing modules:",t.map(n=>n.name).join(", "));let r=await Promise.all(t.map(n=>n.installAsRoot?He(()=>Ee(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"installRootModule",args:[n.address,n.installData]}),{retries:3,onFailedAttempt:async s=>{let a=s.attemptNumber*500;d(`failed to install root module ${n.name}, retrying in ${a}ms...`),await Ne(a)}}):He(()=>Ee(e,{chain:e.chain??null,address:o.address,abi:v,functionName:"installModule",args:[n.address,n.installData]}),{retries:3,onFailedAttempt:async s=>{let a=s.attemptNumber*500;d(`failed to install module ${n.name}, retrying in ${a}ms...`),await Ne(a)}})));return await Promise.all(r)}import{getAddress as Ue}from"viem";import{hexToResource as Ve,resourceToHex as er}from"@latticexyz/common";async function _e({client:e,worldDeploy:o,resourceIds:t}){let r=Array.from(new Set(t.map(c=>Ve(c).namespace))),n=await _({client:e,worldDeploy:o}),s=Array.from(new Set(n.map(c=>Ve(c).namespace))),a=r.filter(c=>s.includes(c)),m=(await Promise.all(a.map(async c=>{let{owner:p}=await A({client:e,worldDeploy:o,table:T.world_NamespaceOwner,key:{namespaceId:er({type:"namespace",namespace:c,name:""})}});return[c,p]}))).filter(([,c])=>Ue(c)!==Ue(e.account.address)).map(([c])=>c);if(m.length)throw new Error(`You are attempting to deploy to namespaces you do not own: ${m.join(", ")}`)}import{uniqueBy as Ke}from"@latticexyz/common/utils";async function ze({client:e,config:o,worldAddress:t}){await me(e);let r=t?await We(e,t):await Ce(e);if(!fe.includes(r.storeVersion))throw new Error(`Unsupported Store version: ${r.storeVersion}`);if(!ue.includes(r.worldVersion))throw new Error(`Unsupported World version: ${r.worldVersion}`);let n=Object.values(o.tables),s=Object.values(o.systems);await _e({client:e,worldDeploy:r,resourceIds:[...n.map(u=>u.tableId),...s.map(u=>u.systemId)]});let a=(await Promise.all([...Ke(s,u=>u.address).map(u=>j({client:e,bytecode:u.bytecode,label:`${S(u)} system`})),...Ke(o.modules,u=>u.address).map(u=>j({client:e,bytecode:u.bytecode,label:`${u.name} module`}))])).flat();if(a.length){d("waiting for contracts");for(let u of a)await Le(e,{hash:u})}let i=await Ie({client:e,worldDeploy:r,tables:n}),m=await Pe({client:e,worldDeploy:r,systems:s}),c=await $e({client:e,worldDeploy:r,functions:s.flatMap(u=>u.functions)}),p=await Be({client:e,worldDeploy:r,modules:o.modules}),w=[...i,...m,...c,...p];d("waiting for all transactions to confirm");for(let u of w)await Le(e,{hash:u});return d("deploy complete"),r}import{createWalletClient as xr,http as Sr}from"viem";import{privateKeyToAccount as vr}from"viem/accounts";import{loadConfig as Cr}from"@latticexyz/config/node";import{forge as Tr,getOutDirectory as kr,getRemappings as Dr,getRpcUrl as Ar,getSrcDirectory as Ir}from"@latticexyz/common/foundry";import R from"chalk";import{execa as Or}from"execa";import{MUDError as Pr}from"@latticexyz/common/errors";import{resolveWorldConfig as sr}from"@latticexyz/world";import{resourceToHex as Q,hexToResource as ir}from"@latticexyz/common";import{resolveWithContext as ar}from"@latticexyz/config";import{encodeField as cr}from"@latticexyz/protocol-parser";import{getFunctionSelector as Ze,getCreate2Address as Qe,getAddress as lr,hexToBytes as dr,bytesToHex as mr,getFunctionSignature as Xe}from"viem";import or from"glob";import{basename as tr}from"path";function F(e){return or.sync(`${e}/**/*.sol`).map(o=>({path:o,basename:tr(o,".sol")}))}import Je from"@latticexyz/world-modules/out/KeysWithValueModule.sol/KeysWithValueModule.json"assert{type:"json"};import qe from"@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json"assert{type:"json"};import Ge from"@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json"assert{type:"json"};var Ye=[{name:"KeysWithValueModule",abi:Je.abi,bytecode:Je.bytecode},{name:"KeysInTableModule",abi:qe.abi,bytecode:qe.bytecode},{name:"UniqueEntityModule",abi:Ge.abi,bytecode:Ge.bytecode}];import{readFileSync as rr}from"fs";import nr from"path";import{MUDError as Z}from"@latticexyz/common/errors";function z(e,o){let t,r=nr.join(o,e+".sol",e+".json");try{t=JSON.parse(rr(r,"utf8"))}catch{throw new Z(`Error reading file at ${r}`)}let n=t?.bytecode?.object;if(!n)throw new Z(`No bytecode found in ${r}`);let s=t?.abi;if(!s)throw new Z(`No ABI found in ${r}`);return{abi:s,bytecode:n}}function eo({config:e,forgeSourceDir:o,forgeOutDir:t}){let r=H(e),n=F(o).map(({basename:f})=>f),s=sr(e,n),i=z("System",t).abi.filter(f=>f.type==="function").map(Xe),m=Object.entries(s.systems).map(([f,g])=>{let h=e.namespace,b=g.name,l=Q({type:"system",namespace:h,name:b}),y=z(f,t),x=y.abi.filter(k=>k.type==="function").map(Xe).filter(k=>!i.includes(k)).map(k=>{let re=h===""?k:`${h}_${b}_${k}`;return{signature:re,selector:Ze(re),systemId:l,systemFunctionSignature:k,systemFunctionSelector:Ze(k)}});return{namespace:h,name:b,systemId:l,allowAll:g.openAccess,allowedAddresses:g.accessListAddresses,allowedSystemIds:g.accessListSystems.map(k=>Q({type:"system",namespace:h,name:s.systems[k].name})),address:Qe({from:C,bytecode:y.bytecode,salt:D}),bytecode:y.bytecode,abi:y.abi,functions:x}}),c=m.map(({allowedAddresses:f,allowedSystemIds:g,...h})=>{let b=g.map(l=>{let y=m.find(x=>x.systemId===l);if(!y)throw new Error(`System ${S(h)} wanted access to ${S(ir(l))}, but it wasn't found in the config.`);return y.address});return{...h,allowedAddresses:Array.from(new Set([...f,...b].map(l=>lr(l))))}}),p={tableIds:Object.fromEntries(Object.entries(e.tables).map(([f,g])=>[f,dr(Q({type:g.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:g.name}))]))},w=Ye.map(f=>({name:f.name,bytecode:typeof f.bytecode=="string"?f.bytecode:f.bytecode.object,abi:f.abi})),u=e.modules.map(f=>{let g=w.find(b=>b.name===f.name)??z(f.name,t),h=f.args.map(b=>ar(b,p)).map(b=>{let l=b.value instanceof Uint8Array?mr(b.value):b.value;return cr(b.type,l)});if(h.length>1)throw new Error(`${f.name} module should only have 0-1 args, but had ${h.length} args.`);return{name:f.name,installAsRoot:f.root,installData:h.length===0?"0x":h[0],address:Qe({from:C,bytecode:g.bytecode,salt:D}),bytecode:g.bytecode,abi:g.abi}});return{tables:r,systems:c,modules:u}}import{getChainId as Mr}from"viem/actions";import{existsSync as pr}from"fs";import fr from"path";import ur from"chalk";import{getScriptDirectory as yr,forge as gr}from"@latticexyz/common/foundry";async function oo(e,o,t,r){let n=fr.join(await yr(),e+".s.sol");pr(n)?(console.log(ur.blue(`Executing post deploy script at ${n}`)),await gr(["script",e,"--sig","run(address)",o,"--broadcast","--rpc-url",t,"-vvv"],{profile:r})):console.log(`No script at ${n}, skipping post deploy hook`)}import{tablegen as Wr}from"@latticexyz/store/codegen";var P={configPath:{type:"string",desc:"Path to the config file"},printConfig:{type:"boolean",desc:"Print the resolved config"},profile:{type:"string",desc:"The foundry profile to use"},saveDeployment:{type:"boolean",desc:"Save the deployment info to a file",default:!0},rpc:{type:"string",desc:"The RPC URL to use. Defaults to the RPC url from the local foundry.toml"},worldAddress:{type:"string",desc:"Deploy to an existing World at the given address"},srcDir:{type:"string",desc:"Source directory. Defaults to foundry src directory."},skipBuild:{type:"boolean",desc:"Skip rebuilding the contracts before deploying"}};async function $(e){let o=e.profile??process.env.FOUNDRY_PROFILE,t=await Cr(e.configPath);e.printConfig&&console.log(R.green(`
|
|
6
6
|
Resolved config:
|
|
7
|
-
`),JSON.stringify(t,null,2));let r=e.srcDir??await
|
|
8
|
-
Deploying MUD contracts${o?" with profile "+o:""} to RPC ${
|
|
9
|
-
`))),!e.skipBuild){let
|
|
7
|
+
`),JSON.stringify(t,null,2));let r=e.srcDir??await Ir(o),n=await kr(o),s=await Dr(),a=e.rpc??await Ar(o);if(console.log(R.bgBlue(R.whiteBright(`
|
|
8
|
+
Deploying MUD contracts${o?" with profile "+o:""} to RPC ${a}
|
|
9
|
+
`))),!e.skipBuild){let f=J.join(r,t.codegenDirectory);await Wr(t,f,s),await Tr(["build","--skip","test","script"],{profile:o}),await Or("mud",["abi-ts"],{stdio:"inherit"})}let i=process.env.PRIVATE_KEY;if(!i)throw new Pr(`Missing PRIVATE_KEY environment variable.
|
|
10
10
|
Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
|
|
11
|
-
in your contracts directory to use the default anvil private key.`);let
|
|
12
|
-
Deployment result (written to ${t.worldsFile} and ${
|
|
13
|
-
`)))}return console.log(
|
|
11
|
+
in your contracts directory to use the default anvil private key.`);let m=eo({config:t,forgeSourceDir:r,forgeOutDir:n}),c=xr({transport:Sr(a),account:vr(i)});console.log("Deploying from",c.account.address);let p=Date.now(),w=await ze({worldAddress:e.worldAddress,client:c,config:m});e.worldAddress==null&&await oo(t.postDeployScript,w.address,a,o),console.log(R.green("Deployment completed in",(Date.now()-p)/1e3,"seconds"));let u={worldAddress:w.address,blockNumber:Number(w.deployBlock)};if(e.saveDeployment){let f=await Mr(c),g=J.join(t.deploysDirectory,f.toString());hr(g,{recursive:!0}),X(J.join(g,"latest.json"),JSON.stringify(u,null,2)),X(J.join(g,Date.now()+".json"),JSON.stringify(u,null,2));let h=[1337,31337],b=br(t.worldsFile)?JSON.parse(wr(t.worldsFile,"utf-8")):{};b[f]={address:u.worldAddress,blockNumber:h.includes(f)?void 0:u.blockNumber},X(t.worldsFile,JSON.stringify(b,null,2)),console.log(R.bgGreen(R.whiteBright(`
|
|
12
|
+
Deployment result (written to ${t.worldsFile} and ${g}):
|
|
13
|
+
`)))}return console.log(u),w}var jr={command:"deploy",describe:"Deploy MUD contracts",builder(e){return e.options(P)},async handler(e){try{await $(e)}catch(o){M(o),process.exit(1)}process.exit(0)}},to=jr;import{loadConfig as Fr}from"@latticexyz/config/node";import{worldgen as Rr}from"@latticexyz/world/node";import{getSrcDirectory as $r}from"@latticexyz/common/foundry";import ro from"path";import{rmSync as Er}from"fs";var Nr={command:"worldgen",describe:"Autogenerate interfaces for Systems and World based on existing contracts and the config file",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"},clean:{type:"boolean",desc:"Clear the worldgen directory before generating new interfaces (defaults to true)",default:!0}})},async handler(e){await Hr(e),process.exit(0)}};async function Hr(e){let o=e.srcDir??await $r(),t=F(o),r=e.config??await Fr(e.configPath),n=ro.join(o,r.codegenDirectory);e.clean&&Er(ro.join(n,r.worldgenDirectory),{recursive:!0,force:!0}),await Rr(r,t,n)}var no=Nr;import B from"chalk";import{readFileSync as Lr,writeFileSync as Kr}from"fs";import oe from"path";import{MUDError as E}from"@latticexyz/common/errors";var so={name:"@latticexyz/cli",version:"2.0.0-next.11",description:"Command line interface for mud",repository:{type:"git",url:"https://github.com/latticexyz/mud.git",directory:"packages/cli"},license:"MIT",type:"module",exports:{".":"./dist/index.js"},types:"src/index.ts",bin:{mud:"./dist/mud.js"},scripts:{build:"pnpm run build:js && pnpm run build:test-tables","build:js":"tsup && chmod +x ./dist/mud.js","build:test-tables":"tsx ./scripts/generate-test-tables.ts",clean:"pnpm run clean:js && pnpm run clean:test-tables","clean:js":"rimraf dist","clean:test-tables":"rimraf src/codegen",dev:"tsup --watch",lint:"eslint . --ext .ts",prepare:"mkdir -p ./dist && touch ./dist/mud.js",test:"tsc --noEmit && forge test","test:ci":"pnpm run test"},dependencies:{"@ethersproject/abi":"^5.7.0","@ethersproject/providers":"^5.7.2","@improbable-eng/grpc-web":"^0.15.0","@improbable-eng/grpc-web-node-http-transport":"^0.15.0","@latticexyz/abi-ts":"workspace:*","@latticexyz/common":"workspace:*","@latticexyz/config":"workspace:*","@latticexyz/gas-report":"workspace:*","@latticexyz/protocol-parser":"workspace:*","@latticexyz/schema-type":"workspace:*","@latticexyz/services":"workspace:*","@latticexyz/store":"workspace:*","@latticexyz/utils":"workspace:*","@latticexyz/world":"workspace:*","@latticexyz/world-modules":"workspace:*",chalk:"^5.0.1",chokidar:"^3.5.3",debug:"^4.3.4",dotenv:"^16.0.3",ejs:"^3.1.8",ethers:"^5.7.2",execa:"^7.0.0",glob:"^8.0.3","nice-grpc-web":"^2.0.1",openurl:"^1.1.1","p-retry":"^5.1.2",path:"^0.12.7",rxjs:"7.5.5","throttle-debounce":"^5.0.0",typescript:"5.1.6",viem:"1.14.0",yargs:"^17.7.1",zod:"^3.21.4","zod-validation-error":"^1.3.0"},devDependencies:{"@types/debug":"^4.1.7","@types/ejs":"^3.1.1","@types/glob":"^7.2.0","@types/node":"^18.15.11","@types/openurl":"^1.0.0","@types/throttle-debounce":"^5.0.0","@types/yargs":"^17.0.10","ds-test":"https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0","forge-std":"https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1",tsup:"^6.7.0",tsx:"^3.12.6",vitest:"0.31.4"},gitHead:"914a1e0ae4a573d685841ca2ea921435057deb8f"};import zr from"glob";import{ZodError as Ur,z as io}from"zod";var Vr=io.object({MUD_PACKAGES:io.string().transform(e=>JSON.parse(e))});function _r(){try{return Vr.parse({MUD_PACKAGES:'{"@latticexyz/abi-ts":{"localPath":"packages/abi-ts"},"@latticexyz/block-logs-stream":{"localPath":"packages/block-logs-stream"},"@latticexyz/cli":{"localPath":"packages/cli"},"@latticexyz/common":{"localPath":"packages/common"},"@latticexyz/config":{"localPath":"packages/config"},"create-mud":{"localPath":"packages/create-mud"},"@latticexyz/dev-tools":{"localPath":"packages/dev-tools"},"@latticexyz/faucet":{"localPath":"packages/faucet"},"@latticexyz/gas-report":{"localPath":"packages/gas-report"},"@latticexyz/noise":{"localPath":"packages/noise"},"@latticexyz/phaserx":{"localPath":"packages/phaserx"},"@latticexyz/protocol-parser":{"localPath":"packages/protocol-parser"},"@latticexyz/react":{"localPath":"packages/react"},"@latticexyz/recs":{"localPath":"packages/recs"},"@latticexyz/schema-type":{"localPath":"packages/schema-type"},"@latticexyz/services":{"localPath":"packages/services"},"solhint-config-mud":{"localPath":"packages/solhint-config-mud"},"solhint-plugin-mud":{"localPath":"packages/solhint-plugin-mud"},"@latticexyz/store-indexer":{"localPath":"packages/store-indexer"},"@latticexyz/store-sync":{"localPath":"packages/store-sync"},"@latticexyz/store":{"localPath":"packages/store"},"@latticexyz/utils":{"localPath":"packages/utils"},"@latticexyz/world-modules":{"localPath":"packages/world-modules"},"@latticexyz/world":{"localPath":"packages/world"}}'})}catch(e){if(e instanceof Ur){let{_errors:o,...t}=e.format();console.error(`
|
|
14
14
|
Missing or invalid environment variables:
|
|
15
15
|
|
|
16
16
|
${Object.keys(t).join(`
|
|
17
17
|
`)}
|
|
18
|
-
`),process.exit(1)}throw e}}var
|
|
19
|
-
`),console.log(`Updating ${e}`),
|
|
18
|
+
`),process.exit(1)}throw e}}var ee=_r().MUD_PACKAGES;var Jr={command:"set-version",describe:"Set MUD version in all package.json files and optionally backup the previously installed version",builder(e){return e.options({mudVersion:{alias:"v",type:"string",description:"Set MUD to the given version"},tag:{alias:"t",type:"string",description:"Set MUD to the latest version with the given tag from npm"},commit:{alias:"c",type:"string",description:"Set MUD to the version based on a given git commit hash from npm"},link:{alias:"l",type:"string",description:"Relative path to the local MUD root directory to link"}})},async handler(e){try{let o=["mudVersion","link","tag","commit","restore"],t=o.reduce((n,s)=>e[s]?n+1:n,0);if(t===0)throw new E(`You need to provide one these options: ${o.join(", ")}`);if(t>1)throw new E(`These options are mutually exclusive: ${o.join(", ")}`);e.mudVersion=await qr(e);let r=zr.sync("**/package.json").filter(n=>!n.includes("node_modules"));for(let n of r)Gr(n,e)}catch(o){M(o)}finally{process.exit(0)}}};async function qr(e){e.mudVersion==="canary"&&(e.tag="main");let o;try{console.log(B.blue("Fetching available versions")),o=await(await fetch(`https://registry.npmjs.org/${so.name}`)).json()}catch{throw new E("Could not fetch available MUD versions")}if(e.tag){let t=o["dist-tags"][e.tag];if(!t)throw new E(`Could not find npm version with tag "${e.tag}"`);return console.log(B.green(`Latest version with tag ${e.tag}: ${t}`)),t}if(e.commit){let t=e.commit.substring(0,8),r=Object.keys(o.versions).find(n=>n.includes(t));if(!r)throw new E(`Could not find npm version based on commit "${e.commit}"`);return console.log(B.green(`Version from commit ${e.commit}: ${r}`)),r}return e.mudVersion}function Gr(e,o){let{link:t}=o,{mudVersion:r}=o,n=Yr(e),s=Object.keys(ee),a={};for(let c in n.dependencies)s.includes(c)&&(a[c]=n.dependencies[c]);let i={};for(let c in n.devDependencies)s.includes(c)&&(i[c]=n.devDependencies[c]);for(let c in n.dependencies)s.includes(c)&&(n.dependencies[c]=m(c,"dependencies"));for(let c in n.devDependencies)s.includes(c)&&(n.devDependencies[c]=m(c,"devDependencies"));return Kr(e,JSON.stringify(n,null,2)+`
|
|
19
|
+
`),console.log(`Updating ${e}`),ao(a,n.dependencies),ao(i,n.devDependencies),n;function m(c,p){return t&&(r=Zr(e,t,c)),r||n[p][c]}}function Yr(e){try{let o=Lr(e,"utf8");return JSON.parse(o)}catch{throw new E("Could not read JSON at "+e)}}function ao(e,o){for(let t in e)e[t]!==o[t]&&console.log(`${t}: ${B.red(e[t])} -> ${B.green(o[t])}`)}function Zr(e,o,t){let r=oe.relative(oe.dirname(e),process.cwd());return"link:"+oe.join(r,o,ee[t].localPath)}var co=Jr;import{anvil as Qr,forge as Xr,getRpcUrl as en}from"@latticexyz/common/foundry";import on from"chalk";var tn={...P,port:{type:"number",description:"Port to run internal node for fork testing on",default:4242},worldAddress:{type:"string",description:"Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing."},forgeOptions:{type:"string",description:"Options to pass to forge test"}},rn={command:"test",describe:"Run tests in MUD contracts",builder(e){return e.options(tn)},async handler(e){if(!e.worldAddress){let n=["--block-base-fee-per-gas","0","--port",String(e.port)];Qr(n)}let o=e.worldAddress?await en(e.profile):`http://127.0.0.1:${e.port}`,t=e.worldAddress??(await $({...e,saveDeployment:!1,rpc:o})).address;console.log(on.blue("World address",t));let r=e.forgeOptions?.replaceAll("\\","").split(" ")??[];try{await Xr(["test","--fork-url",o,...r],{profile:e.profile,env:{WORLD_ADDRESS:t}}),process.exit(0)}catch(n){console.error(n),process.exit(1)}}},lo=rn;import{existsSync as nn,readFileSync as sn}from"fs";import{ethers as mo}from"ethers";import{loadConfig as an}from"@latticexyz/config/node";import{MUDError as po}from"@latticexyz/common/errors";import{cast as cn,getRpcUrl as ln,getSrcDirectory as dn}from"@latticexyz/common/foundry";import{resolveWorldConfig as mn}from"@latticexyz/world";import pn from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import fo from"@latticexyz/world/mud.config.js";import{resourceToHex as yo}from"@latticexyz/common";import{createClient as fn,http as un}from"viem";import{getChainId as yn}from"viem/actions";var uo=yo({type:"system",namespace:fo.namespace,name:fo.tables.Systems.name}),gn={command:"trace",describe:"Display the trace of a transaction",builder(e){return e.options({tx:{type:"string",required:!0,description:"Transaction hash to replay"},worldAddress:{type:"string",description:"World contract address. Defaults to the value from worlds.json, based on rpc's chainId"},configPath:{type:"string",description:"Path to the config file"},profile:{type:"string",description:"The foundry profile to use"},srcDir:{type:"string",description:"Source directory. Defaults to foundry src directory."},rpc:{type:"string",description:"json rpc endpoint. Defaults to foundry's configured eth_rpc_url"}})},async handler(e){e.profile??=process.env.FOUNDRY_PROFILE;let{profile:o}=e;e.srcDir??=await dn(o),e.rpc??=await ln(o);let{tx:t,configPath:r,srcDir:n,rpc:s}=e,a=F(n),i=await an(r),m=mn(i,a.map(({basename:l})=>l)),c=e.worldAddress??await bn(i.worldsFile,s),p=new mo.providers.StaticJsonRpcProvider(s),w=new mo.Contract(c,pn,p),u=i.namespace,f=Object.values(m.systems).map(({name:l})=>l),g=await w.getFieldLayout(uo),h=[];for(let l of f){let y=yo({type:"system",namespace:u,name:l}),x=await w.getField(uo,[y],0,g);h.push({name:l,address:x})}let b=await cn(["run","--label",`${c}:World`,...h.map(({name:l,address:y})=>["--label",`${y}:${l}`]).flat(),`${t}`]);console.log(b),process.exit(0)}},go=gn;async function bn(e,o){if(nn(e)){let t=fn({transport:un(o)}),r=await yn(t),n=JSON.parse(sn(e,"utf-8"));if(!n[r])throw new po(`chainId ${r} is missing in worldsFile "${e}"`);return n[r].address}else throw new po("worldAddress is not specified and worldsFile is missing")}import{anvil as hn,getScriptDirectory as wn,getSrcDirectory as xn}from"@latticexyz/common/foundry";import te from"chalk";import Sn from"chokidar";import{loadConfig as vn,resolveConfigPath as Cn}from"@latticexyz/config/node";import Tn from"path";import{homedir as kn}from"os";import{rmSync as Dn}from"fs";import{BehaviorSubject as An,debounceTime as In,exhaustMap as On}from"rxjs";var Pn={rpc:P.rpc,configPath:P.configPath},Mn={command:"dev-contracts",describe:"Start a development server for MUD contracts",builder(e){return e.options(Pn)},async handler(e){let o=e.rpc,t=e.configPath??await Cn(e.configPath),r=await xn(),n=await wn(),s=await vn(t);if(!e.rpc){console.log(te.gray("Cleaning devnode cache"));let c=kn();Dn(Tn.join(c,".foundry","anvil","tmp"),{recursive:!0,force:!0}),hn(["--block-time","1","--block-base-fee-per-gas","0"]),o="http://127.0.0.1:8545"}let a=new An(Date.now());Sn.watch([t,r,n]).on("all",async(c,p)=>{p.includes(t)&&a.next(Date.now()),(p.includes(r)||p.includes(n))&&(p.includes(s.codegenDirectory)||a.next(Date.now()))});let i;a.pipe(In(200),On(async c=>{i&&console.log(te.blue("Change detected, rebuilding and running deploy..."));let p=await $({configPath:t,rpc:o,skipBuild:!1,printConfig:!1,profile:void 0,saveDeployment:!0,worldAddress:i,srcDir:r});return i=p.address,c<a.value?a.next(a.value):console.log(te.gray("Watching for file changes...")),p})).subscribe()}},bo=Mn;var ho=[to,ne,ie,Wn,ae,ce,no,co,lo,go,bo,jn];import*as xo from"dotenv";import wo from"chalk";xo.config();Fn(Rn(process.argv)).scriptName("mud").command(ho).strict().fail((e,o)=>{console.error(wo.red(e)),e.includes("Missing required argument")&&console.log(wo.yellow(`Run 'pnpm mud ${process.argv[2]} --help' for a list of available and required arguments.`)),console.log(""),o!=null&&(M(o),console.log("")),process.exit(1)}).alias({h:"help"}).argv;
|
|
20
20
|
//# sourceMappingURL=mud.js.map
|