OverviewFilesCommitsIssuesDocsReleasesPeers

favela-markdown / test / uri.test.js

86 lines · javascript ref:
// uri.test.js — the `favela://` scheme, and what goes in the authority position.
//
// ⛔ THE LIVE BUG. `isMention` is `/^(favela:\/\/|did:)/` — it matches ANY favela URI. The blob form
// was noticed and worked around by ordering ("every caller must test for a blob FIRST",
// dialect.js:43). The RECORD form was not, because it was never specified — so
// `favela://<x>/<collection>/<name>`, which favela-surface already emits for a quote
// (router.js:291), is classified as a mention of a user. A quote renders as a mention of nobody.
//
// ⛔ AND THE AUTHORITY MEANT TWO THINGS. Mentions carry an IDENTITY ROOT (dialect.js:37,
// mentions.js:116). The quote path carries a FEED KEY. Both are 64 hex characters, so nothing can
// tell them apart. hyper-social #61 §12 #1 is exactly this question.
//
// ★ THE DECISION: the authority is the IDENTITY ROOT, one space, everywhere.
//   - the mention form already uses it, and those records are written
//   - NAMING.md §3 — a name resolves to an identity root, and only then to a room key
//   - hyper-social #64 §1 — handle claims anchor to the ROOT; pgh paid for the device-key version
//     with `pgh names reanchor --all --force`
//   - #61 §2a — an address derived from a rotatable locator is the failure `favela://` exists to
//     prevent. A feed key is a LOCATOR; the root is the identity. Same split as name vs oplog.
//
// ⚠ Parsing stays PERMISSIVE about the authority's shape, because it must read bytes already
// written — including a vector that mentions `favela://abc123`. Strictness belongs where URIs are
// MINTED, not where old records are read.

import test from 'brittle'
import { parseUri, userUri, recordUri, blobUri, isRecordUri } from '../lib/uri.js'
import { isMention, isBlob } from '../lib/dialect.js'

const ROOT = 'a'.repeat(64)

test('★★ a record URI is NOT a mention', async (t) => {
  const uri = recordUri({ root: ROOT, collection: 'post', name: '01k1v297vo008i4cq4alj7f24p' })
  t.absent(isMention(uri), 'the whole defect: a quote used to render as a mention of nobody')
  t.ok(isRecordUri(uri))
})

test('★★ three forms, told apart by SHAPE rather than by call order', async (t) => {
  t.is(parseUri('favela://' + ROOT).kind, 'user')
  t.is(parseUri('favela://' + ROOT + '/post/abc').kind, 'record')
  t.is(parseUri('favela://blob/deadbeef').kind, 'blob')
  // dialect.js:43 says a caller must test for a blob FIRST or an image silently disappears. With a
  // real parse there is no ordering to get wrong.
  t.absent(isMention('favela://blob/deadbeef'), 'a blob is not a mention either, now')
  t.ok(isBlob('favela://blob/deadbeef'), 'and the blob predicate is unchanged')
})

test('★ the parts come back', async (t) => {
  const u = parseUri('favela://' + ROOT + '/post/01k1v297vo008i4cq4alj7f24p')
  t.is(u.root, ROOT)
  t.is(u.collection, 'post')
  t.is(u.name, '01k1v297vo008i4cq4alj7f24p')
  t.is(parseUri('favela://blob/deadbeef').oid, 'deadbeef')
  t.is(parseUri('favela://' + ROOT).root, ROOT)
})

test('★ minting round-trips', async (t) => {
  const r = recordUri({ root: ROOT, collection: 'post', name: 'abc' })
  t.alike(parseUri(r), { kind: 'record', root: ROOT, collection: 'post', name: 'abc', oid: null })
  t.is(parseUri(userUri(ROOT)).kind, 'user')
  t.is(parseUri(blobUri('deadbeef')).kind, 'blob')
})

// A vector in render.test.js mentions `favela://abc123`. Records are written; the reader must not
// start refusing them because a later spec said roots are 64 hex.
test('⛔ a legacy non-hex authority still reads as a user', async (t) => {
  t.is(parseUri('favela://abc123').kind, 'user')
  t.ok(isMention('favela://abc123'), 'and is still a mention')
})

test('⛔ minting a record URI REQUIRES an identity root — strict where we write', async (t) => {
  t.exception(() => recordUri({ root: 'abc123', collection: 'post', name: 'x' }), /identity root/i,
    'a feed key or a short string must not reach the authority position')
  t.exception(() => recordUri({ root: ROOT, collection: 'a/b', name: 'x' }), /segment/i)
  t.exception(() => recordUri({ root: ROOT, collection: 'post', name: '' }), /segment/i)
})

test('⛔ anything else fails closed', async (t) => {
  for (const bad of ['favela://', 'favela://a/b', 'favela://a/b/c/d', 'https://example.com', 'did:plc:x', '', null]) {
    t.is(parseUri(bad), null, JSON.stringify(bad))
  }
})

test('★ did: stays a mention — it is the legacy user form', async (t) => {
  t.ok(isMention('did:plc:abc'), 'dialect.js:37 calls it the legacy form and records carry it')
})