@@ -27,6 +27,7 @@ import {
2727 type JsonObject ,
2828 type JwtClaims ,
2929 type ReducerCtx ,
30+ type ReducerCtx as IReducerCtx ,
3031} from '../lib/reducers' ;
3132import {
3233 MODULE_DEF ,
@@ -185,45 +186,66 @@ class AuthCtxImpl implements AuthCtx {
185186 }
186187}
187188
188- export const makeReducerCtx = (
189- sender : Identity ,
190- timestamp : Timestamp ,
191- connectionId : ConnectionId | null
192- ) : ReducerCtx < UntypedSchemaDef > => {
193- return {
194- sender,
195- get identity ( ) {
196- return new Identity ( sys . identity ( ) . __identity__ ) ;
197- } ,
198- timestamp,
199- connectionId,
200- db : getDbView ( ) ,
201- senderAuth : AuthCtxImpl . fromSystemTables ( connectionId , sender ) ,
202- counter_uuid : { value : Number ( 0 ) } ,
203-
204- /**
205- * Create a new random {@link Uuid} `v4` using the {@link crypto} RNG.
206- *
207- * WARN: Until we use a spacetime RNG this make calls non-deterministic.
208- */
209- newUuidV4 ( ) : Uuid {
210- // TODO: Use a spacetime RNG when available
211- const bytes = crypto . getRandomValues ( new Uint8Array ( 16 ) ) ;
212- return Uuid . fromRandomBytesV4 ( bytes ) ;
213- } ,
189+ // Using a class expression rather than declaration keeps the class out of the
190+ // type namespace, so that `ReducerCtx` still refers to the interface.
191+ export const ReducerCtxImpl = class ReducerCtx <
192+ SchemaDef extends UntypedSchemaDef ,
193+ > implements IReducerCtx < SchemaDef >
194+ {
195+ #identity: Identity | undefined ;
196+ #senderAuth: AuthCtx | undefined ;
197+ #uuidCounter: { value : number } | undefined ;
198+ sender : Identity ;
199+ timestamp : Timestamp ;
200+ connectionId : ConnectionId | null ;
201+ db : DbView < SchemaDef > ;
214202
215- /**
216- * Create a new sortable {@link Uuid} `v7` using the {@link crypto} RNG, counter,
217- * and the timestamp.
218- *
219- * WARN: Until we use a spacetime RNG this make calls non-deterministic.
220- */
221- newUuidV7 ( ) : Uuid {
222- // TODO: Use a spacetime RNG when available
223- const bytes = crypto . getRandomValues ( new Uint8Array ( 4 ) ) ;
224- return Uuid . fromCounterV7 ( this . counter_uuid , this . timestamp , bytes ) ;
225- } ,
226- } ;
203+ constructor (
204+ sender : Identity ,
205+ timestamp : Timestamp ,
206+ connectionId : ConnectionId | null
207+ ) {
208+ Object . seal ( this ) ;
209+ this . sender = sender ;
210+ this . timestamp = timestamp ;
211+ this . connectionId = connectionId ;
212+ this . db = getDbView ( ) ;
213+ }
214+
215+ get identity ( ) {
216+ return ( this . #identity ??= new Identity ( sys . identity ( ) . __identity__ ) ) ;
217+ }
218+
219+ get senderAuth ( ) {
220+ return ( this . #senderAuth ??= AuthCtxImpl . fromSystemTables (
221+ this . connectionId ,
222+ this . sender
223+ ) ) ;
224+ }
225+
226+ /**
227+ * Create a new random {@link Uuid} `v4` using the {@link crypto} RNG.
228+ *
229+ * WARN: Until we use a spacetime RNG this make calls non-deterministic.
230+ */
231+ newUuidV4 ( ) : Uuid {
232+ // TODO: Use a spacetime RNG when available
233+ const bytes = crypto . getRandomValues ( new Uint8Array ( 16 ) ) ;
234+ return Uuid . fromRandomBytesV4 ( bytes ) ;
235+ }
236+
237+ /**
238+ * Create a new sortable {@link Uuid} `v7` using the {@link crypto} RNG, counter,
239+ * and the timestamp.
240+ *
241+ * WARN: Until we use a spacetime RNG this make calls non-deterministic.
242+ */
243+ newUuidV7 ( ) : Uuid {
244+ // TODO: Use a spacetime RNG when available
245+ const bytes = crypto . getRandomValues ( new Uint8Array ( 4 ) ) ;
246+ const counter = ( this . #uuidCounter ??= { value : 0 } ) ;
247+ return Uuid . fromCounterV7 ( counter , this . timestamp , bytes ) ;
248+ }
227249} ;
228250
229251/**
@@ -257,12 +279,10 @@ export const hooks: ModuleHooks = {
257279 MODULE_DEF . typespace
258280 ) ;
259281 const senderIdentity = new Identity ( sender ) ;
260- const ctx : ReducerCtx < any > = freeze (
261- makeReducerCtx (
262- senderIdentity ,
263- new Timestamp ( timestamp ) ,
264- ConnectionId . nullIfZero ( new ConnectionId ( connId ) )
265- )
282+ const ctx : ReducerCtx < any > = new ReducerCtxImpl (
283+ senderIdentity ,
284+ new Timestamp ( timestamp ) ,
285+ ConnectionId . nullIfZero ( new ConnectionId ( connId ) )
266286 ) ;
267287 try {
268288 return callUserFunction ( REDUCERS [ reducerId ] , ctx , args ) ?? { tag : 'ok' } ;
0 commit comments