@meddleware/seal-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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meddleware/seal-ui",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Standalone Vue 3 SPA for Sealed Storage — client-side Seal encryption + access-gated, decentralised Walrus storage on Sui.",
5
5
  "author": "MeddleWare <meddleware@proton.me>",
6
6
  "license": "0BSD",
@@ -39,7 +39,7 @@
39
39
  "dependencies": {
40
40
  "@meddleware/design-tokens": "^0.1.2",
41
41
  "@meddleware/seal-client": "^0.0.2",
42
- "@meddleware/ui": "^0.1.9",
42
+ "@meddleware/ui": "^0.1.11",
43
43
  "@meddleware/wallet-adapter": "^0.0.5",
44
44
  "@mysten/seal": "^1.4.7",
45
45
  "@mysten/sui": "^2.30.0",
@@ -8,6 +8,7 @@
8
8
  // global stylesheet (which restyles body / #app / bare inputs). The standalone app keeps those
9
9
  // globals via main.ts → styles.css.
10
10
  import { computed, onMounted, ref } from 'vue'
11
+ import { AppTabNav, type AppTab } from '@meddleware/ui'
11
12
  import { Transaction } from '@mysten/sui/transactions'
12
13
  import {
13
14
  buildPublishSealedContentTx,
@@ -20,15 +21,19 @@ import { useWallet } from '../wallet.js'
20
21
  import { registry, getSealController } from '../seal.js'
21
22
  import { storeBlob, readBlob } from '../walrus.js'
22
23
  import { discoverSealedContent } from '../sealed-content.js'
23
- import { NETWORK, MAINNET_PENDING, SEAL_CONFIGURED, SEAL_PACKAGE_ID } from '../config.js'
24
+ import { NETWORK, SEAL_CONFIGURED, SEAL_PACKAGE_ID } from '../config.js'
24
25
 
25
26
  const { account, signPersonalMessage, signAndExecute } = useWallet()
26
27
 
27
28
  const providers = registry.list() as SealPolicyProvider[]
28
- const disabled = computed(() => MAINNET_PENDING || !SEAL_CONFIGURED)
29
+ const disabled = computed(() => !SEAL_CONFIGURED)
29
30
 
30
- type Tab = 'encrypt' | 'decrypt' | 'unlock'
31
- const tab = ref<Tab>('encrypt')
31
+ const TABS: AppTab[] = [
32
+ { id: 'encrypt', label: 'Encrypt' },
33
+ { id: 'decrypt', label: 'Decrypt' },
34
+ { id: 'unlock', label: 'Unlock' },
35
+ ]
36
+ const tab = ref<string>('encrypt')
32
37
 
33
38
  // Deep-link from access-gate-ui: ?gate=<id> preselects the nft-gate policy + gate.
34
39
  onMounted(() => {
@@ -272,21 +277,21 @@ async function performUnlock(item: SealedContentPointer): Promise<void> {
272
277
  <div class="page">
273
278
  <p class="muted">Client-side encrypted, access-gated storage on Walrus + Sui.</p>
274
279
 
275
- <div v-if="MAINNET_PENDING" class="notice notice--warn">
276
- Mainnet support is pending — Seal committee mode is currently testnet-only. Switch to testnet to
277
- seal content.
278
- </div>
279
- <div v-else-if="!SEAL_CONFIGURED" class="notice notice--warn">
280
- This deployment has no Seal policy package or key-server committee configured
281
- (<code>VITE_SEAL_PACKAGE_ID_*</code> / <code>VITE_SEAL_SERVER_OBJECT_IDS_*</code>).
280
+ <div v-if="!SEAL_CONFIGURED" class="notice notice--warn">
281
+ <template v-if="NETWORK === 'mainnet'">
282
+ Seal is not configured for mainnet. Set
283
+ <code>VITE_SEAL_PACKAGE_ID_MAINNET</code>,
284
+ <code>VITE_SEAL_SERVER_OBJECT_IDS_MAINNET</code>, and
285
+ <code>VITE_SEAL_AGGREGATOR_URLS_MAINNET</code>, then redeploy.
286
+ </template>
287
+ <template v-else>
288
+ This deployment has no Seal policy package or key-server committee configured
289
+ (<code>VITE_SEAL_PACKAGE_ID_*</code> / <code>VITE_SEAL_SERVER_OBJECT_IDS_*</code>).
290
+ </template>
282
291
  </div>
283
292
 
284
293
  <WalletGuard message="Connect a Sui wallet to encrypt and decrypt sealed content.">
285
- <nav class="tabs">
286
- <button :class="{ active: tab === 'encrypt' }" @click="tab = 'encrypt'">Encrypt</button>
287
- <button :class="{ active: tab === 'decrypt' }" @click="tab = 'decrypt'">Decrypt</button>
288
- <button :class="{ active: tab === 'unlock' }" @click="tab = 'unlock'">Unlock</button>
289
- </nav>
294
+ <AppTabNav :tabs="TABS" v-model="tab" style="margin: 1rem 0" />
290
295
 
291
296
  <div v-if="errorMsg" class="notice notice--error">{{ errorMsg }}</div>
292
297
 
@@ -446,25 +451,6 @@ async function performUnlock(item: SealedContentPointer): Promise<void> {
446
451
  .notice--warn { background: color-mix(in srgb, #d29922 15%, transparent); }
447
452
  .notice--error { background: color-mix(in srgb, #f85149 18%, transparent); }
448
453
 
449
- .tabs {
450
- display: flex;
451
- gap: 0.25rem;
452
- margin: 1rem 0;
453
- border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent);
454
- }
455
- .tabs button {
456
- background: transparent;
457
- border: 0;
458
- color: inherit;
459
- padding: 0.5rem 0.9rem;
460
- cursor: pointer;
461
- opacity: 0.7;
462
- border-bottom: 2px solid transparent;
463
- }
464
- .tabs button.active {
465
- opacity: 1;
466
- border-bottom-color: var(--accent, #c0503f);
467
- }
468
454
 
469
455
  .card {
470
456
  background: var(--surface, #1e1917);
package/src/config.ts CHANGED
@@ -30,32 +30,53 @@ export const SEAL_PACKAGE_ID: string =
30
30
  ? '0x9f0563bfe42fbd29932cd280cc47efe17f5339b4dc569eb110114665eecc231e'
31
31
  : '')
32
32
 
33
- /** Threshold `t` in the t-of-n committee (default 2 — matches the 3-server testnet default). */
34
- export const SEAL_THRESHOLD = Number(env.VITE_SEAL_THRESHOLD || '2')
33
+ /**
34
+ * Threshold `t` in the t-of-n committee.
35
+ * Testnet default: 2 (matches the 3-server testnet committee)
36
+ * Mainnet default: 5 (matches the 5-of-8 Mysten Labs mainnet committee)
37
+ */
38
+ export const SEAL_THRESHOLD = Number(
39
+ env.VITE_SEAL_THRESHOLD || (NETWORK === 'mainnet' ? '5' : '2'),
40
+ )
35
41
 
36
42
  /**
37
43
  * The key-server committee. Object ids and aggregator URLs are supplied as parallel CSV lists
38
44
  * (index-aligned); aggregatorUrl is required for decentralized (committee-type) servers only —
39
45
  * independent servers derive their URL from the on-chain object and do not need one.
40
46
  *
41
- * Defaults are the three verified Mysten Labs testnet servers:
42
- * [0] Decentralized (Mysten) — requires aggregatorUrl
47
+ * Testnet defaults — three verified Mysten Labs servers:
48
+ * [0] Decentralized (Mysten aggregator) — requires aggregatorUrl
43
49
  * [1] Independent server 1
44
50
  * [2] Independent server 2
45
51
  * Override via VITE_SEAL_SERVER_OBJECT_IDS_TESTNET / VITE_SEAL_AGGREGATOR_URLS_TESTNET.
52
+ *
53
+ * Mainnet defaults — Mysten Labs 5-of-8 decentralized committee:
54
+ * Committee object: 0x686098f1439237fff9f36b99c7329683c22979d2005c2465cb891acb012a7595
55
+ * Aggregator: https://seal-aggregator-mainnet.mystenlabs.com
56
+ * NOTE: The mainnet aggregator requires an Enoki API key (X-API-Key header).
57
+ * Override via VITE_SEAL_SERVER_OBJECT_IDS_MAINNET / VITE_SEAL_AGGREGATOR_URLS_MAINNET.
58
+ * When independent open-mode key servers become available on mainnet, they can be added here.
46
59
  */
47
60
  export const SEAL_SERVERS: KeyServerConfig[] = (() => {
48
- const defaultIds = [
49
- '0xb012378c9f3799fb5b1a7083da74a4069e3c3f1c93de0b27212a5799ce1e1e98',
50
- '0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75',
51
- '0xf5d14a81a982144ae441cd7d64b09027f116a468bd36e7eca494f750591623c8',
52
- ]
53
- const defaultAggs = ['https://seal-aggregator-testnet.mystenlabs.com']
61
+ const defaults: Record<Network, { ids: string[]; aggs: string[] }> = {
62
+ testnet: {
63
+ ids: [
64
+ '0xb012378c9f3799fb5b1a7083da74a4069e3c3f1c93de0b27212a5799ce1e1e98',
65
+ '0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75',
66
+ '0xf5d14a81a982144ae441cd7d64b09027f116a468bd36e7eca494f750591623c8',
67
+ ],
68
+ aggs: ['https://seal-aggregator-testnet.mystenlabs.com'],
69
+ },
70
+ mainnet: {
71
+ ids: ['0x686098f1439237fff9f36b99c7329683c22979d2005c2465cb891acb012a7595'],
72
+ aggs: ['https://seal-aggregator-mainnet.mystenlabs.com'],
73
+ },
74
+ }
54
75
 
55
76
  const envIds = csv(netEnv('VITE_SEAL_SERVER_OBJECT_IDS'))
56
77
  const envAggs = csv(netEnv('VITE_SEAL_AGGREGATOR_URLS'))
57
- const ids = envIds.length > 0 ? envIds : (NETWORK === 'testnet' ? defaultIds : [])
58
- const aggs = envAggs.length > 0 ? envAggs : (NETWORK === 'testnet' ? defaultAggs : [])
78
+ const ids = envIds.length > 0 ? envIds : defaults[NETWORK].ids
79
+ const aggs = envAggs.length > 0 ? envAggs : defaults[NETWORK].aggs
59
80
  return ids.map((objectId, i) => ({ objectId, weight: 1, aggregatorUrl: aggs[i] }))
60
81
  })()
61
82
 
@@ -75,11 +96,12 @@ export const WALRUS_AGGREGATOR: string =
75
96
  /** Default blob lifetime (Walrus storage epochs). */
76
97
  export const WALRUS_EPOCHS = Number(env.VITE_WALRUS_EPOCHS || '5')
77
98
 
78
- /**
79
- * Seal committee mode is testnet-only today. On mainnet the app shows a "pending" notice and
80
- * disables sealing until the committee is available there.
81
- */
82
- export const MAINNET_PENDING = NETWORK === 'mainnet'
83
-
84
99
  /** True when the on-chain policy package + committee are configured for the active network. */
85
100
  export const SEAL_CONFIGURED = Boolean(SEAL_PACKAGE_ID) && SEAL_SERVERS.length > 0
101
+
102
+ /**
103
+ * True when the active network has no Seal committee configured (empty package ID or no servers).
104
+ * On mainnet, populate VITE_SEAL_PACKAGE_ID_MAINNET + VITE_SEAL_SERVER_OBJECT_IDS_MAINNET +
105
+ * VITE_SEAL_AGGREGATOR_URLS_MAINNET to enable sealing — no code change required.
106
+ */
107
+ export const MAINNET_PENDING = !SEAL_CONFIGURED