@meddleware/walrus-ui 0.1.24 → 0.1.25
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/package.json +2 -2
- package/src/components/WalrusView.vue +24 -16
- package/src/upload-flow.ts +23 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meddleware/walrus-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "Standalone Vue 3 SPA for uploading blobs to Walrus decentralised storage and managing owned blobs — wallet-connected, NFT-gated relay support.",
|
|
5
5
|
"author": "Meddleware <dev@meddleware.co.uk>",
|
|
6
6
|
"license": "0BSD",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@meddleware/ui": "^0.1.10",
|
|
46
46
|
"@meddleware/wallet-adapter": "^0.0.5",
|
|
47
47
|
"@meddleware/walrus-client": "^0.0.9",
|
|
48
|
-
"@meddleware/walrus-relay": "^0.1.
|
|
48
|
+
"@meddleware/walrus-relay": "^0.1.10",
|
|
49
49
|
"@mysten/sui": "^2.30.0",
|
|
50
50
|
"@mysten/wallet-standard": "^0.20.0",
|
|
51
51
|
"@mysten/walrus": "~1.2.24",
|
|
@@ -19,6 +19,7 @@ import { useWallet, getSuiClient } from '../wallet.js'
|
|
|
19
19
|
import { fetchChallenge, buildAccessProof } from '@meddleware/nft-gate-client'
|
|
20
20
|
import { NETWORK, relayHosts, accessGate, uploadRelayMaxTipMist, walruscanBlobUrl } from '../config.js'
|
|
21
21
|
import { runBlobUpload } from '../upload-flow.js'
|
|
22
|
+
import { getCertifyRetry } from '@meddleware/walrus-relay'
|
|
22
23
|
import {
|
|
23
24
|
consumeStorageKey,
|
|
24
25
|
isRedeemedConflict,
|
|
@@ -101,22 +102,29 @@ async function performUpload(
|
|
|
101
102
|
})
|
|
102
103
|
|
|
103
104
|
const runOnce = async (authToken: string | undefined): Promise<UploadResult> => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
105
|
+
try {
|
|
106
|
+
const r = await runBlobUpload({
|
|
107
|
+
bytes,
|
|
108
|
+
network: NETWORK,
|
|
109
|
+
relayHost: opts.relayHost,
|
|
110
|
+
address,
|
|
111
|
+
wasmUrl: walrusWasmUrl,
|
|
112
|
+
maxTipMist: uploadRelayMaxTipMist(),
|
|
113
|
+
epochs: MAX_SINGLE_RESERVATION_EPOCHS,
|
|
114
|
+
executor,
|
|
115
|
+
suiClient: getSuiClient(),
|
|
116
|
+
authToken,
|
|
117
|
+
onStatus: opts.onStatus,
|
|
118
|
+
})
|
|
119
|
+
// Success → clear the consume layer (the use is now genuinely spent for an upload).
|
|
120
|
+
if (consumeKey) storage.removeItem(consumeKey)
|
|
121
|
+
return r
|
|
122
|
+
} catch (e) {
|
|
123
|
+
// A certify-only failure means the upload already landed (relay access was used), so clear the
|
|
124
|
+
// consume too — the certify retry is a plain Sui tx and must not trigger a fresh NFT consume.
|
|
125
|
+
if (getCertifyRetry(e) && consumeKey) storage.removeItem(consumeKey)
|
|
126
|
+
throw e
|
|
127
|
+
}
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
try {
|
package/src/upload-flow.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// discovery) hands the relay an old tx with a non-matching nonce. Each attempt re-encodes (free) and
|
|
13
13
|
// registers fresh so the tip+nonce the relay verifies is always recent.
|
|
14
14
|
import type { UploadResult, UploadProgress } from '@meddleware/walrus-relay'
|
|
15
|
+
import { attachCertifyRetry } from '@meddleware/walrus-relay'
|
|
15
16
|
|
|
16
17
|
/** Minimal transaction executor — the structural subset App.vue's wallet executor already provides. */
|
|
17
18
|
export interface UploadExecutor {
|
|
@@ -104,13 +105,27 @@ export async function runBlobUpload(deps: RunBlobUploadDeps): Promise<UploadResu
|
|
|
104
105
|
deps.onStatus({ step: 'upload', detail: 'Uploading to the relay…' })
|
|
105
106
|
await flow.upload({ digest: reg.digest, deletable: false })
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
108
|
+
// Certify is a plain owner tx built from the storage-node certificate the live `flow` now holds
|
|
109
|
+
// (no relay, no tip). If it fails (e.g. the user rejects the prompt) the blob is already registered
|
|
110
|
+
// + stored + paid, so we never want to redo the upload — we expose this closure to retry certify
|
|
111
|
+
// alone. Re-calling `flow.certify()` just rebuilds the same tx from the in-memory certificate.
|
|
112
|
+
const runCertify = async (): Promise<UploadResult> => {
|
|
113
|
+
deps.onStatus({ step: 'certify', detail: 'Certifying (approve in wallet)…' })
|
|
114
|
+
const certTx = flow.certify()
|
|
115
|
+
certTx.setSenderIfNotSet(deps.address)
|
|
116
|
+
await certTx.build({ client: deps.suiClient })
|
|
117
|
+
const cert = await deps.executor.signAndExecute(certTx)
|
|
118
|
+
await deps.executor.waitForTransaction(cert.digest)
|
|
119
|
+
const blob = await flow.getBlob()
|
|
120
|
+
return { blobId: blob.blobId, url: walrusBlobUrl(deps.network, blob.blobId), digest: cert.digest }
|
|
121
|
+
}
|
|
113
122
|
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
try {
|
|
124
|
+
return await runCertify()
|
|
125
|
+
} catch (e) {
|
|
126
|
+
// Upload landed but certify did not: attach a retry so the UI can offer a "Certify" button
|
|
127
|
+
// rather than discarding the paid upload. The closure keeps the live flow (and its certificate).
|
|
128
|
+
attachCertifyRetry<UploadResult>(e, runCertify)
|
|
129
|
+
throw e
|
|
130
|
+
}
|
|
116
131
|
}
|