1- import { BucketDescription , isValidPriority , RequestParameters , SqlSyncRules } from '@powersync/service-sync-rules' ;
1+ import {
2+ BucketDescription ,
3+ BucketPriority ,
4+ isValidPriority ,
5+ RequestedStream ,
6+ RequestParameters ,
7+ ResolvedBucket ,
8+ SqlSyncRules
9+ } from '@powersync/service-sync-rules' ;
210
311import * as storage from '../storage/storage-index.js' ;
412import * as util from '../util/util-index.js' ;
@@ -355,7 +363,9 @@ export class BucketParameterState {
355363 private readonly querier : BucketParameterQuerier ;
356364 private readonly staticBuckets : Map < string , BucketDescription > ;
357365 private readonly includeDefaultStreams : boolean ;
358- private readonly explicitlyOpenedStreams : Record < string , util . OpenedStream > ;
366+ // Indexed by the client-side id
367+ private readonly explicitStreamSubscriptions : Record < string , util . RequestedStreamSubscription > ;
368+ private readonly subscribedStreamNames : Set < string > ;
359369 private readonly logger : Logger ;
360370 private cachedDynamicBuckets : BucketDescription [ ] | null = null ;
361371 private cachedDynamicBucketSet : Set < string > | null = null ;
@@ -376,51 +386,73 @@ export class BucketParameterState {
376386 this . syncParams = syncParams ;
377387 this . logger = logger ;
378388
379- const explicitlyOpenedStreams : Record < string , util . OpenedStream > = { } ;
389+ const idToStreamSubscription : Record < string , util . RequestedStreamSubscription > = { } ;
390+ const streamsByName : Record < string , RequestedStream [ ] > = { } ;
380391 const subscriptions = request . subscriptions ;
381392 if ( subscriptions ) {
382393 for ( const subscription of subscriptions . opened ) {
383- explicitlyOpenedStreams [ subscription . stream ] = subscription ;
394+ idToStreamSubscription [ subscription . stream ] = subscription ;
395+
396+ const syncRuleStream : RequestedStream = {
397+ parameters : subscription . parameters ?? { } ,
398+ opaque_id : subscription . client_id
399+ } ;
400+ if ( Object . hasOwn ( streamsByName , subscription . stream ) ) {
401+ streamsByName [ subscription . stream ] . push ( syncRuleStream ) ;
402+ } else {
403+ streamsByName [ subscription . stream ] = [ syncRuleStream ] ;
404+ }
384405 }
385406 }
386407 this . includeDefaultStreams = subscriptions ?. include_defaults ?? true ;
387- this . explicitlyOpenedStreams = explicitlyOpenedStreams ;
408+ this . explicitStreamSubscriptions = idToStreamSubscription ;
388409
389410 this . querier = syncRules . getBucketParameterQuerier ( {
390411 globalParameters : this . syncParams ,
391412 hasDefaultStreams : this . includeDefaultStreams ,
392- resolveOpenedStream ( name ) {
393- const subscription = explicitlyOpenedStreams [ name ] ;
394- if ( subscription ) {
395- return subscription . parameters ?? { } ;
396- } else {
397- return null ;
398- }
399- }
413+ streams : streamsByName
400414 } ) ;
401415 this . staticBuckets = new Map < string , BucketDescription > ( this . querier . staticBuckets . map ( ( b ) => [ b . bucket , b ] ) ) ;
402416 this . lookups = new Set < string > ( this . querier . parameterQueryLookups . map ( ( l ) => JSONBig . stringify ( l . values ) ) ) ;
417+ this . subscribedStreamNames = new Set ( Object . keys ( streamsByName ) ) ;
403418 }
404419
405420 /**
406- * Overrides the `description` based on subscriptions from the client.
407- *
408- * In partiuclar, this can override the priority assigned to a bucket.
421+ * Translates an internal sync-rules {@link ResolvedBucket} instance to the public
422+ * {@link util.ClientBucketDescription}.
409423 */
410- overrideBucketDescription ( description : BucketDescription ) : BucketDescription {
411- const changedPriority = this . explicitlyOpenedStreams [ description . definition ] ?. override_priority ;
412- if ( changedPriority != null && isValidPriority ( changedPriority ) ) {
413- return {
414- ...description ,
415- priority : changedPriority
416- } ;
417- } else {
418- return description ;
424+ translateResolvedBucket ( description : ResolvedBucket ) : util . ClientBucketDescription {
425+ // Assign
426+ let priorityOverride : BucketPriority | null = null ;
427+ for ( const reason of description . inclusion_reasons ) {
428+ if ( reason != 'default' ) {
429+ const requestedPriority = this . explicitStreamSubscriptions [ reason . subscription ] ?. override_priority ;
430+ if ( requestedPriority != null ) {
431+ if ( priorityOverride == null ) {
432+ priorityOverride = requestedPriority as BucketPriority ;
433+ } else {
434+ priorityOverride = Math . min ( requestedPriority , priorityOverride ) as BucketPriority ;
435+ }
436+ }
437+ }
419438 }
439+
440+ return {
441+ definition : description . definition ,
442+ bucket : description . bucket ,
443+ priority : priorityOverride ?? description . priority ,
444+ subscriptions : description . inclusion_reasons . map ( ( reason ) => {
445+ if ( reason == 'default' ) {
446+ return { def : description . definition } ;
447+ } else {
448+ return { sub : reason . subscription } ;
449+ }
450+ } )
451+ } ;
420452 }
421453
422454 isSubscribedToStream ( desc : SqlBucketDescriptor ) : boolean {
423- return ( desc . subscribedToByDefault && this . includeDefaultStreams ) || desc . name in this . explicitlyOpenedStreams ;
455+ return ( desc . subscribedToByDefault && this . includeDefaultStreams ) || this . subscribedStreamNames . has ( desc . name ) ;
424456 }
425457
426458 async getCheckpointUpdate ( checkpoint : storage . StorageCheckpointUpdate ) : Promise < CheckpointUpdate > {
0 commit comments