File size: 2,018 Bytes
d04f74a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/** Event-local acceptance for raw Session journal responses; payloads remain owner-defined JSON. */

import { validateSessionEventData, validateSurfaceMetadata } from '@deepseek-ai/dsh-session/surface'
import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
import type { SessionWireEvent } from '../types.ts'

/**
 * Reject non-current event envelopes without stripping or normalizing wire fields.
 * Range membership and source existence require the durable log and remain Host-owned.
 * @param value - one event received in a follow frame or history page.
 * @returns nothing after narrowing the accepted event envelope.
 * @throws when the envelope or current event-local metadata is invalid.
 */
export function assertSessionWireEvent(value: unknown): asserts value is SessionWireEvent {
  const subject = 'session wire event'
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
    throw new Error(`${subject} must be an object`)
  }
  const event = value as Record<string, unknown>
  for (const key of Object.keys(event)) {
    switch (key) {
      case 'type':
      case 'seq':
      case 'time':
      case 'data':
      case 'ignorable':
      case 'surfaceOp':
      case 'sourceEventSeqs':
        break
      default:
        throw new Error(`${subject} has unexpected field ${key}`)
    }
  }
  const seq = event['seq']
  if (typeof event['type'] !== 'string'
    || typeof seq !== 'number' || !Number.isSafeInteger(seq) || seq < 0 || Object.is(seq, -0)
    || typeof event['time'] !== 'number' || !Number.isSafeInteger(event['time'])
    || !Object.hasOwn(event, 'data') || event['data'] === undefined
    || (Object.hasOwn(event, 'ignorable') && event['ignorable'] !== true)) {
    throw new Error(`${subject} has an invalid envelope`)
  }
  // Event names and payloads are merge-extensible; only event-local owner rules run here.
  const current = event as unknown as SessionEvent
  validateSurfaceMetadata(current)
  validateSessionEventData(current, subject)
}