@@ -20,16 +20,7 @@ import type { AggregateOptions } from './operations/aggregate';
2020import type { OperationParent } from './operations/command' ;
2121import type { ServerSessionId } from './sessions' ;
2222import { CSOTTimeoutContext , type TimeoutContext } from './timeout' ;
23- import { filterOptions , getTopology , type MongoDBNamespace , squashError } from './utils' ;
24-
25- const CHANGE_STREAM_OPTIONS = [
26- 'resumeAfter' ,
27- 'startAfter' ,
28- 'startAtOperationTime' ,
29- 'fullDocument' ,
30- 'fullDocumentBeforeChange' ,
31- 'showExpandedEvents'
32- ] as const ;
23+ import { type AnyOptions , getTopology , type MongoDBNamespace , squashError } from './utils' ;
3324
3425const CHANGE_DOMAIN_TYPES = {
3526 COLLECTION : Symbol ( 'Collection' ) ,
@@ -43,6 +34,14 @@ const NO_RESUME_TOKEN_ERROR =
4334 'A change stream document has been received that lacks a resume token (_id).' ;
4435const CHANGESTREAM_CLOSED_ERROR = 'ChangeStream is closed' ;
4536
37+ const INVALID_STAGE_OPTIONS = buildDisallowedChangeStreamOptions ( ) ;
38+
39+ export function filterOutOptions ( options : AnyOptions ) : AnyOptions {
40+ return Object . fromEntries (
41+ Object . entries ( options ) . filter ( ( [ k , _ ] ) => ! INVALID_STAGE_OPTIONS . has ( k ) )
42+ ) ;
43+ }
44+
4645/**
4746 * Represents the logical starting point for a new ChangeStream or resuming a ChangeStream on the server.
4847 * @see https://www.mongodb.com/docs/manual/changeStreams/#std-label-change-stream-resume
@@ -898,7 +897,7 @@ export class ChangeStream<
898897 private _createChangeStreamCursor (
899898 options : ChangeStreamOptions | ChangeStreamCursorOptions
900899 ) : ChangeStreamCursor < TSchema , TChange > {
901- const changeStreamStageOptions = filterOptions ( options , CHANGE_STREAM_OPTIONS ) ;
900+ const changeStreamStageOptions : Document = filterOutOptions ( options ) ;
902901 if ( this . type === CHANGE_DOMAIN_TYPES . CLUSTER ) {
903902 changeStreamStageOptions . allChangesForCluster = true ;
904903 }
@@ -1084,3 +1083,76 @@ export class ChangeStream<
10841083 }
10851084 }
10861085}
1086+
1087+ /**
1088+ * This function returns a list of options that are *not* supported by the $changeStream
1089+ * aggregation stage. This is best-effort - it uses the options "officially supported" by the driver
1090+ * to derive a list of known, unsupported options for the $changeStream stage.
1091+ *
1092+ * Notably, at runtime, users can still provide options unknown to the driver and the driver will
1093+ * *not* filter them out of the options object (see NODE-5510).
1094+ */
1095+ function buildDisallowedChangeStreamOptions ( ) : Set < string > {
1096+ /** hard-coded list of allowed ChangeStream options */
1097+ type CSOptions =
1098+ | 'resumeAfter'
1099+ | 'startAfter'
1100+ | 'startAtOperationTime'
1101+ | 'fullDocument'
1102+ | 'fullDocumentBeforeChange'
1103+ | 'showExpandedEvents' ;
1104+
1105+ /**
1106+ * a type representing all known options that the driver supports that are *not* change stream stage options.
1107+ *
1108+ * each known key is mapped to a non-optional string, so that if new driver-specific options are added, the
1109+ * instantiation of `denyList` below results in a TS error.
1110+ */
1111+ type DisallowedOptions = {
1112+ [ k in Exclude <
1113+ keyof ChangeStreamOptions & { timeoutContext : TimeoutContext } ,
1114+ CSOptions
1115+ > ] : string ;
1116+ } ;
1117+
1118+ const denyList : DisallowedOptions = {
1119+ allowDiskUse : '' ,
1120+ authdb : '' ,
1121+ batchSize : '' ,
1122+ bsonRegExp : '' ,
1123+ bypassDocumentValidation : '' ,
1124+ bypassPinningCheck : '' ,
1125+ checkKeys : '' ,
1126+ collation : '' ,
1127+ comment : '' ,
1128+ cursor : '' ,
1129+ dbName : '' ,
1130+ enableUtf8Validation : '' ,
1131+ explain : '' ,
1132+ fieldsAsRaw : '' ,
1133+ hint : '' ,
1134+ ignoreUndefined : '' ,
1135+ let : '' ,
1136+ maxAwaitTimeMS : '' ,
1137+ maxTimeMS : '' ,
1138+ omitMaxTimeMS : '' ,
1139+ out : '' ,
1140+ promoteBuffers : '' ,
1141+ promoteLongs : '' ,
1142+ promoteValues : '' ,
1143+ raw : '' ,
1144+ rawData : '' ,
1145+ readConcern : '' ,
1146+ readPreference : '' ,
1147+ serializeFunctions : '' ,
1148+ session : '' ,
1149+ timeoutContext : '' ,
1150+ timeoutMS : '' ,
1151+ timeoutMode : '' ,
1152+ useBigInt64 : '' ,
1153+ willRetryWrite : '' ,
1154+ writeConcern : ''
1155+ } ;
1156+
1157+ return new Set ( Object . keys ( denyList ) ) ;
1158+ }
0 commit comments