docs: add changelog, e2e-coverage, and version-bump skill documentation and update development workflows

This commit is contained in:
italo jose
2026-04-03 14:01:17 -03:00
parent 109f63d7f3
commit 6d27823279
9 changed files with 192 additions and 64 deletions

View File

@@ -51,7 +51,17 @@ if the error persists, please try to install Meteor using `npm`:
npm install -g meteor --foreground-script
```
Make sure you have Node.js v20 or higher installed.
Make sure you have Node.js v24 or higher installed.
#### Node.js Version Compatibility
Different Meteor versions bundle and require different minimum Node.js active LTS releases:
| Meteor Version | Bundled Node.js Version |
| -------------- | ----------------------- |
| Meteor 3.3 | Node.js 20 |
| Meteor 3.4 | Node.js 22 |
| Meteor 3.5 | Node.js 24 |
:::

View File

@@ -84,14 +84,9 @@ We plan to document the changes in the Meteor documentation, including:
### Phase 1: Opined implementation
**Target Release:** 3.5
**Target Release:** 3.5
**Goal:** Implement a first version for MongoDB Change Streams in Meteor, allowing developers to opt-in to using change streams for real-time updates with a simple configuration option. This version should be transparent to existing applications, allowing them to continue using the current reactivity system while providing an easy path to switch to change streams via settings.json file or environment variable.
### Phase 2: Configurable implementation + feedbacks
**Target Release:** 3.5.x ⏳
**Goal:** Make MongoDB Change Streams more configurable to bring better performance in specific scenarios for real-time updates in Meteor, while gathering feedback from the community to refine and improve the implementation based on real-world usage.
Update for 3.5: MongoDB Change Streams have proven robust and are now the default reactivity engine in Meteor 3.5, replacing Oplog tailing as the default.
## Next priorities

View File

@@ -27,24 +27,47 @@ buckets are reset. Buckets are regularly reset after the end of a time
interval.
Here's example of defining a rule and adding it into the `DDPRateLimiter`:
Here's an example of defining a rule and adding it into the `DDPRateLimiter`:
```js
// Define a rule that matches login attempts by non-admin users.
const loginRule = {
userId(userId) {
const user = Meteor.users.findOne(userId);
return user && user.type !== 'admin';
// Synchronous matcher
clientAddress(clientAddress) {
return clientAddress !== '127.0.0.1';
},
type: 'method',
name: 'login'
};
// Add the rule, allowing up to 5 messages every 1000 milliseconds.
DDPRateLimiter.addRule(loginRule, 5, 1000);
```
### Async Matchers
Starting in Meteor 3.5, `DDPRateLimiter` fully supports asynchronous matchers. Your matchers (`userId`, `clientAddress`, `type`, `name`, `connectionId`) can be `async` functions that return a `Promise<boolean>`.
This is incredibly useful for querying the database to perform complex access control logic:
```js
// Define an async rule matching users who have exhausted their tier limits
const premiumTierRule = {
// Asynchronous matcher evaluating access limits via DB lookup
async userId(userId) {
if (!userId) return true; // Rate limit unauthenticated paths if shared
const user = await Meteor.users.findOneAsync(userId);
return user && user.subscriptionTier !== 'premium';
},
type: 'method',
name: 'Users.expensiveOperation'
};
// Add the rule, allowing up to 2 calls every 60000 milliseconds for non-premium
DDPRateLimiter.addRule(premiumTierRule, 2, 60000);
```
> **Performance Note**: While async matchers unlock powerful database checks, keep in mind they are awaited sequentially on the incoming message queue for that connection. Extremely slow database queries in rate limiters can delay message processing. If a matcher `Promise` rejects, the rate limit check will safely fail the invocation as it errors out.
<ApiBox name="DDPRateLimiter.removeRule" />
<ApiBox name="DDPRateLimiter.setErrorMessage" />
<ApiBox name="DDPRateLimiter.setErrorMessageOnRule" />

View File

@@ -917,7 +917,7 @@ To add password support to your application, run this command in your terminal:
meteor add accounts-password
```
> In addition to configuring the [`email`](./email.md) package's `MAIL_URL`, it is critical that you set proper values (specifically the `from` address) in [`Accounts.emailTemplates`](#Accounts-emailTemplates) to ensure proper delivery of e-mails!
> In addition to configuring the [`email`](./email.md) package's `MAIL_URL`, it is critical that you set proper values (specifically the `from` address) in [`Accounts.emailTemplates`](#Accounts-emailTemplates) to ensure proper delivery of e-mails! Starting in Meteor 3.5, leaving the `from` address unconfigured will generate a server console warning to alert you of potential silent email delivery failures.
You can construct your own user interface using the
functions below, or use the [`accounts-ui` package](../packages/accounts-ui.md) to
@@ -1204,7 +1204,7 @@ Set the fields of the object by assigning to them:
- `from`: (**required**) A `String` with an [RFC5322](http://tools.ietf.org/html/rfc5322) From
address. By default, the email is sent from `no-reply@example.com`. **If you
want e-mails to send correctly, this should be changed to your own domain
as most e-mail providers will reject mail sent from `example.com`.**
as most e-mail providers will reject mail sent from `example.com`.** Starting in Meteor 3.5, failing to configure a valid custom `from` address will result in a prominent server console warning to help prevent silent email failures in production.
- `siteName`: The public name of your application. Defaults to the DNS name of
the application (eg: `awesome.meteor.com`).
- `headers`: An `Object` for custom email headers as described in

View File

@@ -995,9 +995,19 @@ contains the following fields:
## Reconnection
Meteor 3.5+ supports [DDP session resumption](https://github.com/meteor/meteor/pull/14051), allowing clients to automatically resume their previous connection after a temporary network disconnect. When a client reconnects within the grace period, the `onConnection` callback is not called again and the connection retains its original `id`.
Meteor 3.5+ supports [DDP session resumption](https://github.com/meteor/meteor/pull/14051), allowing clients to automatically resume their previous connection after a temporary network disconnect. When a client reconnects within the grace period, the `onConnection` callback is not called again on the server and the connection retains its original `id`.
This behavior is controlled by the following server options:
This behavior is controlled by the following server options, which you can set globally:
```js
import { Meteor } from "meteor/meteor";
// Maintain inactive sessions for 30 seconds
Meteor.server.options.disconnectGracePeriod = 30000;
// Queue up to 500 messages per disconnected session
Meteor.server.options.maxMessageQueueLength = 500;
```
### Meteor.server.options.disconnectGracePeriod
@@ -1007,6 +1017,18 @@ Defines how long (in milliseconds) we should maintain a session for after a non-
Determines how many messages we should queue during a non-graceful disconnect before we destroy the session, to help prevent memory leaks. Defaults to `100`.
### Resume Behavior and Edge Cases
When a session correctly resumes, clients pick up exactly where they left off:
- **Subscriptions:** Active subscriptions automatically resume without needing to be re-published and clients do not re-send subscription requests.
- **Method Calls:** Any in-flight method calls that were unacknowledged during the disconnection will be replayed.
- **Queue Overflow:** If the number of messages emitted while a client is disconnected exceeds `maxMessageQueueLength`, the session is discarded. When the client reconnects, it initiates a fresh session.
- **Hot Code Push:** HCP is treated as a manual, graceful disconnect. Session resumption is gracefully skipped so clients receive entirely fresh state for the new code.
- **Load Balancers:** Server stickiness is still important. A client must reconnect to the *same* physical Meteor instance holding its session state within the grace period to resume successfully.
- **Legacy Migrations:** If your application relied heavily on `onConnection` triggering *every single time* a client socket reconnected after brief hiccups (to handle manual presence tracking or metrics), be aware that `onConnection` is **no longer invoked** during a grace-period resumption.
To explicitly execute logic when a client reconnects (whether it resulted in a successfully resumed session or a completely fresh one), use [`DDP.onReconnect`](#DDP-onReconnect) on the client.
<ApiBox name="DDP.connect" hasCustomExample/>
```js
@@ -1058,7 +1080,23 @@ When you call `Meteor.subscribe`, `Meteor.status`, `Meteor.call`, and
`Meteor.apply`, you are using a connection back to that default
server.
<ApiBox name="DDP.onReconnect" />
<ApiBox name="DDP.onReconnect" hasCustomExample/>
```js
import { DDP } from "meteor/ddp-client";
DDP.onReconnect((connection) => {
console.log("Client reconnected!");
// Check if session was successfully resumed (Meteor 3.5+)
if (connection.sessionResumed) {
console.log("Session state preserved, no need to re-fetch custom data.");
} else {
console.log("A brand new session was established.");
}
});
```
Registers a callback hook that is invoked on the client whenever the DDP connection successfully re-establishes connectivity with the server. Starting in Meteor 3.5, the callback receives the connection instance which includes a `sessionResumed` boolean. You can use this flag to determine if the client recovered its previous session via the graceful disconnect period, or if the session expired forcing it to restart cleanly.
## Timers { #timers }

View File

@@ -39,14 +39,47 @@ DDP_TRANSPORT=uws meteor run
DDP_TRANSPORT=sockjs meteor run
```
You can also configure the transport via your `settings.json` file:
```json
{
"packages": {
"ddp-server": {
"transport": "uws"
}
}
}
```
When using `uws`, the client automatically uses native WebSocket instead of the SockJS client protocol.
::: warning
The `uws` transport uses raw WebSocket without HTTP polling fallback. Clients behind proxies that block WebSocket connections will not be able to connect. Make sure your deployment environment supports WebSocket before switching.
If you are using a load balancer (such as NGINX, HAProxy, or AWS ALB), ensure it is configured to upgrade HTTP connections to WebSocket and that stickiness (session affinity) is not required since `uws` does not use polling.
:::
See also: [`DISABLE_SOCKJS`](#disable-sockjs).
## METEOR_REACTIVITY_ORDER
(_development, production_)
Meteor configures data reactivity mechanism priorities using this variable. The default for Meteor 3.5 is `changeStreams,oplog,polling`. To override the order, set a comma-separated list.
```bash
# Prioritize oplog over change streams
METEOR_REACTIVITY_ORDER="oplog,changeStreams,polling" meteor run
```
This can also be configured via your `settings.json` file:
```json
{
"packages": {
"mongo": {
"reactivity": ["changeStreams", "oplog", "polling"]
}
}
}
```
## DISABLE_WEBSOCKETS
(_development, production_)
@@ -55,10 +88,10 @@ In the event that your own deployment platform does not support WebSockets, or y
## DISABLE_SOCKJS
(_development, production_)
Set `DISABLE_SOCKJS=1` to use raw WebSocket instead of SockJS. This is equivalent to `DDP_TRANSPORT=uws` and is kept for backward compatibility.
Set `DISABLE_SOCKJS=1` to use raw WebSocket instead of SockJS. This is equivalent to `DDP_TRANSPORT=uws` and is kept for backward compatibility.
::: tip
Prefer using [`DDP_TRANSPORT=uws`](#ddp-transport) instead of `DISABLE_SOCKJS=1`. The `DDP_TRANSPORT` variable is more explicit and supports additional transports in the future.
*Migration Note:* `DISABLE_SOCKJS=1` is deprecated. Prefer using [`DDP_TRANSPORT=uws`](#ddp-transport) or configuring `"transport": "uws"` in your `settings.json` file. `DDP_TRANSPORT` is more explicit and establishes a foundation for future transport backend additions.
:::
## DO_NOT_TRACK

View File

@@ -34,7 +34,6 @@ meteor add jam:pub-sub
## How to use it?
## Change Streams-based publish / subscribe
**`Alpha`**
With `jam:pub-sub` and MongoDB Change Streams, you can preserve Meteor's magical reactivity for all clients while opting out of the traditional `publish / subscribe` and its use of the `oplog`. Use `Meteor.publish.stream` instead of using `Meteor.publish` and subscribe using the same `Meteor.subscribe` on the client.
@@ -74,7 +73,7 @@ The downside by splitting into two is it could result in over-fetching but the d
**Note**: If you decide to entirely opt-out of using the traditional `Meteor.publish`, then you'll also want to disable the `oplog` entirely &mdash; add the `disable-oplog` package with `meteor add disable-oplog`.
At the moment, this feature is considered in an `alpha` state. Based on previous [Change Streams experiments](https://github.com/meteor/meteor/discussions/11842#discussioncomment-4061112) by the Meteor Community, it seems that using Change Streams as a wholesale replacement for the traditional `publish / subscribe` could "just work". However, in practice it may be a "Your Mileage May Vary" type of situation depending on the frequency of writes, number of connected clients, how you model your data, and how you set up the cursors inside of `Meteor.publish.stream`. With that said, if you're interested in this feature, I'd encourage you to try it out and share your findings.
At the moment, this feature is built directly on MongoDB Change Streams. Starting in Meteor 3.5, Change Streams became the default reactivity mechanism for Meteor, validating the performance and reliability improvements over the traditional `oplog`. Utilizing it through `jam:pub-sub` is stable and ready for general use.
## Subscription caching
Normally, when a user moves between routes or components, the subscriptions will be stopped. When a user is navigating back and forth in your app, each time will result in a re-subscribe which means more spinners, a slower experience, and is generally a waste.

View File

@@ -1,19 +1,51 @@
## v3.5.0, 10-03-2026
## v3.5.0, 2026-04-03
### Highlights
- **Change streams**, [PR#13910](https://github.com/meteor/meteor/pull/13787)
- ⚡ New `change streams` observe driver
- 📃 [Documentation](https://github.com/meteor/meteor/blob/release-3.5/v3-docs/docs/performance/change-streams-observer-driver.md)
#### Features
- **MongoDB Change Streams**, [PR#13787](https://github.com/meteor/meteor/pull/13787)
- ⚡ New `change streams` observe driver for real-time reactivity using MongoDB native change streams
- 📃 [Documentation](https://docs.meteor.com/performance/change-streams-observer-driver)
- **DDP Session Resumption**, [PR#14051](https://github.com/meteor/meteor/pull/14051)
- 🔄 Automatic session resumption after temporary network disconnects without re-triggering `onConnection` callbacks
- ⏱️ Configurable grace period via `Meteor.server.options.disconnectGracePeriod` (default: 15s)
- 📨 Message queue limit via `Meteor.server.options.maxMessageQueueLength` (default: 100)
- **Pluggable DDP Transport Architecture**, [PR#14231](https://github.com/meteor/meteor/pull/14231)
- 🔌 Swap WebSocket transports without touching the DDP stack — choose between `sockjs` (default), `uws` (µWebSockets.js)
- ⚙️ Configure via `DDP_TRANSPORT=uws` environment variable or `settings.json`
- **Async DDPRateLimiter Rule Matchers**, [PR#14182](https://github.com/meteor/meteor/pull/14182)
- 🔀 Rule matcher functions can now be `async`, enabling DB lookups and other async operations inside rate-limit rules
- **Fully Functional DISABLE_SOCKJS Mode**, [PR#14206](https://github.com/meteor/meteor/pull/14206)
- Make `DISABLE_SOCKJS=1` work end-to-end on both client and server
#### Improvements
- **Upgrade to Node.js 24.14.0 & NPM 11.10.1**, [PR#14176](https://github.com/meteor/meteor/pull/14176)
- **EJSON Performance Optimizations**:
- Zero-clone `stringifyDDP` to reduce allocations in DDP message serialization, [PR#14213](https://github.com/meteor/meteor/pull/14213)
- Copy-on-write `toJSONValue`/`fromJSONValue` to reduce allocations, [PR#14209](https://github.com/meteor/meteor/pull/14209)
- Fast-path primitive comparisons in `EJSON.equals`, [PR#14208](https://github.com/meteor/meteor/pull/14208)
- Early bail-out on key count mismatch in `EJSON.equals`, [PR#14205](https://github.com/meteor/meteor/pull/14205)
- Avoid array allocation in `lengthOf` utility, [PR#14204](https://github.com/meteor/meteor/pull/14204)
- Replace deprecated `url.parse()` with WHATWG `new URL()` API across packages and tools, [PR#14248](https://github.com/meteor/meteor/pull/14248)
- Set change streams as the default reactivity mechanism, [PR#14217](https://github.com/meteor/meteor/pull/14217)
- Warn when `Accounts.emailTemplates.from` is not configured to prevent silent email failures, [PR#14044](https://github.com/meteor/meteor/pull/14044)
#### Fixes
- Fix ObjectID fields sent as binary when using projection with change streams, [PR#14238](https://github.com/meteor/meteor/pull/14238)
- Fix DDP connection latency regression from dynamic SockJS import, [PR#14229](https://github.com/meteor/meteor/pull/14229)
- Fix default DDP connection URL for mirror domains, [PR#14189](https://github.com/meteor/meteor/pull/14189)
- Fix `forEachAsync` and `mapAsync` behavior in minimongo to match server, [PR#14021](https://github.com/meteor/meteor/pull/14021)
All Merged PRs@[GitHub PRs 3.5](https://github.com/meteor/meteor/pulls?q=is%3Apr+is%3Amerged+base%3Arelease-3.5)
#### Breaking Changes
N/A
#### Internal API changes
#### Internal API changes
N/A
@@ -22,57 +54,44 @@ N/A
Please run the following command to update your project:
```bash
meteor update --release 3.5-beta.7
meteor update --release 3.5
```
---
**Add this to your `package.json` to enable the new modern build stack:**
Change streams are now the default reactivity mechanism. If you need to revert to the previous behavior, configure the reactivity order in your `package.json`:
```json
{
"packages"@{
"mongo"@{
"reactivity"@["changeStreams", "oplog", "polling"]
"packages": {
"mongo": {
"reactivity": ["oplog", "polling"]
}
}
}
```
Check out [change streams documentation](https://github.com/meteor/meteor/blob/release-3.5/v3-docs/docs/performance/change-streams-observer-driver.md) for more details.
> Change streams are opt-in and require MongoDB 4.0+ and a replica set or sharded cluster.
> Change streams isnt added by default for new apps, so you need to add the above configuration to enable it.
Check out the [change streams documentation](https://docs.meteor.com/performance/change-streams-observer-driver) for more details.
> Change streams require MongoDB 4.0+ with a replica set or sharded cluster.
#### Bumped Meteor Packages
- accounts-base@3.3.0-beta350.7
- accounts-password@3.2.3-beta350.7
- ddp-client@3.2.0-beta350.7
- ddp-rate-limiter@1.3.0-beta350.7
- ddp-server@3.2.0-beta350.7
- ejson@1.2.0-beta350.7
- email@3.2.0-beta350.7
- minimongo@2.1.0-beta350.7
- mongo@2.3.0-beta350.7
- rate-limit@1.2.0-beta350.7
- socket-stream-client@0.7.0-beta350.7
- test-in-console@2.0.2-beta350.7
- webapp@2.2.0-beta350.7
- meteor-tool@3.5.0-beta.7
TBD
#### Bumped NPM Packages
- meteor-installer@3.5.0-beta
TBD
#### Special thanks to
✨✨✨
- [@italojs](https://github.com/italojs)
- [@radekmie](https://github.com/radekmie)
- [@nachocodoner](https://github.com/nachocodoner)
- [@9Morello](https://github.com/9Morello)
- [@alextaaa](https://github.com/alextaaa)
- [@dupontbertrand](https://github.com/dupontbertrand)
- [@harryadel](https://github.com/harryadel)
- [@mvogttech](https://github.com/mvogttech)
- [@OleksandrChekhovskyi](https://github.com/OleksandrChekhovskyi)
- [@StorytellerCZ](https://github.com/StorytellerCZ)
- [@vlasky](https://github.com/vlasky)
✨✨✨
✨✨✨

View File

@@ -8,14 +8,14 @@ Before moving production traffic to Change Streams, validate that your MongoDB d
## Requirements and Limitations
- MongoDB 3.6+ on a replica set or sharded cluster (Change Streams are not available on standalone or some shared-tier deployments).
- MongoDB 4.0+ on a replica set or sharded cluster (Change Streams are not available on standalone or some shared-tier deployments).
- Works only for unordered observers. Publications that rely on ordered callbacks (`addedBefore`, `movedBefore`) will keep using another driver.
- Selectors must compile with `Minimongo.Matcher`. Unsupported selectors fall back to the next configured driver.
- If Change Streams are unavailable, Meteor automatically moves to the next driver in your configured order.
## Choosing the Reactivity Driver Order
Meteor picks the first available driver from the configured list. The default order is `oplog`, then `changeStreams`, then `polling` (long polling). You can change this globally:
Meteor picks the first available driver from the configured list. Starting in Meteor 3.5, the default order is `changeStreams`, then `oplog`, then `polling` (long polling). You can change this globally:
- Environment variable: `METEOR_REACTIVITY_ORDER=changeStreams,oplog,polling`
- Settings file:
@@ -31,9 +31,9 @@ Meteor picks the first available driver from the configured list. The default or
```
Tips:
- Put `changeStreams` first when you cannot or do not want to tail the oplog (e.g., Atlas Serverless).
- Put `oplog` first if your application relies extensively on ordered observers or you experience performance degradation with change streams on heavily mutated collections.
- Remove `changeStreams` from the list if you want to disable it.
- Valid entries are `oplog`, `changeStreams`, and `polling`/`polling` (alias).
- Valid entries are `changeStreams`, `oplog`, and `polling` (alias long polling).
## Change Stream Driver Settings
@@ -57,3 +57,14 @@ Optional tuning is available via `Meteor.settings`:
- `waitUntilCaughtUpTimeoutMs`: Upper bound for waiting until the stream catches up to the server's current operation time when coordinating with DDP fences (default: `1000`).
- If this timeout elapses, the driver stops waiting and lets the fence continue; the change stream will catch up later, so data is not lost, but clients can temporarily miss read-your-writes (a publication may become ready before the client's own writes appear).
## Performance Comparison
- **Change Streams**: The default in Meteor 3.5+. Offloads the work of determining what changed entirely to the MongoDB server. It is extremely efficient for targeted queries but may cause high overhead on the MongoDB cluster if you have broad selectors or highly mutated collections.
- **Oplog Tailing**: The legacy default. Meteor tails the entire MongoDB oplog and filters changes in the Node.js process. This shifts load from the database to the Meteor app server, which can be beneficial if your MongoDB cluster is under heavy load, but requires oplog tailing permissions and scales poorly with a very high volume of writes across the database.
- **Polling**: The fallback mechanism. Periodically reruns the queries to compare differences. It is very resource-intensive for both the Meteor app and the database and thus discouraged for real-time reactivity except when neither Change Streams nor Oplog tailing are available.
## Troubleshooting
- **No Replica Set**: Change Streams require a replica set or sharded cluster. If you're running MongoDB standalone, it will fall back to `oplog` or `polling`. Ensure your development environment sets up a replica set.
- **Unsupported Selectors**: If your selector includes operators that Minimongo's Matcher cannot compile natively, the observer drops to the next configured fallback. Simplify complex queries to maximize Change Stream compatibility.
- **Performance Degradation**: If you see high CPU usage on your MongoDB cluster after switching to Change Streams, you may have publications with very broad filters. Use narrowed selectors, indexes, or revert to `oplog` for those specific collections.