@le-space/p2pass 0.1.0
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/LICENSE +21 -0
- package/README.md +258 -0
- package/dist/backup/registry-backup.d.ts +26 -0
- package/dist/backup/registry-backup.js +51 -0
- package/dist/identity/identity-service.d.ts +116 -0
- package/dist/identity/identity-service.js +524 -0
- package/dist/identity/mode-detector.d.ts +29 -0
- package/dist/identity/mode-detector.js +124 -0
- package/dist/identity/signing-preference.d.ts +30 -0
- package/dist/identity/signing-preference.js +55 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +91 -0
- package/dist/p2p/setup.d.ts +48 -0
- package/dist/p2p/setup.js +283 -0
- package/dist/recovery/ipns-key.d.ts +41 -0
- package/dist/recovery/ipns-key.js +127 -0
- package/dist/recovery/manifest.d.ts +106 -0
- package/dist/recovery/manifest.js +243 -0
- package/dist/registry/device-registry.d.ts +122 -0
- package/dist/registry/device-registry.js +275 -0
- package/dist/registry/index.d.ts +3 -0
- package/dist/registry/index.js +46 -0
- package/dist/registry/manager.d.ts +76 -0
- package/dist/registry/manager.js +376 -0
- package/dist/registry/pairing-protocol.d.ts +61 -0
- package/dist/registry/pairing-protocol.js +653 -0
- package/dist/ucan/storacha-auth.d.ts +45 -0
- package/dist/ucan/storacha-auth.js +164 -0
- package/dist/ui/StorachaFab.svelte +134 -0
- package/dist/ui/StorachaFab.svelte.d.ts +23 -0
- package/dist/ui/StorachaIntegration.svelte +2467 -0
- package/dist/ui/StorachaIntegration.svelte.d.ts +23 -0
- package/dist/ui/fonts/dm-mono-400.ttf +0 -0
- package/dist/ui/fonts/dm-mono-500.ttf +0 -0
- package/dist/ui/fonts/dm-sans-400.ttf +0 -0
- package/dist/ui/fonts/dm-sans-500.ttf +0 -0
- package/dist/ui/fonts/dm-sans-600.ttf +0 -0
- package/dist/ui/fonts/dm-sans-700.ttf +0 -0
- package/dist/ui/fonts/epilogue-400.ttf +0 -0
- package/dist/ui/fonts/epilogue-500.ttf +0 -0
- package/dist/ui/fonts/epilogue-600.ttf +0 -0
- package/dist/ui/fonts/epilogue-700.ttf +0 -0
- package/dist/ui/fonts/storacha-fonts.css +152 -0
- package/dist/ui/storacha-backup.d.ts +44 -0
- package/dist/ui/storacha-backup.js +218 -0
- package/package.json +112 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storacha auth via UCAN delegation.
|
|
3
|
+
* Replaces the old key+proof credential flow.
|
|
4
|
+
*
|
|
5
|
+
* Delegation storage prefers OrbitDB registry DB when available,
|
|
6
|
+
* falls back to localStorage.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as Client from '@storacha/client';
|
|
10
|
+
import { StoreMemory } from '@storacha/client/stores/memory';
|
|
11
|
+
import {
|
|
12
|
+
storeDelegationEntry,
|
|
13
|
+
listDelegations,
|
|
14
|
+
removeDelegation as removeRegistryDelegation,
|
|
15
|
+
} from '../registry/device-registry.js';
|
|
16
|
+
|
|
17
|
+
const STORAGE_KEY_DELEGATION = 'storacha_ucan_delegation';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create a Storacha client using a UCAN principal and delegation proof.
|
|
21
|
+
*
|
|
22
|
+
* @param {any} principal - UCAN-compatible signer (from IdentityService.getPrincipal())
|
|
23
|
+
* @param {any} delegation - Parsed delegation object (from parseDelegation())
|
|
24
|
+
* @returns {Promise<any>} Storacha Client instance with space set
|
|
25
|
+
*/
|
|
26
|
+
export async function createStorachaClient(principal, delegation) {
|
|
27
|
+
console.log('[storacha] Creating client with UCAN principal...');
|
|
28
|
+
|
|
29
|
+
const store = new StoreMemory();
|
|
30
|
+
const client = await Client.create({ principal, store });
|
|
31
|
+
|
|
32
|
+
// Add space from delegation
|
|
33
|
+
const space = await client.addSpace(delegation);
|
|
34
|
+
await client.setCurrentSpace(space.did());
|
|
35
|
+
|
|
36
|
+
console.log(`[storacha] Client ready. Space: ${space.did()}`);
|
|
37
|
+
return client;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse a delegation proof string. Supports multiple formats:
|
|
42
|
+
* - Multibase base64url (u prefix)
|
|
43
|
+
* - Multibase base64 (m prefix)
|
|
44
|
+
* - Raw base64
|
|
45
|
+
* - CAR bytes
|
|
46
|
+
*
|
|
47
|
+
* @param {string} proofString - The delegation proof as a string
|
|
48
|
+
* @returns {Promise<any>} Parsed delegation object
|
|
49
|
+
*/
|
|
50
|
+
export async function parseDelegation(proofString) {
|
|
51
|
+
const trimmed = proofString.trim();
|
|
52
|
+
|
|
53
|
+
// Try @storacha/client/proof.parse() first (handles most formats)
|
|
54
|
+
try {
|
|
55
|
+
const Proof = await import('@storacha/client/proof');
|
|
56
|
+
const delegation = await Proof.parse(trimmed);
|
|
57
|
+
console.log('[storacha] Delegation parsed via @storacha/client/proof');
|
|
58
|
+
return delegation;
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.warn('[storacha] Proof.parse() failed, trying ucanto extraction...', err.message);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Try @ucanto/core/delegation.extract() with base64 decoding
|
|
64
|
+
try {
|
|
65
|
+
const Delegation = await import('@ucanto/core/delegation');
|
|
66
|
+
|
|
67
|
+
// Handle multibase prefixes
|
|
68
|
+
let base64Data = trimmed;
|
|
69
|
+
if (base64Data.startsWith('u')) {
|
|
70
|
+
base64Data = base64Data.slice(1).replace(/-/g, '+').replace(/_/g, '/');
|
|
71
|
+
} else if (base64Data.startsWith('m')) {
|
|
72
|
+
base64Data = base64Data.slice(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Pad if needed
|
|
76
|
+
while (base64Data.length % 4 !== 0) {
|
|
77
|
+
base64Data += '=';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const bytes = Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0));
|
|
81
|
+
const result = await Delegation.extract(bytes);
|
|
82
|
+
|
|
83
|
+
if (result.ok) {
|
|
84
|
+
console.log('[storacha] Delegation parsed via @ucanto/core/delegation.extract()');
|
|
85
|
+
return result.ok;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
throw new Error(result.error?.message || 'Delegation extraction failed');
|
|
89
|
+
} catch (err) {
|
|
90
|
+
throw new Error(`Failed to parse delegation: ${err.message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Store a raw delegation string.
|
|
96
|
+
* Uses registry DB if provided, otherwise localStorage fallback.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} delegationBase64
|
|
99
|
+
* @param {Object} [registryDb] - OrbitDB registry database
|
|
100
|
+
* @param {string} [spaceDid] - Storacha space DID (for registry metadata)
|
|
101
|
+
*/
|
|
102
|
+
export async function storeDelegation(delegationBase64, registryDb, spaceDid) {
|
|
103
|
+
if (registryDb) {
|
|
104
|
+
try {
|
|
105
|
+
await storeDelegationEntry(registryDb, delegationBase64, spaceDid);
|
|
106
|
+
console.log('[storacha] Delegation stored in registry DB');
|
|
107
|
+
return;
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.warn('[storacha] Registry write failed, falling back to localStorage:', err.message);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
localStorage.setItem(STORAGE_KEY_DELEGATION, delegationBase64);
|
|
113
|
+
console.log('[storacha] Delegation stored in localStorage');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Load a stored delegation string.
|
|
118
|
+
* Reads from registry DB if provided, otherwise localStorage.
|
|
119
|
+
*
|
|
120
|
+
* @param {Object} [registryDb] - OrbitDB registry database
|
|
121
|
+
* @returns {Promise<string|null>}
|
|
122
|
+
*/
|
|
123
|
+
export async function loadStoredDelegation(registryDb) {
|
|
124
|
+
if (registryDb) {
|
|
125
|
+
const delegations = await listDelegations(registryDb);
|
|
126
|
+
if (delegations.length > 0) {
|
|
127
|
+
const sorted = delegations.sort((a, b) => (b.created_at || 0) - (a.created_at || 0));
|
|
128
|
+
console.log('[storacha] Loaded delegation from registry DB');
|
|
129
|
+
return sorted[0].delegation;
|
|
130
|
+
}
|
|
131
|
+
// Registry exists but has no delegations — fall through to localStorage
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const local = localStorage.getItem(STORAGE_KEY_DELEGATION);
|
|
135
|
+
if (local) console.log('[storacha] Loaded delegation from localStorage');
|
|
136
|
+
return local;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Clear stored delegation(s).
|
|
141
|
+
* If registryDb is provided, removes all delegations from it.
|
|
142
|
+
* Otherwise clears from localStorage.
|
|
143
|
+
*
|
|
144
|
+
* @param {Object} [registryDb] - OrbitDB registry database
|
|
145
|
+
* @param {string} [delegationBase64] - specific delegation to remove (if omitted, removes all)
|
|
146
|
+
*/
|
|
147
|
+
export async function clearStoredDelegation(registryDb, delegationBase64) {
|
|
148
|
+
if (registryDb) {
|
|
149
|
+
if (delegationBase64) {
|
|
150
|
+
await removeRegistryDelegation(registryDb, delegationBase64);
|
|
151
|
+
} else {
|
|
152
|
+
// Remove all delegations from registry
|
|
153
|
+
const all = await listDelegations(registryDb);
|
|
154
|
+
for (const entry of all) {
|
|
155
|
+
if (entry.delegation) {
|
|
156
|
+
await removeRegistryDelegation(registryDb, entry.delegation);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
console.log('[storacha] Delegation(s) removed from registry DB');
|
|
161
|
+
} else {
|
|
162
|
+
localStorage.removeItem(STORAGE_KEY_DELEGATION);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import StorachaIntegration from './StorachaIntegration.svelte';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
orbitdb = null,
|
|
6
|
+
database = null,
|
|
7
|
+
isInitialized = false,
|
|
8
|
+
entryCount = 0,
|
|
9
|
+
databaseName = 'restored-db',
|
|
10
|
+
onRestore = () => {},
|
|
11
|
+
onBackup = () => {},
|
|
12
|
+
onAuthenticate = () => {},
|
|
13
|
+
libp2p = null,
|
|
14
|
+
preferWorkerMode = false,
|
|
15
|
+
signingPreference = null,
|
|
16
|
+
} = $props();
|
|
17
|
+
|
|
18
|
+
let showPanel = $state(false);
|
|
19
|
+
let isHovered = $state(false);
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<!-- Floating Storacha FAB Button -->
|
|
23
|
+
<button
|
|
24
|
+
data-testid="storacha-fab-toggle"
|
|
25
|
+
onclick={() => (showPanel = !showPanel)}
|
|
26
|
+
onmouseenter={() => (isHovered = true)}
|
|
27
|
+
onmouseleave={() => (isHovered = false)}
|
|
28
|
+
title={showPanel ? 'Hide P2Pass panel' : 'Open P2Pass — passkey & UCAN, peer-to-peer'}
|
|
29
|
+
aria-label={showPanel ? 'Hide P2Pass panel' : 'Open P2Pass panel'}
|
|
30
|
+
style="
|
|
31
|
+
position: fixed;
|
|
32
|
+
right: 1.5rem;
|
|
33
|
+
bottom: 6rem;
|
|
34
|
+
z-index: 10000;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
height: 4rem;
|
|
39
|
+
width: 4rem;
|
|
40
|
+
border-radius: 9999px;
|
|
41
|
+
border: 2px solid white;
|
|
42
|
+
color: white;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
padding: 0;
|
|
45
|
+
outline: none;
|
|
46
|
+
background: linear-gradient(135deg, #E91315 0%, #FFC83F 100%);
|
|
47
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
48
|
+
transition: all 300ms ease;
|
|
49
|
+
transform: {showPanel
|
|
50
|
+
? 'scale(1.05) rotate(12deg)'
|
|
51
|
+
: isHovered
|
|
52
|
+
? 'scale(1.1) rotate(6deg)'
|
|
53
|
+
: 'scale(1)'};
|
|
54
|
+
font-family: 'Epilogue', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
55
|
+
"
|
|
56
|
+
>
|
|
57
|
+
<svg
|
|
58
|
+
width="28"
|
|
59
|
+
height="32"
|
|
60
|
+
viewBox="0 0 154 172"
|
|
61
|
+
fill="none"
|
|
62
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
63
|
+
style="transition: transform 300ms;"
|
|
64
|
+
>
|
|
65
|
+
<path
|
|
66
|
+
d="M110.999 41.5313H71.4081C70.2881 41.5313 69.334 42.4869 69.334 43.6087V154.359C69.334 159.461 69.1847 164.596 69.334 169.698C69.334 169.773 69.334 169.839 69.334 169.914C69.334 171.036 70.2881 171.992 71.4081 171.992H111.646C112.766 171.992 113.72 171.036 113.72 169.914V129.613L111.646 131.69H151.884C153.004 131.69 153.959 130.735 153.959 129.613V95.7513C153.959 91.6796 154.041 87.5996 153.942 83.5362C153.685 72.9996 149.512 62.8038 142.318 55.1091C135.125 47.4144 125.319 42.7029 114.907 41.7141C113.604 41.5894 112.302 41.5313 110.991 41.5313C108.319 41.523 108.319 45.6777 110.991 45.6861C120.772 45.7193 130.305 49.4171 137.457 56.1229C144.608 62.8287 149.022 71.9443 149.702 81.6416C149.993 85.813 149.802 90.0592 149.802 94.2306V124.677C149.802 126.231 149.694 127.826 149.802 129.38C149.802 129.455 149.802 129.53 149.802 129.604L151.876 127.527H111.638C110.518 127.527 109.564 128.483 109.564 129.604V169.906L111.638 167.829H71.3998L73.474 169.906V48.7689C73.474 47.1319 73.5818 45.4617 73.474 43.8247C73.474 43.7499 73.474 43.6834 73.474 43.6087L71.3998 45.6861H110.991C113.662 45.6861 113.662 41.5313 110.991 41.5313H110.999Z"
|
|
67
|
+
fill="currentColor"
|
|
68
|
+
/>
|
|
69
|
+
<path
|
|
70
|
+
d="M108.519 68.9694C108.452 62.9532 104.727 57.66 99.1103 55.5494C93.4935 53.4387 87.0886 55.2669 83.3718 59.779C79.5554 64.4157 78.9165 71.0966 82.0277 76.2901C85.1389 81.4836 91.2037 84.0762 97.1025 82.9544C103.723 81.6996 108.444 75.617 108.527 68.9694C108.56 66.2937 104.412 66.2937 104.379 68.9694C104.329 73.1325 101.749 77.0878 97.7579 78.4838C93.7673 79.8798 89.03 78.6749 86.3087 75.2265C83.5875 71.778 83.4879 67.2077 85.6865 63.6346C87.8851 60.0615 92.2076 58.1752 96.2811 59.0477C100.985 60.0532 104.32 64.1664 104.379 68.9777C104.412 71.6533 108.56 71.6533 108.527 68.9777L108.519 68.9694Z"
|
|
71
|
+
fill="currentColor"
|
|
72
|
+
/>
|
|
73
|
+
<path
|
|
74
|
+
d="M94.265 73.3237C96.666 73.3237 98.6124 71.3742 98.6124 68.9695C98.6124 66.5647 96.666 64.6152 94.265 64.6152C91.8641 64.6152 89.9177 66.5647 89.9177 68.9695C89.9177 71.3742 91.8641 73.3237 94.265 73.3237Z"
|
|
75
|
+
fill="currentColor"
|
|
76
|
+
/>
|
|
77
|
+
<path
|
|
78
|
+
d="M71.4081 36.8029H132.429C144.642 36.8029 150.64 28.5764 151.752 23.8981C152.863 19.2281 147.263 7.43685 133.624 22.1199C133.624 22.1199 141.754 6.32336 130.869 2.76686C119.984 -0.789637 107.473 10.1042 102.512 20.5577C102.512 20.5577 103.109 7.6529 91.8923 10.769C80.6754 13.8851 71.4081 36.7946 71.4081 36.7946V36.8029Z"
|
|
79
|
+
fill="currentColor"
|
|
80
|
+
/>
|
|
81
|
+
<path
|
|
82
|
+
d="M18.186 66.1195C17.879 66.0531 17.8707 65.6126 18.1694 65.5212C31.6927 61.4246 42.2376 70.7895 46.0457 76.6312C48.3189 80.1212 51.6956 83.3868 54.1182 85.5058C55.4042 86.6276 55.0889 88.7216 53.5292 89.4113C52.4589 89.8849 50.7498 90.9402 49.2316 91.846C46.3859 93.5495 42.4699 100.554 33.0948 101.884C26.1921 102.856 17.6716 98.7014 13.6561 96.4329C13.3408 96.2584 13.5399 95.793 13.8884 95.8761C19.8536 97.3137 24.2673 94.8291 22.4753 91.5302C21.1395 89.0706 17.5223 88.1482 12.2789 90.2339C7.61621 92.087 2.07414 86.0376 0.597357 84.2843C0.439724 84.1015 0.555875 83.8106 0.788177 83.7857C5.16044 83.3453 9.41656 78.8664 12.2291 74.1715C14.801 69.8755 20.5837 69.4849 22.4255 69.4683C22.6744 69.4683 22.8154 69.1858 22.6661 68.9863C22.0605 68.1886 20.6169 66.6513 18.186 66.1112V66.1195ZM30.1413 87.9571C29.7264 87.9322 29.4692 88.3975 29.7181 88.7299C30.7967 90.1342 33.5345 92.5855 38.7448 90.9818C45.8134 88.8047 46.1038 84.3175 40.9516 80.3455C36.4798 76.9054 29.2204 77.5618 24.8647 79.8968C24.4084 80.1461 24.5992 80.8441 25.1136 80.8026C26.8641 80.6696 30.133 80.8607 32.0827 82.2401C34.7126 84.0932 35.617 88.331 30.1413 87.9654V87.9571Z"
|
|
83
|
+
fill="currentColor"
|
|
84
|
+
/>
|
|
85
|
+
</svg>
|
|
86
|
+
</button>
|
|
87
|
+
|
|
88
|
+
<!-- Backdrop overlay -->
|
|
89
|
+
{#if showPanel}
|
|
90
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
91
|
+
<div
|
|
92
|
+
onclick={() => (showPanel = false)}
|
|
93
|
+
onkeydown={(e) => e.key === 'Escape' && (showPanel = false)}
|
|
94
|
+
role="presentation"
|
|
95
|
+
style="
|
|
96
|
+
position: fixed;
|
|
97
|
+
inset: 0;
|
|
98
|
+
z-index: 9998;
|
|
99
|
+
background: radial-gradient(circle at center, rgba(233, 19, 21, 0.15) 0%, rgba(233, 19, 21, 0.05) 70%, transparent 100%);
|
|
100
|
+
backdrop-filter: blur(2px);
|
|
101
|
+
-webkit-backdrop-filter: blur(2px);
|
|
102
|
+
"
|
|
103
|
+
></div>
|
|
104
|
+
{/if}
|
|
105
|
+
|
|
106
|
+
<!-- Floating panel — kept alive, hidden via CSS to preserve state -->
|
|
107
|
+
<div
|
|
108
|
+
style="
|
|
109
|
+
position: fixed;
|
|
110
|
+
right: 1.5rem;
|
|
111
|
+
bottom: 12rem;
|
|
112
|
+
z-index: 9999;
|
|
113
|
+
width: 24rem;
|
|
114
|
+
max-width: calc(100vw - 3rem);
|
|
115
|
+
display: {showPanel ? 'block' : 'none'};
|
|
116
|
+
"
|
|
117
|
+
>
|
|
118
|
+
<StorachaIntegration
|
|
119
|
+
{orbitdb}
|
|
120
|
+
{database}
|
|
121
|
+
{isInitialized}
|
|
122
|
+
{entryCount}
|
|
123
|
+
{databaseName}
|
|
124
|
+
{onRestore}
|
|
125
|
+
{onBackup}
|
|
126
|
+
{onAuthenticate}
|
|
127
|
+
onPairingPromptOpen={() => {
|
|
128
|
+
showPanel = true;
|
|
129
|
+
}}
|
|
130
|
+
{libp2p}
|
|
131
|
+
{preferWorkerMode}
|
|
132
|
+
{signingPreference}
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} StorachaFabProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} StorachaFabEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} StorachaFabSlots */
|
|
4
|
+
export default class StorachaFab extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: never;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type StorachaFabProps = typeof __propDef.props;
|
|
11
|
+
export type StorachaFabEvents = typeof __propDef.events;
|
|
12
|
+
export type StorachaFabSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponentTyped } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
[x: string]: never;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|