#!/usr/bin/env node
/**
* Per-org-invite example — FORWARD-LOOKING SPEC (issue #35)
*
* This example demonstrates the desired post-refactor flow:
* - One autobase per org (Keet-rooms pattern)
* - `createOrgInvite(name, opts)` returns a bearer invite scoped
* to a single org
* - `joinOrg(invite)` consumes it, mounts ONLY that org's autobase,
* and starts replicating just that org's data
*
* Today this example will print a clear "NOT IMPLEMENTED" line and
* exit before the join step — because `createOrgInvite` and
* `joinOrg` do not exist on `HyperOrgs` yet. The matching failing
* test is `test/scope-isolation.test.js` (SPEC #35).
*
* Once the per-org-autobase refactor lands, this example runs
* end-to-end successfully and prints the isolation proof.
*
* Usage:
* node examples/per-org-invite.js
*
* Storage: ephemeral temp dirs, cleaned up on exit.
*/
import Corestore from 'corestore'
import { mkdtempSync, rmSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
import { replicateAndSync } from 'autobase-test-helpers'
import { HyperOrgs } from '../index.js'
const dirs = []
function tmpStore () {
const dir = mkdtempSync(join(tmpdir(), 'hyper-orgs-spec-'))
dirs.push(dir)
return new Corestore(dir)
}
async function main () {
// ── PRIMARY (org owner) ─────────────────────────────────────────
const storeA = tmpStore()
const owner = new HyperOrgs(storeA, { namespace: 'spec-demo' })
await owner.ready()
await owner.create('alpha', 'group', { displayName: 'Alpha' })
await owner.create('beta', 'group', { displayName: 'Beta' })
await owner.create('gamma', 'group', { displayName: 'Gamma' })
await owner.base.update()
console.log('[owner] created 3 orgs: alpha, beta, gamma')
// ── FUTURE API #1 — createOrgInvite ─────────────────────────────
if (typeof owner.createOrgInvite !== 'function') {
console.log('')
console.log(' ⚠ NOT IMPLEMENTED YET: HyperOrgs.createOrgInvite(orgName, opts)')
console.log(' Required by post-mortem #35. This example will run')
console.log(' end-to-end once the per-org-autobase refactor lands.')
console.log(' See test/scope-isolation.test.js for the failing spec.')
console.log('')
await cleanup({ owner, storeA })
process.exit(0)
}
const { invitation: alphaInvite } = await owner.createOrgInvite('alpha', {
role: 'contributor',
maxUses: 1
})
console.log('[owner] issued bearer invite for alpha (contributor, 1 use)')
// ── JOINER ──────────────────────────────────────────────────────
const storeB = tmpStore()
const joiner = new HyperOrgs(storeB, { namespace: 'spec-demo-joiner' })
await joiner.ready()
// FUTURE API #2 — joinOrg
await joiner.joinOrg(alphaInvite)
console.log('[joiner] consumed alpha invite')
// Sync only alpha's per-org base (post-refactor accessor).
await replicateAndSync([owner.getOrgBase('alpha'), joiner.base])
// ── Isolation assertions ────────────────────────────────────────
const alphaSeen = !!(await joiner.get('alpha'))
const betaSeen = !!(await joiner.get('beta'))
const gammaSeen = !!(await joiner.get('gamma'))
console.log('')
console.log('Joiner view after alpha-only join:')
console.log(' alpha:', alphaSeen ? 'visible (expected)' : 'MISSING (broken)')
console.log(' beta:', betaSeen ? 'VISIBLE — SCOPE LEAK' : 'hidden (expected)')
console.log(' gamma:', gammaSeen ? 'VISIBLE — SCOPE LEAK' : 'hidden (expected)')
const ok = alphaSeen && !betaSeen && !gammaSeen
console.log('')
console.log(ok ? '✓ isolation holds' : '✗ isolation broken')
await cleanup({ owner, storeA, joiner, storeB })
process.exit(ok ? 0 : 1)
}
async function cleanup ({ owner, storeA, joiner, storeB }) {
try { if (owner) await owner.close() } catch {}
try { if (joiner) await joiner.close() } catch {}
try { if (storeA) await storeA.close() } catch {}
try { if (storeB) await storeB.close() } catch {}
for (const d of dirs) { try { rmSync(d, { recursive: true, force: true }) } catch {} }
}
main().catch((err) => {
console.error('example failed:', err)
process.exit(1)
})