@meddleware/token-deployer-ui 0.0.8 → 0.0.10

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 (64) hide show
  1. package/.env.example +8 -11
  2. package/.github/workflows/e2e-realchain.yml +1 -1
  3. package/.github/workflows/node-ci.yml +9 -0
  4. package/.github/workflows/npm-publish.yml +16 -2
  5. package/.htmlvalidate.mjs +30 -0
  6. package/CLAUDE.md +14 -7
  7. package/Dockerfile +1 -1
  8. package/LICENSE +11 -118
  9. package/README.md +3 -5
  10. package/eslint.config.ts +63 -0
  11. package/index.html +11 -2
  12. package/package.json +32 -10
  13. package/postcss.config.js +8 -0
  14. package/public/og-image.png +0 -0
  15. package/public/robots.txt +1 -1
  16. package/public/sitemap.xml +1 -1
  17. package/scripts/e2e-deploy.mjs +22 -17
  18. package/scripts/e2e-localnet.mjs +14 -12
  19. package/scripts/e2e-walrus-browser.mjs +1 -4
  20. package/scripts/gen-og-image.mjs +2 -2
  21. package/scripts/publish-localnet.mjs +5 -4
  22. package/src/App.vue +8 -6
  23. package/src/component-styles.css +5 -38
  24. package/src/components/ConfigForm.vue +74 -28
  25. package/src/components/DeployProgress.vue +2 -4
  26. package/src/components/GithubPush.vue +22 -7
  27. package/src/components/IconPicker.vue +103 -42
  28. package/src/components/LicensePicker.vue +66 -66
  29. package/src/components/MyTokens.vue +125 -0
  30. package/src/components/ResultPanel.vue +2 -4
  31. package/src/components/ReviewPanel.vue +1 -1
  32. package/src/components/TermsDialog.vue +28 -27
  33. package/src/components/TokenDeployerView.vue +109 -40
  34. package/src/components/WalletBar.vue +67 -78
  35. package/src/components/WalrusBlobBrowser.vue +33 -25
  36. package/src/composables/useAccessGate.ts +7 -2
  37. package/src/composables/useWalrusRelay.ts +1 -1
  38. package/src/config.ts +10 -13
  39. package/src/lib/accessGate.ts +28 -14
  40. package/src/lib/buildPublishTx.ts +1 -1
  41. package/src/lib/deploy.ts +36 -0
  42. package/src/lib/deployExecutor.ts +14 -12
  43. package/src/lib/generatePackage.ts +18 -13
  44. package/src/lib/licenses.ts +4 -3
  45. package/src/lib/listMyTokens.ts +41 -0
  46. package/src/lib/readClient.ts +15 -7
  47. package/src/lib/types.ts +1 -1
  48. package/src/lib/validation.ts +8 -4
  49. package/src/lib/walrus-constants.ts +1 -1
  50. package/src/lib/walrus.ts +22 -11
  51. package/src/main.ts +46 -58
  52. package/src/styles.css +13 -5
  53. package/src/template-src/files.json +7 -7
  54. package/stylelint.config.js +33 -0
  55. package/test-results/.last-run.json +1 -1
  56. package/tests/accessGate.test.ts +26 -21
  57. package/tests/deploy.test.ts +70 -2
  58. package/tests/generatePackage.test.ts +11 -0
  59. package/tests/licenses.test.ts +6 -3
  60. package/tests/listMyTokens.test.ts +30 -0
  61. package/tests/useAccessGate.test.ts +15 -19
  62. package/typedoc.json +2 -2
  63. package/vite.config.ts +9 -1
  64. package/src/components/WalrusIconUpload.vue +0 -205
@@ -1,205 +0,0 @@
1
- <script setup lang="ts">
2
- import { ref, onMounted, computed } from 'vue'
3
- import { useWallet } from '@meddleware/wallet-adapter'
4
- import { buildDeployExecutor } from '../lib/deployExecutor.js'
5
- import { useWalrusRelay } from '../composables/useWalrusRelay.js'
6
- import { ICON_EPOCHS } from '../lib/walrus-constants.js'
7
- import { ICON_MAX_BYTES, validateIconFile } from '../config.js'
8
- import type { WalrusNetwork } from '../lib/walrus.js'
9
- import type { Network } from '../lib/types.js'
10
- import { UiNotice } from '@meddleware/ui'
11
- // Vite serves the Walrus wasm as an asset URL (lightweight import — just the URL).
12
- import walrusWasmUrl from '@mysten/walrus-wasm/web/walrus_wasm_bg.wasm?url'
13
-
14
- const props = defineProps<{ network: WalrusNetwork; connected: boolean }>()
15
- const emit = defineEmits<{ (e: 'uploaded', url: string): void }>()
16
-
17
- const { account } = useWallet()
18
- const {
19
- selectedRelayHost,
20
- availableRelays,
21
- estimatedCost,
22
- fileSizeBytes,
23
- checkOperatorRelayHealth,
24
- } = useWalrusRelay(props.network)
25
-
26
- const uploading = ref(false)
27
- const status = ref('')
28
- const error = ref<string | null>(null)
29
- const fileName = ref('')
30
- let bytes: Uint8Array | null = null
31
-
32
- const maxSizeLabel = `${Math.round(ICON_MAX_BYTES / 1024)} KB`
33
- const ICON_YEARS = Math.round(ICON_EPOCHS / 26)
34
-
35
- onMounted(() => {
36
- checkOperatorRelayHealth()
37
- })
38
-
39
- const showPublicRelayNotice = computed(() => availableRelays.value.length > 1)
40
-
41
- const showFreeRelayTip = computed(() => {
42
- const publicHost = availableRelays.value.find((r) => r.isPublic)?.host
43
- return showPublicRelayNotice.value && selectedRelayHost.value !== publicHost
44
- })
45
-
46
- function onFile(e: Event): void {
47
- error.value = null
48
- bytes = null
49
- fileName.value = ''
50
- const f = (e.target as HTMLInputElement).files?.[0]
51
- if (!f) return
52
-
53
- // UX/cost guard only — the authoritative cap is the edge (relay) body limit.
54
- const invalid = validateIconFile(f)
55
- if (invalid) {
56
- error.value = invalid
57
- return
58
- }
59
-
60
- fileName.value = f.name
61
- fileSizeBytes.value = f.size
62
- const reader = new FileReader()
63
- reader.onload = () => {
64
- bytes = new Uint8Array(reader.result as ArrayBuffer)
65
- }
66
- reader.readAsArrayBuffer(f)
67
- }
68
-
69
- function onRelayChange(newHost: string): void {
70
- selectedRelayHost.value = newHost
71
- }
72
-
73
- async function upload(): Promise<void> {
74
- if (!bytes) {
75
- error.value = 'Choose an image first.'
76
- return
77
- }
78
- if (!account.value) {
79
- error.value = 'Connect your wallet first.'
80
- return
81
- }
82
- uploading.value = true
83
- error.value = null
84
- try {
85
- // Lazily load the heavy @mysten/walrus code and Sui client only on demand.
86
- const { createWalrusClient, createBlobUploadFlow, walrusBlobUrl } =
87
- await import('../lib/walrus.js')
88
- const { getReadClient } = await import('../lib/readClient.js')
89
- const executor = await buildDeployExecutor(props.network as Network)
90
- const suiClient = getReadClient(props.network as Network)
91
- const client = createWalrusClient(props.network, {
92
- wasmUrl: walrusWasmUrl,
93
- uploadRelayHost: selectedRelayHost.value,
94
- })
95
- const flow = createBlobUploadFlow(client, bytes)
96
-
97
- status.value = 'Encoding…'
98
- await flow.encode()
99
-
100
- // Disclose the relay fee before asking for a signature. `calculateUploadRelayTip`
101
- // takes the UNENCODED size and throws if the tip exceeds the client max guard.
102
- let feeNote = ''
103
- try {
104
- const tipMist = await client.walrus.calculateUploadRelayTip({ size: bytes.length })
105
- const tipSui = Number(tipMist) / 1e9
106
- feeNote = tipMist > 0n ? ` Relay fee ≈ ${tipSui.toFixed(4)} SUI + storage (WAL).` : ''
107
- } catch {
108
- // Non-fatal for disclosure; the register step surfaces any real tip error.
109
- }
110
-
111
- status.value = `Registering blob (approve in wallet)…${feeNote}`
112
- const regTx = flow.register({
113
- owner: account.value.address,
114
- epochs: ICON_EPOCHS,
115
- deletable: false,
116
- })
117
- // Set sender and build with the Sui client to resolve CoinWithBalance intents
118
- regTx.setSenderIfNotSet(account.value.address)
119
- await regTx.build({ client: suiClient })
120
- const reg = await executor.signAndExecute(regTx)
121
- await executor.waitForTransaction(reg.digest)
122
-
123
- status.value = 'Uploading to the relay…'
124
- await flow.upload({ digest: reg.digest })
125
-
126
- status.value = 'Certifying (approve in wallet)…'
127
- const certTx = flow.certify()
128
- // Set sender and build the certify transaction with the Sui client
129
- certTx.setSenderIfNotSet(account.value.address)
130
- await certTx.build({ client: suiClient })
131
- const cert = await executor.signAndExecute(certTx)
132
- await executor.waitForTransaction(cert.digest)
133
-
134
- const blob = await flow.getBlob()
135
- emit('uploaded', walrusBlobUrl(props.network, blob.blobId))
136
- status.value = 'Uploaded ✓ — URL filled in above.'
137
- } catch (e) {
138
- error.value = e instanceof Error ? e.message : String(e)
139
- status.value = ''
140
- } finally {
141
- uploading.value = false
142
- }
143
- }
144
- </script>
145
-
146
- <template>
147
- <div>
148
- <label for="walrus-file" class="hint" style="display: block; font-weight: 600">
149
- …or upload an image to Walrus
150
- </label>
151
- <div class="row">
152
- <input
153
- id="walrus-file"
154
- type="file"
155
- accept="image/*"
156
- aria-label="Choose an image to upload to Walrus"
157
- aria-describedby="walrus-help"
158
- style="width: auto"
159
- @change="onFile"
160
- />
161
- <button type="button" :disabled="uploading || !connected || !fileName" @click="upload">
162
- <span v-if="uploading" class="spinner" aria-hidden="true"></span>
163
- Upload to Walrus
164
- </button>
165
- </div>
166
-
167
- <!-- Relay selection (shown only if multiple relays available) -->
168
- <fieldset v-if="fileName && availableRelays.length > 1" style="margin: 0.75rem 0">
169
- <legend>Upload relay</legend>
170
- <div style="display: flex; flex-direction: column; gap: 0.5rem">
171
- <label
172
- v-for="option in availableRelays"
173
- :key="option.host"
174
- style="display: flex; align-items: center; gap: 0.5rem"
175
- >
176
- <input
177
- type="radio"
178
- :value="option.host"
179
- :checked="selectedRelayHost === option.host"
180
- @change="(e) => onRelayChange((e.target as HTMLInputElement).value)"
181
- />
182
- <span>{{ option.label }}</span>
183
- </label>
184
- </div>
185
- </fieldset>
186
-
187
- <!-- Cost estimation (shown after file selection) -->
188
- <UiNotice v-if="fileName && estimatedCost" style="margin: 0.75rem 0">
189
- <strong>Estimated cost:</strong> {{ estimatedCost.label }}
190
- </UiNotice>
191
-
192
- <!-- Public relay notice -->
193
- <p v-if="showFreeRelayTip" class="hint" style="margin: 0.75rem 0">
194
- Tip: select the public relay above to avoid the relay fee.
195
- </p>
196
-
197
- <p id="walrus-help" class="hint" aria-live="polite">
198
- Max {{ maxSizeLabel }} · PNG/JPEG/WebP/SVG. Requires <strong>WAL</strong> (storage) and
199
- <strong>SUI</strong> (gas + a small relay fee) in your wallet; two wallet approvals. Blob
200
- stored for ~{{ ICON_YEARS }} years.
201
- <span v-if="status">{{ status }}</span>
202
- </p>
203
- <UiNotice v-if="error" type="error">{{ error }}</UiNotice>
204
- </div>
205
- </template>