{"version":3,"sources":["../src/scope.ts","../src/canonical.ts"],"names":[],"mappings":"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","file":"canonical.mjs","sourcesContent":["// Scope grammar, canonicalization, and sub-scope relation. See SPEC.md §7.\n//\n// A scope is <product>:<verb>(<constraint-list>).\n// Constraints are <key><op><value>, op ∈ { =, !=, <, <=, >, >=, * }.\n// Canonical form: constraints sorted by key; no whitespace.\n\nexport type ScopeOp = '=' | '!=' | '<' | '<=' | '>' | '>=' | '*';\n\nexport interface ScopeConstraint {\n    key: string;\n    op: ScopeOp;\n    /** `undefined` for the wildcard `*` op; otherwise the raw textual value (unquoted). */\n    value: string | undefined;\n    /** True if the value was supplied as a quoted string; preserved for round-trip fidelity. */\n    quoted: boolean;\n}\n\nexport interface Scope {\n    product: string;\n    verb: string;\n    constraints: ScopeConstraint[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Registered products/verbs (SPEC §7.3) and constraint keys (SPEC §7.6).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const REGISTERED_SCOPES: Record<string, { keys: string[] }> = {\n    'lock:seal': { keys: ['recipient', 'mime', 'max_bytes'] },\n    'lock:chat': { keys: ['recipient', 'max_bytes_per_msg', 'max_msgs'] },\n    'stamp:sign': { keys: ['mime', 'max_bytes', 'content_hash_prefix'] },\n    'vote:cast': { keys: ['poll_id', 'choice'] },\n    'nostr:publish': { keys: ['kind', 'relay', 'max_bytes'] },\n    'http:request': { keys: ['origin', 'method', 'max_rps', 'max_bytes_out'] },\n    'ln:send': { keys: ['max_sats', 'node', 'max_fee_sats'] },\n    'mcp:invoke': { keys: ['server', 'tool', 'max_invocations'] },\n};\n\n/** Keys whose values are compared numerically for sub-scope ordering. */\nconst NUMERIC_KEYS = new Set<string>([\n    'max_bytes',\n    'max_bytes_per_msg',\n    'max_msgs',\n    'max_bytes_out',\n    'max_rps',\n    'max_sats',\n    'max_fee_sats',\n    'max_invocations',\n    'kind',\n]);\n\nconst IDENT_RE = /^[a-z][a-z0-9_]*$/;\nconst BARE_TOKEN_RE = /^[A-Za-z0-9_.:/@+\\-]+$/;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Parse\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ScopeParseError extends Error {\n    constructor(message: string) {\n        super(message);\n        this.name = 'ScopeParseError';\n    }\n}\n\nexport function parseScope(input: string): Scope {\n    if (typeof input !== 'string' || input.length === 0) {\n        throw new ScopeParseError('scope must be a non-empty string');\n    }\n    if (/\\s/.test(input)) {\n        throw new ScopeParseError(`scope may not contain whitespace: ${JSON.stringify(input)}`);\n    }\n\n    const colonIdx = input.indexOf(':');\n    if (colonIdx < 0) throw new ScopeParseError('scope missing \"product:verb\" separator');\n\n    const product = input.slice(0, colonIdx);\n    if (!IDENT_RE.test(product)) throw new ScopeParseError(`invalid product: ${product}`);\n\n    const rest = input.slice(colonIdx + 1);\n    const parenIdx = rest.indexOf('(');\n\n    let verb: string;\n    let constraintText = '';\n    if (parenIdx < 0) {\n        verb = rest;\n    } else {\n        verb = rest.slice(0, parenIdx);\n        if (!rest.endsWith(')')) throw new ScopeParseError('scope constraint list must end with \")\"');\n        constraintText = rest.slice(parenIdx + 1, -1);\n    }\n    if (!IDENT_RE.test(verb)) throw new ScopeParseError(`invalid verb: ${verb}`);\n\n    const constraints: ScopeConstraint[] = [];\n    if (constraintText.length > 0) {\n        for (const piece of splitTopLevelCommas(constraintText)) {\n            constraints.push(parseConstraint(piece));\n        }\n    }\n\n    // No duplicate keys.\n    const seen = new Set<string>();\n    for (const c of constraints) {\n        if (seen.has(c.key)) throw new ScopeParseError(`duplicate constraint key: ${c.key}`);\n        seen.add(c.key);\n    }\n\n    return { product, verb, constraints };\n}\n\nfunction splitTopLevelCommas(text: string): string[] {\n    const out: string[] = [];\n    let depth = 0;\n    let inQuotes = false;\n    let start = 0;\n    for (let i = 0; i < text.length; i++) {\n        const ch = text[i];\n        if (inQuotes) {\n            if (ch === '\\\\' && i + 1 < text.length) {\n                i++;\n                continue;\n            }\n            if (ch === '\"') inQuotes = false;\n            continue;\n        }\n        if (ch === '\"') {\n            inQuotes = true;\n            continue;\n        }\n        if (ch === '(') depth++;\n        else if (ch === ')') depth--;\n        else if (ch === ',' && depth === 0) {\n            out.push(text.slice(start, i));\n            start = i + 1;\n        }\n    }\n    out.push(text.slice(start));\n    return out;\n}\n\nfunction parseConstraint(piece: string): ScopeConstraint {\n    if (piece.length === 0) throw new ScopeParseError('empty constraint');\n\n    // The `*` op (wildcard) is an op with no value. Recognized by \"key=*\" form.\n    // SPEC uses \"key=*\"; we also accept \"key*\" as legacy alias.\n    // Ops in descending length so \">=\" beats \">\" and \"!=\" beats \"!\".\n    const OPS: ScopeOp[] = ['>=', '<=', '!=', '=', '>', '<'];\n\n    // Special-case wildcard: \"key=*\" or \"key*\".\n    const wildcardMatch = /^([a-z][a-z0-9_]*)(?:=\\*|\\*)$/.exec(piece);\n    if (wildcardMatch) {\n        return { key: wildcardMatch[1]!, op: '*', value: undefined, quoted: false };\n    }\n\n    for (const op of OPS) {\n        const idx = piece.indexOf(op);\n        if (idx <= 0) continue; // key must come first and be non-empty\n        const key = piece.slice(0, idx);\n        if (!IDENT_RE.test(key)) continue;\n        const raw = piece.slice(idx + op.length);\n        const { value, quoted } = parseValue(raw);\n        return { key, op, value, quoted };\n    }\n    throw new ScopeParseError(`constraint missing operator: ${piece}`);\n}\n\nfunction parseValue(raw: string): { value: string; quoted: boolean } {\n    if (raw.length === 0) throw new ScopeParseError('constraint value is empty');\n    if (raw.startsWith('\"')) {\n        if (!raw.endsWith('\"') || raw.length < 2) {\n            throw new ScopeParseError(`unterminated quoted value: ${raw}`);\n        }\n        let v = '';\n        for (let i = 1; i < raw.length - 1; i++) {\n            const ch = raw[i]!;\n            if (ch === '\\\\' && i + 1 < raw.length - 1) {\n                const next = raw[++i]!;\n                v += next;\n            } else if (ch === '\"') {\n                throw new ScopeParseError(`unescaped quote in value: ${raw}`);\n            } else {\n                v += ch;\n            }\n        }\n        return { value: v, quoted: true };\n    }\n    if (!BARE_TOKEN_RE.test(raw)) {\n        throw new ScopeParseError(`invalid bare-token value: ${JSON.stringify(raw)}`);\n    }\n    return { value: raw, quoted: false };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Canonicalize\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function canonicalizeScope(scope: Scope): string {\n    const sorted = [...scope.constraints].sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));\n    const parts = sorted.map(serializeConstraint);\n    const inner = parts.join(',');\n    return `${scope.product}:${scope.verb}${parts.length === 0 ? '' : `(${inner})`}`;\n}\n\nexport function canonicalizeScopeString(input: string): string {\n    return canonicalizeScope(parseScope(input));\n}\n\nfunction serializeConstraint(c: ScopeConstraint): string {\n    if (c.op === '*') return `${c.key}=*`;\n    const v = c.quoted ? quoteValue(c.value ?? '') : c.value ?? '';\n    return `${c.key}${c.op}${v}`;\n}\n\nfunction quoteValue(v: string): string {\n    let out = '\"';\n    for (const ch of v) {\n        if (ch === '\"' || ch === '\\\\') out += '\\\\' + ch;\n        else out += ch;\n    }\n    out += '\"';\n    return out;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Registry-based validation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ValidationOptions {\n    /**\n     * Strict: reject unknown products/verbs and unknown constraint keys.\n     * Permissive: accept unknown products/verbs; ignore unknown keys without treating them as wider.\n     * Default: 'strict'.\n     */\n    mode?: 'strict' | 'permissive';\n}\n\nexport function validateScope(scope: Scope, options: ValidationOptions = {}): void {\n    const mode = options.mode ?? 'strict';\n    const reg = REGISTERED_SCOPES[`${scope.product}:${scope.verb}`];\n    if (!reg) {\n        if (mode === 'strict') {\n            throw new ScopeParseError(`unregistered scope: ${scope.product}:${scope.verb}`);\n        }\n        return; // permissive: no further checks\n    }\n    const registered = new Set(reg.keys);\n    for (const c of scope.constraints) {\n        if (!registered.has(c.key)) {\n            if (mode === 'strict') {\n                throw new ScopeParseError(\n                    `unregistered constraint key for ${scope.product}:${scope.verb}: ${c.key}`\n                );\n            }\n            // permissive: ignore\n        }\n    }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sub-scope relation (SPEC §7.4)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Is `exercised` a sub-scope of `granted`?\n * Returns true iff every constraint of `granted` admits the corresponding constraint\n * (or absence) in `exercised`, per SPEC §7.4.\n */\nexport function isSubScope(exercised: Scope, granted: Scope): boolean {\n    if (exercised.product !== granted.product) return false;\n    if (exercised.verb !== granted.verb) return false;\n\n    const exIndex = new Map<string, ScopeConstraint>();\n    for (const c of exercised.constraints) exIndex.set(c.key, c);\n\n    for (const g of granted.constraints) {\n        const ex = exIndex.get(g.key);\n        if (g.op === '*') continue; // wildcard: no requirement\n\n        if (g.op === '=') {\n            if (!ex) return false;\n            if (ex.op !== '=' || ex.value !== g.value) return false;\n            continue;\n        }\n\n        if (g.op === '!=') {\n            if (!ex) return false;\n            if (ex.op === '=' && ex.value !== g.value) continue;\n            if (ex.op === '!=' && ex.value === g.value) continue;\n            return false;\n        }\n\n        // Ordered ops: >=, <=, >, <. Exercised's implied range must be ⊆ granted's.\n        if (g.op === '<' || g.op === '<=' || g.op === '>' || g.op === '>=') {\n            if (!ex) return false;\n            if (!NUMERIC_KEYS.has(g.key)) return false;\n            if (ex.op === '*') return false;\n            if (ex.value === undefined || g.value === undefined) return false;\n            if (!rangeSubset(ex, g)) return false;\n            continue;\n        }\n    }\n    return true;\n}\n\nfunction rangeSubset(ex: ScopeConstraint, g: ScopeConstraint): boolean {\n    const exRange = opToRange(ex);\n    const gRange = opToRange(g);\n    if (!exRange || !gRange) return false;\n    return gRange.lo <= exRange.lo && exRange.hi <= gRange.hi;\n}\n\nfunction opToRange(c: ScopeConstraint): { lo: number; hi: number } | null {\n    if (c.value === undefined) return null;\n    const n = Number(c.value);\n    if (!Number.isFinite(n)) return null;\n    switch (c.op) {\n        case '=':\n            return { lo: n, hi: n };\n        case '<':\n            return { lo: -Infinity, hi: n - 1 }; // integers only\n        case '<=':\n            return { lo: -Infinity, hi: n };\n        case '>':\n            return { lo: n + 1, hi: Infinity };\n        case '>=':\n            return { lo: n, hi: Infinity };\n        default:\n            return null;\n    }\n}\n","// Canonical messages + envelope canonicalization for OC Agent. SPEC §4.1, §5.1, §9.1.\n//\n// Three canonical-message builders live here — one per envelope kind. Each one\n// produces the exact byte sequence a signer signs via BIP-322 and the hash\n// input for the envelope id.\n//\n// The RFC 8785 JSON canonicalizer and hex utilities are re-exported from\n// @orangecheck/stamp-core so OC Agent and OC Stamp are guaranteed to produce\n// identical bytes for identical structural inputs.\n\nimport { sha256 } from '@noble/hashes/sha256';\nimport { canonicalize, hexEncode } from '@orangecheck/stamp-core/canonical';\n\nimport { canonicalizeScope, parseScope, type Scope } from './scope.js';\nimport type {\n    ActionCanonicalInput,\n    ActionEnvelope,\n    DelegationCanonicalInput,\n    DelegationEnvelope,\n    RevocationCanonicalInput,\n    RevocationEnvelope,\n    SubdelegationCanonicalInput,\n} from './types.js';\n\nexport { canonicalize, hexEncode };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Scope sorting + serialization\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Canonicalize and sort a list of scope strings for the delegation canonical\n * message. Each scope is first parsed, then re-emitted in canonical form\n * (constraints sorted by key), and the whole list is sorted lexicographically.\n */\nexport function canonicalizeScopes(scopes: string[]): string[] {\n    const canonical = scopes.map((s) => canonicalizeScope(parseScope(s)));\n    return [...canonical].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n}\n\n/**\n * Same as `canonicalizeScopes` but returns `Scope` objects too, for callers\n * that need them.\n */\nexport function parseAndCanonicalizeScopes(scopes: string[]): { canonical: string[]; parsed: Scope[] } {\n    const parsed = scopes.map(parseScope);\n    const canonicalStrings = parsed.map(canonicalizeScope);\n    const indexed = canonicalStrings.map((s, i) => ({ s, p: parsed[i]! }));\n    indexed.sort((a, b) => (a.s < b.s ? -1 : a.s > b.s ? 1 : 0));\n    return {\n        canonical: indexed.map((x) => x.s),\n        parsed: indexed.map((x) => x.p),\n    };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Canonical messages (SPEC §4.1, §5.1, §9.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function delegationCanonicalMessage(input: DelegationCanonicalInput): string {\n    const scopeField = input.scopes.join(',');\n    return [\n        'oc-agent:delegation:v1',\n        `principal: ${input.principal}`,\n        `agent: ${input.agent}`,\n        `scopes: ${scopeField}`,\n        `bond_sats: ${input.bond_sats}`,\n        `bond_attestation: ${input.bond_attestation}`,\n        `issued_at: ${input.issued_at}`,\n        `expires_at: ${input.expires_at}`,\n        `nonce: ${input.nonce}`,\n    ].join('\\n');\n}\n\nexport function actionCanonicalMessage(input: ActionCanonicalInput): string {\n    return [\n        'oc-agent:action:v1',\n        `address: ${input.address}`,\n        `content_hash: ${input.content_hash}`,\n        `content_length: ${input.content_length}`,\n        `content_mime: ${input.content_mime}`,\n        `signed_at: ${input.signed_at}`,\n        `delegation_id: ${input.delegation_id}`,\n        `scope_exercised: ${input.scope_exercised}`,\n    ].join('\\n');\n}\n\nexport function revocationCanonicalMessage(input: RevocationCanonicalInput): string {\n    return [\n        'oc-agent:revocation:v1',\n        `address: ${input.address}`,\n        `delegation_id: ${input.delegation_id}`,\n        `reason: ${input.reason}`,\n        `signed_at: ${input.signed_at}`,\n    ].join('\\n');\n}\n\nexport function subdelegationCanonicalMessage(input: SubdelegationCanonicalInput): string {\n    const scopeField = input.scopes.join(',');\n    return [\n        'oc-agent:subdelegation:v1',\n        `parent_id: ${input.parent_id}`,\n        `principal: ${input.principal}`,\n        `agent: ${input.agent}`,\n        `scopes: ${scopeField}`,\n        `issued_at: ${input.issued_at}`,\n        `expires_at: ${input.expires_at}`,\n        `nonce: ${input.nonce}`,\n    ].join('\\n');\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Bytes + ids\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function delegationCanonicalBytes(input: DelegationCanonicalInput): Uint8Array {\n    return new TextEncoder().encode(delegationCanonicalMessage(input));\n}\n\nexport function actionCanonicalBytes(input: ActionCanonicalInput): Uint8Array {\n    return new TextEncoder().encode(actionCanonicalMessage(input));\n}\n\nexport function revocationCanonicalBytes(input: RevocationCanonicalInput): Uint8Array {\n    return new TextEncoder().encode(revocationCanonicalMessage(input));\n}\n\nexport function subdelegationCanonicalBytes(input: SubdelegationCanonicalInput): Uint8Array {\n    return new TextEncoder().encode(subdelegationCanonicalMessage(input));\n}\n\nexport function computeDelegationId(input: DelegationCanonicalInput): string {\n    return hexEncode(sha256(delegationCanonicalBytes(input)));\n}\n\nexport function computeActionId(input: ActionCanonicalInput): string {\n    return hexEncode(sha256(actionCanonicalBytes(input)));\n}\n\nexport function computeRevocationId(input: RevocationCanonicalInput): string {\n    return hexEncode(sha256(revocationCanonicalBytes(input)));\n}\n\nexport function computeSubdelegationId(input: SubdelegationCanonicalInput): string {\n    return hexEncode(sha256(subdelegationCanonicalBytes(input)));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Envelope canonicalization (SPEC §6; RFC 8785 + scope-sorting)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function canonicalizeDelegation(env: DelegationEnvelope): string {\n    return canonicalize(env as unknown as Parameters<typeof canonicalize>[0]);\n}\n\nexport function canonicalizeAction(env: ActionEnvelope): string {\n    return canonicalize(env as unknown as Parameters<typeof canonicalize>[0]);\n}\n\nexport function canonicalizeRevocation(env: RevocationEnvelope): string {\n    return canonicalize(env as unknown as Parameters<typeof canonicalize>[0]);\n}\n\nexport function canonicalDelegationBytes(env: DelegationEnvelope): Uint8Array {\n    return new TextEncoder().encode(canonicalizeDelegation(env) + '\\n');\n}\n\nexport function canonicalActionBytes(env: ActionEnvelope): Uint8Array {\n    return new TextEncoder().encode(canonicalizeAction(env) + '\\n');\n}\n\nexport function canonicalRevocationBytes(env: RevocationEnvelope): Uint8Array {\n    return new TextEncoder().encode(canonicalizeRevocation(env) + '\\n');\n}\n\nexport function sha256Hex(bytes: Uint8Array): string {\n    return hexEncode(sha256(bytes));\n}\n"]}