@meddleware/dev 0.0.1

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.
@@ -0,0 +1,127 @@
1
+ # Walrus Storage — Integration guide
2
+
3
+ ## Upload with progress
4
+
5
+ ```ts
6
+ import { WalrusRelayClient } from '@meddleware/walrus-client'
7
+
8
+ async function uploadFile(
9
+ walrus: WalrusRelayClient,
10
+ file: File,
11
+ epochs = 5,
12
+ onProgress?: (pct: number) => void,
13
+ ): Promise<string> {
14
+ const result = await walrus.store(file, {
15
+ epochs,
16
+ onProgress,
17
+ })
18
+ return result.blobId
19
+ }
20
+ ```
21
+
22
+ ## Upload with wallet signing (gated relay)
23
+
24
+ When the relay requires an NFT gate proof, supply a `Transaction` signer:
25
+
26
+ ```ts
27
+ import { useSignAndExecuteTransaction, useCurrentAccount } from '@mysten/dapp-kit'
28
+
29
+ const account = useCurrentAccount()
30
+ const { mutateAsync: signAndExecute } = useSignAndExecuteTransaction()
31
+
32
+ const result = await walrus.store(file, {
33
+ epochs: 5,
34
+ signer: {
35
+ address: account.value!.address,
36
+ signAndExecute: (tx) => signAndExecute({ transaction: tx }),
37
+ },
38
+ })
39
+ ```
40
+
41
+ The client registers a fresh nonce with the relay, constructs the access-gate proof, submits the transaction, and then uploads the blob — all transparently.
42
+
43
+ ## Read a blob
44
+
45
+ ```ts
46
+ const data = await walrus.read(blobId)
47
+
48
+ // As a Blob for download
49
+ const blob = new Blob([data])
50
+ const url = URL.createObjectURL(blob)
51
+ ```
52
+
53
+ ## Extend blob lifetime
54
+
55
+ ```ts
56
+ await walrus.extend(blobId, { extraEpochs: 10, signer })
57
+ ```
58
+
59
+ ## List owned blobs
60
+
61
+ ```ts
62
+ const blobs = await walrus.listOwned(ownerAddress)
63
+ // BlobInfo[]: blobId, size, expiryEpoch, owner
64
+ ```
65
+
66
+ ## Tip estimation
67
+
68
+ The relay may charge a tip per upload. Estimate the tip before showing a confirmation UI:
69
+
70
+ ```ts
71
+ const estimate = await walrus.estimateTip(file.size, epochs)
72
+ // { tipMist: bigint, relayUrl: string }
73
+ ```
74
+
75
+ Display `estimate.tipMist / 1_000_000_000n` SUI to the user.
76
+
77
+ ## Error handling
78
+
79
+ ```ts
80
+ try {
81
+ const result = await walrus.store(file, { epochs })
82
+ } catch (err) {
83
+ if (err instanceof WalrusRelayError) {
84
+ switch (err.code) {
85
+ case 'RATE_LIMITED': // relay rate limit exceeded
86
+ case 'INSUFFICIENT_FUNDS': // wallet balance too low
87
+ case 'NFT_GATE_DENIED': // no valid access-gate pass
88
+ case 'RELAY_UNAVAILABLE': // relay returned 5xx
89
+ }
90
+ }
91
+ throw err
92
+ }
93
+ ```
94
+
95
+ ## Vue composable pattern
96
+
97
+ ```ts
98
+ // composables/useWalrusUpload.ts
99
+ import { ref } from 'vue'
100
+ import { WalrusRelayClient } from '@meddleware/walrus-client'
101
+
102
+ export function useWalrusUpload(walrus: WalrusRelayClient) {
103
+ const uploading = ref(false)
104
+ const progress = ref(0)
105
+ const blobId = ref<string | null>(null)
106
+ const error = ref<Error | null>(null)
107
+
108
+ async function upload(file: File, epochs = 5) {
109
+ uploading.value = true
110
+ progress.value = 0
111
+ error.value = null
112
+ try {
113
+ const result = await walrus.store(file, {
114
+ epochs,
115
+ onProgress: (pct) => { progress.value = pct },
116
+ })
117
+ blobId.value = result.blobId
118
+ } catch (e) {
119
+ error.value = e as Error
120
+ } finally {
121
+ uploading.value = false
122
+ }
123
+ }
124
+
125
+ return { uploading, progress, blobId, error, upload }
126
+ }
127
+ ```
@@ -0,0 +1,82 @@
1
+ # Self-host a Walrus relay
2
+
3
+ The Meddleware Walrus relay is an HTTP gateway that accepts blob uploads, pays Walrus storage fees on behalf of the uploader (recovering costs via tips), and optionally gates uploads behind an NFT access pass.
4
+
5
+ The relay source lives at `repos/walrus-relay-ui/` (frontend) and `services/walrus-relay/` (backend). The backend is a Cloudflare Worker.
6
+
7
+ ## Architecture
8
+
9
+ ```
10
+ Client → CF Worker relay
11
+ │ tip payment (on-chain)
12
+ │ Walrus upload (Walrus publisher)
13
+ └─→ Walrus storage network
14
+ ```
15
+
16
+ The relay:
17
+ 1. Receives an upload request with an optional NFT gate proof.
18
+ 2. Verifies the proof on-chain (if gate is configured).
19
+ 3. Accepts a tip payment via a PTB signed by the client.
20
+ 4. Forwards the blob to a Walrus publisher.
21
+ 5. Returns the `blobId` to the client.
22
+
23
+ ## Deploying on Cloudflare Workers
24
+
25
+ ### Prerequisites
26
+
27
+ - A Cloudflare account with Workers enabled.
28
+ - A Sui address funded with enough SUI to cover Walrus storage fees.
29
+ - A Walrus publisher URL (testnet: `https://publisher.walrus-testnet.walrus.space`).
30
+
31
+ ### Configuration
32
+
33
+ ```toml
34
+ # wrangler.toml (in services/walrus-relay/)
35
+ name = "walrus-relay"
36
+ main = "src/index.ts"
37
+ compatibility_date = "2025-01-01"
38
+
39
+ [vars]
40
+ WALRUS_PUBLISHER_URL = "https://publisher.walrus-testnet.walrus.space"
41
+ WALRUS_AGGREGATOR_URL = "https://aggregator.walrus-testnet.walrus.space"
42
+ SUI_NETWORK = "testnet"
43
+ # Optional: NFT gate contract address for access-gated relay
44
+ NFT_GATE_PACKAGE_ID = ""
45
+ ```
46
+
47
+ Store secrets securely — never commit them:
48
+
49
+ ```bash
50
+ wrangler secret put RELAY_PRIVATE_KEY # base64-encoded Ed25519 key for tip collection
51
+ wrangler secret put TIP_RECIPIENT # Sui address that receives tips
52
+ ```
53
+
54
+ ### Deploy
55
+
56
+ ```bash
57
+ cd services/walrus-relay
58
+ npm install
59
+ wrangler deploy
60
+ ```
61
+
62
+ ### Tip configuration
63
+
64
+ The relay uses a `tip_config` object to determine the tip amount per byte per epoch. Update this via the DAO or directly in the Worker KV if you run your own relay.
65
+
66
+ ```ts
67
+ const tipConfig = {
68
+ minTipMist: 1_000_000n, // minimum tip regardless of size (1 mSUI)
69
+ perBytePerEpoch: 100n, // tip in MIST per byte per storage epoch
70
+ maxEpochs: 52, // maximum epochs the relay will accept
71
+ }
72
+ ```
73
+
74
+ ## Registering your relay URL
75
+
76
+ To surface your relay in the Meddleware relay picker UI, add it to the relay registry config. The relay must respond to `GET /health` with `{ status: "ok" }`.
77
+
78
+ ::: tip Register fresh, never resume
79
+ The relay embeds a tip+nonce in the register transaction. Never resume a partially-completed registration. Always call the register endpoint fresh — it is idempotent on success.
80
+ :::
81
+
82
+ <!-- white-label: operator customization guide (custom domain, branding, fee collection address, gate config) — planned -->
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@meddleware/dev",
3
+ "version": "0.0.1",
4
+ "description": "Meddleware developer documentation site (dev.meddleware.co.uk) — VitePress. Integration guides, design system usage, and Sui development patterns.",
5
+ "homepage": "https://dev.meddleware.co.uk/",
6
+ "author": "Meddleware <dev@meddleware.co.uk>",
7
+ "license": "0BSD",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/meddleware-org/dev.git"
11
+ },
12
+ "type": "module",
13
+ "files": [
14
+ "docs",
15
+ "tsconfig.json",
16
+ "CHANGELOG.md"
17
+ ],
18
+ "scripts": {
19
+ "dev": "vitepress dev docs",
20
+ "build": "vitepress build docs",
21
+ "preview": "vitepress preview docs",
22
+ "type-check": "tsc --noEmit"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "@meddleware/design-tokens": "^0.1.3"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "~24.12.2",
32
+ "typescript": "~6.0.0",
33
+ "vitepress": "2.0.0-alpha.20",
34
+ "vue": "^3.5.43"
35
+ },
36
+ "engines": {
37
+ "node": "^22.18.0 || >=24.12.0"
38
+ }
39
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "resolveJsonModule": true,
10
+ "types": ["node"]
11
+ },
12
+ "include": ["docs/.vitepress/**/*.ts"]
13
+ }