io-v2-profile.js (3168B)
1 // This table is the implemented browser provider, not the native catalogue. 2 import { canonicalNat, decodeAction, ProtocolError } from './io-v2-protocol.js'; 3 export const coreNames = ['pure', 'bind', 'fail', 'scope', 'current-scope', 'spawn', 'join', 'discard', 'cancel', 'cancelled']; 4 const groups = Object.freeze({ 5 runtime: ['capabilities', 'inspect'], standard: ['input', 'output', 'error'], 6 stream: ['read', 'write'], resource: ['close'], utf8: ['encode', 'decode'], 7 }); 8 export function available(group, revision, operation) { 9 return revision === 1 && Object.hasOwn(groups, group) && groups[group].includes(operation); 10 } 11 export function capabilities(wire, backend) { 12 const { tree } = wire, text = (s) => tree.text(s), number = (n) => tree.natural(BigInt(n)); 13 const strings = (xs) => wire.list(xs.map(text)), row = (name, value) => wire.list([text(name), value]); 14 return wire.list([ 15 row('schema', number(1)), row('io-version', number(2)), row('backend', text(backend)), row('authority', text('browser-terminal')), 16 row('core', strings(coreNames)), row('groups', wire.list(Object.entries(groups).map(([name, ops]) => wire.list([text(name), number(1), strings(ops)])))), 17 row('limits', wire.list(Object.entries({ 'io-actions': 65536, 'chunk-bytes': 4096, 'transfer-handles': 256, 'utf8-encode-scalars': 1024, 'input-line-scalars': 256, 'output-attempted-bytes': 16384 }).map(([key, value]) => row(key, number(value))))), 18 row('restrictions', strings(['action-boundary-cancellation', 'no-hard-deadlines', 'borrowed-standard-streams', 'standard-stream-leases-per-run', 'utf8-strict-scalars', 'text-line-input', 'byte-preserving-output', 'no-filesystem', 'no-network', 'no-processes'])), 19 ]); 20 } 21 export function inspect(wire, value) { 22 const action = decodeAction(wire.tree, value), t = wire.tree; 23 return action.kind === 'core' ? wire.list([t.text('core'), t.text(coreNames[action.code])]) : 24 wire.list([t.text('facility'), t.text(action.group), t.natural(BigInt(action.revision)), t.text(action.operation), t.text(available(action.group, action.revision, action.operation) ? 'available' : 'unsupported')]); 25 } 26 // Authenticate framing before selecting an interpreter. No action is observed. 27 export function envelope(tree, value) { 28 const root = tree.observe(value).node; 29 if (root.kind !== 'fork') 30 throw new ProtocolError('invalid IO envelope'); 31 let rest = root.left; 32 for (const char of 'tricuIO') { 33 const node = tree.observe(rest).node; 34 if (node.kind !== 'fork' || canonicalNat(tree, node.left, 7) !== BigInt(char.charCodeAt(0))) 35 throw new ProtocolError('Missing tricuIO sentinel'); 36 rest = node.right; 37 } 38 if (tree.observe(rest).node.kind !== 'leaf') 39 throw new ProtocolError('Missing tricuIO sentinel'); 40 const body = tree.observe(root.right).node; 41 if (body.kind !== 'fork') 42 throw new ProtocolError('invalid IO envelope'); 43 const version = canonicalNat(tree, body.left, 2); 44 if (version !== 2n) 45 throw new ProtocolError('Unsupported tricuIO version'); 46 return { version: 2, action: body.right }; 47 }