@meddleware/walrus-storage-ui 0.1.68 → 0.1.70
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/CHANGELOG.md +30 -1
- package/LICENSE +1 -1
- package/README.md +10 -5
- package/index.html +2 -3
- package/package.json +16 -10
- package/src/App.vue +11 -22
- package/src/availability.ts +21 -0
- package/src/components/WalrusStorageView.vue +2 -2
- package/src/composables/useOwnedBlobs.ts +6 -2
- package/src/composables/useStorageUpload.ts +2 -2
- package/src/config.ts +92 -14
- package/src/main.ts +2 -4
- package/tsconfig.json +1 -15
- package/vite.config.ts +12 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to `@meddleware/walrus-ui` are documented here.
|
|
3
|
+
All notable changes to `@meddleware/walrus-storage-ui` are documented here.
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/). Before 0.2.0, breaking changes ship as patch releases.
|
|
6
6
|
|
|
7
|
+
## [0.1.70] - 2026-11-12
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- The header shows the company mark (the Kopimi "K") beside the tool name (`@meddleware/ui` 0.1.41 `AppToolShell`).
|
|
12
|
+
- The favicon set (SVG, ICO, Apple touch icon, 192 and 512 icons, web manifest named "Walrus Assets") now comes from `@meddleware/frontend-config` 0.0.8 (`meddlewareApp({ name })`); the app's own `public/favicon.svg` and its icon link tag are removed.
|
|
13
|
+
- Dependencies: `@meddleware/ui` ^0.1.41, `@meddleware/frontend-config` ^0.0.8, `@meddleware/web-utils` ^0.0.4.
|
|
14
|
+
- CI and release workflows set `DO_NOT_TRACK=1`.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Tests: the header shows the mark; sources and the production build name no third-party font, CDN or tracker, ship no font files and carry the brand icon set (run over `dist/` in CI after the build).
|
|
19
|
+
|
|
20
|
+
## [0.1.69] - 2026-11-07
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Words for a person: the page title is "Walrus Assets · Meddleware" (it was "Walrus Uploader · MeddleWare") and the description says what the app does for its reader. The licence holder is spelled Meddleware.
|
|
25
|
+
- Where Walrus storage cannot be used the page says so in plain words and shows no tool: "not available on localnet" (and the networks to switch to), or "not available here right now" for a relay address that is not https or a gate id that is not an object id. A gate id set for a network with no recorded `access_gate` deployment makes that network unavailable instead of silently serving it without the pass. Which networks to suggest comes from the same checks, not from prose. The variable names go to the browser console only.
|
|
26
|
+
- A failed owned-blob load says "Your blobs could not be loaded. Check your connection and press Refresh."; the cause goes to the console.
|
|
27
|
+
- `@meddleware/walrus-storage-kit` ^0.1.38 (the access-pass prompt reads "This upload relay" and "Gate owner receives"; the estimated relay fee is exact), `@meddleware/ui` ^0.1.40, `@meddleware/web-utils` ^0.0.3, `@meddleware/wallet-adapter` ^0.0.22 (peer range now `>=0.0.22 <0.2.0`).
|
|
28
|
+
|
|
29
|
+
### Internal
|
|
30
|
+
|
|
31
|
+
- The standalone shell is the shared `AppToolShell` (the relay badge stays in its `actions` slot); the network comes from `selectBuiltNetwork`.
|
|
32
|
+
- `@meddleware/frontend-config` ^0.0.7: `vite.config.ts` is `meddlewareApp`, `vitest.config.ts` is `vueTestConfig`, `tsconfig.json` extends the shared base; the local audit gate and licence scripts are replaced by `mw-audit-gate` and `mw-third-party-licenses`; `mw-sync --check` and a CSP inline-script check (`npm run check:csp`, also in the image build) run in CI. The `"meddleware"` section of package.json declares the CSP profile (`chain-wasm`) and Lighthouse use.
|
|
33
|
+
- Removed the unused `public/CNAME`, `public/_headers` and `public/_redirects` (the image is served by static-server, which sets the headers and the SPA fallback). `AGENTS.md` points to `CLAUDE.md`.
|
|
34
|
+
- New tests: `availability`, the availability cases of `config`, the unavailable view, the shell, the plain load failure and a wording test over `index.html` and every template.
|
|
35
|
+
|
|
7
36
|
## [0.1.68] - 2026-11-06
|
|
8
37
|
|
|
9
38
|
### Changed
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
|
|
5
5
|
A Vue 3 SPA for uploading and managing blobs on [Walrus](https://walrus.xyz) decentralised
|
|
6
|
-
storage on Sui. Supports NFT-gated
|
|
6
|
+
storage on Sui. Supports NFT-gated Meddleware relays (commission-enforced on-chain via
|
|
7
7
|
`access_gate`) with automatic fallback to the public Mysten relay.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
11
|
- Connect any Sui wallet (wallet-standard)
|
|
12
|
-
- Select between
|
|
12
|
+
- Select between the Meddleware relay (supports the app) and the public relay (free)
|
|
13
13
|
- Upload blobs through an NFT-gated or open relay
|
|
14
14
|
- View and extend your owned Walrus blobs
|
|
15
15
|
- Two-approval upload flow: register tx → upload → certify tx
|
|
@@ -32,17 +32,22 @@ All `VITE_*` vars are baked into the static bundle at build time.
|
|
|
32
32
|
| Variable | Default | Description |
|
|
33
33
|
| --- | --- | --- |
|
|
34
34
|
| `VITE_NETWORK` | `testnet` | Network the standalone build selects (`testnet` or `mainnet`); embedded, the host's selector rules |
|
|
35
|
-
| `VITE_WALRUS_RELAY_TESTNET` | Public Mysten relay |
|
|
36
|
-
| `VITE_WALRUS_RELAY_MAINNET` | Public Mysten relay |
|
|
35
|
+
| `VITE_WALRUS_RELAY_TESTNET` | Public Mysten relay | Meddleware relay URL for testnet (https; plain http only on localhost) |
|
|
36
|
+
| `VITE_WALRUS_RELAY_MAINNET` | Public Mysten relay | Meddleware relay URL for mainnet (https; plain http only on localhost) |
|
|
37
37
|
| `VITE_ACCESS_GATE_ID_TESTNET` | — | Gate object ID (testnet; unset = no gate) |
|
|
38
38
|
| `VITE_ACCESS_GATE_SOULBOUND_TESTNET` | `false` | `true` if NFTs are soulbound |
|
|
39
39
|
| `VITE_ACCESS_GATE_ID_MAINNET` | — | Gate object ID (mainnet) |
|
|
40
40
|
| `VITE_UPLOAD_RELAY_MAX_TIP_MIST` | `5000000` | Max relay tip cap in MIST (0.005 SUI) |
|
|
41
41
|
|
|
42
42
|
The `access_gate` package and `PlatformConfig` come from the published deployment
|
|
43
|
-
(`relayGateConfig` in `@meddleware/walrus-storage-kit`) —
|
|
43
|
+
(`relayGateConfig` in `@meddleware/walrus-storage-kit`) — a deployment only configures the values listed
|
|
44
44
|
above.
|
|
45
45
|
|
|
46
|
+
A setting the app cannot serve (a relay URL that is not https, a gate id that is not an object id) makes that network
|
|
47
|
+
read "not available here right now" to a person; the variable is named only in the browser console. A gate id set for a
|
|
48
|
+
network with no recorded `access_gate` deployment makes the network "not available on <network>" (it would otherwise be
|
|
49
|
+
served without the pass). Networks to switch to are the ones that pass the same checks.
|
|
50
|
+
|
|
46
51
|
## Docker build
|
|
47
52
|
|
|
48
53
|
The Docker context is this repo root. `@meddleware/walrus-storage-kit` resolves from the npm registry,
|
package/index.html
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
<meta name="description" content="Upload blobs to Walrus decentralised storage on Sui through the MeddleWare relay. Client-side; your wallet signs and pays." />
|
|
6
|
+
<title>Walrus Assets · Meddleware</title>
|
|
7
|
+
<meta name="description" content="Upload files to Walrus decentralised storage on Sui and manage the blobs you own: see how long they last, extend them, finish an upload. Runs in your browser; your wallet signs and pays." />
|
|
9
8
|
</head>
|
|
10
9
|
<body>
|
|
11
10
|
<div id="app"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meddleware/walrus-storage-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.70",
|
|
4
4
|
"homepage": "https://docs.meddleware.co.uk/blockchain/sui/walrus-storage/",
|
|
5
5
|
"description": "Standalone Vue 3 SPA for uploading blobs to Walrus decentralised storage and managing owned blobs — wallet-connected, NFT-gated relay support.",
|
|
6
6
|
"author": "Meddleware <dev@meddleware.co.uk>",
|
|
@@ -42,34 +42,35 @@
|
|
|
42
42
|
"lint:js": "eslint .",
|
|
43
43
|
"lint": "npm run lint:css && npm run lint:js && npm run lint:html",
|
|
44
44
|
"lint:html": "html-validate \"src/**/*.vue\"",
|
|
45
|
-
"licenses": "
|
|
46
|
-
"check:licenses": "
|
|
45
|
+
"licenses": "mw-third-party-licenses",
|
|
46
|
+
"check:licenses": "mw-third-party-licenses --check",
|
|
47
47
|
"shots": "SHOTS=1 playwright test",
|
|
48
48
|
"lhci": "npm run build && lhci autorun",
|
|
49
|
-
"check:bundle": "check-prod-bundle dist"
|
|
49
|
+
"check:bundle": "check-prod-bundle dist",
|
|
50
|
+
"check:csp": "mw-check-csp-inline @Dockerfile dist"
|
|
50
51
|
},
|
|
51
52
|
"publishConfig": {
|
|
52
53
|
"access": "public"
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
56
|
"@meddleware/design-tokens": "^0.1.13",
|
|
56
|
-
"@meddleware/ui": "^0.1.
|
|
57
|
+
"@meddleware/ui": "^0.1.41",
|
|
57
58
|
"@meddleware/walrus-storage-client": "^0.0.34",
|
|
58
|
-
"@meddleware/walrus-storage-kit": "^0.1.
|
|
59
|
-
"@meddleware/web-utils": "^0.0.
|
|
59
|
+
"@meddleware/walrus-storage-kit": "^0.1.39",
|
|
60
|
+
"@meddleware/web-utils": "^0.0.4",
|
|
60
61
|
"@mysten/sui": "^2.33.2",
|
|
61
62
|
"@mysten/walrus": "~1.2.32",
|
|
62
63
|
"@mysten/walrus-wasm": "~0.3.1",
|
|
63
64
|
"vue": "^3.5.43"
|
|
64
65
|
},
|
|
65
66
|
"peerDependencies": {
|
|
66
|
-
"@meddleware/wallet-adapter": ">=0.0.
|
|
67
|
+
"@meddleware/wallet-adapter": ">=0.0.22 <0.2.0"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
70
|
"@lhci/cli": "^0.15.1",
|
|
70
71
|
"@meddleware/access-gate-client": "^0.0.13",
|
|
71
|
-
"@meddleware/frontend-config": "^0.0.
|
|
72
|
-
"@meddleware/wallet-adapter": "^0.0.
|
|
72
|
+
"@meddleware/frontend-config": "^0.0.8",
|
|
73
|
+
"@meddleware/wallet-adapter": "^0.0.22",
|
|
73
74
|
"@playwright/test": "~1.64.1",
|
|
74
75
|
"@types/node": "~26.6.5",
|
|
75
76
|
"@vitejs/plugin-vue": "^6.0.8",
|
|
@@ -103,5 +104,10 @@
|
|
|
103
104
|
"basic-ftp": "^6.2.4",
|
|
104
105
|
"tmp": "^0.2.7",
|
|
105
106
|
"zod": "^4.6.7"
|
|
107
|
+
},
|
|
108
|
+
"meddleware": {
|
|
109
|
+
"kind": "app",
|
|
110
|
+
"csp": "chain-wasm",
|
|
111
|
+
"lhci": true
|
|
106
112
|
}
|
|
107
113
|
}
|
package/src/App.vue
CHANGED
|
@@ -1,35 +1,24 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
// Standalone shell for the Walrus SPA:
|
|
2
|
+
// Standalone shell for the Walrus SPA: the shared tool shell (header, colour mode, footer) around the core tool view.
|
|
3
3
|
// The core UI lives in WalrusStorageView.vue (also exported for inline embedding in the dashboard).
|
|
4
|
-
import {
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
import { AppToolShell } from '@meddleware/ui'
|
|
5
6
|
import { TipConfigBadge } from '@meddleware/walrus-storage-kit'
|
|
6
7
|
import { walrusNetwork, OPERATOR_RELAY_HOSTS } from './config.js'
|
|
7
8
|
import WalrusStorageView from './components/WalrusStorageView.vue'
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
/** The relay of the active network (the badge shows whether it is up and what it tips); none where Walrus storage cannot be used. */
|
|
11
|
+
const relayHost = computed(() => (walrusNetwork.value ? OPERATOR_RELAY_HOSTS[walrusNetwork.value] : null))
|
|
12
|
+
const DOCS_URL = import.meta.env.VITE_DOCS_URL || undefined
|
|
13
|
+
const DEV_URL = import.meta.env.VITE_DEV_URL || undefined
|
|
12
14
|
</script>
|
|
13
15
|
|
|
14
16
|
<template>
|
|
15
|
-
<
|
|
16
|
-
<template #
|
|
17
|
-
<
|
|
18
|
-
<template #brand>Walrus Assets</template>
|
|
19
|
-
<template #actions>
|
|
20
|
-
<TipConfigBadge v-if="walrusNetwork" :host="OPERATOR_RELAY_HOSTS[walrusNetwork]" />
|
|
21
|
-
<ColorModeControl :model-value="mode" @update:model-value="set" />
|
|
22
|
-
</template>
|
|
23
|
-
</AppHeader>
|
|
17
|
+
<AppToolShell title="Walrus Assets" slug="walrus-storage" :docs-url="DOCS_URL" :dev-url="DEV_URL">
|
|
18
|
+
<template #actions>
|
|
19
|
+
<TipConfigBadge v-if="relayHost" :host="relayHost" />
|
|
24
20
|
</template>
|
|
25
21
|
|
|
26
|
-
<h1 class="mw-visually-hidden">Walrus Assets</h1>
|
|
27
22
|
<WalrusStorageView />
|
|
28
|
-
|
|
29
|
-
<template #footer>
|
|
30
|
-
<AppFooter :docs-url="DOCS_URL" :dev-url="DEV_URL">
|
|
31
|
-
<CopyrightLine symbol-variant="kopimi" organisation-name="Meddleware" rights-statement="jam" />
|
|
32
|
-
</AppFooter>
|
|
33
|
-
</template>
|
|
34
|
-
</UiAppShell>
|
|
23
|
+
</AppToolShell>
|
|
35
24
|
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// What a person is told when Walrus storage cannot be used on a network. Nothing here names a build variable or a missing setting: a
|
|
2
|
+
// person can do nothing about those, so they read what they can do (wait, or use another network); the technical cause goes to the
|
|
3
|
+
// console (`config.ts` logs it) and to the developer docs.
|
|
4
|
+
//
|
|
5
|
+
// Which networks to suggest is not decided here: `config.ts` passes the networks that currently pass its checks, which follow the
|
|
6
|
+
// deployment records and the configured relay hosts, never prose.
|
|
7
|
+
|
|
8
|
+
/** " Switch to testnet." (or "testnet or mainnet"), or nothing where no other network can be used. */
|
|
9
|
+
function switchHint(others: readonly string[]): string {
|
|
10
|
+
return others.length ? ` Switch to ${others.join(' or ')}.` : ''
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** The network is not one Walrus storage is offered on (no recorded deployment, or no Walrus there): not a fault. */
|
|
14
|
+
export function notAvailableOn(net: string, others: readonly string[]): string {
|
|
15
|
+
return `Walrus storage is not available on ${net}.${switchHint(others)}`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The network is offered but this site cannot serve it right now (a setting the person cannot change). */
|
|
19
|
+
export function notAvailableNow(others: readonly string[]): string {
|
|
20
|
+
return `Walrus storage is not available here right now. Try again later${others.length ? ` or switch to ${others.join(' or ')}` : ''}.`
|
|
21
|
+
}
|
|
@@ -9,7 +9,7 @@ import { WalletGuard } from '@meddleware/wallet-adapter'
|
|
|
9
9
|
import { AccessGateCta, WalrusUpload, useAccessGate, type WalrusNetwork } from '@meddleware/walrus-storage-kit'
|
|
10
10
|
import type { ExistingCopy } from '@meddleware/walrus-storage-client/flow'
|
|
11
11
|
import { buildExecutor, getSuiClient, useWallet } from '../wallet.js'
|
|
12
|
-
import { accessGate, network, relayHosts, walrusNetwork } from '../config.js'
|
|
12
|
+
import { accessGate, availability, network, relayHosts, walrusNetwork } from '../config.js'
|
|
13
13
|
import { useOwnedBlobs } from '../composables/useOwnedBlobs.js'
|
|
14
14
|
import { useStorageUpload, type UploadResult } from '../composables/useStorageUpload.js'
|
|
15
15
|
import MyBlobs from './MyBlobs.vue'
|
|
@@ -97,7 +97,7 @@ function onSettled(): void {
|
|
|
97
97
|
<h2 id="walrus-title">Walrus storage</h2>
|
|
98
98
|
<UiToolIntro>Upload and manage blobs on Walrus decentralised storage ({{ network }}).</UiToolIntro>
|
|
99
99
|
|
|
100
|
-
<UiNotice v-if="!walrusNetwork" type="info" :message="
|
|
100
|
+
<UiNotice v-if="!walrusNetwork" type="info" :message="availability.message ?? ''" />
|
|
101
101
|
<template v-else>
|
|
102
102
|
<AppTabNav v-model="activeTab" :tabs="TABS" id-prefix="walrus" aria-label="Feature tabs" />
|
|
103
103
|
|
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
// (used after an upload/extend, which can create or mutate on-chain blobs).
|
|
9
9
|
import { ref, shallowRef } from 'vue'
|
|
10
10
|
import type { OwnedBlob } from '@meddleware/walrus-storage-client'
|
|
11
|
-
import { errorMessage } from '@meddleware/web-utils'
|
|
12
11
|
import { getSuiClient } from '../wallet.js'
|
|
13
12
|
import { walrusNetwork } from '../config.js'
|
|
14
13
|
import { walrusClient, walrusLib } from '../walrus.js'
|
|
15
14
|
|
|
15
|
+
/** What a person reads when the list could not be loaded. */
|
|
16
|
+
export const LOAD_FAILED = 'Your blobs could not be loaded. Check your connection and press Refresh.'
|
|
17
|
+
|
|
16
18
|
const blobs = shallowRef<OwnedBlob[]>([])
|
|
17
19
|
const currentEpoch = ref(0)
|
|
18
20
|
const loading = ref(false)
|
|
@@ -75,7 +77,9 @@ async function load(address: string | null, opts: { force?: boolean } = {}): Pro
|
|
|
75
77
|
loadedFor.value = key
|
|
76
78
|
} catch (e) {
|
|
77
79
|
if (mine !== latest) return
|
|
78
|
-
|
|
80
|
+
// The page says what the person can do; the technical cause (an RPC or decoding error) goes to the console.
|
|
81
|
+
console.error('walrus-storage-ui: could not load the owned blobs', e)
|
|
82
|
+
error.value = LOAD_FAILED
|
|
79
83
|
} finally {
|
|
80
84
|
if (mine === latest) {
|
|
81
85
|
loading.value = false
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
type ExistingCopy,
|
|
15
15
|
type UploadProgress,
|
|
16
16
|
} from '@meddleware/walrus-storage-client/flow'
|
|
17
|
-
import {
|
|
17
|
+
import { availability, relayHosts, uploadRelayMaxTipMist, walrusNetwork } from '../config.js'
|
|
18
18
|
import { buildExecutor, getSuiClient, useWallet } from '../wallet.js'
|
|
19
19
|
import { walrusClient, walrusLib, walrusWasmUrl } from '../walrus.js'
|
|
20
20
|
|
|
@@ -59,7 +59,7 @@ export function useStorageUpload(gate: () => AccessGateState) {
|
|
|
59
59
|
async function performUpload(bytes: Uint8Array, opts: UploadOptions): Promise<UploadResult> {
|
|
60
60
|
if (!account.value) throw new Error('Connect your wallet first.')
|
|
61
61
|
const net = walrusNetwork.value
|
|
62
|
-
if (!net) throw new Error(
|
|
62
|
+
if (!net) throw new Error(availability.value.message ?? 'Walrus storage is not available here.')
|
|
63
63
|
const executor = await buildExecutor()
|
|
64
64
|
const address = account.value.address
|
|
65
65
|
const access = accessFor({
|
package/src/config.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
// Configuration. The network is wallet-adapter's shared runtime selector (the standalone build
|
|
2
|
-
// selects VITE_NETWORK in main.ts; embedded, the host's selector rules).
|
|
2
|
+
// selects VITE_NETWORK in main.ts; embedded, the host's selector rules). Deployment settings are
|
|
3
3
|
// build-time VITE_* per network: relay hostnames default to the public Mysten relay (set
|
|
4
|
-
// VITE_WALRUS_RELAY_* to
|
|
4
|
+
// VITE_WALRUS_RELAY_* to the Meddleware relay to collect the tip); the access gate is optional
|
|
5
5
|
// (unset ⇒ ungated), and its package + PlatformConfig come from the published deployment; the
|
|
6
6
|
// purchase price and payees are read from the chain, never configured.
|
|
7
|
-
|
|
7
|
+
//
|
|
8
|
+
// A configuration fault is shown to a person as a plain "not available" (`./availability.js`); the technical cause (which variable)
|
|
9
|
+
// is logged to the console for the developer (D117). Which networks are offered follows the deployment records and the configured
|
|
10
|
+
// relay hosts, never prose.
|
|
11
|
+
import { computed, watch } from 'vue'
|
|
8
12
|
import type { WalrusNetwork, RelayGateConfig } from '@meddleware/walrus-storage-kit'
|
|
9
|
-
import { PUBLIC_WALRUS_RELAY_HOSTS, relayGateConfig } from '@meddleware/walrus-storage-kit'
|
|
13
|
+
import { PUBLIC_WALRUS_RELAY_HOSTS, relayGateConfig, requireHttpsHost } from '@meddleware/walrus-storage-kit'
|
|
14
|
+
import { accessGateDeployment } from '@meddleware/access-gate-client/deployments'
|
|
15
|
+
import { isValidSuiObjectId } from '@mysten/sui/utils'
|
|
10
16
|
import { useNetwork } from '@meddleware/wallet-adapter'
|
|
11
17
|
import { withRuntimeEnv } from '@meddleware/ui'
|
|
12
18
|
import { errorMessage } from '@meddleware/web-utils'
|
|
19
|
+
import { notAvailableNow, notAvailableOn } from './availability.js'
|
|
13
20
|
|
|
14
21
|
/** Build-time env bag. Injectable on the env-reading helpers below purely so unit tests can exercise
|
|
15
22
|
* each branch without depending on Vite's (frozen) `import.meta.env` inlining. */
|
|
@@ -21,25 +28,96 @@ const env: EnvSource = withRuntimeEnv((import.meta as unknown as { env?: EnvSour
|
|
|
21
28
|
/** The active network (read-only ref). */
|
|
22
29
|
export const network = useNetwork().network
|
|
23
30
|
|
|
24
|
-
/** The
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
31
|
+
/** The Walrus networks this app can be built for (Walrus runs on these two; localnet has none). */
|
|
32
|
+
const WALRUS_NETWORKS: readonly WalrusNetwork[] = ['testnet', 'mainnet']
|
|
33
|
+
|
|
34
|
+
/** The Meddleware relay host for a network (env → public fallback). */
|
|
35
|
+
function relayHostFor(net: WalrusNetwork, envSource: EnvSource): string {
|
|
36
|
+
return (net === 'mainnet' ? envSource.VITE_WALRUS_RELAY_MAINNET : envSource.VITE_WALRUS_RELAY_TESTNET) || PUBLIC_WALRUS_RELAY_HOSTS[net]
|
|
37
|
+
}
|
|
28
38
|
|
|
29
|
-
/**
|
|
39
|
+
/** Meddleware relay host per network (env → public fallback). */
|
|
30
40
|
export const OPERATOR_RELAY_HOSTS: Record<WalrusNetwork, string> = {
|
|
31
|
-
testnet:
|
|
32
|
-
mainnet:
|
|
41
|
+
testnet: relayHostFor('testnet', env),
|
|
42
|
+
mainnet: relayHostFor('mainnet', env),
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
/** The
|
|
45
|
+
/** The Meddleware/public host pair for `useWalrusRelay` (its `operator` key is the library's name for the Meddleware relay). */
|
|
36
46
|
export function relayHosts(network: WalrusNetwork): { operator: string; public: string } {
|
|
37
47
|
return { operator: OPERATOR_RELAY_HOSTS[network], public: PUBLIC_WALRUS_RELAY_HOSTS[network] }
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
/** Whether Walrus storage can be used on a network, and what to tell a person when it cannot. */
|
|
51
|
+
export interface Availability {
|
|
52
|
+
/** True when the network is offered and its settings are usable. */
|
|
53
|
+
usable: boolean
|
|
54
|
+
/** Plain words for a person when `usable` is false; null otherwise. */
|
|
55
|
+
message: string | null
|
|
56
|
+
/** The technical cause (which setting or record), for the console; null when there is none. */
|
|
57
|
+
cause: string | null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The state of a network, before any message is written (pure; `envSource` is injectable for tests).
|
|
62
|
+
* `offered: false` is "it is not offered there" (localnet; a gate configured on a network with no recorded `access_gate`
|
|
63
|
+
* deployment, which could not be honoured); `offered: true` with a `cause` is a setting this site cannot serve.
|
|
64
|
+
*/
|
|
65
|
+
function inspect(net: string, envSource: EnvSource): { offered: boolean; cause: string | null } {
|
|
66
|
+
if (net !== 'testnet' && net !== 'mainnet') return { offered: false, cause: null }
|
|
67
|
+
const NET = net.toUpperCase()
|
|
68
|
+
const gateId = envSource[`VITE_ACCESS_GATE_ID_${NET}`]
|
|
69
|
+
if (gateId) {
|
|
70
|
+
try {
|
|
71
|
+
accessGateDeployment(net)
|
|
72
|
+
} catch {
|
|
73
|
+
// A gate cannot be honoured without the published package: serving the network ungated would silently skip the pass.
|
|
74
|
+
return { offered: false, cause: `VITE_ACCESS_GATE_ID_${NET} is set but no access_gate deployment is recorded for ${net}` }
|
|
75
|
+
}
|
|
76
|
+
if (!isValidSuiObjectId(gateId)) {
|
|
77
|
+
return { offered: true, cause: `VITE_ACCESS_GATE_ID_${NET} is not a Sui object id: "${gateId}"` }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
requireHttpsHost(relayHostFor(net, envSource), `VITE_WALRUS_RELAY_${NET}`)
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return { offered: true, cause: errorMessage(e) }
|
|
84
|
+
}
|
|
85
|
+
return { offered: true, cause: null }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Availability of Walrus storage on `net` (pure; the networks suggested to switch to are the ones that pass the same checks). */
|
|
89
|
+
export function availabilityOf(net: string, envSource: EnvSource = env): Availability {
|
|
90
|
+
const own = inspect(net, envSource)
|
|
91
|
+
if (own.offered && own.cause === null) return { usable: true, message: null, cause: null }
|
|
92
|
+
const others = WALRUS_NETWORKS.filter((n) => {
|
|
93
|
+
if (n === net) return false
|
|
94
|
+
const o = inspect(n, envSource)
|
|
95
|
+
return o.offered && o.cause === null
|
|
96
|
+
})
|
|
97
|
+
return { usable: false, message: own.offered ? notAvailableNow(others) : notAvailableOn(net, others), cause: own.cause }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Availability on the active network. */
|
|
101
|
+
export const availability = computed(() => availabilityOf(network.value))
|
|
102
|
+
|
|
103
|
+
/** The active network as a Walrus network, or null where Walrus storage cannot be used (localnet, or a network this site cannot serve). */
|
|
104
|
+
export const walrusNetwork = computed<WalrusNetwork | null>(() => (availability.value.usable ? (network.value as WalrusNetwork) : null))
|
|
105
|
+
|
|
106
|
+
// A configuration fault is told to the developer once per cause (a person sees only "not available").
|
|
107
|
+
const reported = new Set<string>()
|
|
108
|
+
watch(
|
|
109
|
+
availability,
|
|
110
|
+
(a) => {
|
|
111
|
+
if (!a.cause || reported.has(a.cause)) return
|
|
112
|
+
reported.add(a.cause)
|
|
113
|
+
console.error(`walrus-storage-ui: Walrus storage is unavailable on ${network.value} (${a.cause})`)
|
|
114
|
+
},
|
|
115
|
+
{ immediate: true },
|
|
116
|
+
)
|
|
117
|
+
|
|
40
118
|
/**
|
|
41
119
|
* Default relay tip ceiling (MIST) when `VITE_UPLOAD_RELAY_MAX_TIP_MIST` is unset: 0.005 SUI, the
|
|
42
|
-
* workspace-wide ceiling (~8× the
|
|
120
|
+
* workspace-wide ceiling (~8× the Meddleware relay's worst-case tip at the 100 MiB edge cap).
|
|
43
121
|
*/
|
|
44
122
|
export const DEFAULT_UPLOAD_RELAY_MAX_TIP_MIST = 5_000_000
|
|
45
123
|
|
|
@@ -54,7 +132,7 @@ export function uploadRelayMaxTipMist(envSource: EnvSource = env): number {
|
|
|
54
132
|
}
|
|
55
133
|
|
|
56
134
|
/**
|
|
57
|
-
* The optional NFT access gate for a network: the
|
|
135
|
+
* The optional NFT access gate for a network: the deployment supplies only the Gate id and soulbound
|
|
58
136
|
* flag (`VITE_ACCESS_GATE_*_{NET}`); `relayGateConfig` fixes the package and `PlatformConfig` to the
|
|
59
137
|
* published deployment (commission enforcement), and the price is read from the gate on the chain.
|
|
60
138
|
* `null` — an ungated
|
package/src/main.ts
CHANGED
|
@@ -3,13 +3,11 @@ import '@meddleware/design-tokens/seasons.css'
|
|
|
3
3
|
import '@meddleware/ui/reset.css'
|
|
4
4
|
import { createApp } from 'vue'
|
|
5
5
|
import { loadRuntimeConfig, useSeason } from '@meddleware/ui'
|
|
6
|
-
import {
|
|
6
|
+
import { selectBuiltNetwork } from '@meddleware/wallet-adapter'
|
|
7
7
|
|
|
8
8
|
// The standalone build targets one network; select it in the shared selector so the client, the
|
|
9
9
|
// relay, the gate and the stored resume keys all agree. (Embedded, the host's selector rules.)
|
|
10
|
-
|
|
11
|
-
const built = env.VITE_NETWORK || 'testnet'
|
|
12
|
-
if (built === 'testnet' || built === 'mainnet') useNetwork().setNetwork(built)
|
|
10
|
+
selectBuiltNetwork(import.meta.env.VITE_NETWORK || 'testnet')
|
|
13
11
|
|
|
14
12
|
useSeason()
|
|
15
13
|
// Machine-zone endpoints (the indexer, the Walrus relays) come from /runtime-config.json when the deployment
|
package/tsconfig.json
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "Bundler",
|
|
6
|
-
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"verbatimModuleSyntax": true,
|
|
13
|
-
"jsx": "preserve",
|
|
14
|
-
"types": ["node"],
|
|
15
|
-
"noEmit": true
|
|
16
|
-
},
|
|
2
|
+
"extends": "@meddleware/frontend-config/tsconfig/vue-app.json",
|
|
17
3
|
"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.d.ts", "vite.config.ts", "playwright.config.ts", "e2e/**/*.ts"]
|
|
18
4
|
}
|
package/vite.config.ts
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
import { defineConfig } from 'vite'
|
|
2
1
|
import vue from '@vitejs/plugin-vue'
|
|
3
|
-
import {
|
|
2
|
+
import { defineConfig } from 'vite'
|
|
3
|
+
import { meddlewareApp } from '@meddleware/frontend-config/vite'
|
|
4
4
|
|
|
5
|
-
// design-tokens and ui resolve from node_modules (published packages).
|
|
6
|
-
// @
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// were pre-bundled, its .vue files (served raw) would load a second copy of the singleton in dev.
|
|
16
|
-
exclude: ['@mysten/walrus', '@mysten/walrus-wasm', '@meddleware/wallet-adapter'],
|
|
17
|
-
},
|
|
18
|
-
}
|
|
19
|
-
})
|
|
5
|
+
// design-tokens and ui resolve from node_modules (published packages). meddlewareApp refuses VITE_E2E outside the e2e mode and keeps
|
|
6
|
+
// @meddleware/wallet-adapter (the shared wallet singleton) out of pre-bundling. @mysten/walrus and its wasm are excluded too, so the
|
|
7
|
+
// wasm `?url` import resolves.
|
|
8
|
+
export default defineConfig(
|
|
9
|
+
meddlewareApp({
|
|
10
|
+
plugins: [vue()],
|
|
11
|
+
name: 'Walrus Assets',
|
|
12
|
+
config: { optimizeDeps: { exclude: ['@mysten/walrus', '@mysten/walrus-wasm'] } },
|
|
13
|
+
}),
|
|
14
|
+
)
|