diff --git a/docs/subsystems/session.md b/docs/subsystems/session.md index eb418f3819..c1651bf32e 100644 --- a/docs/subsystems/session.md +++ b/docs/subsystems/session.md @@ -584,8 +584,8 @@ declare class Session { isOwnSeq(seq: SessionSeq): boolean; /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ get seq(): SessionLogOffset; - /** Current member and final sequence while synchronously notifying a batch's observers. */ - get currentBatchPublication(): { readonly event: SessionEvent; readonly endSeq: SessionSeq } | undefined; + /** Current event while synchronously notifying a batch's observers. */ + get currentBatchPublication(): SessionEvent | undefined; /** * Append consecutive events together after validating every candidate and dispatch. * Observers read the complete committed log and final message surface. diff --git a/docs/subsystems/session.zh.md b/docs/subsystems/session.zh.md index 5958cc26e1..e359382e86 100644 --- a/docs/subsystems/session.zh.md +++ b/docs/subsystems/session.zh.md @@ -586,8 +586,8 @@ declare class Session { isOwnSeq(seq: SessionSeq): boolean; /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ get seq(): SessionLogOffset; - /** Current member and final sequence while synchronously notifying a batch's observers. */ - get currentBatchPublication(): { readonly event: SessionEvent; readonly endSeq: SessionSeq } | undefined; + /** Current event while synchronously notifying a batch's observers. */ + get currentBatchPublication(): SessionEvent | undefined; /** * Append consecutive events together after validating every candidate and dispatch. * Observers read the complete committed log and final message surface. diff --git a/packages/core/session/src/index.ts b/packages/core/session/src/index.ts index 3d1a5ecc00..ea6c337f55 100644 --- a/packages/core/session/src/index.ts +++ b/packages/core/session/src/index.ts @@ -554,7 +554,7 @@ function createAppendEvent(snapshot: ReturnType, seq: Ses */ export class Session { private log: SessionEvent[] = [] - private batchPublication: { readonly event: SessionEvent; readonly endSeq: SessionSeq } | undefined + private batchPublication: SessionEvent | undefined /** Single incremental owner of surface acceptance and projection state. */ private readonly surfaceManager: SurfaceManager @@ -792,8 +792,8 @@ export class Session { return SessionLogOffset(this.log.length) } - /** Current member and final sequence while synchronously notifying a batch's observers. */ - get currentBatchPublication(): { readonly event: SessionEvent; readonly endSeq: SessionSeq } | undefined { + /** Current event while synchronously notifying a batch's observers. */ + get currentBatchPublication(): SessionEvent | undefined { return this.batchPublication } @@ -901,9 +901,8 @@ export class Session { this.eventsSnapshot = undefined acceptSurface() if (entry !== undefined) { - const endSeq = SessionSeq(this.log.length - 1) for (const { event, args, callbacks } of publications) { - this.batchPublication = { event, endSeq } + this.batchPublication = event invokeContainedSessionObservers(entry.emitCtx, 'session/event', entry.id, args, callbacks) } } diff --git a/packages/core/session/src/surface.ts b/packages/core/session/src/surface.ts index 7307cc7672..7a13bc1d7c 100644 --- a/packages/core/session/src/surface.ts +++ b/packages/core/session/src/surface.ts @@ -660,11 +660,10 @@ export class SurfaceManager implements SessionSurface { this._assertProjections() if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta() const lastProcessedSeq = SessionSeq(this.baseSeq + this.log.length + events.length - 1) - if (events.every(event => event.type !== 'developer/message' - && (event.surfaceOp === undefined || event.surfaceOp === 'append') + if (events.every(event => (event.surfaceOp === undefined || event.surfaceOp === 'append') && !this.projections.some(projection => projection.type === event.type))) { const plans = events.map((event, index) => planSurfaceEvent( - this._state, event, SessionSeq(this.baseSeq + this.log.length + index), this.log, this.baseSeq, this.projections, + this._state, event, SessionSeq(this.baseSeq + this.log.length + index), this.log, this.baseSeq, this.projections, events, )) return () => { for (const plan of plans) applySurfacePlan(this._state, plan) diff --git a/packages/core/session/tests/append.spec.ts b/packages/core/session/tests/append.spec.ts index fd637e1ed2..ecc5a514c4 100644 --- a/packages/core/session/tests/append.spec.ts +++ b/packages/core/session/tests/append.spec.ts @@ -54,7 +54,7 @@ describe('multiple Session appends', () => { const observed: number[] = [] ctx.on('session/event', (current, event) => { if (current !== session) return - expect(current.currentBatchPublication).toEqual({ event, endSeq: 1 }) + expect(current.currentBatchPublication).toBe(event) expect(current.seq).toBe(2) expect(current.surface.nodes).toEqual([1]) expect(current.deriveMessages()).toEqual([messageValue]) diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts index 28ab2b4f40..d5b6ba6109 100644 --- a/packages/extensions/tool-cordis/src/api-catalog.ts +++ b/packages/extensions/tool-cordis/src/api-catalog.ts @@ -8539,7 +8539,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'Session', - declaration: 'export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n readonly inheritedEventCount: SessionLogOffset;\n get id(): SessionId;\n readonly firstLiveSeq: SessionLogOffset;\n readonly firstLifecycleSeq: SessionLogOffset;\n static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader, inheritedEventCount?: SessionLogOffset, projections?: readonly SessionMessageProjection[]): Session;\n static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader, inheritedEventCount: SessionLogOffset, eventState: SessionSeedEventState, projections?: readonly SessionMessageProjection[]): Session;\n eventAt(seq: SessionSeq): SessionEvent | undefined;\n snapshotEvents(fromSeq: SessionLogOffset = SessionLogOffset(0), toSeqExclusive: SessionLogOffset = this.seq): readonly SessionEvent[];\n ownEvents(): readonly SessionEvent[];\n isOwnSeq(seq: SessionSeq): boolean;\n get seq(): SessionLogOffset;\n get currentBatchPublication(): {\n readonly event: SessionEvent;\n readonly endSeq: SessionSeq;\n } | undefined;\n append(inputs: readonly SessionEventInput[]): readonly SessionEvent[];\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [\n opts: SurfaceIntent\n ] : [\n ]): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n toolHistory(): ToolHi /* …truncated — full shape in source */', + declaration: 'export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n readonly inheritedEventCount: SessionLogOffset;\n get id(): SessionId;\n readonly firstLiveSeq: SessionLogOffset;\n readonly firstLifecycleSeq: SessionLogOffset;\n static create(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader, inheritedEventCount?: SessionLogOffset, projections?: readonly SessionMessageProjection[]): Session;\n static fromRestore(id: SessionId, seed: readonly SessionEvent[], header: SessionHeader, inheritedEventCount: SessionLogOffset, eventState: SessionSeedEventState, projections?: readonly SessionMessageProjection[]): Session;\n eventAt(seq: SessionSeq): SessionEvent | undefined;\n snapshotEvents(fromSeq: SessionLogOffset = SessionLogOffset(0), toSeqExclusive: SessionLogOffset = this.seq): readonly SessionEvent[];\n ownEvents(): readonly SessionEvent[];\n isOwnSeq(seq: SessionSeq): boolean;\n get seq(): SessionLogOffset;\n get currentBatchPublication(): SessionEvent | undefined;\n append(inputs: readonly SessionEventInput[]): readonly SessionEvent[];\n append(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [\n opts: SurfaceIntent\n ] : [\n ]): SessionEvent;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n toolHistory(): ToolHistory;\n deriveMessages(): Message[];\n deriveEventMessage(event: /* …truncated — full shape in source */', }, { name: 'SessionAccess',