@0xobelisk/sui-common 1.2.0-pre.98 → 2.0.0

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.
Files changed (39) hide show
  1. package/LICENSE +92 -0
  2. package/README.md +670 -1
  3. package/dist/index.d.ts +61 -27
  4. package/dist/index.js +1078 -461
  5. package/dist/index.js.map +1 -1
  6. package/package.json +15 -17
  7. package/src/codegen/debug.ts +0 -4
  8. package/src/codegen/types/index.ts +46 -10
  9. package/src/codegen/utils/config.ts +1 -1
  10. package/src/codegen/utils/format.ts +0 -6
  11. package/src/codegen/utils/formatAndWrite.ts +10 -31
  12. package/src/codegen/utils/generateLock.ts +122 -0
  13. package/src/codegen/utils/index.ts +4 -2
  14. package/src/codegen/utils/renderMove/{schemaGen.ts → codegen.ts} +40 -28
  15. package/src/codegen/utils/renderMove/common.ts +0 -65
  16. package/src/codegen/utils/renderMove/dapp.ts +2 -14
  17. package/src/codegen/utils/renderMove/generateDappKey.ts +33 -18
  18. package/src/codegen/utils/renderMove/generateError.ts +32 -15
  19. package/src/codegen/utils/renderMove/generateGenesis.ts +55 -22
  20. package/src/codegen/utils/renderMove/generateInitTest.ts +26 -14
  21. package/src/codegen/utils/renderMove/generateObjects.ts +377 -0
  22. package/src/codegen/utils/renderMove/generatePermits.ts +151 -0
  23. package/src/codegen/utils/renderMove/generateResources.ts +894 -242
  24. package/src/codegen/utils/renderMove/generateScenes.ts +467 -0
  25. package/src/codegen/utils/renderMove/generateScript.ts +18 -13
  26. package/src/codegen/utils/renderMove/generateSystem.ts +0 -2
  27. package/src/codegen/utils/renderMove/generateUserStorageInit.ts +37 -0
  28. package/src/codegen/utils/validateConfig.ts +237 -0
  29. package/src/index.ts +0 -1
  30. package/src/modules.d.ts +0 -10
  31. package/src/codegen/modules.d.ts +0 -1
  32. package/src/codegen/utils/posixPath.ts +0 -8
  33. package/src/codegen/utils/renderMove/generateComponents.ts +0 -802
  34. package/src/codegen/utils/renderMove/generateDefaultSchema.ts +0 -216
  35. package/src/codegen/utils/renderMove/generateEvent.ts +0 -99
  36. package/src/codegen/utils/renderMove/generateSchema.ts +0 -287
  37. package/src/codegen/utils/renderMove/generateSchemaHub.ts +0 -60
  38. package/src/parseData/index.ts +0 -1
  39. package/src/parseData/parser/index.ts +0 -47
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
- import Y from"prettier";import ke from"prettier-plugin-move-js";async function Ue(e,t){let s;t&&(s=await Y.resolveConfig(t));try{return Y.format(e,{plugins:[ke],parser:"move-parse",printWidth:120,semi:!0,tabWidth:2,useTabs:!1,bracketSpacing:!0,...s})}catch(n){let c;return n instanceof Error?c=n.message:c=n,console.log(`Error during output formatting: ${c}`),e}}async function N(e){return Y.format(e,{parser:"typescript"})}import G from"node:fs/promises";import te from"node:path";import ee from"debug";var R=ee("dubhe:common"),Se=ee("dubhe:common");R.log=console.debug.bind(console);Se.log=console.error.bind(console);var U=R.extend("codegen"),xe=R.extend("codegen");U.log=console.debug.bind(console);xe.log=console.error.bind(console);async function h(e,t,s){let n=e,c=` // Copyright (c) Obelisk Labs, Inc.
2
- // SPDX-License-Identifier: Apache-2.0
3
- #[allow(unused_use)]
4
-
5
- /* Autogenerated file. Do not edit manually. */
6
-
7
- `,l="#[test_only]",S=c+n,D="#[allow(lint(share_owned))]";t.includes(".toml")||t.includes("system")||t.includes("migrate")?S=n:t.includes("init")?S=l+n:t.includes("genesis")&&(S=D+n),await G.mkdir(te.dirname(t),{recursive:!0}),await G.writeFile(t,S),U(`${s}: ${t}`)}async function Ne(e,t,s){let n=await N(e);await G.mkdir(te.dirname(t),{recursive:!0}),await G.writeFile(t,n),U(`${s}: ${t}`)}function tt(e){return e.replace(/\\/g,"/")}import{existsSync as K}from"fs";import P from"fs";function J(e){P.existsSync(e)&&(P.readdirSync(e).forEach(t=>{let s=`${e}/${t}`;P.lstatSync(s).isDirectory()?J(s):P.unlinkSync(s)}),P.rmdirSync(e))}var se={name:"@0xobelisk/sui-common",version:"1.2.0-pre.98",description:"Common low level logic shared between packages",keywords:["sui","obelisk labs","move","blockchain"],homepage:"https://github.com/0xobelisk/dubhe/tree/main/packages/sui-common#readme",bugs:"https://github.com/0xobelisk/dubhe/issues",repository:{type:"git",url:"https://github.com/0xobelisk/dubhe.git"},license:"Apache-2.0",author:"team@obelisk.build",type:"module",exports:{".":{types:"./dist/index.d.ts",default:"./dist/index.js"}},types:"./dist/index.d.ts",typesVersions:{"*":{index:["./src/index.ts"]}},scripts:{build:"pnpm run type-check && pnpm run build:js","build:js":"tsup && chmod +x ./dist/index.js",clean:"pnpm run clean:js","clean:js":"rimraf dist",dev:"tsup --watch",format:"prettier --write .","format:check":"prettier --check .",lint:"eslint . --ext .ts",test:"vitest","type-check":"tsc --noEmit",validate:"pnpm format:check && pnpm type-check"},dependencies:{chalk:"^5.0.1",debug:"^4.3.4",dotenv:"^16.0.3",ejs:"^3.1.8",esbuild:"^0.17.15",execa:"^7.0.0","find-up":"^6.3.0",glob:"^10.5.0",path:"^0.12.7",prettier:"^3.1.1","prettier-plugin-move-js":"^0.0.5","prettier-plugin-rust":"^0.1.9","prettier-plugin-solidity":"^1.1.2",typescript:"^5.8.3",yargs:"^17.7.1",zod:"^3.22.3","zod-validation-error":"^1.3.0"},devDependencies:{"@types/debug":"^4.1.12","@types/ejs":"^3.1.1","@types/glob":"^7.2.0","@types/node":"^22.16.0","@types/yargs":"^17.0.10",eslint:"^9.0.0","eslint-config-prettier":"^9.1.0",prettier:"3.3.3",tsup:"^6.7.0",tsx:"^3.12.6",vitest:"^2.1.3"},engines:{node:">=22.0.0"},publishConfig:{access:"public"}};async function ne(e,t){console.log(`
1
+ import ye from"prettier";import Xe from"prettier-plugin-move-js";async function Rt(e,t){let s;t&&(s=await ye.resolveConfig(t));try{return ye.format(e,{plugins:[Xe],parser:"move-parse",printWidth:120,semi:!0,tabWidth:2,useTabs:!1,bracketSpacing:!0,...s})}catch(n){let r;return n instanceof Error?r=n.message:r=n,console.log(`Error during output formatting: ${r}`),e}}import ve from"node:fs/promises";import Ne from"node:path";import he from"debug";var ce=he("dubhe:common"),Qe=he("dubhe:common");ce.log=console.debug.bind(console);Qe.log=console.error.bind(console);var ue=ce.extend("codegen");ue.log=console.debug.bind(console);async function E(e,t,s){let n=e,r=`// Copyright (c) Obelisk Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /* Autogenerated file. Do not edit manually. */
5
+
6
+ `,i=`#[test_only]
7
+ `,d=r+n,l=`#[allow(lint(share_owned))]
8
+ `;t.includes(".toml")||t.includes("system")||t.includes("migrate")?d=n:t.includes("init_test")?d=i+n:t.includes("genesis")&&(d=l+n),await ve.mkdir(Ne.dirname(t),{recursive:!0}),await ve.writeFile(t,d),ue(`${s}: ${t}`)}import{existsSync as q}from"fs";import X from"fs";function pe(e){X.existsSync(e)&&(X.readdirSync(e).forEach(t=>{let s=`${e}/${t}`;X.lstatSync(s).isDirectory()?pe(s):X.unlinkSync(s)}),X.rmdirSync(e))}var ke={name:"@0xobelisk/sui-common",version:"2.0.0",description:"Common low level logic shared between packages",keywords:["sui","obelisk labs","move","blockchain"],homepage:"https://github.com/0xobelisk/dubhe/tree/main/packages/sui-common#readme",bugs:"https://github.com/0xobelisk/dubhe/issues",repository:{type:"git",url:"https://github.com/0xobelisk/dubhe.git"},license:"Apache-2.0",author:"team@obelisk.build",type:"module",exports:{".":{types:"./dist/index.d.ts",default:"./dist/index.js"}},types:"./dist/index.d.ts",typesVersions:{"*":{index:["./src/index.ts"]}},scripts:{build:"pnpm run type-check && pnpm run build:js","build:js":"tsup && chmod +x ./dist/index.js",clean:"pnpm run clean:js","clean:js":"rimraf dist",dev:"tsup --watch",format:"prettier --write .","format:check":"prettier --check .",lint:"eslint . --ext .ts",test:"vitest","type-check":"tsc --noEmit",validate:"pnpm format:check && pnpm type-check"},dependencies:{chalk:"^5.0.1",debug:"^4.3.4",dotenv:"^16.0.3",ejs:"^3.1.8",esbuild:"^0.17.15",execa:"^7.0.0","find-up":"^6.3.0",glob:"^10.5.0",path:"^0.12.7",prettier:"^3.1.1","prettier-plugin-move-js":"^0.0.5",typescript:"^5.8.3",yargs:"^17.7.1",zod:"^3.22.3","zod-validation-error":"^1.3.0"},devDependencies:{"@types/debug":"^4.1.12","@types/ejs":"^3.1.1","@types/glob":"^7.2.0","@types/node":"^22.16.0","@types/yargs":"^17.0.10",eslint:"^9.0.0","eslint-config-prettier":"^9.1.0",prettier:"3.3.3",tsup:"^6.7.0",tsx:"^3.12.6",vitest:"^2.1.3"},engines:{node:">=22.0.0"},publishConfig:{access:"public"}};async function Se(e,t){console.log(`
8
9
  \u{1F4C4} Starting Move.toml Generation...`),console.log(` \u2514\u2500 Output path: ${t}/src/${e.name}/Move.toml`);let s=`[package]
9
10
  name = "${e.name}"
10
11
  version = "1.0.0"
@@ -12,627 +13,1243 @@ edition = "2024"
12
13
 
13
14
  [dependencies]
14
15
  Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "mainnet-v1.46.3" }
15
- Dubhe = { git = "https://github.com/0xobelisk/dubhe.git", subdir = "framework/src/dubhe", rev = "v${se.version}" }
16
+ Dubhe = { git = "https://github.com/0xobelisk/dubhe.git", subdir = "framework/src/dubhe", rev = "v${ke.version}" }
16
17
 
17
18
  [addresses]
18
19
  sui = "0x2"
19
20
  ${e.name} = "0x0"
20
- `;await h(s,`${t}/src/${e.name}/Move.toml`,"formatAndWriteMove"),console.log(`\u2705 Move.toml Generation Complete
21
- `)}import{existsSync as re}from"fs";async function ue(e,t){if(!re(t)){let s=`module ${e.name}::deploy_hook {
22
- use dubhe::dapp_service::DappHub;
23
-
24
- public(package) fun run(_dapp_hub: &mut DappHub, _ctx: &mut TxContext) {
25
-
26
- }
27
- }`;await h(s,t,"formatAndWriteMove")}}async function ie(e,t){if(!re(`${t}/src/${e.name}/sources/scripts/migrate.move`)){let s=`module ${e.name}::migrate {
21
+ `;await E(s,`${t}/src/${e.name}/Move.toml`,"formatAndWriteMove"),console.log(`\u2705 Move.toml Generation Complete
22
+ `)}import{existsSync as xe}from"fs";async function Ce(e,t,s=1){if(!xe(t)){let n=s===1?`// Settlement mode: USER_PAYS \u2014 users pay transaction fees at settlement time.
23
+ // The framework admin sets the revenue share via set_dapp_revenue_share.
24
+ // Initialise any DappStorage-level defaults here (e.g. resource starting values).`:`// Settlement mode: DAPP_SUBSIDIZES \u2014 the DApp pays for user operations.
25
+ // Recharge the credit pool via dapp_system::recharge_credit before users can write.
26
+ // Initialise any DappStorage-level defaults here (e.g. resource starting values).`,r=`module ${e.name}::deploy_hook {
27
+ use dubhe::dapp_service::DappStorage;
28
+
29
+ public(package) fun run(_dapp_storage: &mut DappStorage, _ctx: &mut TxContext) {
30
+ ${n}
31
+ }
32
+ }`;await E(r,t,"formatAndWriteMove")}}async function we(e,t){if(!xe(`${t}/src/${e.name}/sources/scripts/migrate.move`)){let s=`module ${e.name}::migrate {
28
33
  const ON_CHAIN_VERSION: u32 = 1;
29
34
 
30
35
  public fun on_chain_version(): u32 {
31
36
  ON_CHAIN_VERSION
32
37
  }
33
38
  }
34
- `;await h(s,`${t}/src/${e.name}/sources/scripts/migrate.move`,"formatAndWriteMove")}}async function oe(e,t){let s=`module ${e.name}::dapp_key {
35
- use std::type_name;
36
- use sui::address;
37
- use std::ascii::String;
39
+ `;await E(s,`${t}/src/${e.name}/sources/scripts/migrate.move`,"formatAndWriteMove")}}async function De(e,t){let s=`module ${e.name}::dapp_key {
40
+ use std::type_name;
41
+ use sui::address;
42
+ use std::ascii::String;
43
+
44
+ /// DappKey \u2014 package-level authorization token for this DApp.
45
+ ///
46
+ /// SECURITY: \`new()\` is intentionally \`public(package)\`.
47
+ /// Only code compiled into this package can construct a DappKey instance.
48
+ /// All framework write functions (\`set_record\`, \`set_field\`,
49
+ /// \`take_record\`, \`create_user_storage\`, \u2026) require \`_auth: DappKey\`
50
+ /// as proof that the call originated from inside this package \u2014 an
51
+ /// external PTB cannot fabricate that proof.
52
+ ///
53
+ /// NEVER change \`new()\` to \`public\`, and never accept a DappKey
54
+ /// value as a parameter from an external caller. Either mistake removes
55
+ /// every package-level access guard, allowing any PTB to write arbitrary
56
+ /// user data or register UserStorages without going through the DApp's
57
+ /// own entry functions.
58
+
59
+ public struct DappKey has copy, drop {}
60
+
61
+ /// Constructs an authorization token. Callable only from within this package.
62
+ /// Pass the result as \`_auth\` to any framework function that requires it.
63
+ public(package) fun new(): DappKey {
64
+ DappKey {}
65
+ }
38
66
 
39
- /// Authorization token for the app.
67
+ public fun to_string(): String {
68
+ type_name::with_defining_ids<DappKey>().into_string()
69
+ }
40
70
 
41
- public struct DappKey has copy, drop {}
71
+ public fun package_id(): address {
72
+ let package_id_str = type_name::with_defining_ids<DappKey>().address_string();
73
+ address::from_ascii_bytes(package_id_str.as_bytes())
74
+ }
42
75
 
43
- public(package) fun new(): DappKey {
44
- DappKey { }
45
- }
76
+ public fun eq<DappKey1: copy + drop, DappKey2: copy + drop>(_: &DappKey1, _: &DappKey2): bool {
77
+ type_name::with_defining_ids<DappKey1>() == type_name::with_defining_ids<DappKey2>()
78
+ }
79
+ }
80
+ `;await E(s,t,"formatAndWriteMove")}import{existsSync as je}from"fs";import Te from"node:fs/promises";async function Ae(e,t){je(`${t}/src/${e.name}/sources/systems`)||await Te.mkdir(`${t}/src/${e.name}/sources/systems`,{recursive:!0}),je(`${t}/src/${e.name}/sources/tests`)||await Te.mkdir(`${t}/src/${e.name}/sources/tests`,{recursive:!0})}function tt(e){return"E"+e.split("_").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}function st(e){return typeof e=="string"?e:e.message}async function Ee(e,t,s){console.log(`
81
+ \u{1F4E6} Starting Error Generation...`);let n=Object.entries(t).map(([i,d])=>{let l=tt(i),u=st(d);return console.log(` \u2514\u2500 ${i}: ${u}`),[" #[error]",` const ${l}: vector<u8> = b"${u}";`,` public fun ${i}(condition: bool) { assert!(condition, ${l}) }`].join(`
82
+ `)}).join(`
46
83
 
47
- public fun to_string(): String {
48
- type_name::get<DappKey>().into_string()
84
+ `),r=`module ${e}::error {
85
+ ${n}
86
+ }
87
+ `;await E(r,`${s}/src/${e}/sources/codegen/error.move`,"formatAndWriteMove")}async function Oe(e,t){let n=e.name==="dubhe"?"":`
88
+ /// Create a DappStorage for this DApp without sharing it.
89
+ /// Suitable for unit tests that exercise global-resource functions.
90
+ public fun create_dapp_storage_for_testing(ctx: &mut TxContext): dubhe::dapp_service::DappStorage {
91
+ dubhe::dapp_system::create_dapp_storage_for_testing<${e.name}::dapp_key::DappKey>(ctx)
49
92
  }
50
93
 
51
- public fun package_id(): address {
52
- let package_id_str = type_name::get<DappKey>().get_address();
53
- address::from_ascii_bytes(package_id_str.as_bytes())
54
- }
94
+ /// Create a UserStorage for \`owner\` without sharing it.
95
+ /// Suitable for unit tests that exercise user-level resource functions.
96
+ public fun create_user_storage_for_testing(owner: address, ctx: &mut TxContext): dubhe::dapp_service::UserStorage {
97
+ dubhe::dapp_system::create_user_storage_for_testing<${e.name}::dapp_key::DappKey>(owner, ctx)
98
+ }`,r=`
99
+ module ${e.name}::init_test {
100
+ use dubhe::dapp_system;
55
101
 
56
- public fun eq<DappKey1: copy + drop, DappKey2: copy + drop>(_: &DappKey1, _: &DappKey2): bool {
57
- type_name::get<DappKey1>() == type_name::get<DappKey2>()
102
+ /// Create a DappHub for testing without sharing it.
103
+ /// Suitable for unit tests that need a DappHub context.
104
+ public fun create_dapp_hub_for_testing(ctx: &mut TxContext): dubhe::dapp_service::DappHub {
105
+ dapp_system::create_dapp_hub_for_testing(ctx)
58
106
  }
107
+ ${n}
59
108
  }
60
- `;await h(s,t,"formatAndWriteMove")}import{existsSync as ce}from"fs";import pe from"node:fs/promises";async function ae(e,t){ce(`${t}/src/${e.name}/sources/systems`)||await pe.mkdir(`${t}/src/${e.name}/sources/systems`,{recursive:!0}),ce(`${t}/src/${e.name}/sources/tests`)||await pe.mkdir(`${t}/src/${e.name}/sources/tests`,{recursive:!0})}async function le(e,t,s){console.log(`
61
- \u{1F4E6} Starting Schema Error Generation...`);let n=`module ${e}::errors {
62
- ${Object.entries(t).map(([c,l])=>(console.log(` \u2514\u2500 ${c}: ${l}`),`#[error]
63
- const ${c.toUpperCase()}: vector<u8> = b"${l}";
64
- public fun ${c}_error(condition: bool) { assert!(condition, ${c.toUpperCase()}) }
65
- `)).join(`
66
- `)}
67
- }`;await h(n,`${s}/src/${e}/sources/codegen/errors.move`,"formatAndWriteMove")}async function _e(e,t){let s=`module ${e.name}::init_test {
68
- use sui::clock;
69
- use sui::test_scenario;
70
- use sui::test_scenario::Scenario;
71
- use dubhe::dapp_service::DappHub;
72
- use dubhe::dapp_system;
109
+ `;await E(r,t,"formatAndWriteMove")}async function Fe(e,t,s=1){let r=e.name==="dubhe"?`module ${e.name}::genesis {
110
+ use dubhe::dapp_service::DappHub;
111
+
112
+ // The framework genesis initialises the DappHub state via deploy_hook.
113
+ // No DappStorage is created for the framework itself \u2014 the framework is
114
+ // infrastructure, not a DApp.
115
+ public fun run(dapp_hub: &mut DappHub, ctx: &mut TxContext) {
116
+ ${e.name}::deploy_hook::run(dapp_hub, ctx);
117
+ }
73
118
 
74
- public fun deploy_dapp_for_testing(scenario: &mut Scenario): DappHub {
75
- let ctx = test_scenario::ctx(scenario);
76
- let clock = clock::create_for_testing(ctx);
77
- let mut dapp_hub = dapp_system::create_dapp_hub_for_testing(ctx);
78
- ${e.name!="dubhe"?"dubhe::genesis::run(&mut dapp_hub, &clock, ctx);":""}
79
- ${e.name}::genesis::run(&mut dapp_hub, &clock, ctx);
80
- clock::destroy_for_testing(clock);
81
- test_scenario::next_tx(scenario, ctx.sender());
82
- dapp_hub
83
- }
119
+ // Called during framework upgrades to run any custom migration logic.
120
+ // \`dubhe upgrade\` rewrites the region between the separator comments.
121
+ public(package) fun migrate(_dapp_hub: &mut DappHub, _ctx: &mut TxContext) {
122
+ // ==========================================
123
+ // Add custom migration logic here.
124
+ // ==========================================
125
+ }
84
126
  }
85
- `;await h(s,t,"formatAndWriteMove")}function x(e){return e==="dubhe"?"dapp_service":"dapp_system"}async function Z(e,t){console.log(`
86
- \u{1F4E6} Starting Components Generation...`);for(let[s,n]of Object.entries(e.components)){if(console.log(` \u2514\u2500 ${s}: ${JSON.stringify(n)}`),typeof n=="string"){let l=Ce(e.name,s,n,"Onchain");await h(l,`${t}/${s}.move`,"formatAndWriteMove");continue}if(Object.keys(n).length===0){let l=de(e.name,s,{fields:{entity_id:"address"},keys:["entity_id"],offchain:!1});await h(l,`${t}/${s}.move`,"formatAndWriteMove");continue}if(n.keys||(n.keys=["entity_id"],n.fields.entity_id||(n.fields={entity_id:"address",...n.fields})),n.keys&&n.keys.length>1)throw new Error(`Component '${s}' can only have one key, but found ${n.keys.length} keys: ${n.keys.join(", ")}`);let c=de(e.name,s,n);await h(c,`${t}/${s}.move`,"formatAndWriteMove")}}function Ce(e,t,s,n="Onchain"){let c=!T(s),l=c?`${be(s)}`:"";return`module ${e}::${t} {
87
- use sui::bcs::{to_bytes};
88
- use std::ascii::{string, String, into_bytes};
89
- use dubhe::table_id;
90
- use dubhe::dapp_service::{Self, DappHub};
127
+ `:`module ${e.name}::genesis {
128
+ use sui::clock::Clock;
129
+ use dubhe::dapp_service::{DappHub, DappStorage};
130
+ use ${e.name}::dapp_key;
91
131
  use dubhe::dapp_system;
92
- use ${e}::dapp_key;
93
- use ${e}::dapp_key::DappKey;
94
- ${c&&s!=="string"&&s!=="String"?` use ${e}::${l};
95
- use ${e}::${l}::{${s}};`:""}
132
+ use std::ascii::string;
96
133
 
97
- const TABLE_NAME: vector<u8> = b"${t}";
98
- const TABLE_TYPE: vector<u8> = b"Component";
99
- const OFFCHAIN: bool = ${n==="Offchain"};
134
+ // The one-shot guard is enforced inside dapp_system::create_dapp, which
135
+ // records the DappKey type in DappHub before returning DappStorage.
136
+ // genesis.move does not need to carry its own guard.
137
+ public fun run(dapp_hub: &mut DappHub, clock: &Clock, ctx: &mut TxContext) {
138
+ // create_dapp aborts with dapp_already_initialized_error on repeated calls.
139
+ let dapp_key = dapp_key::new();
140
+ let mut ds = dapp_system::create_dapp(dapp_key, dapp_hub, string(b"${e.name}"), string(b"${e.description}"), ${s}, clock, ctx);
100
141
 
101
- public fun get_table_id(): String {
102
- string(TABLE_NAME)
142
+ // Set up initial DApp state (e.g. default resource values).
143
+ ${e.name}::deploy_hook::run(&mut ds, ctx);
144
+
145
+ // Share DappStorage so every transaction can access it.
146
+ transfer::public_share_object(ds);
103
147
  }
104
148
 
105
- public fun get_key_schemas(): vector<String> {
106
- vector[string(b"address")]
149
+ // Called during contract upgrades to register newly added resource tables
150
+ // and run any custom migration logic. \`dubhe upgrade\` rewrites the region
151
+ // between the separator comments; do not edit that block manually.
152
+ public(package) fun migrate(_dapp_hub: &mut DappHub, _dapp_storage: &mut DappStorage, _ctx: &mut TxContext) {
153
+ // ==========================================
154
+ // Add custom migration logic here (e.g. initialise new resource defaults).
155
+ // migrate_to_vN in migrate.move calls this function automatically.
156
+ // ==========================================
107
157
  }
158
+ }
159
+ `;await E(r,t,"formatAndWriteMove")}function Ke(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`).replace(/^_/,"")}async function Ie(e,t){if(console.log(`
160
+ \u{1F4E6} Starting Enums Generation...`),!!e.enums)for(let[s,n]of Object.entries(e.enums)){console.log(` \u2514\u2500 ${s}: ${JSON.stringify(n)}`);let r=[...n].sort((d,l)=>d.localeCompare(l)),i=rt(e.name,s,r);await E(i,`${t}/${Ke(s)}.move`,"formatAndWriteMove")}}function rt(e,t,s){let n=s.map(r=>r.charAt(0).toUpperCase()+r.slice(1)).join(",");return`module ${e}::${Ke(t)} {
161
+ use sui::bcs::{BCS, to_bytes, peel_enum_tag};
108
162
 
109
- public fun get_value_schemas(): vector<String> {
110
- vector[string(b"${s}")]
163
+ public enum ${t} has copy, drop, store {
164
+ ${n}
111
165
  }
112
166
 
113
- public fun get_key_names(): vector<String> {
114
- vector[string(b"entity_id")]
167
+ ${s.map(r=>` public fun new_${r.toLowerCase()}(): ${t} {
168
+ ${t}::${r.charAt(0).toUpperCase()+r.slice(1)}
169
+ }`).join(`
170
+
171
+ `)}
172
+
173
+ public fun encode(self: ${t}): vector<u8> {
174
+ to_bytes(&self)
115
175
  }
116
176
 
117
- public fun get_value_names(): vector<String> {
118
- vector[string(b"value")]
177
+ public fun decode(bytes: &mut BCS): ${t} {
178
+ match(peel_enum_tag(bytes)) {
179
+ ${s.map((r,i)=>` ${i} => ${t}::${r.charAt(0).toUpperCase()+r.slice(1)},`).join(`
180
+ `)}
181
+ _ => abort,
182
+ }
183
+ }
184
+ }`}function Me(e){return e==="dubhe"?"dapp_service":"dapp_system"}function R(e){return e!=="dubhe"?"dapp_key::new(), ":""}function z(e,t){return""}function H(e,t){return""}function Pe(e){return e?"DappStorage":"UserStorage"}function Re(e){return e?"dapp_storage":"user_storage"}function le(e,t){let s=Me(e);return t?{set_record:`${s}::set_global_record`,set_field:`${s}::set_global_field`,get_field:`${s}::get_global_field`,has_record:`${s}::has_global_record`,ensure_has:`${s}::ensure_has_global_record`,ensure_has_not:`${s}::ensure_has_not_global_record`,delete_record:`${s}::delete_global_record`,delete_field:`${s}::delete_global_field`}:{set_record:`${s}::set_record`,set_field:`${s}::set_field`,get_field:`${s}::get_field`,has_record:`${s}::has_record`,ensure_has:`${s}::ensure_has_record`,ensure_has_not:`${s}::ensure_has_not_record`,delete_record:`${s}::delete_record`,delete_field:`${s}::delete_field`}}async function Le(e,t){if(console.log(`
185
+ \u{1F4E6} Starting Resources Generation...`),!!e.resources)for(let[s,n]of Object.entries(e.resources)){if(console.log(` \u2514\u2500 ${s}: ${JSON.stringify(n)}`),typeof n=="string"){let l=nt(e.name,s,n,"Onchain");await E(l,`${t}/${s}.move`,"formatAndWriteMove");continue}if(!n.fields||Object.keys(n.fields).length===0)throw new Error(`Resource '${s}' must have fields defined, but found empty object`);n.keys||(n.keys=[]);let r=ot(e.name,s,n),i=at(e,s,n),d=i?r.replace(/^}$/m,`
186
+ ${i}
187
+ }`):r;await E(d,`${t}/${s}.move`,"formatAndWriteMove")}}function nt(e,t,s,n="Onchain"){let r=!B(s),i=r?`${de(s)}`:"",d=n==="Offchain",l=!1,u=Pe(l),_=Re(l),g=le(e,l),y=d?"":`
188
+ public fun has(${_}: &${u}): bool {
189
+ let mut key_tuple = vector::empty();
190
+ key_tuple.push_back(TABLE_NAME);
191
+ ${g.has_record}<DappKey>(${_}, key_tuple)
119
192
  }
120
193
 
121
- public(package) fun register_table(dapp_hub: &mut DappHub, ctx: &mut TxContext) {
122
- let dapp_key = dapp_key::new();
123
- ${x(e)}::register_table(
124
- dapp_hub,
125
- dapp_key,
126
- string(TABLE_TYPE),
127
- get_table_id(),
128
- get_key_schemas(),
129
- get_key_names(),
130
- get_value_schemas(),
131
- get_value_names(),
132
- OFFCHAIN,
133
- ctx
134
- );
194
+ public fun ensure_has(${_}: &${u}) {
195
+ let mut key_tuple = vector::empty();
196
+ key_tuple.push_back(TABLE_NAME);
197
+ ${g.ensure_has}<DappKey>(${_}, key_tuple)
135
198
  }
136
199
 
137
- public fun has(dapp_hub: &DappHub, entity_id: address): bool {
200
+ public fun ensure_has_not(${_}: &${u}) {
138
201
  let mut key_tuple = vector::empty();
139
- key_tuple.push_back(to_bytes(&entity_id));
140
- ${x(e)}::has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
202
+ key_tuple.push_back(TABLE_NAME);
203
+ ${g.ensure_has_not}<DappKey>(${_}, key_tuple)
141
204
  }
142
205
 
143
- public(package) fun delete(dapp_hub: &mut DappHub, entity_id: address) {
206
+ public(package) fun delete(${_}: &mut ${u}, ctx: &TxContext) {
144
207
  let mut key_tuple = vector::empty();
145
- key_tuple.push_back(to_bytes(&entity_id));
146
- ${x(e)}::delete_record<DappKey>(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, OFFCHAIN);
208
+ key_tuple.push_back(TABLE_NAME);
209
+ ${g.delete_record}<DappKey>(${R(e)}${_}, key_tuple, vector[b"value"], ctx);
147
210
  }
148
211
 
149
- public fun get(dapp_hub: &DappHub, entity_id: address): (${s==="string"||s==="String"?"String":s}) {
212
+ public fun get(${_}: &${u}): (${s==="string"||s==="String"?"String":s}) {
150
213
  let mut key_tuple = vector::empty();
151
- key_tuple.push_back(to_bytes(&entity_id));
152
- let value_tuple = ${x(e)}::get_record<DappKey>(dapp_hub, get_table_id(), key_tuple);
153
- let mut bsc_type = sui::bcs::new(value_tuple);
154
- ${s==="string"||s==="String"?"let value = dubhe::bcs::peel_string(&mut bsc_type);":s==="vector<String>"?"let value = dubhe::bcs::peel_vec_string(&mut bsc_type);":c?`let value = ${e}::${l}::decode(&mut bsc_type);`:`let value = sui::bcs::peel_${L(s)}(&mut bsc_type);`}
214
+ key_tuple.push_back(TABLE_NAME);
215
+ let value_raw = ${g.get_field}<DappKey>(${_}, key_tuple, b"value");
216
+ let mut value_bcs = sui::bcs::new(value_raw);
217
+ let value = ${J(e,s,"value_bcs",r?[{type:s,module:i}]:[])};
155
218
  (value)
156
219
  }
220
+ `,o=l?"use dubhe::dapp_service::DappStorage;":"use dubhe::dapp_service::UserStorage;",b=r&&s!=="string"&&s!=="String";return`module ${e}::${t} {${!b?`
221
+ use sui::bcs::{to_bytes};`:""}${s==="string"||s==="String"?`
222
+ use std::ascii::{String, into_bytes};`:s==="vector<String>"?`
223
+ use std::ascii::String;`:""}
224
+ ${o}
225
+ use dubhe::dapp_system;
226
+ use ${e}::dapp_key;
227
+ use ${e}::dapp_key::DappKey;
228
+ ${b?` use ${e}::${i}::{${s}};`:""}
157
229
 
158
- public(package) fun set(dapp_hub: &mut DappHub, entity_id: address, value: ${s==="string"||s==="String"?"String":s}) {
230
+ const TABLE_NAME: vector<u8> = b"${t}";
231
+ const OFFCHAIN: bool = ${n==="Offchain"};
232
+
233
+ ${y}
234
+ public(package) fun set(${H(e,l)}${_}: &mut ${u}, value: ${s==="string"||s==="String"?"String":s}, ctx: &mut TxContext) {
159
235
  let mut key_tuple = vector::empty();
160
- key_tuple.push_back(to_bytes(&entity_id));
236
+ key_tuple.push_back(TABLE_NAME);
237
+ let field_names = vector[b"value"];
161
238
  let value_tuple = encode(value);
162
- ${x(e)}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
239
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN, ctx);
163
240
  }
164
241
 
165
242
  public fun encode(value: ${s==="string"||s==="String"?"String":s}): vector<vector<u8>> {
166
243
  let mut value_tuple = vector::empty();
167
- value_tuple.push_back(${s==="string"||s==="String"?"to_bytes(&into_bytes(value))":s==="vector<String>"?"to_bytes(&value)":c?`${e}::${l}::encode(value)`:"to_bytes(&value)"});
244
+ value_tuple.push_back(${s==="string"||s==="String"?"to_bytes(&into_bytes(value))":s==="vector<String>"?"to_bytes(&value)":r?`${e}::${i}::encode(value)`:"to_bytes(&value)"});
168
245
  value_tuple
169
246
  }
170
- }`}function be(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`).replace(/^_/,"")}function de(e,t,s){let n=s.fields,c=s.keys||["entity_id"],S=s.offchain||!1?"Offchain":"Onchain",D=Object.keys(n).every(p=>c.includes(p)),$=Object.entries(n).filter(([p])=>!c.includes(p)).map(([p])=>p),v=$.length===1,C=Object.entries(n).filter(([p,A])=>!T(A)&&A!=="string"&&A!=="String").map(([p,A])=>({type:A,module:`${be(A)}`})).filter((p,A,a)=>a.findIndex(w=>w.type===p.type)===A),O=Oe(e,t,n,c,!D&&!v,C,S);if(D||v)return`module ${e}::${t} {
171
- use sui::bcs::{to_bytes};
172
- use std::ascii::{string, String, into_bytes};
173
- use dubhe::table_id;
174
- use dubhe::dapp_service::{Self, DappHub};
247
+ }`}function de(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`).replace(/^_/,"")}function ot(e,t,s){let n=s.fields,r=s.keys||[],i=s.offchain||!1,d=s.global||!1,l=i?"Offchain":"Onchain",u=d,_=Pe(u),g=Re(u),y=le(e,u),o=Object.keys(n).every(m=>r.includes(m)),b=Object.entries(n).filter(([m])=>!r.includes(m)),p=b.map(([m])=>m),h=p.length===1,a=b.filter(([m,C])=>!B(C)&&C!=="string"&&C!=="String").map(([m,C])=>({type:C,module:`${de(C)}`})).filter((m,C,W)=>W.findIndex(Y=>Y.type===m.type)===C),$=Object.entries(n).filter(([m,C])=>!B(C)&&C!=="string"&&C!=="String").map(([m,C])=>({type:C,module:`${de(C)}`})).filter((m,C,W)=>W.findIndex(Y=>Y.type===m.type)===C),x=it(e,t,n,r,!o&&!h,a,l,u,_,g,y),k=u?"use dubhe::dapp_service::DappStorage;":s.listable?"use dubhe::dapp_service::{UserStorage, DappStorage};":"use dubhe::dapp_service::UserStorage;",T=s.reactive?`
248
+ use dubhe::dapp_service::ScenePermit;`:"",w=Object.values(n),A=p.filter(m=>{let C=n[m];return B(C)||C==="string"||C==="String"}).length>0||r.length>0?`
249
+ use sui::bcs::{to_bytes};`:"",D=w.some(m=>m==="string"||m==="String"),v=w.some(m=>m==="vector<String>"),K=p.some(m=>{let C=n[m];return C==="string"||C==="String"}),P=K?`
250
+ use std::ascii::{String, into_bytes};`:D||v?`
251
+ use std::ascii::String;`:"",c=K?`
252
+ use std::ascii::{string, String, into_bytes};`:D||v?`
253
+ use std::ascii::String;`:"";if(o||h)return`module ${e}::${t} {${A}${P}
254
+ ${k}${T}
175
255
  use dubhe::dapp_system;
176
256
  use ${e}::dapp_key;
177
257
  use ${e}::dapp_key::DappKey;
178
- ${C.length>0?C.map(p=>` use ${e}::${p.module};
179
- use ${e}::${p.module}::{${p.type}};`).join(`
258
+ ${$.length>0?$.map(m=>` use ${e}::${m.module}::{${m.type}};`).join(`
180
259
  `):""}
181
260
 
182
261
  const TABLE_NAME: vector<u8> = b"${t}";
183
- const TABLE_TYPE: vector<u8> = b"Component";
184
- const OFFCHAIN: bool = ${S==="Offchain"};
185
- ${O}
186
- }`;let i=$.map(p=>` ${p}: ${n[p]==="string"||n[p]==="String"?"String":n[p]==="vector<String>"?"vector<String>":n[p]},`).join(`
187
- `),g=$.map(p=>`${p}: ${n[p]==="string"||n[p]==="String"?"String":n[p]==="vector<String>"?"vector<String>":n[p]}`).join(", "),b=$.map(p=>` ${p},`).join(`
188
- `),f=$.map(p=>` public fun ${p}(self: &${j(t)}): ${n[p]==="string"||n[p]==="String"?"String":n[p]==="vector<String>"?"vector<String>":n[p]} {
189
- self.${p}
262
+ const OFFCHAIN: bool = ${i};
263
+
264
+ ${x}
265
+ }`;let f=p.map(m=>` ${m}: ${n[m]==="string"||n[m]==="String"?"String":n[m]==="vector<String>"?"vector<String>":n[m]},`).join(`
266
+ `),S=p.map(m=>`${m}: ${n[m]==="string"||n[m]==="String"?"String":n[m]==="vector<String>"?"vector<String>":n[m]}`).join(", "),j=p.map(m=>` ${m},`).join(`
267
+ `),M=p.map(m=>` public fun ${m}(self: &${I(t)}): ${n[m]==="string"||n[m]==="String"?"String":n[m]==="vector<String>"?"vector<String>":n[m]} {
268
+ self.${m}
190
269
  }`).join(`
191
270
 
192
- `),m=$.map(p=>` public fun update_${p}(self: &mut ${j(t)}, ${p}: ${n[p]==="string"||n[p]==="String"?"String":n[p]==="vector<String>"?"vector<String>":n[p]}) {
193
- self.${p} = ${p}
271
+ `),ee=p.map(m=>` public fun update_${m}(self: &mut ${I(t)}, ${m}: ${n[m]==="string"||n[m]==="String"?"String":n[m]==="vector<String>"?"vector<String>":n[m]}) {
272
+ self.${m} = ${m}
194
273
  }`).join(`
195
274
 
196
- `);return`module ${e}::${t} {
197
- use sui::bcs::{to_bytes};
198
- use std::ascii::{string, String, into_bytes};
199
- use dubhe::table_id;
200
- use dubhe::dapp_service::{Self, DappHub};
275
+ `);return`module ${e}::${t} {${A}${c}
276
+ ${k}${T}
201
277
  use dubhe::dapp_system;
202
278
  use ${e}::dapp_key;
203
279
  use ${e}::dapp_key::DappKey;
204
- ${C.length>0?C.map(p=>` use ${e}::${p.module};
205
- use ${e}::${p.module}::{${p.type}};`).join(`
280
+ ${$.length>0?$.map(m=>` use ${e}::${m.module}::{${m.type}};`).join(`
206
281
  `):""}
207
282
 
208
283
  const TABLE_NAME: vector<u8> = b"${t}";
209
- const TABLE_TYPE: vector<u8> = b"Component";
210
- const OFFCHAIN: bool = ${S==="Offchain"};
211
-
212
- public struct ${j(t)} has copy, drop, store {
213
- ${i}
214
- }
215
-
216
- public fun new(${g}): ${j(t)} {
217
- ${j(t)} {
218
- ${b}
219
- }
220
- }
284
+ const OFFCHAIN: bool = ${i};
221
285
 
286
+ public struct ${I(t)} has copy, drop, store {
222
287
  ${f}
223
-
224
- ${m}
225
-
226
- ${O}
227
- }`}function T(e){return["address","bool","u8","u16","u32","u64","u128","u256","string","String","vector<address>","vector<bool>","vector<u8>","vector<u16>","vector<u32>","vector<u64>","vector<u128>","vector<u256>","vector<String>","vector<vector<address>>","vector<vector<bool>>","vector<vector<u8>>","vector<vector<u16>>","vector<vector<u32>>","vector<vector<u64>>","vector<vector<u128>>","vector<vector<u256>>"].includes(e)}function Oe(e,t,s,n,c=!0,l=[],S="Onchain"){let D=n.reduce((u,y)=>({...u,[y]:s[y]}),{}),o=Object.entries(s).filter(([u])=>!n.includes(u)).reduce((u,[y,r])=>({...u,[y]:r}),{}),$=Object.keys(D),v=Object.keys(o),C=Object.keys(s).every(u=>n.includes(u)),O=v.length===1,i=n.length>0?n.map(u=>`${u}: ${s[u]}`).join(", "):"",g=n.length>0?`let mut key_tuple = vector::empty();
228
- ${n.map(u=>`key_tuple.push_back(to_bytes(&${u}));`).join(`
229
- `)}`:"let key_tuple = vector::empty();",b=` public fun get_table_id(): String {
230
- string(TABLE_NAME)
231
288
  }
232
289
 
233
- public fun get_key_schemas(): vector<String> {
234
- vector[${n.map(u=>`string(b"${s[u]}")`).join(", ")}]
290
+ public fun new(${S}): ${I(t)} {
291
+ ${I(t)} {
292
+ ${j}
293
+ }
235
294
  }
236
295
 
237
- public fun get_value_schemas(): vector<String> {
238
- vector[${Object.values(o).map(u=>`string(b"${u}")`).join(", ")}]
239
- }
296
+ ${M}
240
297
 
241
- public fun get_key_names(): vector<String> {
242
- vector[${n.map(u=>`string(b"${u}")`).join(", ")}]
243
- }
298
+ ${ee}
244
299
 
245
- public fun get_value_names(): vector<String> {
246
- vector[${v.map(u=>`string(b"${u}")`).join(", ")}]
247
- }`,f=` public(package) fun register_table(dapp_hub: &mut DappHub, ctx: &mut TxContext) {
248
- let dapp_key = dapp_key::new();
249
- ${x(e)}::register_table(
250
- dapp_hub,
251
- dapp_key,
252
- string(TABLE_TYPE),
253
- get_table_id(),
254
- get_key_schemas(),
255
- get_key_names(),
256
- get_value_schemas(),
257
- get_value_names(),
258
- OFFCHAIN,
259
- ctx
260
- );
261
- }`,m=` public fun has(dapp_hub: &DappHub${i?", "+i:""}): bool {
262
- ${g}
263
- ${x(e)}::has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
300
+ ${x}
301
+ }`}function B(e){return["address","bool","u8","u16","u32","u64","u128","u256","string","String","vector<address>","vector<bool>","vector<u8>","vector<u16>","vector<vector<u8>>","vector<u32>","vector<u64>","vector<u128>","vector<u256>","vector<String>"].includes(e)}function J(e,t,s,n){let r=!B(t),i=r?n.find(d=>d.type===t):null;return t==="string"||t==="String"?`dubhe::bcs::peel_string(&mut ${s})`:t==="vector<String>"?`dubhe::bcs::peel_vec_string(&mut ${s})`:r&&i?`${e}::${i.module}::decode(&mut ${s})`:`sui::bcs::peel_${ge(t)}(&mut ${s})`}function Ue(e,t,s,n,r,i,d){let l=`${n}_raw`,u=`${n}_bcs`;return[`let ${l} = ${t.get_field}<DappKey>(${s}, key_tuple, b"${n}");`,`let mut ${u} = sui::bcs::new(${l});`,`let ${n} = ${J(e,r,u,d)};`].join(`
302
+ `)}function it(e,t,s,n,r=!0,i=[],d="Onchain",l=!1,u="UserStorage",_="user_storage",g=le("dubhe",!1)){let y=Object.entries(s).filter(([c])=>!n.includes(c)).reduce((c,[f,S])=>({...c,[f]:S}),{}),o=Object.keys(y),b=Object.keys(s).every(c=>n.includes(c)),p=o.length===1,h=d==="Offchain",a=n.length>0?n.map(c=>`${c}: ${s[c]}`).join(", "):"",$=n.length>0?`let mut key_tuple = vector::empty();
303
+ key_tuple.push_back(TABLE_NAME);
304
+ ${n.map(c=>`key_tuple.push_back(to_bytes(&${c}));`).join(`
305
+ `)}`:`let mut key_tuple = vector::empty();
306
+ key_tuple.push_back(TABLE_NAME);`,x=l?"":", ctx: &mut TxContext",k=l?"":", ctx",T=h?"":` public fun has(${_}: &${u}${a?", ":""}${a}): bool {
307
+ ${$}
308
+ ${g.has_record}<DappKey>(${_}, key_tuple)
264
309
  }
265
310
 
266
- public fun ensure_has(dapp_hub: &DappHub${i?", "+i:""}) {
267
- ${g}
268
- ${x(e)}::ensure_has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
311
+ public fun ensure_has(${_}: &${u}${a?", ":""}${a}) {
312
+ ${$}
313
+ ${g.ensure_has}<DappKey>(${_}, key_tuple)
269
314
  }
270
315
 
271
- public fun ensure_not_has(dapp_hub: &DappHub${i?", "+i:""}) {
272
- ${g}
273
- ${x(e)}::ensure_not_has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
316
+ public fun ensure_has_not(${_}: &${u}${a?", ":""}${a}) {
317
+ ${$}
318
+ ${g.ensure_has_not}<DappKey>(${_}, key_tuple)
274
319
  }
275
- `,p=` public(package) fun delete(dapp_hub: &mut DappHub${i?", "+i:""}) {
276
- ${g}
277
- ${x(e)}::delete_record<DappKey>(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, OFFCHAIN);
278
- }`,A=O?"":v.map(u=>{let y=v.indexOf(u),r=s[u],_=!T(r),d=_?l.find(F=>F.type===r):null;return` public fun get_${u}(dapp_hub: &DappHub${i?", "+i:""}): ${r==="string"||r==="String"?"String":r} {
279
- ${g}
280
- let value = ${x(e)}::get_field<DappKey>(dapp_hub, get_table_id(), key_tuple, ${y});
281
- let mut bsc_type = sui::bcs::new(value);
282
- ${r==="string"||r==="String"?`let ${u} = dubhe::bcs::peel_string(&mut bsc_type);`:r==="vector<String>"?`let ${u} = dubhe::bcs::peel_vec_string(&mut bsc_type);`:_?`let ${u} = ${e}::${d?.module}::decode(&mut bsc_type);`:`let ${u} = sui::bcs::peel_${L(r)}(&mut bsc_type);`}
283
- ${u}
320
+ `,w=`vector[${o.map(c=>`b"${c}"`).join(", ")}]`,F=h?"":` public(package) fun delete(${_}: &mut ${u}${a?", ":""}${a}${l?"":", ctx: &TxContext"}) {
321
+ ${$}
322
+ ${g.delete_record}<DappKey>(${R(e)}${_}, key_tuple, ${w}${l?"":", ctx"});
323
+ }`,O=!p&&!h?o.map(c=>{let f=s[c],S=!B(f),j=S?i.find(M=>M.type===f):null;return` public fun get_${c}(${_}: &${u}${a?", ":""}${a}): ${f==="string"||f==="String"?"String":f==="vector<String>"?"vector<String>":f} {
324
+ ${$}
325
+ let ${c}_raw = ${g.get_field}<DappKey>(${_}, key_tuple, b"${c}");
326
+ let mut ${c}_bcs = sui::bcs::new(${c}_raw);
327
+ let ${c} = ${J(e,f,`${c}_bcs`,i)};
328
+ ${c}
284
329
  }
285
330
 
286
- public(package) fun set_${u}(dapp_hub: &mut DappHub${i?", "+i:""}, ${u}: ${r==="string"||r==="String"?"String":r}) {
287
- ${g}
288
- let value = ${r==="string"||r==="String"?`to_bytes(&into_bytes(${u}))`:r==="vector<String>"?`to_bytes(&${u})`:_?`${e}::${d?.module}::encode(${u})`:`to_bytes(&${u})`};
289
- ${x(e)}::set_field(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, ${y}, value, OFFCHAIN);
331
+ public(package) fun set_${c}(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, ${c}: ${f==="string"||f==="String"?"String":f==="vector<String>"?"vector<String>":f}${x}) {
332
+ ${$}
333
+ let value = ${f==="string"||f==="String"?`to_bytes(&into_bytes(${c}))`:f==="vector<String>"?`to_bytes(&${c})`:S?`${e}::${j?.module}::encode(${c})`:`to_bytes(&${c})`};
334
+ ${g.set_field}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, b"${c}", value${k});
290
335
  }`}).join(`
291
336
 
292
- `),a=C?` public(package) fun set(dapp_hub: &mut DappHub${i?", "+i:""}) {
293
- ${g}
294
- let value_tuple = vector::empty();
295
- ${x(e)}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
296
- }`:O?` public fun get(dapp_hub: &DappHub${i?", "+i:""}): ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]} {
297
- ${g}
298
- let value = ${x(e)}::get_field<DappKey>(dapp_hub, get_table_id(), key_tuple, 0);
299
- let mut bsc_type = sui::bcs::new(value);
300
- ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"let value = dubhe::bcs::peel_string(&mut bsc_type);":Object.values(o)[0]==="vector<String>"?"let value = dubhe::bcs::peel_vec_string(&mut bsc_type);":T(Object.values(o)[0])?`let value = sui::bcs::peel_${L(Object.values(o)[0])}(&mut bsc_type);`:`let value = ${e}::${l.find(u=>u.type===Object.values(o)[0])?.module}::decode(&mut bsc_type);`}
337
+ `):"",A=`vector[${o.map(c=>`b"${c}"`).join(", ")}]`,D=b?` public(package) fun set(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}${x}) {
338
+ ${$}
339
+ let field_names: vector<vector<u8>> = vector[];
340
+ let value_tuple: vector<vector<u8>> = vector[];
341
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
342
+ }`:p?h?` public(package) fun set(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, value: ${Object.values(y)[0]==="string"||Object.values(y)[0]==="String"?"String":Object.values(y)[0]}${x}) {
343
+ ${$}
344
+ let field_names = vector[b"${o[0]}"];
345
+ let value_tuple = encode(value);
346
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
347
+ }`:` public fun get(${_}: &${u}${a?", ":""}${a}): ${Object.values(y)[0]==="string"||Object.values(y)[0]==="String"?"String":Object.values(y)[0]} {
348
+ ${$}
349
+ let ${o[0]}_raw = ${g.get_field}<DappKey>(${_}, key_tuple, b"${o[0]}");
350
+ let mut ${o[0]}_bcs = sui::bcs::new(${o[0]}_raw);
351
+ let value = ${J(e,Object.values(y)[0],`${o[0]}_bcs`,i)};
301
352
  value
302
353
  }
303
354
 
304
- public(package) fun set(dapp_hub: &mut DappHub${i?", "+i:""}, value: ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]}) {
305
- ${g}
355
+ public(package) fun set(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, value: ${Object.values(y)[0]==="string"||Object.values(y)[0]==="String"?"String":Object.values(y)[0]}${x}) {
356
+ ${$}
357
+ let field_names = vector[b"${o[0]}"];
306
358
  let value_tuple = encode(value);
307
- ${x(e)}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
308
- }`:` public fun get(dapp_hub: &DappHub${i?", "+i:""}): (${Object.values(o).map(u=>u==="string"||u==="String"?"String":u).join(", ")}) {
309
- ${g}
310
- let value_tuple = ${x(e)}::get_record<DappKey>(dapp_hub, get_table_id(), key_tuple);
311
- let mut bsc_type = sui::bcs::new(value_tuple);
312
- ${v.map(u=>{let y=s[u],r=!T(y),_=r?l.find(d=>d.type===y):null;return`let ${u} = ${y==="string"||y==="String"?"dubhe::bcs::peel_string(&mut bsc_type)":y==="vector<String>"?"dubhe::bcs::peel_vec_string(&mut bsc_type)":r?`${e}::${_?.module}::decode(&mut bsc_type)`:`sui::bcs::peel_${L(y)}(&mut bsc_type)`};`}).join(`
359
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
360
+ }`:h?` public(package) fun set(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, ${o.map(c=>`${c}: ${s[c]==="string"||s[c]==="String"?"String":s[c]}`).join(", ")}${x}) {
361
+ ${$}
362
+ let field_names = ${A};
363
+ let value_tuple = encode(${o.join(", ")});
364
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
365
+ }`:` public fun get(${_}: &${u}${a?", ":""}${a}): (${Object.values(y).map(c=>c==="string"||c==="String"?"String":c).join(", ")}) {
366
+ ${$}
367
+ ${o.map((c,f)=>Ue(e,g,_,c,s[c],f,i)).join(`
313
368
  `)}
314
- (${v.join(", ")})
369
+ (${o.join(", ")})
315
370
  }
316
371
 
317
- public(package) fun set(dapp_hub: &mut DappHub${i?", "+i:""}, ${v.map(u=>`${u}: ${s[u]==="string"||s[u]==="String"?"String":s[u]}`).join(", ")}) {
318
- ${g}
319
- let value_tuple = encode(${v.join(", ")});
320
- ${x(e)}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
321
- }`,w=c?` public fun get_struct(dapp_hub: &DappHub${i?", "+i:""}): ${j(t)} {
322
- ${g}
323
- let value_tuple = ${x(e)}::get_record<DappKey>(dapp_hub, get_table_id(), key_tuple);
324
- decode(value_tuple)
372
+ public(package) fun set(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, ${o.map(c=>`${c}: ${s[c]==="string"||s[c]==="String"?"String":s[c]}`).join(", ")}${x}) {
373
+ ${$}
374
+ let field_names = ${A};
375
+ let value_tuple = encode(${o.join(", ")});
376
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
377
+ }`,v=r?h?` public(package) fun set_struct(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, ${t}: ${I(t)}${x}) {
378
+ ${$}
379
+ let field_names = ${A};
380
+ let value_tuple = encode_struct(${t});
381
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
382
+ }`:` public fun get_struct(${_}: &${u}${a?", ":""}${a}): ${I(t)} {
383
+ ${$}
384
+ ${o.map((c,f)=>Ue(e,g,_,c,s[c],f,i)).join(`
385
+ `)}
386
+ ${I(t)} { ${o.join(", ")} }
325
387
  }
326
388
 
327
- public(package) fun set_struct(dapp_hub: &mut DappHub${i?", "+i:""}, ${t}: ${j(t)}) {
328
- ${g}
389
+ public(package) fun set_struct(${H(e,l)}${_}: &mut ${u}${a?", ":""}${a}, ${t}: ${I(t)}${x}) {
390
+ ${$}
391
+ let field_names = ${A};
329
392
  let value_tuple = encode_struct(${t});
330
- ${x(e)}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
331
- }`:"",B=O?` public fun encode(value: ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]}): vector<vector<u8>> {
393
+ ${g.set_record}<DappKey>(${R(e)}${z(e,l)}${_}, key_tuple, field_names, value_tuple, OFFCHAIN${k});
394
+ }`:"",K=p?` public fun encode(value: ${Object.values(y)[0]==="string"||Object.values(y)[0]==="String"?"String":Object.values(y)[0]}): vector<vector<u8>> {
332
395
  let mut value_tuple = vector::empty();
333
- value_tuple.push_back( ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"to_bytes(&into_bytes(value))":Object.values(o)[0]==="vector<String>"||T(Object.values(o)[0])?"to_bytes(&value)":`${e}::${l.find(u=>u.type===Object.values(o)[0])?.module}::encode(value)`});
396
+ value_tuple.push_back(${Object.values(y)[0]==="string"||Object.values(y)[0]==="String"?"to_bytes(&into_bytes(value))":Object.values(y)[0]==="vector<String>"||B(Object.values(y)[0])?"to_bytes(&value)":`${e}::${i.find(c=>c.type===Object.values(y)[0])?.module}::encode(value)`});
334
397
  value_tuple
335
- }`:c?` public fun encode(${v.map(u=>`${u}: ${s[u]==="string"||s[u]==="String"?"String":s[u]}`).join(", ")}): vector<vector<u8>> {
398
+ }`:r?h?` public fun encode(${o.map(c=>`${c}: ${s[c]==="string"||s[c]==="String"?"String":s[c]}`).join(", ")}): vector<vector<u8>> {
336
399
  let mut value_tuple = vector::empty();
337
- ${v.map(u=>{let y=s[u],r=!T(y),_=r?l.find(d=>d.type===y):null;return`value_tuple.push_back(${y==="string"||y==="String"?`to_bytes(&into_bytes(${u}))`:y==="vector<String>"?`to_bytes(&${u})`:r?`${e}::${_?.module}::encode(${u})`:`to_bytes(&${u})`});`}).join(`
400
+ ${o.map(c=>{let f=s[c],S=!B(f),j=S?i.find(M=>M.type===f):null;return`value_tuple.push_back(${f==="string"||f==="String"?`to_bytes(&into_bytes(${c}))`:f==="vector<String>"?`to_bytes(&${c})`:S?`${e}::${j?.module}::encode(${c})`:`to_bytes(&${c})`});`}).join(`
338
401
  `)}
339
402
  value_tuple
340
403
  }
341
404
 
342
- public fun encode_struct(${t}: ${j(t)}): vector<vector<u8>> {
343
- encode(${v.map(u=>`${t}.${u}`).join(", ")})
405
+ public fun encode_struct(${t}: ${I(t)}): vector<vector<u8>> {
406
+ encode(${o.map(c=>`${t}.${c}`).join(", ")})
407
+ }`:` public fun encode(${o.map(c=>`${c}: ${s[c]==="string"||s[c]==="String"?"String":s[c]}`).join(", ")}): vector<vector<u8>> {
408
+ let mut value_tuple = vector::empty();
409
+ ${o.map(c=>{let f=s[c],S=!B(f),j=S?i.find(M=>M.type===f):null;return`value_tuple.push_back(${f==="string"||f==="String"?`to_bytes(&into_bytes(${c}))`:f==="vector<String>"?`to_bytes(&${c})`:S?`${e}::${j?.module}::encode(${c})`:`to_bytes(&${c})`});`}).join(`
410
+ `)}
411
+ value_tuple
344
412
  }
345
413
 
346
- public fun decode(data: vector<u8>): ${j(t)} {
347
- let mut bsc_type = sui::bcs::new(data);
348
- ${v.map(u=>{let y=s[u],r=!T(y),_=r?l.find(d=>d.type===y):null;return`let ${u} = ${y==="string"||y==="String"?"string(sui::bcs::peel_vec_u8(&mut bsc_type))":y==="vector<String>"?"dubhe::bcs::peel_vec_string(&mut bsc_type)":r?`${e}::${_?.module}::decode(&mut bsc_type)`:`sui::bcs::peel_${L(y)}(&mut bsc_type)`};`}).join(`
414
+ public fun encode_struct(${t}: ${I(t)}): vector<vector<u8>> {
415
+ encode(${o.map(c=>`${t}.${c}`).join(", ")})
416
+ }
417
+
418
+ public fun decode(data: vector<u8>): ${I(t)} {
419
+ let mut bcs_type = sui::bcs::new(data);
420
+ ${o.map(c=>{let f=s[c],S=!B(f),j=S?i.find(M=>M.type===f):null;return`let ${c} = ${f==="string"||f==="String"?"string(sui::bcs::peel_vec_u8(&mut bcs_type))":f==="vector<String>"?"dubhe::bcs::peel_vec_string(&mut bcs_type)":S?`${e}::${j?.module}::decode(&mut bcs_type)`:`sui::bcs::peel_${ge(f)}(&mut bcs_type)`};`}).join(`
349
421
  `)}
350
- ${j(t)} {
351
- ${v.map(u=>`${u},`).join(`
422
+ ${I(t)} {
423
+ ${o.map(c=>`${c},`).join(`
352
424
  `)}
353
425
  }
354
- }`:"";return`${b}
426
+ }`:"";return[T,F,O,D,v,K].filter(c=>c.trim().length>0).join(`
355
427
 
356
- ${f}
428
+ `)}function I(e){return e.split("_").map((t,s)=>/^\d+$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function ge(e){if(e.startsWith("vector<")){let t=e.slice(7,-1);return t==="vector<u8>"?"vec_vec_u8":t==="String"?"vec_string":`vec_${ge(t)}`}switch(e){case"u8":return"u8";case"u16":return"u16";case"u32":return"u32";case"u64":return"u64";case"u128":return"u128";case"u256":return"u256";case"bool":return"bool";case"address":return"address";case"String":return"string";default:return e}}function at(e,t,s){let n=[],r=e.name,i=Me(r),d=R(r),l=s.fields,u=s.keys??[],_=Object.entries(l).filter(([o])=>!u.includes(o)),g=_.map(([o])=>o),y=u.length>0?u.map(o=>`${o}: ${l[o]}`).join(", "):"";if(s.fungible&&g.length===1){let[o,b]=_[0];n.push(`
429
+ // \u2500\u2500\u2500 fungible add / sub \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
430
+ #[error]
431
+ const EInsufficientAmount: vector<u8> = b"Insufficient amount";
357
432
 
358
- ${m}
433
+ public(package) fun add(user_storage: &mut UserStorage, amount: ${b}, ctx: &mut TxContext) {
434
+ let current = if (has(user_storage)) { get(user_storage) } else { 0 };
435
+ set(user_storage, current + amount, ctx);
436
+ }
359
437
 
360
- ${p}
438
+ public(package) fun sub(user_storage: &mut UserStorage, amount: ${b}, ctx: &mut TxContext) {
439
+ let current = get(user_storage);
440
+ assert!(current >= amount, EInsufficientAmount);
441
+ set(user_storage, current - amount, ctx);
442
+ }`)}if(u.length>0&&!s.offchain&&!s.global){let o=u.map($=>`${$}: ${l[$]}`).join(", "),b=g.map($=>`${$}: ${l[$]}`).join(", "),p=[o,b].filter(Boolean).join(", "),h=u.join(", "),a=[...u,...g].join(", ");n.push(`
443
+ // \u2500\u2500\u2500 keys: mint (developer provides keys; framework ensures no duplicate) \u2500
444
+ // Choosing the ID strategy (fresh address, counter, coordinate pack, etc.)
445
+ // is intentionally left to the caller.
446
+ public(package) fun mint(
447
+ user_storage: &mut UserStorage,
448
+ ${p},
449
+ ctx: &mut TxContext,
450
+ ) {
451
+ ensure_has_not(user_storage, ${h});
452
+ set(user_storage, ${a}, ctx);
453
+ }`)}if(s.reactive){let o=u.length>0?`let mut key_tuple = vector::empty();
454
+ key_tuple.push_back(TABLE_NAME);
455
+ ${u.map(b=>`key_tuple.push_back(sui::bcs::to_bytes(&${b}));`).join(`
456
+ `)}`:`let mut key_tuple = vector::empty();
457
+ key_tuple.push_back(TABLE_NAME);`;if(g.length>1){let b=g.map(p=>`${p}: ${l[p]}`).join(", ");n.push(`
458
+ // \u2500\u2500\u2500 reactive: cross-user write variants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
459
+ // Package-level helpers: add pause checks and access control in your system
460
+ // functions before calling these.
461
+ public(package) fun set_reactive<PermType>(
462
+ permit: &ScenePermit<PermType>,
463
+ from: &mut UserStorage,
464
+ target: &mut UserStorage,
465
+ ${y?y+", ":""}${b},
466
+ ctx: &mut TxContext,
467
+ ) {
468
+ ${o}
469
+ let field_names = vector[${g.map(p=>`b"${p}"`).join(", ")}];
470
+ let value_tuple = encode(${g.join(", ")});
471
+ ${i}::set_record_reactive<DappKey, PermType>(${d}permit, from, target, key_tuple, field_names, value_tuple, ctx);
472
+ }`)}for(let[b,p]of _){let h=p==="string"||p==="String"?`sui::bcs::to_bytes(&std::ascii::into_bytes(${b}))`:`sui::bcs::to_bytes(&${b})`;n.push(`
473
+ public(package) fun set_${b}_reactive<PermType>(
474
+ permit: &ScenePermit<PermType>,
475
+ from: &mut UserStorage,
476
+ target: &mut UserStorage,
477
+ ${y?y+", ":""}${b}: ${p==="string"||p==="String"?"String":p},
478
+ ctx: &mut TxContext,
479
+ ) {
480
+ ${o}
481
+ let value = ${h};
482
+ ${i}::set_field_reactive<DappKey, PermType>(${d}permit, from, target, key_tuple, b"${b}", value, ctx);
483
+ }`)}}if(s.transferable){let o=e.objects??{},b=e.scenes??{},p=!!s.fungible,h=!p&&u.length>0,a=h?u[0]:null;for(let[$,x]of Object.entries(o)){if(!(x.accepts??[]).includes(t))continue;let k=I($),T=`dubhe::dapp_service::ObjectStorage<${r}::${$}::${k}>`,w=$;if(p&&g.length===1){let[,F]=_[0];n.push(`
484
+ // \u2500\u2500\u2500 transferable: User \u2194 ${k}Storage (fungible) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
485
+ public(package) fun transfer_user_to_${$}(
486
+ user: &mut UserStorage,
487
+ target: &mut ${T},
488
+ amount: ${F},
489
+ ctx: &mut TxContext,
490
+ ) {
491
+ sub(user, amount, ctx);
492
+ ${r}::${w}::add_${t}(target, amount);
493
+ }
361
494
 
362
- ${A}
495
+ public(package) fun transfer_${$}_to_user(
496
+ source: &mut ${T},
497
+ user: &mut UserStorage,
498
+ amount: ${F},
499
+ ctx: &mut TxContext,
500
+ ) {
501
+ ${r}::${w}::sub_${t}(source, amount);
502
+ add(user, amount, ctx);
503
+ }`)}else if(h&&a)if(g.length===1){let[,F]=_[0],O=F==="string"||F==="String"?`to_bytes(&std::ascii::into_bytes(get(user, ${a})))`:`to_bytes(&get(user, ${a}))`,A=Object.entries(e.enums??{}).map(([v])=>({type:I(v),module:v})),D=J(r,F,"bcs",A);n.push(`
504
+ // \u2500\u2500\u2500 transferable: User \u2194 ${k}Storage (keyed) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
505
+ public(package) fun transfer_user_to_${$}(
506
+ user: &mut UserStorage,
507
+ target: &mut ${T},
508
+ ${a}: u64,
509
+ ctx: &TxContext,
510
+ ) {
511
+ ensure_has(user, ${a});
512
+ // Guard before any mutation: abort if target already holds this item.
513
+ dubhe::error::item_already_owned(!${r}::${w}::has_${t}(target, ${a}));
514
+ let raw = ${O};
515
+ delete(user, ${a}, ctx);
516
+ ${r}::${w}::set_${t}_data(target, ${a}, raw);
517
+ }
363
518
 
364
- ${a}
519
+ public(package) fun transfer_${$}_to_user(
520
+ source: &mut ${T},
521
+ user: &mut UserStorage,
522
+ ${a}: u64,
523
+ ctx: &mut TxContext,
524
+ ) {
525
+ // Guard before any mutation: abort if user already owns this item.
526
+ ensure_has_not(user, ${a});
527
+ let raw = ${r}::${w}::remove_${t}_data(source, ${a});
528
+ let mut bcs = sui::bcs::new(raw);
529
+ let value = ${D};
530
+ set(user, ${a}, value, ctx);
531
+ }`)}else n.push(`
532
+ // \u2500\u2500\u2500 transferable: User \u2194 ${k}Storage (keyed, multi-field) \u2500\u2500
533
+ public(package) fun transfer_user_to_${$}(
534
+ user: &mut UserStorage,
535
+ target: &mut ${T},
536
+ ${a}: u64,
537
+ ctx: &TxContext,
538
+ ) {
539
+ ensure_has(user, ${a});
540
+ // Guard before any mutation: abort if target already holds this item.
541
+ dubhe::error::item_already_owned(!${r}::${w}::has_${t}(target, ${a}));
542
+ let data = encode_struct(get_struct(user, ${a}));
543
+ delete(user, ${a}, ctx);
544
+ let raw: vector<u8> = sui::bcs::to_bytes(&data);
545
+ ${r}::${w}::set_${t}_data(target, ${a}, raw);
546
+ }
365
547
 
366
- ${w}
548
+ public(package) fun transfer_${$}_to_user(
549
+ source: &mut ${T},
550
+ user: &mut UserStorage,
551
+ ${a}: u64,
552
+ ctx: &mut TxContext,
553
+ ) {
554
+ // Guard before any mutation: abort if user already owns this item.
555
+ ensure_has_not(user, ${a});
556
+ let raw = ${r}::${w}::remove_${t}_data(source, ${a});
557
+ let decoded = decode(raw);
558
+ set_struct(user, ${a}, decoded, ctx);
559
+ }`)}for(let[$,x]of Object.entries(b)){if(!(x.accepts??[]).includes(t))continue;let k=I($),T=`dubhe::dapp_service::SceneStorage<${r}::${$}::${k}>`,w=$,F=x.authorization.kind==="permit"?`dubhe::dapp_service::ScenePermit<${r}::${x.authorization.permit}::${I(x.authorization.permit)}>`:"",O=x.authorization.kind==="permit"?` permit: &${F},
560
+ `:"",A=x.authorization.kind==="permit"?"permit, ":"",D=x.authorization.kind==="permit"?"user, ":"",v=x.authorization.kind==="permit"?", ctx":"";if(p&&g.length===1){let[,K]=_[0];n.push(`
561
+ // \u2500\u2500\u2500 transferable: User \u2194 ${k}Storage (fungible) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
562
+ public(package) fun transfer_user_to_${$}(
563
+ ${O} user: &mut UserStorage,
564
+ target: &mut ${T},
565
+ amount: ${K},
566
+ ctx: &mut TxContext,
567
+ ) {
568
+ sub(user, amount, ctx);
569
+ ${r}::${w}::add_${t}(${A}target, ${D}amount${v});
570
+ }
367
571
 
368
- ${B}`}function j(e){return e.split("_").map((t,s)=>/^\d+$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function L(e){if(e.startsWith("vector<")){let t=e.slice(7,-1);return t==="vector<u8>"?"vec_vec_u8":t==="String"?"vec_string":`vec_${L(t)}`}switch(e){case"u8":return"u8";case"u16":return"u16";case"u32":return"u32";case"u64":return"u64";case"u128":return"u128";case"u256":return"u256";case"bool":return"bool";case"address":return"address";case"String":return"string";default:return e}}async function ge(e,t){let s=`module ${e.name}::genesis {
369
- use sui::clock::Clock;
370
- use dubhe::dapp_service::DappHub;
371
- use ${e.name}::dapp_key;
372
- use dubhe::dapp_system;
373
- use std::ascii::string;
572
+ // \u2605 No expiry check on withdraw direction \u2014 prevents asset lock-in expired scenes.
573
+ public(package) fun transfer_${$}_to_user(
574
+ ${O} source: &mut ${T},
575
+ user: &mut UserStorage,
576
+ amount: ${K},
577
+ ctx: &mut TxContext,
578
+ ) {
579
+ ${r}::${w}::sub_${t}(${A}source, ${D}amount${v});
580
+ add(user, amount, ctx);
581
+ }`)}else if(h&&a)if(g.length===1){let[,K]=_[0],P=K==="string"||K==="String"?`to_bytes(&std::ascii::into_bytes(get(user, ${a})))`:`to_bytes(&get(user, ${a}))`,c=Object.entries(e.enums??{}).map(([S])=>({type:I(S),module:S})),f=J(r,K,"bcs",c);n.push(`
582
+ // \u2500\u2500\u2500 transferable: User \u2194 ${k}Storage (keyed) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
583
+ public(package) fun transfer_user_to_${$}(
584
+ ${O} user: &mut UserStorage,
585
+ target: &mut ${T},
586
+ ${a}: u64,
587
+ ctx: &TxContext,
588
+ ) {
589
+ ensure_has(user, ${a});
590
+ // Guard before any mutation: abort if target already holds this item.
591
+ dubhe::error::item_already_owned(!${r}::${w}::has_${t}(target, ${a}));
592
+ let raw = ${P};
593
+ delete(user, ${a}, ctx);
594
+ ${r}::${w}::set_${t}_data(${A}target, ${D}${a}, raw${v});
595
+ }
374
596
 
375
- public entry fun run(dapp_hub: &mut DappHub, clock: &Clock, ctx: &mut TxContext) {
376
- // Create Dapp
377
- let dapp_key = dapp_key::new();
378
- dapp_system::create_dapp(dapp_hub, dapp_key, string(b"${e.name}"), string(b"${e.description}"), clock, ctx);
597
+ public(package) fun transfer_${$}_to_user(
598
+ ${O} source: &mut ${T},
599
+ user: &mut UserStorage,
600
+ ${a}: u64,
601
+ ctx: &mut TxContext,
602
+ ) {
603
+ // Guard before any mutation: abort if user already owns this item.
604
+ ensure_has_not(user, ${a});
605
+ let raw = ${r}::${w}::remove_${t}_data(${A}source, ${D}${a}${v});
606
+ let mut bcs = sui::bcs::new(raw);
607
+ let value = ${f};
608
+ set(user, ${a}, value, ctx);
609
+ }`)}else n.push(`
610
+ // \u2500\u2500\u2500 transferable: User \u2194 ${k}Storage (keyed, multi-field) \u2500
611
+ public(package) fun transfer_user_to_${$}(
612
+ ${O} user: &mut UserStorage,
613
+ target: &mut ${T},
614
+ ${a}: u64,
615
+ ctx: &TxContext,
616
+ ) {
617
+ ensure_has(user, ${a});
618
+ // Guard before any mutation: abort if target already holds this item.
619
+ dubhe::error::item_already_owned(!${r}::${w}::has_${t}(target, ${a}));
620
+ let data = encode_struct(get_struct(user, ${a}));
621
+ delete(user, ${a}, ctx);
622
+ let raw: vector<u8> = sui::bcs::to_bytes(&data);
623
+ ${r}::${w}::set_${t}_data(${A}target, ${D}${a}, raw${v});
624
+ }
379
625
 
380
- // Logic that needs to be automated once the contract is deployed
381
- ${e.name}::deploy_hook::run(dapp_hub, ctx);
382
- }
383
- }
384
- `;await h(s,t,"formatAndWriteMove")}function $e(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`).replace(/^_/,"")}async function ye(e,t){if(console.log(`
385
- \u{1F4E6} Starting Enums Generation...`),!!e.enums)for(let[s,n]of Object.entries(e.enums)){console.log(` \u2514\u2500 ${s}: ${JSON.stringify(n)}`);let c=[...n].sort((S,D)=>S.localeCompare(D)),l=Ae(e.name,s,c);await h(l,`${t}/${$e(s)}.move`,"formatAndWriteMove")}}function Ae(e,t,s){let n=s.map(c=>c.charAt(0).toUpperCase()+c.slice(1)).join(",");return`module ${e}::${$e(t)} {
386
- use sui::bcs::{BCS, to_bytes, peel_enum_tag};
626
+ public(package) fun transfer_${$}_to_user(
627
+ ${O} source: &mut ${T},
628
+ user: &mut UserStorage,
629
+ ${a}: u64,
630
+ ctx: &mut TxContext,
631
+ ) {
632
+ // Guard before any mutation: abort if user already owns this item.
633
+ ensure_has_not(user, ${a});
634
+ let raw = ${r}::${w}::remove_${t}_data(${A}source, ${D}${a}${v});
635
+ let decoded = decode(raw);
636
+ set_struct(user, ${a}, decoded, ctx);
637
+ }`)}}if(s.listable){let o=!!s.fungible,p=!o&&u.length>0,h=p?u[0]:null,a=`b"${t}"`;if(o&&g.length===1)n.push(`
638
+ // \u2500\u2500\u2500 listable: market protocol (fungible) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
639
+ // Package-level helpers: call these from your system functions.
640
+ // Add pause checks, access control, and custom logic there.
641
+ public(package) fun list<CoinType>(
642
+ user_storage: &mut UserStorage,
643
+ amount: u64,
644
+ price: u64,
645
+ listed_until: std::option::Option<u64>,
646
+ ctx: &mut TxContext,
647
+ ) {
648
+ dubhe::dapp_system::take_fungible_record<DappKey, CoinType>(
649
+ dapp_key::new(),
650
+ user_storage,
651
+ ${a},
652
+ { let mut k = vector::empty(); k.push_back(TABLE_NAME); k },
653
+ b"${g[0]}",
654
+ amount,
655
+ price,
656
+ listed_until,
657
+ ctx,
658
+ );
659
+ }
387
660
 
388
- public enum ${t} has copy, drop, store {
389
- ${n}
661
+ public(package) fun buy<CoinType>(
662
+ dh: &dubhe::dapp_service::DappHub,
663
+ dapp_storage: &mut DappStorage,
664
+ listing: dubhe::dapp_service::Listing<CoinType>,
665
+ user_storage: &mut UserStorage,
666
+ payment: sui::coin::Coin<CoinType>,
667
+ ctx: &mut TxContext,
668
+ ): sui::coin::Coin<CoinType> {
669
+ dubhe::dapp_system::buy_fungible_record<DappKey, CoinType>(
670
+ dapp_key::new(), dh, dapp_storage, listing, user_storage, payment, ctx
671
+ )
390
672
  }
391
673
 
392
- ${s.map(c=>` public fun new_${c.toLowerCase()}(): ${t} {
393
- ${t}::${c.charAt(0).toUpperCase()+c.slice(1)}
394
- }`).join(`
674
+ public(package) fun cancel_listing<CoinType>(
675
+ listing: dubhe::dapp_service::Listing<CoinType>,
676
+ user_storage: &mut UserStorage,
677
+ ctx: &TxContext,
678
+ ) {
679
+ dubhe::dapp_system::cancel_fungible_listing<DappKey, CoinType>(
680
+ dapp_key::new(), listing, user_storage, ctx
681
+ );
682
+ }
395
683
 
396
- `)}
684
+ public(package) fun expire_listing<CoinType>(
685
+ listing: dubhe::dapp_service::Listing<CoinType>,
686
+ user_storage: &mut UserStorage,
687
+ ctx: &TxContext,
688
+ ) {
689
+ dubhe::dapp_system::expire_fungible_listing<DappKey, CoinType>(
690
+ dapp_key::new(), listing, user_storage, ctx
691
+ );
692
+ }`);else if(p&&h){let $=u.map(k=>`${k}: ${l[k]}`).join(`,
693
+ `),x=u.map(k=>`record_key.push_back(sui::bcs::to_bytes(&${k}));`).join(`
694
+ `);n.push(`
695
+ // \u2500\u2500\u2500 listable: market protocol (keyed) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
696
+ // Package-level helpers: call these from your system functions.
697
+ // Add pause checks, access control, and custom logic there.
698
+ public(package) fun list<CoinType>(
699
+ user_storage: &mut UserStorage,
700
+ ${$},
701
+ price: u64,
702
+ listed_until: std::option::Option<u64>,
703
+ ctx: &mut TxContext,
704
+ ) {
705
+ let mut record_key = vector::empty();
706
+ record_key.push_back(TABLE_NAME);
707
+ ${x}
708
+ dubhe::dapp_system::take_record<DappKey, CoinType>(
709
+ dapp_key::new(),
710
+ user_storage,
711
+ ${a},
712
+ record_key,
713
+ vector[${g.map(k=>`b"${k}"`).join(", ")}],
714
+ price,
715
+ listed_until,
716
+ ctx,
717
+ );
718
+ }
397
719
 
398
- public fun encode(self: ${t}): vector<u8> {
399
- to_bytes(&self)
720
+ public(package) fun buy<CoinType>(
721
+ dh: &dubhe::dapp_service::DappHub,
722
+ dapp_storage: &mut DappStorage,
723
+ listing: dubhe::dapp_service::Listing<CoinType>,
724
+ user_storage: &mut UserStorage,
725
+ payment: sui::coin::Coin<CoinType>,
726
+ ctx: &mut TxContext,
727
+ ): sui::coin::Coin<CoinType> {
728
+ dubhe::dapp_system::buy_record<DappKey, CoinType>(
729
+ dapp_key::new(), dh, dapp_storage, listing, user_storage, payment, ctx
730
+ )
400
731
  }
401
732
 
402
- public fun decode(bytes: &mut BCS): ${t} {
403
- match(peel_enum_tag(bytes)) {
404
- ${s.map((c,l)=>` ${l} => ${t}::${c.charAt(0).toUpperCase()+c.slice(1)},`).join(`
405
- `)}
406
- _ => abort,
407
- }
733
+ public(package) fun cancel_listing<CoinType>(
734
+ listing: dubhe::dapp_service::Listing<CoinType>,
735
+ user_storage: &mut UserStorage,
736
+ ctx: &TxContext,
737
+ ) {
738
+ dubhe::dapp_system::restore_record<DappKey, CoinType>(
739
+ dapp_key::new(), listing, user_storage, ctx
740
+ );
408
741
  }
409
- }`}function k(e){return e==="dubhe"?"dapp_service":"dapp_system"}async function q(e,t){console.log(`
410
- \u{1F4E6} Starting Resources Generation...`);for(let[s,n]of Object.entries(e.resources)){if(console.log(` \u2514\u2500 ${s}: ${JSON.stringify(n)}`),typeof n=="string"){let l=we(e.name,s,n,"Onchain");await h(l,`${t}/${s}.move`,"formatAndWriteMove");continue}if(!n.fields||Object.keys(n.fields).length===0)throw new Error(`Resource '${s}' must have fields defined, but found empty object`);n.keys||(n.keys=[]);let c=Fe(e.name,s,n);await h(c,`${t}/${s}.move`,"formatAndWriteMove")}}function we(e,t,s,n="Onchain"){let c=!M(s),l=c?`${ve(s)}`:"",D=n==="Offchain"?"":`
411
- public fun has(dapp_hub: &DappHub, resource_account: String): bool {
412
- let mut key_tuple = vector::empty();
413
- key_tuple.push_back(TABLE_NAME);
414
- ${k(e)}::has_record<DappKey>(dapp_hub, resource_account, key_tuple)
742
+
743
+ public(package) fun expire_listing<CoinType>(
744
+ listing: dubhe::dapp_service::Listing<CoinType>,
745
+ user_storage: &mut UserStorage,
746
+ ctx: &TxContext,
747
+ ) {
748
+ dubhe::dapp_system::expire_listing<DappKey, CoinType>(
749
+ dapp_key::new(), listing, user_storage, ctx
750
+ );
751
+ }`)}}return n.join(`
752
+ `)}import ct from"node:path";function V(e){return e.split("_").map(t=>/^\d+$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function ut(e){return e==="string"||e==="String"?"String":e}function te(e){return`dubhe::dapp_service::ObjectStorage<${e}>`}function pt(e,t){let s=V(e),n=te(s),r=[];for(let[i,d]of Object.entries(t.fields)){let l=ut(d);r.push(`
753
+ public fun get_${i}(storage: &${n}): ${l} {
754
+ dubhe::dapp_system::get_object_field<${s}, ${l}>(storage, b"${i}")
415
755
  }
416
756
 
417
- public(package) fun delete(dapp_hub: &mut DappHub, resource_account: String) {
418
- let mut key_tuple = vector::empty();
419
- key_tuple.push_back(TABLE_NAME);
420
- ${k(e)}::delete_record<DappKey>(dapp_hub, dapp_key::new(), key_tuple, resource_account);
757
+ public(package) fun set_${i}(storage: &mut ${n}, value: ${l}) {
758
+ dubhe::dapp_system::set_object_field<DappKey, ${s}, ${l}>(
759
+ dapp_key::new(), storage, b"${i}", value
760
+ );
761
+ }`)}return r.join(`
762
+ `)}function dt(e,t){let s=V(e),n=te(s);return`
763
+ public fun get_${t}(storage: &${n}): u64 {
764
+ if (dubhe::dapp_system::has_object_field<${s}, u64>(storage, b"${t}")) {
765
+ dubhe::dapp_system::get_object_field<${s}, u64>(storage, b"${t}")
766
+ } else { 0 }
421
767
  }
422
768
 
423
- public fun get(dapp_hub: &DappHub, resource_account: String): (${s==="string"||s==="String"?"String":s}) {
424
- let mut key_tuple = vector::empty();
425
- key_tuple.push_back(TABLE_NAME);
426
- let value_tuple = ${k(e)}::get_record<DappKey>(dapp_hub, resource_account, key_tuple);
427
- let mut bsc_type = sui::bcs::new(value_tuple);
428
- ${s==="string"||s==="String"?"let value = dubhe::bcs::peel_string(&mut bsc_type);":s==="vector<String>"?"let value = dubhe::bcs::peel_vec_string(&mut bsc_type);":c?`let value = ${e}::${l}::decode(&mut bsc_type);`:`let value = sui::bcs::peel_${W(s)}(&mut bsc_type);`}
429
- (value)
769
+ public(package) fun add_${t}(storage: &mut ${n}, amount: u64) {
770
+ let current = get_${t}(storage);
771
+ dubhe::dapp_system::set_object_field<DappKey, ${s}, u64>(
772
+ dapp_key::new(), storage, b"${t}", current + amount
773
+ );
430
774
  }
431
- `;return`module ${e}::${t} {
432
- use sui::bcs::{to_bytes};
433
- use std::ascii::{string, String, into_bytes};
434
- use dubhe::table_id;
435
- use dubhe::dapp_service::{Self, DappHub};
436
- use dubhe::dapp_system;
437
- use ${e}::dapp_key;
438
- use ${e}::dapp_key::DappKey;
439
- ${c&&s!=="string"&&s!=="String"?` use ${e}::${l};
440
- use ${e}::${l}::{${s}};`:""}
441
775
 
442
- const TABLE_NAME: vector<u8> = b"${t}";
443
- const OFFCHAIN: bool = ${n==="Offchain"};
776
+ public(package) fun sub_${t}(storage: &mut ${n}, amount: u64) {
777
+ let current = get_${t}(storage);
778
+ assert!(current >= amount, EInsufficientAmount);
779
+ dubhe::dapp_system::set_object_field<DappKey, ${s}, u64>(
780
+ dapp_key::new(), storage, b"${t}", current - amount
781
+ );
782
+ }`}function lt(e,t,s){let n=V(e),r=te(n);return`
783
+ public fun has_${t}(storage: &${r}, ${s}: u64): bool {
784
+ let key = sui::bcs::to_bytes(&${s});
785
+ dubhe::dapp_system::has_object_field<${n}, vector<u8>>(storage, key)
786
+ }
444
787
 
445
- ${D}
446
- public(package) fun set(dapp_hub: &mut DappHub, resource_account: String, value: ${s==="string"||s==="String"?"String":s}, ctx: &mut TxContext) {
447
- let mut key_tuple = vector::empty();
448
- key_tuple.push_back(TABLE_NAME);
449
- let value_tuple = encode(value);
450
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, resource_account, OFFCHAIN, ctx);
788
+ public fun get_${t}_data(storage: &${r}, ${s}: u64): vector<u8> {
789
+ let key = sui::bcs::to_bytes(&${s});
790
+ dubhe::dapp_system::get_object_field<${n}, vector<u8>>(storage, key)
451
791
  }
452
792
 
453
- public fun encode(value: ${s==="string"||s==="String"?"String":s}): vector<vector<u8>> {
454
- let mut value_tuple = vector::empty();
455
- value_tuple.push_back(${s==="string"||s==="String"?"to_bytes(&into_bytes(value))":s==="vector<String>"?"to_bytes(&value)":c?`${e}::${l}::encode(value)`:"to_bytes(&value)"});
456
- value_tuple
793
+ public(package) fun set_${t}_data(storage: &mut ${r}, ${s}: u64, data: vector<u8>) {
794
+ let key = sui::bcs::to_bytes(&${s});
795
+ assert!(!dubhe::dapp_system::has_object_field<${n}, vector<u8>>(storage, key), EDuplicateItemId);
796
+ dubhe::dapp_system::set_object_field<DappKey, ${n}, vector<u8>>(
797
+ dapp_key::new(), storage, key, data
798
+ );
457
799
  }
458
- }`}function ve(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`).replace(/^_/,"")}function Fe(e,t,s){let n=s.fields,c=s.keys||[],l=s.offchain||!1,S=s.global||!1,D=l?"Offchain":"Onchain",o=l||S,$=Object.keys(n).every(a=>c.includes(a)),v=Object.entries(n).filter(([a])=>!c.includes(a)),C=v.map(([a])=>a),O=C.length===1,i=v.filter(([a,w])=>!M(w)&&w!=="string"&&w!=="String").map(([a,w])=>({type:w,module:`${ve(w)}`})).filter((a,w,B)=>B.findIndex(u=>u.type===a.type)===w),g=He(e,t,n,c,!$&&!O,i,D,o);if($||O)return`module ${e}::${t} {
459
- use sui::bcs::{to_bytes};
460
- use std::ascii::{string, String, into_bytes};
461
- use dubhe::table_id;
462
- use dubhe::dapp_service::{Self, DappHub};
463
- use dubhe::dapp_system;
464
- use ${e}::dapp_key;
465
- use ${e}::dapp_key::DappKey;
466
- ${i.length>0?i.map(a=>` use ${e}::${a.module};
467
- use ${e}::${a.module}::{${a.type}};`).join(`
468
- `):""}
469
800
 
470
- const TABLE_NAME: vector<u8> = b"${t}";
471
- const OFFCHAIN: bool = ${l};
801
+ public(package) fun remove_${t}_data(storage: &mut ${r}, ${s}: u64): vector<u8> {
802
+ let key = sui::bcs::to_bytes(&${s});
803
+ assert!(dubhe::dapp_system::has_object_field<${n}, vector<u8>>(storage, key), EFieldNotFound);
804
+ dubhe::dapp_system::remove_object_field<DappKey, ${n}, vector<u8>>(dapp_key::new(), storage, key)
805
+ }`}function gt(e,t,s,n,r){let i=r.resources??{},d=r.objects??{},l=r.scenes??{},u=V(t),_=te(u),g=[],y=[];for(let o of n){let b=d[o]??l[o];if(!b)continue;let p=b.accepts??[],h=V(o);g.push(` use ${e}::${o};`);let a=p.filter($=>s.includes($));for(let $ of a){let x=i[$];if(!x||typeof x=="string")continue;let k=x,T=!!l[o],w=`${e}::${o}::${h}`,F=T?`dubhe::dapp_service::SceneStorage<${w}>`:`dubhe::dapp_service::ObjectStorage<${w}>`,O=T?l[o]:void 0,A=O?.authorization.kind==="permit"?`dubhe::dapp_service::ScenePermit<${e}::${O.authorization.permit}::${V(O.authorization.permit)}>`:"",D=O?.authorization.kind==="permit"?` source_permit: &${A},
806
+ `:"",v=O?.authorization.kind==="permit",K=v?"source_permit, ":"",P=v?` user_storage: &dubhe::dapp_service::UserStorage,
807
+ `:"",c=v?"user_storage, ":"",f=v?` ctx: &TxContext,
808
+ `:"",S=v?", ctx":"";if(!k.fungible&&k.keys?.length){let j=k.keys[0];y.push(`
809
+ /// Transfer ${$} (keyed item) from ${o} into this ${t}.
810
+ public(package) fun transfer_${o}_to_${t}_${$}(
811
+ ${D} from: &mut ${F},
812
+ to: &mut ${_},
813
+ ${P} ${j}: u64,
814
+ ${f}
815
+ ) {
816
+ let data = ${o}::remove_${$}_data(${K}from, ${c}${j}${S});
817
+ set_${$}_data(to, ${j}, data);
818
+ }`)}else y.push(`
819
+ /// Transfer ${$} (fungible) from ${o} into this ${t}.
820
+ public(package) fun transfer_${o}_to_${t}_${$}(
821
+ ${D} from: &mut ${F},
822
+ to: &mut ${_},
823
+ ${P} amount: u64,
824
+ ${f}
825
+ ) {
826
+ ${o}::sub_${$}(${K}from, ${c}amount${S});
827
+ add_${$}(to, amount);
828
+ }`)}}return{imports:g,functions:y}}async function Be(e,t){if(!e.objects||Object.keys(e.objects).length===0)return;console.log(`
829
+ \u{1F4E6} Starting Object Storage Generation...`);let s=e.name,n=e.resources??{};for(let[r,i]of Object.entries(e.objects)){console.log(` \u2514\u2500 ${r}`);let d=V(r),l=`${d}Storage`,u=`b"${r}"`,_=pt(r,i),g=i.accepts??[],y=[];for(let S of g){let j=n[S];if(!j||typeof j=="string")continue;let M=j;!M.fungible&&M.keys?.length?y.push(lt(r,S,M.keys[0])):y.push(dt(r,S))}let{imports:o,functions:b}=gt(s,r,g,i.acceptsFrom??[],e),p=i.adminOnly?" assert!(ctx.sender() == dubhe::dapp_service::dapp_admin(dapp_storage), ENoPermission);":"",h=`dubhe::dapp_service::ObjectStorage<${d}>`,a=`
830
+ public fun assert_${r}_id(storage: &${h}, expected: vector<u8>) {
831
+ assert!(*dubhe::dapp_service::object_storage_entity_id(storage) == expected, EWrongEntityId);
832
+ }`,$=`
833
+ public fun entity_id(storage: &${h}): vector<u8> {
834
+ *dubhe::dapp_service::object_storage_entity_id(storage)
835
+ }`,T=Object.values(i.fields).some(S=>S==="string"||S==="String"||S==="vector<String>")?`
836
+ use std::ascii::String;`:"",w=g.some(S=>{let j=n[S];return!j||typeof j=="string"?!1:!!j.keys?.length&&!j.fungible}),F=g.some(S=>{let j=n[S];return!j||typeof j=="string"?!1:!!j.fungible}),O=w,A=F,D=w,v=!!i.adminOnly,K=[O?` #[error]
837
+ const EFieldNotFound: vector<u8> = b"Field not found";`:"",A?` #[error]
838
+ const EInsufficientAmount: vector<u8> = b"Insufficient amount";`:"",D?` #[error]
839
+ const EDuplicateItemId: vector<u8> = b"Duplicate item id";`:"",` #[error]
840
+ const EWrongEntityId: vector<u8> = b"Wrong entity id";`,v?` #[error]
841
+ const ENoPermission: vector<u8> = b"Caller does not have permission";`:""].filter(Boolean).join(`
842
+ `),P=o.length>0?`
843
+ `+o.join(`
844
+ `):"",c=`dubhe::dapp_service::ObjectStorage<${d}>`,f=`module ${s}::${r} {
845
+ use dubhe::dapp_service::DappStorage;
846
+ use ${s}::dapp_key;
847
+ use ${s}::dapp_key::DappKey;${T}${P}
848
+
849
+ // \u2500\u2500\u2500 Error constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
850
+ ${K}
851
+
852
+ const TYPE_TAG: vector<u8> = ${u};
853
+
854
+ // \u2500\u2500\u2500 Phantom marker type \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
855
+ /// Phantom type that distinguishes ${l} from other ObjectStorage types
856
+ /// at the Move compiler level, preserving compile-time type safety.
857
+ /// All functions use ObjectStorage<${d}> directly in their signatures.
858
+ public struct ${d} has copy, drop {}
859
+
860
+ // \u2500\u2500\u2500 ID / entity accessors \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
861
+ ${$}
472
862
 
473
- ${g}
474
- }`;let b=C.map(a=>` ${a}: ${n[a]==="string"||n[a]==="String"?"String":n[a]==="vector<String>"?"vector<String>":n[a]},`).join(`
475
- `),f=C.map(a=>`${a}: ${n[a]==="string"||n[a]==="String"?"String":n[a]==="vector<String>"?"vector<String>":n[a]}`).join(", "),m=C.map(a=>` ${a},`).join(`
476
- `),p=C.map(a=>` public fun ${a}(self: &${H(t)}): ${n[a]==="string"||n[a]==="String"?"String":n[a]==="vector<String>"?"vector<String>":n[a]} {
477
- self.${a}
478
- }`).join(`
863
+ ${a}
479
864
 
480
- `),A=C.map(a=>` public fun update_${a}(self: &mut ${H(t)}, ${a}: ${n[a]==="string"||n[a]==="String"?"String":n[a]==="vector<String>"?"vector<String>":n[a]}) {
481
- self.${a} = ${a}
482
- }`).join(`
865
+ // \u2500\u2500\u2500 Field accessors (own fields) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
866
+ ${_}
483
867
 
484
- `);return`module ${e}::${t} {
485
- use sui::bcs::{to_bytes};
486
- use std::ascii::{string, String, into_bytes};
487
- use dubhe::table_id;
488
- use dubhe::dapp_service::{Self, DappHub};
489
- use dubhe::dapp_system;
490
- use ${e}::dapp_key;
491
- use ${e}::dapp_key::DappKey;
492
- ${i.length>0?i.map(a=>` use ${e}::${a.module};
493
- use ${e}::${a.module}::{${a.type}};`).join(`
494
- `):""}
868
+ // \u2500\u2500\u2500 Bag accessors for accepted resources \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
869
+ ${y.join(`
870
+ `)}
495
871
 
496
- const TABLE_NAME: vector<u8> = b"${t}";
497
- const OFFCHAIN: bool = ${l};
872
+ // \u2500\u2500\u2500 acceptsFrom: cross-storage transfer functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
873
+ ${b.join(`
874
+ `)}
498
875
 
499
- public struct ${H(t)} has copy, drop, store {
500
- ${b}
876
+ // \u2500\u2500\u2500 Lifecycle entry functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
877
+ public(package) fun create_${r}(
878
+ dapp_storage: &mut DappStorage,
879
+ entity_id: vector<u8>,
880
+ ctx: &mut TxContext,
881
+ ) {
882
+ ${p}
883
+ dubhe::dapp_system::create_and_share_typed_object<DappKey, ${d}>(
884
+ dapp_key::new(), dapp_storage, TYPE_TAG, entity_id, ctx
885
+ );
501
886
  }
502
887
 
503
- public fun new(${f}): ${H(t)} {
504
- ${H(t)} {
505
- ${m}
506
- }
888
+ public(package) fun destroy_${r}(
889
+ dapp_storage: &mut DappStorage,
890
+ storage: ${c},
891
+ _ctx: &TxContext,
892
+ ) {
893
+ dubhe::dapp_system::destroy_typed_object<DappKey, ${d}>(
894
+ dapp_key::new(), dapp_storage, storage
895
+ );
507
896
  }
897
+ }
898
+ `;await E(f,ct.join(t,`${r}.move`),"formatAndWriteMove")}}import $t from"node:path";function _t(e){return e.split("_").map(t=>/^\d+$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}async function ze(e,t){if(!e.permits||Object.keys(e.permits).length===0)return;console.log(`
899
+ \u{1F4E6} Starting Scene Permit Generation...`);let s=e.name;for(let n of Object.keys(e.permits)){console.log(` \u2514\u2500 ${n}`);let r=_t(n),i=`b"${n}"`,d=`dubhe::dapp_service::ScenePermit<${r}>`,l=`module ${s}::${n} {
900
+ use dubhe::dapp_service::{Self, DappStorage};
901
+ use ${s}::dapp_key;
902
+ use ${s}::dapp_key::DappKey;
508
903
 
509
- ${p}
904
+ const PERMIT_TYPE: vector<u8> = ${i};
510
905
 
511
- ${A}
906
+ #[error]
907
+ const EPermitNotExpiredYet: vector<u8> = b"Scene permit is still active";
512
908
 
513
- ${g}
514
- }`}function M(e){return["address","bool","u8","u32","u64","u128","u256","string","String","vector<address>","vector<bool>","vector<u8>","vector<vector<u8>>","vector<u32>","vector<u64>","vector<u128>","vector<u256>","vector<String>"].includes(e)}function He(e,t,s,n,c=!0,l=[],S="Onchain",D=!1){let o=Object.entries(s).filter(([r])=>!n.includes(r)).reduce((r,[_,d])=>({...r,[_]:d}),{}),$=Object.keys(o),v=Object.keys(s).every(r=>n.includes(r)),C=$.length===1,O=S==="Offchain",i=n.length>0?n.map(r=>`${r}: ${s[r]}`).join(", "):"",g=n.length>0?`let mut key_tuple = vector::empty();
515
- key_tuple.push_back(TABLE_NAME);
516
- ${n.map(r=>`key_tuple.push_back(to_bytes(&${r}));`).join(`
517
- `)}`:`let mut key_tuple = vector::empty();
518
- key_tuple.push_back(TABLE_NAME);`,b=D?"":"resource_account: String",f=D?"dapp_key::package_id().to_ascii_string()":"resource_account",m=b&&i?", ":"",p=O?"":` public fun has(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}): bool {
519
- ${g}
520
- ${k(e)}::has_record<DappKey>(dapp_hub, ${f}, key_tuple)
909
+ /// Phantom type that distinguishes this permit from others at compile time.
910
+ public struct ${r} has copy, drop {}
911
+
912
+ public fun meta(permit: &${d}): &dubhe::dapp_service::PermitMetadata {
913
+ dapp_service::scene_permit_meta(permit)
521
914
  }
522
915
 
523
- public fun ensure_has(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}) {
524
- ${g}
525
- ${k(e)}::ensure_has_record<DappKey>(dapp_hub, ${f}, key_tuple)
916
+ public fun is_active(permit: &${d}, now_ms: u64): bool {
917
+ dapp_service::is_scene_active(dapp_service::scene_permit_meta(permit), now_ms)
526
918
  }
527
919
 
528
- public fun ensure_has_not(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}) {
529
- ${g}
530
- ${k(e)}::ensure_has_not_record<DappKey>(dapp_hub, ${f}, key_tuple)
920
+ public fun is_participant(permit: &${d}, addr: address): bool {
921
+ dubhe::dapp_system::is_scene_permit_participant<${r}>(permit, addr)
531
922
  }
532
- `,A=O?"":` public(package) fun delete(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}) {
533
- ${g}
534
- ${k(e)}::delete_record<DappKey>(dapp_hub, dapp_key::new(), key_tuple, ${f});
535
- }`,a=!C&&!O?$.map(r=>{let _=$.indexOf(r),d=s[r],F=!M(d),E=F?l.find(he=>he.type===d):null;return` public fun get_${r}(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}): ${d==="string"||d==="String"?"String":d==="vector<String>"?"vector<String>":d} {
536
- ${g}
537
- let value = ${k(e)}::get_field<DappKey>(dapp_hub, ${f}, key_tuple, ${_});
538
- let mut bsc_type = sui::bcs::new(value);
539
- ${d==="string"||d==="String"?`let ${r} = dubhe::bcs::peel_string(&mut bsc_type);`:d==="vector<String>"?`let ${r} = dubhe::bcs::peel_vec_string(&mut bsc_type);`:F?`let ${r} = ${e}::${E?.module}::decode(&mut bsc_type);`:`let ${r} = sui::bcs::peel_${W(d)}(&mut bsc_type);`}
540
- ${r}
923
+
924
+ public(package) fun new_${n}(
925
+ dapp_storage: &DappStorage,
926
+ participants: vector<address>,
927
+ expires_at: std::option::Option<u64>,
928
+ max_participants: std::option::Option<u64>,
929
+ ctx: &mut TxContext,
930
+ ): ${d} {
931
+ dubhe::dapp_system::new_scene_permit<DappKey, ${r}>(
932
+ dapp_key::new(), dapp_storage, PERMIT_TYPE, participants, expires_at, max_participants, ctx
933
+ )
541
934
  }
542
935
 
543
- public(package) fun set_${r}(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, ${r}: ${d==="string"||d==="String"?"String":d==="vector<String>"?"vector<String>":d}) {
544
- ${g}
545
- let value = ${d==="string"||d==="String"?`to_bytes(&into_bytes(${r}))`:d==="vector<String>"?`to_bytes(&${r})`:F?`${e}::${E?.module}::encode(${r})`:`to_bytes(&${r})`};
546
- ${k(e)}::set_field(dapp_hub, dapp_key::new(), key_tuple, ${_}, value, ${f});
547
- }`}).join(`
936
+ public(package) fun new_${n}_with_invitations(
937
+ dapp_storage: &DappStorage,
938
+ invitees: vector<address>,
939
+ invites_expire_at: std::option::Option<u64>,
940
+ scene_expires_at: std::option::Option<u64>,
941
+ max_participants: std::option::Option<u64>,
942
+ ctx: &mut TxContext,
943
+ ): ${d} {
944
+ dubhe::dapp_system::new_scene_permit_with_invitations<DappKey, ${r}>(
945
+ dapp_key::new(), dapp_storage, PERMIT_TYPE, invitees, invites_expire_at, scene_expires_at, max_participants, ctx
946
+ )
947
+ }
548
948
 
549
- `):"",w=v?` public(package) fun set(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, ctx: &mut TxContext) {
550
- ${g}
551
- let value_tuple = vector::empty();
552
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
553
- }`:C?O?` public(package) fun set(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, value: ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]}, ctx: &mut TxContext) {
554
- ${g}
555
- let value_tuple = encode(value);
556
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
557
- }`:` public fun get(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}): ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]} {
558
- ${g}
559
- let value = ${k(e)}::get_field<DappKey>(dapp_hub, ${f}, key_tuple, 0);
560
- let mut bsc_type = sui::bcs::new(value);
561
- ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"let value = dubhe::bcs::peel_string(&mut bsc_type);":Object.values(o)[0]==="vector<String>"?"let value = dubhe::bcs::peel_vec_string(&mut bsc_type);":M(Object.values(o)[0])?`let value = sui::bcs::peel_${W(Object.values(o)[0])}(&mut bsc_type);`:`let value = ${e}::${l.find(r=>r.type===Object.values(o)[0])?.module}::decode(&mut bsc_type);`}
562
- value
949
+ public(package) fun share_${n}(permit: ${d}) {
950
+ dubhe::dapp_system::share_scene_permit<DappKey, ${r}>(
951
+ dapp_key::new(), permit
952
+ );
563
953
  }
564
954
 
565
- public(package) fun set(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, value: ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]}, ctx: &mut TxContext) {
566
- ${g}
567
- let value_tuple = encode(value);
568
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
569
- }`:O?` public(package) fun set(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, ${$.map(r=>`${r}: ${s[r]==="string"||s[r]==="String"?"String":s[r]}`).join(", ")}, ctx: &mut TxContext) {
570
- ${g}
571
- let value_tuple = encode(${$.join(", ")});
572
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
573
- }`:` public fun get(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}): (${Object.values(o).map(r=>r==="string"||r==="String"?"String":r).join(", ")}) {
574
- ${g}
575
- let value_tuple = ${k(e)}::get_record<DappKey>(dapp_hub, ${f}, key_tuple);
576
- let mut bsc_type = sui::bcs::new(value_tuple);
577
- ${$.map(r=>{let _=s[r],d=!M(_),F=d?l.find(E=>E.type===_):null;return`let ${r} = ${_==="string"||_==="String"?"dubhe::bcs::peel_string(&mut bsc_type)":_==="vector<String>"?"dubhe::bcs::peel_vec_string(&mut bsc_type)":d?`${e}::${F?.module}::decode(&mut bsc_type)`:`sui::bcs::peel_${W(_)}(&mut bsc_type)`};`}).join(`
578
- `)}
579
- (${$.join(", ")})
955
+ public(package) fun create_${n}(
956
+ dapp_storage: &DappStorage,
957
+ participants: vector<address>,
958
+ expires_at: std::option::Option<u64>,
959
+ max_participants: std::option::Option<u64>,
960
+ ctx: &mut TxContext,
961
+ ) {
962
+ dubhe::dapp_system::create_and_share_scene_permit<DappKey, ${r}>(
963
+ dapp_key::new(), dapp_storage, PERMIT_TYPE, participants, expires_at, max_participants, ctx
964
+ );
580
965
  }
581
966
 
582
- public(package) fun set(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, ${$.map(r=>`${r}: ${s[r]==="string"||s[r]==="String"?"String":s[r]}`).join(", ")}, ctx: &mut TxContext) {
583
- ${g}
584
- let value_tuple = encode(${$.join(", ")});
585
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
586
- }`,B=c?O?` public(package) fun set_struct(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, ${t}: ${H(t)}, ctx: &mut TxContext) {
587
- ${g}
588
- let value_tuple = encode_struct(${t});
589
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
590
- }`:` public fun get_struct(dapp_hub: &DappHub${b||i?", ":""}${b}${m}${i}): ${H(t)} {
591
- ${g}
592
- let value_tuple = ${k(e)}::get_record<DappKey>(dapp_hub, ${f}, key_tuple);
593
- decode(value_tuple)
967
+ public(package) fun create_${n}_with_invitations(
968
+ dapp_storage: &DappStorage,
969
+ invitees: vector<address>,
970
+ invites_expire_at: std::option::Option<u64>,
971
+ scene_expires_at: std::option::Option<u64>,
972
+ max_participants: std::option::Option<u64>,
973
+ ctx: &mut TxContext,
974
+ ) {
975
+ dubhe::dapp_system::create_and_share_scene_permit_with_invitations<DappKey, ${r}>(
976
+ dapp_key::new(), dapp_storage, PERMIT_TYPE, invitees, invites_expire_at, scene_expires_at, max_participants, ctx
977
+ );
594
978
  }
595
979
 
596
- public(package) fun set_struct(dapp_hub: &mut DappHub${b||i?", ":""}${b}${m}${i}, ${t}: ${H(t)}, ctx: &mut TxContext) {
597
- ${g}
598
- let value_tuple = encode_struct(${t});
599
- ${k(e)}::set_record(dapp_hub, dapp_key::new(), key_tuple, value_tuple, ${f}, OFFCHAIN, ctx);
600
- }`:"",u=C?` public fun encode(value: ${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"String":Object.values(o)[0]}): vector<vector<u8>> {
601
- let mut value_tuple = vector::empty();
602
- value_tuple.push_back(${Object.values(o)[0]==="string"||Object.values(o)[0]==="String"?"to_bytes(&into_bytes(value))":Object.values(o)[0]==="vector<String>"||M(Object.values(o)[0])?"to_bytes(&value)":`${e}::${l.find(r=>r.type===Object.values(o)[0])?.module}::encode(value)`});
603
- value_tuple
604
- }`:c?O?` public fun encode(${$.map(r=>`${r}: ${s[r]==="string"||s[r]==="String"?"String":s[r]}`).join(", ")}): vector<vector<u8>> {
605
- let mut value_tuple = vector::empty();
606
- ${$.map(r=>{let _=s[r],d=!M(_),F=d?l.find(E=>E.type===_):null;return`value_tuple.push_back(${_==="string"||_==="String"?`to_bytes(&into_bytes(${r}))`:_==="vector<String>"?`to_bytes(&${r})`:d?`${e}::${F?.module}::encode(${r})`:`to_bytes(&${r})`});`}).join(`
607
- `)}
608
- value_tuple
980
+ public(package) fun accept_${n}(
981
+ permit: &mut ${d},
982
+ user_storage: &dubhe::dapp_service::UserStorage,
983
+ ctx: &TxContext,
984
+ ) {
985
+ dubhe::dapp_system::accept_scene_permit_invitation<DappKey, ${r}>(
986
+ dapp_key::new(), permit, user_storage, ctx
987
+ );
609
988
  }
610
989
 
611
- public fun encode_struct(${t}: ${H(t)}): vector<vector<u8>> {
612
- encode(${$.map(r=>`${t}.${r}`).join(", ")})
613
- }`:` public fun encode(${$.map(r=>`${r}: ${s[r]==="string"||s[r]==="String"?"String":s[r]}`).join(", ")}): vector<vector<u8>> {
614
- let mut value_tuple = vector::empty();
615
- ${$.map(r=>{let _=s[r],d=!M(_),F=d?l.find(E=>E.type===_):null;return`value_tuple.push_back(${_==="string"||_==="String"?`to_bytes(&into_bytes(${r}))`:_==="vector<String>"?`to_bytes(&${r})`:d?`${e}::${F?.module}::encode(${r})`:`to_bytes(&${r})`});`}).join(`
616
- `)}
617
- value_tuple
990
+ public(package) fun join_${n}(
991
+ permit: &mut ${d},
992
+ user_storage: &dubhe::dapp_service::UserStorage,
993
+ ctx: &TxContext,
994
+ ) {
995
+ dubhe::dapp_system::join_scene_permit<DappKey, ${r}>(dapp_key::new(), permit, user_storage, ctx);
618
996
  }
619
997
 
620
- public fun encode_struct(${t}: ${H(t)}): vector<vector<u8>> {
621
- encode(${$.map(r=>`${t}.${r}`).join(", ")})
998
+ public(package) fun leave_${n}(
999
+ permit: &mut ${d},
1000
+ user_storage: &dubhe::dapp_service::UserStorage,
1001
+ ctx: &TxContext,
1002
+ ) {
1003
+ dubhe::dapp_system::leave_scene_permit<DappKey, ${r}>(dapp_key::new(), permit, user_storage, ctx);
622
1004
  }
623
1005
 
624
- public fun decode(data: vector<u8>): ${H(t)} {
625
- let mut bsc_type = sui::bcs::new(data);
626
- ${$.map(r=>{let _=s[r],d=!M(_),F=d?l.find(E=>E.type===_):null;return`let ${r} = ${_==="string"||_==="String"?"string(sui::bcs::peel_vec_u8(&mut bsc_type))":_==="vector<String>"?"dubhe::bcs::peel_vec_string(&mut bsc_type)":d?`${e}::${F?.module}::decode(&mut bsc_type)`:`sui::bcs::peel_${W(_)}(&mut bsc_type)`};`}).join(`
627
- `)}
628
- ${H(t)} {
629
- ${$.map(r=>`${r},`).join(`
630
- `)}
631
- }
632
- }`:"";return[p,A,a,w,B,u].filter(r=>r.trim().length>0).join(`
1006
+ public(package) fun expire_${n}(
1007
+ permit: ${d},
1008
+ ctx: &TxContext,
1009
+ ) {
1010
+ assert!(
1011
+ !dapp_service::is_scene_active(dapp_service::scene_permit_meta(&permit), ctx.epoch_timestamp_ms()),
1012
+ EPermitNotExpiredYet
1013
+ );
1014
+ dubhe::dapp_system::destroy_scene_permit<DappKey, ${r}>(
1015
+ dapp_key::new(), permit
1016
+ );
1017
+ }
1018
+ }
1019
+ `;await E(l,$t.join(t,`${n}.move`),"formatAndWriteMove")}}import mt from"node:path";function G(e){return e.split("_").map(t=>/^\d+$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function bt(e){return e==="string"||e==="String"?"String":e}function N(e){return`dubhe::dapp_service::SceneStorage<${e}>`}function Z(e,t){if(t.authorization.kind==="permit")return`${e.name}::${t.authorization.permit}::${G(t.authorization.permit)}`}function Q(e,t){if(t.authorization.kind==="permit")return`dubhe::dapp_service::ScenePermit<${Z(e,t)}>`}function ft(e,t,s){let n=G(t),r=N(n),i=Z(e,s),d=Q(e,s),l=[];for(let[u,_]of Object.entries(s.fields)){let g=bt(_);s.authorization.kind==="permit"&&i&&d?l.push(`
1020
+ public fun get_${u}(storage: &${r}): ${g} {
1021
+ dubhe::dapp_system::get_scene_field<${n}, ${g}>(storage, b"${u}")
1022
+ }
1023
+
1024
+ public(package) fun set_${u}(
1025
+ permit: &${d},
1026
+ storage: &mut ${r},
1027
+ user_storage: &dubhe::dapp_service::UserStorage,
1028
+ value: ${g},
1029
+ ctx: &TxContext,
1030
+ ) {
1031
+ dubhe::dapp_system::set_scene_field<DappKey, ${i}, ${n}, ${g}>(
1032
+ dapp_key::new(), permit, storage, user_storage, b"${u}", value, ctx
1033
+ );
1034
+ }
1035
+
1036
+ public(package) fun remove_${u}_system_maintenance(storage: &mut ${r}): ${g} {
1037
+ dubhe::dapp_system::remove_scene_field_system_maintenance<DappKey, ${n}, ${g}>(
1038
+ dapp_key::new(), storage, b"${u}"
1039
+ )
1040
+ }`):l.push(`
1041
+ public fun get_${u}(storage: &${r}): ${g} {
1042
+ dubhe::dapp_system::get_scene_field<${n}, ${g}>(storage, b"${u}")
1043
+ }
1044
+
1045
+ public(package) fun set_${u}(storage: &mut ${r}, value: ${g}) {
1046
+ dubhe::dapp_system::set_scene_field_system<DappKey, ${n}, ${g}>(
1047
+ dapp_key::new(), storage, b"${u}", value
1048
+ );
1049
+ }
1050
+
1051
+ public(package) fun remove_${u}(storage: &mut ${r}): ${g} {
1052
+ dubhe::dapp_system::remove_scene_field_system_maintenance<DappKey, ${n}, ${g}>(
1053
+ dapp_key::new(), storage, b"${u}"
1054
+ )
1055
+ }`)}return l.join(`
1056
+ `)}function se(e,t){let s=Q(e,t);return t.authorization.kind!=="permit"||!s?"":` permit: &${s},
1057
+ `}function re(e){return e.authorization.kind!=="permit"?"":` user_storage: &dubhe::dapp_service::UserStorage,
1058
+ `}function ne(e){return e.authorization.kind==="permit"?` ctx: &TxContext,
1059
+ `:""}function $e(e,t,s,n,r,i){let d=Z(e,t);return t.authorization.kind==="permit"&&d?`dubhe::dapp_system::set_scene_field<DappKey, ${d}, ${s}, ${n}>(
1060
+ dapp_key::new(), permit, storage, user_storage, ${r}, ${i}, ctx
1061
+ );`:`dubhe::dapp_system::set_scene_field_system<DappKey, ${s}, ${n}>(
1062
+ dapp_key::new(), storage, ${r}, ${i}
1063
+ );`}function yt(e,t,s,n,r){let i=Z(e,t);return t.authorization.kind==="permit"&&i?`dubhe::dapp_system::remove_scene_field<DappKey, ${i}, ${s}, ${n}>(
1064
+ dapp_key::new(), permit, storage, user_storage, ${r}, ctx
1065
+ )`:`dubhe::dapp_system::remove_scene_field_system_maintenance<DappKey, ${s}, ${n}>(
1066
+ dapp_key::new(), storage, ${r}
1067
+ )`}function ht(e,t,s,n){let r=G(t),i=N(r);return`
1068
+ public fun get_${n}(storage: &${i}): u64 {
1069
+ if (dubhe::dapp_system::has_scene_field<${r}, u64>(storage, b"${n}")) {
1070
+ dubhe::dapp_system::get_scene_field<${r}, u64>(storage, b"${n}")
1071
+ } else { 0 }
1072
+ }
1073
+
1074
+ public(package) fun add_${n}(
1075
+ ${se(e,s)} storage: &mut ${i},
1076
+ ${re(s)} amount: u64,
1077
+ ${ne(s)} ) {
1078
+ let current = get_${n}(storage);
1079
+ ${$e(e,s,r,"u64",`b"${n}"`,"current + amount")}
1080
+ }
633
1081
 
634
- `)}function H(e){return e.split("_").map((t,s)=>/^\d+$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}function W(e){if(e.startsWith("vector<")){let t=e.slice(7,-1);return t==="vector<u8>"?"vec_vec_u8":t==="String"?"vec_string":`vec_${W(t)}`}switch(e){case"u8":return"u8";case"u16":return"u16";case"u32":return"u32";case"u64":return"u64";case"u128":return"u128";case"u256":return"u256";case"bool":return"bool";case"address":return"address";case"String":return"string";default:return e}}import I from"node:path";async function Rt(e,t,s){console.log(`
635
- \u{1F680} Starting Schema Generation Process...`),console.log("\u{1F4CB} Project Configuration:"),console.log(` \u2514\u2500 Name: ${t.name}`),console.log(` \u2514\u2500 Description: ${t.description||"No description provided"}`),console.log(` \u2514\u2500 Network: ${s||"testnet"}`),console.log(e);let n=I.join(e,"src",t.name);K(`${n}`)&&J(`${n}/sources/codegen`),K(`${n}/Move.toml`)||await ne(t,e);let c=I.join(n,"sources","codegen","genesis.move");K(c)||await ge(t,c);let l=I.join(n,"sources","codegen","init_test.move");K(l)||await _e(t,l);let S=I.join(n,"sources","codegen","dapp_key.move");K(S)||await oe(t,S);let D=I.join(n,"sources","scripts","deploy_hook.move");K(D)||await ue(t,D);let o=I.join(n,"sources","codegen","components");K(o)?await Z(t,o):await Z(t,o);let $=I.join(n,"sources","codegen","resources");K($)?await q(t,$):await q(t,$);let v=I.join(n,"sources","codegen","enums");K(v)||await ye(t,v),t.errors&&await le(t.name,t.errors,e),await ae(t,e),await ie(t,e),console.log(`
636
- \u2705 Schema Generation Process Complete!
637
- `)}var Ee=e=>{let t=Object.keys(e.components||{}),s=Object.keys(e.resources||{}),n=t.filter(c=>s.includes(c));if(n.length>0)throw new Error(`Duplicate keys found between components and resources: ${n.join(", ")}`)},Gt=e=>(Ee(e),e);import{findUp as je}from"find-up";import Q from"path";import Me from"esbuild";var V=class extends Error{name="NotInsideProjectError";message="You are not inside a Dubhe project"};import{rmSync as Ke}from"fs";import{pathToFileURL as Te}from"url";import Ie from"os";var Le=["dubhe.config.js","dubhe.config.mjs","dubhe.config.ts","dubhe.config.mts"],X="dubhe.config.example.mjs";async function es(e){e=await fe(e);try{return await Me.build({entryPoints:[e],format:"esm",outfile:X,platform:"node",bundle:!0,packages:"external"}),e=await fe(X,!0),(await import(e+`?update=${Date.now()}`)).dubheConfig}finally{Ke(X,{force:!0})}}async function fe(e,t){return e===void 0?e=await We():Q.isAbsolute(e)||(e=Q.join(process.cwd(),e),e=Q.normalize(e)),t&&Ie.platform()==="win32"?Te(e).href:e}async function We(){let e=await je(Le);if(e===void 0)throw new V;return e}var z=e=>{if(typeof e!="object"||e===null)return e;let t={};for(let s in e)if(e.hasOwnProperty(s)){let n=e[s];typeof n=="object"&&n!==null?Array.isArray(n)?t[s]=me(n):n.hasOwnProperty("variant")?t[s]={[n.variant]:{}}:n.hasOwnProperty("fields")?t[s]=z(n.fields):t[s]=z(n):t[s]=n}return t},me=e=>{let t=[];return e.forEach(s=>{typeof s=="object"&&s!==null?Array.isArray(s)?t.push(me(s)):s.hasOwnProperty("variant")?t.push({[s.variant]:{}}):s.hasOwnProperty("fields")?t.push(z(s.fields)):t.push(z(s)):t.push(s)}),t};var Be=(s=>(s.Event="event",s.Schema="schema",s))(Be||{});export{Be as SubscriptionKind,Gt as defineConfig,h as formatAndWriteMove,Ne as formatAndWriteTypescript,Ue as formatMove,N as formatTypescript,es as loadConfig,z as parseData,tt as posixPath,fe as resolveConfigPath,Rt as schemaGen};
1082
+ public(package) fun sub_${n}(
1083
+ ${se(e,s)} storage: &mut ${i},
1084
+ ${re(s)} amount: u64,
1085
+ ${ne(s)} ) {
1086
+ let current = get_${n}(storage);
1087
+ assert!(current >= amount, EInsufficientAmount);
1088
+ ${$e(e,s,r,"u64",`b"${n}"`,"current - amount")}
1089
+ }`}function vt(e,t,s,n,r){let i=G(t),d=N(i);return`
1090
+ public fun has_${n}(storage: &${d}, ${r}: u64): bool {
1091
+ let key = sui::bcs::to_bytes(&${r});
1092
+ dubhe::dapp_system::has_scene_field<${i}, vector<u8>>(storage, key)
1093
+ }
1094
+
1095
+ public fun get_${n}_data(storage: &${d}, ${r}: u64): vector<u8> {
1096
+ let key = sui::bcs::to_bytes(&${r});
1097
+ dubhe::dapp_system::get_scene_field<${i}, vector<u8>>(storage, key)
1098
+ }
1099
+
1100
+ public(package) fun set_${n}_data(
1101
+ ${se(e,s)} storage: &mut ${d},
1102
+ ${re(s)} ${r}: u64,
1103
+ data: vector<u8>,
1104
+ ${ne(s)} ) {
1105
+ let key = sui::bcs::to_bytes(&${r});
1106
+ assert!(!dubhe::dapp_system::has_scene_field<${i}, vector<u8>>(storage, key), EDuplicateItemId);
1107
+ ${$e(e,s,i,"vector<u8>","key","data")}
1108
+ }
1109
+
1110
+ public(package) fun remove_${n}_data(
1111
+ ${se(e,s)} storage: &mut ${d},
1112
+ ${re(s)} ${r}: u64,
1113
+ ${ne(s)} ): vector<u8> {
1114
+ let key = sui::bcs::to_bytes(&${r});
1115
+ assert!(dubhe::dapp_system::has_scene_field<${i}, vector<u8>>(storage, key), EFieldNotFound);
1116
+ ${yt(e,s,i,"vector<u8>","key")}
1117
+ }`}function kt(e,t,s,n,r,i){let d=i.resources??{},l=i.objects??{},u=i.scenes??{},_=G(t),g=N(_),y=[],o=[],b=Q(i,s),p=s.authorization.kind==="permit"&&b?` dest_permit: &${b},
1118
+ `:"",h=s.authorization.kind==="permit"?"dest_permit, ":"",a=s.authorization.kind==="permit"?", ctx":"";for(let $ of r){let x=l[$]??u[$];if(!x)continue;let k=x.accepts??[],T=G($);y.push(` use ${e}::${$};`);let w=!!u[$],F=`${e}::${$}::${T}`,O=w?`dubhe::dapp_service::SceneStorage<${F}>`:`dubhe::dapp_service::ObjectStorage<${F}>`,A=w?x:void 0,D=A?Q(i,A):void 0,v=A?.authorization.kind==="permit"&&!!D,K=v?` source_permit: &${D},
1119
+ `:"",P=v?"source_permit, ":"",c=v?"user_storage, ":"",f=v?", ctx":"",S=s.authorization.kind==="permit",j=S?"user_storage, ":"",M=v||S?` user_storage: &dubhe::dapp_service::UserStorage,
1120
+ `:"",ee=v||S?` ctx: &TxContext,
1121
+ `:"",m=k.filter(C=>n.includes(C));for(let C of m){let W=d[C];if(!W||typeof W=="string")continue;let Y=W;if(!Y.fungible&&Y.keys?.length){let ae=Y.keys[0];o.push(`
1122
+ public(package) fun transfer_${$}_to_${t}_${C}(
1123
+ ${K}${p} from: &mut ${O},
1124
+ to: &mut ${g},
1125
+ ${M} ${ae}: u64,
1126
+ ${ee} ) {
1127
+ let data = ${$}::remove_${C}_data(${P}from, ${c}${ae}${f});
1128
+ set_${C}_data(${h}to, ${j}${ae}, data${a});
1129
+ }`)}else o.push(`
1130
+ public(package) fun transfer_${$}_to_${t}_${C}(
1131
+ ${K}${p} from: &mut ${O},
1132
+ to: &mut ${g},
1133
+ ${M} amount: u64,
1134
+ ${ee} ) {
1135
+ ${$}::sub_${C}(${P}from, ${c}amount${f});
1136
+ add_${C}(${h}to, ${j}amount${a});
1137
+ }`)}}return{imports:y,functions:o}}async function He(e,t){if(!e.scenes||Object.keys(e.scenes).length===0)return;console.log(`
1138
+ \u{1F4E6} Starting Scene Storage Generation...`);let s=e.name,n=e.resources??{};for(let[r,i]of Object.entries(e.scenes)){console.log(` \u2514\u2500 ${r}`);let d=G(r),l=`b"${r}"`,u=N(d),_=ft(e,r,i),g=i.accepts??[],y=[];for(let D of g){let v=n[D];if(!v||typeof v=="string")continue;let K=v;!K.fungible&&K.keys?.length?y.push(vt(e,r,i,D,K.keys[0])):y.push(ht(e,r,i,D))}let{imports:o,functions:b}=kt(s,r,i,g,i.acceptsFrom??[],e),a=Object.values(i.fields).some(D=>D==="string"||D==="String"||D==="vector<String>")?`
1139
+ use std::ascii::String;`:"",$=g.some(D=>{let v=n[D];return!v||typeof v=="string"?!1:!!v.keys?.length&&!v.fungible}),x=g.some(D=>{let v=n[D];return!v||typeof v=="string"?!1:!!v.fungible}),k=[$?` #[error]
1140
+ const EFieldNotFound: vector<u8> = b"Field not found";`:"",x?` #[error]
1141
+ const EInsufficientAmount: vector<u8> = b"Insufficient amount";`:"",$?` #[error]
1142
+ const EDuplicateItemId: vector<u8> = b"Duplicate item id";`:""].filter(Boolean).join(`
1143
+ `),T=k.length>0?`
1144
+ // \u2500\u2500\u2500 Error constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1145
+ ${k}
1146
+ `:"",w=o.length>0?`
1147
+ `+o.join(`
1148
+ `):"",F=Q(e,i),O=i.authorization.kind==="permit"&&F?`
1149
+ public(package) fun new_${r}_with_permit(
1150
+ dapp_storage: &DappStorage,
1151
+ permit: &${F},
1152
+ ctx: &mut TxContext,
1153
+ ): ${u} {
1154
+ dubhe::dapp_system::new_typed_scene_with_permit<DappKey, ${Z(e,i)}, ${d}>(
1155
+ dapp_key::new(), dapp_storage, permit, SCENE_TYPE, ctx
1156
+ )
1157
+ }
1158
+
1159
+ public(package) fun create_${r}_with_permit(
1160
+ dapp_storage: &DappStorage,
1161
+ permit: &${F},
1162
+ ctx: &mut TxContext,
1163
+ ) {
1164
+ dubhe::dapp_system::create_and_share_typed_scene_with_permit<DappKey, ${Z(e,i)}, ${d}>(
1165
+ dapp_key::new(), dapp_storage, permit, SCENE_TYPE, ctx
1166
+ );
1167
+ }`:`
1168
+ public(package) fun new_${r}_system(
1169
+ dapp_storage: &DappStorage,
1170
+ ctx: &mut TxContext,
1171
+ ): ${u} {
1172
+ dubhe::dapp_system::new_typed_scene_system<DappKey, ${d}>(
1173
+ dapp_key::new(), dapp_storage, SCENE_TYPE, ctx
1174
+ )
1175
+ }
1176
+
1177
+ public(package) fun create_${r}_system(
1178
+ dapp_storage: &DappStorage,
1179
+ ctx: &mut TxContext,
1180
+ ) {
1181
+ dubhe::dapp_system::create_and_share_typed_scene_system<DappKey, ${d}>(
1182
+ dapp_key::new(), dapp_storage, SCENE_TYPE, ctx
1183
+ );
1184
+ }`,A=`module ${s}::${r} {
1185
+ use dubhe::dapp_service::DappStorage;
1186
+ use ${s}::dapp_key;
1187
+ use ${s}::dapp_key::DappKey;${a}${w}
1188
+ ${T}
1189
+ const SCENE_TYPE: vector<u8> = ${l};
1190
+
1191
+ /// Phantom type that distinguishes this scene storage at compile time.
1192
+ public struct ${d} has copy, drop {}
1193
+
1194
+ // \u2500\u2500\u2500 Field accessors (own fields) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1195
+ ${_}
1196
+
1197
+ // \u2500\u2500\u2500 Bag accessors for accepted resources \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1198
+ ${y.join(`
1199
+ `)}
1200
+
1201
+ // \u2500\u2500\u2500 acceptsFrom: cross-storage transfer functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1202
+ ${b.join(`
1203
+ `)}
1204
+
1205
+ // \u2500\u2500\u2500 SceneStorage lifecycle wrappers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1206
+ ${O}
1207
+
1208
+ public(package) fun share_${r}(storage: ${u}) {
1209
+ dubhe::dapp_system::share_scene_storage<DappKey, ${d}>(
1210
+ dapp_key::new(), storage
1211
+ );
1212
+ }
1213
+
1214
+ public(package) fun destroy_${r}(storage: ${u}) {
1215
+ dubhe::dapp_system::destroy_typed_scene<DappKey, ${d}>(
1216
+ dapp_key::new(), storage
1217
+ );
1218
+ }
1219
+ }
1220
+ `;await E(A,mt.join(t,`${r}.move`),"formatAndWriteMove")}}async function We(e,t){if(e.name==="dubhe")return;let s=`module ${e.name}::user_storage_init {
1221
+ use dubhe::dapp_service::{DappHub, DappStorage};
1222
+ use dubhe::dapp_system;
1223
+ use ${e.name}::dapp_key;
1224
+ use ${e.name}::dapp_key::DappKey;
1225
+ use ${e.name}::migrate;
1226
+
1227
+ /// Create a UserStorage for the transaction sender within this DApp.
1228
+ /// Must be called once before the user can interact with any user-level resources.
1229
+ /// Aborts if the DApp version does not match this package, the DApp is paused,
1230
+ /// or the framework version has advanced.
1231
+ #[allow(lint(public_entry))]
1232
+ public entry fun init_user_storage(
1233
+ dapp_hub: &DappHub,
1234
+ dapp_storage: &mut DappStorage,
1235
+ ctx: &mut TxContext,
1236
+ ) {
1237
+ dapp_system::ensure_latest_version<DappKey>(dapp_storage, migrate::on_chain_version());
1238
+ dapp_system::create_user_storage(dapp_key::new(), dapp_hub, dapp_storage, ctx);
1239
+ }
1240
+ }
1241
+ `;await E(s,t,"formatAndWriteMove")}import Ye from"chalk";import{existsSync as St,readFileSync as xt,writeFileSync as Ve}from"fs";import Ct from"node:path";function wt(e){if(typeof e=="string")return{value:e};let t={};for(let[s,n]of Object.entries(e.fields??{}))t[s]=n;return t}function Ge(e){let t={};for(let[s,n]of Object.entries(e.fields))t[s]=n;return t}function Dt(e){let t={};for(let[r,i]of Object.entries(e.resources??{}))t[r]=wt(i);let s={};for(let[r,i]of Object.entries(e.objects??{}))s[r]=Ge(i);let n={};for(let[r,i]of Object.entries(e.scenes??{}))n[r]=Ge(i);return{version:1,resources:t,objects:s,scenes:n}}function _e(e,t,s){for(let[n,r]of Object.entries(s)){let i=t[n];if(i)for(let[d,l]of Object.entries(i)){if(!(d in r))throw new Error(`[dubhe] Breaking change detected in ${e}.${n}:
1242
+ Field "${d}" was removed.
1243
+
1244
+ Resources, objects, and scenes are stored as raw bytes on-chain.
1245
+ Removing fields corrupts existing data. Use a new name (e.g. "${n}_v2") for breaking changes.`);if(r[d]!==l)throw new Error(`[dubhe] Breaking change detected in ${e}.${n}:
1246
+ Field "${d}" type changed from "${l}" to "${r[d]}".
1247
+
1248
+ Resources, objects, and scenes are stored as raw bytes on-chain.
1249
+ Changing field types corrupts existing data. Use a new name (e.g. "${n}_v2") for breaking changes.`)}}}function qe(e,t){let s=Ct.join(e,`${t.name}.lock.json`),n=Dt(t);if(St(s)){let r;try{r=JSON.parse(xt(s,"utf-8"))}catch{console.warn(Ye.yellow("[dubhe]")+` Could not parse ${Ye.bold(s)}, skipping break-check.`),Ve(s,JSON.stringify(n,null,2)+`
1250
+ `,"utf-8");return}_e("resources",r.resources??{},n.resources),_e("objects",r.objects??{},n.objects),_e("scenes",r.scenes??{},n.scenes)}Ve(s,JSON.stringify(n,null,2)+`
1251
+ `,"utf-8")}import U from"chalk";var oe=e=>console.warn(U.yellow("[dubhe codegen]")+U.yellow(" WARNING: ")+e);function Je(e){me(e,!1)}function me(e,t=!0){let s=e.resources??{},n=e.objects??{},r=e.permits??{},i=e.scenes??{},d=new Set(Object.keys(s)),l=new Set(Object.keys(n)),u=new Set(Object.keys(r)),_=new Set(Object.keys(i)),g=new Set;for(let o of d)(l.has(o)||u.has(o)||_.has(o))&&g.add(o);for(let o of l)(u.has(o)||_.has(o))&&g.add(o);for(let o of u)_.has(o)&&g.add(o);if(g.size>0)throw new Error(`Duplicate module names found across resources/objects/permits/scenes: ${[...g].sort().join(", ")}`);let y=new Set;for(let[o,b]of Object.entries(n)){for(let p of b.accepts??[]){y.add(p);let h=s[p];if(!h)throw new Error(`objects.${o}.accepts references '${p}' which is not defined in resources`);if(typeof h!="string"&&!h.transferable)throw new Error(`objects.${o}.accepts includes '${p}', but resources.${p} is missing transferable: true. Add transferable: true to resources.${p} to enable cross-storage transfers.`)}for(let p of b.acceptsFrom??[]){let h=!!n[p],a=!!i[p];if(!h&&!a)throw new Error(`objects.${o}.acceptsFrom references '${p}' which is not defined in objects or scenes`)}}for(let[o,b]of Object.entries(i)){if(!b.authorization)throw new Error(`scenes.${o} is missing authorization. Use { kind: 'system' } or { kind: 'permit', permit: '<permit_name>' }.`);if(b.authorization.kind==="permit"){if(!r[b.authorization.permit])throw new Error(`scenes.${o}.authorization references permit '${b.authorization.permit}', but permits.${b.authorization.permit} is not defined`)}else if(b.authorization.kind!=="system")throw new Error(`scenes.${o}.authorization.kind must be 'system' or 'permit'`);for(let p of b.accepts??[]){y.add(p);let h=s[p];if(!h)throw new Error(`scenes.${o}.accepts references '${p}' which is not defined in resources`);if(typeof h!="string"&&!h.transferable)throw new Error(`scenes.${o}.accepts includes '${p}', but resources.${p} is missing transferable: true. Add transferable: true to resources.${p} to enable cross-storage transfers.`)}for(let p of b.acceptsFrom??[]){let h=!!n[p],a=!!i[p];if(!h&&!a)throw new Error(`scenes.${o}.acceptsFrom references '${p}' which is not defined in objects or scenes`)}}for(let[o,b]of Object.entries(s)){if(typeof b=="string")continue;let p=b;if(p.offchain){if(p.listable)throw new Error(`resources.${o} has both offchain: true and listable: true. offchain resources emit events but store no on-chain state, so there is nothing to take out and place into a Listing.`);if(p.transferable)throw new Error(`resources.${o} has both offchain: true and transferable: true. offchain resources have no on-chain state to transfer between storages.`);if(p.reactive)throw new Error(`resources.${o} has both offchain: true and reactive: true. reactive writes target on-chain state, which offchain resources do not have.`);p.fungible&&t&&oe(`resources.${U.bold(o)} has both ${U.cyan("offchain: true")} and ${U.cyan("fungible: true")}. offchain fungible events are emitted only; no on-chain balance is maintained and no add/sub functions are generated. This is unusual \u2014 verify your intent.`)}if(p.reactive&&p.fungible&&t&&oe(`resources.${U.bold(o)} has both ${U.cyan("reactive: true")} and ${U.cyan("fungible: true")}. Fungible quantity changes (add/sub) do not suit reactive cross-user writes. Consider using a transfer function instead.`),p.global){if(p.reactive)throw new Error(`resources.${o} has both global: true and reactive: true. global resources live in DappStorage (shared), not in UserStorage. Reactive writes operate between two UserStorage objects and are incompatible with global resources.`);if(p.listable)throw new Error(`resources.${o} has both global: true and listable: true. global resources live in DappStorage and cannot be individually listed for sale. listable requires per-user ownership in UserStorage.`);if(p.transferable)throw new Error(`resources.${o} has both global: true and transferable: true. global resources live in DappStorage and are not owned by individual users. transferable requires per-user state in UserStorage or ObjectStorage.`)}p.fungible&&p.listable&&t&&oe(`resources.${U.bold(o)} has both ${U.cyan("fungible: true")} and ${U.cyan("listable: true")}. The generated ${U.green(`list_${o}`)} entry function will include an ${U.cyan("amount")} parameter for partial listings.`),p.transferable&&!y.has(o)&&t&&oe(`resources.${U.bold(o)} has ${U.cyan("transferable: true")} but is not referenced in any ${U.cyan("objects.accepts")} or ${U.cyan("scenes.accepts")}. The cross-layer transfer functions will not be generated.`)}}import L from"node:path";async function jt(e,t,s,n=1){console.log(`
1252
+ \u{1F680} Starting Code Generation Process...`),console.log("\u{1F4CB} Project Configuration:"),console.log(` \u2514\u2500 Name: ${t.name}`),console.log(` \u2514\u2500 Description: ${t.description||"No description provided"}`),console.log(` \u2514\u2500 Network: ${s||"testnet"}`),console.log(` \u2514\u2500 Settlement Mode: ${n===1?"USER_PAYS":"DAPP_SUBSIDIZES"}`),me(t),qe(e,t),console.log(e);let r=L.join(e,"src",t.name);q(`${r}`)&&pe(`${r}/sources/codegen`),q(`${r}/Move.toml`)||await Se(t,e);let i=L.join(r,"sources","codegen","genesis.move");q(i)||await Fe(t,i,n);let d=L.join(r,"sources","codegen","init_test.move");q(d)||await Oe(t,d);let l=L.join(r,"sources","codegen","dapp_key.move");q(l)||await De(t,l);let u=L.join(r,"sources","scripts","deploy_hook.move");q(u)||await Ce(t,u,n);let _=L.join(r,"sources","codegen","resources");await Le(t,_);let g=L.join(r,"sources","codegen","objects");await Be(t,g);let y=L.join(r,"sources","codegen","permits");await ze(t,y);let o=L.join(r,"sources","codegen","scenes");await He(t,o);let b=L.join(r,"sources","codegen","enums");q(b)||await Ie(t,b),t.errors&&await Ee(t.name,t.errors,e);let p=L.join(r,"sources","codegen","user_storage_init.move");await We(t,p),await Ae(t,e),await we(t,e),console.log(`
1253
+ \u2705 Code Generation Complete!
1254
+ `)}var er=jt;var rr=e=>(Je(e),e);import{findUp as Tt}from"find-up";import be from"path";import At from"esbuild";var ie=class extends Error{name="NotInsideProjectError";message="You are not inside a Dubhe project"};import{rmSync as Et}from"fs";import{pathToFileURL as Ot}from"url";import Ft from"os";var Kt=["dubhe.config.js","dubhe.config.mjs","dubhe.config.ts","dubhe.config.mts"],fe="dubhe.config.example.mjs";async function gr(e){e=await Ze(e);try{return await At.build({entryPoints:[e],format:"esm",outfile:fe,platform:"node",bundle:!0,packages:"external"}),e=await Ze(fe,!0),(await import(e+`?update=${Date.now()}`)).dubheConfig}finally{Et(fe,{force:!0})}}async function Ze(e,t){return e===void 0?e=await It():be.isAbsolute(e)||(e=be.join(process.cwd(),e),e=be.normalize(e)),t&&Ft.platform()==="win32"?Ot(e).href:e}async function It(){let e=await Tt(Kt);if(e===void 0)throw new ie;return e}var Ut=(s=>(s.Event="event",s.Schema="schema",s))(Ut||{});export{Ut as SubscriptionKind,qe as checkAndUpdateLock,jt as codegen,rr as defineConfig,E as formatAndWriteMove,Rt as formatMove,Be as generateObjects,He as generateScenes,gr as loadConfig,er as schemaGen};
638
1255
  //# sourceMappingURL=index.js.map