@meddleware/token-deployer-ui 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/package.json +22 -8
- package/src/App.vue +1 -1
- package/src/component-styles.css +39 -57
- package/src/components/GithubPush.vue +2 -2
- package/src/components/IconPicker.vue +44 -75
- package/src/components/LicensePicker.vue +2 -2
- package/src/components/ResultPanel.vue +2 -2
- package/src/components/ReviewPanel.vue +11 -3
- package/src/components/TokenDeployerView.vue +52 -48
- package/src/components/WalletBar.vue +12 -1
- package/src/components/WalrusBlobBrowser.vue +4 -4
- package/src/composables/useWalrusRelay.ts +1 -2
- package/src/config.ts +19 -17
- package/src/lib/buildPublishTx.ts +0 -10
- package/src/lib/deploy.ts +9 -3
- package/src/lib/deployExecutor.ts +18 -45
- package/src/lib/template.ts +3 -0
- package/src/lib/walrus-constants.ts +2 -2
- package/src/main.ts +4 -6
- package/src/styles.css +22 -0
- package/.claude/move-language-reference/SKILL.md +0 -445
- package/.claude/skills/move-language-reference/SKILL.md +0 -445
- package/.claude/skills/sui-move-bootcamp/SKILL.md +0 -128
- package/.claude/sui-move-bootcamp/SKILL.md +0 -128
- package/.editorconfig +0 -8
- package/.env.example +0 -72
- package/.gitattributes +0 -1
- package/.github/workflows/docker-publish.yml +0 -348
- package/.github/workflows/e2e-realchain.yml +0 -64
- package/.github/workflows/node-ci.yml +0 -43
- package/.github/workflows/npm-publish.yml +0 -83
- package/.htmlvalidate.mjs +0 -30
- package/.oxfmtrc.json +0 -5
- package/.oxlintrc.json +0 -10
- package/.vscode/extensions.json +0 -9
- package/AGENTS.md +0 -39
- package/CLAUDE.md +0 -166
- package/Dockerfile +0 -96
- package/eslint.config.ts +0 -63
- package/index.html +0 -22
- package/playwright.config.ts +0 -30
- package/postcss.config.js +0 -8
- package/public/CNAME +0 -1
- package/public/_headers +0 -12
- package/public/_redirects +0 -1
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +0 -5
- package/public/og-image.png +0 -0
- package/public/robots.txt +0 -3
- package/public/sitemap.xml +0 -8
- package/scripts/e2e-browser.mjs +0 -15
- package/scripts/e2e-deploy.mjs +0 -227
- package/scripts/e2e-localnet.mjs +0 -67
- package/scripts/e2e-walrus-browser.mjs +0 -112
- package/scripts/gen-og-image.mjs +0 -31
- package/scripts/publish-localnet.mjs +0 -56
- package/scripts/regen-template.sh +0 -45
- package/scripts/sync-template-src.sh +0 -36
- package/scripts/verify-bytecode.mjs +0 -49
- package/src/__tests__/App.spec.js +0 -11
- package/src/composables/useAccessGate.ts +0 -127
- package/src/lib/accessGate.ts +0 -155
- package/src/lib/walrus.ts +0 -155
- package/stylelint.config.js +0 -33
- package/test-results/.last-run.json +0 -4
- package/tests/accessGate.test.ts +0 -113
- package/tests/buildPublishTx.test.ts +0 -243
- package/tests/deploy.test.ts +0 -149
- package/tests/errors.test.ts +0 -32
- package/tests/generatePackage.test.ts +0 -193
- package/tests/github.test.ts +0 -61
- package/tests/licenses.test.ts +0 -81
- package/tests/listMyTokens.test.ts +0 -30
- package/tests/template.test.ts +0 -93
- package/tests/templateArtifact.test.ts +0 -61
- package/tests/templateParity.test.ts +0 -55
- package/tests/useAccessGate.test.ts +0 -97
- package/tests/useWallet.test.ts +0 -74
- package/tests/useWalrusRelayGating.test.ts +0 -30
- package/tests/validation.test.ts +0 -117
- package/tests/walrusUpload.test.ts +0 -93
- package/tests/walrus_url_patch.test.ts +0 -26
- package/tsconfig.json +0 -19
- package/typedoc.json +0 -34
- package/vite.config.ts +0 -73
- package/vitest.config.ts +0 -10
package/tests/validation.test.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
validateForm,
|
|
4
|
-
deriveStructName,
|
|
5
|
-
parseSupply,
|
|
6
|
-
isValid,
|
|
7
|
-
validateIdentifier,
|
|
8
|
-
hasAllowedIconScheme,
|
|
9
|
-
MAX_IDENT_LEN,
|
|
10
|
-
} from '../src/lib/validation.js'
|
|
11
|
-
|
|
12
|
-
const good = {
|
|
13
|
-
packageName: 'my_token',
|
|
14
|
-
moduleName: 'mytoken',
|
|
15
|
-
symbol: 'MTK',
|
|
16
|
-
name: 'My Token',
|
|
17
|
-
description: 'A friendly token',
|
|
18
|
-
iconUrl: 'https://example.com/i.png',
|
|
19
|
-
decimals: 9,
|
|
20
|
-
initialSupply: '1000000',
|
|
21
|
-
recipient: '',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe('deriveStructName', () => {
|
|
25
|
-
it('uppercases the module name (Sui OTW rule)', () => {
|
|
26
|
-
expect(deriveStructName('mwsui')).toBe('MWSUI')
|
|
27
|
-
expect(deriveStructName('sui_token_template')).toBe('SUI_TOKEN_TEMPLATE')
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
describe('validateForm', () => {
|
|
32
|
-
it('accepts a well-formed config', () => {
|
|
33
|
-
expect(isValid(validateForm(good))).toBe(true)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('rejects invalid identifiers', () => {
|
|
37
|
-
expect(validateForm({ ...good, packageName: 'My-Token' }).packageName).toBeTruthy()
|
|
38
|
-
expect(validateForm({ ...good, moduleName: '1coin' }).moduleName).toBeTruthy()
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('rejects unsafe characters that would break the Move byte-string', () => {
|
|
42
|
-
expect(validateForm({ ...good, symbol: 'A"B' }).symbol).toBeTruthy()
|
|
43
|
-
expect(validateForm({ ...good, name: 'back\\slash' }).name).toBeTruthy()
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('requires symbol and name', () => {
|
|
47
|
-
expect(validateForm({ ...good, symbol: '' }).symbol).toBeTruthy()
|
|
48
|
-
expect(validateForm({ ...good, name: ' ' }).name).toBeTruthy()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('bounds decimals to 0..18', () => {
|
|
52
|
-
expect(validateForm({ ...good, decimals: 19 }).decimals).toBeTruthy()
|
|
53
|
-
expect(validateForm({ ...good, decimals: -1 }).decimals).toBeTruthy()
|
|
54
|
-
expect(validateForm({ ...good, decimals: 6 }).decimals).toBeUndefined()
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('rejects supply that overflows u64 for the decimals', () => {
|
|
58
|
-
expect(validateForm({ ...good, initialSupply: '99999999999999', decimals: 18 }).initialSupply).toBeTruthy()
|
|
59
|
-
expect(validateForm({ ...good, initialSupply: 'abc' }).initialSupply).toBeTruthy()
|
|
60
|
-
expect(validateForm({ ...good, initialSupply: '' }).initialSupply).toBeUndefined()
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('validates an optional recipient address', () => {
|
|
64
|
-
expect(validateForm({ ...good, recipient: '0x123' }).recipient).toBeTruthy()
|
|
65
|
-
expect(validateForm({ ...good, recipient: '0x' + 'a'.repeat(64) }).recipient).toBeUndefined()
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('rejects Move reserved words as package/module names', () => {
|
|
69
|
-
expect(validateForm({ ...good, packageName: 'module' }).packageName).toBeTruthy()
|
|
70
|
-
expect(validateForm({ ...good, moduleName: 'struct' }).moduleName).toBeTruthy()
|
|
71
|
-
expect(validateForm({ ...good, moduleName: 'public' }).moduleName).toBeTruthy()
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('rejects over-length identifiers', () => {
|
|
75
|
-
const tooLong = 'a'.repeat(MAX_IDENT_LEN + 1)
|
|
76
|
-
expect(validateForm({ ...good, packageName: tooLong }).packageName).toBeTruthy()
|
|
77
|
-
expect(validateForm({ ...good, moduleName: 'a'.repeat(MAX_IDENT_LEN) }).moduleName).toBeUndefined()
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('rejects a whitespace-only symbol even though it contains "safe" chars', () => {
|
|
81
|
-
expect(validateForm({ ...good, symbol: ' ' }).symbol).toBeTruthy()
|
|
82
|
-
})
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
describe('iconUrl scheme allowlist', () => {
|
|
86
|
-
it('accepts https:// and ipfs:// (and empty = no icon)', () => {
|
|
87
|
-
expect(isValid(validateForm({ ...good, iconUrl: 'https://x.io/a.png' }))).toBe(true)
|
|
88
|
-
expect(isValid(validateForm({ ...good, iconUrl: 'ipfs://bafy.../a.png' }))).toBe(true)
|
|
89
|
-
expect(isValid(validateForm({ ...good, iconUrl: '' }))).toBe(true)
|
|
90
|
-
expect(hasAllowedIconScheme('HTTPS://X.IO/a.png')).toBe(true) // case-insensitive
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('rejects javascript:, data:, and insecure http:', () => {
|
|
94
|
-
expect(validateForm({ ...good, iconUrl: 'javascript:alert(1)' }).iconUrl).toBeTruthy()
|
|
95
|
-
expect(validateForm({ ...good, iconUrl: 'data:image/png;base64,AAAA' }).iconUrl).toBeTruthy()
|
|
96
|
-
expect(validateForm({ ...good, iconUrl: 'http://x.io/a.png' }).iconUrl).toBeTruthy()
|
|
97
|
-
expect(hasAllowedIconScheme('javascript:alert(1)')).toBe(false)
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
describe('validateIdentifier', () => {
|
|
102
|
-
it('accepts a valid identifier and rejects shape/keyword/length violations', () => {
|
|
103
|
-
expect(validateIdentifier('my_token')).toBeNull()
|
|
104
|
-
expect(validateIdentifier('My-Token')).toBeTruthy()
|
|
105
|
-
expect(validateIdentifier('const')).toBeTruthy()
|
|
106
|
-
expect(validateIdentifier('a'.repeat(MAX_IDENT_LEN + 1))).toBeTruthy()
|
|
107
|
-
})
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
describe('parseSupply', () => {
|
|
111
|
-
it('parses whole numbers and blank', () => {
|
|
112
|
-
expect(parseSupply('')).toBe(0n)
|
|
113
|
-
expect(parseSupply(' 42 ')).toBe(42n)
|
|
114
|
-
expect(parseSupply('1.5')).toBeNull()
|
|
115
|
-
expect(parseSupply('-1')).toBeNull()
|
|
116
|
-
})
|
|
117
|
-
})
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
-
|
|
3
|
-
// Capture the options handed to `walrus(...)` and the SuiGrpcClient so we can
|
|
4
|
-
// assert the relay host + tip guard are wired, without a live network. `vi.mock`
|
|
5
|
-
// is hoisted, so the mock fns are declared via `vi.hoisted`.
|
|
6
|
-
const { walrusMock, grpcCtor, extendMock } = vi.hoisted(() => {
|
|
7
|
-
const extendMock = vi.fn<(ext: unknown) => { extendedWith: unknown }>((ext: unknown) => ({ extendedWith: ext }))
|
|
8
|
-
return {
|
|
9
|
-
walrusMock: vi.fn<(_cfg?: unknown) => { __walrusExtension: boolean }>((_cfg?: unknown) => ({ __walrusExtension: true })),
|
|
10
|
-
extendMock,
|
|
11
|
-
// `src/lib/walrus.ts` calls `new SuiGrpcClient(...)`, so the mock must be newable — an
|
|
12
|
-
// arrow function is not a constructor (`new arrowFn()` throws). Use a function expression.
|
|
13
|
-
grpcCtor: vi.fn<() => { $extend: typeof extendMock }>(function () {
|
|
14
|
-
return { $extend: extendMock }
|
|
15
|
-
}),
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
vi.mock('@mysten/walrus', () => ({ walrus: walrusMock }))
|
|
19
|
-
vi.mock('@mysten/sui/grpc', () => ({ SuiGrpcClient: grpcCtor }))
|
|
20
|
-
|
|
21
|
-
import { createWalrusClient, walrusBlobUrl } from '../src/lib/walrus.js'
|
|
22
|
-
import {
|
|
23
|
-
WALRUS_RELAY_HOSTS,
|
|
24
|
-
WALRUS_MAX_TIP_MIST,
|
|
25
|
-
validateIconFile,
|
|
26
|
-
ICON_MAX_BYTES,
|
|
27
|
-
} from '../src/config.js'
|
|
28
|
-
|
|
29
|
-
type WalrusCfg = { wasmUrl?: string; uploadRelay: { host: string; sendTip: { max: number } } }
|
|
30
|
-
|
|
31
|
-
describe('createWalrusClient', () => {
|
|
32
|
-
beforeEach(() => {
|
|
33
|
-
walrusMock.mockClear()
|
|
34
|
-
grpcCtor.mockClear()
|
|
35
|
-
extendMock.mockClear()
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('defaults to the configured relay host + max-tip guard', () => {
|
|
39
|
-
createWalrusClient('testnet', 'wasm-url')
|
|
40
|
-
expect(walrusMock).toHaveBeenCalledTimes(1)
|
|
41
|
-
const cfg = walrusMock.mock.calls[0][0] as unknown as WalrusCfg
|
|
42
|
-
expect(cfg.uploadRelay.host).toBe(WALRUS_RELAY_HOSTS.testnet)
|
|
43
|
-
expect(cfg.uploadRelay.sendTip.max).toBe(Number(WALRUS_MAX_TIP_MIST))
|
|
44
|
-
// The bare-string arg is treated as the WASM URL (back-compat).
|
|
45
|
-
expect(cfg.wasmUrl).toBe('wasm-url')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('honours an explicit relay host + max-tip override', () => {
|
|
49
|
-
createWalrusClient('mainnet', {
|
|
50
|
-
uploadRelayHost: 'https://my.relay.example',
|
|
51
|
-
uploadRelayMaxTipMist: 123n,
|
|
52
|
-
})
|
|
53
|
-
const cfg = walrusMock.mock.calls[0][0] as unknown as WalrusCfg
|
|
54
|
-
expect(cfg.uploadRelay.host).toBe('https://my.relay.example')
|
|
55
|
-
expect(cfg.uploadRelay.sendTip.max).toBe(123)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('never sets a tip address/kind (the relay declares those via /v1/tip-config)', () => {
|
|
59
|
-
createWalrusClient('testnet')
|
|
60
|
-
const cfg = walrusMock.mock.calls[0][0] as unknown as WalrusCfg & {
|
|
61
|
-
uploadRelay: { sendTip: Record<string, unknown> }
|
|
62
|
-
}
|
|
63
|
-
expect(cfg.uploadRelay.sendTip).not.toHaveProperty('address')
|
|
64
|
-
expect(cfg.uploadRelay.sendTip).not.toHaveProperty('kind')
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
describe('walrusBlobUrl', () => {
|
|
69
|
-
it('points at the network aggregator raw-blob route', () => {
|
|
70
|
-
expect(walrusBlobUrl('testnet', 'BLOB123')).toContain('/v1/blobs/BLOB123')
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
describe('validateIconFile (UX/cost gate — not a security control)', () => {
|
|
75
|
-
it('accepts an in-spec PNG', () => {
|
|
76
|
-
expect(validateIconFile({ type: 'image/png', size: 10 * 1024 })).toBeNull()
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('rejects a disallowed MIME type', () => {
|
|
80
|
-
const msg = validateIconFile({ type: 'application/pdf', size: 1024 })
|
|
81
|
-
expect(msg).toMatch(/Unsupported image type/)
|
|
82
|
-
expect(msg).toContain('pdf')
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('rejects a file over the size cap', () => {
|
|
86
|
-
const msg = validateIconFile({ type: 'image/png', size: ICON_MAX_BYTES + 1 })
|
|
87
|
-
expect(msg).toMatch(/too large/)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('accepts a file exactly at the cap', () => {
|
|
91
|
-
expect(validateIconFile({ type: 'image/webp', size: ICON_MAX_BYTES })).toBeNull()
|
|
92
|
-
})
|
|
93
|
-
})
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import init, { deserialize } from '@mysten/move-bytecode-template'
|
|
3
|
-
import { patchTemplateModule } from '../src/lib/template.js'
|
|
4
|
-
|
|
5
|
-
const asStr = (data: number[]) => Buffer.from(data.slice(1)).toString('utf8')
|
|
6
|
-
interface Decoded { constant_pool: { type_: unknown; data: number[] }[] }
|
|
7
|
-
|
|
8
|
-
describe('Walrus blob URL patching', () => {
|
|
9
|
-
it('patches a 99-char Walrus blob URL correctly', async () => {
|
|
10
|
-
await (init as unknown as () => Promise<unknown>)()
|
|
11
|
-
const BLOB_URL = 'https://aggregator.walrus-testnet.walrus.space/v1/blobs/OVB5WTWEqkOktRXHIXTBybPAERD0wfORn8NQ1a2lbFQ'
|
|
12
|
-
const bytes = await patchTemplateModule({
|
|
13
|
-
moduleName: 'mycoin', structName: 'MYCOIN',
|
|
14
|
-
symbol: 'MYC', name: 'My Coin', description: 'A test',
|
|
15
|
-
iconUrl: BLOB_URL, decimals: 9,
|
|
16
|
-
})
|
|
17
|
-
// Valid magic bytes
|
|
18
|
-
expect(Buffer.from(bytes.slice(0, 4)).toString('hex')).toBe('a11ceb0b')
|
|
19
|
-
// Round-trips through deserialize
|
|
20
|
-
const back = deserialize(bytes) as unknown as Decoded
|
|
21
|
-
// Icon URL constant present
|
|
22
|
-
const iconEntry = back.constant_pool.find(c => c.type_ !== 'U8' && asStr(c.data).startsWith('https://aggregator'))
|
|
23
|
-
expect(iconEntry).toBeTruthy()
|
|
24
|
-
expect(asStr(iconEntry!.data)).toBe(BLOB_URL)
|
|
25
|
-
})
|
|
26
|
-
})
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "esnext",
|
|
4
|
-
"lib": ["esnext", "DOM", "DOM.Iterable"],
|
|
5
|
-
"module": "esnext",
|
|
6
|
-
"moduleResolution": "Bundler",
|
|
7
|
-
"resolveJsonModule": true,
|
|
8
|
-
"isolatedModules": true,
|
|
9
|
-
"allowSyntheticDefaultImports": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"strict": true,
|
|
13
|
-
"skipLibCheck": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"jsx": "preserve",
|
|
16
|
-
"types": ["node", "vite/client"]
|
|
17
|
-
},
|
|
18
|
-
"include": ["src/**/*.ts", "src/**/*.vue", "tests/**/*.ts", "env.d.ts"]
|
|
19
|
-
}
|
package/typedoc.json
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://typedoc.org/schema.json",
|
|
3
|
-
"entryPoints": [
|
|
4
|
-
"src/config.ts",
|
|
5
|
-
"src/lib/types.ts",
|
|
6
|
-
"src/lib/validation.ts",
|
|
7
|
-
"src/lib/form.ts",
|
|
8
|
-
"src/lib/template.ts",
|
|
9
|
-
"src/lib/buildPublishTx.ts",
|
|
10
|
-
"src/lib/deploy.ts",
|
|
11
|
-
"src/lib/generatePackage.ts",
|
|
12
|
-
"src/lib/licenses.ts",
|
|
13
|
-
"src/lib/github.ts",
|
|
14
|
-
"src/lib/walrus.ts",
|
|
15
|
-
"src/lib/walrus-constants.ts",
|
|
16
|
-
"src/composables/useAccessGate.ts",
|
|
17
|
-
"src/composables/useWalrusRelay.ts"
|
|
18
|
-
],
|
|
19
|
-
"out": "docs/api",
|
|
20
|
-
"readme": "none",
|
|
21
|
-
"excludeInternal": true,
|
|
22
|
-
"excludePrivate": true,
|
|
23
|
-
"excludeExternals": true,
|
|
24
|
-
"includeVersion": true,
|
|
25
|
-
"skipErrorChecking": true,
|
|
26
|
-
"categorizeByGroup": true,
|
|
27
|
-
"validation": {
|
|
28
|
-
"invalidLink": false,
|
|
29
|
-
"notExported": false
|
|
30
|
-
},
|
|
31
|
-
"navigationLinks": {
|
|
32
|
-
"Repository": "https://github.com/meddleware"
|
|
33
|
-
}
|
|
34
|
-
}
|
package/vite.config.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { defineConfig, loadEnv } from 'vite'
|
|
2
|
-
import vue from '@vitejs/plugin-vue'
|
|
3
|
-
|
|
4
|
-
const ZERO_ADDR = '0x' + '0'.repeat(64)
|
|
5
|
-
|
|
6
|
-
// Networks a production build must have a real (non-zero) treasury for. Mirrors
|
|
7
|
-
// SELECTABLE_NETWORKS in src/config.ts — kept as a literal here to avoid importing
|
|
8
|
-
// app code into the build config.
|
|
9
|
-
const REQUIRED_TREASURY_NETWORKS = ['TESTNET', 'MAINNET'] as const
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Fail a production build when a selectable network's fee treasury is still the
|
|
13
|
-
* zero address, so revenue can never silently burn to 0x0. Bypass for dev/e2e
|
|
14
|
-
* builds with VITE_ALLOW_UNSET_TREASURY=1 (or VITE_E2E=1).
|
|
15
|
-
*/
|
|
16
|
-
function assertTreasuryConfigured(env: Record<string, string>): void {
|
|
17
|
-
if (env.VITE_ALLOW_UNSET_TREASURY === '1' || env.VITE_E2E === '1') return
|
|
18
|
-
const unset = REQUIRED_TREASURY_NETWORKS.filter((n) => {
|
|
19
|
-
const v = env[`VITE_FEE_TREASURY_${n}`]
|
|
20
|
-
return !v || v === ZERO_ADDR
|
|
21
|
-
})
|
|
22
|
-
if (unset.length > 0) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
`Refusing to build: fee treasury unset (zero address) for ${unset.join(', ')}. ` +
|
|
25
|
-
`Set VITE_FEE_TREASURY_${unset[0]} (see .env.production/.env.example), ` +
|
|
26
|
-
`or set VITE_ALLOW_UNSET_TREASURY=1 for a dev/e2e build.`,
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// The move-bytecode-template package ships a .wasm that must be served as an
|
|
32
|
-
// asset; `wasm` is excluded from dep-optimization so its URL import resolves.
|
|
33
|
-
/** Public origin used for the canonical URL + Open Graph tags (`%VITE_PUBLIC_URL%` in index.html). */
|
|
34
|
-
const DEFAULT_PUBLIC_URL = 'https://sui-token-deployer.meddleware.co.uk'
|
|
35
|
-
|
|
36
|
-
export default defineConfig(({ command, mode }) => {
|
|
37
|
-
const env = loadEnv(mode, process.cwd(), '')
|
|
38
|
-
if (command === 'build' && mode === 'production') assertTreasuryConfigured(env)
|
|
39
|
-
// Every mode (dev, e2e, production) resolves the placeholder; a white-label deployment overrides it
|
|
40
|
-
// with VITE_PUBLIC_URL (Docker build arg / CI var / .env file).
|
|
41
|
-
process.env.VITE_PUBLIC_URL = (env.VITE_PUBLIC_URL || DEFAULT_PUBLIC_URL).replace(/\/+$/, '')
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
base: "/",
|
|
45
|
-
plugins: [vue()],
|
|
46
|
-
optimizeDeps: {
|
|
47
|
-
// @meddleware/wallet-adapter ships TS + .vue source and holds the shared wallet singleton; if it
|
|
48
|
-
// were pre-bundled, its .vue files (served raw) would load a second copy of the singleton in dev.
|
|
49
|
-
exclude: ['@mysten/move-bytecode-template', '@meddleware/wallet-adapter'],
|
|
50
|
-
},
|
|
51
|
-
build: {
|
|
52
|
-
target: 'esnext',
|
|
53
|
-
rollupOptions: {
|
|
54
|
-
output: {
|
|
55
|
-
// Pin the Sui SDK into its own long-lived vendor chunk so app changes
|
|
56
|
-
// don't bust its cache. Matched by module id (not package entry, which
|
|
57
|
-
// @mysten/sui does not expose). @mysten/walrus + move-bytecode-template
|
|
58
|
-
// are explicitly left out so they stay in their lazy dynamic chunks.
|
|
59
|
-
manualChunks(id: string) {
|
|
60
|
-
if (id.includes('@mysten/walrus') || id.includes('move-bytecode-template')) return
|
|
61
|
-
if (
|
|
62
|
-
id.includes('@mysten/sui') ||
|
|
63
|
-
id.includes('@mysten/bcs') ||
|
|
64
|
-
id.includes('@mysten/wallet-standard')
|
|
65
|
-
) {
|
|
66
|
-
return 'vendor-sui'
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
})
|