@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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +258 -0
  3. package/dist/backup/registry-backup.d.ts +26 -0
  4. package/dist/backup/registry-backup.js +51 -0
  5. package/dist/identity/identity-service.d.ts +116 -0
  6. package/dist/identity/identity-service.js +524 -0
  7. package/dist/identity/mode-detector.d.ts +29 -0
  8. package/dist/identity/mode-detector.js +124 -0
  9. package/dist/identity/signing-preference.d.ts +30 -0
  10. package/dist/identity/signing-preference.js +55 -0
  11. package/dist/index.d.ts +15 -0
  12. package/dist/index.js +91 -0
  13. package/dist/p2p/setup.d.ts +48 -0
  14. package/dist/p2p/setup.js +283 -0
  15. package/dist/recovery/ipns-key.d.ts +41 -0
  16. package/dist/recovery/ipns-key.js +127 -0
  17. package/dist/recovery/manifest.d.ts +106 -0
  18. package/dist/recovery/manifest.js +243 -0
  19. package/dist/registry/device-registry.d.ts +122 -0
  20. package/dist/registry/device-registry.js +275 -0
  21. package/dist/registry/index.d.ts +3 -0
  22. package/dist/registry/index.js +46 -0
  23. package/dist/registry/manager.d.ts +76 -0
  24. package/dist/registry/manager.js +376 -0
  25. package/dist/registry/pairing-protocol.d.ts +61 -0
  26. package/dist/registry/pairing-protocol.js +653 -0
  27. package/dist/ucan/storacha-auth.d.ts +45 -0
  28. package/dist/ucan/storacha-auth.js +164 -0
  29. package/dist/ui/StorachaFab.svelte +134 -0
  30. package/dist/ui/StorachaFab.svelte.d.ts +23 -0
  31. package/dist/ui/StorachaIntegration.svelte +2467 -0
  32. package/dist/ui/StorachaIntegration.svelte.d.ts +23 -0
  33. package/dist/ui/fonts/dm-mono-400.ttf +0 -0
  34. package/dist/ui/fonts/dm-mono-500.ttf +0 -0
  35. package/dist/ui/fonts/dm-sans-400.ttf +0 -0
  36. package/dist/ui/fonts/dm-sans-500.ttf +0 -0
  37. package/dist/ui/fonts/dm-sans-600.ttf +0 -0
  38. package/dist/ui/fonts/dm-sans-700.ttf +0 -0
  39. package/dist/ui/fonts/epilogue-400.ttf +0 -0
  40. package/dist/ui/fonts/epilogue-500.ttf +0 -0
  41. package/dist/ui/fonts/epilogue-600.ttf +0 -0
  42. package/dist/ui/fonts/epilogue-700.ttf +0 -0
  43. package/dist/ui/fonts/storacha-fonts.css +152 -0
  44. package/dist/ui/storacha-backup.d.ts +44 -0
  45. package/dist/ui/storacha-backup.js +218 -0
  46. package/package.json +112 -0
@@ -0,0 +1,23 @@
1
+ /** @typedef {typeof __propDef.props} StorachaIntegrationProps */
2
+ /** @typedef {typeof __propDef.events} StorachaIntegrationEvents */
3
+ /** @typedef {typeof __propDef.slots} StorachaIntegrationSlots */
4
+ export default class StorachaIntegration extends SvelteComponentTyped<{
5
+ [x: string]: never;
6
+ }, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {}> {
9
+ }
10
+ export type StorachaIntegrationProps = typeof __propDef.props;
11
+ export type StorachaIntegrationEvents = typeof __propDef.events;
12
+ export type StorachaIntegrationSlots = 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 {};
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,152 @@
1
+ /* Storacha Brand Typography - Keep it Spicy! 🌶️ */
2
+
3
+ /* DM Mono - For code and small text */
4
+ @font-face {
5
+ font-family: 'DM Mono';
6
+ font-style: normal;
7
+ font-weight: 400;
8
+ font-display: swap;
9
+ src: url('./dm-mono-400.ttf') format('truetype');
10
+ }
11
+
12
+ @font-face {
13
+ font-family: 'DM Mono';
14
+ font-style: normal;
15
+ font-weight: 500;
16
+ font-display: swap;
17
+ src: url('./dm-mono-500.ttf') format('truetype');
18
+ }
19
+
20
+ /* DM Sans - For body text */
21
+ @font-face {
22
+ font-family: 'DM Sans';
23
+ font-style: normal;
24
+ font-weight: 400;
25
+ font-display: swap;
26
+ src: url('./dm-sans-400.ttf') format('truetype');
27
+ }
28
+
29
+ @font-face {
30
+ font-family: 'DM Sans';
31
+ font-style: normal;
32
+ font-weight: 500;
33
+ font-display: swap;
34
+ src: url('./dm-sans-500.ttf') format('truetype');
35
+ }
36
+
37
+ @font-face {
38
+ font-family: 'DM Sans';
39
+ font-style: normal;
40
+ font-weight: 600;
41
+ font-display: swap;
42
+ src: url('./dm-sans-600.ttf') format('truetype');
43
+ }
44
+
45
+ @font-face {
46
+ font-family: 'DM Sans';
47
+ font-style: normal;
48
+ font-weight: 700;
49
+ font-display: swap;
50
+ src: url('./dm-sans-700.ttf') format('truetype');
51
+ }
52
+
53
+ /* Epilogue - For headers and large text */
54
+ @font-face {
55
+ font-family: 'Epilogue';
56
+ font-style: normal;
57
+ font-weight: 400;
58
+ font-display: swap;
59
+ src: url('./epilogue-400.ttf') format('truetype');
60
+ }
61
+
62
+ @font-face {
63
+ font-family: 'Epilogue';
64
+ font-style: normal;
65
+ font-weight: 500;
66
+ font-display: swap;
67
+ src: url('./epilogue-500.ttf') format('truetype');
68
+ }
69
+
70
+ @font-face {
71
+ font-family: 'Epilogue';
72
+ font-style: normal;
73
+ font-weight: 600;
74
+ font-display: swap;
75
+ src: url('./epilogue-600.ttf') format('truetype');
76
+ }
77
+
78
+ @font-face {
79
+ font-family: 'Epilogue';
80
+ font-style: normal;
81
+ font-weight: 700;
82
+ font-display: swap;
83
+ src: url('./epilogue-700.ttf') format('truetype');
84
+ }
85
+
86
+ /* Storacha Brand CSS Variables */
87
+ :root {
88
+ /* Storacha Brand Colors */
89
+ --storacha-red-1: #e91315; /* Primary Red - Logo, buttons */
90
+ --storacha-blue-1: #0176ce; /* Primary Blue - Links, accents */
91
+ --storacha-yellow-1: #ffc83f; /* Primary Yellow - Highlights */
92
+ --storacha-red-2: #efe3f3; /* Light Red - Backgrounds */
93
+ --storacha-blue-2: #bde0ff; /* Light Blue - Backgrounds */
94
+ --storacha-yellow-2: #ffe4ae; /* Light Yellow - Backgrounds */
95
+
96
+ /* Storacha Typography */
97
+ --storacha-font-heading:
98
+ 'Epilogue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
99
+ --storacha-font-body:
100
+ 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
101
+ --storacha-font-mono:
102
+ 'DM Mono', 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', 'Consolas', 'Courier New', monospace;
103
+ }
104
+
105
+ /* Utility classes for Storacha branding */
106
+ .storacha-heading {
107
+ font-family: var(--storacha-font-heading);
108
+ font-weight: 600;
109
+ color: var(--storacha-red-1);
110
+ }
111
+
112
+ .storacha-body {
113
+ font-family: var(--storacha-font-body);
114
+ font-weight: 400;
115
+ }
116
+
117
+ .storacha-mono {
118
+ font-family: var(--storacha-font-mono);
119
+ font-weight: 400;
120
+ }
121
+
122
+ .storacha-spicy {
123
+ background: linear-gradient(135deg, var(--storacha-red-1) 0%, var(--storacha-yellow-1) 100%);
124
+ color: white;
125
+ font-family: var(--storacha-font-heading);
126
+ font-weight: 700;
127
+ }
128
+
129
+ /* Additional Storacha Brand Utilities */
130
+ .storacha-bg-primary {
131
+ background: linear-gradient(135deg, var(--storacha-red-1) 0%, var(--storacha-yellow-1) 100%);
132
+ }
133
+
134
+ .storacha-bg-light {
135
+ background: linear-gradient(135deg, var(--storacha-yellow-2) 0%, var(--storacha-red-2) 100%);
136
+ }
137
+
138
+ .storacha-bg-secondary {
139
+ background: linear-gradient(135deg, var(--storacha-blue-1) 0%, var(--storacha-red-1) 100%);
140
+ }
141
+
142
+ .storacha-text-primary {
143
+ color: var(--storacha-red-1);
144
+ }
145
+
146
+ .storacha-border {
147
+ border-color: var(--storacha-red-1);
148
+ }
149
+
150
+ .storacha-shadow {
151
+ box-shadow: 0 10px 25px rgba(233, 19, 21, 0.15);
152
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Initialize Storacha client with credentials (key + proof)
3
+ */
4
+ export function initializeStorachaClient(storachaKey: any, storachaProof: any): Promise<Client.Client>;
5
+ /**
6
+ * Initialize Storacha client with UCAN delegation
7
+ */
8
+ export function initializeStorachaClientWithUCAN(ucanToken: any, recipientKey: any): Promise<Client.Client>;
9
+ /**
10
+ * List spaces for authenticated client
11
+ */
12
+ export function listSpaces(client: any): Promise<{
13
+ did: any;
14
+ name: any;
15
+ registered: boolean;
16
+ current: boolean;
17
+ }[] | {
18
+ did: any;
19
+ name: any;
20
+ registered: any;
21
+ }[]>;
22
+ /**
23
+ * Get space usage information
24
+ */
25
+ export function getSpaceUsage(client: any, detailed?: boolean): Promise<{
26
+ totalFiles: any;
27
+ lastUploadDate: any;
28
+ oldestUploadDate: any;
29
+ uploads: {
30
+ cid: any;
31
+ uploadedAt: any;
32
+ size: any;
33
+ type: string;
34
+ }[];
35
+ backupFiles: number;
36
+ blockFiles: number;
37
+ otherFiles: number;
38
+ analyzed: boolean;
39
+ }>;
40
+ /**
41
+ * List files in Storacha space
42
+ */
43
+ export function listStorachaFiles(storachaKey: any, storachaProof: any): Promise<any[]>;
44
+ import * as Client from '@storacha/client';
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Storacha Backup Utilities for OrbitDB
3
+ *
4
+ * Decoupled from any specific app - accepts orbitdb/database instances as parameters.
5
+ * Uses the orbitdb-storacha-bridge library from npm.
6
+ */
7
+
8
+ import { listStorachaSpaceFiles } from 'orbitdb-storacha-bridge';
9
+ import * as Client from '@storacha/client';
10
+ import { StoreMemory } from '@storacha/client/stores/memory';
11
+ import { Signer } from '@storacha/client/principal/ed25519';
12
+ import * as Proof from '@storacha/client/proof';
13
+ import * as Delegation from '@ucanto/core/delegation';
14
+
15
+ /**
16
+ * Initialize Storacha client with credentials (key + proof)
17
+ */
18
+ export async function initializeStorachaClient(storachaKey, storachaProof) {
19
+ const principal = Signer.parse(storachaKey);
20
+ const store = new StoreMemory();
21
+ const client = await Client.create({ principal, store });
22
+
23
+ const proof = await Proof.parse(storachaProof);
24
+ const space = await client.addSpace(proof);
25
+ await client.setCurrentSpace(space.did());
26
+
27
+ return client;
28
+ }
29
+
30
+ /**
31
+ * Initialize Storacha client with UCAN delegation
32
+ */
33
+ export async function initializeStorachaClientWithUCAN(ucanToken, recipientKey) {
34
+ const recipientKeyData = JSON.parse(recipientKey);
35
+ const fixedArchive = {
36
+ id: recipientKeyData.id,
37
+ keys: {
38
+ [recipientKeyData.id]: new Uint8Array(
39
+ Object.values(recipientKeyData.keys[recipientKeyData.id])
40
+ ),
41
+ },
42
+ };
43
+
44
+ const recipientPrincipal = Signer.from(fixedArchive);
45
+ const store = new StoreMemory();
46
+ const client = await Client.create({
47
+ principal: recipientPrincipal,
48
+ store,
49
+ });
50
+
51
+ const delegationBytes = Buffer.from(ucanToken, 'base64');
52
+ const delegation = await Delegation.extract(delegationBytes);
53
+
54
+ if (!delegation.ok) {
55
+ throw new Error('Failed to extract delegation from token');
56
+ }
57
+
58
+ const space = await client.addSpace(delegation.ok);
59
+ await client.setCurrentSpace(space.did());
60
+
61
+ return client;
62
+ }
63
+
64
+ /**
65
+ * List spaces for authenticated client
66
+ */
67
+ export async function listSpaces(client) {
68
+ const currentSpace = client.currentSpace();
69
+ if (currentSpace) {
70
+ let registered = false;
71
+ try {
72
+ registered =
73
+ typeof currentSpace.registered === 'function' ? currentSpace.registered() : false;
74
+ } catch {
75
+ registered = false;
76
+ }
77
+
78
+ return [
79
+ {
80
+ did: currentSpace.did(),
81
+ name: currentSpace.name || 'Current Space',
82
+ registered: registered,
83
+ current: true,
84
+ },
85
+ ];
86
+ }
87
+
88
+ const accounts = client.accounts();
89
+ if (accounts.length === 0) {
90
+ return [];
91
+ }
92
+
93
+ const account = accounts[0];
94
+ const spaces = [];
95
+ for (const space of account.spaces()) {
96
+ spaces.push({
97
+ did: space.did(),
98
+ name: space.name || 'Unnamed Space',
99
+ registered: space.registered(),
100
+ });
101
+ }
102
+
103
+ return spaces;
104
+ }
105
+
106
+ /**
107
+ * Get space usage information
108
+ */
109
+ export async function getSpaceUsage(client, detailed = false) {
110
+ const result = await client.capability.upload.list({ size: 1000 });
111
+ const uploads = result.results || [];
112
+
113
+ if (uploads.length === 0) {
114
+ return {
115
+ totalFiles: 0,
116
+ lastUploadDate: null,
117
+ oldestUploadDate: null,
118
+ uploads: [],
119
+ backupFiles: 0,
120
+ blockFiles: 0,
121
+ otherFiles: 0,
122
+ analyzed: false,
123
+ };
124
+ }
125
+
126
+ const sortedUploads = uploads.sort((a, b) => new Date(b.insertedAt) - new Date(a.insertedAt));
127
+ const lastUploadDate = sortedUploads[0].insertedAt;
128
+ const oldestUploadDate = sortedUploads[sortedUploads.length - 1].insertedAt;
129
+
130
+ let backupFiles = 0;
131
+ let blockFiles = 0;
132
+ let otherFiles = 0;
133
+ const processedUploads = [];
134
+
135
+ if (detailed && uploads.length <= 50) {
136
+ const samplesToAnalyze = uploads.slice(0, 20);
137
+
138
+ for (const upload of samplesToAnalyze) {
139
+ const cid = upload.root.toString();
140
+ let fileType = 'block';
141
+
142
+ try {
143
+ const response = await fetch(`https://w3s.link/ipfs/${cid}`, {
144
+ headers: { Range: 'bytes=0-512' },
145
+ signal: AbortSignal.timeout(3000),
146
+ });
147
+
148
+ if (response.ok) {
149
+ const text = await response.text();
150
+ if (text.trim().startsWith('{') && text.includes('backupVersion')) {
151
+ fileType = 'backup';
152
+ }
153
+ }
154
+ } catch {
155
+ // Keep default 'block' type
156
+ }
157
+
158
+ if (fileType === 'backup') backupFiles++;
159
+ else if (fileType === 'block') blockFiles++;
160
+ else otherFiles++;
161
+
162
+ processedUploads.push({
163
+ cid,
164
+ uploadedAt: upload.insertedAt,
165
+ size: upload.size || null,
166
+ type: fileType,
167
+ });
168
+ }
169
+
170
+ const remaining = uploads.length - samplesToAnalyze.length;
171
+ if (remaining > 0) {
172
+ blockFiles += remaining;
173
+ for (let i = samplesToAnalyze.length; i < uploads.length; i++) {
174
+ const upload = uploads[i];
175
+ processedUploads.push({
176
+ cid: upload.root.toString(),
177
+ uploadedAt: upload.insertedAt,
178
+ size: upload.size || null,
179
+ type: 'block',
180
+ });
181
+ }
182
+ }
183
+ } else {
184
+ blockFiles = uploads.length;
185
+ for (const upload of uploads) {
186
+ processedUploads.push({
187
+ cid: upload.root.toString(),
188
+ uploadedAt: upload.insertedAt,
189
+ size: upload.size || null,
190
+ type: 'unknown',
191
+ });
192
+ }
193
+ }
194
+
195
+ return {
196
+ totalFiles: uploads.length,
197
+ lastUploadDate,
198
+ oldestUploadDate,
199
+ uploads: processedUploads,
200
+ backupFiles,
201
+ blockFiles,
202
+ otherFiles,
203
+ analyzed: detailed && uploads.length <= 50,
204
+ };
205
+ }
206
+
207
+ /**
208
+ * List files in Storacha space
209
+ */
210
+ export async function listStorachaFiles(storachaKey, storachaProof) {
211
+ const spaceFiles = await listStorachaSpaceFiles({
212
+ storachaKey,
213
+ storachaProof,
214
+ size: 1000,
215
+ });
216
+
217
+ return spaceFiles;
218
+ }
package/package.json ADDED
@@ -0,0 +1,112 @@
1
+ {
2
+ "name": "@le-space/p2pass",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "P2Pass — peer-to-peer passkeys, UCANs, OrbitDB registry sync, and Storacha backup (Svelte)",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/asabya/p2p-passkeys.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/asabya/p2p-passkeys/issues"
13
+ },
14
+ "homepage": "https://github.com/asabya/p2p-passkeys#readme",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "scripts": {
19
+ "dev:example": "vite --config example/vite.config.js",
20
+ "build:example": "vite build --config example/vite.config.js",
21
+ "test:e2e": "playwright test",
22
+ "test:e2e:ui": "playwright test --ui",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "package": "svelte-package && publint",
26
+ "prepublishOnly": "npm run package",
27
+ "check": "svelte-check --tsconfig ./jsconfig.json",
28
+ "format": "prettier --write .",
29
+ "format:check": "prettier --check .",
30
+ "lint": "eslint ."
31
+ },
32
+ "svelte": "./dist/index.js",
33
+ "types": "./dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "svelte": "./dist/index.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "!dist/**/*.test.*",
43
+ "!dist/**/*.spec.*"
44
+ ],
45
+ "devDependencies": {
46
+ "@eslint/js": "^10.0.1",
47
+ "@playwright/test": "^1.51.0",
48
+ "@sveltejs/package": "^2.3.10",
49
+ "@sveltejs/vite-plugin-svelte": "^6.1.4",
50
+ "@tailwindcss/vite": "^4.1.17",
51
+ "eslint": "^10.1.0",
52
+ "eslint-plugin-svelte": "^3.16.0",
53
+ "globals": "^17.4.0",
54
+ "prettier": "^3.8.1",
55
+ "prettier-plugin-svelte": "^3.5.1",
56
+ "publint": "^0.2.0",
57
+ "svelte": "^5.38.7",
58
+ "svelte-check": "^4.3.1",
59
+ "svelte-eslint-parser": "^1.6.0",
60
+ "tailwindcss": "^4.1.13",
61
+ "typescript": "^5.9.2",
62
+ "typescript-eslint": "^8.57.2",
63
+ "vite": "^7.1.12",
64
+ "vite-plugin-node-polyfills": "^0.24.0",
65
+ "vitest": "^3.0.0"
66
+ },
67
+ "dependencies": {
68
+ "@chainsafe/libp2p-gossipsub": "14.1.1",
69
+ "@chainsafe/libp2p-noise": "^16.1.4",
70
+ "@chainsafe/libp2p-yamux": "^7.0.4",
71
+ "@helia/ipns": "^8.0.0",
72
+ "@le-space/orbitdb-identity-provider-webauthn-did": "^0.2.13",
73
+ "@libp2p/autonat": "^2.0.38",
74
+ "@libp2p/bootstrap": "^11.0.47",
75
+ "@libp2p/circuit-relay-v2": "^3.2.24",
76
+ "@libp2p/crypto": "^5.1.8",
77
+ "@libp2p/dcutr": "^2.0.38",
78
+ "@libp2p/identify": "^3.0.39",
79
+ "@libp2p/peer-id": "^5.1.9",
80
+ "@libp2p/ping": "^2.0.36",
81
+ "@libp2p/pubsub-peer-discovery": "^11.0.2",
82
+ "@libp2p/webrtc": "^5.2.23",
83
+ "@libp2p/websockets": "^9.2.19",
84
+ "@multiformats/multiaddr": "^12.0.0",
85
+ "@orbitdb/core": "^3.0.2",
86
+ "@storacha/client": "^1.8.21",
87
+ "blockstore-level": "^2.0.1",
88
+ "buffer": "^6.0.3",
89
+ "datastore-level": "^11.0.4",
90
+ "helia": "^5.3.0",
91
+ "ipns": "^10.0.0",
92
+ "iso-webauthn-varsig": "npm:@le-space/iso-webauthn-varsig@^0.1.0",
93
+ "it-length-prefixed-stream": "^2.0.4",
94
+ "libp2p": "^2.9.0",
95
+ "lucide-svelte": "^0.500.0",
96
+ "multiformats": "^13.3.7",
97
+ "orbitdb-relay-pinner": "^0.5.0",
98
+ "orbitdb-storacha-bridge": "^0.4.2",
99
+ "w3name": "^1.1.3"
100
+ },
101
+ "overrides": {
102
+ "picomatch": "4.0.4",
103
+ "@ucanto/interface": "npm:@le-space/ucanto-interface@^11.1.1",
104
+ "@ucanto/core": "npm:@le-space/ucanto-core@^10.5.1",
105
+ "@ucanto/principal": "npm:@le-space/ucanto-principal@^9.1.2",
106
+ "@ucanto/client": "npm:@le-space/ucanto-client@^9.1.1",
107
+ "@ucanto/validator": "npm:@le-space/ucanto-validator@^10.1.1"
108
+ },
109
+ "engines": {
110
+ "node": ">=22"
111
+ }
112
+ }