@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.
- package/CHANGELOG.md +10 -0
- package/docs/.vitepress/config.ts +111 -0
- package/docs/.vitepress/env.d.ts +6 -0
- package/docs/.vitepress/theme/custom.css +63 -0
- package/docs/.vitepress/theme/index.ts +19 -0
- package/docs/design-system/components.md +111 -0
- package/docs/design-system/index.md +64 -0
- package/docs/design-system/tokens.md +136 -0
- package/docs/getting-started/index.md +52 -0
- package/docs/getting-started/local-dev.md +74 -0
- package/docs/getting-started/toolchain.md +83 -0
- package/docs/index.md +44 -0
- package/docs/sui/access-gate/gateway.md +159 -0
- package/docs/sui/access-gate/index.md +62 -0
- package/docs/sui/access-gate/integration.md +168 -0
- package/docs/sui/dao/index.md +154 -0
- package/docs/sui/environment.md +101 -0
- package/docs/sui/index.md +46 -0
- package/docs/sui/ptb-patterns.md +136 -0
- package/docs/sui/sealed-storage/index.md +49 -0
- package/docs/sui/sealed-storage/integration.md +125 -0
- package/docs/sui/sealed-storage/policies.md +81 -0
- package/docs/sui/walrus-storage/index.md +67 -0
- package/docs/sui/walrus-storage/integration.md +127 -0
- package/docs/sui/walrus-storage/relay-self-host.md +82 -0
- package/package.json +39 -0
- package/tsconfig.json +13 -0
|
@@ -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
|
+
}
|