| … | … | @@ -1,18 +1,19 @@ |
| 1 | 1 | { |
| 2 | 2 | "name": "favela-node", |
| 3 | "version": "0.1.0", | |
| 3 | "version": "0.1.2", | |
| 4 | 4 | "lockfileVersion": 3, |
| 5 | 5 | "requires": true, |
| 6 | 6 | "packages": { |
| 7 | 7 | "": { |
| 8 | 8 | "name": "favela-node", |
| 9 | "version": "0.1.0", | |
| 9 | "version": "0.1.2", | |
| 10 | 10 | "dependencies": { |
| 11 | 11 | "atproto-identity": "file:../atproto-identity", |
| 12 | 12 | "atproto-room": "file:../atproto-room", |
| 13 | 13 | "b4a": "^1.8.1", |
| 14 | 14 | "bare-path": "^3.0.0", |
| 15 | 15 | "bare-process": "^4.0.0", |
| 16 | "bip39-mnemonic": "^2.5.0", | |
| 16 | 17 | "corestore": "^7.4.0", |
| 17 | 18 | "favela-community": "file:../favela-community", |
| 18 | 19 | "hypercore-crypto": "^3.4.0", |
| … | … | @@ -23,7 +24,7 @@ |
| 23 | 24 | } |
| 24 | 25 | }, |
| 25 | 26 | "../atproto-identity": { |
| 26 | "version": "0.0.1", | |
| 27 | "version": "0.0.2", | |
| 27 | 28 | "hasInstallScript": true, |
| 28 | 29 | "dependencies": { |
| 29 | 30 | "@ipld/dag-cbor": "^9.2.1", |
| … | … | @@ -72,7 +73,7 @@ |
| 72 | 73 | } |
| 73 | 74 | }, |
| 74 | 75 | "../favela-community": { |
| 75 | "version": "0.1.3", | |
| 76 | "version": "0.1.4", | |
| 76 | 77 | "dependencies": { |
| 77 | 78 | "autobase": "^7.28.0", |
| 78 | 79 | "b4a": "^1.8.1", |
| … | … | @@ -425,6 +426,17 @@ |
| 425 | 426 | "integrity": "sha512-6RjV/3mSZORlMdpUaQ6rUSpG637cZm0//E54YYGtQg1c1O+AbZP8UTdJ/TchsDZcTVLmyWZcseBfp2HBeXUXOQ==", |
| 426 | 427 | "license": "MIT" |
| 427 | 428 | }, |
| 429 | "node_modules/bip39-mnemonic": { | |
| 430 | "version": "2.5.0", | |
| 431 | "resolved": "https://registry.npmjs.org/bip39-mnemonic/-/bip39-mnemonic-2.5.0.tgz", | |
| 432 | "integrity": "sha512-hgCxFHN129ta0bHl9VPykoqCPagBUr2oaXjfSbfeXAPe+y/byxwjPFFEFTMNO/1T/GSoMP1cOXHa2ZaprHG1kg==", | |
| 433 | "license": "Apache-2.0", | |
| 434 | "dependencies": { | |
| 435 | "b4a": "^1.6.6", | |
| 436 | "nanoassert": "^2.0.0", | |
| 437 | "sodium-universal": "^5.0.1" | |
| 438 | } | |
| 439 | }, | |
| 428 | 440 | "node_modules/bits-to-bytes": { |
| 429 | 441 | "version": "1.3.0", |
| 430 | 442 | "resolved": "https://registry.npmjs.org/bits-to-bytes/-/bits-to-bytes-1.3.0.tgz", |
| … | … | @@ -13,6 +13,7 @@ |
| 13 | 13 | "b4a": "^1.8.1", |
| 14 | 14 | "bare-path": "^3.0.0", |
| 15 | 15 | "bare-process": "^4.0.0", |
| 16 | "bip39-mnemonic": "^2.5.0", | |
| 16 | 17 | "corestore": "^7.4.0", |
| 17 | 18 | "favela-community": "file:../favela-community", |
| 18 | 19 | "hypercore-crypto": "^3.4.0", |
| … | … | @@ -0,0 +1,67 @@ |
| 1 | // Mint the loser-club community DID (step 1, LOCAL — no PLC submit here). Creates a co-owned community | |
| 2 | // did:plc (handle loser-club.7rnx.net) with a keyless CommunityRoom whose roster = p2p.7rnx.net + ashatron. | |
| 3 | // Persists to ~/.config/loser-club and saves the secrets + prints the genesis op for the PLC submit. | |
| 4 | // Run once: bare scripts/mint-loser-club.mjs | |
| 5 | import '../lib/bare-globals.js' | |
| 6 | import process from 'bare-process' | |
| 7 | import fs from 'bare-fs' | |
| 8 | import Corestore from 'corestore' | |
| 9 | import { generateMnemonic } from 'bip39-mnemonic' | |
| 10 | import { createCommunity } from '../index.js' | |
| 11 | ||
| 12 | const HOME = process.env.HOME | |
| 13 | const DIR = HOME + '/.config/loser-club' | |
| 14 | const SECRETS = DIR + '/secrets.json' | |
| 15 | if (fs.existsSync(SECRETS)) { console.error('refusing to overwrite existing', SECRETS, '(loser-club already minted)'); process.exit(1) } | |
| 16 | fs.mkdirSync(DIR + '/room', { recursive: true }) | |
| 17 | fs.mkdirSync(DIR + '/repo', { recursive: true }) | |
| 18 | ||
| 19 | const WJ62 = 'did:plc:wj62ebbusln6gxo5azo6ogzo' // p2p.7rnx.net | |
| 20 | const ASHATRON = 'did:plc:e2jevhuurrhlm36ufk7fklpg' // ashatron.7rnx.net | |
| 21 | const MEMBRANE = 'https://pds.7rnx.net' | |
| 22 | ||
| 23 | const rootMnemonic = generateMnemonic() | |
| 24 | const founderDeviceMnemonic = generateMnemonic() | |
| 25 | ||
| 26 | const roomStore = new Corestore(DIR + '/room') | |
| 27 | const c = await createCommunity({ | |
| 28 | rootMnemonic, | |
| 29 | founderDeviceMnemonic, | |
| 30 | handle: 'loser-club.7rnx.net', | |
| 31 | name: 'loser-club', | |
| 32 | feedGenEndpoint: MEMBRANE, | |
| 33 | labelerEndpoint: MEMBRANE, | |
| 34 | roomStore, | |
| 35 | repoStorage: DIR + '/repo', | |
| 36 | network: false | |
| 37 | }) | |
| 38 | await c.room.addMember(WJ62) | |
| 39 | await c.room.addMember(ASHATRON) | |
| 40 | ||
| 41 | const secrets = { | |
| 42 | did: c.did, | |
| 43 | handle: 'loser-club.7rnx.net', | |
| 44 | rootMnemonic, | |
| 45 | founderDeviceMnemonic, | |
| 46 | signingKey: c.signingKey, | |
| 47 | roomKey: c.room.key, | |
| 48 | members: [WJ62, ASHATRON], | |
| 49 | createdAt: null // stamped by the operator; Date.now() is unavailable under bare here | |
| 50 | } | |
| 51 | fs.writeFileSync(SECRETS, JSON.stringify(secrets, null, 2)) | |
| 52 | try { fs.chmodSync(SECRETS, 0o600) } catch {} | |
| 53 | ||
| 54 | console.log('=== loser-club minted (LOCAL — not yet PLC-submitted) ===') | |
| 55 | console.log('DID: ' + c.did) | |
| 56 | console.log('handle: loser-club.7rnx.net') | |
| 57 | console.log('roomKey: ' + c.room.key) | |
| 58 | console.log('members: ' + (await c.room.members()).join(', ')) | |
| 59 | console.log('secrets: ' + SECRETS + ' (root mnemonic + keys — KEEP SAFE)') | |
| 60 | console.log('\n--- genesis op (submit this to plc.directory: POST https://plc.directory/<did>) ---') | |
| 61 | console.log(JSON.stringify(c.identity.signedOp)) | |
| 62 | console.log('--- end genesis op ---') | |
| 63 | ||
| 64 | await c.sb.close() | |
| 65 | await c.room.close() | |
| 66 | try { await roomStore.close() } catch {} | |
| 67 | process.exit(0) |
| … | … | @@ -0,0 +1,26 @@ |
| 1 | // Step 2 — SUBMIT loser-club's genesis op to plc.directory. ⚠️ IRREVERSIBLE (a permanent append to the | |
| 2 | // global PLC op-log). Re-derives the identity deterministically from the saved root mnemonic, verifies the | |
| 3 | // DID matches the minted one, validates the op (checkGenesisOp), POSTs, and confirms via GET /:did/data. | |
| 4 | // Run under node (global fetch): node scripts/submit-loser-club-plc.mjs | |
| 5 | import fs from 'node:fs' | |
| 6 | import { createSwarmIdentity } from 'atproto-identity' | |
| 7 | import { PlcDirectory } from 'atproto-identity/lib/plc-directory.js' | |
| 8 | ||
| 9 | const SECRETS = process.env.HOME + '/.config/loser-club/secrets.json' | |
| 10 | const s = JSON.parse(fs.readFileSync(SECRETS, 'utf8')) | |
| 11 | const MEMBRANE = 'https://pds.7rnx.net' | |
| 12 | ||
| 13 | const id = createSwarmIdentity(s.rootMnemonic, { handle: s.handle, pdsUrl: MEMBRANE, feedGenEndpoint: MEMBRANE, labelerEndpoint: MEMBRANE }) | |
| 14 | if (id.did !== s.did) { console.error('DID mismatch — re-derived', id.did, 'vs saved', s.did, '— REFUSING to submit'); process.exit(1) } | |
| 15 | console.log('re-derived DID matches:', id.did) | |
| 16 | ||
| 17 | const plc = new PlcDirectory({}) // uses global fetch (node) | |
| 18 | console.log('submitting genesis op to plc.directory …') | |
| 19 | try { | |
| 20 | const data = await plc.submitGenesis({ did: id.did, signedOp: id.signedOp, confirm: true }) | |
| 21 | console.log('✓ SUBMITTED + confirmed. PLC data:') | |
| 22 | console.log(JSON.stringify(data)) | |
| 23 | } catch (e) { | |
| 24 | console.error('submit FAILED:', e.message) | |
| 25 | process.exit(1) | |
| 26 | } |