graph LR
subgraph Cliente
DDPConnect["DDP.connect<br/>(namespace.js)"]
Conn["Connection<br/>livedata_connection.js"]
StreamH["ConnectionStreamHandlers<br/>connection_stream_handlers.js"]
MsgP["MessageProcessors<br/>message_processors.js"]
DocP["DocumentProcessors<br/>document_processors.js"]
Inv["MethodInvoker<br/>method_invoker.js"]
MongoMap["MongoIDMap<br/>mongo_id_map.js"]
HbC["Heartbeat<br/>ddp-common/heartbeat.js"]
end
subgraph Servidor
DDPServer["DDPServer<br/>livedata_server.js"]
Ses["Session<br/>livedata_server.js"]
Sub["Subscription<br/>livedata_server.js"]
CollView["SessionCollectionView<br/>session_collection_view.ts"]
DocView["SessionDocumentView<br/>session_document_view.ts"]
DummyView["DummyDocumentView<br/>dummy_document_view.ts"]
HbS["Heartbeat<br/>ddp-common/heartbeat.js"]
end
%% Construção / composição
DDPConnect --> Conn
Conn --> StreamH
Conn --> MsgP
Conn --> DocP
Conn --> HbC
Conn --> Inv
DocP --> MongoMap
DDPServer --> Ses
Ses --> HbS
Ses --> Sub
Sub --> CollView
CollView --> DocView
CollView --> DummyView
%% Comunicação
Conn <--> Ses
StreamH -- roteia msgs --> MsgP
MsgP -- dados --> DocP
MsgP -- lifecycle método --> Inv
-
DDP.connect Instantiates
Connectionand exposes it as Meteor.connection. All public methods (subscribe,call,apply,status, etc.) are proxyed there. -
Connection: Central state/manager of the DDP link on the client; manages session, heartbeat, method/sub queues, caches, reconnection, and delegates parsing/routing and data application. - Constructs
_streamwithClientStream(SockJS/WebSocket) and injectsmessage/reset/disconnectcallbacks.-
Maintains link state (session, heartbeat, method/sub queues, caches) and delegates message parsing/routing to
ConnectionStreamHandlersand DDP protocol logic toMessageProcessorsandDocumentProcessors. -
Creates auxiliary instances:
-
-
ClientStream class is the DDP transport client used in browsers. It extends
-
StreamClientCommon to reuse the callback, status, and reconnection logic infrastructure, and adds browser-specific environment details. In summary, it:
-
Initializes a connection to a Meteor server by converting the URL to SockJS(when available) or WebSocket and applies the appropriate transport whitelist to avoid issues in older browsers (e.g., iOS 4/5).
-
Maintains the connection state (
currentStatus, retryCount, lastError) and exposes events such asmessage, reset, and disconnectfor the rest of the stack to react. -
Implements the dual heartbeat flow: the legacy via SockJS (HEARTBEAT_TIMEOUT) and the modern via DDP. It schedules/cancels timers, detects timeouts, and calls _lostConnection to trigger the base class's retry policy.
-
Handles faults and cleanups (
_cleanup, clearConnectionAndHeartbeatTimers), including registeringwindow.onlinelisteners to attempt to reconnect when the network returns. It encapsulates helpers such as_changeUrl, send, and _connected, providing the transparent transport layer for the DDP protocol.
-
-
ConnectionStreamHandlers: receives the raw text from WebSocket/SockJS and parses it with
DDPCommon.parseDDP, updates the heartbeat withmessageReceived(), sets_versionupon receivingconnected, routes toMessageProcessors'slivedata_*and, ononReset, sends a newconnect, marksnoRetrymethods as failed, and resends subs/methods. -
MessageProcessors: Implements the protocol logic by message type
_livedata_connected/_data/_result/_nosub/_error; Manages quiescence (_messagesBufferedUntilQuiescence, _methodsBlockingQuiescence, _subsBeingRevived), reconciles sessions (reset stores, revive subs, half-finished methods), and controls write flushing withbufferedWritesInterval/MaxAge. It also dispatches received document messages (mongo) toDocumentProcessors. -
DocumentProcessors: Applies data messages to stores (Minimongo), reconciling stub effects with
_serverDocuments/MongoIDMap, generatingadded/changed/removed/replaceand releasingdataVisible. -
_stores:
createStoreMethods/registerStoreClient|Serversets up wrappersbeginUpdate/update/endUpdate/saveOriginals/retrieveOriginals/getDocand dumps pending updates. -
Heartbeat: - DDPCommon.Heartbeat: ping/pong timer; sends a ping if there was no traffic and triggers a timeout to reconnect/close. When connecting (
MessageProcessors._livedata_connected), it createsDDPCommon.Heartbeat(packages/ddp-common/heartbeat.js#L8) withsendPing->{msg:'ping'}andonTimeout->_lostConnection(...). -
MethodInvoker: represents a remote call; registers with
_methodInvokers, controls resending,noRetry, result callbacks, and only completes when the result + data are visible (dataVisible), releasing the method block in_outstandingMethodBlocks. -
MongoIDMap:
IdMapspecialized for Mongo/Minimongo IDs (stringify/parse), used to track server documents/stubs. -
DDP.onReconnect injects functions executed before resending pending methods (e.g., redo login/token).
-
DDPServer: instantiates a Session per client and dispatches messages (method, sub, unsub, pings)
-
Session: maintains the connection state (user, subs, message queue) and uses
SessionCollectionViewto maintain the "view" by collection for each client. -
SessionCollectionView composes several SessionDocumentView or DummyDocumentView (for strategies without merge) and generates diffs (
added/changed/removed) sent as DDP messages. -
Subscription — is the “server-side” of each Meteor.subscribe that arrives from the client.
-
Stores identity (id sent by the client or undefined for universal publishes) and an internal handle used for precedence in
SessionDocumentView. -
Maintains the publication state (name, parameters, documents that have already been sent, ready/deactivated flag).
-
Exposes the API that the publish code uses (
this.added/changed/removed/ready/error/stop, this.userId, this.connection, this.unblock) to send DDP messages and control the subnet lifecycle. -
Executes the handler within a publish context (
DDP._CurrentPublicationInvocation), catching errors, accepting Promises/thenables. -
When the handler returns cursors, observes them and converts diffs into DDP messages, calling ready() at the end of the initial load.
-
-
-
Maintains
documents: Map<id, DocumentView>and{added,changed,removed}callbacks of the session. -
Use
DiffSequence.diffMapsto issue adds/removes/changes between two views (used in_setUserId). -
added/changed/removedforwards changes toSessionDocumentView/DummyDocumentViewand triggers session callbacks.
-
-
-
Precedence structure by field (
dataByKey: Map<field, [subscriptionHandle, value][]>) andexistsIn(subs that see the doc). -
getFields()returns the dominant value (first in the list) by key;changeFieldandclearFieldcontrol precedence and collect changes to send.
-
-
DummyDocumentView: always returns an empty object and logs changes directly (strategies that do not maintain merge).
-
SERVER_MERGE: maintains mirroring by collection with full diffing. -
NO_MERGE_NO_HISTORY: sends everything without saving history (does not send removed). -
NO_MERGE: remembers IDs to sendremoved, but does not save fields. -
NO_MERGE_MULTI: remembers sharing between multiple publications with dummy view for light precedence.
-
Unnamed handlers (
Meteor.publish(null, ...)) are stored in server.universal_publish_handlers. -
Each Session.startUniversalSubs() creates an
Subscriptionwithout an id and places it in [universalSubs]packages/ddp-server/livedata_server.js#L100); reset whenuserIdchanges; they do not receive an explicitnosub.
- Client-side Invocation
-
Connection.call/apply/subscribe packages
msg({msg:'method'| 'sub', ...}), createsMethodInvokerif it's a method, and enqueues it in_outstandingMethodBlocks.applyrespectswaitto serialize blocks. -
_sendQueued/_send(same file) writes to the_stream; if the socket is not yet connected, messages remain in the internal queue of theClientStream.
- Server Reception
-
Socket delivers text →
StreamServer(not listed here) forwards toSession→_processMessagedispatches by type (method/sub/unsub/ping). -
method: creates contextDDP._CurrentMethodInvocation, runs handler, captures result or exception, sendsresultand thenupdatedwhen data is ready. -
sub: createsSubscription, runs handler (synchronous or thenable), sendsreadyat the end; data diffs are pushed viaadded/changed/removedoriginating fromSessionCollectionView. -
Publishing strategy defines whether the session maintains mirrored
collectionViewsand how to calculate diffs.
- Data transmission from server to client
SessionCollectionView/SessionDocumentView(or Dummy) produce mutations;Sessiondecides whether to send immediately or just register (when_isSendingis false in_setUserId).
DDP messages generated: added, changed, removed, ready, updated, nosub, ping/pong.
- Arrival at the client (stream layer)
-
Raw text → ConnectionStreamHandlers.onMessage:
parseDDP,heartbeat.messageReceived(), sets_versionifconnected, and routes. -
In
reset, mountconnectagain, marknoRetrymethods with errors, and resend subs/methods.
- Protocol Processing
-
MessageProcessors decides whether to buffer during quiescence: reviving subs (
_subsBeingRevived) orwait/active methods (_methodsBlockingQuiescence). When free, drains the data buffer and, if_resetStores, callsbeginUpdate/endUpdateon all stores to clear and reapply. -
result: ensures flush of writes before delivering callback; looks for the correspondingMethodInvokerin the first block; writes the result and attempts completion. -
updated: forwards toDocumentProcessorsto resolve stubs and then callsdataVisiblefrom eachMethodInvoker.
- Local Cached Application
-
DocumentProcessorsforadded/changed/removed: if_serverDocexists due to a stub, mutates the snapshot and/or throws a coherent error; otherwise,_pushUpdateaccumulates inupdatesby collection.ready/updateduses_runWhenAllServerDocsAreFlushedto ensure order. -
Store (Minimongo) consumes
updatesviabeginUpdate/update/endUpdate(calls triggered by_flushBufferedWrites).
- Method Finalization and Reactivity
-
When
MethodInvokerhas a result +dataVisible, it removes itself from_methodInvokersand frees_outstandingMethodFinished()to send the next block. -
Subs:
readymarkssubRecord.ready, triggersreadyCallbackandreadyDeps.changed()(Tracker reactivity).
- Heartbeats and Reconnection
-
Client:
Heartbeatsendspingif it hasn't seen traffic in the interval; timeout triggers_lostConnection→ automatic reconnection of theClientStream, resending of pending subs and methods (_callOnReconnectAndSendAppropriateOutstandingMethods). -
Server:
Heartbeatsendsping; timeout callsSession.close()and clears subs/collectionViews.
-
_streamHandlers: transport + initial routing. -
_messageProcessors: DDP protocol rules and local consistency. -
DocumentProcessors: applies data to local collections, reconciling stubs. -
_universalSubs: unnamed subs that run automatically throughout the session.
sequenceDiagram
participant DDPc as DDP.connect<br/>(namespace.js)
participant UI as UI/Tracker
participant Conn as Connection<br/>livedata_connection.js
participant Inv as MethodInvoker<br/>method_invoker.js
participant SH as StreamHandlers<br/>connection_stream_handlers.js
participant Net as WebSocket/SockJS
participant Ses as Session<br/>livedata_server.js
participant Sub as Subscription<br/>livedata_server.js
participant CV as SessionCollectionView<br/>session_collection_view.ts
participant DV as SessionDocumentView/Dummy<br/>session_document_view.ts
participant MP as MessageProcessors<br/>message_processors.js
participant DP as DocumentProcessors<br/>document_processors.js
participant Store as Store/Minimongo
DDPc->>Conn: cria Connection (ClientStream)
Conn->>SH: registra handlers message/reset/disconnect
Conn->>Net: msg connect (DDP)
Net-->>Ses: connect
Ses-->>Net: connected (sessionId) + heartbeat iniciado
Net-->>SH: connected
SH->>Conn: seta version/heartbeat
UI->>Conn: Meteor.call / subscribe
Conn->>Inv: cria invoker (methods) / registra sub
Conn->>SH: _sendQueued(msg)
SH->>Net: envia DDP (method/sub)
Net-->>Ses: texto DDP
Ses->>Sub: cria/reencontra Subscription
Sub->>CV: add/changed/removed
CV->>DV: aplica precedência por sub
Ses-->>Net: DDP added/changed/removed/ready/updated/result
Net-->>SH: entrega raw msg
SH->>Conn: parseDDP + heartbeat.messageReceived()
SH->>MP: route por tipo
MP->>DP: dados (added/changed/removed/ready/updated)
DP->>Store: beginUpdate/update/endUpdate
MP->>Inv: result / updated → dataVisible
Inv-->>UI: callback/Promise resolvida