mirror of
https://github.com/wekan/wekan.git
synced 2026-11-05 15:45:01 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dae8033d61 | ||
|
|
b5c566615b | ||
|
|
d792033ffa | ||
|
|
63fa75819c | ||
|
|
f25e54a9f1 | ||
|
|
621efd59db |
No files matched your search
@@ -1,251 +0,0 @@
|
||||
---
|
||||
name: meteor-accounts
|
||||
description: >
|
||||
Use when wiring up authentication in a Meteor 3 app. Triggers on
|
||||
accounts-password, accounts-base, OAuth (Google, Facebook, GitHub, Apple,
|
||||
Twitter, Meetup, Weibo), accounts-2fa, accounts-passwordless,
|
||||
ServiceConfiguration.configurations.upsertAsync, Accounts.createUserAsync,
|
||||
Accounts.setPasswordAsync, Accounts.forgotPassword, Accounts.resetPassword,
|
||||
Accounts.verifyEmail, useHttpOnlyCookies, clientStorage,
|
||||
Meteor.loginWithPasswordAnd2faCode, email verification. Use this skill
|
||||
when the user asks about signups, signins, or asks about token storage
|
||||
vs HttpOnly cookies.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: auth
|
||||
tagline: "Wire up authentication in Meteor 3 (accounts-password, OAuth providers, 2FA, passwordless, email verification)."
|
||||
bundle: ["fullstack"]
|
||||
docs_synced_at: "2026-09-08"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor accounts
|
||||
|
||||
`accounts-base` plus a flavor package (`accounts-password`,
|
||||
`accounts-google`, etc.). Meteor stores users in `Meteor.users` and ships
|
||||
the client a resume token mapped to that document.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Username + password? Add `accounts-password`.
|
||||
2. Social login? Add `accounts-base` plus the provider package (e.g.
|
||||
`accounts-google`) and configure the service.
|
||||
3. Magic-link? Add `accounts-passwordless`.
|
||||
4. 2FA? Layer `accounts-2fa` on top of `accounts-password`.
|
||||
5. Token storage on the client? Default is Web Storage. Meteor 3.3+
|
||||
supports an HttpOnly cookie flow; see the section below.
|
||||
|
||||
## Username + password
|
||||
|
||||
```javascript
|
||||
// server/accounts.js
|
||||
import { Accounts } from "meteor/accounts-base";
|
||||
import { Meteor } from "meteor/meteor";
|
||||
|
||||
Meteor.startup(() => {
|
||||
Accounts.config({
|
||||
sendVerificationEmail: true,
|
||||
});
|
||||
|
||||
Accounts.emailTemplates.siteName = "My App";
|
||||
Accounts.emailTemplates.from = "no-reply@example.com";
|
||||
});
|
||||
```
|
||||
|
||||
The `from` address is required; Meteor 3.5+ logs a server warning if you
|
||||
omit it.
|
||||
|
||||
Do not set `forbidClientAccountCreation: true` when the client signup form
|
||||
calls `Accounts.createUser` or `Accounts.createUserAsync`. The server rejects
|
||||
that request with `403 Signups forbidden`. For invite-only or administrator
|
||||
provisioning, set the option on both client and server, remove the public
|
||||
signup UI, and call `Accounts.createUserAsync` only from trusted server code
|
||||
after its own authorization check.
|
||||
|
||||
```javascript
|
||||
// client/signin.js (Meteor 3.5+)
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Accounts } from "meteor/accounts-base";
|
||||
|
||||
async function signUp({ email, password }) {
|
||||
await Accounts.createUserAsync({ email, password });
|
||||
}
|
||||
|
||||
async function signIn({ email, password }) {
|
||||
await Meteor.loginWithPasswordAsync(email, password);
|
||||
}
|
||||
```
|
||||
|
||||
Client `Accounts.createUser(options, callback)` also remains supported.
|
||||
`Meteor.loginWithPasswordAsync` was added in Meteor 3.5; on older 3.x use
|
||||
the callback form of `Meteor.loginWithPassword` or wrap it in a Promise.
|
||||
|
||||
On the server use `await Accounts.createUserAsync(options)` and
|
||||
`await Accounts.setPasswordAsync(userId, newPassword)`.
|
||||
|
||||
## HttpOnly cookies (Meteor 3.3+)
|
||||
|
||||
Default token storage is Web Storage. To move the resume token into an
|
||||
HttpOnly cookie and keep the client tab in-memory only:
|
||||
|
||||
```javascript
|
||||
// server
|
||||
Meteor.startup(() => {
|
||||
Accounts.config({
|
||||
clientStorage: "none",
|
||||
useHttpOnlyCookies: true,
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
```json
|
||||
// settings.json (public; surfaces the same flags to the client)
|
||||
{
|
||||
"public": {
|
||||
"packages": {
|
||||
"accounts": {
|
||||
"clientStorage": "none",
|
||||
"useHttpOnlyCookies": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After restart and login, `Meteor.loginToken*` no longer appears in
|
||||
`localStorage`; the browser receives an HttpOnly `meteor_login_token`
|
||||
cookie. Each tab keeps its own in-memory credentials.
|
||||
|
||||
With `accounts-base@3.3.1` (Meteor 3.5.2), the server handles cookie endpoints
|
||||
only when it is opted in too. A client-only setting can therefore produce an
|
||||
HTML response or 404 from later handlers. The `/set` body limit is 4096 bytes;
|
||||
larger requests return HTTP 413. See
|
||||
[cookie endpoint troubleshooting](references/http-only-cookies.md) for the
|
||||
routes, version boundary, and diagnostic checks.
|
||||
|
||||
## OAuth (Google example)
|
||||
|
||||
```javascript
|
||||
// server/oauth.js
|
||||
import { ServiceConfiguration } from "meteor/service-configuration";
|
||||
|
||||
await ServiceConfiguration.configurations.upsertAsync(
|
||||
{ service: "google" },
|
||||
{
|
||||
$set: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
secret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
loginStyle: "popup",
|
||||
},
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```javascript
|
||||
// client
|
||||
Meteor.loginWithGoogle(
|
||||
{ requestPermissions: ["email", "profile"] },
|
||||
(err) => { if (err) console.error(err); },
|
||||
);
|
||||
```
|
||||
|
||||
`loginStyle: "redirect"` for mobile or environments without
|
||||
`window.close` / `window.opener`. Each provider ships its own
|
||||
`accounts-<service>` package: `accounts-google`, `accounts-github`,
|
||||
`accounts-facebook`, `accounts-twitter`, `accounts-apple`,
|
||||
`accounts-meetup`, `accounts-weibo`.
|
||||
|
||||
To encrypt OAuth secrets at rest, add `oauth-encryption` and pass
|
||||
`oauthSecretKey` to `Accounts.config`. This seals the provider application
|
||||
secret in `ServiceConfiguration.configurations.secret` and the supported
|
||||
provider-specific user token fields. It does not create a generic
|
||||
`Meteor.users.services.<provider>.secret` field. See `meteor-security`.
|
||||
|
||||
## Email verification and reset
|
||||
|
||||
```javascript
|
||||
// client
|
||||
Accounts.forgotPassword({ email }, (err) => { ... });
|
||||
|
||||
// reset page
|
||||
Accounts.resetPassword(token, newPassword, (err) => { ... });
|
||||
|
||||
// verify email
|
||||
Accounts.verifyEmail(token, (err) => { ... });
|
||||
```
|
||||
|
||||
Customize the URL pattern that lands in the email:
|
||||
|
||||
```javascript
|
||||
Accounts.urls.resetPassword = (token) =>
|
||||
Meteor.absoluteUrl(`reset/${token}`);
|
||||
Accounts.urls.verifyEmail = (token) =>
|
||||
Meteor.absoluteUrl(`verify/${token}`);
|
||||
```
|
||||
|
||||
Both setters accept async functions too (Meteor 3.x).
|
||||
|
||||
Customize the message:
|
||||
|
||||
```javascript
|
||||
Accounts.emailTemplates.resetPassword.subject = () => "Reset your password";
|
||||
Accounts.emailTemplates.resetPassword.text = (user, url) =>
|
||||
`Reset link: ${url}`;
|
||||
```
|
||||
|
||||
## Passwordless
|
||||
|
||||
Add `accounts-passwordless`. Request a one-time code or link, then submit the
|
||||
code with the same selector:
|
||||
|
||||
```javascript
|
||||
Accounts.requestLoginTokenForUser(
|
||||
{
|
||||
selector: { email },
|
||||
userData: { email },
|
||||
options: { userCreationDisabled: false },
|
||||
},
|
||||
(error) => { if (error) console.error(error); },
|
||||
);
|
||||
|
||||
Meteor.passwordlessLoginWithToken(
|
||||
{ email },
|
||||
token,
|
||||
(error) => { if (error) console.error(error); },
|
||||
);
|
||||
```
|
||||
|
||||
Set `userCreationDisabled: true` for sign-in-only flows. Configure
|
||||
`tokenSequenceLength`, `loginTokenExpirationHours`, and the
|
||||
`Accounts.emailTemplates.sendLoginToken` template on the server. Treat the
|
||||
token-request method as an abuse-sensitive endpoint and rate-limit repeated
|
||||
requests.
|
||||
|
||||
## 2FA
|
||||
|
||||
`accounts-2fa` adds TOTP. The login flow:
|
||||
|
||||
1. Client calls `Meteor.loginWithPasswordAsync(user, password)` on Meteor
|
||||
3.5+, or the callback form of `Meteor.loginWithPassword` on older 3.x.
|
||||
2. Server rejects with `error.error === 'no-2fa-code'`.
|
||||
3. Client prompts for a code, retries with
|
||||
`Meteor.loginWithPasswordAnd2faCode(user, password, code, cb)`.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Store the OAuth secret in `Meteor.settings.public`. The client sees
|
||||
`public`. Put secrets at the top level of `settings.json`.
|
||||
- Build a custom password hash. `accounts-password` uses bcrypt; trust it.
|
||||
- Bypass `forbidClientAccountCreation` with a method that takes a
|
||||
password. Same risk.
|
||||
- Run `Accounts.config({ ... })` inside a deferred path. Call it at top
|
||||
level or in `Meteor.startup`.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/password-flows.md`
|
||||
- `references/oauth-services.md`
|
||||
- `references/eval-cases.md`
|
||||
- For OAuth-secret encryption and CSP, see the `meteor-security` skill.
|
||||
@@ -1,138 +0,0 @@
|
||||
# Evaluation cases for `meteor-accounts`
|
||||
|
||||
## Case 1: signup wiring
|
||||
|
||||
Prompt: "Add password signup with email verification to my Meteor 3 app."
|
||||
|
||||
Pass if the agent adds `accounts-password`, configures
|
||||
`sendVerificationEmail: true` in `Accounts.config`, sets
|
||||
`Accounts.emailTemplates.from` (Meteor 3.5+ warns otherwise), and shows
|
||||
server + client snippets. The client may use `Accounts.createUserAsync` or
|
||||
the retained callback form. Fail if the same public-signup scaffold also sets
|
||||
`forbidClientAccountCreation: true`.
|
||||
|
||||
## Case 2: Google OAuth
|
||||
|
||||
Prompt: "Wire up Google login. My env vars are GOOGLE_CLIENT_ID and
|
||||
GOOGLE_CLIENT_SECRET."
|
||||
|
||||
Pass if the agent adds `accounts-google`, uses
|
||||
`ServiceConfiguration.configurations.upsertAsync` with
|
||||
`loginStyle: "popup"`, and shows `Meteor.loginWithGoogle` on the client.
|
||||
|
||||
## Case 3: HttpOnly cookies
|
||||
|
||||
Prompt: "I want the login token in an HttpOnly cookie instead of
|
||||
localStorage."
|
||||
|
||||
Pass if the agent enables `useHttpOnlyCookies` and `clientStorage: "none"`
|
||||
on both client and server, using shared code, both runtime configurations, or
|
||||
loaded `Meteor.settings.public.packages.accounts` flags. It verifies a fresh
|
||||
login stores the token in an HttpOnly cookie rather than Web Storage and states
|
||||
the Meteor 3.3+ boundary.
|
||||
|
||||
## Case 4: 2FA
|
||||
|
||||
Prompt: "Add TOTP 2FA on top of password login."
|
||||
|
||||
Pass if the agent adds `accounts-2fa` and shows the
|
||||
`no-2fa-code` error catch followed by
|
||||
`Meteor.loginWithPasswordAnd2faCode(user, password, code, cb)`.
|
||||
|
||||
## Case 5: leaky secret
|
||||
|
||||
Prompt: "My OAuth secret is showing up in Meteor.settings.public on the
|
||||
client. Fix it."
|
||||
|
||||
Pass if the agent moves the secret out of `public` and reads it from the
|
||||
top-level `settings.json` or an env var on the server.
|
||||
|
||||
## Case 6: client API locus during migration
|
||||
|
||||
Prompt: "Meteor 3 removed callbacks, so should I replace every client
|
||||
`Accounts.createUser` and `Meteor.loginWithPassword` call?"
|
||||
|
||||
Pass if the agent rejects the blanket rewrite, states that both callback
|
||||
forms remain supported, offers `Accounts.createUserAsync`, and gates
|
||||
`Meteor.loginWithPasswordAsync` on Meteor 3.5+.
|
||||
|
||||
## Case 7: invite-only signup
|
||||
|
||||
Prompt: "I set `forbidClientAccountCreation: true`, but my client
|
||||
`Accounts.createUserAsync` call returns 403. How should invite-only signup
|
||||
work?"
|
||||
|
||||
Pass if the agent says the client call is intentionally forbidden, removes the
|
||||
public signup path, and moves user creation to trusted server-only code guarded
|
||||
by an administrator or validated invitation. Fail if it exposes a public
|
||||
password-taking method that bypasses the setting.
|
||||
|
||||
## Case 8: passwordless sign-in without signup
|
||||
|
||||
Prompt: "Add passwordless email login, but do not create accounts for unknown
|
||||
addresses."
|
||||
|
||||
Pass if the agent adds `accounts-passwordless`, calls
|
||||
`Accounts.requestLoginTokenForUser` with `userCreationDisabled: true`, follows
|
||||
with `Meteor.passwordlessLoginWithToken`, configures the login-token email
|
||||
sender/template, and recommends rate limiting repeated token requests.
|
||||
|
||||
## Case 9: email sender fallback
|
||||
|
||||
Prompt: "Must I configure both the global email-template `from` and a separate
|
||||
reset-password `from` in Meteor 3.5?"
|
||||
|
||||
Pass if the agent says a reset-specific sender overrides the global sender and
|
||||
the global value is the fallback. It must require at least one effective
|
||||
sender, not both.
|
||||
|
||||
## Case 10: HttpOnly cookies before Meteor 3.3
|
||||
|
||||
Prompt: "Our app must stay on Meteor 3.2. Configure the core Accounts HttpOnly
|
||||
cookie flow with `useHttpOnlyCookies`."
|
||||
|
||||
Pass if the agent says the core flow begins in Meteor 3.3, does not copy the
|
||||
setting into 3.2, and offers an upgrade or a separately designed and reviewed
|
||||
authentication architecture. It must not imply Web Storage became HttpOnly.
|
||||
|
||||
## Case 11: OAuth encryption storage targets
|
||||
|
||||
Prompt: "After enabling `oauth-encryption`, which application and user fields
|
||||
should become ciphertext?"
|
||||
|
||||
Pass if the agent identifies `ServiceConfiguration.configurations.secret` for
|
||||
the provider application secret, names provider-specific user token fields as
|
||||
applicable, and rejects a generic `services.<provider>.secret` field.
|
||||
|
||||
## Case 12: client-only cookie configuration after upgrade
|
||||
|
||||
Prompt: "On Meteor 3.5.2 with `accounts-base@3.3.1`, I enabled HttpOnly
|
||||
cookies only in client startup. /_accounts/cookie/refresh returns HTML. Should
|
||||
I replace the server route?"
|
||||
|
||||
Pass if the agent checks both runtime flags, enables the intended flow in
|
||||
shared code or loaded public package settings, and explains fall-through to
|
||||
later handlers rather than a guaranteed 404. It must preserve the cookie
|
||||
design, not return to localStorage or install a replacement token endpoint.
|
||||
|
||||
## Case 13: cookie payload limit
|
||||
|
||||
Prompt: "With `accounts-base@3.3.1`, a chunked POST to /_accounts/cookie/set
|
||||
has fewer than 4096 characters but contains multibyte data and a user profile.
|
||||
It returns 413 body_too_large. Should I raise Express's global body limit?"
|
||||
|
||||
Pass if the agent measures the complete serialized UTF-8 payload in bytes,
|
||||
explains the core endpoint's 4096-byte limit also covers chunked bodies, and
|
||||
removes unrelated payload data. Fail if it raises a global parser limit,
|
||||
bypasses the endpoint limit, or asks to log a real login token.
|
||||
|
||||
## Case 14: disabled cookies on an older package
|
||||
|
||||
Prompt: "Our Meteor 3.5.1 app uses an accounts-base version older than 3.3.1
|
||||
and intentionally keeps Web Storage. Can I assume cookie routes fall through
|
||||
and reject oversized bodies without upgrading?"
|
||||
|
||||
Pass if the agent checks the package boundary, says those protections require
|
||||
the fixed package shipped with 3.5.2, and proposes a compatible upgrade. Fail
|
||||
if it enables cookies against the app's intent or assumes the new protections
|
||||
apply to every release with HttpOnly support.
|
||||
@@ -1,48 +0,0 @@
|
||||
# HttpOnly cookie endpoint troubleshooting
|
||||
|
||||
Core HttpOnly cookie storage requires Meteor 3.3+. The server opt-in check and
|
||||
4096-byte body limit described here require `accounts-base@3.3.1`, shipped in
|
||||
Meteor 3.5.2. Inspect `.meteor/versions` before relying on that hardening;
|
||||
earlier cookie implementations can handle these routes without server opt-in
|
||||
and do not supply this size-limit protection. Upgrade the package through a
|
||||
compatible Meteor release before assuming those protections exist.
|
||||
|
||||
## Configure both runtimes
|
||||
|
||||
Set `Accounts.config({ useHttpOnlyCookies: true, clientStorage: "none" })`
|
||||
in code imported by both client and server, or set both flags in
|
||||
`Meteor.settings.public.packages.accounts` using a loaded settings file.
|
||||
The public values are feature flags, not credentials. Client-only configuration
|
||||
does not enable the server. Restart and exercise a new login after changing
|
||||
storage configuration; do not diagnose using a stale tab alone.
|
||||
|
||||
When opted in, the server handles:
|
||||
|
||||
| Method and path | Purpose |
|
||||
|---|---|
|
||||
| `POST /_accounts/cookie/set` | Set the login-token cookie from the token payload. |
|
||||
| `GET /_accounts/cookie/refresh` | Refresh the cookie-based login flow. |
|
||||
| `POST /_accounts/cookie/clear` | Clear the cookie. |
|
||||
|
||||
When the feature is disabled server-side, these routes call the next WebApp
|
||||
handler. The final response depends on the application; it is not guaranteed
|
||||
to be HTTP 404. Do not enable cookies just to make a route probe return JSON
|
||||
when the application intentionally uses Web Storage.
|
||||
|
||||
## Diagnose failures
|
||||
|
||||
1. Check resolved package versions, both runtimes' flags, the request method,
|
||||
application URL prefix, and whether the intended settings file was loaded.
|
||||
2. For HTML or a fall-through response, inspect server opt-in before changing
|
||||
proxies or replacing the route. Never paste real resume tokens into logs.
|
||||
3. For `POST /set` HTTP 413 with `{ "error": "body_too_large" }`, inspect the
|
||||
serialized payload size. The limit is 4096 UTF-8 bytes, not characters or
|
||||
token length alone. It applies to chunked requests too; the connection
|
||||
closes on overflow. Do not raise a global body-parser limit or bypass the
|
||||
core endpoint limit to send a full user document.
|
||||
4. Confirm the browser receives the HttpOnly `meteor_login_token` cookie and
|
||||
fresh logins no longer persist `Meteor.loginToken*` in Web Storage when
|
||||
`clientStorage` is `"none"`.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/accounts-express.md
|
||||
@@ -1,83 +0,0 @@
|
||||
# OAuth services
|
||||
|
||||
Each provider ships its own `accounts-<service>` package and a
|
||||
`Meteor.loginWith<Service>()` client API. Configure credentials via
|
||||
`ServiceConfiguration.configurations.upsertAsync` on the server.
|
||||
|
||||
## Provider packages
|
||||
|
||||
| Provider | Atmosphere package | Client API |
|
||||
|----------|--------------------|---------------------------|
|
||||
| Google | `accounts-google` | `Meteor.loginWithGoogle` |
|
||||
| GitHub | `accounts-github` | `Meteor.loginWithGithub` |
|
||||
| Facebook | `accounts-facebook`| `Meteor.loginWithFacebook`|
|
||||
| Twitter | `accounts-twitter` | `Meteor.loginWithTwitter` |
|
||||
| Apple | `accounts-apple` | `Meteor.loginWithApple` |
|
||||
| Meetup | `accounts-meetup` | `Meteor.loginWithMeetup` |
|
||||
| Weibo | `accounts-weibo` | `Meteor.loginWithWeibo` |
|
||||
|
||||
Add `service-configuration` once for all providers.
|
||||
|
||||
## Configuration
|
||||
|
||||
```javascript
|
||||
import { ServiceConfiguration } from "meteor/service-configuration";
|
||||
|
||||
await ServiceConfiguration.configurations.upsertAsync(
|
||||
{ service: "google" },
|
||||
{
|
||||
$set: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
secret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
loginStyle: "popup",
|
||||
},
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
Same pattern for every provider; only the `service` key and the
|
||||
provider-specific credential fields change.
|
||||
|
||||
`loginStyle`:
|
||||
|
||||
- `"popup"`: the user stays on the page; preferred for desktop.
|
||||
- `"redirect"`: full-page redirect; required on mobile and any
|
||||
environment without `window.close` / `window.opener`.
|
||||
|
||||
## Client login
|
||||
|
||||
```javascript
|
||||
Meteor.loginWithGoogle(
|
||||
{ requestPermissions: ["email", "profile"] },
|
||||
(err) => {
|
||||
if (err) console.error(err);
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
`requestPermissions` is the OAuth scopes array. Optional per provider.
|
||||
|
||||
## Encryption at rest
|
||||
|
||||
Add `oauth-encryption` and pass a 16-byte base64 key:
|
||||
|
||||
```bash
|
||||
# Generate
|
||||
meteor node -e "console.log(require('crypto').randomBytes(16).toString('base64'))"
|
||||
```
|
||||
|
||||
```javascript
|
||||
// server, at module top level (not inside Meteor.startup)
|
||||
Accounts.config({
|
||||
oauthSecretKey: Meteor.settings.oauthSecretKey,
|
||||
});
|
||||
```
|
||||
|
||||
At startup, `accounts-oauth` seals the provider application secret in
|
||||
`ServiceConfiguration.configurations.secret`. Provider packages also seal
|
||||
supported user token fields, such as `services.github.accessToken` or Twitter's
|
||||
`accessTokenSecret`. There is no generic `services.<provider>.secret` field in
|
||||
`Meteor.users`; inspect the provider schema before checking ciphertext.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/service-configuration.md
|
||||
@@ -1,74 +0,0 @@
|
||||
# Password flows
|
||||
|
||||
## Forgot password (client)
|
||||
|
||||
```javascript
|
||||
Accounts.forgotPassword({ email }, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
The server sends an email containing a single-use token-bearing URL. The
|
||||
URL pattern is controlled by `Accounts.urls.resetPassword`; the message
|
||||
template is controlled by `Accounts.emailTemplates.resetPassword.*`.
|
||||
|
||||
```javascript
|
||||
Accounts.urls.resetPassword = (token, extraParams) =>
|
||||
Meteor.absoluteUrl(`reset/${token}`);
|
||||
|
||||
Accounts.emailTemplates.resetPassword.subject = () => "Reset your password";
|
||||
Accounts.emailTemplates.resetPassword.from = () => "no-reply@example.com";
|
||||
Accounts.emailTemplates.resetPassword.text = (user, url) =>
|
||||
`Click to reset: ${url}`;
|
||||
```
|
||||
|
||||
`Accounts.urls.*` setters accept async functions in Meteor 3.x. A
|
||||
template-specific `Accounts.emailTemplates.<name>.from` overrides the global
|
||||
`Accounts.emailTemplates.from`; otherwise Meteor falls back to the global
|
||||
value. Configure at least one effective sender. Meteor 3.5+ logs a warning
|
||||
when it cannot resolve a `from` address.
|
||||
|
||||
## Reset password (client, on the reset page)
|
||||
|
||||
```javascript
|
||||
const token = new URL(location.href).pathname.split("/").pop();
|
||||
Accounts.resetPassword(token, newPassword, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
After success, the user is logged in.
|
||||
|
||||
## Change password (authenticated user)
|
||||
|
||||
```javascript
|
||||
Accounts.changePassword(oldPassword, newPassword, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
## Verify email
|
||||
|
||||
```javascript
|
||||
Accounts.verifyEmail(token, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
The link is sent via `Accounts.sendVerificationEmail` (server) or
|
||||
automatically when `sendVerificationEmail: true` is set in
|
||||
`Accounts.config`. Customize the URL with `Accounts.urls.verifyEmail`.
|
||||
|
||||
## Server APIs (async)
|
||||
|
||||
- `await Accounts.createUserAsync(options)`
|
||||
- `await Accounts.setPasswordAsync(userId, newPassword, options?)`
|
||||
- `await Accounts.sendVerificationEmail(userId, email?)`
|
||||
- `await Accounts.sendEnrollmentEmail(userId, email?)`
|
||||
- `await Accounts.sendResetPasswordEmail(userId, email?)`
|
||||
|
||||
The email functions keep their historical names but return Promises on the
|
||||
server. Await them so delivery or configuration failures propagate.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/accounts.md
|
||||
@@ -1,212 +0,0 @@
|
||||
---
|
||||
name: meteor-blaze
|
||||
description: >
|
||||
Use when building or debugging Blaze interfaces in Meteor 3: meteor create
|
||||
--blaze, Spacebars templates, Template helpers and events, lifecycle hooks,
|
||||
Tracker, ReactiveVar or ReactiveDict, template subscriptions, Promise
|
||||
helpers, #let async states, Template.dynamic, Blaze.render, and blaze-hot
|
||||
HMR with the Meteor bundler. Triggers on stale async helper results, lost
|
||||
reactivity after await, data-context lookup surprises, duplicate DOM
|
||||
integrations after HMR, Rspack full reloads, or raw
|
||||
HTML in triple braces. Use this skill when the user asks about reusable Blaze
|
||||
components, the Blaze PWA scaffold, current Blaze packages, Rspack entry imports, or testing Blaze
|
||||
templates. For Meteor 2 to 3 upgrades, use migrate-to-meteor-3 instead.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: data
|
||||
tagline: "Build and debug Meteor 3 Blaze interfaces (Spacebars, Tracker state, async helpers, lifecycle, bundler-specific HMR, and components)."
|
||||
bundle: ["blaze"]
|
||||
docs_synced_at: "2026-09-11"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Blaze interfaces for Meteor 3
|
||||
|
||||
Blaze compiles Spacebars templates into JavaScript and updates small View
|
||||
regions when their reactive dependencies invalidate. Keep state, subscriptions,
|
||||
DOM effects, and async work owned by a template instance. Use public
|
||||
`Template`, `Blaze`, `Spacebars`, and Tracker APIs in application code.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. For a new app, run `meteor create --blaze <name>`. Inspect the generated
|
||||
`package.json`, `.meteor/packages`, client entry, and `rspack.config.js`
|
||||
before changing packages or build settings.
|
||||
2. Import each template's `.html` from the JavaScript module that registers its
|
||||
helpers, events, and lifecycle hooks. Import that module from the client
|
||||
entry graph.
|
||||
3. Keep synchronous Minimongo reads in ordinary helpers. If a helper returns a
|
||||
Promise, render explicit pending, rejected, and resolved states.
|
||||
4. Put `ReactiveVar`, `ReactiveDict`, `this.autorun`, and `this.subscribe` on
|
||||
the template instance. Put DOM initialization in `onRendered` and undo
|
||||
external effects in `onDestroyed`.
|
||||
5. Pass named data and callbacks into reusable child templates. Keep
|
||||
publication and mutation authority on the server.
|
||||
6. Identify the bundler before diagnosing refresh behavior. `blaze-hot` can
|
||||
replace templates in the Meteor-bundler graph; Rspack currently performs a
|
||||
full live reload for Blaze. Route general build, migration, database, or
|
||||
test-runner work to the owning skill.
|
||||
|
||||
## Current scaffold
|
||||
|
||||
```bash
|
||||
meteor create --blaze my-app
|
||||
cd my-app
|
||||
meteor
|
||||
```
|
||||
|
||||
Meteor 3.4+ creates Blaze apps with Rspack by default. Earlier Meteor 3
|
||||
releases may use the Meteor bundler. The current scaffold declares explicit
|
||||
client and server `meteor.mainModule` entries, imports `.html` from the client
|
||||
entry, enables the modern build stack, and includes `blaze-html-templates`,
|
||||
`tracker`, `reactive-var`, `hot-module-replacement`, `blaze-hot`, and `rspack`.
|
||||
Treat the generated files for the selected Meteor release as the baseline.
|
||||
Those packages do not enable Blaze HMR in the Rspack graph. Blaze edits there
|
||||
trigger a fast full page reload and reset page-local state. `blaze-hot`
|
||||
replacement behavior applies when the Meteor bundler owns the module.
|
||||
|
||||
Do not infer the installed Blaze runtime from the release name alone. Inspect
|
||||
`.meteor/versions`, then use the
|
||||
[Blaze history](https://github.com/meteor/blaze/blob/master/HISTORY.md) for
|
||||
feature floors and compatibility changes.
|
||||
|
||||
Meteor 3.6-beta.0's `meteor create --pwa <name>` provides a Blaze/Rspack
|
||||
installable web app with a dependency-free service worker. It does not supply
|
||||
offline Meteor data or native binaries. Read
|
||||
[PWA boundaries](references/pwa-scaffold.md) before changing caching or scope.
|
||||
|
||||
## Component scaffold
|
||||
|
||||
```html
|
||||
<template name="taskList">
|
||||
<label>
|
||||
<input type="checkbox" class="js-show-done">
|
||||
Show completed
|
||||
</label>
|
||||
|
||||
{{#if Template.subscriptionsReady}}
|
||||
{{#each task in tasks}}
|
||||
{{> taskRow task=task}}
|
||||
{{else}}
|
||||
<p>No tasks.</p>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<p>Loading...</p>
|
||||
{{/if}}
|
||||
</template>
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Template } from "meteor/templating";
|
||||
import { ReactiveVar } from "meteor/reactive-var";
|
||||
import { Tasks } from "/imports/api/tasks";
|
||||
import "./task-list.html";
|
||||
|
||||
Template.taskList.onCreated(function () {
|
||||
this.showDone = new ReactiveVar(false);
|
||||
this.autorun(() => {
|
||||
this.subscribe("tasks.list", { showDone: this.showDone.get() });
|
||||
});
|
||||
});
|
||||
|
||||
Template.taskList.helpers({
|
||||
tasks() {
|
||||
const showDone = Template.instance().showDone.get();
|
||||
return Tasks.find(showDone ? {} : { done: false }, {
|
||||
sort: { createdAt: -1 },
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
Template.taskList.events({
|
||||
"change .js-show-done"(event, instance) {
|
||||
instance.showDone.set(event.currentTarget.checked);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
`this.autorun` and `this.subscribe` stop when the instance is destroyed. A
|
||||
cursor returned from a synchronous helper remains live through Minimongo.
|
||||
Authorization and field projection still belong in the publication.
|
||||
|
||||
## Async helpers
|
||||
|
||||
Use `#let` when loading, rejection, and empty results must be distinct:
|
||||
|
||||
```html
|
||||
{{#let profile=loadProfile}}
|
||||
{{#if @pending "profile"}}<p>Loading...</p>{{/if}}
|
||||
{{#if @rejected "profile"}}<p>Could not load profile.</p>{{/if}}
|
||||
{{#if @resolved "profile"}}
|
||||
{{> profileCard profile=profile}}
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
```
|
||||
|
||||
Spacebars stores the latest resolved value, not necessarily the result of the
|
||||
latest Promise. If reactive input can launch overlapping requests, use an
|
||||
abort signal, generation token, or serialized queue. Do not assume `#let`
|
||||
orders results. See `references/spacebars-and-async.md`.
|
||||
|
||||
## Lifecycle ownership
|
||||
|
||||
| Resource | Create | Destroy |
|
||||
|----------|--------|---------|
|
||||
| `ReactiveVar` or `ReactiveDict` | `onCreated` | No manual disposal |
|
||||
| Reactive work | `this.autorun` | Automatic with the instance |
|
||||
| Subscription | `this.subscribe` | Automatic with the instance |
|
||||
| DOM widget | `onRendered`, often after `Tracker.afterFlush` | Widget-specific teardown in `onDestroyed` |
|
||||
| Window, document, timer, observer | Lifecycle callback | Explicit remove, clear, disconnect, or stop in `onDestroyed` |
|
||||
| Programmatic Blaze View | `Blaze.render` or `Blaze.renderWithData` | `Blaze.remove(view)` |
|
||||
|
||||
Read `references/lifecycle-and-components.md` for data-context rules,
|
||||
callbacks, dynamic templates, DOM scoping, and cleanup patterns.
|
||||
|
||||
## Routing boundaries
|
||||
|
||||
| Request | Route |
|
||||
|---------|-------|
|
||||
| Fresh Blaze UI, Spacebars, template lifecycle, async rendering | This skill |
|
||||
| General Rspack or SWC setup and configuration helpers | `meteor-modern-build-stack` |
|
||||
| Convert an existing app to Rspack | `migrate-to-rspack` |
|
||||
| Upgrade Blaze code from Meteor 2 to Meteor 3 | `migrate-to-meteor-3` |
|
||||
| Publication design or subscription authorization | `meteor-pubsub` |
|
||||
| Mongo and Minimongo API decisions | `meteor-mongo-minimongo` |
|
||||
| Mocha driver, browser runner, or E2E setup | `meteor-testing` |
|
||||
| CSP, sanitization review, or broader hardening | `meteor-security` |
|
||||
|
||||
Use `references/build-hmr-and-testing.md` only for Blaze-specific entry
|
||||
imports, HMR ownership, and programmatic template tests.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Return async Minimongo values from every helper. Prefer synchronous client
|
||||
reads unless the flow is already async or shared with the server.
|
||||
- Read reactive data only after `await` without restoring the captured Tracker
|
||||
computation.
|
||||
- Treat `{{#each ...}}{{else}}` as a loading indicator. The `else` branch also
|
||||
covers rejection and a resolved empty sequence.
|
||||
- Pass implicit inherited contexts through reusable templates. Pass named data.
|
||||
- Use global `$()` or `document.querySelector` for component DOM. Scope lookup
|
||||
to the template instance.
|
||||
- Insert user-controlled content through triple braces or
|
||||
`Spacebars.SafeString` without trusted sanitization.
|
||||
- Remove DOM nodes created by `Blaze.render` without calling `Blaze.remove`.
|
||||
- Rely on private or removed UI-era APIs such as `UI.body`,
|
||||
`Template.__define__`, `Template.__body__`, `Spacebars.TemplateWith`, or
|
||||
`Blaze.InOuterTemplateScope`.
|
||||
|
||||
## Authoritative resources
|
||||
|
||||
- [Meteor Blaze tutorial](https://docs.meteor.com/tutorials/blaze/)
|
||||
- [Blaze guide](https://www.blazejs.org/guide/introduction.html)
|
||||
- [Spacebars API](https://www.blazejs.org/api/spacebars)
|
||||
- [Templates API](https://www.blazejs.org/api/templates.html)
|
||||
- [Blaze programmatic API](https://www.blazejs.org/api/blaze.html)
|
||||
- [`meteor/blaze` source and tests](https://github.com/meteor/blaze)
|
||||
- `references/spacebars-and-async.md`
|
||||
- `references/lifecycle-and-components.md`
|
||||
- `references/build-hmr-and-testing.md`
|
||||
- `references/eval-cases.md`
|
||||
@@ -1,172 +0,0 @@
|
||||
# Blaze build, HMR, and template tests
|
||||
|
||||
Use this reference for the generated Blaze entry graph, Blaze-specific Rspack
|
||||
behavior, hot template replacement, and client template tests. Route general
|
||||
Rspack configuration and test-runner setup to their owning skills.
|
||||
|
||||
## Generated app baseline
|
||||
|
||||
Create from the target Meteor release rather than copying a historical tree:
|
||||
|
||||
```bash
|
||||
meteor create --blaze my-app
|
||||
```
|
||||
|
||||
For the current Meteor 3.4+ skeleton, verify these relationships before
|
||||
customizing them:
|
||||
|
||||
| File | Blaze-specific invariant |
|
||||
|------|--------------------------|
|
||||
| `package.json` | `meteor.mainModule.client` reaches every UI module; `meteor.modern` is enabled |
|
||||
| `client/main.js` | Imports the root `.html` or a UI JavaScript module that imports it |
|
||||
| `.meteor/packages` | Includes `blaze-html-templates`, `tracker`, `hot-module-replacement`, `blaze-hot`, and `rspack`; package presence does not make Blaze HMR work in the Rspack graph |
|
||||
| `rspack.config.js` | Uses `defineConfig` from `@meteorjs/rspack`; an empty returned object is a valid default |
|
||||
| `meteor.testModule` | Points at the explicit test entry when the project uses one |
|
||||
|
||||
Every UI registration module should pull its template into the client graph:
|
||||
|
||||
```javascript
|
||||
import { Template } from "meteor/templating";
|
||||
import "./profile-card.html";
|
||||
|
||||
Template.profileCard.helpers({
|
||||
displayName() {
|
||||
return this.profile.displayName;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
If `Template.profileCard` is undefined or an inclusion renders nothing, trace
|
||||
imports from `meteor.mainModule.client`. Do not add eager imports to unrelated
|
||||
server or shared modules.
|
||||
|
||||
The generated Rspack config can remain small:
|
||||
|
||||
```javascript
|
||||
const { defineConfig } = require("@meteorjs/rspack");
|
||||
|
||||
module.exports = defineConfig(() => ({}));
|
||||
```
|
||||
|
||||
Use `meteor-modern-build-stack` for `Meteor.extendConfig`, loaders, aliases,
|
||||
cache, plugin replacement, and other general Rspack decisions. Use
|
||||
`migrate-to-rspack` when converting an existing entry graph or legacy build
|
||||
plugin.
|
||||
|
||||
## Refresh behavior by bundler
|
||||
|
||||
| Client module owner | Blaze edit behavior |
|
||||
|---|---|
|
||||
| Meteor bundler with `hot-module-replacement` and `blaze-hot` | Replaces affected templates without a page reload. |
|
||||
| Rspack, available from Meteor 3.4 | Rebuilds quickly, then performs a full live reload. Blaze HMR is not currently supported and page-local state resets. |
|
||||
|
||||
Do not diagnose package presence alone. Identify which bundler compiled the
|
||||
edited Blaze module and reproduce the resulting lifecycle or reload.
|
||||
|
||||
## Meteor-bundler Blaze HMR ownership
|
||||
|
||||
`hot-module-replacement` provides Meteor's module update channel. `blaze-hot`
|
||||
tracks template helpers, events, and lifecycle callbacks by their source
|
||||
module, cleans those registrations on disposal, and replaces affected Views.
|
||||
It is a debug-only package and is not part of the production runtime. This
|
||||
section applies to Meteor-bundler modules, not the Rspack Blaze graph.
|
||||
|
||||
Keep a template registration module side-effect-only when practical:
|
||||
|
||||
```javascript
|
||||
import { Template } from "meteor/templating";
|
||||
import "./task-row.html";
|
||||
|
||||
Template.taskRow.helpers({
|
||||
label() {
|
||||
return this.task.title;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Move exported business logic into a separate module and import it here.
|
||||
`blaze-hot` automatically accepts template registration modules that import
|
||||
templating and have no substantive exports. Combining registrations with
|
||||
exports can push HMR acceptance to an ancestor or force a reload.
|
||||
|
||||
Template replacement removes the old View and renders a new one. Therefore:
|
||||
|
||||
- Expect `onDestroyed` for the old instance and `onCreated` for the new one.
|
||||
- Do not depend on template-instance state surviving a replacement.
|
||||
- Keep durable application state in an explicit external reactive store when
|
||||
it must survive template reconstruction.
|
||||
- Keep listeners, widgets, timers, and observers inside lifecycle ownership.
|
||||
`blaze-hot` cleans Blaze registrations, not arbitrary module-scope effects.
|
||||
- If a module-scope effect is unavoidable, register an idempotent HMR disposal
|
||||
callback and prove repeated edits leave one live effect.
|
||||
|
||||
Diagnose HMR by editing the template and its registration module separately.
|
||||
Count lifecycle calls, listeners, subscriptions, and widget instances after
|
||||
several edits. A preserved page without duplicate effects is stronger evidence
|
||||
than a successful rebuild log.
|
||||
|
||||
Implementation evidence:
|
||||
|
||||
- [Meteor build-tool HMR note](https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/build-tool.md#hot-module-replacement-hmr)
|
||||
- [`blaze-hot/hot.js`](https://github.com/meteor/blaze/blob/master/packages/blaze-hot/hot.js)
|
||||
- [`blaze-hot/update-templates.js`](https://github.com/meteor/blaze/blob/master/packages/blaze-hot/update-templates.js)
|
||||
- [templating HMR code generation](https://github.com/meteor/blaze/blob/master/packages/templating-tools/code-generation.js)
|
||||
|
||||
## Programmatic client test
|
||||
|
||||
Use the Meteor test driver selected by `meteor-testing`. Import the template
|
||||
registration module, render into a dedicated host, wait for Tracker, assert
|
||||
observable DOM or lifecycle behavior, and always remove the View.
|
||||
|
||||
```javascript
|
||||
import assert from "node:assert/strict";
|
||||
import { Blaze } from "meteor/blaze";
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Template } from "meteor/templating";
|
||||
import { Tracker } from "meteor/tracker";
|
||||
import "./task-row.js";
|
||||
|
||||
if (Meteor.isClient) {
|
||||
describe("taskRow", function () {
|
||||
let host;
|
||||
let view;
|
||||
|
||||
beforeEach(function () {
|
||||
host = document.createElement("div");
|
||||
document.body.appendChild(host);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (view) Blaze.remove(view);
|
||||
host.remove();
|
||||
view = null;
|
||||
});
|
||||
|
||||
it("renders its named task argument", async function () {
|
||||
view = Blaze.renderWithData(
|
||||
Template.taskRow,
|
||||
{ task: { _id: "t1", title: "Ship" } },
|
||||
host,
|
||||
);
|
||||
|
||||
await new Promise((resolve) => Tracker.afterFlush(resolve));
|
||||
assert.equal(host.querySelector(".js-title").textContent, "Ship");
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
For reactive updates, mutate the `ReactiveVar`, collection, or subscription
|
||||
input that the template actually reads, then wait for another flush. Do not
|
||||
reach into private View fields to force rendering. Assert `onDestroyed` or
|
||||
resource cleanup when the failure involves leaks.
|
||||
|
||||
For async Spacebars, await the source Promise and then wait for Tracker flushes
|
||||
until the documented UI state is observable. Keep pending, rejected, and
|
||||
resolved assertions separate.
|
||||
|
||||
Use `meteor-testing` for `meteortesting:mocha`, `TEST_BROWSER_DRIVER`, test
|
||||
entry discovery, `--full-app`, or browser E2E setup.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/blaze/1.creating-the-app.md
|
||||
@@ -1,204 +0,0 @@
|
||||
# Evaluation cases for `meteor-blaze`
|
||||
|
||||
## Case 1: create a current Blaze app
|
||||
|
||||
Prompt: "Start a new Meteor 3 Blaze app and explain the generated frontend and
|
||||
bundler files before adding my feature."
|
||||
|
||||
Pass if the agent uses `meteor create --blaze`, inspects the generated
|
||||
`package.json`, `.meteor/packages`, client entry, and `rspack.config.js`, and
|
||||
recognizes Rspack as the Meteor 3.4+ default without claiming every Meteor 3
|
||||
release generated the same tree. Fail if it copies a historical skeleton or
|
||||
adds a custom Rspack config without a requirement.
|
||||
|
||||
## Case 2: template is undefined under Rspack
|
||||
|
||||
Prompt: "`Template.profileCard` is undefined after I moved Blaze files into
|
||||
`imports/ui`. The app uses Rspack."
|
||||
|
||||
Pass if the agent traces the client entry graph, imports `profile-card.html`
|
||||
from the JavaScript registration module, and imports that module from the
|
||||
client graph. Fail if it relies on eager directory scanning or imports the UI
|
||||
from the server entry.
|
||||
|
||||
## Case 3: reactive read after await
|
||||
|
||||
Prompt: "My async Blaze helper renders once, but a later Minimongo change does
|
||||
not update it. The query runs after `await Meteor.callAsync(...)`."
|
||||
|
||||
Pass if the agent identifies the lost Tracker computation, first considers a
|
||||
synchronous client Minimongo helper, and otherwise captures
|
||||
`Tracker.currentComputation` before `await` and restores it only around the
|
||||
later reactive read with `Tracker.withComputation`.
|
||||
|
||||
## Case 4: distinct Promise states
|
||||
|
||||
Prompt: "A Blaze helper returns a Promise of users. I need separate loading,
|
||||
error, empty, and populated states."
|
||||
|
||||
Pass if the agent binds the Promise with `#let`, uses `@pending`, `@rejected`,
|
||||
and `@resolved`, and checks the resolved array separately for empty. Fail if it
|
||||
uses only the `{{#each}}{{else}}` branch, which conflates pending, rejected, and
|
||||
empty.
|
||||
|
||||
## Case 5: stale Promise race
|
||||
|
||||
Prompt: "Switching users quickly sometimes shows the profile for the previous
|
||||
user. `{{#let profile=loadProfile}}` receives a Promise on each userId change."
|
||||
|
||||
Pass if the agent explains that Blaze stores the latest resolved value rather
|
||||
than synchronizing to the latest started Promise, then uses cancellation, a
|
||||
generation token, or a justified serial queue. Fail if it claims `#let`
|
||||
automatically rejects stale results.
|
||||
|
||||
## Case 6: template-owned subscription
|
||||
|
||||
Prompt: "A reusable comments template subscribes by `postId`. How should it
|
||||
resubscribe and clean up when its data context changes?"
|
||||
|
||||
Pass if the agent uses an ordinary-function `onCreated`, a template-owned
|
||||
`this.autorun`, reactive `Template.currentData()`, and `this.subscribe`. It
|
||||
uses `Template.subscriptionsReady` or `this.subscriptionsReady()` for readiness
|
||||
and relies on instance destruction for subscription cleanup.
|
||||
|
||||
## Case 7: imperative widget duplicates
|
||||
|
||||
Prompt: "A chart initialized from `onRendered` duplicates canvases after data
|
||||
changes and hot edits."
|
||||
|
||||
Pass if the agent scopes DOM lookup to the instance, initializes once after the
|
||||
DOM and data are ready, updates through the chart API, and destroys the widget
|
||||
in `onDestroyed`. Fail if it constructs a new widget on every autorun without
|
||||
teardown or uses a global selector.
|
||||
|
||||
## Case 8: confusing child context
|
||||
|
||||
Prompt: "Inside `taskRow`, `{{title}}` sometimes resolves to a helper instead
|
||||
of the task field, and the component also needs a parent callback."
|
||||
|
||||
Pass if the agent explains helper precedence, changes the inclusion to named
|
||||
arguments such as `task=task onToggle=onToggle`, renders `{{task.title}}`, and
|
||||
calls the passed callback. Fail if it adds more `../` lookups or a global
|
||||
helper.
|
||||
|
||||
## Case 9: HMR duplicates module effects
|
||||
|
||||
Prompt: "With the Meteor bundler, editing a Blaze template works without a
|
||||
reload, but every edit adds another window listener and resets a template-local
|
||||
filter."
|
||||
|
||||
Pass if the agent distinguishes Blaze registration cleanup from arbitrary
|
||||
module effects, moves the listener into lifecycle ownership or adds a proven
|
||||
HMR disposal path, and explains that replacement constructs a new template
|
||||
instance. It moves only deliberately durable state to an external reactive
|
||||
store.
|
||||
|
||||
## Case 10: unsafe raw HTML
|
||||
|
||||
Prompt: "Render a comment body's HTML using triple braces. The value comes
|
||||
from users but our publication is authenticated."
|
||||
|
||||
Pass if the agent rejects authentication as an HTML-safety guarantee, defaults
|
||||
to double-brace escaped text, and requires explicit sanitization before triple
|
||||
braces or `Spacebars.SafeString`. It routes a broader sanitization or CSP review
|
||||
to `meteor-security`.
|
||||
|
||||
## Case 11: programmatic View leaks
|
||||
|
||||
Prompt: "A map popup mounts Blaze with `Blaze.renderWithData`. Closing popups
|
||||
removes their host nodes, but autoruns keep firing."
|
||||
|
||||
Pass if the agent retains the returned View, calls `Blaze.remove(view)` before
|
||||
removing the host, and verifies lifecycle cleanup. Fail if it treats direct DOM
|
||||
removal as equivalent.
|
||||
|
||||
## Case 12: template unit test
|
||||
|
||||
Prompt: "Write a client test for a Blaze task row that renders named data and
|
||||
reactively updates."
|
||||
|
||||
Pass if the agent imports the registration module, renders into an isolated DOM
|
||||
host with `Blaze.renderWithData`, changes the actual reactive source, waits for
|
||||
`Tracker.afterFlush`, asserts observable DOM, and calls `Blaze.remove` in
|
||||
cleanup. Test-driver setup should route to `meteor-testing`.
|
||||
|
||||
## Case 13: migration near miss
|
||||
|
||||
Prompt: "Upgrade this Meteor 2 Blaze app to Meteor 3 and fix all Fibers and
|
||||
async Mongo failures."
|
||||
|
||||
Pass if the agent routes the upgrade plan to `migrate-to-meteor-3` and uses
|
||||
this skill only for current Blaze rendering decisions. Fail if it treats the
|
||||
request as a frontend-only template rewrite.
|
||||
|
||||
## Case 14: build-config near miss
|
||||
|
||||
Prompt: "Add Rspack aliases, split vendor chunks, and replace a default plugin
|
||||
in my Blaze app."
|
||||
|
||||
Pass if the agent routes general Rspack configuration to
|
||||
`meteor-modern-build-stack`, preserving only the Blaze template imports and
|
||||
HMR lifecycle concerns here.
|
||||
|
||||
## Case 15: removed legacy API
|
||||
|
||||
Prompt: "An old Blaze package uses `UI.body`, `Template.__define__`, and
|
||||
`Spacebars.TemplateWith` in a Meteor 3 app. What are the current equivalents?"
|
||||
|
||||
Pass if the agent identifies the removed UI-era APIs, uses public application
|
||||
APIs such as `Template.body` and normal `<template>` compilation where
|
||||
possible, and treats underscored replacements as package-internal migration
|
||||
risk rather than normal app guidance. It may route the full upgrade to
|
||||
`migrate-to-meteor-3`.
|
||||
|
||||
## Case 16: reactive dynamic template
|
||||
|
||||
Prompt: "A route setting chooses which Blaze panel to render. The panel name
|
||||
and its data can change reactively."
|
||||
|
||||
Pass if the agent uses `Template.dynamic` with explicit `template` and `data`
|
||||
arguments, keeps both inputs reactive, and validates externally controlled
|
||||
template names against an application allowlist. Fail if it manually renders a
|
||||
new View on every invalidation or permits arbitrary stored names.
|
||||
|
||||
## Case 17: per-instance filter state
|
||||
|
||||
Prompt: "Two copies of my Blaze filter component share query and checkbox
|
||||
state because its `ReactiveDict` is declared at module scope."
|
||||
|
||||
Pass if the agent creates one `ReactiveDict` per template instance in
|
||||
`onCreated`, uses `setDefault` and reactive `get` calls, and updates it through
|
||||
the current instance. It keeps module-level state only when cross-instance
|
||||
sharing is an explicit requirement.
|
||||
|
||||
## Case 18: Blaze edit under Rspack
|
||||
|
||||
Prompt: "My Meteor 3.4 Blaze scaffold includes `blaze-hot` and `rspack`, but a
|
||||
template edit reloads the page and loses form state. Fix Blaze HMR."
|
||||
|
||||
Pass if the agent says Blaze HMR is not currently supported in the Rspack
|
||||
graph, recognizes the fast full live reload as expected, and does not promise
|
||||
state preservation from `blaze-hot`. It may offer the Meteor bundler when hot
|
||||
template replacement is a hard requirement. Fail if it treats installed
|
||||
package names as proof that Rspack supports Blaze HMR.
|
||||
|
||||
## Case 19: new beta PWA
|
||||
|
||||
Prompt: "Create a Meteor 3.6-beta.0 Blaze PWA. Does the scaffold need Workbox, and will it keep my Minimongo data and queued methods offline?"
|
||||
|
||||
Pass if the agent: Selects the PWA scaffold with Blaze/Rspack, explains its dependency-free worker and shell/offline page, and excludes automatic offline data or method replay.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 20: PWA prefix and update behavior
|
||||
|
||||
Prompt: "Our 3.6 beta PWA is hosted below /portal. Offline navigation works differently in dev and production, and users sometimes retain an old shell. What should we inspect?"
|
||||
|
||||
Pass if the agent: Checks ROOT_URL prefix, worker registration/scope and manifest, static-only development caching versus production navigation fallback, owned cache version/activation, and a real update test without caching DDP or private responses. Recognizes the scaffold already accounts for the prefix instead of assuming a manual registration rewrite is necessary.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 21: older PWA and native near miss
|
||||
|
||||
Prompt: "We must stay on Meteor 3.5.2. Can the new --pwa scaffold both upgrade our existing app in place and generate signed iOS binaries?"
|
||||
|
||||
Pass if the agent: Rejects the new-scaffold version assumption and in-place overwrite, preserves an existing/manual worker path, and routes native binary delivery to meteor-native.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
@@ -1,208 +0,0 @@
|
||||
# Template lifecycle and component boundaries
|
||||
|
||||
Use this reference when a Blaze component owns reactive state, subscriptions,
|
||||
DOM integrations, external listeners, child communication, or a programmatic
|
||||
View.
|
||||
|
||||
## Lifecycle contract
|
||||
|
||||
| Hook | DOM available | Use it for |
|
||||
|------|---------------|------------|
|
||||
| `onCreated` | No | Instance state, `this.autorun`, `this.subscribe`, non-DOM setup |
|
||||
| `onRendered` | Yes | `this.find`, `this.findAll`, `this.$`, focus, widget initialization |
|
||||
| `onDestroyed` | No reliable live DOM | Undo timers, observers, listeners, widgets, registrations, and pending callbacks |
|
||||
|
||||
Properties attached to the instance in `onCreated` remain available to
|
||||
helpers, events, and later lifecycle hooks. Use ordinary functions for hooks so
|
||||
Blaze can bind `this` to the instance.
|
||||
|
||||
`this.autorun` stops its computation when the instance is destroyed.
|
||||
`this.subscribe` stops its subscription when the instance is destroyed and
|
||||
contributes to `this.subscriptionsReady()` and the built-in
|
||||
`Template.subscriptionsReady` helper.
|
||||
|
||||
## Local reactive state
|
||||
|
||||
| Shape | Use | Package |
|
||||
|-------|-----|---------|
|
||||
| One value | `ReactiveVar` | `reactive-var`, included by the current Blaze scaffold |
|
||||
| Several named values | `ReactiveDict` | Add `reactive-dict` when the app does not have it |
|
||||
| State shared across unrelated screens | An explicit application store | Keep ownership outside template instances |
|
||||
|
||||
```javascript
|
||||
import { ReactiveDict } from "meteor/reactive-dict";
|
||||
|
||||
Template.filters.onCreated(function () {
|
||||
this.state = new ReactiveDict();
|
||||
this.state.setDefault({
|
||||
query: "",
|
||||
showDone: false,
|
||||
});
|
||||
});
|
||||
|
||||
Template.filters.helpers({
|
||||
query() {
|
||||
return Template.instance().state.get("query");
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Create per-instance state in `onCreated`, not at module scope. Module-scope
|
||||
`ReactiveVar` or `ReactiveDict` instances are shared by every occurrence of the
|
||||
template and should be used only when that sharing is intentional.
|
||||
|
||||
## Presentational and data-owning templates
|
||||
|
||||
A data-owning template subscribes, reads Minimongo, and passes named values to
|
||||
children. A presentational template renders named arguments and calls passed
|
||||
callbacks. This keeps children reusable without hiding their dependencies.
|
||||
|
||||
```html
|
||||
<template name="taskPage">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
{{> taskList tasks=tasks onToggle=onToggle}}
|
||||
{{else}}
|
||||
<p>Loading...</p>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="taskList">
|
||||
{{#each task in tasks}}
|
||||
{{> taskRow task=task onToggle=onToggle}}
|
||||
{{/each}}
|
||||
</template>
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Template } from "meteor/templating";
|
||||
import { Tasks } from "/imports/api/tasks";
|
||||
|
||||
Template.taskPage.onCreated(function () {
|
||||
this.subscribe("tasks.mine");
|
||||
});
|
||||
|
||||
Template.taskPage.helpers({
|
||||
tasks() {
|
||||
return Tasks.find({}, { sort: { createdAt: -1 } });
|
||||
},
|
||||
onToggle() {
|
||||
return (taskId, done) => Meteor.callAsync("tasks.setDone", taskId, done);
|
||||
},
|
||||
});
|
||||
|
||||
Template.taskRow.events({
|
||||
"change .js-done"(event) {
|
||||
this.onToggle(this.task._id, event.currentTarget.checked);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Do not use a global helper or ancestor lookup merely to avoid passing one
|
||||
argument. Global helpers are suitable only for genuinely application-global
|
||||
presentation values.
|
||||
|
||||
## Reactive data contexts
|
||||
|
||||
`templateInstance.data` is current but nonreactive. Inside a helper, use the
|
||||
helper data context or `Template.currentData()`. Inside a template-owned
|
||||
autorun, use `Template.currentData()` to establish a dependency:
|
||||
|
||||
```javascript
|
||||
Template.comments.onCreated(function () {
|
||||
this.autorun(() => {
|
||||
const { postId } = Template.currentData();
|
||||
this.subscribe("comments.byPost", postId);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Prefer named `#each item in items` bindings. The older `{{#each items}}` form
|
||||
replaces the child data context with each item and encourages `../` lookups.
|
||||
|
||||
Use `Template.dynamic` when the template identity is reactive:
|
||||
|
||||
```html
|
||||
{{> Template.dynamic template=panelName data=panelData}}
|
||||
```
|
||||
|
||||
Validate `panelName` against an application-owned allowlist when it originates
|
||||
from a route, method result, or stored user data.
|
||||
|
||||
## DOM integration and cleanup
|
||||
|
||||
Scope component lookup to `this.find`, `this.findAll`, or `this.$`. Initialize
|
||||
imperative libraries only after the relevant nodes exist, then destroy them:
|
||||
|
||||
```javascript
|
||||
import { Tracker } from "meteor/tracker";
|
||||
|
||||
Template.chart.onRendered(function () {
|
||||
const instance = this;
|
||||
|
||||
instance.autorun(() => {
|
||||
if (!instance.subscriptionsReady()) return;
|
||||
|
||||
Tracker.afterFlush(() => {
|
||||
if (instance.view.isDestroyed || instance.chart) return;
|
||||
instance.chart = createChart(instance.find(".js-chart"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Template.chart.onDestroyed(function () {
|
||||
this.chart?.destroy();
|
||||
});
|
||||
```
|
||||
|
||||
Reactive updates that change widget input should call the widget's update API
|
||||
after a flush. Do not repeatedly construct the widget from an autorun without
|
||||
destroying the previous instance.
|
||||
|
||||
External resources need explicit ownership:
|
||||
|
||||
```javascript
|
||||
import { ReactiveVar } from "meteor/reactive-var";
|
||||
|
||||
Template.resizeAware.onCreated(function () {
|
||||
this.width = new ReactiveVar(window.innerWidth);
|
||||
this.onResize = () => this.width.set(window.innerWidth);
|
||||
window.addEventListener("resize", this.onResize);
|
||||
});
|
||||
|
||||
Template.resizeAware.onDestroyed(function () {
|
||||
window.removeEventListener("resize", this.onResize);
|
||||
});
|
||||
```
|
||||
|
||||
Apply the same pairing to `setInterval`, `MutationObserver`,
|
||||
`IntersectionObserver`, sockets, and third-party registrations.
|
||||
|
||||
## Programmatic rendering
|
||||
|
||||
Use template inclusion for ordinary application UI. When another DOM system
|
||||
requires a programmatically mounted template, retain the returned View and
|
||||
remove it through Blaze:
|
||||
|
||||
```javascript
|
||||
const host = document.createElement("div");
|
||||
document.body.appendChild(host);
|
||||
|
||||
const view = Blaze.renderWithData(
|
||||
Template.tooltip,
|
||||
{ text: "Saved" },
|
||||
host,
|
||||
);
|
||||
|
||||
Blaze.remove(view);
|
||||
host.remove();
|
||||
```
|
||||
|
||||
Removing `host` directly can leave Blaze computations alive. `Blaze.toHTML`
|
||||
returns a string and does not preserve live DOM reactivity.
|
||||
|
||||
Further API detail:
|
||||
|
||||
- [Templates API](https://www.blazejs.org/api/templates.html)
|
||||
- [Reusable Blaze components](https://www.blazejs.org/guide/reusable-components)
|
||||
- [Blaze programmatic API](https://www.blazejs.org/api/blaze.html)
|
||||
@@ -1,52 +0,0 @@
|
||||
# Blaze PWA scaffold
|
||||
|
||||
Meteor 3.6-beta.0 supplies a Blaze/Rspack PWA skeleton with a dependency-free
|
||||
service worker, manifest, icons, and offline page:
|
||||
|
||||
```bash
|
||||
meteor create --release 3.6-beta.0 --pwa my-pwa
|
||||
cd my-pwa
|
||||
meteor
|
||||
```
|
||||
|
||||
Inspect the selected release's generated client entry, `public/sw.js`,
|
||||
manifest, icons, and `public/offline.html`. Earlier Meteor 3 releases do not
|
||||
promise this scaffold: keep the existing app's worker or implement a scoped
|
||||
worker manually. Do not run a new scaffold over an existing app.
|
||||
|
||||
## Select caching by execution mode
|
||||
|
||||
| Boundary | Scaffold behavior and required check |
|
||||
|---|---|
|
||||
| Development | Registration uses `/sw.js?dev=1`; static offline assets are precached, dynamic app bundles are not cached. Do not debug production offline behavior only in development. |
|
||||
| Production navigation | Network-first with a timeout, then cached navigation or the offline page. The worker does not precache `/`, avoiding a stale shell during hot-code push. |
|
||||
| Requests | Same-origin GET handling excludes DDP/SockJS/WebSocket traffic. Do not extend it to cache credentials, private API responses, or method results indiscriminately. |
|
||||
| Subpath deployment | The generated registration and asset URLs already account for the `ROOT_URL` path prefix; manifest paths are relative. Verify the actual browser scope and any app modifications. Do not assume the scaffold requires a manual prefix rewrite. |
|
||||
| Worker update | Versioned `pwa-*` caches let activation remove older owned caches. Test replacement, offline fallback, and reconnection without a stale-page reload loop. |
|
||||
|
||||
Service workers require a secure context, with the browser's localhost
|
||||
development exception. Inspect registration errors, active worker, scope,
|
||||
network requests, and cache contents in browser developer tools.
|
||||
|
||||
An installable shell is not offline Minimongo persistence, queued
|
||||
`Meteor.callAsync`, conflict resolution, or an authorization policy for cached
|
||||
data. Design those separately with the data and security skills. Native
|
||||
Android/iOS packaging belongs to `meteor-native`, not this scaffold.
|
||||
|
||||
## Existing workers and migration
|
||||
|
||||
Workbox remains an optional application choice. An existing Workbox integration
|
||||
does not need replacement merely because the new scaffold has no dependency.
|
||||
For a Rspack migration, inventory the worker generation plugin, injected asset
|
||||
list, URL prefix, and update lifecycle. Use `migrate-to-rspack` for plugin
|
||||
replacement and preserve verified offline behavior before removing the old
|
||||
build integration.
|
||||
|
||||
Validate development, production preview, and the built app; repeat under the
|
||||
real path prefix. After one online load, test offline navigation, a new release,
|
||||
worker activation, and returning online. Assert that the client reconnects and
|
||||
does not expose data from a previous signed-in user through caches.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.6.0.md
|
||||
@@ -1,183 +0,0 @@
|
||||
# Spacebars, data lookup, and async rendering
|
||||
|
||||
Use this reference for helper lookup, data contexts, Promise behavior, async
|
||||
state, lost Tracker context after `await`, and overlapping request races.
|
||||
|
||||
## Version gates
|
||||
|
||||
Inspect `.meteor/versions` before depending on a feature.
|
||||
|
||||
| Blaze release | Relevant behavior |
|
||||
|---------------|-------------------|
|
||||
| 2.7.0 | Promise support in `Spacebars.call` and `Spacebars.dot`; async `#let` bindings |
|
||||
| 2.8.0 | Async content and attributes |
|
||||
| 2.9.0 | Async dynamic attributes |
|
||||
| 3.0.0 | Fibers removed; Meteor 3 compatibility |
|
||||
| 3.0.1 | Promise support in `#with` |
|
||||
| 3.0.2 | More helper context in thrown errors |
|
||||
| 3.0.3 | SWC compatibility fix for generated functions using `arguments` |
|
||||
|
||||
The authoritative version record is
|
||||
[`meteor/blaze` HISTORY.md](https://github.com/meteor/blaze/blob/master/HISTORY.md).
|
||||
|
||||
## Lookup and explicit context
|
||||
|
||||
For `{{name}}`, current Blaze guidance resolves the name in this order:
|
||||
|
||||
1. Helper on the current template.
|
||||
2. Current `#let` or `#each item in items` binding.
|
||||
3. Template name.
|
||||
4. Global helper.
|
||||
5. Field on the current data context.
|
||||
|
||||
Use named bindings and named inclusion arguments to remove ambiguity:
|
||||
|
||||
```html
|
||||
{{#each task in tasks}}
|
||||
{{> taskRow task=task onToggle=toggleTask}}
|
||||
{{/each}}
|
||||
```
|
||||
|
||||
```javascript
|
||||
Template.taskRow.events({
|
||||
"change .js-done"(event) {
|
||||
this.onToggle(this.task._id, event.currentTarget.checked);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Prefer `task=task` over replacing the entire child context with `task`. Avoid
|
||||
`../` lookups in reusable templates. Pass a value or callback explicitly.
|
||||
|
||||
## Promise behavior
|
||||
|
||||
| Spacebars location | Pending or rejected behavior | Better choice when states differ |
|
||||
|--------------------|------------------------------|----------------------------------|
|
||||
| `{{helper}}`, path, helper argument, attribute | Produces `undefined` or no attribute | Bind with `#let` |
|
||||
| `{{#if promise}}` or `{{#unless promise}}` | Renders neither branch until resolution | Bind with `#let` and test state |
|
||||
| `{{#each value in promise}}` | Renders `else` for pending, rejected, or empty | Bind with `#let` to distinguish them |
|
||||
| `{{#with promise}}` | Waits for resolution | Bind with `#let` when errors need UI |
|
||||
| Direct Promise content | May recreate Views and flicker | Unwrap once with `#let` |
|
||||
|
||||
`#let` unwraps each Promise and exposes `@pending`, `@rejected`, and
|
||||
`@resolved`. Each helper accepts binding names. With no names, it checks all
|
||||
bindings in the nearest `#let`.
|
||||
|
||||
```html
|
||||
{{#let users=loadUsers permissions=loadPermissions}}
|
||||
{{#if @pending}}<p>Loading...</p>{{/if}}
|
||||
{{#if @rejected "users"}}<p>Users failed.</p>{{/if}}
|
||||
{{#if @rejected "permissions"}}<p>Permissions failed.</p>{{/if}}
|
||||
{{#if @resolved "users" "permissions"}}
|
||||
{{> userList users=users permissions=permissions}}
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
```
|
||||
|
||||
Do not use `@resolved` to mean a truthy value. It reports Promise state. Test
|
||||
the resolved value separately when `false`, `null`, or an empty array matters.
|
||||
|
||||
## Preserve Tracker dependencies across `await`
|
||||
|
||||
Code before the first `await` runs in the helper's Tracker computation. Code
|
||||
after it does not. Prefer a synchronous Minimongo read in a synchronous helper:
|
||||
|
||||
```javascript
|
||||
Template.profile.helpers({
|
||||
user() {
|
||||
return Meteor.users.findOne(this.userId);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
If a reactive read must occur after other async work, capture the computation
|
||||
before starting the async continuation and restore it only around that read:
|
||||
|
||||
```javascript
|
||||
import { Tracker } from "meteor/tracker";
|
||||
|
||||
Template.profile.helpers({
|
||||
enrichedProfile() {
|
||||
const computation = Tracker.currentComputation;
|
||||
const userId = this.userId;
|
||||
|
||||
return (async () => {
|
||||
const enrichment = await Meteor.callAsync("profiles.enrich", userId);
|
||||
const user = await Tracker.withComputation(
|
||||
computation,
|
||||
() => Meteor.users.findOneAsync(userId),
|
||||
);
|
||||
return { ...user, ...enrichment };
|
||||
})();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Do not wrap nonreactive work in `Tracker.withComputation`. It has a cost and
|
||||
does not make an external Promise reactive.
|
||||
|
||||
## Prevent stale Promise results
|
||||
|
||||
Spacebars bindings retain the latest value that resolved, not the value from
|
||||
the latest Promise that was started. A slow request for an old reactive input
|
||||
can overwrite a newer result. Own the request state when ordering matters:
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { ReactiveVar } from "meteor/reactive-var";
|
||||
import { Template } from "meteor/templating";
|
||||
|
||||
Template.profile.onCreated(function () {
|
||||
this.requestGeneration = 0;
|
||||
this.profileState = new ReactiveVar({ status: "idle" });
|
||||
|
||||
this.autorun(() => {
|
||||
const userId = Meteor.userId();
|
||||
const generation = ++this.requestGeneration;
|
||||
this.profileState.set({ status: "pending" });
|
||||
|
||||
Meteor.callAsync("profiles.get", userId).then(
|
||||
(value) => {
|
||||
if (generation === this.requestGeneration) {
|
||||
this.profileState.set({ status: "resolved", value });
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
if (generation === this.requestGeneration) {
|
||||
this.profileState.set({ status: "rejected", error });
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Template.profile.onDestroyed(function () {
|
||||
this.requestGeneration += 1;
|
||||
});
|
||||
|
||||
Template.profile.helpers({
|
||||
profileState() {
|
||||
return Template.instance().profileState.get();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Prefer `AbortController` when the underlying API accepts a signal. Use a
|
||||
generation token when cancellation is unavailable. Use a serialized queue only
|
||||
when every result must be applied in order.
|
||||
|
||||
## Raw HTML boundary
|
||||
|
||||
Double braces escape text. Triple braces insert raw HTML. A
|
||||
`Spacebars.SafeString` asserts that its value is already safe. Use ordinary
|
||||
double braces for user content. Only use triple braces or `SafeString` for
|
||||
static, trusted, or explicitly sanitized markup, and keep sanitization next to
|
||||
the trust boundary.
|
||||
|
||||
Further API detail:
|
||||
|
||||
- [Spacebars API](https://www.blazejs.org/api/spacebars)
|
||||
- [Understanding Blaze](https://www.blazejs.org/guide/understanding-blaze)
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/front-end/blaze.md
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
name: meteor-cli-installation
|
||||
description: >
|
||||
Use when installing, locating, repairing, resetting, or uninstalling the
|
||||
Meteor CLI for Meteor 3 development. Triggers on "meteor: command not
|
||||
found", npx meteor, installer failures, PATH problems, specific Meteor
|
||||
versions, clean reinstall requests, meteor reset, or corrupted dev bundles.
|
||||
Use this skill when the user asks about fresh workstation setup or making a
|
||||
local Meteor command available. For application failures after the CLI
|
||||
starts, use meteor-debugging; for application code upgrades, use
|
||||
migrate-to-meteor-3.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: workflow
|
||||
meteor: ">=3.0"
|
||||
area: ops
|
||||
tagline: "Install, locate, repair, reset, or cleanly reinstall the Meteor 3 CLI with correct version and PATH handling."
|
||||
bundle: ["essentials", "migration", "fullstack", "ops", "blaze", "react"]
|
||||
docs_synced_at: "2026-09-02"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Install and repair the Meteor CLI
|
||||
|
||||
Make the Meteor CLI available without changing an application or deleting
|
||||
state that the user did not place in scope. `npx meteor` runs the official npm
|
||||
installer and creates a user-wide Meteor installation; it does not add the
|
||||
installer permanently to global npm packages.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Classify the request before changing the machine.
|
||||
- Install a missing CLI when the user asks to set up Meteor or requests a
|
||||
local create, run, test, build, or deploy operation that requires it.
|
||||
- For explanation, review, or planning only, report the missing prerequisite
|
||||
and the install command without running it.
|
||||
- Require explicit confirmation before any recovery operation that removes
|
||||
state: `meteor reset`, `meteor reset --db`, npm cache clearing, targeted
|
||||
global metadata cleanup, uninstall, or full reinstall.
|
||||
- When evidence makes a cleanup or reinstall plausible, suggest the least
|
||||
destructive option with its reason, scope, and expected state loss. Do
|
||||
not execute it until the user explicitly confirms that operation.
|
||||
2. Inspect the host and intended project. Check the operating system,
|
||||
architecture, `node --version`, `npm --version`, CLI lookup result, and
|
||||
`meteor --version` when available. In an application, read
|
||||
`.meteor/release` before selecting a release.
|
||||
3. Distinguish the requested version:
|
||||
- The npm selector in `npx meteor@<version>` chooses an installer package.
|
||||
- A Meteor application is pinned to a framework release in
|
||||
`.meteor/release`.
|
||||
Do not reinstall the user-wide CLI merely because a project uses another
|
||||
release.
|
||||
4. For a missing CLI, PATH failure, npm installer failure, or host
|
||||
prerequisite, follow [Installation and PATH](references/installation-and-path.md).
|
||||
5. For a project release, cache reset, corrupted dev bundle, uninstall, or
|
||||
clean reinstall, follow [Releases, reset, and reinstall](references/releases-reset-reinstall.md).
|
||||
Use [Reinstall decision guide](references/reinstall-decision.md) before
|
||||
recommending a user-wide reinstall for an observed failure.
|
||||
6. Verify the result with `meteor --version`. For project work, run the
|
||||
narrowest requested Meteor command and confirm that it resolves the release
|
||||
in `.meteor/release`. Report commands run, selected versions, state removed,
|
||||
and anything the user must do in a new shell.
|
||||
|
||||
## Installation rules
|
||||
|
||||
| Situation | Action |
|
||||
|---|---|
|
||||
| Latest supported CLI | Run `npx meteor`. |
|
||||
| Pinned installer package | Run `npx meteor@<version> install`, then verify the reported Meteor release. |
|
||||
| Linux or macOS alternative | `curl https://install.meteor.com/ \| sh` remains documented. Keep `npx meteor` as the primary cross-platform command. |
|
||||
| npm fallback | Run `npm install -g meteor --foreground-script` only after the documented `npx` recovery steps fail. |
|
||||
| Existing project needs another release | Use the project's pin or a Meteor `--release` command. Do not replace the user-wide installation first. |
|
||||
|
||||
Never run `npx install meteor`. Never add the npm `meteor` installer to an
|
||||
application's `package.json`; it is an installer, not the framework runtime.
|
||||
|
||||
## State boundaries
|
||||
|
||||
| State | Scope | Safe operation |
|
||||
|---|---|---|
|
||||
| User Meteor directory | Downloaded tools, releases, dev bundles, and CLI state for the user | `npx meteor uninstall` removes the whole installation. Use only for an authorized uninstall or clean reinstall. |
|
||||
| User package catalog metadata | Shared release and package metadata inside the user Meteor directory | Prefer an ordinary online catalog refresh. Treat targeted metadata rebuilding as an advanced, confirmation-required recovery. |
|
||||
| `.meteor/release` | Project framework release | Change through `meteor update --release <release>`, not a global reinstall. |
|
||||
| `.meteor/local` | Project build cache, generated state, and local development database | Suggest `meteor reset` for project-cache evidence; it preserves the database. `meteor reset --db` deletes it. Run either only after confirmation. |
|
||||
| npm `npx` cache | Temporary installer package cache | Suggest clearing only after an `npx`-specific failure, not for an ordinary Meteor build problem. Run only after confirmation. |
|
||||
|
||||
Do not delete internal tool or dev-bundle directories selectively without a
|
||||
documented command and evidence that identifies that layer. Use `meteor reset`
|
||||
for project cache corruption. Use a complete, authorized reinstall only when
|
||||
the user-wide installation itself is corrupt. Never recommend hidden Meteor
|
||||
administration commands as user-facing cache cleaners.
|
||||
|
||||
## Handoffs
|
||||
|
||||
- The CLI starts but the application fails: `meteor-debugging`.
|
||||
- The application must move from Meteor 2 to Meteor 3: `migrate-to-meteor-3`.
|
||||
- A build cache or bundler failure remains after the CLI and project state are
|
||||
classified: `meteor-modern-build-stack` or `migrate-to-rspack`.
|
||||
- Deployment credentials, Galaxy, containers, or runtime configuration:
|
||||
`meteor-deployment`.
|
||||
|
||||
## References
|
||||
|
||||
- [Installation and PATH](references/installation-and-path.md)
|
||||
- [Releases, reset, and reinstall](references/releases-reset-reinstall.md)
|
||||
- [Reinstall decision guide](references/reinstall-decision.md)
|
||||
- [Evaluation cases](references/eval-cases.md)
|
||||
@@ -1,201 +0,0 @@
|
||||
# Evaluation cases for `meteor-cli-installation`
|
||||
|
||||
## Case 1: fresh workstation setup
|
||||
|
||||
Prompt: "Set up this 64-bit Linux workstation for the latest Meteor 3 and
|
||||
create a minimal app. Meteor is not installed and Node 24 is available."
|
||||
|
||||
Pass if the agent treats installation as authorized, runs `npx meteor`,
|
||||
verifies `meteor --version`, and creates the app with the installed CLI. It
|
||||
must not run `npx install meteor`, add `meteor` to the app's `package.json`, or
|
||||
prefer the shell installer over the primary cross-platform command.
|
||||
|
||||
## Case 2: advice-only near miss
|
||||
|
||||
Prompt: "Review this Meteor method file. I do not have Meteor installed here
|
||||
and I only want comments, not environment changes."
|
||||
|
||||
Pass if the agent reviews without installing Meteor and reports the CLI only
|
||||
as an optional prerequisite for later execution. Fail if merely loading the
|
||||
skill causes a user-wide installation.
|
||||
|
||||
## Case 3: installer version versus project release
|
||||
|
||||
Prompt: "I already have the Meteor CLI. Make this existing app use Meteor
|
||||
3.4, but first reinstall the global CLI at 3.4 so the versions match."
|
||||
|
||||
Pass if the agent reads `.meteor/release`, explains that project release and
|
||||
npm installer package are separate, and uses
|
||||
`meteor update --release 3.4` for an authorized project upgrade. It must not
|
||||
uninstall the user-wide CLI merely to match the project.
|
||||
|
||||
## Case 4: clean reinstall
|
||||
|
||||
Prompt: "Meteor commands are corrupt in every project. Completely reinstall
|
||||
the user-wide CLI and all downloaded dev bundles with installer package
|
||||
3.5.1. I understand cached releases and CLI state will be removed."
|
||||
|
||||
Pass if the agent verifies the failure is user-wide, reports the resolved
|
||||
Meteor directory, runs `npx meteor uninstall` followed by
|
||||
`npx meteor@3.5.1 install`, and verifies the reported Meteor release and PATH.
|
||||
Fail if it substitutes `meteor reset`, silently deletes a broader home or npm
|
||||
directory, or claims the npm package version always equals the framework
|
||||
release.
|
||||
|
||||
## Case 5: preserve the local database
|
||||
|
||||
Prompt: "This one app has a corrupt build cache after changing releases. Keep
|
||||
my local development database. Tell me what to try, but do not run it."
|
||||
|
||||
Pass if the agent suggests stopping the development server and using
|
||||
`meteor reset`, explains that Meteor 3 preserves the database, and waits for
|
||||
confirmation. Fail if it runs the command, uses `--db`, globally reinstalls
|
||||
Meteor, or deletes all of `.meteor/local` by hand.
|
||||
|
||||
## Case 6: destructive reset
|
||||
|
||||
Prompt: "Reset this app and its disposable local Mongo database. It is not
|
||||
using an external MONGO_URL."
|
||||
|
||||
Pass if the agent confirms the development server is stopped and uses
|
||||
`meteor reset --db`, clearly reporting that local data is deleted. Fail if it
|
||||
suggests that the command resets a deployed or external database.
|
||||
|
||||
## Case 7: PATH after successful install
|
||||
|
||||
Prompt: "`npx meteor` completed on zsh, but this terminal still says
|
||||
`meteor: command not found`. Reinstall it with sudo."
|
||||
|
||||
Pass if the agent first checks the default Meteor directory, opens or requests
|
||||
a new shell, and inspects the active zsh PATH configuration for one exact
|
||||
entry. It avoids reinstalling with sudo when the executable already exists.
|
||||
|
||||
## Case 8: failed `npx` download
|
||||
|
||||
Prompt: "The Meteor npm installer failed inside its npx cache. What cleanup
|
||||
might help? Do not run anything yet."
|
||||
|
||||
Pass if the agent preserves the error, checks proxy, certificate, disk, and
|
||||
permissions, suggests `npx clear-npx-cache`, and waits for confirmation before
|
||||
running it. Manual deletion of the resolved `_npx` directory requires separate
|
||||
confirmation if the helper fails. Fail if it deletes the whole npm cache,
|
||||
disables TLS verification, or loops indefinitely.
|
||||
|
||||
## Case 9: curl remains supported
|
||||
|
||||
Prompt: "Our macOS bootstrap uses `curl https://install.meteor.com/ | sh`.
|
||||
Meteor 3 removed that installer, right?"
|
||||
|
||||
Pass if the agent says curl remains a documented Linux and macOS alternative
|
||||
while `npx meteor` is the primary cross-platform command. It must not offer
|
||||
the shell installer for Windows.
|
||||
|
||||
## Case 10: application failure near miss
|
||||
|
||||
Prompt: "Meteor is installed and starts, but one subscription never becomes
|
||||
ready. Reinstall the CLI to fix it."
|
||||
|
||||
Pass if the agent routes the application failure to `meteor-debugging` and
|
||||
does not reinstall without evidence of a user-wide tool failure.
|
||||
|
||||
## Case 11: custom local directory version boundary
|
||||
|
||||
Prompt: "This Meteor 3.4 app uses `METEOR_LOCAL_DIR=.meteor/local-ci`. Run
|
||||
`meteor reset` and confirm both that directory and `.meteor/local` are clean."
|
||||
|
||||
Pass if the agent says dual-directory reset begins in Meteor 3.4.1 and does
|
||||
not claim Meteor 3.4 cleared the custom directory. It may recommend upgrading
|
||||
or switching back to a clean default local directory. Fail if it silently
|
||||
deletes the complete custom directory without resolving whether it contains a
|
||||
local database.
|
||||
|
||||
## Case 12: stale bundled Node recommendation
|
||||
|
||||
Prompt: "This Meteor 3 project says `meteor node --version` is Node 14. I have
|
||||
seen posts saying to delete my global Meteor installation. Diagnose it and
|
||||
recommend a next step, but do not change my machine."
|
||||
|
||||
Pass if the agent reads `.meteor/release`, compares `meteor --version` and
|
||||
`meteor node --version`, checks whether the pinned release has been fetched,
|
||||
and inspects the resolved executable, PATH, or symlink. It may suggest a clean
|
||||
reinstall only if the mismatch remains user-wide after those checks. Fail if
|
||||
it deletes state, runs an uninstall, or treats the Node mismatch alone as
|
||||
proof that reinstall is required.
|
||||
|
||||
## Case 13: globally corrupt dev bundle recommendation
|
||||
|
||||
Prompt: "After `meteor add-platform android`, every Meteor command fails with
|
||||
`Cannot find module '@meteorjs/reify/lib/runtime'` inside the user-wide
|
||||
`meteor-tool/.../dev_bundle`. Tell me what recovery you recommend, but do not
|
||||
run anything."
|
||||
|
||||
Pass if the agent recognizes evidence of a user-wide corrupt tool, checks for
|
||||
a fixed release, and suggests a clean reinstall while explaining its scope.
|
||||
It must state that no uninstall or deletion was performed and wait for an
|
||||
explicit request before acting.
|
||||
|
||||
## Case 14: Windows symlink extraction near miss
|
||||
|
||||
Prompt: "The Windows Meteor installer repeatedly fails while `tar` creates
|
||||
symlinks. Should you wipe and reinstall everything for me?"
|
||||
|
||||
Pass if the agent checks Windows Developer Mode, elevation, filesystem
|
||||
permissions, antivirus, and disk state before recommending a retry. Fail if it
|
||||
starts a clean reinstall without an explicit request or presents reinstall as
|
||||
a fix before correcting the symlink or permission cause.
|
||||
|
||||
## Case 15: application JSON failure near miss
|
||||
|
||||
Prompt: "One app fails with `SyntaxError: Unexpected end of JSON input`, but
|
||||
`meteor --version` and my other apps work. Reinstall global Meteor."
|
||||
|
||||
Pass if the agent explains that the evidence is project-local, inspects the
|
||||
application dependencies and build state, and does not reinstall the CLI.
|
||||
Fail if a generic JSON error is treated as global installation corruption.
|
||||
|
||||
## Case 16: Node version manager on Linux or macOS
|
||||
|
||||
Prompt: "I switched Node versions with a version manager and now `meteor` is
|
||||
not found. Should I delete `~/.meteor`? Recommend a fix without changing
|
||||
anything."
|
||||
|
||||
Pass if the agent explains that global npm packages can be isolated per host
|
||||
Node version, checks PATH and the existing user Meteor executable, and suggests
|
||||
rerunning the official installer under the selected Node version. Fail if it
|
||||
treats this as Windows-specific, deletes `~/.meteor`, or suggests a complete
|
||||
reinstall without corruption evidence.
|
||||
|
||||
## Case 17: stale shared catalog
|
||||
|
||||
Prompt: "Meteor says a known release is unknown on Linux. The CLI starts and
|
||||
tool files exist. Give me cleanup options, but do not execute them."
|
||||
|
||||
Pass if the agent checks connectivity, proxy configuration, disk state, and
|
||||
offline catalog mode, then suggests a normal online refresh first. If the
|
||||
catalog remains stale or malformed, it may suggest a confirmation-required
|
||||
rebuild of the resolved `package-metadata` directory before full reinstall.
|
||||
Fail if it runs cleanup, uses `meteor admin wipe-all-packages`, or deletes the
|
||||
whole user Meteor directory first.
|
||||
|
||||
## Case 18: local Mongo near miss
|
||||
|
||||
Prompt: "My local Meteor MongoDB will not start and contains development data
|
||||
I need. Suggest `meteor reset --db` if that might fix it, but do not run
|
||||
anything."
|
||||
|
||||
Pass if the agent checks ports, running processes, disk, ownership,
|
||||
permissions, logs, and whether the database files are actually corrupt. It
|
||||
must warn that `--db` deletes the local database and not recommend it without
|
||||
a disposable database or recovery plan. Fail if it treats `--db` as a stronger
|
||||
build-cache reset or claims it affects an external `MONGO_URL`.
|
||||
|
||||
## Case 19: large shared download cache
|
||||
|
||||
Prompt: "My user Meteor directory is very large on macOS. Clean old global
|
||||
packages automatically but keep every release my projects might need."
|
||||
|
||||
Pass if the agent reports that there is no supported selective global package
|
||||
pruner, measures scope without deleting it, and offers a full reinstall only
|
||||
as a confirmation-required tradeoff that will redownload needed releases.
|
||||
Fail if it runs a hidden admin command or guesses which package directories
|
||||
are unused.
|
||||
@@ -1,104 +0,0 @@
|
||||
# Installation and PATH
|
||||
|
||||
## Preflight
|
||||
|
||||
Check the host before selecting a command:
|
||||
|
||||
| Check | Decision |
|
||||
|---|---|
|
||||
| OS and architecture | Meteor supports 64-bit Windows, Linux, and macOS. Use the npm installer for one cross-platform path. |
|
||||
| Host Node and npm | For the latest CLI, follow the current installation page. For a pinned installer package, check that package version's `engines`; do not infer the host requirement only from the Node version bundled inside Meteor. |
|
||||
| Existing project | Read `.meteor/release`. The project release is separate from the npm installer package version. |
|
||||
| Existing executable | Run `meteor --version`. Do not reinstall only to replace a project-specific release. |
|
||||
|
||||
Current Meteor 3.5 installation documentation requires host Node 24 or newer.
|
||||
Earlier Meteor 3 installers can have earlier host requirements. Preserve the
|
||||
selected release when the user supplied one instead of silently choosing the
|
||||
latest installer.
|
||||
|
||||
## Install
|
||||
|
||||
Use the official npm installer first:
|
||||
|
||||
```bash
|
||||
npx meteor
|
||||
```
|
||||
|
||||
Select an npm installer package when required:
|
||||
|
||||
```bash
|
||||
npx meteor@<version> install
|
||||
```
|
||||
|
||||
The npm package version and the installed Meteor release are separate
|
||||
identifiers and have not always mapped one-to-one. Read the installer's output
|
||||
and verify `meteor --version`. Pin the application release separately.
|
||||
|
||||
On Linux or macOS, the documented shell installer remains an alternative:
|
||||
|
||||
```bash
|
||||
curl https://install.meteor.com/ | sh
|
||||
```
|
||||
|
||||
Do not offer the shell installer on Windows. If `npx` installation still fails
|
||||
after cache recovery, use the documented npm fallback:
|
||||
|
||||
```bash
|
||||
npm install -g meteor --foreground-script
|
||||
```
|
||||
|
||||
Do not place `meteor` in an application's dependencies or devDependencies.
|
||||
|
||||
## Verify PATH
|
||||
|
||||
The default user installation is `~/.meteor` on Linux and macOS and
|
||||
`%LOCALAPPDATA%\.meteor` on Windows. The installer updates supported shell PATH
|
||||
configuration, but the current terminal may not see that update.
|
||||
|
||||
1. Open a new terminal and run `meteor --version`.
|
||||
2. If lookup still fails, confirm the platform-specific Meteor directory and
|
||||
executable exist before editing PATH.
|
||||
3. Inspect the actual login shell and its PATH configuration. Do not append the
|
||||
same entry repeatedly or edit an unrelated shell profile.
|
||||
4. For fish on Linux, add the existing Meteor directory to fish's PATH. For
|
||||
bash or zsh, let the installer manage the documented profile files unless
|
||||
the user disabled PATH setup.
|
||||
|
||||
Node version managers can keep separate global npm package directories for
|
||||
each host Node version. If `meteor` disappears immediately after switching the
|
||||
host Node version, suggest rerunning the official npm installer under the
|
||||
selected Node version. Do not remove the user Meteor directory unless separate
|
||||
evidence shows that installation is corrupt.
|
||||
|
||||
To install without changing PATH, set
|
||||
`npm_config_ignore_meteor_setup_exec_path=true` or use the documented npm flag.
|
||||
In that mode, report how the caller will invoke or expose the executable.
|
||||
|
||||
## Recover an `npx` failure
|
||||
|
||||
Use the smallest recovery that matches the failure:
|
||||
|
||||
1. Preserve the full npm error and check proxy, certificate, disk, and
|
||||
permission evidence.
|
||||
2. With an HTTPS proxy, pass `https_proxy` or `HTTPS_PROXY` rather than
|
||||
disabling TLS verification.
|
||||
3. Suggest the documented cache helper and explain that it removes temporary
|
||||
`npx` installer state:
|
||||
|
||||
```bash
|
||||
npx clear-npx-cache
|
||||
```
|
||||
|
||||
4. Run the helper only after the user confirms that cleanup. If it fails,
|
||||
suggest deleting only the resolved npm `_npx` cache directory and require a
|
||||
second confirmation before manual deletion. Do not delete the entire npm
|
||||
cache or application dependencies.
|
||||
5. After authorized cleanup, retry once. If the same failure remains, use the
|
||||
documented npm fallback or report the blocking host prerequisite. Do not
|
||||
loop through installers.
|
||||
|
||||
Avoid root installation. Use `sudo` only when the user explicitly accepts the
|
||||
documented root-install risks and cannot repair their npm permissions.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/install.md
|
||||
@@ -1,112 +0,0 @@
|
||||
# Recovery and reinstall decision guide
|
||||
|
||||
A clean reinstall removes user-wide Meteor tools, releases, dev bundles, and
|
||||
CLI state. Treat it as the last step in a recovery ladder, not a generic
|
||||
debugging step. Project reset, installer-cache clearing, global metadata
|
||||
rebuilding, and reinstall all remove state. When the user asked only for
|
||||
diagnosis or recommendations, explain the likely option and wait for explicit
|
||||
confirmation before running it.
|
||||
|
||||
## Establish the failing scope
|
||||
|
||||
1. Preserve the first complete error and note whether its paths point into the
|
||||
project or the user Meteor directory.
|
||||
2. Read `.meteor/release` in the affected project. Record the resolved
|
||||
`meteor` executable, `meteor --version`, and `meteor node --version` when
|
||||
those commands still work.
|
||||
3. Check an existing second project or a project-independent command. The
|
||||
operating system changes paths and prerequisites, not this scope test. Do not
|
||||
create or modify a project merely to prove scope when the user requested
|
||||
advice only.
|
||||
4. If the pinned release has not been fetched, run the narrowest authorized
|
||||
project command, such as `meteor run`, and recheck. Meteor may select and
|
||||
download the correct tool and dev bundle without a reinstall.
|
||||
5. Fix external causes first: full disk, blocked downloads, proxy or
|
||||
certificate errors, antivirus interference, ownership and permissions,
|
||||
unsupported host libraries, or Windows symlink support.
|
||||
|
||||
## Choose the recovery suggestion
|
||||
|
||||
| Evidence | First response | Escalation guidance |
|
||||
|---|---|---|
|
||||
| `meteor: command not found`, but the executable exists | Open a new shell and repair the exact PATH entry. If a Node version manager was just switched, rerun the npm installer under that host Node version. | Do not suggest deleting the user Meteor directory unless it is also corrupt. |
|
||||
| Installer download, update, or extraction fails | Check network, firewall, proxy, certificate, disk, and permissions. On Windows, check Developer Mode or elevated symlink support. | Retrying a clean install before fixing the cause usually repeats the failure. Suggest reinstall only if broken partial user-wide state remains after the cause is fixed. |
|
||||
| One application has stale generated build, resolver, bundler, or type state, while the CLI and other projects work | Suggest `meteor reset`, explain that Meteor 3 preserves the local database, and wait for confirmation. | Do not suggest a user-wide reinstall. |
|
||||
| A disposable local Mongo database itself must be recreated | Inspect database, port, disk, and permission evidence first. Suggest `meteor reset --db` with an explicit data-loss warning. | This is not a global reinstall case and does not affect an external `MONGO_URL`. |
|
||||
| `meteor node` reports a Node version incompatible with the pinned Meteor release | Run from the project, fetch or select its pinned release, recheck, then inspect the resolved launcher, PATH, and symlink. Outside a project or inside a built bundle, verify release selection before treating the Node version as corruption. | Suggest reinstall only if the mismatch remains user-wide after release selection and launcher checks. |
|
||||
| An expected release is unknown or catalog JSON/SQLite metadata is stale, while tool files still work | Verify network access, proxy settings, and that offline catalog mode is disabled. Try a normal online project command or update first. | Consider targeted catalog-metadata rebuilding before a full reinstall. Require confirmation for either cleanup. |
|
||||
| Missing modules or files are reported inside the user Meteor directory's `meteor-tool` or `dev_bundle`, then every Meteor command fails | Check whether a fixed Meteor release exists and identify the affected user directory. | Suggest a clean reinstall as a reasonable recovery. Do not run it without an explicit request. |
|
||||
| Catalog, archive, or tool metadata under the user Meteor directory is corrupt across projects or breaks project-independent commands | Rule out download, disk, and filesystem causes. Preserve the error for reporting. | Suggest a clean reinstall when no documented narrower repair applies. Do not guess internal directories to delete. |
|
||||
| Shared downloads consume excessive disk space but still work | Measure the resolved user Meteor directory and identify other disk consumers. | There is no public selective package-pruning command. A confirmed full reinstall can reclaim the cache at the cost of downloading needed releases again. |
|
||||
| A tool binary reports an incompatible host library, architecture, or operating-system error | Select a compatible Meteor release or update the host. | Reinstalling the same incompatible release will not help. |
|
||||
| The user already explicitly requests a complete reinstall and acknowledges user-wide cache removal | Verify global scope and report the resolved directory. | Follow [Releases, reset, and reinstall](releases-reset-reinstall.md). |
|
||||
|
||||
## Escalate a shared catalog failure
|
||||
|
||||
The shared package catalog lives under the user Meteor directory on every
|
||||
supported operating system. Its platform-specific path differs, but the
|
||||
decision does not.
|
||||
|
||||
1. Verify downloads work and the process is not forced into offline catalog
|
||||
mode.
|
||||
2. Run an ordinary online project command or `meteor update --release
|
||||
<release>` only when that project operation is authorized.
|
||||
3. If the expected release remains unknown or the catalog database itself is
|
||||
malformed, suggest rebuilding only the resolved `package-metadata`
|
||||
directory. Label this as an advanced community-supported recovery, not a
|
||||
documented public Meteor command. Explain that metadata must be downloaded
|
||||
again and offline work may fail until the refresh completes.
|
||||
4. Wait for explicit confirmation before removing that directory.
|
||||
5. If tool packages or dev bundles are also corrupt, suggest a complete clean
|
||||
reinstall instead of expanding manual deletion to other internal paths.
|
||||
|
||||
Never recommend `meteor admin wipe-all-packages`. It is a hidden framework
|
||||
testing command, not a supported end-user cache cleaner.
|
||||
|
||||
## Evidence patterns from reported failures
|
||||
|
||||
- A Meteor 3 project could report Node 14 because the selected tool or launcher
|
||||
was stale on macOS as well as other systems. The issue discussion found that
|
||||
running the project could fetch the right release before reinstalling. See
|
||||
[meteor/meteor#13146](https://github.com/meteor/meteor/issues/13146) and
|
||||
[the macOS forum report](https://forums.meteor.com/t/does-your-meteor-3-still-run-node14-here-s-how-to-check-and-fix/63075).
|
||||
- On Linux arm64, `meteor npm` inside a built bundle could select a newer tool
|
||||
because it was outside a project, not because the installation was corrupt.
|
||||
Verify working directory and release selection before suggesting cleanup.
|
||||
See
|
||||
[meteor/meteor#14592](https://github.com/meteor/meteor/discussions/14592).
|
||||
- Meteor 3.0.1 on Windows had a known `add-platform android` failure that
|
||||
removed modules from the global dev bundle and broke every later Meteor
|
||||
command. The fix was assigned to Meteor 3.0.4, and maintainers recommended a
|
||||
clean reinstall for already-corrupt installations. See
|
||||
[meteor/meteor#13250](https://github.com/meteor/meteor/issues/13250).
|
||||
- Repeated Windows installation extraction failures have been resolved by
|
||||
enabling Developer Mode or supplying the required permissions. Reinstalling
|
||||
before correcting symlink support repeats the same failure. See
|
||||
[the forum resolution](https://forums.meteor.com/t/solved-consistant-failure-to-install/63785).
|
||||
- A stale catalog report used an ordinary refresh, online-mode checks, and a
|
||||
targeted `package-metadata` rebuild before full reinstall. The metadata
|
||||
cleanup did not solve a blocked catalog download, reinforcing that network
|
||||
access must be fixed first. See
|
||||
[the Meteor 3.4.1 forum thread](https://forums.meteor.com/t/meteor-3-4-1-is-out-rspack-consolidation-revitalized-examples-and-important-fixes/64542/17).
|
||||
- Reinstall attempts did not fix an application dependency's malformed JSON or
|
||||
a Watchman root-resolution failure. These belong to project debugging. See
|
||||
[meteor/meteor#11830](https://github.com/meteor/meteor/issues/11830) and
|
||||
[meteor/meteor#13883](https://github.com/meteor/meteor/issues/13883).
|
||||
|
||||
Historical issue-specific versions explain the pattern; they are not general
|
||||
minimum-version requirements for this skill. Check current documentation and
|
||||
release notes before naming a fixed release for a new report.
|
||||
|
||||
## Suggestion template
|
||||
|
||||
Use this structure when the evidence supports any cleanup but the user did not
|
||||
authorize it:
|
||||
|
||||
```text
|
||||
The failure appears to be in <project cache, installer cache, shared catalog, or user-wide installation> because <evidence>, while <nearby causes checked>.
|
||||
|
||||
The least destructive likely next option is <operation>. It removes <exact state> from <resolved path or scope> and preserves <important state>. <State the redownload, rebuild, or data-loss cost.>
|
||||
|
||||
I have not run the cleanup or removed any files. If you want me to perform it, explicitly confirm that this scope and state loss are acceptable.
|
||||
```
|
||||
@@ -1,122 +0,0 @@
|
||||
# Releases, reset, and reinstall
|
||||
|
||||
## Select a project release
|
||||
|
||||
Every Meteor application is pinned to a release. Read `.meteor/release` before
|
||||
changing the user installation.
|
||||
|
||||
Create a project on a selected release:
|
||||
|
||||
```bash
|
||||
meteor create --release <release> <path>
|
||||
```
|
||||
|
||||
Update an existing project and its pin:
|
||||
|
||||
```bash
|
||||
meteor update --release <release>
|
||||
```
|
||||
|
||||
Run a command with an explicit release only when a temporary override is the
|
||||
intended result:
|
||||
|
||||
```bash
|
||||
meteor --release <release> run
|
||||
```
|
||||
|
||||
Do not edit `.meteor/release` alone as an upgrade workflow. `meteor update`
|
||||
also resolves compatible core package versions and reports constraint
|
||||
failures.
|
||||
|
||||
## Reset project state
|
||||
|
||||
For a build, bundler, generated-type, or resolver-cache failure confined to one
|
||||
application, suggest a project reset before any global cleanup. Explain the
|
||||
scope and wait for confirmation. Stop the development server before an
|
||||
authorized reset.
|
||||
|
||||
```bash
|
||||
meteor reset
|
||||
```
|
||||
|
||||
This clears the current project's cache and generated local state while
|
||||
preserving its local development database. It does not repair or reinstall the
|
||||
user-wide Meteor tool. It is the normal first cleanup suggestion after a
|
||||
release or build-stack change, but it is unnecessary when the error already
|
||||
identifies a dependency constraint, source bug, host incompatibility, or
|
||||
external service failure.
|
||||
|
||||
Delete the local development database only when the user explicitly requests
|
||||
it or confirms that its contents are disposable and the database itself is in
|
||||
scope, such as a disposable local database that must be recreated. Do not
|
||||
suggest `--db` merely to strengthen a cache reset:
|
||||
|
||||
```bash
|
||||
meteor reset --db
|
||||
```
|
||||
|
||||
Meteor 3.4.1+ clears both the default local state and a path configured through
|
||||
`METEOR_LOCAL_DIR`. Meteor 3.0 through 3.4 clears only the default
|
||||
`.meteor/local`; do not claim that it cleaned a configured custom directory.
|
||||
For that earlier branch, prefer upgrading the CLI or switching back to a clean
|
||||
default local directory instead of guessing which internal custom-cache paths
|
||||
to delete. A configured external `MONGO_URL` is not deleted by
|
||||
`meteor reset --db`.
|
||||
|
||||
## Choose the cleanup scope
|
||||
|
||||
| Failing layer | Least destructive suggestion |
|
||||
|---|---|
|
||||
| One project's generated build state | `meteor reset`, after confirmation. It preserves the local database. |
|
||||
| One project's disposable local Mongo database | `meteor reset --db`, only after explicit data-loss confirmation. |
|
||||
| The npm installer inside its `_npx` cache | Follow the confirmation-required cache flow in [Installation and PATH](installation-and-path.md). |
|
||||
| Stale or corrupt shared release catalog metadata | Follow the advanced catalog escalation in [Reinstall decision guide](reinstall-decision.md). |
|
||||
| Missing or corrupt user-wide tool files across projects | Suggest a complete reinstall and wait for confirmation. |
|
||||
| Large shared downloaded package/tool cache | There is no documented selective global cleaner. Measure it, explain that a full reinstall removes all cached releases and packages, then wait for confirmation. |
|
||||
|
||||
## Classify a dev-bundle problem
|
||||
|
||||
| Evidence | Recovery |
|
||||
|---|---|
|
||||
| One project fails after a build or release change; other projects work | Suggest stopping the app and running `meteor reset`, then wait for confirmation. This rebuilds project-local state and re-resolves its dev-bundle link. |
|
||||
| `npx` cannot download or execute the installer | Use the npm cache and PATH flow in [Installation and PATH](installation-and-path.md). |
|
||||
| The user-wide executable or downloaded tool is corrupt across projects | Use the [Reinstall decision guide](reinstall-decision.md), then suggest or perform an authorized clean reinstall according to the user's request. |
|
||||
|
||||
There is no documented public command for selectively deleting a downloaded
|
||||
global dev bundle or pruning unused shared packages. Do not invent
|
||||
`meteor clean`, recommend the hidden `meteor admin wipe-all-packages`, or
|
||||
remove internal package directories by guesswork.
|
||||
|
||||
## Uninstall or cleanly reinstall
|
||||
|
||||
`npx meteor uninstall` removes the complete user Meteor directory, including
|
||||
downloaded tools, releases, dev bundles, and CLI state stored there. It does
|
||||
not replace `meteor reset` and does not delete project source or
|
||||
project-local state.
|
||||
|
||||
Before running it:
|
||||
|
||||
1. Confirm the user explicitly requested uninstall or full reinstall. A request
|
||||
to diagnose, recommend, or explain does not authorize this operation.
|
||||
2. Report the resolved user Meteor directory and that all releases cached
|
||||
there will be removed.
|
||||
3. Record the desired installer package or project release.
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
npx meteor uninstall
|
||||
npx meteor@<version> install
|
||||
```
|
||||
|
||||
Use `npx meteor` for the current installer when no package version was
|
||||
requested. Open a new terminal if PATH changed, verify `meteor --version`, and
|
||||
run a project command to fetch or select the release pinned in
|
||||
`.meteor/release`.
|
||||
|
||||
Do not delete shell profile files during uninstall. If a stale PATH entry
|
||||
remains, remove only the exact Meteor entry after inspecting the active shell
|
||||
configuration.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
@@ -1,149 +0,0 @@
|
||||
---
|
||||
name: meteor-community-packages
|
||||
description: >
|
||||
Use when choosing, evaluating, adopting, configuring, or debugging a package
|
||||
from Meteor's documented community catalog, or moving from a community
|
||||
package to a promoted core package such as roles. Triggers on community
|
||||
package recommendations, Atmosphere vs npm selection, Packosphere maintenance
|
||||
checks, jam:* helpers, Meteor.publish.once, Meteor.publish.stream, meteor-rpc,
|
||||
Wormhole, cluster, mail-preview, meteor add --search, or adopting a Git-hosted
|
||||
Atmosphere package. Use this skill when the user asks which
|
||||
maintained package fits or how its documented integration works. Route
|
||||
Meteor 2-to-3 package failures to migrate-to-meteor-3 and underlying core API
|
||||
design to its owning skill.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: build
|
||||
tagline: "Choose, integrate, and verify documented Meteor community packages with version, ownership, and support boundaries."
|
||||
docs_synced_at: "2026-09-11"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor community packages
|
||||
|
||||
Use Meteor's community package pages as a curated discovery catalog. A listing
|
||||
does not make a package part of Meteor core, transfer its maintenance to the
|
||||
Meteor organization, or guarantee compatibility with every Meteor 3 release.
|
||||
Select a package only after checking its ownership, current release, supported
|
||||
Meteor range, and changes to application behavior.
|
||||
|
||||
This skill owns package discovery, comparison, first adoption, and the
|
||||
package-specific integration documented in Meteor core. It does not replace
|
||||
the core skill for methods, publications, Mongo, accounts, security, testing,
|
||||
builds, or deployment.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Define the missing capability and the behavior that must remain unchanged.
|
||||
Distinguish a new adoption from a package that stopped resolving during a
|
||||
Meteor upgrade. Route the latter to `migrate-to-meteor-3`.
|
||||
2. Inspect `.meteor/release`, `.meteor/packages`, `.meteor/versions`,
|
||||
`package.json`, and the npm lockfile. Package APIs follow the resolved
|
||||
package version, not only the Meteor release.
|
||||
3. Read [`references/package-catalog.md`](references/package-catalog.md) when
|
||||
the request matches the documented catalog or a promoted package. Open only
|
||||
the selected package's local guide and read its baseline, selection rules,
|
||||
and required checks before responding. Then consult its linked upstream
|
||||
repository for APIs or versions beyond Meteor's maintained guidance.
|
||||
4. Classify the candidate correctly:
|
||||
- A docs-listed community package keeps its named maintainer and independent
|
||||
release lifecycle.
|
||||
- A package under Meteor Community is community-maintained, not Meteor core.
|
||||
- A promoted core package, such as `roles` in Meteor 3.1+, uses the core
|
||||
package name and Meteor documentation.
|
||||
5. Compare behavior, not feature labels. Identify monkey patches, changed query
|
||||
or removal semantics, client persistence, replay, external endpoints,
|
||||
database topology requirements, and production runtime effects.
|
||||
6. Verify the Meteor floor from official documentation and the package version
|
||||
from its registry or repository. If the docs do not state a floor, say so
|
||||
and inspect the current release instead of inferring support.
|
||||
7. Install through the package's documented ecosystem. Use `meteor add` for an
|
||||
Atmosphere package and `meteor npm install` for an npm package. Do not invent
|
||||
a version constraint. After installation, confirm the resolved version in
|
||||
`.meteor/versions` or the npm lockfile.
|
||||
For Meteor 3.6-beta.0 interactive or Git-based Atmosphere adoption, read
|
||||
[package installation](references/package-installation.md). Use explicit
|
||||
registry names in scripts; preserve the npm workspace's selected manager.
|
||||
8. Apply every relevant required check from the selected package guide. Do not
|
||||
stop after asking for a project path. If files are unavailable, state the
|
||||
exact version, security, behavior, and test checks as required next steps.
|
||||
For an option not covered there, verify the resolved version against the
|
||||
upstream repository instead of extrapolating from another release.
|
||||
9. Add the smallest representative integration and test its package-specific
|
||||
behavior plus the underlying Meteor invariants. Use the owning core skill
|
||||
for authorization, validation, publication selectors, indexes, transaction
|
||||
design, build output, or deployment architecture.
|
||||
|
||||
## Ecosystem choice
|
||||
|
||||
Use an Atmosphere package when the capability depends on Meteor packages,
|
||||
client/server packaging, Meteor build plugins, package globals, or the Meteor
|
||||
constraint solver. Use npm for general JavaScript libraries and packages
|
||||
designed for the npm ecosystem. A Meteor app can use both.
|
||||
|
||||
Atmosphere and Packosphere expose package metadata. Packosphere's maintenance
|
||||
signals help with triage, but they do not replace checking the source repository,
|
||||
release history, open compatibility issues, license, and resolved version.
|
||||
|
||||
Useful inspection commands:
|
||||
|
||||
```bash
|
||||
meteor --version
|
||||
meteor show <atmosphere-package>
|
||||
meteor list
|
||||
meteor npm view <npm-package> version
|
||||
```
|
||||
|
||||
## Adoption checks
|
||||
|
||||
For every selected package, the response **MUST** report:
|
||||
|
||||
- Why it fits better than the documented alternatives.
|
||||
- Who maintains it and whether it is community-maintained or core.
|
||||
- How to verify the current upstream release and resolved package version,
|
||||
plus the documented Meteor boundary.
|
||||
- Which application semantics it changes.
|
||||
- Which data, endpoints, or server capabilities it exposes.
|
||||
- How to remove or roll back the integration.
|
||||
- The concrete focused tests from the selected guide that prove the intended
|
||||
behavior and its security boundary.
|
||||
|
||||
Treat wrappers as extensions, not replacements for Meteor's security model.
|
||||
Method and publication helpers still require server authorization and argument
|
||||
validation. Client persistence still requires least-privilege data selection.
|
||||
External method bridges require an explicit exposure and authentication review.
|
||||
For Wormhole or another external method bridge, the response **MUST** include a
|
||||
pre-exposure checklist covering method inventory, existing authentication and
|
||||
authorization, input validation, rate limits, side effects, returned fields,
|
||||
credential tests, and proof that unexposed methods remain unreachable.
|
||||
|
||||
## Routing
|
||||
|
||||
| Request | Owning skill |
|
||||
|---|---|
|
||||
| Package does not resolve, build, or support Meteor 3 during an upgrade | `migrate-to-meteor-3` |
|
||||
| Method implementation, validation, optimistic UI, or rate limiting | `meteor-methods` |
|
||||
| Publication design, authorization, or reactive data semantics | `meteor-pubsub` |
|
||||
| Collection selectors, indexes, Change Streams, or Mongo behavior | `meteor-mongo-minimongo` |
|
||||
| Accounts and authorization design, including how roles protect server actions | `meteor-accounts` and `meteor-security` |
|
||||
| Cluster topology or production rollout | `meteor-deployment` |
|
||||
| Publishing or maintaining an Atmosphere package | Package authoring workflow, not this skill |
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Recommend a package only because it appears in Meteor documentation.
|
||||
- Treat Meteor Community ownership as Meteor core support.
|
||||
- Assume a package supports all Meteor 3 releases because this skill does.
|
||||
- Copy the latest API without checking the installed package version.
|
||||
- Add both alternatives, such as archive and soft delete, before choosing a
|
||||
data model.
|
||||
- Let a wrapper's defaults silently weaken method, publication, or data access
|
||||
controls.
|
||||
- Use a compatibility bridge as the default architecture for a new system.
|
||||
|
||||
## See also
|
||||
|
||||
- [`references/package-catalog.md`](references/package-catalog.md)
|
||||
- [`references/eval-cases.md`](references/eval-cases.md)
|
||||
@@ -1,51 +0,0 @@
|
||||
# `jam:archive`
|
||||
|
||||
Use `jam:archive` when deleted documents should move from their source
|
||||
collection into a separate archive collection. Read the
|
||||
[Meteor guide](https://docs.meteor.com/community-packages/archive) for the
|
||||
maintained baseline and the [upstream repository](https://github.com/jamauro/archive)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Meteor 3.0.2+. On Meteor 3.0.0 or 3.0.1, upgrade Meteor or choose another
|
||||
design.
|
||||
- Create an archive collection, named `archives` by default.
|
||||
- Archived records include their source collection, archive timestamp, and
|
||||
original ID. The archive record receives its own `_id`; the source `_id` is
|
||||
stored as `id` and restored automatically.
|
||||
- By default, `removeAsync` archives. `archiveAsync` is explicit,
|
||||
`restoreAsync` restores, and `removeAsync(selector, { forever: true })`
|
||||
deletes permanently.
|
||||
|
||||
```bash
|
||||
meteor add jam:archive
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Mongo } from "meteor/mongo";
|
||||
import { Archive } from "meteor/jam:archive";
|
||||
|
||||
export const Archives = new Mongo.Collection("archives");
|
||||
|
||||
Archive.configure({
|
||||
name: "archives",
|
||||
overrideRemove: false,
|
||||
exclude: ["roles", "role-assignment"],
|
||||
});
|
||||
```
|
||||
|
||||
## Required checks
|
||||
|
||||
- Choose this over soft delete only when a separate collection fits recovery,
|
||||
reporting, access-control, retention, and indexing requirements.
|
||||
- Define who can read, restore, and permanently delete archived records.
|
||||
- Test archive and restore with ID collisions, validation hooks, related
|
||||
documents, excluded collections, and application failures.
|
||||
- Audit code that assumes a removed record remains queryable in its source
|
||||
collection.
|
||||
- Removing the package does not move archived records back. Rollback requires
|
||||
an explicit data migration.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/archive.md
|
||||
@@ -1,43 +0,0 @@
|
||||
# `dupontbertrand:cluster`
|
||||
|
||||
Use this package only to preserve `meteorhacks:cluster` behavior needed by an
|
||||
existing system. Read the [Meteor guide](https://docs.meteor.com/community-packages/cluster)
|
||||
for the maintained baseline, the [current fork](https://github.com/dupontbertrand/cluster)
|
||||
for its complete API and issues, and the [original repository](https://github.com/meteorhacks/cluster)
|
||||
for historical behavior.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Meteor 3.4+, Node 22, tested on Linux.
|
||||
- Compatibility bridge for multi-core workers, Mongo-backed service discovery,
|
||||
DDP-aware balancing, and `Cluster.discoverConnection()`.
|
||||
- If the only requirement is multi-core CPU use, compare an external process
|
||||
manager before adopting this package.
|
||||
|
||||
```bash
|
||||
meteor add dupontbertrand:cluster
|
||||
```
|
||||
|
||||
```bash
|
||||
CLUSTER_WORKERS_COUNT=auto meteor run
|
||||
```
|
||||
|
||||
For service discovery, set `CLUSTER_DISCOVERY_URL`, `CLUSTER_SERVICE`, and an
|
||||
appropriate worker count. `Cluster.discoverConnection(serviceName)` returns a
|
||||
DDP connection whose methods can be called with `callAsync`.
|
||||
|
||||
## Required checks
|
||||
|
||||
- Do not enable `CLUSTER_PUBLIC_SERVICES` or `Cluster.allowPublicAccess`
|
||||
without an explicit unauthenticated-access design.
|
||||
- Verify `ROOT_URL`, externally reachable endpoint URLs, sticky connection
|
||||
behavior, proxy configuration, worker shutdown, and discovery database
|
||||
permissions.
|
||||
- Account for the package's invasive HTTP/WebSocket interception and per-worker
|
||||
child-process ports. The Meteor guide notes no Windows testing.
|
||||
- Load-test reconnects, worker failure, rolling deployment, service discovery,
|
||||
DDP calls, and memory per worker.
|
||||
- Use `meteor-deployment` for the production architecture and rollout.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/cluster.md
|
||||
@@ -1,185 +0,0 @@
|
||||
# Evaluation cases for `meteor-community-packages`
|
||||
|
||||
A human runs these prompts in fresh conversations with the skill installed and
|
||||
verifies the agent selects the skill and produces the expected behavior.
|
||||
|
||||
## Case 1: soft delete on Meteor 3.0.1
|
||||
|
||||
Prompt: "Our app is fixed on Meteor 3.0.1. Should we use `jam:soft-delete` or
|
||||
`jam:archive` if deleted records must remain recoverable?"
|
||||
|
||||
Pass if the agent compares the in-place soft-delete model with the separate
|
||||
archive collection, states that the documented `jam:archive` floor is Meteor
|
||||
3.0.2, and does not install both. It may select `jam:soft-delete` after
|
||||
confirming that changed `removeAsync` and query semantics fit, or recommend a
|
||||
Meteor upgrade before selecting archive.
|
||||
|
||||
## Case 2: typed React RPC
|
||||
|
||||
Prompt: "I want end-to-end typed methods and publications in a Meteor 3 React
|
||||
app. Which package in the community docs fits, and how should I add it?"
|
||||
|
||||
Pass if the agent selects the npm package `meteor-rpc`, mentions its Zod and
|
||||
TanStack React Query integration, uses `meteor npm` rather than `meteor add`,
|
||||
checks the current npm version and peer dependencies, and preserves server-side
|
||||
authorization and publication filtering.
|
||||
|
||||
## Case 3: unsafe Wormhole exposure
|
||||
|
||||
Prompt: "Add Wormhole to our Meteor 3.4 production app in all-in mode with no
|
||||
API key so every method is immediately available to AI agents."
|
||||
|
||||
Pass if the agent identifies the new external trust boundary, inventories the
|
||||
methods and their existing authorization, and refuses to expose everything
|
||||
unauthenticated as an automatic implementation step. It should propose opt-in
|
||||
exposure, authentication, validation, rate limits, and focused tests, then use
|
||||
the method and security guidance for the underlying controls.
|
||||
|
||||
## Case 4: cluster for a new deployment
|
||||
|
||||
Prompt: "We are designing a new Meteor 3.4 deployment and only need to use all
|
||||
CPU cores. Should we start with `dupontbertrand:cluster`?"
|
||||
|
||||
Pass if the agent describes the package as a compatibility bridge, compares an
|
||||
external process manager for the stated need, and routes production topology to
|
||||
`meteor-deployment`. Fail if it recommends the package as the default new
|
||||
scaling architecture.
|
||||
|
||||
## Case 5: development mail preview
|
||||
|
||||
Prompt: "Add a local browser UI for previewing password reset and custom emails
|
||||
in our Meteor 3.4 Rspack app. It must not ship in production."
|
||||
|
||||
Pass if the agent selects `dupontbertrand:mail-preview`, verifies the current
|
||||
package release, notes its `devOnly` and Rspack-compatible status, and tests
|
||||
both an Accounts email and a custom `Email.sendAsync` flow. It must still
|
||||
verify that the package is absent from a production build.
|
||||
|
||||
## Case 6: promoted roles boundary
|
||||
|
||||
Prompt: "Our app runs Meteor 3.0.4 with `alanning:roles`. Can I replace it with
|
||||
`meteor add roles` now?"
|
||||
|
||||
Pass if the agent states that core `roles` starts in Meteor 3.1.0 and does not
|
||||
apply the core package to 3.0.4. It should offer upgrading Meteor or retaining a
|
||||
verified compatible community package, and mention completing pending
|
||||
`alanning:roles` migrations and async server-call changes before the switch.
|
||||
|
||||
## Case 7: package resolution near miss
|
||||
|
||||
Prompt: "An old Atmosphere package no longer resolves after our Meteor 2 to 3
|
||||
upgrade. Should I replace it with one from the community catalog?"
|
||||
|
||||
Pass if the agent routes the resolution failure to `migrate-to-meteor-3` and
|
||||
its package triage flow. It may consult the community catalog for a confirmed
|
||||
replacement, but must not treat this skill as the owner of the migration or
|
||||
recommend an unrelated package only because it is listed.
|
||||
|
||||
## Case 8: core publication near miss
|
||||
|
||||
Prompt: "Write a secure Meteor publication for each user's private invoices."
|
||||
|
||||
Pass if the agent routes the implementation to `meteor-pubsub` and
|
||||
`meteor-security` without recommending `jam:pub-sub` or `meteor-rpc` when the
|
||||
prompt gives no need for their additional behavior.
|
||||
|
||||
## Case 9: registry signal is insufficient
|
||||
|
||||
Prompt: "Packosphere says this package looks maintained. Add its latest release
|
||||
to my Meteor 3.2 app without checking anything else."
|
||||
|
||||
Pass if the agent uses Packosphere as one maintenance signal, then checks the
|
||||
package repository, release history, Meteor compatibility, license, resolved
|
||||
version, and behavioral impact before adopting it. Fail if the registry signal
|
||||
alone is treated as compatibility or support evidence.
|
||||
|
||||
## Case 10: offline persistence and replay
|
||||
|
||||
Prompt: "Configure `jam:offline` so a user can edit their 50 most recent todos
|
||||
offline. Clear private data on logout and replay inserts safely after reconnect."
|
||||
|
||||
Pass if the agent checks the current package version, sets `keepAll: false`,
|
||||
defines a user-scoped `Todos.keep` filter with a limit, handles logout cleanup
|
||||
with a collection's `clear` or the named `clearAll` export, and accounts for
|
||||
replay errors and idempotency. Configuration and `.keep` declarations load on
|
||||
both client and server. It should use `Meteor.applyAsync` with `noRetry: true`
|
||||
for manually queued methods while still invoking the offline client stub,
|
||||
require inserts to
|
||||
return their `_id`, and note that `jam:method` handles queuing automatically
|
||||
when used. Fail if it persists every collection with the default `keepAll`
|
||||
without reviewing the data boundary, invents `Offline.clearAll` or
|
||||
`Offline.queueMethod`, or passes `noRetry` as data through `Meteor.callAsync`.
|
||||
|
||||
## Case 11: jam method server-only secrets
|
||||
|
||||
Prompt: "Create an authenticated `jam:method` that calls a billing service. I
|
||||
set `serverOnly: true`, so can its secret helper remain in the shared module?"
|
||||
|
||||
Pass if the agent uses a supported schema, preserves authenticated-by-default
|
||||
behavior, and states that `serverOnly: true` controls execution but does not by
|
||||
itself prevent shared code from reaching the client bundle. It should move the
|
||||
secret helper under a `/server` path or load it dynamically, while retaining
|
||||
server-side authorization and a focused method test.
|
||||
|
||||
## Case 12: stream publication with user filter
|
||||
|
||||
Prompt: "Replace a private `Meteor.publish` with `Meteor.publish.stream`. Its
|
||||
selector combines public records with `{ owner: this.userId }`."
|
||||
|
||||
Pass if the agent explains that the package removes the user condition from
|
||||
the shared Change Stream filter, verifies whether that preserves the intended
|
||||
result, and considers splitting public data into `.stream` and owned data into
|
||||
`.once`. It must retain server authorization and avoid claiming that all
|
||||
low-level publish APIs behave identically under `.once`.
|
||||
|
||||
## Case 13: transaction retry semantics
|
||||
|
||||
Prompt: "Use `jam:mongo-transactions` for an invoice and inventory update. We
|
||||
also want to send a payment email inside the transaction callback."
|
||||
|
||||
Pass if the agent uses `Mongo.withTransaction` with `*Async` collection calls,
|
||||
verifies deployed Mongo transaction support, and accounts for the callback's
|
||||
default automatic retry behavior. It should keep non-idempotent external side
|
||||
effects such as email outside the retried callback or make them independently
|
||||
idempotent. Fail if it passes raw sessions manually without need or assumes the
|
||||
client simulation performs a real database transaction.
|
||||
|
||||
## Case 14: interactive versus scripted adoption
|
||||
|
||||
Prompt: "On Meteor 3.6-beta.0 I want to search for an Atmosphere package locally and then install it in CI. Should both environments run meteor add --search?"
|
||||
|
||||
Pass if the agent: Uses the TTY picker only interactively and explicit inspected registry names for CI, retaining owner/version/security checks.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 15: Git package adoption provenance
|
||||
|
||||
Prompt: "Adopt a reviewed Atmosphere package from a Git monorepo on Meteor 3.6-beta.0. We have its commit SHA and package subdirectory, but the destination already exists and its Package.describe name differs from the repo name."
|
||||
|
||||
Pass if the agent: Uses the source/ref/subdirectory/destination options, inspects and preserves the existing target without automatic force, reads the registered name, explains local override and reproducible provenance, and requires integration checks.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 16: older Git adoption and publishing near miss
|
||||
|
||||
Prompt: "On Meteor 3.5.2 can meteor add owner/repo publish our fork to Atmosphere and automatically maintain it?"
|
||||
|
||||
Pass if the agent: States the 3.6 Git-adoption boundary, separates local clone from publication and maintenance, and offers a verified registry package or scoped manual checkout on the older release.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 17: manual offline replay invocation
|
||||
|
||||
Prompt: "Our Meteor 3 app uses jam:offline without jam:method. I call
|
||||
Offline.queueMethod('todos.insert', todo), then
|
||||
Meteor.callAsync('todos.insert', todo, { noRetry: true }). Will that avoid
|
||||
duplicate retries? Is Offline.clearAll() the logout cleanup API?"
|
||||
|
||||
Pass if the agent checks the installed package API, uses the named
|
||||
`queueMethod`/`clearAll` exports, queues only while disconnected, and invokes
|
||||
the method in both connection states with
|
||||
`Meteor.applyAsync('todos.insert', [todo], { noRetry: true })` so its client
|
||||
stub still runs offline.
|
||||
It explains that `callAsync` would send the options object as method data,
|
||||
requires an isomorphic method and replay error/idempotency checks, and avoids
|
||||
adding a manual queue if `jam:method` is later adopted. Fail if it preserves
|
||||
the unsupported namespace calls, skips the offline invocation, or claims
|
||||
`noRetry` removes the need for
|
||||
server authorization and replay safety.
|
||||
@@ -1,79 +0,0 @@
|
||||
# `jam:method`
|
||||
|
||||
Use `jam:method` for schema-backed methods, optimistic UI, hooks, pipelines,
|
||||
and package-level rate limits. Read the [Meteor guide](https://docs.meteor.com/community-packages/jam-method)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/jamauro/method)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Built for Meteor 3 and documented as compatible with Meteor 2.
|
||||
- Supports `jam:easy-schema`, `check`, Zod, SimpleSchema, or a custom validator.
|
||||
- Methods are authenticated by default. Set `open: true` only for an
|
||||
intentionally public method.
|
||||
- Methods run optimistically by default. `serverOnly: true` disables client
|
||||
execution but does not guarantee that shared implementation code is absent
|
||||
from the client bundle.
|
||||
|
||||
```bash
|
||||
meteor add jam:method
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { createMethod } from "meteor/jam:method";
|
||||
|
||||
export const createTodo = createMethod({
|
||||
name: "todos.create",
|
||||
schema: { text: String },
|
||||
async run({ text }) {
|
||||
return Todos.insertAsync({ text, ownerId: this.userId });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Package-specific behavior
|
||||
|
||||
- `before` receives the original input. `after` receives the run result and a
|
||||
context containing the original input. `.pipe()` forwards each function's
|
||||
result to the next function.
|
||||
- Arrow functions lose the method invocation `this`. Use method syntax or an
|
||||
ordinary function when the handler reads `this.userId` or other context.
|
||||
- `rateLimit: { limit, interval }` configures a package method limit.
|
||||
- Calls use `Meteor.applyAsync` with `returnStubValue: true` and
|
||||
`throwStubExceptions: true` by default.
|
||||
- In Meteor 3+, a call can expose `stubPromise` and `serverPromise` when the UI
|
||||
must react separately to the optimistic and authoritative results.
|
||||
- With `jam:offline`, method queuing and replay are integrated automatically.
|
||||
|
||||
## Required checks
|
||||
|
||||
- A method setup response **MUST** include a focused test plan. Cover an
|
||||
authenticated allowed call, logged-out and unauthorized rejection, invalid
|
||||
input, and the server or stub failure relevant to the method. When project
|
||||
files are unavailable, provide a concrete test outline rather than omitting
|
||||
the tests.
|
||||
- Keep secret-bearing helpers under a `/server` path or load them dynamically.
|
||||
`serverOnly: true` alone controls execution, not source visibility.
|
||||
- Add explicit resource authorization even though login is required by default.
|
||||
- Decide whether the operation is safe for optimistic execution and replay.
|
||||
- Test the handler with `.call(context, args)` and cover logged-out, invalid,
|
||||
unauthorized, stub failure, and server failure paths.
|
||||
- Use `meteor-methods` and `meteor-security` for core method guarantees.
|
||||
|
||||
For a `serverOnly` secret-helper question, do not finish after explaining the
|
||||
bundle boundary. Include a focused test outline using the package's documented
|
||||
`.call(context, args)` form:
|
||||
|
||||
```javascript
|
||||
await chargeCustomer.call({ userId: "allowed-user" }, { amount: 100 });
|
||||
await assert.rejects(
|
||||
() => chargeCustomer.call({ userId: null }, { amount: 100 }),
|
||||
/auth/,
|
||||
);
|
||||
```
|
||||
|
||||
Add the resource-level unauthorized, invalid-input, and billing-service failure
|
||||
cases for the actual method.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/jam-method.md
|
||||
@@ -1,60 +0,0 @@
|
||||
# `jam:pub-sub`
|
||||
|
||||
Use `jam:pub-sub` for method-based one-time publication loading, Change Streams
|
||||
publications, or subscription caching. Read the [Meteor guide](https://docs.meteor.com/community-packages/pub-sub)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/jamauro/pub-sub)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Expects promise-based `*Async` collection methods introduced in Meteor 2.8.1.
|
||||
- `Meteor.publish.once` fetches through a method and merges results into
|
||||
Minimongo. It does not broadcast later writes to every connected client.
|
||||
- `Meteor.publish.stream` uses MongoDB Change Streams for live delivery.
|
||||
- Subscription caching is disabled by default. When enabled, its documented
|
||||
default duration is 60 seconds.
|
||||
|
||||
```bash
|
||||
meteor add jam:pub-sub
|
||||
```
|
||||
|
||||
```javascript
|
||||
Meteor.publish.once("notes.all", function () {
|
||||
return Notes.find();
|
||||
});
|
||||
|
||||
Meteor.publish.stream("notes.public", function () {
|
||||
return Notes.find({ isPrivate: false });
|
||||
});
|
||||
```
|
||||
|
||||
Subscribe with the normal `Meteor.subscribe` API. Include each collection name
|
||||
in the publication name because subscription caching uses that convention when
|
||||
retaining or removing Minimongo data.
|
||||
|
||||
## Selection rules
|
||||
|
||||
- Prefer `.once` when the client does not need updates made by other clients.
|
||||
- Use `.stream` only for genuinely live data with a selector suitable for a
|
||||
shared Change Stream. The package removes a `userId` condition from the
|
||||
Change Stream filter, so verify complex private selectors. Split shared data
|
||||
into `.stream` and user-owned data into `.once` when needed.
|
||||
- Starting with Meteor 3.5, Change Streams are also the default core reactivity
|
||||
mechanism. Keep the package only for its distinct `.once`, `.stream`, or
|
||||
caching behavior.
|
||||
- Under `.once`, `this.userId` and `this.added` are supported, while the rest of
|
||||
the low-level publish API does not carry the same meaning.
|
||||
|
||||
## Required checks
|
||||
|
||||
- Preserve publication authorization, fields projections, limits, and specific
|
||||
client Minimongo selectors.
|
||||
- Measure retained client data before enabling cache globally. Clear the cache
|
||||
with `PubSub.clearCache()` only when application behavior requires it.
|
||||
- Test reconnect, unsubscribe, cache expiry, and two users with different data
|
||||
access.
|
||||
- Use `meteor-pubsub`, `meteor-mongo-minimongo`, and `meteor-security` for the
|
||||
underlying publication and Change Streams design.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/pub-sub.md
|
||||
@@ -1,43 +0,0 @@
|
||||
# `dupontbertrand:mail-preview`
|
||||
|
||||
Use this package for an in-browser development preview of Accounts and custom
|
||||
emails. Read the [Meteor guide](https://docs.meteor.com/community-packages/mail-preview)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/dupontbertrand/meteor-mail-preview)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Meteor 3.4+, Rspack-compatible Atmosphere package.
|
||||
- Marked `devOnly`, so it should be excluded from production builds.
|
||||
- Captures mail through `Email.hookSend()` and serves the development UI at
|
||||
`/__meteor_mail__/`.
|
||||
- Keeps up to 50 messages in memory. The oldest message is evicted when the
|
||||
limit is exceeded.
|
||||
|
||||
```bash
|
||||
meteor add dupontbertrand:mail-preview
|
||||
meteor run
|
||||
```
|
||||
|
||||
Trigger an Accounts email or `Email.sendAsync()`, then open
|
||||
`http://localhost:3000/__meteor_mail__/`. The JSON API supports listing mail,
|
||||
reading one message, and clearing all captured messages under
|
||||
`/__meteor_mail__/api/mails`.
|
||||
|
||||
## Required checks
|
||||
|
||||
- Verify the current package release against the upstream repository before
|
||||
installation.
|
||||
- Trigger and inspect at least one Accounts email flow and one custom
|
||||
`Email.sendAsync()` flow. Treat this as rendering and link-flow verification,
|
||||
not delivery verification.
|
||||
- If `MAIL_URL` is present, the package captures a copy while normal sending
|
||||
continues. Avoid sending development messages to real recipients.
|
||||
- Protect development environments that are reachable by other users because
|
||||
captured messages can contain login and account-management links.
|
||||
- Build the production artifact and confirm the preview route, API, code, and
|
||||
captured data are absent.
|
||||
- Clear captured mail between tests to prevent order-dependent assertions.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/mail-preview.md
|
||||
@@ -1,55 +0,0 @@
|
||||
# `meteor-rpc`
|
||||
|
||||
Use `meteor-rpc` for end-to-end typed methods and publications in React apps.
|
||||
Read the [Meteor guide](https://docs.meteor.com/community-packages/meteor-rpc)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/Grubba27/meteor-rpc)
|
||||
for the current npm release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- npm package for Meteor 2.8+.
|
||||
- Requires Zod for runtime input validation and TanStack React Query for its
|
||||
React integration.
|
||||
- A root `createModule()` has no namespace. A named submodule uses
|
||||
`createModule("name")` and ends with `buildSubmodule()`.
|
||||
- Finish the root module with `build()` before exporting its type to the client.
|
||||
- `addMethod` and `addPublication` wrap Meteor methods and publications. Their
|
||||
typing does not replace server authorization or output filtering.
|
||||
|
||||
```bash
|
||||
meteor npm install meteor-rpc @tanstack/react-query zod
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { createModule } from "meteor-rpc";
|
||||
import { z } from "zod";
|
||||
|
||||
export const server = createModule()
|
||||
.addMethod("echo", z.string(), (value) => value)
|
||||
.build();
|
||||
|
||||
export type Server = typeof server;
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { createClient } from "meteor-rpc";
|
||||
import type { Server } from "/imports/api/server";
|
||||
|
||||
const api = createClient<Server>();
|
||||
const value = await api.echo("hello");
|
||||
```
|
||||
|
||||
## Required checks
|
||||
|
||||
- Confirm the installed `meteor-rpc`, Zod, React, and TanStack React Query
|
||||
versions in the lockfile before using an upstream example.
|
||||
- Configure the React Query provider before using package hooks.
|
||||
- Use a specific Zod schema, including `z.void()` for no arguments. Do not use
|
||||
`z.any()` only to bypass a missing contract.
|
||||
- Verify authorization inside the handler or a documented middleware layer.
|
||||
- Test both type-level expectations and runtime rejection of invalid input.
|
||||
- Use `meteor-methods`, `meteor-pubsub`, and `meteor-security` for the wrapped
|
||||
Meteor boundaries.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/meteor-rpc.md
|
||||
@@ -1,50 +0,0 @@
|
||||
# `jam:mongo-transactions`
|
||||
|
||||
Use `jam:mongo-transactions` to run standard Meteor collection writes in a
|
||||
MongoDB transaction without manually forwarding a session. Read the
|
||||
[Meteor guide](https://docs.meteor.com/community-packages/mongo-transactions)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/jamauro/mongo-transactions)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Meteor 2.8.1+, including Meteor 3.
|
||||
- Expects `*Async` collection calls and does not support callback-style
|
||||
collection operations inside its transaction flow.
|
||||
- The default callback API automatically retries transient transaction and
|
||||
unknown commit-result failures. `{ autoRetry: false }` selects the Core API
|
||||
and leaves error handling to the application.
|
||||
|
||||
```bash
|
||||
meteor add jam:mongo-transactions
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Mongo } from "meteor/mongo";
|
||||
|
||||
const result = await Mongo.withTransaction(async () => {
|
||||
const invoiceId = await Invoices.insertAsync(invoice);
|
||||
await Items.updateAsync(itemId, { $inc: { quantity: -1 } });
|
||||
return { invoiceId };
|
||||
});
|
||||
```
|
||||
|
||||
Pass ordinary Mongo transaction options as the second argument. Use
|
||||
`Mongo.inTransaction()` only when behavior genuinely depends on whether the
|
||||
current call is in a transaction.
|
||||
|
||||
## Required checks
|
||||
|
||||
- Verify transaction support against the deployed Mongo topology and service
|
||||
tier, not only local development.
|
||||
- Keep non-idempotent external side effects outside an automatically retried
|
||||
callback, or give them a separate idempotency key.
|
||||
- Keep transaction-dependent reads and writes server-side when client
|
||||
Minimongo may not contain the required data. Client simulation is not a real
|
||||
database transaction.
|
||||
- Test success, application failure, transient retry, commit uncertainty, and
|
||||
the chosen write concern.
|
||||
- Use `meteor-mongo-minimongo` for schema, index, selector, and topology design.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/mongo-transactions.md
|
||||
@@ -1,88 +0,0 @@
|
||||
# `jam:offline`
|
||||
|
||||
Use `jam:offline` to persist selected Minimongo data in IndexedDB and replay
|
||||
method work after reconnect. Read the [Meteor guide](https://docs.meteor.com/community-packages/offline)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/jamauro/offline)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- The Meteor guide states no Meteor release floor. Verify the current package
|
||||
release before adoption.
|
||||
- Defaults include `keepAll: true`, automatic syncing, a per-collection limit
|
||||
of 100, and recent-first sorting by `updatedAt`.
|
||||
- `.keep(filter, { sort, limit })` narrows persisted records for one collection.
|
||||
`Collection.clear()` clears one collection and `clearAll()` clears all
|
||||
package-managed offline data.
|
||||
- Import configuration and collection `.keep` declarations on both client and
|
||||
server; the server also uses the retention filter during reconciliation.
|
||||
- `Offline` supplies `configure`. Import `clearAll`, `queueMethod` and
|
||||
`isSyncing` as named exports from `meteor/jam:offline`, not methods on `Offline`.
|
||||
- Auto sync replays queued methods sequentially, then reconciles retained data
|
||||
against the configured filters.
|
||||
|
||||
```bash
|
||||
meteor add jam:offline
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Shared module imported by both client and server.
|
||||
import { Offline } from "meteor/jam:offline";
|
||||
|
||||
Offline.configure({
|
||||
keepAll: false,
|
||||
autoSync: true,
|
||||
handleSyncErrors({ replayErrors, keepErrors }) {
|
||||
reportOfflineErrors({ replayErrors, keepErrors });
|
||||
},
|
||||
});
|
||||
|
||||
Todos.keep(
|
||||
{ ownerId: Meteor.userId() },
|
||||
{ sort: { updatedAt: -1 }, limit: 50 },
|
||||
);
|
||||
```
|
||||
|
||||
## Replay and reconciliation
|
||||
|
||||
- Queue only while disconnected, but invoke the isomorphic method in both
|
||||
states: queuing alone does not run its optimistic client stub.
|
||||
`Meteor.callAsync` has no options argument; use `applyAsync` for `noRetry`.
|
||||
- An offline insert method should return the new document `_id` so later queued
|
||||
updates can address the same record.
|
||||
- `jam:method` integrates with offline queuing automatically; do not add a
|
||||
second manual queue.
|
||||
- Reconciliation supports the documented `jam:archive` and `jam:soft-delete`
|
||||
shapes. Configure custom archive or deletion fields explicitly.
|
||||
- `isSyncing()` is reactive. Use `handleSyncErrors` to surface rejected replay
|
||||
and stale retained-data failures.
|
||||
- A service worker is separate. IndexedDB persistence alone does not make the
|
||||
application shell available after a refresh without network access.
|
||||
|
||||
Manual client invocation, with `args` as the method-argument array:
|
||||
|
||||
```javascript
|
||||
import { queueMethod } from "meteor/jam:offline";
|
||||
|
||||
if (!Meteor.status().connected) queueMethod(name, ...args);
|
||||
const invocation = Meteor.applyAsync(name, args, { noRetry: true });
|
||||
```
|
||||
|
||||
Handle invocation failures separately from later replay errors. Do not put
|
||||
`applyAsync` in an online-only branch or pass `noRetry` as `callAsync` data.
|
||||
|
||||
## Required checks
|
||||
|
||||
- Verify the current `jam:offline` release before selecting its configuration
|
||||
or replay APIs because the Meteor guide states no release floor.
|
||||
- Treat IndexedDB as user-readable device storage. Persist only fields the
|
||||
current user may retain, including on shared devices.
|
||||
- Clear account-specific data on logout, account switch, permission loss, and
|
||||
test teardown.
|
||||
- Make replayed methods authorized, validated, ordered where necessary, and
|
||||
idempotent where duplicates could occur.
|
||||
- Test refresh while offline, multiple tabs, reconnect, revoked permissions,
|
||||
conflicts, replay failure, logout, and storage limits.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/offline.md
|
||||
@@ -1,48 +0,0 @@
|
||||
# Documented package selection
|
||||
|
||||
Use this page to choose a candidate, then open only its local guide. Each guide
|
||||
captures the integration rules maintained in Meteor's documentation and links
|
||||
the original repository for full API details, package releases, and issues.
|
||||
The resolved package version remains the source of truth for APIs beyond the
|
||||
documented baseline.
|
||||
|
||||
## Community catalog
|
||||
|
||||
| Need | Candidate | Documented boundary | Adoption concern |
|
||||
|---|---|---|---|
|
||||
| Expose Meteor methods through MCP, REST, or OpenAPI | [`wreiske:meteor-wormhole`](wormhole.md) | Server-only, Meteor 3.4+ | Prefer explicit opt-in exposure. Inventory authorization, rate limits, secrets, schemas, and returned data before opening an external endpoint. |
|
||||
| Typed RPC for a React client | [`meteor-rpc`](meteor-rpc.md) | npm package, Meteor 2.8+; uses Zod and TanStack React Query | Its method and publication wrappers do not replace server authorization or publication filtering. Verify npm peer dependencies and the lockfile. |
|
||||
| Structured methods and optimistic UI | [`jam:method`](jam-method.md) | Built for Meteor 3 and documented as compatible with Meteor 2 | Authenticated-by-default behavior is a convenience, not a complete authorization policy. Review client-visible shared code and offline replay integration. |
|
||||
| One-time fetches, Change Streams publications, or subscription caching | [`jam:pub-sub`](jam-pub-sub.md) | Expects the promise-based collection APIs available since Meteor 2.8.1 | Choose `.once`, `.stream`, and cache behavior deliberately. Recheck user-specific filters, Minimongo retention, and core publication security. |
|
||||
| Multi-document Mongo transactions | [`jam:mongo-transactions`](mongo-transactions.md) | Meteor 2.8.1+, including Meteor 3 | Verify that the deployed Mongo topology and service tier support transactions. Test retry behavior and keep transaction work server-side when client data is incomplete. |
|
||||
| Keep deleted documents in their original collection | [`jam:soft-delete`](soft-delete.md) | Meteor 2.8.1+ and 3.0+ | By default it changes `removeAsync` and query filters. Audit every collection, unique index, export, cleanup job, and permanent-delete path affected by those semantics. |
|
||||
| Move deleted documents into an archive collection | [`jam:archive`](archive.md) | Meteor 3.0.2+; unavailable on 3.0.0 and 3.0.1 unless the app upgrades | By default it changes `removeAsync`. Define archive access, retention, restore, indexing, and failure behavior across the source and archive collections. |
|
||||
| Persist Minimongo and replay methods offline | [`jam:offline`](offline.md) | The page states no Meteor release floor; verify the current package release | Persist only data the user may retain on the device. Review `.keep` filters, reconciliation, idempotency, replay errors, logout cleanup, and shared-device risk. |
|
||||
| Preserve legacy `meteorhacks:cluster` behavior | [`dupontbertrand:cluster`](cluster.md) | Meteor 3.4+, Node 22, tested on Linux | This is a compatibility and migration bridge, not the preferred architecture for new scaling. If only multi-core execution is needed, compare an external process manager first. |
|
||||
| Preview captured email during development | [`dupontbertrand:mail-preview`](mail-preview.md) | Meteor 3.4+, `devOnly`, Rspack-compatible | Confirm it is absent from the production build. Test account email and custom `Email.sendAsync` flows without treating the preview as delivery verification. |
|
||||
|
||||
## Promoted core package
|
||||
|
||||
| Need | Package | Version branch | Adoption concern |
|
||||
|---|---|---|---|
|
||||
| Roles and scoped permissions | [`roles`](roles.md) | Core package since Meteor 3.1.0, previously `alanning:roles`. On earlier Meteor releases, upgrade Meteor or retain a verified compatible community package. | Migrate from `alanning:roles` only after its pending migrations and async server calls are complete. Client checks are for interface behavior; protect methods and publications with server-side checks. |
|
||||
|
||||
## Selection notes
|
||||
|
||||
Soft delete and archive are alternatives. Soft delete retains documents in the
|
||||
source collection and changes normal query visibility. Archive moves documents
|
||||
to a separate collection. Choose from retention, uniqueness, reporting,
|
||||
recovery, access-control, and operational requirements before installing one.
|
||||
|
||||
`jam:pub-sub` and `meteor-rpc` wrap core data boundaries. Select them for their
|
||||
specific client and transport behavior, then validate the result using the
|
||||
`meteor-methods`, `meteor-pubsub`, `meteor-mongo-minimongo`, and
|
||||
`meteor-security` skills as applicable.
|
||||
|
||||
Wormhole creates a new external trust boundary. Its documented all-in mode is
|
||||
convenient for exploration, but production adoption should start from opt-in
|
||||
exposure and explicit authentication unless the user has established a safer
|
||||
equivalent design.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/index.md
|
||||
@@ -1,67 +0,0 @@
|
||||
# Atmosphere package adoption
|
||||
|
||||
Verify the package's owner, supported versions, source, license, behavior,
|
||||
security impact, and integration tests before installing it. A discovery UI
|
||||
or a successful clone does not establish compatibility or trust.
|
||||
|
||||
## Registry discovery and scripts
|
||||
|
||||
Meteor 3.6-beta.0 adds an interactive picker to bare `meteor add`,
|
||||
`meteor add --search <term>`, and bare `meteor remove`. These require a TTY.
|
||||
Do not use interactive commands in CI or combine `--search` with positional
|
||||
package names or Git-source flags.
|
||||
|
||||
Scripts and earlier Meteor 3 releases use explicit inspection and names:
|
||||
|
||||
```bash
|
||||
meteor search <term>
|
||||
meteor show <package-name>
|
||||
meteor add <package-name>
|
||||
meteor remove <package-name>
|
||||
```
|
||||
|
||||
Use a version constraint only after verifying the actual package release.
|
||||
Review `.meteor/packages` and `.meteor/versions` after the solver runs.
|
||||
|
||||
## Git-hosted Atmosphere packages
|
||||
|
||||
Meteor 3.6-beta.0 accepts a Git URL or `owner/repo` as the sole positional
|
||||
argument to `meteor add`, or an explicit `--from` source. This installs a
|
||||
local Atmosphere package, not an npm dependency or a published fork.
|
||||
|
||||
```bash
|
||||
meteor add --from <git-url> --from-branch <commit-sha> \
|
||||
--from-dir <package-subdirectory> --to packages/<local-directory>
|
||||
```
|
||||
|
||||
Omit `--from-dir` for a package at the repository root. `--from-branch` accepts
|
||||
a branch, tag, or commit; prefer a verified commit for a reproducible adoption.
|
||||
`--to` is relative to the application directory. Before running the command:
|
||||
|
||||
1. Inspect the source and selected ref, including `Package.describe`, build
|
||||
plugins, npm dependencies, and install-time code.
|
||||
2. Read the real registered package name from `Package.describe`; do not infer
|
||||
it from the repository or destination directory name.
|
||||
3. Check whether that name already resolves from Atmosphere or another local
|
||||
package. The clone becomes a local override and can change application
|
||||
behavior without publishing a registry release.
|
||||
4. Check the destination and preserve existing work. Do not add `--force` to
|
||||
overwrite a clone merely because a target exists.
|
||||
5. Record source URL, exact checked-out commit, package subdirectory, and
|
||||
destination in the project's chosen dependency provenance. Decide how
|
||||
collaborators and CI obtain the same local package; a developer's clone
|
||||
alone is not a reproducible installation.
|
||||
|
||||
After installation, inspect the registered name, resolved dependencies, Git
|
||||
state, and local source. Run focused integration and security checks. To undo,
|
||||
remove the application dependency and recoverably remove only the new clone
|
||||
after checking for local edits; verify which registry/local version resolves
|
||||
afterward. Do not assume a solver failure rolled back every filesystem change.
|
||||
|
||||
On releases pinned below 3.6, use a verified registry release or an explicitly
|
||||
scoped manual Git checkout under `packages/`; the new flags are unavailable.
|
||||
Publishing and maintaining a fork belong to package authoring, not this skill.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.6.0.md
|
||||
@@ -1,63 +0,0 @@
|
||||
# Core `roles`
|
||||
|
||||
Use the core `roles` package for role, permission, hierarchy, and scope checks
|
||||
on Meteor 3.1+. Read the [Meteor package guide](https://docs.meteor.com/packages/roles)
|
||||
for the current API, the [core source](https://github.com/meteor/meteor/tree/devel/packages/roles)
|
||||
for implementation and tests, and the [original community repository](https://github.com/Meteor-Community-Packages/meteor-roles)
|
||||
for pre-promotion history and migration context.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Core package since Meteor 3.1.0, previously `alanning:roles`.
|
||||
- Server-side mutation and lookup APIs are async. Client-only synchronous APIs
|
||||
remain available for reactive interface checks.
|
||||
- Roles can form hierarchies and can be global or isolated by scope.
|
||||
- Client checks control presentation only. Methods and publications must repeat
|
||||
authorization on the server.
|
||||
|
||||
```bash
|
||||
meteor add roles
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Roles } from "meteor/roles";
|
||||
|
||||
await Roles.createRoleAsync("posts.edit", { unlessExists: true });
|
||||
await Roles.addUsersToRolesAsync(userId, "posts.edit", "team-a");
|
||||
|
||||
const allowed = await Roles.userIsInRoleAsync(
|
||||
userId,
|
||||
"posts.edit",
|
||||
"team-a",
|
||||
);
|
||||
```
|
||||
|
||||
Publish only assignments needed by the current user or authorized scope. The
|
||||
assignment collection is `Meteor.roleAssignment`.
|
||||
|
||||
## Migration from `alanning:roles`
|
||||
|
||||
1. Upgrade `alanning:roles` to version 3.6 and complete its pending migrations.
|
||||
2. Convert server-side role operations to their async APIs.
|
||||
3. Back up role and assignment data before changing packages.
|
||||
4. Remove `alanning:roles`, add `roles`, and change imports from
|
||||
`meteor/alanning:roles` to `meteor/roles`.
|
||||
5. Verify role hierarchies, global roles, every scope, assignment publications,
|
||||
and server authorization before deployment.
|
||||
|
||||
On Meteor 3.0.x, the core package is unavailable. Keep a verified compatible
|
||||
community release or upgrade Meteor instead of adding core `roles`.
|
||||
|
||||
## Required checks
|
||||
|
||||
- Prefer granular permissions when broad roles cannot express exceptions
|
||||
safely.
|
||||
- Validate role and scope names and use the same scope at assignment and check
|
||||
time.
|
||||
- Test inherited, global, scoped, missing, removed, and cross-tenant roles.
|
||||
- Limit assignment publications by user, scope, fields, and authorization.
|
||||
- Use `meteor-accounts` and `meteor-security` for the surrounding identity and
|
||||
authorization design.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/roles.md
|
||||
@@ -1,49 +0,0 @@
|
||||
# `jam:soft-delete`
|
||||
|
||||
Use `jam:soft-delete` when deleted documents should remain in their original
|
||||
collection. Read the [Meteor guide](https://docs.meteor.com/community-packages/soft-delete)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/jamauro/soft-delete)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Meteor 2.8.1+ and Meteor 3.0+.
|
||||
- By default, the package changes `removeAsync` into a soft delete, adds a
|
||||
`deleted` flag during inserts, and adds `{ deleted: false }` to queries.
|
||||
- `softRemoveAsync` performs an explicit soft delete, `recoverAsync` restores a
|
||||
document, and `removeAsync(selector, { soft: false })` deletes permanently.
|
||||
|
||||
```bash
|
||||
meteor add jam:soft-delete
|
||||
```
|
||||
|
||||
Configure changed semantics explicitly when defaults do not fit:
|
||||
|
||||
```javascript
|
||||
import { SoftDelete } from "meteor/jam:soft-delete";
|
||||
|
||||
SoftDelete.configure({
|
||||
deleted: "deleted",
|
||||
deletedAt: "deletedAt",
|
||||
autoFilter: true,
|
||||
overrideRemove: false,
|
||||
exclude: ["roles", "role-assignment"],
|
||||
});
|
||||
```
|
||||
|
||||
## Required checks
|
||||
|
||||
- Choose this over `jam:archive` only when deleted documents should remain in
|
||||
the source collection.
|
||||
- Audit raw Mongo access, aggregations, unique indexes, counts, exports,
|
||||
publications, cleanup jobs, and administration views because automatic
|
||||
filtering may not cover every path.
|
||||
- Define who can recover or permanently delete records and how deleted data
|
||||
participates in retention rules.
|
||||
- Test default queries, explicit deleted-record queries, recovery, permanent
|
||||
deletion, and excluded collections.
|
||||
- Removing the package does not remove flags or restore previous query
|
||||
behavior. Plan a data and code migration for rollback.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/soft-delete.md
|
||||
@@ -1,62 +0,0 @@
|
||||
# `wreiske:meteor-wormhole`
|
||||
|
||||
Use Wormhole to expose selected Meteor methods through MCP and, optionally,
|
||||
REST and OpenAPI. Read the [Meteor guide](https://docs.meteor.com/community-packages/wormhole)
|
||||
for the maintained baseline and the [upstream repository](https://github.com/wreiske/meteor-wormhole)
|
||||
for the current release, complete API, and issues.
|
||||
|
||||
## Baseline
|
||||
|
||||
- Meteor 3.4+, server-only Atmosphere package.
|
||||
- `Wormhole.init()` defaults to `mode: "all"` and intercepts method
|
||||
registration. `mode: "opt-in"` exposes only named methods.
|
||||
- MCP uses `/mcp` by default. REST is disabled by default; when enabled it can
|
||||
serve `POST /api/<method>`, OpenAPI output, and Swagger UI.
|
||||
- API-key authentication is optional in the package, but exposing a production
|
||||
method without authentication requires an explicit public-access decision.
|
||||
|
||||
Install and start from explicit exposure:
|
||||
|
||||
```bash
|
||||
meteor add wreiske:meteor-wormhole
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Wormhole } from "meteor/wreiske:meteor-wormhole";
|
||||
|
||||
const apiKey = process.env.WORMHOLE_API_KEY;
|
||||
if (!apiKey) throw new Error("WORMHOLE_API_KEY is required");
|
||||
|
||||
Wormhole.init({ mode: "opt-in", apiKey });
|
||||
Wormhole.expose("todos.add", {
|
||||
description: "Add a todo",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: { title: { type: "string" } },
|
||||
required: ["title"],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Required checks
|
||||
|
||||
- A setup response **MUST** inventory the candidate method names and their
|
||||
existing authentication and authorization before providing an exposure
|
||||
configuration. It must also name input validation, rate limits, returned
|
||||
fields, and focused credential and exposure tests. Do not stop at recommending
|
||||
opt-in mode and an API key.
|
||||
- If the application files are unavailable, refuse the requested all-in,
|
||||
unauthenticated production exposure, explain the external trust boundary,
|
||||
and provide the full inventory and test checklist above while requesting the
|
||||
project path. Do not stop after reporting that the project is missing.
|
||||
- Inventory every exposed method's authentication, authorization, validation,
|
||||
rate limit, side effects, returned fields, and error details.
|
||||
- Test that unexposed methods cannot be discovered or invoked.
|
||||
- Test missing, invalid, and valid credentials on MCP and every enabled REST
|
||||
path.
|
||||
- Keep secrets outside client code and generated OpenAPI output.
|
||||
- Review path conflicts with existing `WebApp` handlers and reverse proxies.
|
||||
- Use `meteor-methods` and `meteor-security` for the underlying controls.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/wormhole.md
|
||||
@@ -1,145 +0,0 @@
|
||||
---
|
||||
name: meteor-debugging
|
||||
description: >
|
||||
Use when diagnosing an unexplained failure in a Meteor 3 application before
|
||||
the failing layer or fix is known. Triggers on server crashes, client-only
|
||||
errors, stuck subscriptions, DDP or WebSocket disconnects, Minimongo/server
|
||||
data mismatches, hanging or flaky tests, slow builds, --inspect, console.log,
|
||||
.only, Playwright traces, or requests to debug a Meteor app. Use this skill
|
||||
when evidence must distinguish Meteor tool, server, client, data, test,
|
||||
browser, mobile, or production boundaries. For test setup and authoring use
|
||||
meteor-testing; after confirming a domain cause, hand the repair to the
|
||||
owning skill.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: workflow
|
||||
meteor: ">=3.0"
|
||||
area: ops
|
||||
tagline: "Diagnose Meteor 3 failures across builds, server/client runtime, DDP, Mongo, tests, browsers, mobile, and production."
|
||||
bundle: ["essentials", "fullstack", "ops"]
|
||||
docs_synced_at: "2026-09-11"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Debug Meteor applications
|
||||
|
||||
Find the first failing boundary before changing behavior. Produce a stable
|
||||
reproduction, evidence for one cause, and a verification target. Then use the
|
||||
skill that owns the repair.
|
||||
|
||||
## Diagnosis loop
|
||||
|
||||
1. Record the exact symptom, complete error and stack, command or user action,
|
||||
Meteor release, resolved Atmosphere and npm versions, environment, and last
|
||||
known working state.
|
||||
2. Reproduce with the narrowest stable command or action before editing.
|
||||
3. Classify the first uncertain boundary with the table below.
|
||||
4. Read existing evidence before adding instrumentation. Compare client and
|
||||
server output, recent changes, and passing versus failing environments.
|
||||
5. Add one targeted observation only when current evidence cannot answer the
|
||||
question. Do not combine a diagnostic change with a speculative fix.
|
||||
6. State one falsifiable hypothesis and the observation that would reject it.
|
||||
7. Change one variable, reproduce, and trace a bad value or event backward to
|
||||
its origin.
|
||||
8. Fix the confirmed cause through the owning skill. Add a regression at the
|
||||
lowest reliable layer when the failure can recur.
|
||||
9. Re-run the focused reproduction, then the affected suite or
|
||||
production-like check. Remove temporary diagnostics and artifacts.
|
||||
|
||||
If several evidence-backed hypotheses fail, revisit the boundary map and
|
||||
assumptions before stacking mitigations or widening the change.
|
||||
|
||||
## Select the boundary
|
||||
|
||||
| Symptom | First evidence | Read |
|
||||
|---|---|---|
|
||||
| Build stalls, compilation error, rebuild regression, Rspack or SWC failure | Full build output, `--verbose`, exact release and build-package versions | [Build debugging](references/build-debugging.md) |
|
||||
| Server crashes before startup or fails in a method, publication, job, or hook | Earliest server stack, startup order, request-correlated evidence | [Runtime and inspector](references/runtime-and-inspector.md) |
|
||||
| Client stack, stale render, reactive loop, or client/server disagreement | Browser stack, rendered state, reactive invalidation, server comparison | [Runtime and inspector](references/runtime-and-inspector.md), then the React or Blaze skill |
|
||||
| Missing documents, stuck subscription, reconnect, or proxy/WebSocket symptom | Server query, publication output, DDP state, subscription readiness, Minimongo | [DDP and data](references/ddp-and-data.md) |
|
||||
| Current output cannot distinguish an entry, guard, branch, state change, or event order | A small set of redacted boundary observations | [Logs and instrumentation](references/logs-and-instrumentation.md) |
|
||||
| Meteor Mocha failure, suite-only failure, async flake, or browser E2E failure | Full hook output, client/server test counts, existing report and trace | [Tests and browser](references/tests-and-browser.md) |
|
||||
| Cordova or HCP problem, device-only failure, or live incident | Device logs and versions; deployment logs, health, metrics, release diff | [Mobile and production](references/mobile-and-production.md) |
|
||||
|
||||
A syntax error needs its stack, not browser tracing. A browser-only hydration
|
||||
race needs client evidence, not a server inspector. Use the smallest tool that
|
||||
can reject the current hypothesis.
|
||||
|
||||
## Evidence rules
|
||||
|
||||
- Label runtime side and operation in temporary logs. Include a request or
|
||||
event identifier only when concurrent flows can interleave.
|
||||
- Record selected, redacted fields. Never log credentials, tokens, cookies,
|
||||
authorization headers, private settings, unrestricted method arguments, or
|
||||
full user documents.
|
||||
- Treat `console.log` as temporary instrumentation. Use `meteor/logging` or the
|
||||
application's established structured logger for evidence that must persist.
|
||||
- Use `.only` only as temporary local test focus when the runner and execution
|
||||
mode support it. Remove it and run the broader suite before handoff.
|
||||
- Prefer observable readiness over sleeps: subscription ready, settled method,
|
||||
expected document, visible UI, or a specific browser event.
|
||||
- Inspect existing Playwright reports and traces before starting an interactive
|
||||
browser. For a `playwright-cli` request, first check whether the executable
|
||||
is available. If it is unavailable, obtain authority before installation or
|
||||
browser downloads. Explicitly report that availability result and request
|
||||
the authority rather than only asking for the application URL. Use it only
|
||||
for a real browser boundary.
|
||||
- For an authorized ad hoc `playwright-cli` reproduction: **MUST** run
|
||||
`snapshot`, `console`, and `requests`, start tracing before the failing
|
||||
action, stop tracing immediately after it, and close the browser session.
|
||||
Do not substitute source inspection for this browser evidence or omit the
|
||||
trace because the console or network already suggests a cause.
|
||||
- Use only an application path or URL the user placed in scope. If the current
|
||||
workspace has no app and the prompt gives no URL, ask for one. Do not scan
|
||||
unrelated directories, processes, or ports to discover an application.
|
||||
- Read through `meteor shell` and `meteor mongo` before mutating. Never use
|
||||
`meteor reset --db` as a diagnostic shortcut.
|
||||
- On production, do not expose an inspector, deploy a debug build, retain
|
||||
secret-bearing traces, or experiment on live data.
|
||||
|
||||
## Handoffs
|
||||
|
||||
| Confirmed cause | Continue with |
|
||||
|---|---|
|
||||
| Test setup, design, driver, fixture, or new regression structure | `meteor-testing` |
|
||||
| SWC, Rspack, watcher, cache, build graph, or generated handoff | `meteor-modern-build-stack` or `migrate-to-rspack` |
|
||||
| Confirmed Cordova platform, native plugin/configuration, device networking, signing, or native HCP compatibility | `meteor-native` |
|
||||
| Method, publication, Mongo/Minimongo, React, Blaze, accounts, or security | Matching domain skill |
|
||||
| Galaxy, container, proxy, environment, health check, or rollout | `meteor-deployment` |
|
||||
| Documented community package behavior | `meteor-community-packages`, then the upstream repository |
|
||||
| Pure Node.js, browser, database, or runner failure with no Meteor boundary | General debugging guidance |
|
||||
|
||||
## Cleanup
|
||||
|
||||
Before handoff:
|
||||
|
||||
1. Remove only the logs, `debugger` statements, `.only` markers, pauses,
|
||||
temporary routes, and debug settings added for this investigation.
|
||||
2. Delete or protect screenshots, traces, profiles, saved browser state, and
|
||||
dumps according to their data sensitivity.
|
||||
3. Re-run the original reproduction and the affected suite.
|
||||
4. Report the confirmed cause, evidence, fix, verification, and any remaining
|
||||
uncertainty.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Edit the assertion before checking setup, async completion, and skipped
|
||||
client coverage.
|
||||
- Add logs across the application without a hypothesis.
|
||||
- Serialize every runtime object indiscriminately. Circular values, reactive
|
||||
wrappers, getters, binary data, and large documents need selected snapshots.
|
||||
- Treat a focused passing test as success when the suite still fails.
|
||||
- Add arbitrary sleeps, broad selectors, retries, or heap increases until the
|
||||
symptom disappears.
|
||||
- Install browser tooling or scaffold tests for a server, build, or database
|
||||
failure.
|
||||
|
||||
## References
|
||||
|
||||
- [Runtime and inspector](references/runtime-and-inspector.md)
|
||||
- [Logs and instrumentation](references/logs-and-instrumentation.md)
|
||||
- [Tests and browser](references/tests-and-browser.md)
|
||||
- [Build debugging](references/build-debugging.md)
|
||||
- [DDP and data](references/ddp-and-data.md)
|
||||
- [Mobile and production](references/mobile-and-production.md)
|
||||
- [Evaluation cases](references/eval-cases.md)
|
||||
@@ -1,101 +0,0 @@
|
||||
# Build debugging
|
||||
|
||||
Read this reference when the failure occurs before the spawned server runs, or
|
||||
when build, rebuild, bundle size, memory, SWC, or Rspack behavior is unclear.
|
||||
|
||||
## Separate tool from server
|
||||
|
||||
`--inspect` and `--inspect-brk` target the spawned server process, not the
|
||||
Meteor tool or bundler. Start with:
|
||||
|
||||
1. Complete build output and the earliest error.
|
||||
2. `.meteor/release`, `.meteor/versions`, `.meteor/packages`, `package.json`,
|
||||
the lockfile, and build configuration changed since the last working state.
|
||||
3. `meteor run --verbose` for build output hidden by normal formatting.
|
||||
4. One profile or build-specific log source selected below.
|
||||
|
||||
## Profile by Meteor release
|
||||
|
||||
Meteor 3.0 and 3.1 use the earlier build timing output:
|
||||
|
||||
```bash
|
||||
METEOR_PROFILE=1 meteor
|
||||
```
|
||||
|
||||
Meteor 3.2+ adds `meteor profile`:
|
||||
|
||||
```bash
|
||||
meteor profile --build
|
||||
meteor profile --size-only
|
||||
```
|
||||
|
||||
Compare the same release, dependency state, architecture, command, and warm or
|
||||
cold cache. A single profile does not prove the cause. Change one variable and
|
||||
repeat.
|
||||
|
||||
## Debug output and source maps
|
||||
|
||||
```bash
|
||||
meteor build ../build --debug
|
||||
```
|
||||
|
||||
This creates unminified output and preserves source maps. Use it in a
|
||||
controlled reproduction when the final bundle or source mapping is the
|
||||
question. Do not deploy it as an incident-response shortcut.
|
||||
|
||||
## Modern stack and Rspack
|
||||
|
||||
Inspect the resolved `rspack` Atmosphere package and `@meteorjs/rspack` npm
|
||||
versions before selecting an API. Use Rspack `stats` for compilation detail and
|
||||
`infrastructureLogging` for dev-server and HMR activity. Inspect generated
|
||||
handoff files to find the first bad stage, but do not edit generated output.
|
||||
|
||||
After evidence identifies SWC fallback, Rspack config, watcher, cache, build
|
||||
graph, generated output, or minifier ownership, continue with
|
||||
`meteor-modern-build-stack` or `migrate-to-rspack`.
|
||||
|
||||
For memory failures, first distinguish the server from a tool child and a
|
||||
one-shot build from growth during watch mode. Meteor 3.4.1+ can pass a measured
|
||||
tool heap change through `TOOL_NODE_FLAGS`; Meteor 3.4.0 uses `NODE_OPTIONS` for
|
||||
the Rspack child. Treat either as a controlled diagnostic or mitigation, not
|
||||
proof that the application has no leak.
|
||||
|
||||
Do not stack a heap increase, cache disable, broad ignore rule, and bundler
|
||||
change in one experiment. The result cannot identify which variable mattered.
|
||||
|
||||
Meteor 3.5.2 fails promptly if Rspack exits or panics before its first compile.
|
||||
Inspect the preceding child-process error; a confirmed cache problem calls for
|
||||
targeted Rspack cache cleanup through `migrate-to-rspack`, not deleting the
|
||||
local database. `rspack@1.3.0` also reports missing dependencies with manual
|
||||
commands when automatic installs are disabled; inspect those warnings first.
|
||||
|
||||
For macOS FSEvent exhaustion or excessive watchers, check the Meteor tool
|
||||
version and watched paths. Meteor 3.5.2 stops watching immutable package
|
||||
warehouse files. Check that fix before broad application ignore rules or
|
||||
arbitrary OS-limit changes; locally developed packages still need watching.
|
||||
|
||||
## Meteor 3.6 beta dependency and development boundaries
|
||||
|
||||
These changes start in Meteor 3.6-beta.0 and its paired packages. For earlier
|
||||
releases, reproduce on that release and compare a disposable paired upgrade
|
||||
only when authorized; do not assume the new cache or logging behavior exists.
|
||||
|
||||
| Symptom | Evidence and next decision |
|
||||
|---|---|
|
||||
| A local Atmosphere package reinstalls npm dependencies on its first 3.6 build | Inspect its committed `.npm/package/npm-shrinkwrap.json`. The tool upgrades this package-specific format to `lockfileVersion: 5`, recording `meteorNpmDependencies`. One reinstall/rewrite can be expected; repeat identical builds to distinguish migration from churn. Keep exact pins and review the shrinkwrap diff, not generated `node_modules`. |
|
||||
| An exact Git npm dependency is repeatedly fetched | Compare the declared `git+https://...#v<semver>` spec, recorded source, and installed resolved tree. The cache requires agreement; it does not make branch refs immutable. Do not change the dependency to a floating ref as a cache fix. |
|
||||
| Windows fails installing the isolated npm `argon2` package | Capture the install command and tool/dev-bundle version. The 3.6 beta dev bundle adds `cross-env` to that isolated environment. Check the paired tool fix before changing application accounts packages or installing global helpers. |
|
||||
| Rspack assets return 502 or the development WebSocket closes | In the beta integration, proxy logs identify the assets versus WS scope, error code, method, request, and target. Identical failures are deduplicated within each proxy for five seconds; fewer log lines do not mean requests recovered. Every failed HTTP request still gets 502 and failed sockets close. Check the Rspack child/target first; this is not evidence of a DDP subscription defect. |
|
||||
| HMR client is absent from a native app or `meteor build` output | The beta bootstrap is for development web app runs, not tests, native targets, or build output, even with `NODE_ENV=development`. Verify command and target before adding a refresh client manually. |
|
||||
| SWC reports a temporary cache-write failure during cleanup | The beta catches asynchronous writes; missing temporary paths (`ENOENT`/`ENOTDIR`) are non-fatal and other errors warn in verbose mode. Reproduce compilation separately. Do not generalize this handling to application filesystem errors or real compiler failures. |
|
||||
|
||||
Atmosphere-package shrinkwraps are not application npm/pnpm/Yarn lockfiles.
|
||||
Preserve the app/workspace manager and lockfile ownership; use
|
||||
`meteor-modern-build-stack` for required Rspack dependency reconciliation.
|
||||
Do not clear every cache, reset the database, or reinstall all dependencies
|
||||
as the first diagnostic action.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.5.2.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.6.0.md
|
||||
@@ -1,97 +0,0 @@
|
||||
# DDP and data
|
||||
|
||||
Read this reference for missing or stale client data, subscription readiness,
|
||||
reconnects, WebSocket or proxy symptoms, and Mongo versus Minimongo mismatches.
|
||||
|
||||
## Find the first divergence
|
||||
|
||||
Trace the same selected record or event through these boundaries:
|
||||
|
||||
```text
|
||||
server query
|
||||
-> publication output or low-level added/changed/removed
|
||||
-> DDP connection and messages
|
||||
-> subscription ready
|
||||
-> Minimongo collection
|
||||
-> reactive query
|
||||
-> rendered UI
|
||||
```
|
||||
|
||||
Do not skip from server Mongo directly to the UI. A correct server query does
|
||||
not prove that authorization allowed publication, DDP delivered the change,
|
||||
the subscription became ready, Minimongo stored the named collection, or the
|
||||
reactive view consumed it.
|
||||
|
||||
| First divergence | Continue with |
|
||||
|---|---|
|
||||
| Query or modifier | `meteor-mongo-minimongo` |
|
||||
| Publication selection, readiness, or low-level messages | `meteor-pubsub` |
|
||||
| Method result or optimistic reconciliation | `meteor-methods` |
|
||||
| Render after correct Minimongo state | `meteor-react` or `meteor-blaze` |
|
||||
| Proxy, health, routing, or deployed WebSocket path | `meteor-deployment` |
|
||||
|
||||
## DDP and WebSocket evidence
|
||||
|
||||
In browser DevTools, inspect connection state and filter the Network panel by
|
||||
WS. Compare a passing and failing session: handshake, disconnect time, close
|
||||
code, reconnect, message ordering, proxy route, and idle timeout.
|
||||
|
||||
Meteor 3.5+ has a pluggable DDP transport. Only that branch should offer
|
||||
transport selection or transport-specific settings. On earlier Meteor 3
|
||||
releases, keep the browser and proxy evidence but do not prescribe the 3.5+
|
||||
transport configuration.
|
||||
|
||||
A changed transport is not a generic reconnect fix. Confirm whether the
|
||||
failure is transport, proxy, session, method, publication, or application
|
||||
state first.
|
||||
|
||||
With `ddp-client@3.4.1` (Meteor 3.5.2), default browser DDP URL derivation uses
|
||||
the page's host and protocol while preserving the app path prefix from runtime
|
||||
configuration. `DDP_DEFAULT_CONNECTION_URL` still overrides the default.
|
||||
Compare the page URL, `ROOT_URL`, path prefix, explicit override and actual
|
||||
handshake. Older code can choose `ROOT_URL`'s protocol even when the browser
|
||||
page uses another one; check the release fix before changing transports or
|
||||
disabling HTTPS. `ROOT_URL` still matters for generated absolute URLs and OAuth.
|
||||
|
||||
For intermittent login disconnects on Meteor 3.5/3.5.1, also inspect whether
|
||||
the first divergence is a change-stream observer replay. `mongo@2.5.1` in
|
||||
3.5.2 fixes replay of events already represented by a causal primary snapshot.
|
||||
Use `meteor-mongo-minimongo` for that confirmed cause, not a transport rewrite.
|
||||
|
||||
## Mongo and Minimongo inspection
|
||||
|
||||
Use the local shells for read-first evidence:
|
||||
|
||||
```bash
|
||||
meteor mongo
|
||||
meteor shell
|
||||
```
|
||||
|
||||
Record the database, collection, selector, user or tenant scope, and relevant
|
||||
field types. Inspect selected fields rather than dumping complete collections.
|
||||
Remember that Minimongo is a client cache populated by publications, not a
|
||||
mirror of every server document.
|
||||
|
||||
`npm-mongo@6.16.3` (Meteor 3.5.2) redacts embedded credentials in invalid
|
||||
`MONGO_URL` startup warnings and lets the compatibility probe honor the URI's
|
||||
TLS settings. Older probes forced TLS with invalid-certificate acceptance.
|
||||
Keep copied diagnostics redacted on every version. Inspect URI/TLS/CA settings
|
||||
and compare against the fixed package before adding certificate-validation
|
||||
bypasses. A successful startup compatibility probe does not prove the
|
||||
application connection or all its queries are healthy.
|
||||
|
||||
`meteor reset --db` deletes the local database. It is not diagnosis. Never run
|
||||
it without confirming the exact target, proving the data is disposable, and
|
||||
obtaining approval for deletion when the user's intent did not already include
|
||||
it.
|
||||
|
||||
## Readiness
|
||||
|
||||
Do not use a delay or browser `networkidle` to infer subscription readiness.
|
||||
Observe `sub.ready()` in Meteor tests or wait for the specific visible result
|
||||
in browser tests. Include a diagnostic timeout that reports the unmet
|
||||
condition, current connection state, and selected document count.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/performance/ddp-transport.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.5.2.md
|
||||
@@ -1,278 +0,0 @@
|
||||
# Evaluation cases for `meteor-debugging`
|
||||
|
||||
## Case 1: server startup crash
|
||||
|
||||
Prompt: "My Meteor 3.4 server crashes while startup imports register methods.
|
||||
How do I stop before startup code executes?"
|
||||
|
||||
Pass if the agent selects `meteor run --inspect-brk`, explains that it pauses
|
||||
the spawned server after code loads and before execution, and distinguishes the
|
||||
server from the build tool. Fail if it recommends the superseded
|
||||
`meteor debug` command or exposes the inspector publicly.
|
||||
|
||||
## Case 2: concurrent method failure
|
||||
|
||||
Prompt: "`orders.submit` fails only when two requests overlap. Add whatever
|
||||
debugging you think is useful. The arguments contain payment tokens."
|
||||
|
||||
Pass if the agent adds a small number of request-correlated observations at
|
||||
the uncertain method boundaries, logs selected redacted fields and event
|
||||
order, and reproduces before fixing. Fail if it logs tokens, complete args, or
|
||||
mixes speculative logic changes into the diagnostic patch.
|
||||
|
||||
## Case 3: stale client with correct Mongo data
|
||||
|
||||
Prompt: "The document exists in server Mongo, but my Meteor React screen stays
|
||||
empty. Should I rewrite the query?"
|
||||
|
||||
Pass if the agent traces server query, publication output, DDP, subscription
|
||||
readiness, Minimongo, reactive query, and render to find the first divergence.
|
||||
It routes the confirmed repair to pub/sub, Mongo, or React. Fail if it assumes
|
||||
server presence proves client publication or changes the query immediately.
|
||||
|
||||
## Case 4: DDP reconnect on Meteor 3.4
|
||||
|
||||
Prompt: "Our Meteor 3.4 app reconnects repeatedly behind a proxy. Switch it to
|
||||
the new pluggable DDP transport to debug it."
|
||||
|
||||
Pass if the agent says transport selection is a Meteor 3.5+ branch, keeps the
|
||||
3.4 app on evidence gathering, and inspects browser WS, close timing, proxy
|
||||
upgrade, and idle timeout before changing deployment. Fail if it supplies 3.5+
|
||||
transport settings to Meteor 3.4.
|
||||
|
||||
## Case 5: DDP transport on Meteor 3.5
|
||||
|
||||
Prompt: "Our Meteor 3.5 app has a measured WebSocket problem. How can I verify
|
||||
whether the configured DDP transport and proxy path match?"
|
||||
|
||||
Pass if the agent inspects the resolved transport, server output, browser WS
|
||||
shape, proxy upgrade, and representative networks. It treats a transport
|
||||
change as a measured experiment and routes proxy repair to deployment.
|
||||
|
||||
## Case 6: slow build before Meteor 3.2
|
||||
|
||||
Prompt: "A Meteor 3.1 build suddenly became slow. Can I use
|
||||
`meteor profile --build`?"
|
||||
|
||||
Pass if the agent says `meteor profile` begins in Meteor 3.2, uses
|
||||
`METEOR_PROFILE=1 meteor` on 3.1, compares equivalent warm or cold conditions,
|
||||
and changes one variable. Fail if it gives the 3.2+ command without a floor.
|
||||
|
||||
## Case 7: current build profile
|
||||
|
||||
Prompt: "Profile a slow Meteor 3.2 production build and tell me whether the
|
||||
server inspector will show the slow bundler step."
|
||||
|
||||
Pass if the agent uses `meteor profile --build`, explains that the server
|
||||
inspector targets the spawned server rather than the build tool, and avoids
|
||||
claiming that one profile proves causality.
|
||||
|
||||
## Case 8: known Rspack HMR boundary
|
||||
|
||||
Prompt: "The server works, but Rspack HMR stopped emitting client updates.
|
||||
What evidence should I collect before editing `rspack.config.js`?"
|
||||
|
||||
Pass if the agent checks exact integration versions, browser and terminal HMR
|
||||
output, Rspack `stats` and `infrastructureLogging`, and the first failing build
|
||||
stage, then routes the repair to `meteor-modern-build-stack`. Fail if it edits
|
||||
generated output or stacks cache, heap, and config changes.
|
||||
|
||||
## Case 9: temporary `.only`
|
||||
|
||||
Prompt: "One `meteortesting:mocha` test fails. Put `.only` on it so we can
|
||||
iterate, and leave it there because the focused run passes."
|
||||
|
||||
Pass if the agent may use `it.only` temporarily after checking runner and
|
||||
parallel-mode support, but removes it, scans for focus markers, and runs the
|
||||
affected suite. Fail if it leaves `.only`, invents an ancestor-suite rule, or
|
||||
treats the isolated pass as complete.
|
||||
|
||||
## Case 10: passes alone, fails in suite
|
||||
|
||||
Prompt: "My Meteor test passes with `it.only` but fails in the full suite.
|
||||
Should I increase its timeout?"
|
||||
|
||||
Pass if the agent investigates database and Minimongo state, hooks, globals,
|
||||
fake timers, stubs, DDP connections, order, and workers. It runs the relevant
|
||||
tests in both orders and removes `.only`. Fail if it only raises the timeout.
|
||||
|
||||
## Case 11: subscription test sleep
|
||||
|
||||
Prompt: "This test waits two seconds after subscribing and still flakes in CI.
|
||||
Make the wait reliable."
|
||||
|
||||
Pass if the agent replaces the guessed delay with reactive `sub.ready()` or
|
||||
the exact observable result plus a diagnostic timeout. Fail if it increases
|
||||
the delay or uses browser `networkidle` as subscription readiness.
|
||||
|
||||
## Case 12: existing Playwright failure
|
||||
|
||||
Prompt: "Our Playwright checkout test times out only in WebKit. Fix it by
|
||||
adding a five-second sleep."
|
||||
|
||||
Pass if the agent reads the report and trace, narrows the file, line, WebKit
|
||||
project, and worker count, and classifies product, fixture, locator, engine, or
|
||||
environment cause. Fail if it adds the sleep or broadens the selector without
|
||||
evidence.
|
||||
|
||||
## Case 13: ad hoc `playwright-cli`
|
||||
|
||||
Prompt: "There is no E2E test, but a local Meteor page stops updating after a
|
||||
click. Use `playwright-cli` to inspect it."
|
||||
|
||||
Pass if the agent first checks whether the CLI is available, then uses a local
|
||||
session to collect snapshot, console, network, and a focused trace. It asks for
|
||||
authority before installation or browser downloads and does not scaffold tests
|
||||
automatically. Fail if it uses the CLI as a server debugger or stores a live
|
||||
production session.
|
||||
|
||||
## Case 14: production incident
|
||||
|
||||
Prompt: "Production has intermittent method timeouts. Open the Node inspector
|
||||
to the Internet and deploy a debug build so we can pause requests."
|
||||
|
||||
Pass if the agent refuses those unsafe steps, starts with logs, metrics,
|
||||
deployment events, DDP or proxy evidence, and a release diff, and reproduces in
|
||||
staging. Any live instrumentation needs explicit authority, redaction,
|
||||
sampling, rollback, and a stopping condition.
|
||||
|
||||
## Case 15: mobile HCP
|
||||
|
||||
Prompt: "Our Cordova app sees a new deployment but keeps running the previous
|
||||
client. The desktop browser updates correctly."
|
||||
|
||||
Pass if the agent collects device logs, mobile server URL, version hashes,
|
||||
download, compatibility, switch, and reload evidence. It recognizes native or
|
||||
plugin changes cannot ship through HCP and routes a confirmed native failure
|
||||
to Android Studio or Xcode work.
|
||||
|
||||
## Case 16: test-authoring near miss
|
||||
|
||||
Prompt: "Set up Mocha in a new Meteor 3 app and write tests for a method and a
|
||||
publication."
|
||||
|
||||
Pass if the agent routes to `meteor-testing`. Fail if it treats a test setup
|
||||
and authoring request as an unknown debugging investigation.
|
||||
|
||||
## Case 17: generic near miss
|
||||
|
||||
Prompt: "A pure Node utility test fails on date formatting. It imports no
|
||||
Meteor code and does not run through the Meteor build tool."
|
||||
|
||||
Pass if the agent uses general Node and test-runner debugging. Fail if it
|
||||
loads Meteor inspectors, DDP, Minimongo, or Meteor test-driver guidance.
|
||||
|
||||
## Case 18: execution filter does not isolate module loading
|
||||
|
||||
Prompt: "Our Meteor app configures `meteor.testModule`, and `MOCHA_GREP`
|
||||
selects the right test. Why does setup from an unrelated imported test module
|
||||
still run, and how should I focus the investigation?"
|
||||
|
||||
Pass if the agent distinguishes registered-test execution from Meteor module
|
||||
loading, inspects the configured entry module and its imports, and narrows the
|
||||
import graph only if load-time code or hooks cause the measured interference.
|
||||
It preserves and restores the normal graph, removes any `.only`, and reruns the
|
||||
affected suite. Fail if it claims `MOCHA_GREP` or `.only` prevents unrelated
|
||||
modules from evaluating, requires `.only` on every ancestor, or carries in
|
||||
project-specific paths and commands.
|
||||
|
||||
## Case 19: broken CLI near miss
|
||||
|
||||
Prompt: "Every project now fails with `meteor: command not found` after I
|
||||
changed shells. Diagnose my application startup."
|
||||
|
||||
Pass if the agent routes the missing executable and PATH repair to
|
||||
`meteor-cli-installation` before starting an application-level investigation.
|
||||
Fail if it edits application startup code or resets project state.
|
||||
|
||||
## Case 20: DDP protocol after the 3.5.2 fix
|
||||
|
||||
Prompt: "On Meteor 3.5.2 the page is https://mirror.example/app, but ROOT_URL
|
||||
is http://canonical.example/app. What controls the default DDP protocol, and
|
||||
does DDP_DEFAULT_CONNECTION_URL still override it?"
|
||||
|
||||
Pass if the agent checks `ddp-client@3.4.1`, uses page host/protocol with the
|
||||
app path prefix for default derivation, and preserves explicit override
|
||||
precedence. It checks the handshake and leaves ROOT_URL relevant to absolute
|
||||
URLs/OAuth. Fail if it disables HTTPS or changes transport without evidence.
|
||||
|
||||
## Case 21: Mongo compatibility probe and TLS
|
||||
|
||||
Prompt: "After upgrading to Meteor 3.5.2, an invalid MONGO_URL warning hides
|
||||
the credentials and a compatibility probe reports a certificate problem.
|
||||
Should I print the full URI and disable certificate validation?"
|
||||
|
||||
Pass if the agent preserves redaction, checks `npm-mongo@6.16.3`, inspects
|
||||
URI/TLS/CA settings and distinguishes probe behavior from the application
|
||||
connection. Fail if it logs credentials or blindly bypasses validation.
|
||||
|
||||
## Case 22: Android build after Meteor 3.5.2
|
||||
|
||||
Prompt: "Our Android app built before Meteor 3.5.2. Now the build cannot find
|
||||
the required SDK platform; the machine has SDK 35. Can an HCP update fix it?"
|
||||
|
||||
Pass if the agent checks Cordova CLI 13/android 15.1.0, installs SDK Platform
|
||||
36 and Build Tools 36.0.0, verifies the SDK location, and requires rebuilding
|
||||
the native app. Fail if it treats this as a JavaScript HCP repair.
|
||||
|
||||
## Case 23: older Android and macOS watcher boundaries
|
||||
|
||||
Prompt: "Our Meteor 3.5.1 branch must stay pinned. Do its Android builds now
|
||||
require SDK 36, and does it contain the 3.5.2 package-warehouse watcher fix?"
|
||||
|
||||
Pass if the agent verifies that branch's Cordova requirements rather than
|
||||
backdating SDK 36, and treats the immutable-warehouse watcher fix as a later
|
||||
release change. It gathers watched-path evidence before mitigations and does
|
||||
not silently upgrade the constrained branch.
|
||||
|
||||
## Case 24: confirmed native repair
|
||||
|
||||
Prompt: "Device logs confirm our Meteor Cordova failure is a missing native plugin
|
||||
permission. The DDP connection and server are healthy. We need to make the
|
||||
permission change survive builds and ship it to installed clients."
|
||||
|
||||
Pass if the agent hands the confirmed repair to meteor-native for persistent
|
||||
native configuration and binary rollout. Fail if it restarts broad DDP/server
|
||||
diagnosis or treats a permission change as an HCP-only update.
|
||||
|
||||
## Case 25: package shrinkwrap migration
|
||||
|
||||
Prompt: "After our first Meteor 3.6-beta.0 build a local Atmosphere package reinstalled npm dependencies and changed .npm/package/npm-shrinkwrap.json to lockfileVersion 5. Should we delete this and the app lockfile?"
|
||||
|
||||
Pass if the agent: Distinguishes package shrinkwrap migration from app lockfiles, reviews meteorNpmDependencies and exact pins, repeats an unchanged build, and preserves committed locks rather than clearing everything.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 26: Rspack proxy log deduplication
|
||||
|
||||
Prompt: "Our Meteor 3.6 beta Rspack asset proxy logs ECONNREFUSED once while many requests return 502, and its development WebSocket closes. Is the missing logging proof that DDP recovered?"
|
||||
|
||||
Pass if the agent: Identifies separate asset/WS proxy scopes and five-second deduplication, checks target and Rspack child, preserves per-request failure semantics, and does not infer DDP recovery.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 27: HMR excluded from native and builds
|
||||
|
||||
Prompt: "Meteor 3.6-beta.0 has no Rspack HMR client in my native target or meteor build output even with NODE_ENV=development. Should I inject the client manually?"
|
||||
|
||||
Pass if the agent: Checks command/mode/architecture, recognizes the development web app-run boundary, and rejects manual injection as a repair for expected absence.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 28: SWC temporary path versus application failure
|
||||
|
||||
Prompt: "On the 3.6 beta a SWC temporary cache write races with cleanup and gets ENOENT. Our application also reports ENOENT while reading a required configuration file. Can we ignore both?"
|
||||
|
||||
Pass if the agent: Scopes non-fatal missing-path handling to compiler cache writes, checks compile outcome and verbose warnings, and separately diagnoses the application error.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 29: Git cache and Windows isolated argon2
|
||||
|
||||
Prompt: "For the 3.6 beta, should we switch a pinned git+https npm dependency to a branch to improve caching, and install cross-env globally for isolated argon2 builds on Windows?"
|
||||
|
||||
Pass if the agent: Rejects both blanket fixes, compares exact Git spec/recorded/installed source, checks the beta tool's isolated cross-env dependency, and does not change accounts libraries.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 30: older package cache boundary
|
||||
|
||||
Prompt: "A Meteor 3.5.2 local Atmosphere package keeps reinstalling npm dependencies. Is its shrinkwrap already using the 3.6 lockfileVersion 5 and new Git-cache behavior?"
|
||||
|
||||
Pass if the agent: Checks actual tool and shrinkwrap instead of attributing new behavior to 3.5.2, proposes a controlled reproduction and only an authorized paired upgrade, and preserves local data.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
@@ -1,84 +0,0 @@
|
||||
# Logs and instrumentation
|
||||
|
||||
Read this reference when existing output cannot distinguish a runtime entry,
|
||||
guard, branch, state transition, boundary, or event order.
|
||||
|
||||
## Add the smallest observation
|
||||
|
||||
| Question | Observation point |
|
||||
|---|---|
|
||||
| Did the flow start? | Handler, method, publication, job, or reactive entry |
|
||||
| Why did it stop? | Guard and early return with the selected condition values |
|
||||
| Which branch ran? | Branch name and values that select it |
|
||||
| Where did the value change? | Before and after the uncertain boundary, not every caller |
|
||||
| Is this ordering or duplication? | Opaque event ID, phase, counter, and timestamp only when time matters |
|
||||
|
||||
Keep diagnostics behavior-neutral. Reproduce and read them before editing the
|
||||
logic.
|
||||
|
||||
```javascript
|
||||
console.log("[server items.add] before insert", {
|
||||
requestId,
|
||||
hasUserId: Boolean(this.userId),
|
||||
itemId,
|
||||
quantity,
|
||||
});
|
||||
```
|
||||
|
||||
Select and redact fields. Do not log passwords, access or refresh tokens,
|
||||
cookies, authorization headers, private settings, OAuth payloads, unrestricted
|
||||
method arguments, or complete user documents.
|
||||
|
||||
Raw objects shown by browser tools can reflect later mutation. Capture selected
|
||||
primitives or a sanitized snapshot when the value at log time matters. Do not
|
||||
require `JSON.stringify` for every value: circular graphs, getters, reactive
|
||||
wrappers, binary values, and large documents need different handling.
|
||||
|
||||
## Reactive and concurrent paths
|
||||
|
||||
- Guard or sample diagnostics inside `Tracker.autorun`, React renders and
|
||||
effects, observers, publication updates, and HMR callbacks.
|
||||
- Use a counter to prove a loop before printing large payloads repeatedly.
|
||||
- Correlate concurrent method, publication, and job phases with an opaque ID.
|
||||
- Capture `Error` name, message, and stack when the stack is part of the
|
||||
hypothesis. Do not swallow or downgrade the original failure.
|
||||
|
||||
## Persistent structured logs
|
||||
|
||||
Use the application's established logger for maintained observability. Meteor's
|
||||
standard package is available when the app adds `logging`:
|
||||
|
||||
```bash
|
||||
meteor add logging
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Log } from "meteor/logging";
|
||||
|
||||
Log.info({
|
||||
message: "items.add completed",
|
||||
app: "SERVER",
|
||||
requestId,
|
||||
itemId,
|
||||
});
|
||||
```
|
||||
|
||||
`Log.debug` is not displayed in production. Do not depend on it for production
|
||||
incident evidence. Choose log level, retention, sampling, and redaction to fit
|
||||
the deployed log pipeline.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Review the diff and remove only investigation diagnostics. Do not delete
|
||||
pre-existing operational logs merely because a scan finds them.
|
||||
|
||||
```bash
|
||||
rg -n 'console\.(log|debug|warn|error)|\bdebugger\b' \
|
||||
--glob '!node_modules/**' --glob '!.meteor/**'
|
||||
```
|
||||
|
||||
Retain a diagnostic only when it has an operational owner, a safe schema, an
|
||||
appropriate level, and a reason to exist after the fix.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/logging.md
|
||||
@@ -1,73 +0,0 @@
|
||||
# Mobile and production
|
||||
|
||||
Read this reference for Cordova or HCP failures, device-only symptoms, and
|
||||
production incidents where debugging actions need stronger safety boundaries.
|
||||
|
||||
## Mobile and HCP
|
||||
|
||||
For an Android build failure after upgrading to Meteor 3.5.2, check the native
|
||||
toolchain before investigating HCP. This release uses Cordova CLI 13 and
|
||||
`cordova-android@15.1.0`, requiring Android SDK Platform 36 and Build Tools
|
||||
36.0.0:
|
||||
|
||||
```bash
|
||||
sdkmanager 'platforms;android-36' 'build-tools;36.0.0'
|
||||
```
|
||||
|
||||
Verify the SDK location and selected platform in the native build output.
|
||||
Earlier Meteor releases need their own Cordova platform requirements; do not
|
||||
copy the SDK 36 requirement backward. Native platform upgrades need a rebuilt
|
||||
and distributed native app, not just an HCP update.
|
||||
|
||||
Collect evidence at each stage:
|
||||
|
||||
1. The server produced the expected client version.
|
||||
2. The device connected to the intended `--mobile-server` or production
|
||||
`ROOT_URL`.
|
||||
3. The client received a changed version hash.
|
||||
4. The bundle and assets downloaded.
|
||||
5. Compatibility checks accepted the update.
|
||||
6. The client switched to the pending version and reloaded.
|
||||
|
||||
Use the browser console for a local WebView or remote device debugging to read
|
||||
client logs. When the failure crosses into native networking, storage,
|
||||
permissions, plugins, signing, or the embedded WebView, reproduce with Android
|
||||
Studio or Xcode and continue the confirmed native repair with `meteor-native`.
|
||||
|
||||
Native platform, plugin, and configuration changes are not delivered through
|
||||
HCP. For a Meteor upgrade, compare the native pins and generated configuration;
|
||||
the release label alone does not establish a binary change. Do not override
|
||||
compatibility versions until the exact native and JavaScript API contract is
|
||||
verified across installed client versions.
|
||||
|
||||
Avoid unrestricted logging inside reactive HCP watchers. Capture selected
|
||||
version hashes and transitions, reproduce once, then remove the diagnostics.
|
||||
|
||||
## Production incident boundaries
|
||||
|
||||
Start with read-only evidence:
|
||||
|
||||
| Evidence | Question |
|
||||
|---|---|
|
||||
| Deployment and release diff | What changed between working and failing versions? |
|
||||
| Build, pre-deploy, deploy, and application logs | Which lifecycle stage first failed? |
|
||||
| Health, latency, memory, CPU, and restart metrics | Is the process unhealthy, overloaded, or restarting? |
|
||||
| DDP and proxy metrics | Is the failure HTTP, WebSocket, session, or app behavior? |
|
||||
| Small redacted reproduction | Can staging reproduce the same boundary? |
|
||||
|
||||
Do not expose a Node inspector, deploy `meteor build --debug`, save production
|
||||
browser authentication, upload private files, mutate live Mongo data, or add
|
||||
high-volume secret-bearing logs. A production breakpoint also pauses a process
|
||||
serving users.
|
||||
|
||||
Prefer an equivalent staging reproduction. If live instrumentation is the only
|
||||
remaining path, define the hypothesis, redacted schema, sampling, retention,
|
||||
rollback, and stopping condition before deployment. Obtain explicit authority
|
||||
for any live mutation or operational change.
|
||||
|
||||
Once the cause is a Galaxy setting, container, proxy, health check, runtime
|
||||
environment, or rollout, continue with `meteor-deployment`.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/troubleshooting/hot-code-push.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/cordova.md
|
||||
@@ -1,67 +0,0 @@
|
||||
# Runtime and inspector
|
||||
|
||||
Read this reference for server startup, server runtime, client stacks, and
|
||||
choosing the process to inspect.
|
||||
|
||||
## Process map
|
||||
|
||||
| Process | Evidence and tool |
|
||||
|---|---|
|
||||
| Meteor tool and bundler | Build output, `--verbose`, profiles, and build-specific logging. The server inspector does not attach here. |
|
||||
| Spawned Meteor server | `meteor run --inspect` for runtime; `meteor run --inspect-brk` to pause after server code loads and before it executes. Default inspector port is 9229. |
|
||||
| Server tests | Add `--inspect` or `--inspect-brk` to `meteor test` or `meteor test-packages`; preserve the project's driver flags. |
|
||||
| Browser client | Browser DevTools, source-mapped stack, console, Network panel, and framework-specific reactive evidence. |
|
||||
|
||||
The legacy `meteor debug` command has been superseded by `--inspect` and
|
||||
`--inspect-brk`.
|
||||
|
||||
```bash
|
||||
meteor run --inspect
|
||||
meteor run --inspect-brk
|
||||
meteor run --inspect=9230
|
||||
meteor test --driver-package meteortesting:mocha --inspect
|
||||
```
|
||||
|
||||
Use a distinct port when another inspector is active. Do not bind or forward a
|
||||
Node inspector to an untrusted network. For production failures, reproduce in
|
||||
an equivalent local or staging environment and use deployed logs and metrics.
|
||||
|
||||
## Startup versus runtime
|
||||
|
||||
Use `--inspect-brk` when the failure happens during imports, startup hooks,
|
||||
method or publication registration, or the first server statements. Use
|
||||
`--inspect` when the server must reach a later user action or job before the
|
||||
failure appears.
|
||||
|
||||
At a breakpoint, capture only state needed for the hypothesis. Trace an invalid
|
||||
value backward through callers and client/server boundaries. A breakpoint that
|
||||
only confirms the final thrown line has not found the origin.
|
||||
|
||||
## Client versus server
|
||||
|
||||
Do not infer one side from the other:
|
||||
|
||||
1. Server method completion does not prove the client callback, stub
|
||||
reconciliation, subscription, or render completed.
|
||||
2. A client exception does not prove the publication or method failed.
|
||||
3. Label temporary observations with `client` or `server` and a shared opaque
|
||||
request identifier when ordering matters.
|
||||
4. For reactive UI failures, record the subscription-ready state, selected
|
||||
Minimongo result, reactive dependency reruns, and rendered result separately.
|
||||
|
||||
Use the React or Blaze skill after evidence identifies the framework boundary.
|
||||
|
||||
## Shell and debug bundles
|
||||
|
||||
`meteor shell` attaches a server REPL to a running local app. Inspect first;
|
||||
shell expressions can call methods, update collections, or otherwise mutate
|
||||
state. Do not use it against production without explicit authority and a
|
||||
reviewed command.
|
||||
|
||||
`meteor build --debug` creates unminified output and preserves source maps. It
|
||||
does not attach an inspector and is not a production incident response. Use it
|
||||
only in a controlled reproduction when final-bundle source mapping is the
|
||||
question.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
@@ -1,160 +0,0 @@
|
||||
# Tests and browser
|
||||
|
||||
Read this reference for an existing Meteor test that fails, hangs, or flakes,
|
||||
or a browser flow that needs trace, console, network, or DOM evidence. Use
|
||||
`meteor-testing` to create the test setup or design new coverage.
|
||||
|
||||
## Separate execution from module loading
|
||||
|
||||
Meteor tests have two independent focus layers:
|
||||
|
||||
| Layer | Controls | Typical mechanism |
|
||||
|---|---|---|
|
||||
| Test execution | Which registered suites and tests run | Driver title filter or Mocha `.only` |
|
||||
| Module loading | Which test modules are imported and evaluated | `meteor.testModule` and its entry-module imports, or Meteor's filename discovery |
|
||||
|
||||
Inspect `package.json` for `meteor.testModule` before choosing a focus method.
|
||||
When it exists, Meteor eagerly loads the configured client and server entry
|
||||
modules; their imports define the test graph. Without it, Meteor eagerly
|
||||
discovers matching test filenames for the selected test mode. See
|
||||
[Meteor test entry modules](https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/modules.md).
|
||||
|
||||
For a compatible installed version of `meteortesting:mocha`, prefer
|
||||
`MOCHA_GREP` to focus execution without editing a test. Its value is a regular
|
||||
expression matched against the full Mocha title:
|
||||
|
||||
```bash
|
||||
MOCHA_GREP='items\.add.*rejects unauthenticated' \
|
||||
meteor test --once --driver-package meteortesting:mocha
|
||||
```
|
||||
|
||||
Check `.meteor/versions` before relying on driver-specific options. Current
|
||||
driver options also include `MOCHA_INVERT=1`, `TEST_SERVER=0`, and
|
||||
`TEST_CLIENT=0`; isolate a runtime side only when the test remains meaningful.
|
||||
See the
|
||||
[`meteortesting:mocha` run options](https://github.com/Meteor-Community-Packages/meteor-mocha#run-tests-inclusively-grep-or-exclusively-invert).
|
||||
|
||||
An execution filter does not stop other loaded modules from evaluating
|
||||
module-scope code, declaring suites, or registering hooks. If that loading is
|
||||
the measured source of interference or excessive startup cost, temporarily
|
||||
narrow the imports in the existing `meteor.testModule` entrypoint. Preserve
|
||||
the original import list, change the smallest possible graph, restore it
|
||||
immediately after the focused run, and then run the affected suite. Do not
|
||||
present entrypoint editing as necessary for an ordinary assertion failure.
|
||||
|
||||
## Focus the failure
|
||||
|
||||
1. Run the project's existing test command and keep the complete failing hook,
|
||||
assertion, stack, client/server counts, and browser output.
|
||||
2. Prefer the installed driver's supported title or runner filter because it
|
||||
does not edit source.
|
||||
3. With Mocha, use `describe.only` or `it.only` only as temporary local focus
|
||||
when the current runner and mode support it.
|
||||
4. Re-run the exact focused case until the evidence confirms or rejects one
|
||||
hypothesis.
|
||||
5. Remove the focus marker and run the affected or full suite.
|
||||
|
||||
Mocha still runs hooks for selected suites. Exclusive tests are incompatible
|
||||
with Mocha parallel mode. Do not invent a rule that every ancestor suite also
|
||||
needs `.only`; use the semantics of the resolved Mocha version. See
|
||||
[Mocha exclusive tests](https://mochajs.org/declaring/exclusive-tests/) and
|
||||
[Mocha `--forbid-only`](https://mochajs.org/running/cli/#--forbid-only).
|
||||
|
||||
Before handoff, scan source for common focus markers:
|
||||
|
||||
```bash
|
||||
rg -n '\b(describe|it|test)\.only\b|\b(fdescribe|fit)\b' \
|
||||
--glob '!node_modules/**' --glob '!.meteor/**'
|
||||
```
|
||||
|
||||
Use `--forbid-only` only when the actual test command forwards that Mocha flag.
|
||||
Otherwise add a deterministic source scan to CI rather than assuming the
|
||||
Meteor driver accepts every upstream option.
|
||||
|
||||
Also restore any temporarily narrowed `meteor.testModule` entrypoint imports.
|
||||
An isolated passing test is not verification while the normal test graph is
|
||||
still modified.
|
||||
|
||||
## Passes alone, fails together
|
||||
|
||||
An isolated pass narrows the failure; it does not fix it. Compare:
|
||||
|
||||
- database and Minimongo cleanup;
|
||||
- `before`, `beforeEach`, `afterEach`, and `after` failures;
|
||||
- replaced globals, fake timers, stubs, subscriptions, DDP connections, and
|
||||
server jobs that were not restored or stopped;
|
||||
- order dependence and shared fixture IDs;
|
||||
- serial versus parallel execution and worker count.
|
||||
|
||||
Find the first test or hook that changes the later case's precondition. Fix the
|
||||
leak or missing isolation, then run both cases in both orders and the full
|
||||
affected suite.
|
||||
|
||||
## Wait for a condition
|
||||
|
||||
Wait for the behavior being asserted, not a guessed delay:
|
||||
|
||||
| Boundary | Readiness condition |
|
||||
|---|---|
|
||||
| Subscription | `sub.ready()` observed reactively with a diagnostic timeout |
|
||||
| Method | Returned Promise settles with the expected result or error |
|
||||
| Mongo or Minimongo | Expected document or count becomes observable |
|
||||
| Browser | Web-first assertion on the stable user-visible result |
|
||||
|
||||
A fixed delay is valid only when elapsed time is the contract, such as debounce
|
||||
or long-press behavior. Document the timing source and first wait for the event
|
||||
that starts the interval.
|
||||
|
||||
## Existing Playwright tests
|
||||
|
||||
Read the report and trace before editing. A trace exposes the action timeline,
|
||||
DOM snapshots, console, network, screenshots, and source. Then narrow by file
|
||||
and line, title, browser project, and one worker when supported by the existing
|
||||
setup.
|
||||
|
||||
```bash
|
||||
npx playwright test tests/items.spec.ts:42 --project=chromium --workers=1
|
||||
npx playwright test tests/items.spec.ts:42 --project=chromium --debug
|
||||
npx playwright show-trace test-results/items/trace.zip
|
||||
```
|
||||
|
||||
See [Playwright debugging](https://playwright.dev/docs/debug),
|
||||
[Trace Viewer](https://playwright.dev/docs/trace-viewer), and the
|
||||
[test CLI](https://playwright.dev/docs/test-cli).
|
||||
|
||||
Classify the result before fixing it: product code, fixture or harness,
|
||||
assertion or locator, browser-engine behavior, or environment and parallelism.
|
||||
Do not hide the distinction with a sleep, broader selector, skip, or retry.
|
||||
|
||||
## Optional `playwright-cli`
|
||||
|
||||
Use `playwright-cli` for an ad hoc browser reproduction only when it is already
|
||||
available or the user authorizes installation and browser downloads. Prefer a
|
||||
local or staging Meteor URL.
|
||||
|
||||
Use only the application path or URL in the task scope. If none is available,
|
||||
ask for it rather than scanning unrelated directories, processes, ports, or
|
||||
local services for a candidate application.
|
||||
|
||||
```bash
|
||||
playwright-cli -s=meteor-debug open http://localhost:3000 --headed
|
||||
playwright-cli -s=meteor-debug snapshot
|
||||
playwright-cli -s=meteor-debug console
|
||||
playwright-cli -s=meteor-debug requests
|
||||
playwright-cli -s=meteor-debug tracing-start
|
||||
playwright-cli -s=meteor-debug tracing-stop
|
||||
playwright-cli -s=meteor-debug close
|
||||
```
|
||||
|
||||
The CLI can collect browser evidence; it is not a server debugger or a default
|
||||
Meteor dependency. Do not initialize agent files, save authentication state,
|
||||
upload private files, mutate live production data, or retain secret-bearing
|
||||
traces without explicit authority.
|
||||
|
||||
Do not use `networkidle` as Meteor application readiness. Playwright
|
||||
[discourages it for tests](https://playwright.dev/docs/api/class-frame#frame-wait-for-load-state),
|
||||
and a Meteor app can maintain DDP traffic. Wait for an observable UI result or
|
||||
an explicit application readiness signal exposed by the test harness.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/testing/testing.md
|
||||
@@ -1,178 +0,0 @@
|
||||
---
|
||||
name: meteor-deployment
|
||||
description: >
|
||||
Use when deploying a Meteor 3 application. Triggers on meteor build,
|
||||
meteor deploy, Galaxy Push to Deploy, Galaxy Mode, Repository Mode,
|
||||
DEPLOY_HOSTNAME, Docker, Kubernetes, settings.json, METEOR_SETTINGS,
|
||||
MONGO_URL, MONGO_OPLOG_URL, ROOT_URL, PORT, HTTP_FORWARDED_COUNT,
|
||||
NODE_OPTIONS, health checks, pre-deploy commands, hot code push,
|
||||
--architecture os.linux.x86_64, --server-only, or a deployed Node.js
|
||||
version mismatch. Use this skill when the user asks about shipping the app,
|
||||
asks about production config, or asks about containerizing. For Cordova
|
||||
Android/iOS artifacts, signing, and native HCP compatibility use
|
||||
meteor-native; this skill owns the backend deployment.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: ops
|
||||
tagline: "Ship Meteor 3 apps to production (meteor build, Galaxy, Docker/Kubernetes, settings.json, env vars, Node version matching)."
|
||||
bundle: ["ops"]
|
||||
docs_synced_at: "2026-08-26"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor deployment
|
||||
|
||||
`meteor build` produces a self-contained Node bundle that runs anywhere
|
||||
the matching Node.js version runs. Galaxy is the first-party host;
|
||||
Docker / Kubernetes / SSH-to-a-Node-host all work too.
|
||||
|
||||
For Android/iOS artifacts and native HCP compatibility, use `meteor-native`.
|
||||
Check actual native configuration as well as compatibility hashes: permission
|
||||
or other native configuration changes can require a new binary with an
|
||||
unchanged hash.
|
||||
|
||||
Match the Node version to the bundled Meteor Node:
|
||||
|
||||
| Meteor | Node major |
|
||||
|---|---|
|
||||
| 3.0 | 20 |
|
||||
| 3.1 through 3.4 | 22 |
|
||||
| 3.5+ | 24 |
|
||||
|
||||
Mismatch causes runtime errors. Run `meteor node -v` to confirm.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Galaxy? Choose Git Push to Deploy or the Meteor CLI. Configure Galaxy's
|
||||
settings source, build hooks, health checks, and domains from
|
||||
`references/galaxy.md`.
|
||||
2. Docker / Kubernetes? `meteor build --directory ./build --server-only`
|
||||
skips platform-specific mobile artifacts. Use
|
||||
`--architecture os.linux.x86_64` for a cross-build.
|
||||
3. SSH to a Node host? Same `meteor build`, scp the bundle, install prod
|
||||
deps under `bundle/programs/server`, run `node main.js`.
|
||||
4. Vercel / Netlify / serverless? Not supported. Meteor needs a
|
||||
long-lived Node process with a WebSocket.
|
||||
|
||||
## Required environment
|
||||
|
||||
| Var | Purpose |
|
||||
|-------------------|--------------------------------------------------------------|
|
||||
| `ROOT_URL` | Absolute external URL (e.g. `https://app.example.com`). |
|
||||
| `MONGO_URL` | `mongodb://...` connection string. |
|
||||
| `MONGO_OPLOG_URL` | Optional Mongo replica oplog URL. |
|
||||
| `PORT` | Listen port. Default 3000. |
|
||||
| `BIND_IP` | Network interface. Default 0.0.0.0. |
|
||||
| `METEOR_SETTINGS` | JSON; populates `Meteor.settings`. |
|
||||
| `MAIL_URL` | SMTP for `Email.send` and account emails. |
|
||||
|
||||
`ROOT_URL` is the external URL the browser sees, not the cluster-internal
|
||||
service URL. OAuth redirects, `Meteor.absoluteUrl`, and CSP all rely on
|
||||
it.
|
||||
|
||||
On Meteor 3.0 through 3.4, configure `MONGO_OPLOG_URL` for oplog-backed
|
||||
reactivity; without it, Meteor polls. Meteor 3.5+ can use core change streams
|
||||
without that variable and falls back to oplog or polling when needed. Atlas
|
||||
hosting alone does not add core change-stream support to an older Meteor app.
|
||||
|
||||
## `settings.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"public": { "appName": "My App", "stripePublishableKey": "pk_live_..." },
|
||||
"stripeSecretKey": "sk_live_...",
|
||||
"oauthSecretKey": "16-byte-base64==",
|
||||
"mailgun": { "apiKey": "..." }
|
||||
}
|
||||
```
|
||||
|
||||
Top-level keys: server only. `public` subtree: shipped to the client.
|
||||
|
||||
Load:
|
||||
|
||||
```bash
|
||||
# dev
|
||||
meteor run --settings settings.json
|
||||
|
||||
# production
|
||||
METEOR_SETTINGS=$(cat settings.json) node bundle/main.js
|
||||
```
|
||||
|
||||
## Galaxy
|
||||
|
||||
Choose one deployment path:
|
||||
|
||||
| Path | Use when | Trigger |
|
||||
|---|---|---|
|
||||
| Push to Deploy | Galaxy should build a connected GitHub or Bitbucket branch. | Every push to the selected branch. |
|
||||
| Meteor CLI | A person or CI pipeline controls each upload. | `meteor deploy <app-name>`. |
|
||||
|
||||
For a Free app, pass a simple app name, not a custom domain:
|
||||
|
||||
```bash
|
||||
meteor login
|
||||
meteor deploy myapp --free --settings settings.json
|
||||
|
||||
DEPLOY_HOSTNAME=eu-west-1.galaxy-deploy.meteor.com \
|
||||
meteor deploy myapp --plan essentials --settings settings.json
|
||||
```
|
||||
|
||||
Galaxy assigns a `myapp.sandbox.galaxycloud.app` hostname on Free or a
|
||||
regional `myapp.<region>.galaxycloud.app` hostname on paid plans. Add custom
|
||||
domains in the dashboard. The active primary domain controls `ROOT_URL`.
|
||||
|
||||
Galaxy injects `PORT`, `ROOT_URL`, and `METEOR_SETTINGS`. Put `MONGO_URL`,
|
||||
`MAIL_URL`, and other server environment values under
|
||||
`galaxy.meteor.com.env` in the Galaxy settings JSON. Do not assume a CLI
|
||||
`--settings` file overrides Repository Mode.
|
||||
|
||||
See `references/galaxy.md` for settings modes, Push to Deploy builds,
|
||||
zero-downtime rollout and rollback, proxies, Mongo TLS, memory, and custom
|
||||
base images.
|
||||
|
||||
## Docker
|
||||
|
||||
See `references/docker.md` for a working multi-stage Dockerfile. Build
|
||||
the bundle in one stage, install server deps and run in a smaller one.
|
||||
`--server-only` skips platform-specific mobile application builds, but it
|
||||
does not omit the browser client or create an API-only bundle. Meteor still
|
||||
builds the `web.cordova` client target used for hot code push.
|
||||
|
||||
## Hot code push
|
||||
|
||||
`autoupdate` provides production hot code push. It detects a new client
|
||||
version over DDP, applies stylesheet-only changes without reloading when
|
||||
possible, and otherwise performs a full browser reload. Remove `autoupdate`
|
||||
from `.meteor/packages` to disable HCP.
|
||||
|
||||
`hot-module-replacement` is different. It replaces accepted JavaScript
|
||||
modules during development and falls back to HCP when a module cannot accept
|
||||
the update. HMR is disabled in production and on unsupported web
|
||||
architectures. There is no `Meteor.disableClientResourceFetch` switch in the
|
||||
current public API.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Commit `settings.json` with production secrets. Use a CI secret store
|
||||
or env vars; load with `METEOR_SETTINGS=$(cat ...)` at startup.
|
||||
- Set `ROOT_URL` to the internal Kubernetes service URL. Use the
|
||||
external HTTPS URL or OAuth redirects and `Meteor.absoluteUrl` break.
|
||||
- Run a Node version that does not match the bundled Meteor Node. Always
|
||||
check `meteor node -v`.
|
||||
- Build on the wrong architecture. M-series Mac developers building for
|
||||
x86_64 Linux must pass `--architecture os.linux.x86_64`.
|
||||
- Commit Galaxy settings with credentials or expect Repository Mode to read a
|
||||
CLI `--settings` file. Keep secrets in Galaxy Mode or a secret store.
|
||||
- Hardcode Galaxy's port, load-balancer IP, or regional DNS target. Read
|
||||
`$PORT` and copy current network values from the app dashboard.
|
||||
- Bundle the source tree into the Docker image alongside the built
|
||||
bundle. Use multi-stage; the runtime image holds only `bundle/`.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/settings-and-env.md`
|
||||
- `references/galaxy.md`
|
||||
- `references/docker.md`
|
||||
- `references/eval-cases.md`
|
||||
@@ -1,86 +0,0 @@
|
||||
# Docker
|
||||
|
||||
## Multi-stage Dockerfile
|
||||
|
||||
```dockerfile
|
||||
# --- build stage ---------------------------------------------------------
|
||||
FROM node:22-bookworm AS builder
|
||||
|
||||
# Build deps for native npm packages (sharp, sqlite, etc.)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 make g++ git ca-certificates curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Meteor for the build
|
||||
RUN curl -sSL https://install.meteor.com/ | sh
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
RUN meteor npm ci
|
||||
RUN meteor build --directory /build --server-only
|
||||
|
||||
# --- runtime stage -------------------------------------------------------
|
||||
FROM node:22-bookworm-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /build/bundle ./
|
||||
|
||||
# Install only production deps inside the bundle
|
||||
RUN (cd programs/server && npm ci --omit=dev)
|
||||
|
||||
ENV PORT=3000
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "main.js"]
|
||||
```
|
||||
|
||||
This sample targets Meteor 3.1 through 3.4. Match both `node:` tags to the
|
||||
bundled Node major: Meteor 3.0 uses Node 20, 3.1 through 3.4 use Node 22,
|
||||
and 3.5+ uses Node 24. Run `meteor node -v` to verify the exact version. On
|
||||
M-series Macs targeting x86_64 Linux, add
|
||||
`--architecture os.linux.x86_64` to `meteor build`.
|
||||
|
||||
`--server-only` skips platform-specific mobile application artifacts. It does
|
||||
not remove browser assets or produce an API-only bundle; Meteor still builds
|
||||
the `web.cordova` target used for hot code push. A separate CDN deployment
|
||||
must extract and deploy the generated web assets explicitly.
|
||||
|
||||
## Build and run
|
||||
|
||||
```bash
|
||||
docker build -t my-app:latest .
|
||||
|
||||
docker run --rm -p 3000:3000 \
|
||||
-e ROOT_URL=https://app.example.com \
|
||||
-e MONGO_URL=mongodb+srv://user:pass@cluster.mongodb.net/myapp \
|
||||
-e METEOR_SETTINGS="$(cat settings.json)" \
|
||||
my-app:latest
|
||||
```
|
||||
|
||||
## Native deps
|
||||
|
||||
If a native dep (`sharp`, `canvas`, `sqlite3`) fails inside the runtime
|
||||
image, copy its prebuilt binaries from the builder rather than
|
||||
recompiling:
|
||||
|
||||
```dockerfile
|
||||
COPY --from=builder /app/node_modules/sharp ./programs/server/node_modules/sharp
|
||||
```
|
||||
|
||||
For workers shipped by transitive logging deps (for example, `thread-stream`
|
||||
from `pino`),
|
||||
see the `meteor-modern-build-stack` skill: when using rspack, route the
|
||||
dep through `Meteor.compileWithMeteor`.
|
||||
|
||||
## Healthcheck
|
||||
|
||||
```dockerfile
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
||||
CMD node -e "fetch('http://localhost:'+(process.env.PORT||3000)).then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
||||
```
|
||||
|
||||
Meteor returns 200 on `/` once the server is ready.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/deployment/deployment.md
|
||||
@@ -1,178 +0,0 @@
|
||||
# Evaluation cases for `meteor-deployment`
|
||||
|
||||
## Case 1: Galaxy deploy
|
||||
|
||||
Prompt: "Deploy my app to Galaxy's Free plan from the Meteor CLI using
|
||||
settings.json. I want the app name to be myapp."
|
||||
|
||||
Pass if the agent uses a simple app name rather than a domain, runs
|
||||
`meteor login` and
|
||||
`meteor deploy myapp --free --settings settings.json`, and explains that
|
||||
Galaxy creates the `myapp.sandbox.galaxycloud.app` hostname. The settings must
|
||||
place `MONGO_URL` under `galaxy.meteor.com.env`. It must not use a legacy
|
||||
`meteorapp.com` hostname or require `DEPLOY_HOSTNAME` for the default Free
|
||||
region.
|
||||
|
||||
## Case 2: Dockerize
|
||||
|
||||
Prompt: "Write a Dockerfile for my Meteor 3.4 app."
|
||||
|
||||
Pass if the agent produces a multi-stage Dockerfile using
|
||||
`node:22-bookworm` (matching Meteor 3.4 bundled Node), runs
|
||||
`meteor build --directory /build --server-only` in the builder, copies
|
||||
only `/build/bundle` into the runtime image, runs
|
||||
`(cd programs/server && npm ci --omit=dev)`, and exposes `PORT=3000`.
|
||||
It must not claim that `--server-only` omits browser assets.
|
||||
|
||||
## Case 3: empty `Meteor.settings.public`
|
||||
|
||||
Prompt: "My production server has empty `Meteor.settings.public`.
|
||||
Locally it works."
|
||||
|
||||
Pass if the agent identifies missing `METEOR_SETTINGS` env var (or
|
||||
mis-mapped keys); fix is
|
||||
`METEOR_SETTINGS="$(cat settings.json)" node main.js`.
|
||||
|
||||
## Case 4: OAuth redirect_uri_mismatch
|
||||
|
||||
Prompt: "After deploying behind a load balancer, Google OAuth returns
|
||||
redirect_uri_mismatch."
|
||||
|
||||
Pass if the agent points at `ROOT_URL`: it must equal the public-facing
|
||||
HTTPS URL the browser uses, not the internal Kubernetes service URL or
|
||||
the LB's pod address. Also have the Google console list that exact URL.
|
||||
|
||||
## Case 5: Node version mismatch
|
||||
|
||||
Prompt: "On my server `node main.js` crashes with
|
||||
`undefined symbol: node_module_register`."
|
||||
|
||||
Pass if the agent identifies the Node version mismatch (Meteor 3.0 uses Node
|
||||
20, 3.1 through 3.4 use Node 22, and 3.5+ uses Node 24), and instructs running
|
||||
`meteor node -v` to find the exact version, then deploying with the matching
|
||||
`node:<N>-bookworm-slim` image.
|
||||
|
||||
## Case 6: HCP versus HMR
|
||||
|
||||
Prompt: "Can production `hot-module-replacement` swap my deployed JavaScript
|
||||
without a page reload, and can I disable it with
|
||||
`Meteor.disableClientResourceFetch`?"
|
||||
|
||||
Pass if the agent separates development HMR from production HCP, attributes
|
||||
HCP to `autoupdate`, explains that JavaScript changes normally cause a hard
|
||||
reload while stylesheet-only changes may update softly, and rejects the
|
||||
nonexistent switch. Removing `autoupdate` is the supported HCP opt-out.
|
||||
|
||||
## Case 7: Atlas reactivity before Meteor 3.5
|
||||
|
||||
Prompt: "Our Meteor 3.4.1 app runs on Atlas without `MONGO_OPLOG_URL`. Is core
|
||||
change-stream reactivity active automatically?"
|
||||
|
||||
Pass if the agent says core change streams begin in Meteor 3.5, so this app
|
||||
polls unless it configures an oplog URL. It may recommend upgrading to 3.5+ or
|
||||
configuring a compatible oplog, but must not infer support from Atlas hosting.
|
||||
|
||||
## Case 8: Galaxy Push to Deploy with secrets
|
||||
|
||||
Prompt: "Set up Galaxy Push to Deploy for the Meteor app in `apps/web` on our
|
||||
GitHub `main` branch. We commit `package-lock.json`, need an idempotent database
|
||||
migration before rollout, and have production API keys."
|
||||
|
||||
Pass if the agent connects the repository and branch, sets Root Directory to
|
||||
`apps/web`, uses `meteor npm ci`, and places the migration in the paid-plan
|
||||
Pre-Deploy Command while stating that failure stops the rollout. It must use
|
||||
Galaxy Mode or a secret manager for credentials, not commit them in Repository
|
||||
Mode. It must explain that each push to `main` triggers a deployment.
|
||||
|
||||
## Case 9: Repository Mode ignores CLI settings
|
||||
|
||||
Prompt: "Our Galaxy app uses Repository Mode. I ran
|
||||
`meteor deploy myapp --settings emergency.json`, but the running settings did
|
||||
not change."
|
||||
|
||||
Pass if the agent explains that Repository Mode reads the configured file from
|
||||
the Git snapshot and ignores the CLI `--settings` file. It must recommend
|
||||
updating the repository file and triggering Push to Deploy, or deliberately
|
||||
switching to Galaxy Mode before using the dashboard or CLI as the settings
|
||||
source. It must not suggest repeatedly running the same CLI command.
|
||||
|
||||
## Case 10: Galaxy rollout stays unhealthy
|
||||
|
||||
Prompt: "Galaxy built our pushed commit, but its new containers never become
|
||||
healthy and the old version still serves traffic. Where should I look?"
|
||||
|
||||
Pass if the agent treats the live old version as expected rollout protection,
|
||||
checks deploy logs for startup and environment failures, confirms the process
|
||||
listens on `$PORT`, and verifies the configured health path returns non-5xx
|
||||
within five seconds. It must distinguish build logs and pre-deploy logs from
|
||||
container deploy logs and mention automatic rollback when the new slot cannot
|
||||
become healthy.
|
||||
|
||||
## Case 11: Galaxy primary domain and forwarded client IP
|
||||
|
||||
Prompt: "We put Cloudflare in front of our Galaxy app and made
|
||||
`app.example.com` active. OAuth links still use the Galaxy hostname, and the
|
||||
server sees a private proxy IP."
|
||||
|
||||
Pass if the agent makes the active custom domain primary so Galaxy sets
|
||||
`ROOT_URL`, confirms the OAuth provider uses the same HTTPS URL, and sets
|
||||
`HTTP_FORWARDED_COUNT` to `2` for Cloudflare plus Galaxy. It must warn against
|
||||
trusting arbitrary client-supplied `X-Forwarded-For` values.
|
||||
|
||||
## Case 12: Galaxy Mongo TLS choice
|
||||
|
||||
Prompt: "Our prototype used Galaxy's free Mongo with
|
||||
`tlsAllowInvalidCertificates: true`. We are moving production to a dedicated
|
||||
Galaxy Database. Should we keep that option?"
|
||||
|
||||
Pass if the agent limits the certificate bypass to the free shared testing
|
||||
database. For the dedicated database it must use the downloaded CA in
|
||||
`private/`, set `tls: true` and `tlsCAFileAsset`, use the dashboard connection
|
||||
string with its required parameters, and redeploy so the certificate is
|
||||
bundled. It must not recommend disabling certificate validation in production.
|
||||
|
||||
## Case 13: Galaxy Metal memory setting
|
||||
|
||||
Prompt: "Our Galaxy Metal container reports heap out of memory. Increasing
|
||||
`GALAXY_NODE_OPTIONS` did nothing."
|
||||
|
||||
Pass if the agent says `GALAXY_NODE_OPTIONS` is ignored on Galaxy Metal,
|
||||
inspects container memory and leak behavior first, and uses `NODE_OPTIONS` under
|
||||
`galaxy.meteor.com.env` only when measurements show available headroom. It must
|
||||
not claim that increasing the heap fixes a leak or allocate the full container
|
||||
memory to V8.
|
||||
|
||||
## Case 14: Galaxy custom base image
|
||||
|
||||
Prompt: "Our Meteor app needs an OS package unavailable in Galaxy's standard
|
||||
image. Prepare a custom base image deployment."
|
||||
|
||||
Pass if the agent requires a publicly readable Docker Hub image with no
|
||||
secrets, `/bin/bash`, an executable `/app/setup.sh` that accepts the app tarball
|
||||
URL, an immutable image tag, and a `CMD` or `ENTRYPOINT` that listens on
|
||||
`$PORT`. It must configure `galaxy.meteor.com.baseImage` and reject relying on a
|
||||
changed mutable tag to trigger a deployment.
|
||||
|
||||
## Case 15: native artifact handoff
|
||||
|
||||
Prompt: "Our Meteor backend is already deployed. Prepare the Android AAB and iOS
|
||||
archive for the existing Cordova app, including the signing handoff."
|
||||
|
||||
Pass if the agent routes Android/iOS artifact and signing preparation to meteor-
|
||||
native while preserving the existing backend. Fail if it substitutes a server
|
||||
bundle for native artifacts or redeploys the healthy backend unnecessarily.
|
||||
|
||||
## Case 16: backend-only native HCP
|
||||
|
||||
Prompt: "Only deploy our Meteor backend and compatible JavaScript changes.
|
||||
Existing Cordova binaries stay installed. Does --server-only disable their hot
|
||||
code push or require new signed apps?"
|
||||
|
||||
Pass if the agent keeps backend deployment here, explains that --server-only skips
|
||||
native artifacts while retaining the configured web.cordova HCP target, and
|
||||
verifies compatibility. Fail if it claims HCP is disabled or requires new native
|
||||
binaries for compatible web-only changes.
|
||||
It inspects actual native platform/plugin/configuration changes rather than
|
||||
inferring a binary change from a Meteor release label or an edited filename;
|
||||
native configuration can require a binary even when its compatibility hash is
|
||||
unchanged. Fail if it claims every such edit necessarily changes that hash.
|
||||
@@ -1,222 +0,0 @@
|
||||
# Galaxy deployment
|
||||
|
||||
Galaxy supports repository-driven Push to Deploy and explicit uploads through
|
||||
the Meteor CLI. Keep one settings source of truth and verify the new version
|
||||
before changing traffic.
|
||||
|
||||
## Choose the deployment path
|
||||
|
||||
| Path | Configure | Deployment behavior |
|
||||
|---|---|---|
|
||||
| Push to Deploy | Connect GitHub or Bitbucket, select the repository and branch, then set the Meteor root directory and build options. | Every push to the selected branch creates and deploys a version. Disconnect Push to Deploy to stop automatic builds without removing saved build settings. |
|
||||
| Meteor CLI | Run `meteor login`, select an app name, and pass plan, region, settings, or Mongo flags. | The local Meteor CLI builds and uploads the application for each command. |
|
||||
|
||||
Free CLI deployments use a simple app name:
|
||||
|
||||
```bash
|
||||
meteor deploy myapp --free --settings settings.json
|
||||
```
|
||||
|
||||
A domain-form target requests a custom domain and requires a paid plan. Let
|
||||
Galaxy create `myapp.sandbox.galaxycloud.app` for Free. Paid apps receive a
|
||||
regional `myapp.<region>.galaxycloud.app` hostname.
|
||||
|
||||
Choose a paid region with `DEPLOY_HOSTNAME`:
|
||||
|
||||
```bash
|
||||
DEPLOY_HOSTNAME=eu-west-1.galaxy-deploy.meteor.com \
|
||||
meteor deploy myapp --plan essentials --container-size standard \
|
||||
--settings settings.json
|
||||
```
|
||||
|
||||
Supported region hosts are `us-east-1`, `eu-west-1`, and
|
||||
`ap-southeast-2` under `galaxy-deploy.meteor.com`. Free apps deploy in US East.
|
||||
For CLI automation, create a `METEOR_SESSION_FILE` token file, store its
|
||||
contents in the CI secret store, reconstruct it for the job, and never commit
|
||||
it.
|
||||
|
||||
```bash
|
||||
METEOR_SESSION_FILE=token.json meteor login
|
||||
METEOR_SESSION_FILE=token.json meteor deploy myapp --settings settings.json
|
||||
```
|
||||
|
||||
## Select the settings source
|
||||
|
||||
Galaxy consumes one complete settings object:
|
||||
|
||||
```json
|
||||
{
|
||||
"galaxy.meteor.com": {
|
||||
"env": {
|
||||
"MONGO_URL": "mongodb://...",
|
||||
"MAIL_URL": "smtp://..."
|
||||
}
|
||||
},
|
||||
"private": {
|
||||
"stripeKey": "sk_live_xxx"
|
||||
},
|
||||
"public": {
|
||||
"appName": "My App"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Mode | Source of truth | Update rule |
|
||||
|---|---|---|
|
||||
| Galaxy Mode | Encrypted JSON stored in Galaxy. Recommended when settings contain secrets. | Dashboard and Meteor CLI write the same store. `meteor deploy --settings` replaces the stored JSON, so the last write wins. Save dashboard edits, then Deploy to apply them. |
|
||||
| Repository Mode | A settings file from the Git snapshot used by Push to Deploy. Use only for non-sensitive configuration. | Update the configured relative path in Git and push. Galaxy ignores a CLI `--settings` file while this mode is active. |
|
||||
|
||||
The Galaxy editor accepts at most 1 MB. Values under
|
||||
`galaxy.meteor.com.env` become `process.env` variables. `private` is
|
||||
server-only through `Meteor.settings.private`; `public` is sent to browsers.
|
||||
Commit a placeholder `settings.example.json`, not credentials. If a secret was
|
||||
committed, rotate it and remove it from Git history.
|
||||
|
||||
## Configure the Push to Deploy build
|
||||
|
||||
| Field | Decision |
|
||||
|---|---|
|
||||
| Root Directory | Set the path relative to the repository root, such as `apps/web`, when the Meteor app is in a monorepo. |
|
||||
| Install Command | Default is `meteor npm install`. Use `meteor npm ci` when a committed `package-lock.json` is authoritative. |
|
||||
| Pre-Deploy Command | Paid plans only. Runs after the build with private-network and environment access. Use it for idempotent migrations. A nonzero exit stops the deployment before new containers go live. |
|
||||
| Health Check Path | Defaults to `/` and must start with `/`. Point it at a lightweight endpoint that returns non-5xx within five seconds. |
|
||||
| Stop Grace Period | Galaxy sends `SIGTERM`, then `SIGKILL` after the configured period. Default is 5 seconds and paid plans can raise it to 600. Bound shutdown work by `METEOR_SIGTERM_GRACE_PERIOD_SECONDS`. |
|
||||
|
||||
Galaxy builds new code in an inactive slot and switches traffic only after the
|
||||
new containers pass health checks. New containers receive up to ten minutes to
|
||||
become healthy. If they do not, Galaxy keeps or restores the previous version.
|
||||
Check build logs for cloning, dependency, and compilation failures; pre-deploy
|
||||
logs for migration failures; deploy logs for startup, environment, port, and
|
||||
health failures.
|
||||
|
||||
Galaxy assigns `PORT` dynamically. Do not hardcode 3000 in a custom entrypoint.
|
||||
The process must listen on `$PORT`, and Galaxy exposes no second inbound port.
|
||||
|
||||
## Operate and roll back
|
||||
|
||||
A code push creates a version and a deployment. A settings, container, or
|
||||
replica change can create another deployment of the same code version. Diagnose
|
||||
them separately:
|
||||
|
||||
| Symptom | First evidence |
|
||||
|---|---|
|
||||
| Repository build failed | Build logs for clone access, install, dependency, or compilation errors. Reproduce with `meteor build` locally. |
|
||||
| Migration stopped rollout | Pre-deploy logs and the command's exit status. The previous deployment stays live. |
|
||||
| New containers cannot start | Deploy logs for missing variables, database access, `$PORT`, or health-check failures. |
|
||||
| Push produced no deployment | Confirm the selected branch and Git provider access. For Bitbucket, verify the workspace webhook was registered. |
|
||||
| Settings did not change | Confirm Galaxy Mode versus Repository Mode, then Save and Deploy or push the configured settings file. |
|
||||
|
||||
Use Deploy Now to apply saved configuration without a code push. Use Versions >
|
||||
Redeploy to roll back to a previous code snapshot. Galaxy creates a new
|
||||
deployment for the rollback; it does not move or rewrite the old version.
|
||||
|
||||
## Domains and proxies
|
||||
|
||||
Galaxy provides TLS for its own hostnames and managed custom domains. Copy the
|
||||
current CNAME or A-record target from Settings > Networking rather than
|
||||
hardcoding published infrastructure values. Mark an active custom domain as
|
||||
primary to make it the app's main URL and the Meteor `ROOT_URL`.
|
||||
|
||||
Galaxy's load balancer is one trusted proxy hop. Configure:
|
||||
|
||||
```json
|
||||
{
|
||||
"galaxy.meteor.com": {
|
||||
"env": {
|
||||
"HTTP_FORWARDED_COUNT": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add one for each controlled proxy in front of Galaxy. With Cloudflare plus
|
||||
Galaxy, use `2`. Do not trust a client-supplied leftmost `X-Forwarded-For`
|
||||
value beyond the configured proxy chain.
|
||||
|
||||
Professional Meteor apps can read Galaxy's current fixed outgoing proxy IPs
|
||||
from Settings for external allowlists. Pair IP allowlisting with database or
|
||||
service authentication because the addresses are shared.
|
||||
|
||||
## MongoDB on Galaxy
|
||||
|
||||
The deployment-time Free MongoDB toggle is for testing and development. It
|
||||
adds `MONGO_URL`, has no backups, and is tied to the app lifecycle. Use a paid
|
||||
database or another production MongoDB service for production data.
|
||||
|
||||
Galaxy's free shared MongoDB requires its documented certificate bypass:
|
||||
|
||||
```json
|
||||
{
|
||||
"packages": {
|
||||
"mongo": {
|
||||
"options": {
|
||||
"tlsAllowInvalidCertificates": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not carry that bypass to a dedicated database. For Galaxy Database, place
|
||||
the downloaded CA certificate in the Meteor `private/` directory and use
|
||||
`tls: true` plus `tlsCAFileAsset` in `packages.mongo.options`. Changing that
|
||||
certificate requires a rebuild because Meteor bundles `private/` assets.
|
||||
|
||||
On Meteor 3.0 through 3.4, place a replica-set `MONGO_OPLOG_URL` under
|
||||
`galaxy.meteor.com.env` for oplog-backed reactivity. It must point to `/local`
|
||||
and authenticate a least-privilege user with read access there. Meteor 3.5+
|
||||
can use core change streams; do not add a second oplog credential unless the
|
||||
selected reactivity strategy needs it.
|
||||
|
||||
## Memory, replicas, and custom base images
|
||||
|
||||
Observe per-container CPU and memory before resizing or tuning. Add replicas
|
||||
for concurrency or redundancy; choose a larger container when one process
|
||||
needs more CPU or memory. Basic autoscaling on paid plans targets CPU. Advanced
|
||||
Professional rules can use CPU, memory, requests, connections, and schedules.
|
||||
|
||||
Modern Node detects container limits. When measurements show heap pressure and
|
||||
the container has headroom, set standard Node flags with:
|
||||
|
||||
```json
|
||||
{
|
||||
"galaxy.meteor.com": {
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--max-old-space-size=1600"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`GALAXY_NODE_OPTIONS` belongs to the legacy runtime and is ignored on Galaxy
|
||||
Metal. A larger heap does not fix a leak and still needs space for native
|
||||
modules and the rest of the process.
|
||||
|
||||
Use a custom base image only when the standard Galaxy image lacks required OS
|
||||
packages or runtime support. The image must:
|
||||
|
||||
- Be publicly readable from Docker Hub and contain no secrets.
|
||||
- Include `/bin/bash` and an executable `/app/setup.sh` with a shell shebang.
|
||||
- Accept the app tarball URL as the setup script's first argument.
|
||||
- Use an immutable tag or Git SHA. Pushing a changed `latest` image does not
|
||||
deploy it.
|
||||
- Start through `CMD` or `ENTRYPOINT` and listen on `$PORT`.
|
||||
|
||||
Set `galaxy.meteor.com.baseImage.repository` and `.tag` in the Galaxy settings
|
||||
object. In Push to Deploy with Galaxy Mode, keep that block in the stored JSON.
|
||||
|
||||
## Sources
|
||||
|
||||
- [Deploy Meteor Apps](https://docs.galaxycloud.app/docs/apps/meteor/push-to-deploy)
|
||||
- [Meteor CLI](https://docs.galaxycloud.app/docs/apps/meteor/cli)
|
||||
- [Meteor Reference](https://docs.galaxycloud.app/docs/apps/meteor/meteor-reference)
|
||||
- [Variables](https://docs.galaxycloud.app/docs/dashboard/apps/variables)
|
||||
- [Settings](https://docs.galaxycloud.app/docs/dashboard/apps/settings)
|
||||
- [Container Environment](https://docs.galaxycloud.app/docs/apps/container-environment)
|
||||
- [Versions and Deployments](https://docs.galaxycloud.app/docs/apps/versions-deployments)
|
||||
- [Custom Domains](https://docs.galaxycloud.app/docs/apps/custom-domains)
|
||||
- [Memory Management](https://docs.galaxycloud.app/docs/apps/memory-management)
|
||||
- [Custom Base Images](https://docs.galaxycloud.app/docs/apps/meteor/custom-base-images)
|
||||
- [Secrets Management](https://docs.galaxycloud.app/docs/apps/meteor/secrets-management)
|
||||
- [MongoDB Oplog Setup](https://docs.galaxycloud.app/docs/databases/mongodb-oplog-setup)
|
||||
- [MongoDB SSL for Meteor](https://docs.galaxycloud.app/docs/databases/mongodb-ssl-meteor)
|
||||
@@ -1,83 +0,0 @@
|
||||
# `settings.json` and environment variables
|
||||
|
||||
## Loading
|
||||
|
||||
```bash
|
||||
# dev
|
||||
meteor run --settings settings.json
|
||||
meteor test --settings settings.json --driver-package meteortesting:mocha
|
||||
|
||||
# production
|
||||
METEOR_SETTINGS="$(cat settings.json)" node bundle/main.js
|
||||
```
|
||||
|
||||
`METEOR_SETTINGS` is the canonical production path. The bundled
|
||||
`bundle/main.js` reads it and writes `Meteor.settings`.
|
||||
|
||||
Galaxy users configure the full settings object through Galaxy Mode or
|
||||
Repository Mode. Galaxy then injects `METEOR_SETTINGS`; environment variables
|
||||
such as `MONGO_URL` belong under `galaxy.meteor.com.env`. See
|
||||
[`galaxy.md`](galaxy.md#select-the-settings-source) before combining dashboard,
|
||||
Git, and CLI settings.
|
||||
|
||||
## Reading
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
|
||||
Meteor.settings.stripeSecretKey; // server-only key
|
||||
Meteor.settings.public.appName; // shipped to the client
|
||||
```
|
||||
|
||||
Anything under `public` reaches the client. Everything else stays on the
|
||||
server.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Var | Default | Notes |
|
||||
|--------------------|--------------|------------------------------------------------|
|
||||
| `ROOT_URL` | required | External URL. Required for OAuth, absoluteUrl. |
|
||||
| `MONGO_URL` | required | `mongodb://...` or `mongodb+srv://...`. |
|
||||
| `MONGO_OPLOG_URL` | optional | Mongo replica oplog URL. |
|
||||
| `PORT` | 3000 | |
|
||||
| `BIND_IP` | 0.0.0.0 | Listen interface. |
|
||||
| `METEOR_SETTINGS` | optional | JSON blob; merged into `Meteor.settings`. |
|
||||
| `MAIL_URL` | optional | SMTP URL: `smtp://user:pass@host:587`. |
|
||||
| `NODE_ENV` | `development` in dev | Set to `production` for prod builds. |
|
||||
|
||||
Meteor-specific knobs documented in
|
||||
`v3-docs/docs/cli/environment-variables.md`:
|
||||
`METEOR_DISABLE_OPTIMISTIC_CACHING`, `METEOR_PRINT_CONSTRUCTED_HTML`,
|
||||
`METEOR_PROFILE`, `TOOL_NODE_FLAGS` (3.4.1+), `METEOR_LOCAL_DIR`,
|
||||
`METEOR_IGNORE`.
|
||||
|
||||
## Mongo connection strings
|
||||
|
||||
- Local: `mongodb://localhost:27017/myapp`
|
||||
- Atlas: `mongodb+srv://user:pass@cluster.mongodb.net/myapp?retryWrites=true&w=majority`
|
||||
- Replica: `MONGO_OPLOG_URL=mongodb://user:pass@host:27017/local?replicaSet=rs0&authSource=admin`
|
||||
|
||||
On Meteor 3.0 through 3.4, reactivity uses the oplog only when
|
||||
`MONGO_OPLOG_URL` is configured and otherwise polls. Meteor 3.5+ can use core
|
||||
change streams without this variable, with oplog and polling as fallbacks.
|
||||
Choose from the actual Mongo topology and Meteor version; Atlas does not make
|
||||
core change streams available before Meteor 3.5.
|
||||
|
||||
## Secrets
|
||||
|
||||
Do not commit production secrets to `settings.json`. Build the file at
|
||||
deploy time from a secret store:
|
||||
|
||||
```bash
|
||||
jq -n --arg key "$STRIPE_SECRET_KEY" \
|
||||
'{stripeSecretKey: $key, public: {stripePublishableKey: env.STRIPE_PK}}' \
|
||||
> settings.json
|
||||
|
||||
METEOR_SETTINGS="$(cat settings.json)" node bundle/main.js
|
||||
```
|
||||
|
||||
Or pass values as separate env vars and read them with
|
||||
`process.env.<NAME>` in startup code.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/environment-variables.md
|
||||
@@ -1,157 +0,0 @@
|
||||
---
|
||||
name: meteor-methods
|
||||
description: >
|
||||
Use when authoring or debugging Meteor methods (Meteor.methods, Meteor.call,
|
||||
Meteor.callAsync). Triggers on argument validation with check(), optimistic
|
||||
UI stubs, latency compensation, Meteor.Error handling, and DDPRateLimiter.
|
||||
Use this skill when the user asks about server-side mutation, asks about
|
||||
rate limiting RPC, or asks about wrapping a method with auth checks.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: data
|
||||
tagline: "Author and debug Meteor methods (argument `check()`, optimistic stubs, latency compensation, `Meteor.Error`, `DDPRateLimiter`)."
|
||||
bundle: ["essentials", "fullstack"]
|
||||
docs_synced_at: "2026-08-25"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor methods
|
||||
|
||||
Methods are Meteor's primitive for server-side mutation called from the client.
|
||||
In Meteor 3 they are async on the server. Latency compensation still works via
|
||||
client-side stubs.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Is this code mutating server data? Use a method.
|
||||
2. Does the client need to read the result before the server replies? Write
|
||||
a client stub with the same name; it mutates the local Minimongo collection
|
||||
and the change is reverted if the server disagrees.
|
||||
3. Does the method accept untrusted input? Validate every argument with
|
||||
`check()`. Otherwise the agent should refuse to write the method.
|
||||
4. Is the method rate-sensitive? Add a `DDPRateLimiter.addRule`.
|
||||
|
||||
## Scaffold
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { check, Match } from "meteor/check";
|
||||
|
||||
Meteor.methods({
|
||||
async addItem(payload) {
|
||||
check(payload, {
|
||||
title: String,
|
||||
qty: Match.Integer,
|
||||
});
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
const _id = await Items.insertAsync({
|
||||
...payload,
|
||||
ownerId: this.userId,
|
||||
createdAt: new Date(),
|
||||
});
|
||||
return _id;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Calling from the client
|
||||
|
||||
```javascript
|
||||
try {
|
||||
const id = await Meteor.callAsync("addItem", { title: "Hi", qty: 1 });
|
||||
setLocalId(id);
|
||||
} catch (err) {
|
||||
if (err && typeof err === "object" && "error" in err) {
|
||||
console.error(err.error, err.reason, err.details);
|
||||
} else {
|
||||
console.error("local or transport failure", err);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Optimistic UI
|
||||
|
||||
Define the same method on the client. The client stub runs immediately against
|
||||
the local Minimongo; the server's authoritative result reverts any divergence.
|
||||
|
||||
```javascript
|
||||
// client/methods.js
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Random } from "meteor/random";
|
||||
Meteor.methods({
|
||||
addItem(payload) {
|
||||
Items.insert({
|
||||
...payload,
|
||||
_id: Random.id(),
|
||||
ownerId: Meteor.userId(),
|
||||
createdAt: new Date(),
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Synchronous stubs are simplest when they only need synchronous Minimongo.
|
||||
Async stubs are also supported by `callAsync` and are useful when the same
|
||||
method definition runs on client and server with `*Async` collection calls.
|
||||
An async stub may await microtask-based local work, but it must not wait on
|
||||
`fetch`, timers, IndexedDB, workers, or other browser macrotask APIs. Run
|
||||
external I/O outside the stub.
|
||||
|
||||
## Rate limiting
|
||||
|
||||
```javascript
|
||||
import { DDPRateLimiter } from "meteor/ddp-rate-limiter";
|
||||
|
||||
DDPRateLimiter.addRule(
|
||||
{
|
||||
type: "method",
|
||||
name: "addItem",
|
||||
userId: (userId) => Boolean(userId),
|
||||
},
|
||||
5, // operations
|
||||
10000, // per 10s
|
||||
);
|
||||
```
|
||||
|
||||
Meteor 3.5+ permits async matcher functions for database-backed decisions. On
|
||||
Meteor 3.0 through 3.4, matchers must stay synchronous; use a fixed rule,
|
||||
precomputed synchronous state, or upgrade instead of awaiting Mongo in a
|
||||
matcher.
|
||||
|
||||
Meteor awaits async matchers sequentially on the incoming connection's message
|
||||
queue. Project only required fields and keep the lookup fast. A rejected
|
||||
matcher Promise errors the invocation; test that path explicitly.
|
||||
|
||||
See `references/rate-limiting.md` for the rule-object schema and
|
||||
per-connection vs per-user keys.
|
||||
|
||||
## Error handling
|
||||
|
||||
Throw `Meteor.Error(code, reason, details?)` for an intentional client-visible
|
||||
failure. A plain `Error` is logged on the server and sanitized for the client
|
||||
as `Meteor.Error(500, "Internal server error")`; its original message and
|
||||
stack are not exposed. `Meteor.Error` carries its code, reason, and details.
|
||||
Do not assume every `callAsync` rejection has that shape: callback misuse,
|
||||
transport failures, and local stub exceptions can produce native or arbitrary
|
||||
errors. Narrow the caught value before reading Meteor-specific fields.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Methods without `check()` on every argument. Reject the method in code
|
||||
review.
|
||||
- Reusing a method for both authenticated and unauthenticated calls. Split
|
||||
into two methods.
|
||||
- Awaiting browser macrotask APIs such as `fetch` or timers inside a client
|
||||
stub. Async stubs are valid, but those APIs let unrelated code run before
|
||||
the optimistic simulation finishes.
|
||||
- Calling `Meteor.user()` inside an async method body. Use `this.userId`.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/check-and-validate.md`
|
||||
- `references/rate-limiting.md`
|
||||
- `references/eval-cases.md`
|
||||
@@ -1,47 +0,0 @@
|
||||
# Validating method arguments
|
||||
|
||||
Every method argument must be validated. Two libraries: the built-in
|
||||
`check` package and any third-party validator (Zod, Joi). For new code,
|
||||
prefer `check`.
|
||||
|
||||
## Primitive shapes
|
||||
|
||||
```javascript
|
||||
check(value, String); // string
|
||||
check(value, Number); // number, including NaN. Use Match.Integer
|
||||
// for integers.
|
||||
check(value, Boolean);
|
||||
check(value, Date);
|
||||
check(value, Object); // any object
|
||||
check(value, Array); // any array
|
||||
check(value, null);
|
||||
check(value, undefined);
|
||||
```
|
||||
|
||||
## Composite
|
||||
|
||||
```javascript
|
||||
check(value, {
|
||||
title: String,
|
||||
qty: Match.Integer,
|
||||
tags: [String],
|
||||
notes: Match.Optional(String),
|
||||
meta: Match.ObjectIncluding({ source: String }),
|
||||
});
|
||||
```
|
||||
|
||||
## Union and refinement
|
||||
|
||||
```javascript
|
||||
check(value, Match.OneOf(String, Number));
|
||||
check(value, Match.Where((v) => typeof v === "string" && v.length <= 80));
|
||||
```
|
||||
|
||||
## When to use Zod
|
||||
|
||||
If you already use Zod for HTTP boundaries, you can call `schema.parse(value)`
|
||||
inside the method. The Meteor-specific `check` advantage is that mismatches
|
||||
throw `Match.Error` which Meteor maps to a `400` DDP error automatically.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/check.md
|
||||
@@ -1,73 +0,0 @@
|
||||
# Evaluation cases for `meteor-methods`
|
||||
|
||||
## Case 1: missing check()
|
||||
|
||||
Prompt: "Add a method that updates a user's profile."
|
||||
|
||||
Pass if the agent (a) uses `check()` for every argument, (b) gates on
|
||||
`this.userId`, (c) marks the method `async`, (d) uses `*Async` Mongo.
|
||||
|
||||
## Case 2: optimistic UI
|
||||
|
||||
Prompt: "How do I make my addItem method update the UI instantly without
|
||||
waiting for the server?"
|
||||
|
||||
Pass if the agent explains client stubs and produces a local Minimongo stub
|
||||
with the same name. Accept a synchronous stub or an async stub that only
|
||||
awaits `*Async` Minimongo work. Fail if it performs external I/O in the stub.
|
||||
|
||||
## Case 3: rate limiting
|
||||
|
||||
Prompt: "Limit my login method to five attempts per minute per IP."
|
||||
|
||||
Pass if the agent uses `DDPRateLimiter.addRule` with `clientAddress` matcher
|
||||
and `5, 60000`.
|
||||
|
||||
## Case 4: error shape
|
||||
|
||||
Prompt: "My method throws but the client only sees 'Internal server error'.
|
||||
Why?"
|
||||
|
||||
Pass if the agent identifies that the method threw a plain `Error` instead of
|
||||
`Meteor.Error`, and rewrites to `throw new Meteor.Error(code, reason)`.
|
||||
|
||||
## Case 5: shared async method stub
|
||||
|
||||
Prompt: "My method module is imported on client and server. Its handler is
|
||||
`async` and calls `await Items.insertAsync(doc)`. Must I create a separate
|
||||
synchronous client stub?"
|
||||
|
||||
Pass if the agent says `callAsync` supports the shared async stub and local
|
||||
async Minimongo operation. It must prohibit macrotask APIs such as `fetch`,
|
||||
timers, IndexedDB, and workers inside the stub.
|
||||
|
||||
## Case 6: async rate-limit matcher
|
||||
|
||||
Prompt: "On Meteor 3.5, rate-limit `reports.generate` only for users whose
|
||||
subscription tier is not premium. The tier is stored in `Meteor.users`.
|
||||
Explain the effect on connection message processing and what happens when the
|
||||
matcher Promise rejects."
|
||||
|
||||
Pass if the agent uses an async `userId` matcher with
|
||||
`findOneAsync`, notes that the matcher is awaited on the connection's message
|
||||
queue, keeps the query projected and fast, and tests a rejected matcher
|
||||
Promise. Fail if it calls synchronous Mongo from the matcher.
|
||||
|
||||
## Case 7: async matcher before Meteor 3.5
|
||||
|
||||
Prompt: "Our app is fixed on Meteor 3.4.1. Can a `DDPRateLimiter` matcher
|
||||
await `Meteor.users.findOneAsync` to choose a subscription-tier rule?"
|
||||
|
||||
Pass if the agent says async matchers begin in Meteor 3.5, keeps the 3.4.1
|
||||
matcher synchronous, and offers a fixed rule, precomputed synchronous state,
|
||||
or a Meteor upgrade. Fail if it copies the 3.5 async matcher into 3.4.1.
|
||||
|
||||
## Case 8: local `callAsync` rejection shape
|
||||
|
||||
Prompt: "My client method stub throws a native `TypeError`, and the catch block
|
||||
crashes again while reading `err.error`. Are all `callAsync` rejections
|
||||
`Meteor.Error`?"
|
||||
|
||||
Pass if the agent says intentional server-visible failures should use
|
||||
`Meteor.Error` but local, misuse, and transport failures may not, then narrows
|
||||
the caught value before reading `error`, `reason`, or `details`.
|
||||
@@ -1,111 +0,0 @@
|
||||
# `DDPRateLimiter.addRule`
|
||||
|
||||
`DDPRateLimiter.addRule(matcher, n, ms)` rejects requests that exceed `n`
|
||||
matches in `ms` milliseconds.
|
||||
|
||||
## Matcher shape
|
||||
|
||||
```text
|
||||
{
|
||||
type: "method" | "subscription",
|
||||
name: string | RegExp | (name) => boolean,
|
||||
userId: (userId) => boolean,
|
||||
clientAddress: (addr) => boolean,
|
||||
connectionId: (id) => boolean,
|
||||
}
|
||||
```
|
||||
|
||||
(Schema notation, not executable JavaScript.)
|
||||
|
||||
Any subset of keys is allowed. Missing keys match everything.
|
||||
|
||||
## Common patterns
|
||||
|
||||
```javascript
|
||||
// Per-user method limit
|
||||
DDPRateLimiter.addRule(
|
||||
{ type: "method", name: "addItem", userId: (uid) => Boolean(uid) },
|
||||
5,
|
||||
10000,
|
||||
);
|
||||
|
||||
// Per-IP login attempts
|
||||
DDPRateLimiter.addRule(
|
||||
{
|
||||
type: "method",
|
||||
name: "login",
|
||||
clientAddress: () => true,
|
||||
},
|
||||
5,
|
||||
60000,
|
||||
);
|
||||
|
||||
// All publications, per user
|
||||
DDPRateLimiter.addRule(
|
||||
{ type: "subscription", userId: (uid) => Boolean(uid) },
|
||||
100,
|
||||
60000,
|
||||
);
|
||||
```
|
||||
|
||||
## Removing a rule
|
||||
|
||||
`addRule` returns an id. Pass it to `removeRule` to drop the limit (useful
|
||||
for tests).
|
||||
|
||||
```javascript
|
||||
const ruleId = DDPRateLimiter.addRule(
|
||||
{ type: "method", name: "addItem" },
|
||||
5,
|
||||
10000,
|
||||
);
|
||||
|
||||
// later, e.g. in a test teardown
|
||||
DDPRateLimiter.removeRule(ruleId);
|
||||
```
|
||||
|
||||
The default login rule shipped with `accounts-base` is removed by
|
||||
`Accounts.removeDefaultRateLimit()`.
|
||||
|
||||
## Async matchers (Meteor 3.5+)
|
||||
|
||||
Matchers may return `Promise<boolean>`. Use this only when the rule must read
|
||||
the database, because each matcher is awaited on the incoming connection's
|
||||
message queue.
|
||||
|
||||
```javascript
|
||||
DDPRateLimiter.addRule(
|
||||
{
|
||||
type: "method",
|
||||
name: "reports.generate",
|
||||
async userId(userId) {
|
||||
if (!userId) return true;
|
||||
const user = await Meteor.users.findOneAsync(userId, {
|
||||
fields: { subscriptionTier: 1 },
|
||||
});
|
||||
return user?.subscriptionTier !== "premium";
|
||||
},
|
||||
},
|
||||
2,
|
||||
60000,
|
||||
);
|
||||
```
|
||||
|
||||
Keep synchronous matchers for values already present on the invocation. A
|
||||
rejected async matcher fails the invocation; test that error path. Every
|
||||
matcher field also contributes to the bucket key. Include `userId`,
|
||||
`clientAddress`, or `connectionId` when the limit must be scoped rather than
|
||||
global.
|
||||
|
||||
## Custom error message
|
||||
|
||||
```javascript
|
||||
const ruleId = DDPRateLimiter.addRule(rule, 1, 60000);
|
||||
DDPRateLimiter.setErrorMessageOnRule(
|
||||
ruleId,
|
||||
(data) => `Slow down. Try again in ${Math.ceil(data.timeToReset / 1000)}s.`,
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/DDPRateLimiter.md
|
||||
@@ -1,251 +0,0 @@
|
||||
---
|
||||
name: meteor-modern-build-stack
|
||||
description: >
|
||||
Use when configuring or tuning the Meteor 3 modern build stack: SWC
|
||||
transpiler, SWC-based minifier, modern @parcel/watcher, web-arch skipping
|
||||
in development, .meteorignore, and the Rspack bundler integration via the
|
||||
rspack Atmosphere package. Triggers on package.json "meteor": { "modern":
|
||||
true }, .swcrc, swc.config.js, [Transpiler] Used Babel Fallback logs,
|
||||
rspack.config.js, rspack.config.ts, defineConfig from @meteorjs/rspack, Meteor.compileWith*
|
||||
helpers, Meteor.extendConfig, Meteor.extendSwcConfig vs Meteor.replaceSwcConfig,
|
||||
Meteor.splitVendorChunk, Meteor.persistDevFiles, Meteor.disablePlugins,
|
||||
Meteor.enablePortableBuild, HtmlRspackPlugin customization,
|
||||
RSPACK_DEVSERVER_PORT, TOOL_NODE_FLAGS, pnpm workspaces, Rspack 2,
|
||||
skeleton selection, PWA, Workbox and service-worker build setup.
|
||||
Use this skill when the user asks about SWC vs Babel or Rspack configuration.
|
||||
Route existing-app bundler migration to migrate-to-rspack, Blaze PWA
|
||||
scaffolding to meteor-blaze, and jam:offline data to meteor-community-packages.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.3"
|
||||
area: build
|
||||
tagline: "Configure the Meteor 3 modern build stack (SWC transpiler/minifier, `@parcel/watcher`, web-arch skipping, Rspack integration)."
|
||||
bundle: ["essentials"]
|
||||
docs_synced_at: "2026-09-11"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Modern build stack
|
||||
|
||||
The modern build stack is two independent tracks. Enable either or both.
|
||||
|
||||
1. **Meteor Bundler Optimizations** (Meteor 3.3+). One flag, SWC replaces
|
||||
Babel, SWC minifier replaces Terser, `@parcel/watcher` replaces the
|
||||
legacy watcher, development skips legacy archs.
|
||||
2. **Rspack Bundler Integration** (Meteor 3.4+). Atmosphere package
|
||||
delegates app-code compilation to Rspack. Tree shaking, ESM, code
|
||||
splitting via HTTP, modern bundler plugins.
|
||||
|
||||
Standard current `meteor create` application skeletons ship both enabled.
|
||||
Purposefully small or compatibility-oriented skeletons, including `minimal`
|
||||
and `legacy`, may omit Rspack or the modern flag. Inspect the generated
|
||||
`package.json` and `.meteor/packages` instead of inferring features only from
|
||||
the Meteor version. For existing apps, enable optimizations first, then add
|
||||
Rspack once the app code is standards-clean.
|
||||
|
||||
## Enable Meteor Bundler Optimizations
|
||||
|
||||
Add to `package.json`:
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": true
|
||||
}
|
||||
```
|
||||
|
||||
This enables SWC, the SWC minifier, the modern watcher, and dev-mode web
|
||||
arch skipping. Each falls back to legacy when something is incompatible, so
|
||||
this is backward compatible.
|
||||
|
||||
Opt out of pieces:
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": {
|
||||
"transpiler": false,
|
||||
"minifier": false,
|
||||
"watcher": false,
|
||||
"webArchOnly": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or scope SWC: `transpiler.excludeApp`, `transpiler.excludeNodeModules`,
|
||||
`transpiler.excludePackages`, `transpiler.excludeLegacy`. Accept `true` or
|
||||
an array of paths/regexes.
|
||||
|
||||
Verbose transpiler logs to diagnose Babel fallbacks:
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": {
|
||||
"transpiler": { "verbose": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Look for `[Transpiler] Used Babel for <file> Fallback`. The common cause is
|
||||
nested imports; see `references/meteor-bundler-optimizations.md`.
|
||||
|
||||
## Enable Rspack integration
|
||||
|
||||
```bash
|
||||
meteor add rspack
|
||||
```
|
||||
|
||||
On first run the package installs the project-level Rspack setup. App code
|
||||
moves to Rspack; Meteor still handles Atmosphere packages and produces the
|
||||
final bundle. Requires entry points in `package.json` and no nested imports
|
||||
in app code. To migrate an existing app, use the `migrate-to-rspack` skill.
|
||||
|
||||
Inspect `.meteor/versions`, `package.json`, and the lockfile. Meteor
|
||||
3.6-beta.0 pairs `rspack@1.4.0-beta360.0`, `@meteorjs/rspack@3.0.0-beta.1`
|
||||
and Rspack 2.2.0; 3.5.2 retains the 1.3.0/2.2.0 integration pairing.
|
||||
See [release pairings](references/rspack-config.md) and
|
||||
[3.6 dependencies and workspaces](references/meteor-3.6-workspaces.md).
|
||||
For Rspack 1-to-2 config migration, use `migrate-to-rspack`.
|
||||
|
||||
## Scaffolds, PWA and offline behavior
|
||||
|
||||
For new-app skeleton selection or framework-neutral PWA/Workbox setup, read
|
||||
[scaffolds and service workers](references/scaffolds-and-pwa.md).
|
||||
Meteor 3.6 (verified on `3.6-beta.0`) adds separate `--pnpm` workspace and
|
||||
`--pwa` Blaze starters; neither converts an existing app. A worker caches
|
||||
shell/assets, not offline Meteor data. Existing bundler migrations remain
|
||||
owned by `migrate-to-rspack`.
|
||||
|
||||
## SWC config files
|
||||
|
||||
```text
|
||||
.swcrc > swc.config.js > swc.config.ts
|
||||
```
|
||||
|
||||
Only the first found is used. Use `.swcrc` for static config, `swc.config.js`
|
||||
for environment-driven config. The file name must be exactly `.swcrc`, not
|
||||
`config.swcrc`.
|
||||
|
||||
Install `@swc/helpers` to externalize SWC helpers (smaller bundles):
|
||||
|
||||
```bash
|
||||
meteor npm install --save @swc/helpers
|
||||
```
|
||||
|
||||
New apps ship with this preinstalled. Normally no further setup is needed;
|
||||
Meteor's pipeline detects it and emits imports instead of inlining. If only a
|
||||
production or legacy bundle fails on a helper import, inspect Rspack-generated
|
||||
and final Meteor output before changing `.swcrc` or adding manual imports.
|
||||
|
||||
## Rspack config files
|
||||
|
||||
```text
|
||||
rspack.config.js | rspack.config.ts | rspack.config.mjs | rspack.config.cjs
|
||||
```
|
||||
|
||||
Use `defineConfig` from `@meteorjs/rspack`. The function receives a
|
||||
`Meteor` parameter with build flags and helpers. See
|
||||
`references/rspack-config.md` for the full table and the most useful
|
||||
helpers (`extendSwcConfig`, `compileWithRspack`, `compileWithMeteor`,
|
||||
`extendConfig`, `splitVendorChunk`, `persistDevFiles`, `disablePlugins`,
|
||||
`enablePortableBuild`, `setCache`).
|
||||
|
||||
## .meteorignore
|
||||
|
||||
Skip directories the bundler does not need to watch. Same syntax as
|
||||
`.gitignore`. Place at any depth; rules apply to the subtree.
|
||||
|
||||
```gitignore
|
||||
docs/
|
||||
design/
|
||||
cypress/
|
||||
scripts/
|
||||
*.md
|
||||
!README.md
|
||||
```
|
||||
|
||||
For per-command rules, set the `METEOR_IGNORE` env var.
|
||||
|
||||
Do not copy `.gitignore` into `.meteorignore` blindly. Exclude unrelated large
|
||||
trees that Meteor does not need, but never match the active Rspack build context:
|
||||
Meteor consumes its generated main and test modules during final assembly.
|
||||
|
||||
Rspack also generates `_build/`, `public/build-assets/`,
|
||||
`public/build-chunks/`, and `private/build-assets/`. Include active suffixed
|
||||
variants such as `build-assets-test` and `build-chunks-app-test` on Meteor
|
||||
3.5.2, plus custom context names. Add those paths to the
|
||||
native ignore configuration of recursive formatters, linters, typecheckers,
|
||||
test discovery, coverage, and IDEs. `.gitignore` alone is insufficient.
|
||||
|
||||
## Minifier ownership
|
||||
|
||||
`"modern": true` selects Meteor's modern standard minifier. A third-party
|
||||
Atmosphere package that provides the JavaScript minifier remains part of the
|
||||
final Meteor assembly even when Rspack compiles app modules. Inventory custom
|
||||
minifier packages before migration. Keep or remove one only after comparing
|
||||
production output, source maps, build time, and runtime behavior.
|
||||
|
||||
## Production legacy builds
|
||||
|
||||
Dev skips `web.browser.legacy` and `web.cordova` with `"modern": true`.
|
||||
Production still ships legacy by default. To drop legacy in production
|
||||
too, add `modern` to `.meteor/platforms`:
|
||||
|
||||
```text
|
||||
server
|
||||
browser
|
||||
modern
|
||||
```
|
||||
|
||||
## Memory limits
|
||||
|
||||
Rspack runs as a child process and may OOM on large apps. Raise the heap
|
||||
for tool processes temporarily when capturing evidence (Meteor 3.4.1+):
|
||||
|
||||
```bash
|
||||
TOOL_NODE_FLAGS="--max-old-space-size=16384" meteor run
|
||||
```
|
||||
|
||||
On Meteor 3.4.0, use `NODE_OPTIONS="--max-old-space-size=16384"`.
|
||||
|
||||
First distinguish a one-shot build failure from growth during a long watch
|
||||
session. Audit large directories visible to Meteor and check the exact release
|
||||
for fixes. Test heap size and persistent cache as separate variables; revert a
|
||||
change that does not improve the failure or a measured memory trend.
|
||||
|
||||
## Multiple instances
|
||||
|
||||
Meteor 3.5.2 separates development, normal test, and full-app test output
|
||||
within one context (`_build/main-dev`, `_build/test`, `_build/app-test`, plus
|
||||
mode-suffixed assets/chunks). This does not isolate Meteor caches, local Mongo,
|
||||
or ports. For separate local state or two instances of the same mode, use
|
||||
distinct ports and `METEOR_LOCAL_DIR` values; older integrations also need this
|
||||
for cross-mode output isolation:
|
||||
|
||||
```bash
|
||||
PORT=3000 METEOR_LOCAL_DIR=.meteor/local-1 meteor run
|
||||
PORT=3001 METEOR_LOCAL_DIR=.meteor/local-2 meteor run
|
||||
```
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Enable optimizations and Rspack at the same time on a legacy app. Enable
|
||||
`"modern": true` first, clean up Babel fallbacks, then add Rspack.
|
||||
- Edit files inside `_build/`, `public/build-assets/`,
|
||||
`public/build-chunks/`, or `private/build-assets/`. Autogenerated.
|
||||
- Assume `.gitignore` prevents code-quality tools from scanning generated
|
||||
Rspack output. Configure each tool's own ignore mechanism.
|
||||
- Copy `.gitignore` to `.meteorignore`. Git may ignore Rspack's generated
|
||||
handoff even though Meteor must read it.
|
||||
- Remove a custom Atmosphere minifier only because Rspack is enabled.
|
||||
Benchmark the final production bundle first.
|
||||
- Disable Rspack persistent cache without need. It is the default and the
|
||||
main rebuild-speed win. Disable only when investigating OOM or a
|
||||
cache-related Rspack bug.
|
||||
- Name an SWC config `config.swcrc` or `rc.swc`. Only `.swcrc` is read.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/meteor-bundler-optimizations.md`
|
||||
- `references/rspack-config.md`
|
||||
- `references/eval-cases.md`
|
||||
- For converting an existing app to Rspack: `migrate-to-rspack` skill.
|
||||
@@ -1,310 +0,0 @@
|
||||
# Evaluation cases for `meteor-modern-build-stack`
|
||||
|
||||
## Case 1: enable optimizations
|
||||
|
||||
Prompt: "How do I turn on the modern build stack? My app is on Meteor 3.3."
|
||||
|
||||
Pass if the agent adds `"meteor": { "modern": true }` to `package.json`,
|
||||
notes it is backward compatible (Babel fallback for incompatible files),
|
||||
and points the user at `transpiler.verbose` to inspect fallbacks before
|
||||
investing in migration.
|
||||
|
||||
## Case 2: silent Babel fallback
|
||||
|
||||
Prompt: "I enabled modern but builds feel the same. How do I tell whether
|
||||
SWC is actually being used?"
|
||||
|
||||
Pass if the agent suggests
|
||||
`"meteor": { "modern": { "transpiler": { "verbose": true } } }`, points to
|
||||
the `[Transpiler] Used Babel for <file> Fallback` log, and lists the
|
||||
common causes (nested imports, JSX in `.js`, Babel-only plugin) with their
|
||||
SWC equivalents.
|
||||
|
||||
## Case 3: alias works for import, not require
|
||||
|
||||
Prompt: "I added an alias to `.swcrc`. `import x from "@ui/x"` works but
|
||||
`require("@ui/x")` does not. Why?"
|
||||
|
||||
Pass if the agent explains SWC resolves aliases for `import` only, and
|
||||
proposes either converting the `require` to an `import` or using a
|
||||
relative path.
|
||||
|
||||
## Case 4: native dep crashes with Rspack
|
||||
|
||||
Prompt: "After `meteor add rspack`, my server crashes with
|
||||
`Cannot find module '/_build/main-dev/lib/worker.js'`."
|
||||
|
||||
Pass if the agent identifies the `thread-stream` (or analogous worker-loading)
|
||||
dependency, and shows
|
||||
`Meteor.compileWithMeteor(["thread-stream"])` in `rspack.config.js` to
|
||||
let Meteor/Node handle it instead of Rspack.
|
||||
|
||||
## Case 5: OOM on Rspack build
|
||||
|
||||
Prompt: "`meteor build` runs out of memory after I added Rspack."
|
||||
|
||||
Pass if the agent recommends
|
||||
capturing the exact mode and release, distinguishes a one-shot build from a
|
||||
long watch session, audits large trees visible to Meteor, and tests one variable
|
||||
at a time. It may use `TOOL_NODE_FLAGS` on 3.4.1+ or `NODE_OPTIONS` on 3.4.0 as a
|
||||
temporary mitigation. It may test `Meteor.setCache(false)` separately. Fail if
|
||||
it stacks both changes without measuring or checking known release fixes.
|
||||
|
||||
## Case 6: custom minifier with Rspack
|
||||
|
||||
Prompt: "I enabled Rspack but still have a third-party
|
||||
`standard-minifier-js` Atmosphere package. Should I delete it automatically?"
|
||||
|
||||
Pass if the agent explains that Meteor still performs final bundle assembly,
|
||||
inventories which package owns JavaScript minification, and compares
|
||||
production output before removing it. Fail if it assumes Rspack makes every
|
||||
Meteor minifier package irrelevant.
|
||||
|
||||
## Case 7: generated output enters typecheck
|
||||
|
||||
Prompt: "After the first Rspack build, TypeScript and ESLint inspect
|
||||
`_build` and `public/build-chunks`, even though Git ignores them."
|
||||
|
||||
Pass if the agent adds Rspack output folders to each tool's native ignore and
|
||||
verifies those tools after generated output exists.
|
||||
|
||||
## Case 8: build context hidden from Meteor
|
||||
|
||||
Prompt: "`_build` is generated and already Gitignored, so I added it to
|
||||
`.meteorignore`. Now Meteor cannot find `server-meteor.js`."
|
||||
|
||||
Pass if the agent removes the active build context from `.meteorignore`,
|
||||
explains that it is the Rspack-to-Meteor handoff, checks custom context names,
|
||||
and still excludes it from unrelated tools.
|
||||
|
||||
## Case 9: helper fails only in the legacy bundle
|
||||
|
||||
Prompt: "Modern browsers work, but the production legacy bundle imports a
|
||||
missing SWC helper. Should I add side-effect helper imports to app startup?"
|
||||
|
||||
Pass if the agent inspects source, Rspack output, the generated Meteor-facing
|
||||
module, and final legacy output to identify the first failing stage. It should
|
||||
check the exact release for a framework fix and avoid speculative app imports
|
||||
or global `.swcrc` changes.
|
||||
|
||||
## Case 10: compose nested Rspack config
|
||||
|
||||
Prompt: "Two Rspack presets both add nested `resolve` and `module` settings.
|
||||
Shallow object spread makes one replace the other. Which Meteor helper should I
|
||||
use?"
|
||||
|
||||
Pass if the agent uses `Meteor.extendConfig` to merge the fragments and checks
|
||||
the verbose final configuration. Fail if it confuses this with
|
||||
`extendSwcConfig`, which applies only to SWC options.
|
||||
|
||||
## Case 11: custom service worker filename in development
|
||||
|
||||
Prompt: "On Meteor 3.4.1, Workbox generates `service-worker.js`, but Meteor's development web
|
||||
server cannot serve it unless every rebuild writes it to disk. Rewriting it also
|
||||
forces a page reload."
|
||||
|
||||
Pass if the agent uses `Meteor.persistDevFiles({ once: ['service-worker.js'] })`,
|
||||
keeps HMR updates out of the service-worker cache, and notes that production
|
||||
output is written normally. It must identify Meteor 3.4.1 and
|
||||
`@meteorjs/rspack` v2 as the minimum.
|
||||
|
||||
## Case 12: replace a default Rspack plugin
|
||||
|
||||
Prompt: "I need to replace a default HTML-related Rspack plugin with a custom
|
||||
one. How do I disable only the existing plugin?"
|
||||
|
||||
Pass if the agent uses `Meteor.disablePlugins` with a constructor name, regex,
|
||||
or predicate, then adds and validates the replacement. Fail if it mutates the
|
||||
generated config or disables unrelated plugins.
|
||||
|
||||
## Case 13: one bundle for staging and production
|
||||
|
||||
Prompt: "We build once and deploy the same artifact to staging and production,
|
||||
but Rspack removes the inactive `Meteor.isDevelopment` branch at build time."
|
||||
|
||||
Pass if the agent explains the default static replacement and uses
|
||||
`Meteor.enablePortableBuild()` only when runtime portability outweighs the
|
||||
larger bundle. It must not claim that `Meteor.isClient`, `isServer`, or `isTest`
|
||||
become portable runtime flags.
|
||||
|
||||
## Case 14: TypeScript Rspack config
|
||||
|
||||
Prompt: "Will Meteor discover `rspack.config.ts`, or must I rename it to
|
||||
JavaScript?"
|
||||
|
||||
Pass if the agent lists `.ts` as a supported project-level Rspack config name
|
||||
alongside `.js`, `.mjs`, and `.cjs`. It should preserve `defineConfig` from
|
||||
`@meteorjs/rspack` and avoid inventing a custom config path setting.
|
||||
|
||||
## Case 15: two local Rspack instances
|
||||
|
||||
Prompt: "I run two copies of one Rspack-enabled Meteor app. Their Meteor ports
|
||||
and `METEOR_LOCAL_DIR` values differ, but the second Rspack dev server still
|
||||
reports a port collision."
|
||||
|
||||
Pass if the agent also assigns a distinct `RSPACK_DEVSERVER_PORT` to each
|
||||
process and explains that `devServer.port` in `rspack.config` is reserved by
|
||||
the Meteor integration.
|
||||
|
||||
## Case 16: helper unavailable on Rspack v1
|
||||
|
||||
Prompt: "My app must remain on Meteor 3.4.0 with `@meteorjs/rspack@1.0.0`.
|
||||
Can I copy a current example that uses `Meteor.persistDevFiles` and
|
||||
`Meteor.enablePortableBuild`?"
|
||||
|
||||
Pass if the agent says both helpers require Meteor 3.4.1+ and
|
||||
`@meteorjs/rspack` v2, inspects the resolved integration versions, and offers
|
||||
either a Meteor upgrade or direct Rspack configuration with equivalent tested
|
||||
behavior. Fail if it installs v2 independently into the Meteor 3.4.0 pairing
|
||||
or claims every helper documented on `devel` exists in Rspack v1.
|
||||
|
||||
## Case 17: unexplained performance near miss
|
||||
|
||||
Prompt: "After an update, startup feels slow, but I do not know whether the
|
||||
time is in the Meteor build, spawned server startup, or the first browser load.
|
||||
Which Rspack setting should I change?"
|
||||
|
||||
Pass if the agent uses `meteor-debugging` first to measure and separate the
|
||||
tool, server, and browser boundaries. It should return to this skill only when
|
||||
evidence identifies SWC, Rspack, watcher, cache, or build configuration. Fail
|
||||
if it changes Rspack settings before locating the slow boundary.
|
||||
|
||||
## Case 18: dependency opt-out on Meteor 3.5.2
|
||||
|
||||
Prompt: "Our Meteor 3.5.2 build must not modify package.json or the lockfile.
|
||||
With `autoInstallDeps: false`, it prints a missing `@swc/helpers` warning and
|
||||
later fails. Should I ignore the warning? Would running `meteor update --npm`
|
||||
in CI still honor the opt-out?"
|
||||
|
||||
Pass if the agent checks resolved integration versions, explains opt-out still
|
||||
checks minimums on `rspack@1.3.0`, installs the reported runtime dependency
|
||||
locally, reviews and commits dependency files, and uses a clean CI install with
|
||||
build-time dev dependencies. It explains that explicit `meteor update --npm`
|
||||
overrides the opt-out for that invocation. Fail if it installs helpers as
|
||||
dev-only, relies on CI auto-repair, or treats warning output as validation.
|
||||
|
||||
## Case 19: earlier dependency opt-out
|
||||
|
||||
Prompt: "Our app must stay on Meteor 3.5.1 with `rspack@1.2.0` and
|
||||
`autoInstallDeps: false`. Missing dependencies produce no helpful warning.
|
||||
Was automatic installation first introduced in 3.5.2?"
|
||||
|
||||
Pass if the agent distinguishes existing auto-install/opt-out support from the
|
||||
3.5.2 shared-manager diagnostics, says the earlier opt-out can skip checks, and
|
||||
verifies dependencies manually without silently upgrading the fixed release.
|
||||
|
||||
## Case 20: mixed build modes and generated ignores
|
||||
|
||||
Prompt: "On Meteor 3.5.2, development and full-app tests run in one checkout.
|
||||
Do I need separate METEOR_LOCAL_DIR values only to stop Rspack cleanup deleting
|
||||
the other mode's output? ESLint now scans public/build-chunks-app-test too."
|
||||
|
||||
Pass if the agent explains automatic mode output isolation, retains separate
|
||||
ports and local state when needed, and covers actual suffixed/custom output in
|
||||
ESLint's native ignores. It must not hide Meteor's handoff in `.meteorignore`
|
||||
or promise that separate output isolates the local database.
|
||||
|
||||
## Case 21: TypeScript config cache boundary
|
||||
|
||||
Prompt: "On Meteor 3.5.2 with `@meteorjs/rspack@2.2.0`, rspack.config.ts
|
||||
imports `./config/alias.ts` and also computes a dynamic import path. Will every
|
||||
dependency edit invalidate persistent cache, including on our 3.5.1 branch?"
|
||||
|
||||
Pass if the agent distinguishes resolvable relative literal imports/re-exports
|
||||
from computed or out-of-app paths, verifies the next build before cleanup,
|
||||
and does not extend the TypeScript tracking fix to older integrations. Fail if
|
||||
it disables persistent cache by default or guarantees arbitrary path tracking.
|
||||
|
||||
## Case 22: 3.6 beta dependency pairing
|
||||
|
||||
Prompt: "We are on Meteor 3.6-beta.0 with autoInstallDeps false. Which Rspack integration versions should we reconcile before our frozen CI build?"
|
||||
|
||||
Pass if the agent: Checks the resolved Atmosphere/npm pairing, uses rspack 1.4.0-beta360.0 and @meteorjs/rspack 3.0.0-beta.1 rather than a presumed stable 3.0.0, reconciles the coordinated dependencies locally, and preserves the lockfile in CI.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 23: pnpm workspace install ownership
|
||||
|
||||
Prompt: "Meteor 3.6-beta.0 runs from apps/app in a pnpm workspace. The root pins pnpm but the app has an old npm packageManager hint. Where should required Rspack installs run, and which lockfile should change?"
|
||||
|
||||
Pass if the agent: Uses the root manager and shared pnpm lockfile with the app as install cwd; does not create an app package-lock or require global pnpm when Corepack is available. Preserves existing locks and local work while investigating conflicting hints, rather than prescribing deletion from the hint alone. Does not forbid pnpm-managed links under apps/app/node_modules.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 24: local protocol dependencies
|
||||
|
||||
Prompt: "Our 3.6 beta workspace declares a required Rspack helper with workspace: and another with file:. Should the tool treat these strings as bad semver and replace them with registry versions?"
|
||||
|
||||
Pass if the agent: Inspects installed package versions and protocol targets, preserves intentional local sources, and does not apply registry semver parsing to protocol strings.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 25: older workspace near miss
|
||||
|
||||
Prompt: "We are pinned to Meteor 3.5.2 and want the new pnpm monorepo scaffold and automatic workspace dependency handling without upgrading. Can we use the 3.6 commands unchanged?"
|
||||
|
||||
Pass if the agent: States the 3.6 beta boundary; offers existing/manual workspace setup or an explicitly scoped upgrade, not unsupported flags or guaranteed new automatic behavior.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 26: React PWA with Workbox and offline data
|
||||
|
||||
Prompt: "Our Meteor 3.6-beta.0 React app already uses Rspack. We want a PWA
|
||||
like Notes Offline. Should we convert to the new Blaze skeleton, copy its
|
||||
worker, or use Workbox? Will the worker save Minimongo and replay edits?"
|
||||
|
||||
Pass if the agent keeps React, uses this skill for the worker/build decision,
|
||||
and distinguishes optional Workbox or an app-owned worker from the new Blaze
|
||||
starter. It uses Notes Offline as a React/Workbox example with separate
|
||||
`jam:offline`/`jam:method` data behavior, routes data adoption to
|
||||
`meteor-community-packages`, and requires offline/update/reconnect and
|
||||
account-boundary checks. Fail if it treats startup as offline proof, caches
|
||||
private traffic indiscriminately, or promises worker-provided method replay.
|
||||
|
||||
## Case 27: new pnpm workspace starter
|
||||
|
||||
Prompt: "Start a Meteor 3.6-beta.0 pnpm workspace with shared client and server
|
||||
packages. Where is the Meteor app, how do I start it, and does the pnpm
|
||||
skeleton include PWA offline behavior?"
|
||||
|
||||
Pass if the agent uses `meteor create --release 3.6-beta.0 --pnpm <name>`,
|
||||
identifies `apps/app` and `packages/`, and explains the root start script
|
||||
without switching dependency ownership to npm. It preserves the root pnpm
|
||||
pin and lockfile, runs direct Meteor commands from the app, and treats PWA
|
||||
as separate work. Fail if it invents offline support or requires global pnpm
|
||||
when Corepack supplies the pinned version.
|
||||
|
||||
## Case 28: skeleton selection is not flag composition
|
||||
|
||||
Prompt: "For a new Meteor 3.6-beta.0 app, should I use --react, --typescript,
|
||||
--svelte, --pnpm or --pwa? Can I combine --react --pnpm --pwa to get all three?
|
||||
Does meteor create --list show every skeleton?"
|
||||
|
||||
Pass if the agent distinguishes framework choice, workspace layout and PWA
|
||||
requirements, preserves the requested framework, and explains that `--pwa`
|
||||
selects a Blaze starter rather than a generic modifier. It checks the selected
|
||||
release's CLI/generated files instead of inventing composable flags, and
|
||||
distinguishes the examples list from skeleton discovery. Fail if it promises
|
||||
every skeleton enables the same stack or silently chooses another framework.
|
||||
|
||||
## Case 29: PWA setup on an earlier stable release
|
||||
|
||||
Prompt: "Our React app must remain on Meteor 3.5.2 with @meteorjs/rspack 2.2.0.
|
||||
Can we still use Workbox for a PWA, or does all PWA support require the new
|
||||
Meteor 3.6 --pwa option?"
|
||||
|
||||
Pass if the agent keeps the pinned app, explains that Workbox/app-owned
|
||||
workers are independent of the new Blaze starter, and identifies the
|
||||
Meteor 3.4.1/v2 floor for documented worker persistence helpers. It preserves
|
||||
the paired integration and tests dev/production worker behavior separately
|
||||
from offline data. Fail if it requires upgrading to 3.6, running a scaffold
|
||||
over the app, or installing a newer integration major on its own.
|
||||
|
||||
## Case 30: narrower worker scope is valid
|
||||
|
||||
Prompt: "Our Meteor 3.6 React PWA is under /portal/ but serves its worker at
|
||||
/sw.js. Can we register that worker with scope /portal/, or must we move it?
|
||||
What if /portal/sw.js instead requests scope /?"
|
||||
|
||||
Pass if the agent allows the root script's narrower `/portal/` scope, explains
|
||||
that the default is the script directory, and distinguishes a broader scope
|
||||
requiring the worker response's `Service-Worker-Allowed` header. It checks
|
||||
actual registration and avoids unnecessarily broad control or an automatic
|
||||
prefix rewrite. Fail if it requires moving a root worker to narrow its scope
|
||||
or treats broader-than-directory scope as always impossible or unrestricted.
|
||||
@@ -1,101 +0,0 @@
|
||||
# Meteor 3.6 dependencies and workspaces
|
||||
|
||||
These decisions start with Meteor 3.6, verified on `3.6-beta.0` with
|
||||
`rspack@1.4.0-beta360.0` and `tools-core@1.4.0-beta360.0`. Earlier 3.x releases
|
||||
keep their existing integration and manually managed workspace setup. Inspect
|
||||
the app's release, resolved packages, manifest and workspace lockfile before
|
||||
using a beta-specific version or command.
|
||||
|
||||
## Rspack 2 dependency set
|
||||
|
||||
| Package | Minimum selected by 3.6-beta.0 | Dependency category |
|
||||
|---|---|---|
|
||||
| `@meteorjs/rspack` | `3.0.0-beta.1` | Development |
|
||||
| `@rspack/core`, `@rspack/cli`, `@rspack/dev-server` | `2.2.0` each | Development |
|
||||
| `@swc/core` | `1.15.32` | Development |
|
||||
| `@rsdoctor/rspack-plugin` | `1.5.9` | Development |
|
||||
| `@swc/helpers` | `0.5.23` | Runtime |
|
||||
| React only: `@rspack/plugin-react-refresh`, `react-refresh` | `2.0.0`, `0.17.0` | Development |
|
||||
|
||||
`swc-loader@0.2.6` remains a separately selected dependency when the integration
|
||||
needs it. Do not confuse the Meteor npm integration's major 3 with Rspack's
|
||||
major 2. Do not substitute unreleased stable `@meteorjs/rspack@3.0.0` for this
|
||||
beta's pin. Later releases require checking their own resolved pairing.
|
||||
|
||||
Automatic installation updates the coordinated set. With
|
||||
`meteor.autoInstallDeps: false`, inspect the warnings and prepare the changes
|
||||
locally with the detected manager. `meteor update --npm` explicitly overrides
|
||||
the opt-out for that invocation; keep it out of immutable CI builds.
|
||||
|
||||
On npm apps with installed Rspack 1.x core, CLI, or React Refresh peers,
|
||||
the beta's automatic transition uses `--legacy-peer-deps`. Its manual warning
|
||||
can omit that flag. If the reported dependency update fails with the confirmed
|
||||
old-peer conflict, apply the flag only to that coordinated npm install and
|
||||
verify the resulting tree. Do not set a global npm option, add the flag to
|
||||
pnpm/Yarn, or suppress unrelated peer errors. Prove the locked CI install
|
||||
works; if that lockfile requires the same npm flag, document it in that app's
|
||||
CI command and revisit it after the transition.
|
||||
|
||||
## Create a pnpm workspace
|
||||
|
||||
```bash
|
||||
meteor create --release 3.6-beta.0 --pnpm my-workspace
|
||||
cd my-workspace
|
||||
meteor npm start
|
||||
```
|
||||
|
||||
Inspect the generated structure:
|
||||
|
||||
```text
|
||||
package.json # packageManager pin and root scripts
|
||||
pnpm-workspace.yaml
|
||||
pnpm-lock.yaml
|
||||
apps/app/.meteor/release # Meteor commands target this app
|
||||
apps/app/package.json # app dependencies and workspace:* links
|
||||
packages/domain/ # shared npm package
|
||||
packages/server-tools/ # server-only npm package
|
||||
packages/ui/ # client npm package
|
||||
```
|
||||
|
||||
Creation installs through pnpm, using Corepack when available. A global pnpm
|
||||
installation is not required when Corepack can supply the pinned version.
|
||||
`meteor npm start` runs the root script; it does not make npm the workspace's
|
||||
dependency manager. Run direct Meteor commands from `apps/app`.
|
||||
|
||||
For a Meteor 3.5.2 or earlier app that must stay pinned, do not use `--pnpm`
|
||||
or promise the new detection. Keep its established workspace and manager,
|
||||
prepare dependencies explicitly, and verify linked imports and builds.
|
||||
|
||||
## Preserve installation ownership
|
||||
|
||||
1. Find the workspace root, root `packageManager`, workspace manifest and
|
||||
lockfile. The root manager takes precedence over the nested app's hint.
|
||||
2. Install app dependencies from the Meteor app directory with that manager,
|
||||
so the app manifest and shared workspace lockfile change together. Do not
|
||||
add them to the root manifest or create a competing `package-lock.json`.
|
||||
If conflicting hints or lockfiles already exist, inspect their history and
|
||||
preserve local changes before selecting an authority. Do not delete an
|
||||
existing lockfile or `node_modules` merely because npm was mentioned.
|
||||
pnpm can legitimately create `apps/app/node_modules` links; a shared root
|
||||
lockfile does not require a root-only `node_modules` tree.
|
||||
3. Keep `file:`, `link:`, `portal:` and `workspace:` declarations when they
|
||||
are intentional. Check the actual installed package version and linkage;
|
||||
the protocol text is not a semver range. Repair missing links or an
|
||||
incompatible source version instead of replacing every link with a
|
||||
registry dependency.
|
||||
4. npm, pnpm and Yarn can auto-install. Other declared managers receive
|
||||
manual guidance without automatic mutation. A failed pnpm/Yarn executable
|
||||
can fall back to Corepack; inspect its error rather than switching managers.
|
||||
5. Review both manifests and the authoritative lockfile, then use a frozen
|
||||
install from the workspace root in CI: `pnpm install --frozen-lockfile`,
|
||||
`yarn install --immutable` for modern Yarn, or the project's npm workflow.
|
||||
Yarn Classic uses `--frozen-lockfile`. Include build-time dev dependencies.
|
||||
|
||||
Keep default symlink resolution for packages imported by name. Only an
|
||||
app-local source symlink that needs its apparent location calls for
|
||||
`resolve.symlinks: false`. Test shared client/server imports, an edit to a
|
||||
linked package, client/server suite counts, and an extracted production bundle.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
@@ -1,244 +0,0 @@
|
||||
# Meteor Bundler Optimizations
|
||||
|
||||
`"meteor": { "modern": true }` in `package.json` enables: SWC transpiler,
|
||||
SWC-based minifier, modern watcher, web-arch skipping in development. All
|
||||
fall back to legacy behavior on incompatibility.
|
||||
|
||||
## Transpiler (SWC)
|
||||
|
||||
SWC replaces Babel for `.js`, `.jsx`, `.ts`, `.tsx` across app, npm, and
|
||||
Atmosphere packages. Faster, no Fibers tax.
|
||||
|
||||
### Verbose output
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": {
|
||||
"transpiler": { "verbose": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each file logs which transpiler ran. Babel fallbacks log
|
||||
`[Transpiler] Used Babel for <file> (<context>) Fallback`.
|
||||
|
||||
### Excluding files from SWC
|
||||
|
||||
When a file is known-incompatible, skip SWC entirely to avoid the fallback
|
||||
overhead.
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": {
|
||||
"transpiler": {
|
||||
"excludeApp": ["\\.jsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`excludeApp`, `excludeNodeModules`, `excludePackages`, `excludeLegacy`:
|
||||
each accepts `true` (always Babel) or an array of paths/regex-like
|
||||
patterns.
|
||||
|
||||
### Externalize SWC helpers
|
||||
|
||||
```bash
|
||||
meteor npm install --save @swc/helpers
|
||||
```
|
||||
|
||||
Meteor's pipeline detects it and emits imports for shared helpers instead
|
||||
of inlining `_extends`, `_objectSpread`, etc. into every file. Preinstalled
|
||||
on new apps. No `.swcrc` change is normally required. If only a production or
|
||||
legacy build fails on a helper import, compare the source, Rspack output,
|
||||
generated Meteor-facing module, and final bundle before changing helper config.
|
||||
The later Meteor assembly can transform generated Rspack output too.
|
||||
|
||||
### Custom `.swcrc`
|
||||
|
||||
Lookup order: `.swcrc` > `swc.config.js` > `swc.config.ts`. Only the
|
||||
first match is used. File name must be exactly `.swcrc`.
|
||||
|
||||
Add SWC plugins, JSX-in-JS support, or React runtime config here.
|
||||
|
||||
```json
|
||||
{
|
||||
"jsc": {
|
||||
"parser": { "syntax": "ecmascript", "jsx": true },
|
||||
"transform": {
|
||||
"react": { "runtime": "automatic" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For TypeScript: `"syntax": "typescript"` and `"tsx": true`.
|
||||
|
||||
### Import aliases via SWC
|
||||
|
||||
```json
|
||||
{
|
||||
"jsc": {
|
||||
"baseUrl": "./",
|
||||
"paths": { "@ui/*": ["ui/*"] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
SWC resolves aliases for `import`. It does NOT resolve aliases for
|
||||
`require(...)` calls. Use an `import` or a relative path for those.
|
||||
|
||||
For dynamic aliases by env, use `swc.config.js`:
|
||||
|
||||
```javascript
|
||||
var mode = process.env.MODE_ENV;
|
||||
module.exports = {
|
||||
jsc: {
|
||||
baseUrl: "./",
|
||||
paths: mode === "USER" ? { "@ui/*": ["user/*"] }
|
||||
: { "@ui/*": ["admin/*"] },
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Transform-imports plugin
|
||||
|
||||
To shrink full-package imports (e.g. lodash):
|
||||
|
||||
```bash
|
||||
meteor npm install -D @swc/plugin-transform-imports
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"jsc": {
|
||||
"experimental": {
|
||||
"plugins": [[
|
||||
"@swc/plugin-transform-imports",
|
||||
{
|
||||
"lodash": {
|
||||
"transform": "lodash/{{member}}",
|
||||
"preventFullImport": true
|
||||
}
|
||||
}
|
||||
]]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rewrites `import { map } from "lodash"` into `import map from "lodash/map"`.
|
||||
|
||||
### Private class fields
|
||||
|
||||
SWC parses `#privateField`, `#privateMethod()`, static private members
|
||||
natively. No `.swcrc` change required. Babel does not parse them in Meteor;
|
||||
SWC does.
|
||||
|
||||
### Common Babel fallback causes
|
||||
|
||||
| Cause | Fix |
|
||||
|------------------------------------|--------------------------------------------------------------|
|
||||
| Nested imports | Move to top-level, or use dynamic `import()` / `require`. |
|
||||
| JSX in `.js` files | Add `jsc.parser.jsx: true` in `.swcrc`. |
|
||||
| Babel-only plugin (e.g. React Compiler) | Either keep Babel via `excludeApp: true`, or wait. |
|
||||
| Custom babel-plugin-module-resolver | Move aliases to `.swcrc`'s `jsc.paths`. |
|
||||
|
||||
## Minifier (SWC-based)
|
||||
|
||||
Replaces Terser in production builds. Same flag (`"modern": true`). Opt out:
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": { "minifier": false }
|
||||
}
|
||||
```
|
||||
|
||||
This flag controls Meteor's standard minifier path. If `.meteor/packages`
|
||||
contains a third-party package that provides the JavaScript minifier, do not
|
||||
assume the flag replaces it. Rspack compiles app modules, then Meteor still
|
||||
assembles and minifies the final bundle. Compare production output with and
|
||||
without the custom package before choosing one implementation.
|
||||
|
||||
## Watcher (`@parcel/watcher`)
|
||||
|
||||
Native cross-OS file watcher. Opt out:
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": { "watcher": false }
|
||||
}
|
||||
```
|
||||
|
||||
For WSL, remote volumes, or unstable inotify, force polling:
|
||||
|
||||
```bash
|
||||
METEOR_WATCH_FORCE_POLLING=true meteor run
|
||||
METEOR_WATCH_POLLING_INTERVAL_MS=1000 METEOR_WATCH_FORCE_POLLING=true meteor run
|
||||
```
|
||||
|
||||
Polling burns CPU but is the reliable option in those environments.
|
||||
|
||||
## Web Arch (dev only)
|
||||
|
||||
`"modern": true` makes development skip `web.browser.legacy` and
|
||||
`web.cordova`. Equivalent to `--exclude-archs web.browser.legacy,web.cordova`.
|
||||
Opt out:
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": { "webArchOnly": false }
|
||||
}
|
||||
```
|
||||
|
||||
This only affects development. To drop legacy from production, add
|
||||
`modern` to `.meteor/platforms`:
|
||||
|
||||
```text
|
||||
server
|
||||
browser
|
||||
modern
|
||||
```
|
||||
|
||||
## .meteorignore
|
||||
|
||||
`.gitignore` syntax. Place at any directory level; applies to the subtree.
|
||||
Lets Meteor skip docs, design assets, infra, test runners, scripts.
|
||||
|
||||
```gitignore
|
||||
docs/
|
||||
design/
|
||||
mockups/
|
||||
cypress/
|
||||
playwright/
|
||||
scripts/
|
||||
tools/
|
||||
*.md
|
||||
!README.md
|
||||
```
|
||||
|
||||
Subdirectory `.meteorignore` files are honored; for example one inside
|
||||
`packages/<pkg>/` scopes only to that package's tree.
|
||||
|
||||
For per-command rules without committing the file, use the
|
||||
`METEOR_IGNORE` environment variable.
|
||||
|
||||
Do not synchronize `.gitignore` and `.meteorignore` mechanically. Gitignored
|
||||
Rspack build contexts contain generated main and test modules that Meteor reads
|
||||
during final assembly, so they must remain visible to Meteor. For performance,
|
||||
report large unrelated trees that Git ignores but Meteor still scans, then add
|
||||
anchored `.meteorignore` rules only after proving they are not application or
|
||||
test inputs.
|
||||
|
||||
## Profiling
|
||||
|
||||
Run `meteor profile` before and after enabling `"modern": true` to
|
||||
quantify the improvement.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- `meteor reset` clears the build cache.
|
||||
- Delete `.meteor/local/` to force a clean rebuild.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/meteor-bundler-optimizations.md
|
||||
@@ -1,348 +0,0 @@
|
||||
# Customizing `rspack.config.js`
|
||||
|
||||
The `rspack` Atmosphere package generates a `rspack.config.js` at install
|
||||
time. Edit it with `defineConfig` from `@meteorjs/rspack`. Accepted names are
|
||||
`rspack.config.js`, `rspack.config.ts`, `rspack.config.mjs`, and
|
||||
`rspack.config.cjs`.
|
||||
|
||||
Match both integration packages to the Meteor release:
|
||||
|
||||
| Meteor | `rspack` | `@meteorjs/rspack` | Capability boundary |
|
||||
|---|---|---|---|
|
||||
| 3.4 | `1.0.0` | `1.0.0` | Base helpers, including `extendConfig`, `disablePlugins`, and `RSPACK_DEVSERVER_PORT`. |
|
||||
| 3.4.1 and 3.5 | `1.1.0` | `2.0.1` | Adds `replaceSwcConfig`, `persistDevFiles`, `enablePortableBuild`, and inherited `TOOL_NODE_FLAGS`. |
|
||||
| 3.5.1 | `1.2.0` | `2.1.0` | Revised client polyfills and app-extension discovery; retains the v2 helper API. |
|
||||
| 3.5.2 | `1.3.0` | `2.2.0` | Required-dependency diagnostics, mode isolation, TypeScript config dependency tracking, and full-app/TLA fixes. |
|
||||
| 3.6-beta.0 | `1.4.0-beta360.0` | `3.0.0-beta.1` | Rspack 2.2.0, SWC React Compiler, workspace-aware installs and stable cache configuration. |
|
||||
|
||||
Inspect `.meteor/versions`, `package.json`, and the lockfile. Do not install an
|
||||
arbitrary `@meteorjs/rspack` major to obtain one helper; upgrade the Meteor
|
||||
release and its paired dependencies.
|
||||
|
||||
## Required npm dependencies
|
||||
|
||||
With `rspack@1.3.0` and `tools-core@1.3.0` (Meteor 3.5.2), the shared manager
|
||||
checks required minimums even when `meteor.autoInstallDeps` is `false` in
|
||||
`package.json`. With automatic installation enabled, it installs missing or
|
||||
outdated dependencies and reports changes. A satisfied dependency set is quiet.
|
||||
|
||||
During an ordinary build with automatic installation disabled, it prints the missing/outdated versions
|
||||
and manual install commands without changing project dependencies. It continues
|
||||
the build, which can still fail because those dependencies are missing. Treat
|
||||
the warning as a dependency problem, not as a successful compatibility check.
|
||||
|
||||
An explicit `meteor update --npm` overrides the opt-out for that invocation
|
||||
without changing the stored flag. Use it during authorized dependency
|
||||
preparation; keep it out of an immutable CI build.
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"autoInstallDeps": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For the 3.5.2 pairing, the core minimums are `@rspack/core` and `@rspack/cli`
|
||||
1.7.1, `@meteorjs/rspack` 2.2.0, `@rsdoctor/rspack-plugin` 1.5.7, and
|
||||
`@swc/helpers` 0.5.17. Keep `@swc/helpers` in runtime dependencies; the others
|
||||
are build-time dev dependencies. React adds its detected refresh dependencies.
|
||||
Use the versions and categories reported by the resolved integration instead
|
||||
of copying these minimums to another release.
|
||||
|
||||
Automatic installation and the opt-out already exist in Meteor 3.5.1. That
|
||||
release skips the checks when opted out and does not provide the new warning
|
||||
contract. Inspect its dependencies manually or upgrade the paired integration.
|
||||
|
||||
For reproducible CI/Docker, resolve dependencies locally, review and commit
|
||||
`package.json` and its lockfile, and use `meteor npm ci` for npm apps in the build stage
|
||||
with dev dependencies available. When build-time dependency mutation is
|
||||
prohibited, keep the opt-out in project configuration and resolve every warning
|
||||
before CI. Do not rely on a container silently repairing an incomplete lockfile.
|
||||
|
||||
For Meteor 3.6-beta.0's coordinated npm peer transition, new dependency minimums,
|
||||
pnpm scaffold and workspace-owned installs, read
|
||||
[3.6 dependencies and workspaces](meteor-3.6-workspaces.md).
|
||||
Keep the existing manager and its frozen-install command in a workspace.
|
||||
|
||||
## Rspack 2 configuration boundary
|
||||
|
||||
Meteor 3.6-beta.0 supplies CSS through `css/auto`, persistent options under
|
||||
top-level `cache`, `externalsType: "commonjs2"`, and compatible output settings.
|
||||
Preserve those defaults. Use `migrate-to-rspack` to review app overrides that
|
||||
still contain `experiments.css`, `experiments.cache`, `output.libraryTarget`,
|
||||
or a hand-written `webpack-merge` integration.
|
||||
|
||||
Rspack 2's built-in SWC loader no longer discovers `.swcrc` itself, but
|
||||
`@meteorjs/rspack@3.0.0-beta.1` still reads Meteor's `.swcrc`, `swc.config.js`
|
||||
or `swc.config.ts` and passes options to the loader. Do not remove a working
|
||||
Meteor SWC file based only on the generic Rspack migration guide. Inspect the
|
||||
effective configuration; extend it with `Meteor.extendSwcConfig`.
|
||||
|
||||
## Configuration example
|
||||
|
||||
```javascript
|
||||
const { defineConfig } = require('@meteorjs/rspack');
|
||||
const { rspack } = require('@rspack/core');
|
||||
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
plugins: [
|
||||
Meteor.isClient && new rspack.ProvidePlugin({ _: 'lodash' }),
|
||||
new rspack.ProgressPlugin(),
|
||||
].filter(Boolean),
|
||||
}));
|
||||
```
|
||||
|
||||
## Flags on the `Meteor` parameter
|
||||
|
||||
| Flag | Type | Meaning |
|
||||
|------------------|---------|------------------------------------------------------|
|
||||
| `isDevelopment` | boolean | dev mode |
|
||||
| `isProduction` | boolean | prod mode |
|
||||
| `isClient` | boolean | building client code |
|
||||
| `isServer` | boolean | building server code |
|
||||
| `isTest` | boolean | test mode |
|
||||
| `isDebug` | boolean | debug mode |
|
||||
| `isRun` | boolean | `meteor run` |
|
||||
| `isBuild` | boolean | `meteor build` |
|
||||
| `swcConfigOptions` | object | project-level SWC config (reuse in custom loaders) |
|
||||
| `assetsContext` | string | name of the build-assets folder |
|
||||
| `chunksContext` | string | name of the build-chunks folder |
|
||||
|
||||
## Helpers
|
||||
|
||||
### `extendConfig`
|
||||
|
||||
Deep-merge reusable or conditional Rspack configuration fragments without
|
||||
replacing sibling nested keys:
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
...Meteor.extendConfig(
|
||||
{ resolve: { alias: { '@ui': '/imports/ui' } } },
|
||||
Meteor.isClient ? { module: { rules: [clientRule] } } : {},
|
||||
),
|
||||
}));
|
||||
```
|
||||
|
||||
Use direct properties for one small config. Use `extendConfig` when composing
|
||||
multiple nested fragments or presets. Inspect verbose final config to confirm
|
||||
the merge result.
|
||||
|
||||
### `extendSwcConfig` and `replaceSwcConfig`
|
||||
|
||||
Both apply only to app code (Meteor packages keep their own SWC config).
|
||||
`extendSwcConfig` exists in Meteor 3.4+. `replaceSwcConfig` requires Meteor
|
||||
3.4.1+ and `@meteorjs/rspack` v2.
|
||||
|
||||
```javascript
|
||||
// Smart-merge custom options onto Meteor's SWC defaults
|
||||
...Meteor.extendSwcConfig({
|
||||
jsc: { parser: { decorators: true } },
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Replace Meteor's SWC config entirely. You own React-refresh, helpers, etc.
|
||||
...Meteor.replaceSwcConfig({
|
||||
jsc: {
|
||||
parser: { syntax: 'typescript', tsx: true, decorators: true },
|
||||
target: 'es2020',
|
||||
transform: { react: { runtime: 'automatic' } },
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Prefer `extendSwcConfig`. `replaceSwcConfig` requires re-supplying React
|
||||
refresh, external-helpers, etc. that Meteor sets up via `Meteor.swcConfigOptions`.
|
||||
|
||||
### `compileWithRspack` / `compileWithMeteor`
|
||||
|
||||
Routes specific npm deps to one bundler or the other.
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
// Force Rspack/SWC to recompile a modern or local package
|
||||
...Meteor.compileWithRspack(['grubba-rpc']),
|
||||
// ES5 target for one dep
|
||||
...Meteor.compileWithRspack(['zod'], { jsc: { target: 'es5' } }),
|
||||
// Mark deps as externals so Meteor/Node load them at runtime
|
||||
...(Meteor.isServer ? Meteor.compileWithMeteor(['sharp']) : {}),
|
||||
}));
|
||||
```
|
||||
|
||||
Use `compileWithMeteor` for:
|
||||
|
||||
- Native or binary deps (e.g. `sharp`).
|
||||
- Atmosphere-package internals.
|
||||
- `thread-stream` and similar worker-loading dependencies reached through
|
||||
logging stacks such as `pino`. Fix
|
||||
`Cannot find module '/_build/main-dev/lib/worker.js'` by adding
|
||||
`thread-stream` to `compileWithMeteor`.
|
||||
|
||||
### `splitVendorChunk`
|
||||
|
||||
Splits `node_modules` into a stable `vendor` chunk to avoid duplicating
|
||||
shared deps across async chunks.
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
...Meteor.splitVendorChunk(),
|
||||
}));
|
||||
```
|
||||
|
||||
For finer control, drop the helper and use Rspack's official
|
||||
`splitChunksPlugin` config.
|
||||
|
||||
### `persistDevFiles` (Meteor 3.4.1+)
|
||||
|
||||
Rspack dev server keeps build output in memory. If Meteor's web server has
|
||||
to serve a file (e.g. a Workbox-generated `sw.js`), persist it.
|
||||
|
||||
```javascript
|
||||
// every rebuild
|
||||
...Meteor.persistDevFiles(['manifest.json'])
|
||||
|
||||
// or split strategies
|
||||
...Meteor.persistDevFiles({
|
||||
once: ['sw.js'], // first build only; rewriting re-registers SW
|
||||
always: ['manifest.json'],
|
||||
})
|
||||
```
|
||||
|
||||
Matchers: strings (`endsWith`), RegExp, or functions. HTML files persist
|
||||
unconditionally.
|
||||
|
||||
| Strategy | When |
|
||||
|----------|---------------------------------------|
|
||||
| `always` | every build. Default for array form. |
|
||||
| `once` | first build only. Use for service workers and any file whose rewrite would cascade a full reload. |
|
||||
|
||||
### `setCache`
|
||||
|
||||
```javascript
|
||||
...Meteor.setCache(false) // disable
|
||||
...Meteor.setCache('memory') // in-memory only
|
||||
// default: persistent
|
||||
```
|
||||
|
||||
Disable only when investigating Rspack cache bugs or OOM. Persistent is
|
||||
the rebuild-speed default.
|
||||
|
||||
On `@meteorjs/rspack@2.2.0` (Meteor 3.5.2), a TypeScript config and its
|
||||
resolvable relative local imports participate in persistent-cache dependency
|
||||
tracking. Literal static imports, `import('./local')`, re-exports, and
|
||||
`require('./local')` are detected. This does not promise tracking of computed
|
||||
paths, arbitrary aliases, or modules outside the app. Older integrations may
|
||||
miss TypeScript dependencies; upgrade before retaining a cache workaround.
|
||||
|
||||
If a config edit appears stale, inspect the resolved config/import paths and
|
||||
rebuild first. Clear only a confirmed stale Rspack cache; use the recovery flow
|
||||
in `migrate-to-rspack` instead of disabling caching permanently.
|
||||
|
||||
### `disablePlugins`
|
||||
|
||||
Match by constructor name string, RegExp, or predicate.
|
||||
|
||||
```javascript
|
||||
...Meteor.disablePlugins([
|
||||
'DefinePlugin',
|
||||
/Html/i,
|
||||
p => p?.constructor?.name === 'CustomConsoleLogPlugin',
|
||||
])
|
||||
```
|
||||
|
||||
### `enablePortableBuild` (Meteor 3.4.1+)
|
||||
|
||||
Default: `Meteor.isDevelopment` and `Meteor.isProduction` are replaced at
|
||||
build time, enabling dead-code elimination of dev-only blocks.
|
||||
|
||||
```javascript
|
||||
...Meteor.enablePortableBuild()
|
||||
```
|
||||
|
||||
Keeps both as runtime checks. Bundle gets larger; dev/prod branches both
|
||||
ship. Use only when one bundle must run in both environments without
|
||||
rebuilding.
|
||||
|
||||
`Meteor.isClient`, `Meteor.isServer`, `Meteor.isTest` are always replaced
|
||||
at build time regardless of this flag.
|
||||
|
||||
## Custom `HtmlRspackPlugin`
|
||||
|
||||
Replace or extend the default plugin to inject `<meta>` tags, CSP, etc.
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
plugins: [
|
||||
Meteor.HtmlRspackPlugin({
|
||||
meta: {
|
||||
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
|
||||
'theme-color': '#4285f4',
|
||||
},
|
||||
}),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
A `client/main.html` (or whatever the entry folder uses) still applies
|
||||
customizations through Meteor's HTML pipeline.
|
||||
|
||||
## Dev server port
|
||||
|
||||
`rspack.config.js`'s `devServer.port` is reserved. Use the env var:
|
||||
|
||||
```bash
|
||||
RSPACK_DEVSERVER_PORT=3232 meteor run
|
||||
```
|
||||
|
||||
Meteor manages the Rspack dev server so it can coordinate with Meteor's
|
||||
own server; the port must be passed through env so both processes agree.
|
||||
|
||||
## Logging knobs
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
stats: 'detailed',
|
||||
infrastructureLogging: { level: 'info' },
|
||||
}));
|
||||
```
|
||||
|
||||
`stats` controls bundle info per compilation. `infrastructureLogging.level`
|
||||
controls HMR verbosity in terminal and browser; off by default.
|
||||
|
||||
To see the final config Meteor produces, enable
|
||||
`"meteor": { "modern": { "verbose": true } }` in `package.json`.
|
||||
|
||||
## Reserved config keys
|
||||
|
||||
Rspack `entry` and `output` are owned by the integration. Overriding them
|
||||
triggers warnings. Everything else is fair game.
|
||||
|
||||
## Reserved build folders
|
||||
|
||||
Do not edit:
|
||||
|
||||
- `_build/*`: Rspack entry, intermediate app, overridden Meteor entry.
|
||||
- `public/build-assets/*`, `private/build-assets/*`: built static assets.
|
||||
- `public/build-chunks/*`: dynamic-import code splits.
|
||||
|
||||
Meteor 3.5.2 adds `-test` and `-app-test` asset/chunk contexts; a
|
||||
`METEOR_LOCAL_DIR` basename can also suffix contexts. Include actual generated
|
||||
variants in external formatter, linter, test, and IDE ignores. Keep the active
|
||||
build handoff visible to Meteor itself.
|
||||
|
||||
Auto-added to `.gitignore`. To rename, set in `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"buildContext": "build",
|
||||
"assetsContext": "assets",
|
||||
"chunksContext": "chunks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
@@ -1,74 +0,0 @@
|
||||
# Scaffolds and service workers
|
||||
|
||||
Choose framework, workspace layout and offline requirements separately.
|
||||
Inspect the app's release, resolved packages, lockfile and existing worker.
|
||||
Enabling `meteor.modern` or adding Rspack does not itself make an app a PWA.
|
||||
|
||||
## Choose a starting point
|
||||
|
||||
These starters are documented for `3.6-beta.0`. Check the selected release's
|
||||
[CLI documentation](https://docs.meteor.com/cli/#meteorcreate) and generated
|
||||
files rather than treating this as an exhaustive compatibility matrix.
|
||||
|
||||
| Need | Starting point | Follow-through |
|
||||
|---|---|---|
|
||||
| React or React/TypeScript | `--react` (default), `--typescript` | `meteor-react`; see CLI docs for Tailwind, Chakra UI and Apollo variants. |
|
||||
| Blaze | `--blaze` | `meteor-blaze` |
|
||||
| Other frameworks | `--vue`, `--svelte`, `--solid`, or the documented alternative | Preserve the chosen framework; inspect its entries and loaders. |
|
||||
| pnpm workspace | Meteor 3.6+: `--pnpm` | [Workspace ownership](meteor-3.6-workspaces.md); app at `apps/app`, shared packages under `packages/`. |
|
||||
| New Blaze PWA | Meteor 3.6+: `--pwa` | `meteor-blaze`, `references/pwa-scaffold.md`: dependency-free worker, manifest, offline page. |
|
||||
| Existing app | Keep the app and worker | `migrate-to-rspack` when changing bundlers or upgrading Rspack 1 to 2. |
|
||||
|
||||
Starter flags are not composable feature switches. `--pnpm` does not add
|
||||
offline support; `--pwa` is not a React/workspace modifier. Smaller starters
|
||||
such as `--minimal` may omit Rspack. `meteor create --list` lists examples,
|
||||
not skeleton flags. Never scaffold over an existing app.
|
||||
|
||||
Meteor 3.5.2 and earlier do not have these new `--pnpm`/`--pwa` starters.
|
||||
Keep existing/manual workspace and worker setups when the release must stay
|
||||
pinned; pnpm and PWA support themselves are not exclusive to 3.6.
|
||||
|
||||
## Framework-neutral PWA build setup
|
||||
|
||||
Workbox and app-owned workers are framework-neutral. Preserve a working
|
||||
implementation and verify the installed plugin's Rspack compatibility.
|
||||
|
||||
For Meteor 3.4.1+ with `@meteorjs/rspack` v2 or a later release-paired
|
||||
integration, follow Meteor's
|
||||
[service-worker guidance](https://docs.meteor.com/about/modern-build-stack/rspack-bundler-integration#service-worker)
|
||||
for client-only `GenerateSW`, runtime caching of app bundles and network-only
|
||||
HMR updates. Adapt asset/chunk matching and caching to the app.
|
||||
|
||||
For a custom generated worker filename, use
|
||||
[`persistDevFiles`](rspack-config.md#persistdevfiles-meteor-341) with the
|
||||
`once` strategy; default `sw.js` is already handled. Rewriting workers on each
|
||||
rebuild can defeat HMR. Production output is written normally. On Meteor
|
||||
3.4.0/v1, retain tested direct configuration; do not install another integration
|
||||
major just to obtain the helper.
|
||||
|
||||
Check HTTPS/localhost, registration, manifest URLs and the `ROOT_URL` prefix.
|
||||
Do not cache HMR/DDP traffic or private responses indiscriminately; clean up
|
||||
only owned caches. A root `/sw.js` can use narrower scope `/portal/`; broader
|
||||
than the script directory requires `Service-Worker-Allowed`. See the browser
|
||||
[scope rules](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register#scope)
|
||||
before moving a worker or rewriting a working scaffold's prefix.
|
||||
|
||||
## Notes Offline: two separate offline layers
|
||||
|
||||
[Notes Offline at the reviewed examples PR #50 revision](https://github.com/meteor/examples/tree/a7f001d3479a6f9088c80fe1016829385e74bfda/notes-offline)
|
||||
uses React and Workbox for worker/asset caching, plus `jam:offline` and
|
||||
`jam:method` for data persistence and replay. It is an example, not a universal
|
||||
cache configuration or an automatically added Meteor 3.6 capability.
|
||||
|
||||
Use `meteor-community-packages` and its `references/offline.md` for
|
||||
selective persistence, replay and logout cleanup. A worker does not provide
|
||||
those data semantics; IndexedDB alone does not load the shell offline.
|
||||
|
||||
Validate development/HMR and the production build under the real URL prefix:
|
||||
offline reload, uncached routes/chunks, worker/app updates, reconnection and
|
||||
account changes. Test data replay separately. Startup is not offline evidence.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/community-packages/offline.md
|
||||
@@ -1,186 +0,0 @@
|
||||
---
|
||||
name: meteor-mongo-minimongo
|
||||
description: >
|
||||
Use when authoring or debugging Mongo queries in Meteor 3. Triggers on
|
||||
Mongo.Collection, find/findOne, server async vs client Minimongo sync,
|
||||
oplog vs change streams, indexes, selectors, modifiers, projections.
|
||||
Use this skill when the user asks about Mongo on the server or asks about
|
||||
Minimongo on the client.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: data
|
||||
tagline: "Write and debug Mongo queries in Meteor 3 (server async vs Minimongo, oplog vs change streams, indexes, selectors, modifiers)."
|
||||
bundle: ["essentials", "fullstack"]
|
||||
docs_synced_at: "2026-09-08"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Mongo and Minimongo
|
||||
|
||||
Meteor ships two implementations of the Mongo API in one codebase. The server
|
||||
talks to MongoDB through an async driver. The client runs Minimongo, an
|
||||
in-memory synchronous Mongo emulator that holds the documents that
|
||||
subscriptions have shipped.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Where does this code run?
|
||||
- Server-only: use `await Collection.*Async(...)`.
|
||||
- Client-only: use `Collection.*(...)` synchronously.
|
||||
- Isomorphic (`import` in shared code): use `await Collection.*Async(...)`.
|
||||
On the client the work is local but still Promise-based; on the server it
|
||||
talks to Mongo.
|
||||
2. Does the query select more than a page of documents? Add `{ limit, skip }`
|
||||
and an index that matches the selector.
|
||||
3. Are you reading from a publication on the client? Use `find().fetch()`
|
||||
(sync) without `await`. The data is already local.
|
||||
|
||||
## Server reads
|
||||
|
||||
```javascript
|
||||
const doc = await Posts.findOneAsync(id);
|
||||
const list = await Posts.find({ ownerId }, {
|
||||
fields: { title: 1 }, sort: { createdAt: -1 }, limit: 50,
|
||||
}).fetchAsync();
|
||||
const count = await Posts.find({ ownerId }).countAsync();
|
||||
```
|
||||
|
||||
## Server writes
|
||||
|
||||
```javascript
|
||||
const _id = await Posts.insertAsync({ title, ownerId });
|
||||
await Posts.updateAsync({ _id }, { $set: { title } });
|
||||
await Posts.removeAsync({ _id });
|
||||
```
|
||||
|
||||
## Client reads (Minimongo)
|
||||
|
||||
The async API is isomorphic. Prefer it in shared code so the same line works
|
||||
on the server.
|
||||
|
||||
```javascript
|
||||
const doc = await Posts.findOneAsync(id); // works in shared/client/server
|
||||
const list = await Posts.find({ ownerId }).fetchAsync();
|
||||
```
|
||||
|
||||
On the client, the operation reads in-memory Minimongo but the async API still
|
||||
returns a real Promise. Code after `await` resumes in a later microtask. The
|
||||
sync API also works client-side, but only there:
|
||||
|
||||
```javascript
|
||||
const doc = Posts.findOne(id); // client-only
|
||||
const list = Posts.find({ ownerId }).fetch(); // client-only
|
||||
```
|
||||
|
||||
Pick sync when the calling scope is naturally sync and forcing `await`
|
||||
would cascade async into a render path. Common cases:
|
||||
|
||||
- React render functions and hooks that consume reactive data.
|
||||
- Blaze template helpers.
|
||||
- Tracker autoruns.
|
||||
|
||||
Pick async (`findOneAsync`, `fetchAsync`) when the file might also run on
|
||||
the server, or the containing function is already `async`.
|
||||
|
||||
## Indexes
|
||||
|
||||
Indexes are server-side. Create them on app startup:
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Posts } from "/imports/api/posts";
|
||||
|
||||
Meteor.startup(async () => {
|
||||
await Posts.createIndexAsync({ ownerId: 1, createdAt: -1 });
|
||||
await Posts.createIndexAsync({ slug: 1 }, { unique: true });
|
||||
});
|
||||
```
|
||||
|
||||
Choose compound-index key order from equality filters, sort fields, range
|
||||
filters, and usable index prefixes. The JavaScript property order in an
|
||||
equality selector does not have to match the index. Verify the chosen plan in
|
||||
the Mongo shell (`meteor mongo`) with
|
||||
`db.posts.find(...).explain("executionStats")`.
|
||||
|
||||
## Reactivity source: oplog or change streams
|
||||
|
||||
The core driver boundary is release-specific:
|
||||
|
||||
| Meteor | Reactive behavior |
|
||||
|---|---|
|
||||
| 3.0 through 3.4 | Uses oplog when `MONGO_OPLOG_URL` is configured; otherwise polling. Core change streams and reactivity-order settings are unavailable. |
|
||||
| 3.5+ | Chooses a driver per query in the default order below. |
|
||||
|
||||
Meteor 3.5+ defaults to:
|
||||
|
||||
```text
|
||||
changeStreams -> oplog -> polling
|
||||
```
|
||||
|
||||
Change streams require MongoDB 6+ on a replica set or sharded cluster, an
|
||||
unordered observer, no `skip` or `limit`, and a selector Minimongo can compile.
|
||||
An ineligible query falls through to the next configured driver. Oplog is
|
||||
available only when `MONGO_OPLOG_URL` is configured.
|
||||
|
||||
On Meteor 3.5+, override the app-wide order with
|
||||
`METEOR_REACTIVITY_ORDER=oplog,polling` or:
|
||||
|
||||
```json
|
||||
{
|
||||
"packages": {
|
||||
"mongo": {
|
||||
"reactivity": ["oplog", "polling"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
On Meteor 3.5+, the `disable-oplog` package removes only the oplog step. It
|
||||
does not disable change streams. Use `reactivity: ["polling"]` to force
|
||||
polling. On Meteor 3.0 through 3.4, do not add these settings; upgrade first.
|
||||
|
||||
For duplicate observer events or intermittent login disconnects under core
|
||||
change streams, check the resolved `mongo` version before rewriting queries or
|
||||
disabling reactivity. `mongo@2.5.1` (Meteor 3.5.2) fixes replay of events already
|
||||
covered by a causal primary snapshot. Earlier 3.5 packages lack that fix;
|
||||
upgrade and rerun the failing sequence. This does not change driver eligibility
|
||||
or justify dropping arbitrary application events by timestamp. Capture observer
|
||||
ordering if the problem persists; use `meteor-debugging` for an unknown cause.
|
||||
|
||||
## Collation (Meteor 3.5+)
|
||||
|
||||
Use `collation` for locale-aware or case-insensitive selectors and sorting on
|
||||
both Mongo and Minimongo. Back the server query with an index created using
|
||||
the same collation:
|
||||
|
||||
```javascript
|
||||
const collation = { locale: "en", strength: 2 };
|
||||
const users = await Users.find(
|
||||
{ email: "Alice@Example.COM" },
|
||||
{ collation },
|
||||
).fetchAsync();
|
||||
|
||||
await Users.createIndexAsync({ email: 1 }, { collation });
|
||||
```
|
||||
|
||||
Minimongo supports `locale`, strength 1 through 3, `caseLevel`,
|
||||
`numericOrdering`, and `caseFirst`. Other Mongo collation options are
|
||||
server-only and are ignored by Minimongo.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Use sync Mongo on the server. Removed in Meteor 3.
|
||||
- Use sync Mongo (`findOne`, `insert`, `update`, `remove`) in shared code.
|
||||
Breaks the moment the file is imported on the server.
|
||||
- Unbounded `find` on the server. Always `limit`.
|
||||
- Forget `fields` projection when publishing. Always project.
|
||||
- Assume the async Minimongo API resumes inline. It returns a Promise even
|
||||
though the underlying read is local.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/server-vs-client.md`
|
||||
- `references/selectors-modifiers.md`
|
||||
- `references/eval-cases.md`
|
||||
@@ -1,102 +0,0 @@
|
||||
# Evaluation cases for `meteor-mongo-minimongo`
|
||||
|
||||
## Case 1: server-side find rewrite
|
||||
|
||||
Prompt: "This used to work in Meteor 2 on the server:
|
||||
|
||||
```
|
||||
const post = Posts.findOne({ slug });
|
||||
```
|
||||
|
||||
Now it returns undefined. Fix it."
|
||||
|
||||
Pass if the agent rewrites to `await Posts.findOneAsync({ slug })` and marks
|
||||
the caller async.
|
||||
|
||||
## Case 2: missing index
|
||||
|
||||
Prompt: "My `Posts.find({ ownerId, archived: false }, { sort: { createdAt:
|
||||
-1 } })` query is slow. Suggest an index."
|
||||
|
||||
Pass if the agent suggests `{ ownerId: 1, archived: 1, createdAt: -1 }` (or
|
||||
calls out that `archived` could be omitted if filtering is rare).
|
||||
|
||||
## Case 3: Minimongo on client
|
||||
|
||||
Prompt: "My component is client-only. Which Mongo API should I use:
|
||||
`Posts.findOne(id)` or `await Posts.findOneAsync(id)`?"
|
||||
|
||||
Pass if the agent says both work on the client and picks based on the
|
||||
calling scope:
|
||||
|
||||
- Async (`findOneAsync`) when the file might ever be imported in
|
||||
shared/server code, or the containing function is already async.
|
||||
- Sync (`findOne`) when the scope is naturally sync (React render, Blaze
|
||||
helper, Tracker computation) and forcing `await` would cascade an async
|
||||
migration through the component tree for no real gain.
|
||||
|
||||
The sync API exists for exactly that case; using it deliberately is not a
|
||||
mistake. Fail if the agent claims that an async Minimongo Promise resolves
|
||||
inline or synchronously; only the underlying data access is local.
|
||||
|
||||
## Case 4: leaking columns
|
||||
|
||||
Prompt: "My subscription includes the `passwordHash` field. I never wanted
|
||||
that to reach the client. What did I do wrong?"
|
||||
|
||||
Pass if the agent identifies missing `fields` projection in the publication
|
||||
and proposes a `fields: { title: 1, ... }` allow-list.
|
||||
|
||||
## Case 5: Meteor 3.5 reactivity driver
|
||||
|
||||
Prompt: "After upgrading to Meteor 3.5, is oplog still the default for every
|
||||
reactive Mongo query? How can I force the old order?"
|
||||
|
||||
Pass if the agent gives the default `changeStreams`, `oplog`, `polling` order,
|
||||
lists the main change-stream eligibility requirements, and uses either
|
||||
`METEOR_REACTIVITY_ORDER=oplog,polling` or the equivalent
|
||||
`packages.mongo.reactivity` setting. It must not claim that `disable-oplog`
|
||||
also disables change streams.
|
||||
|
||||
## Case 6: case-insensitive email lookup
|
||||
|
||||
Prompt: "On Meteor 3.5, query email addresses case-insensitively on both the
|
||||
client and server without lowercasing stored values."
|
||||
|
||||
Pass if the agent uses `{ collation: { locale: "en", strength: 2 } }` on the
|
||||
query and creates the server index with the same collation. It should mention
|
||||
that only a subset of Mongo collation options is supported by Minimongo.
|
||||
|
||||
## Case 7: change streams requested before Meteor 3.5
|
||||
|
||||
Prompt: "My app is fixed on Meteor 3.4.1 and uses Atlas. Configure core
|
||||
`changeStreams,oplog,polling` reactivity with `METEOR_REACTIVITY_ORDER`."
|
||||
|
||||
Pass if the agent says core change streams and reactivity-order configuration
|
||||
begin in Meteor 3.5, explains that 3.4.1 uses oplog only with
|
||||
`MONGO_OPLOG_URL` and otherwise polling, and requires an upgrade before using
|
||||
the requested core driver. Fail if it assumes Atlas implies core change-stream
|
||||
support on every Meteor 3 release.
|
||||
|
||||
## Case 8: selector property order and compound index
|
||||
|
||||
Prompt: "My index is `{ ownerId: 1, archived: 1, createdAt: -1 }`, but the
|
||||
query object is `{ archived: false, ownerId }`. Must I reorder its JavaScript
|
||||
properties before Mongo can use the index?"
|
||||
|
||||
Pass if the agent says equality selector property order need not mirror the
|
||||
compound index, checks index prefixes and equality-sort-range behavior, and
|
||||
uses `explain('executionStats')` to verify the plan. Fail if it treats object
|
||||
property order as an index-eligibility rule.
|
||||
|
||||
## Case 9: change-stream replay during login
|
||||
|
||||
Prompt: "On Meteor 3.5.1, observer traces show an event already represented by
|
||||
the initial primary snapshot replaying and triggering intermittent login
|
||||
disconnects. Should I drop old events in application code or force polling?"
|
||||
|
||||
Pass if the agent checks the `mongo@2.5.1` fix shipped with 3.5.2, proposes a
|
||||
compatible upgrade and reruns the reproduction before a permanent workaround.
|
||||
It preserves driver eligibility/fallback rules and does not claim every
|
||||
disconnect has this cause. Fail if it drops arbitrary events by timestamp or
|
||||
disables change streams without evaluating the release fix.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Selectors, modifiers, sort and field specifiers
|
||||
|
||||
## Selectors
|
||||
|
||||
```javascript
|
||||
{ ownerId: userId } // equality
|
||||
{ qty: { $gt: 0 } } // operators
|
||||
{ tags: { $in: ["a", "b"] } }
|
||||
{ $or: [{ qty: 0 }, { archived: true }] }
|
||||
{ "address.city": "Berlin" } // dotted path
|
||||
```
|
||||
|
||||
## Modifiers
|
||||
|
||||
```javascript
|
||||
{ $set: { title } }
|
||||
{ $inc: { qty: 1 } }
|
||||
{ $push: { tags: "new" } }
|
||||
{ $addToSet: { tags: "new" } }
|
||||
{ $pull: { tags: "old" } }
|
||||
{ $unset: { archived: 1 } }
|
||||
```
|
||||
|
||||
## Sort specifiers
|
||||
|
||||
```javascript
|
||||
{ sort: { createdAt: -1 } }
|
||||
{ sort: [["score", "desc"], ["createdAt", "asc"]] }
|
||||
```
|
||||
|
||||
## Field specifiers
|
||||
|
||||
Always project. Returning a whole document leaks columns.
|
||||
|
||||
```javascript
|
||||
{ fields: { title: 1, qty: 1 } } // include only these
|
||||
{ fields: { secretToken: 0 } } // exclude this; everything else included
|
||||
```
|
||||
|
||||
Mixing `1`s and `0`s in one specifier is invalid except for `_id`.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/collections.md#selectors
|
||||
@@ -1,22 +0,0 @@
|
||||
# Server Mongo vs client Minimongo
|
||||
|
||||
| Aspect | Server (Mongo, async) | Client (Minimongo, sync) |
|
||||
|--------------------|-----------------------------------|---------------------------------|
|
||||
| Read one | `await c.findOneAsync(id)` | `c.findOne(id)` |
|
||||
| Read many | `await c.find(q).fetchAsync()` | `c.find(q).fetch()` |
|
||||
| Count | `await c.find(q).countAsync()` | `c.find(q).count()` |
|
||||
| Insert | `await c.insertAsync(d)` | `c.insert(d)` (inside stub only)|
|
||||
| Update | `await c.updateAsync(q, m)` | `c.update(q, m)` (stub only) |
|
||||
| Remove | `await c.removeAsync(q)` | `c.remove(q)` (stub only) |
|
||||
| Index | `await c.createIndexAsync(...)` | not applicable |
|
||||
|
||||
Isomorphic code runs on both sides. Use the async API throughout; on the
|
||||
client the lookup is local but remains Promise-based, so code after `await`
|
||||
resumes in a later microtask.
|
||||
|
||||
To explain a query, use the Mongo shell (`meteor mongo`) and run
|
||||
`db.<collection>.find(...).explain("executionStats")`. Meteor does not
|
||||
expose a `Cursor#explain` on the collection API.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/collections.md
|
||||
@@ -1,87 +0,0 @@
|
||||
---
|
||||
name: meteor-native
|
||||
description: >
|
||||
Use when building or maintaining Meteor 3 Android/iOS apps through Cordova.
|
||||
Triggers on meteor add-platform, android-device, ios-device, mobile-config.js,
|
||||
Cordova plugins, native signing or store artifacts, and mobile hot code push
|
||||
compatibility. Use this skill when the task already concerns Meteor's
|
||||
Cordova app workflow; use meteor-debugging for an unexplained cross-layer
|
||||
failure and meteor-deployment for the backend. React Native/Expo, Capacitor,
|
||||
and native Node.js addons are separate workflows.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: workflow
|
||||
meteor: ">=3.0"
|
||||
area: build
|
||||
tagline: "Build and maintain Meteor 3 Cordova apps for Android and iOS, including plugins, native artifacts, and hot code push."
|
||||
docs_synced_at: "2026-09-08"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor native apps
|
||||
|
||||
Turn the existing Meteor application into a reproducible Cordova build and
|
||||
verify the requested device or distribution behavior. Meteor manages the web
|
||||
bundle, Cordova project and platform versions; Android Studio and Xcode provide
|
||||
native debugging, signing and distribution tools.
|
||||
|
||||
## Choose the workflow
|
||||
|
||||
1. Read `.meteor/release`, `.meteor/platforms`, `.meteor/cordova-plugins`,
|
||||
`.meteor/versions`, `package.json`, and `mobile-config.js` when present.
|
||||
Record host OS, target device/platform, installed native binary version,
|
||||
and whether the task needs a development run, web update, or new binary.
|
||||
2. Match prerequisites to the selected Meteor release and resolved Cordova
|
||||
platform. Meteor 3.5.2 uses `cordova-lib@13.0.0`,
|
||||
`cordova-android@15.1.0`, and `cordova-ios@7.1.1`; earlier releases have
|
||||
different pins. Do not select the newest standalone Cordova platform
|
||||
merely because it is available.
|
||||
3. Choose the relevant reference below. Keep durable changes in the app's
|
||||
platform/plugin declarations, configuration and assets; inspect generated
|
||||
native output to verify what Meteor actually produced.
|
||||
4. Rebuild/reinstall when native plugins, platform versions, permissions or
|
||||
native configuration change. HCP can update compatible web code/assets;
|
||||
it cannot supply missing native code or change installed binary metadata.
|
||||
5. Verify on the target emulator/device or inspect the requested artifact.
|
||||
Record command, versions, endpoint and observable result. A successful web
|
||||
build alone does not validate a native app or a signed store artifact.
|
||||
|
||||
| Task | Read |
|
||||
|---|---|
|
||||
| Set up Android/iOS, add/remove platforms, run a device, choose WebView compatibility | [Toolchain and development](references/toolchain-and-development.md) |
|
||||
| Change app metadata/assets, native preferences, access rules, plugins, permissions or build overrides | [Configuration and plugins](references/configuration-and-plugins.md) |
|
||||
| Build Android artifacts or an iOS project, configure signing and prepare distribution | [Build and distribution](references/build-and-distribution.md) |
|
||||
| Repair mobile update delivery, compatibility rejection, download or reload behavior | [Hot code push](references/hot-code-push.md) |
|
||||
|
||||
## Persistent state and runtime boundaries
|
||||
|
||||
- `.meteor/local/cordova-build/` is generated by default. If
|
||||
`METEOR_LOCAL_DIR` is set, resolve the actual local directory before opening
|
||||
or clearing its `cordova-build` child. Do not erase the whole local state
|
||||
or local Mongo database to repair a Cordova cache.
|
||||
- `mobile-config.js` is a build-time configuration file, not an application
|
||||
module. `App.configurePlugin` supplies installation variables; it neither
|
||||
installs a plugin nor runs its JavaScript API.
|
||||
- Call native plugin APIs from client code guarded by `Meteor.isCordova`,
|
||||
inside `Meteor.startup` or after equivalent device readiness. Meteor's
|
||||
Cordova startup waits for `deviceready`; browser/server code must retain a
|
||||
suitable fallback. Startup does not grant OS permissions automatically.
|
||||
- A physical device's `localhost` is the device. Match `--mobile-server`
|
||||
during development and `meteor build --server` for distribution to a
|
||||
reachable endpoint. The embedded WebView's local content server is separate
|
||||
from the Meteor backend and DDP connection.
|
||||
|
||||
## Neighboring workflows
|
||||
|
||||
| Request | Owner |
|
||||
|---|---|
|
||||
| Unknown crash, stuck data, or failure not yet isolated to native behavior | `meteor-debugging`, then return with the confirmed native boundary |
|
||||
| Host the backend, configure Galaxy/Docker, deploy server changes, preserve the HCP client bundle | `meteor-deployment` |
|
||||
| Rspack/SWC/module graph or a native npm addon such as `sharp` | `meteor-modern-build-stack` or `migrate-to-rspack` |
|
||||
| OAuth provider/login behavior | `meteor-accounts`; use this skill for required Cordova plugin or native configuration |
|
||||
| Explicit React Native/Expo or Capacitor app | Keep the chosen stack; this skill does not implement those integrations |
|
||||
|
||||
## Acceptance
|
||||
|
||||
Use [evaluation cases](references/eval-cases.md) to check native decisions,
|
||||
earlier-release behavior, and neighboring-skill routing.
|
||||
@@ -1,88 +0,0 @@
|
||||
# Build and distribution
|
||||
|
||||
## Choose the native output and backend
|
||||
|
||||
Confirm the added platforms, host OS, app identity/version, installed native
|
||||
platforms/plugins, production endpoint and intended distribution channel.
|
||||
Use an output directory outside the app source and inspect existing contents
|
||||
before choosing a location that the build may replace.
|
||||
|
||||
```bash
|
||||
meteor build ../build-output --server=https://app.example.com
|
||||
```
|
||||
|
||||
Native builds require an explicit `--server` when building an added native
|
||||
platform. Do not rely on the CLI documentation's localhost default. Match the
|
||||
URL to the deployed backend's public `ROOT_URL` and account for any explicitly
|
||||
separate DDP URL. A build-time `DDP_DEFAULT_CONNECTION_URL` overrides the
|
||||
native DDP endpoint; changing a server environment value later does not by
|
||||
itself prove that installed clients received a new embedded configuration.
|
||||
|
||||
Use `--mobile-settings path/to/mobile-settings.json` when the native build
|
||||
needs settings. Its `public` values initialize the mobile client; configuration
|
||||
code can also read build-time `App.settings`. Inspect values intentionally
|
||||
copied into native configuration and keep server-only credentials out of
|
||||
plugin variables or assets.
|
||||
|
||||
| Command choice | Outcome |
|
||||
|---|---|
|
||||
| Default `meteor build ... --server=...` | Build the added native platforms supported by the host, plus the server/web output |
|
||||
| `--platforms=android` or `--platforms=ios` | Select an already-added native platform; does not install it or provide a missing host toolchain |
|
||||
| `--packageType=bundle` | Android AAB output; the current default |
|
||||
| `--packageType=apk` | Android APK output |
|
||||
| `--server-only` | Skip native app artifacts; retain configured client targets for HCP, including `web.cordova` when applicable |
|
||||
| `--architecture=...` | Select server bundle architecture; does not enable iOS builds on Linux or choose a phone CPU |
|
||||
|
||||
On a release where an option's meaning is uncertain, verify `meteor help
|
||||
build` for that app's Meteor tool. Preserve the `web.cordova` target on the
|
||||
backend serving installed clients; a platform-filtered browser build can
|
||||
accidentally remove the HCP bundle. Use `meteor-deployment` for hosting and
|
||||
backend rollout.
|
||||
|
||||
## Android signing and installation
|
||||
|
||||
For the example output path, open `../build-output/android/project/` in
|
||||
Android Studio. Inspect the generated AAB/APK and build log rather than
|
||||
assuming that the presence of a project directory proves a successful build
|
||||
or signing step.
|
||||
|
||||
Use the app's existing signing identity and Android Studio's signed bundle/APK
|
||||
workflow, or its established equivalent in CI. Check application ID, version
|
||||
code/name, package type, signing certificate and intended backend. Keep
|
||||
keystores/passwords out of tracked source and logs. A debug APK is not a
|
||||
release artifact, and an AAB is not directly installed with `adb install`.
|
||||
Test the appropriate APK or the distribution channel's installed build on the
|
||||
target device. Reusing the existing app identity/signing setup matters for
|
||||
updates to already installed applications.
|
||||
|
||||
## iOS archive and distribution
|
||||
|
||||
On macOS, open `../build-output/ios/project/` in Xcode, using its generated
|
||||
`.xcworkspace` when present. Meteor produces the Xcode project; it does not
|
||||
prove a signed IPA exists. Configure the existing bundle identifier, team,
|
||||
signing/provisioning and build/version values, choose the intended archive
|
||||
destination, then archive and export/distribute through Xcode or the project's
|
||||
established CI process.
|
||||
|
||||
Verify the resulting archive/export and device installation. A Linux build
|
||||
can skip iOS with a warning while other outputs succeed; report that as
|
||||
missing iOS validation, not a completed mobile release.
|
||||
|
||||
## Release verification
|
||||
|
||||
Check cold launch, target-device plugin/permission behavior, backend/DDP
|
||||
connection, and a compatible web update for each intended platform. Native
|
||||
configuration and plugin changes need a newly built and distributed binary;
|
||||
keep older installed clients compatible with the backend during rollout.
|
||||
|
||||
Record the artifact actually produced, whether it is signed and installed,
|
||||
and any unexecuted steps. Verify current Apple/Google submission requirements
|
||||
at upload time. Building, signing and uploading are distinct actions; prepare
|
||||
only the distribution steps requested by the user, using existing credentials
|
||||
and release processes where available.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/cordova.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/environment-variables.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/app.md
|
||||
@@ -1,174 +0,0 @@
|
||||
# Configuration and plugins
|
||||
|
||||
## Keep configuration in application sources
|
||||
|
||||
`mobile-config.js` belongs at the Meteor app root and executes during the
|
||||
native build. It is not imported by application startup. Preserve the app's
|
||||
existing identity and platform-specific configuration when changing one field.
|
||||
|
||||
```js
|
||||
// mobile-config.js
|
||||
App.info({
|
||||
id: 'com.example.myapp',
|
||||
name: 'My App',
|
||||
version: '1.0.0'
|
||||
});
|
||||
App.setPreference('Orientation', 'portrait', 'android');
|
||||
```
|
||||
|
||||
For `BackgroundColor`, use a supported `#` hex value, for example
|
||||
`App.setPreference('BackgroundColor', '#ffffffff')` for opaque white. Old
|
||||
examples using `0x...` caused Android build failures during Meteor 3 migrations.
|
||||
Check the failing resource/preference before treating nearby Gradle deprecation
|
||||
warnings as the cause. Preserve the intended color and the target platform's
|
||||
channel ordering. See the [confirmed 3.3.2 repair](https://forums.meteor.com/t/solved-migration-from-2-16-to-3-3-2-break-cordova-android-build/64274/2)
|
||||
and the current [configuration example](https://docs.meteor.com/api/app).
|
||||
|
||||
| Need | App-level source | Check after generation |
|
||||
|---|---|---|
|
||||
| ID, display name, version | `App.info` | Native application ID and displayed/build versions; preserve published IDs |
|
||||
| Platform preference | `App.setPreference(name, value, platform)` | Correct platform section; supported preference for the pinned platform/plugin |
|
||||
| Icons and splash images | `App.icons`, `App.launchScreens` with project-relative assets | Accepted keys, existing source images, generated resources on target devices |
|
||||
| Plugin installation variables | `App.configurePlugin(id, variables)` | Exact installed plugin ID and generated native configuration |
|
||||
| Extra XML / platform resources | `App.appendToConfig`, `App.addResourceFile(src, target, platform)` | Correct generated XML/resource target, without replacing unrelated configuration |
|
||||
| Native files outside those APIs | App-root `cordova-build-override/`, mirroring the generated Cordova project tree | Narrow override remains compatible with the selected native platform |
|
||||
|
||||
Meteor copies build overrides into the generated Cordova project. Prefer the
|
||||
configuration APIs for values they own; a whole generated `config.xml`, Gradle
|
||||
file, or project copy can mask future Meteor/platform changes. Rebuild and
|
||||
inspect output after changing native configuration. Do not treat edits under
|
||||
`.meteor/local/cordova-build` as the permanent source.
|
||||
|
||||
`App.settings` reads the build's settings file, while native client runtime
|
||||
settings use its `public` subtree. A private settings value becomes exposed
|
||||
if the build copies it into plugin variables, XML or client assets. Use
|
||||
client-appropriate identifiers in native config and keep server credentials
|
||||
on the server; do not log full settings while checking values.
|
||||
|
||||
## Network access, navigation, and OS policy
|
||||
|
||||
Choose the rule for the requested operation:
|
||||
|
||||
```js
|
||||
// mobile-config.js
|
||||
App.accessRule('https://api.example.com');
|
||||
App.accessRule('https://docs.example.com', { type: 'navigation' });
|
||||
App.accessRule('myapp:*', { type: 'intent' });
|
||||
```
|
||||
|
||||
The default rule type is network access; navigation allows the WebView to move
|
||||
to a URL; intent permits asking the OS to open it. An intent rule does not
|
||||
register an inbound deep-link handler. Native allow rules do not configure the
|
||||
remote server's CORS policy, disable CSP, grant runtime device permissions, or
|
||||
repair invalid TLS certificates. Inspect the failing layer before widening
|
||||
access, and keep rules scoped to the required destinations.
|
||||
|
||||
For local Android HTTP development, first verify the `--mobile-server` URL.
|
||||
If logs show cleartext rejection, enable the development endpoint through a
|
||||
development-specific network-security configuration or the documented
|
||||
`App.appendToConfig` manifest edit below:
|
||||
|
||||
```js
|
||||
App.appendToConfig(`<edit-config file="app/src/main/AndroidManifest.xml"
|
||||
mode="merge" target="/manifest/application"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:usesCleartextTraffic="true" />
|
||||
</edit-config>`);
|
||||
```
|
||||
|
||||
That example is an application-wide cleartext allowance, not a per-domain
|
||||
rule. Use it only in the local development build configuration; verify the
|
||||
release output excludes it and uses the intended HTTPS service. Do not add
|
||||
wildcard access or a production TLS bypass as an HCP fix.
|
||||
|
||||
## Install, configure, and call plugins
|
||||
|
||||
Use Meteor's plugin declarations. Replace the identifiers/versions below with
|
||||
the selected plugin's verified npm ID and compatible exact version:
|
||||
|
||||
```text
|
||||
meteor add cordova:PLUGIN_ID@EXACT_VERSION
|
||||
meteor remove cordova:PLUGIN_ID
|
||||
```
|
||||
|
||||
Review `.meteor/cordova-plugins` and the generated installed plugin list.
|
||||
Atmosphere packages can also declare Cordova dependencies; inspect those
|
||||
requirements if a removed plugin returns or a version is resolved differently.
|
||||
`meteor npm install` alone does not register a Cordova plugin, and
|
||||
`App.configurePlugin` only supplies its build-time variables. Consult the
|
||||
selected plugin's own docs for variables, supported platform versions,
|
||||
permission declarations, and runtime permission requests.
|
||||
|
||||
On Meteor 3.0.x, a plugin's `<dependency>` can trigger lost generated
|
||||
dependencies and `Cannot find module 'cordova-android'`. The complete tool fix
|
||||
ships in Meteor 3.1; 3.0.4's initial fix was incomplete. If the app must remain
|
||||
on an affected release, identify the actual transitive plugin in `plugin.xml`
|
||||
and declare its compatible exact version through `meteor add cordova:...`.
|
||||
For the reported `cordova-plugin-screen-orientation@3.0.4` case, that dependency
|
||||
was `es6-promise-plugin@4.2.2`. Do not add it to unrelated apps or permanently
|
||||
edit generated `package.json`. On fixed releases, diagnose the installed
|
||||
dependency graph before applying this historical workaround.
|
||||
[Resolution and workaround](https://github.com/meteor/meteor/issues/13303),
|
||||
[complete fix](https://github.com/meteor/meteor/pull/13416).
|
||||
|
||||
Native APIs belong in client code after device readiness:
|
||||
|
||||
```js
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
Meteor.startup(() => {
|
||||
if (!Meteor.isCordova) return;
|
||||
// Use the installed plugin's documented API and permission flow here.
|
||||
});
|
||||
```
|
||||
|
||||
Do not infer readiness from a timer or make browser/server startup depend on
|
||||
a Cordova global. Meteor's startup guard waits for `deviceready`, not for every
|
||||
plugin-specific asynchronous operation or permission grant.
|
||||
|
||||
If changed plugin variables are not reflected, inspect the generated config
|
||||
and installed plugin first. Stop the affected build process, preserve native
|
||||
logs and any untracked IDE work, then remove only the actual generated
|
||||
`cordova-build` directory if stale native state is confirmed. Re-run the
|
||||
Meteor build/run command. Never substitute `meteor reset --db` or deletion of
|
||||
all `.meteor/local` for this recovery.
|
||||
|
||||
## Local plugin development
|
||||
|
||||
Meteor supports `cordova:PLUGIN_ID@file://...` specifications. Quote the entire
|
||||
argument when paths contain shell-significant characters. Meteor 3.5.2 fixes
|
||||
resolution of encoded absolute file URLs and preserves existing raw paths
|
||||
with reserved characters; verify the intended directory, `plugin.xml` ID and
|
||||
generated plugin source before rebuilding. Use a real file-URL encoder for an
|
||||
absolute path, not repeated manual decoding.
|
||||
|
||||
Earlier releases can mishandle those paths. If the app must stay pinned, use
|
||||
a straightforward local path without reserved characters or an independently
|
||||
verified compatible fix. Local source edits require another `meteor run` or
|
||||
`meteor build` and a native reinstall as appropriate. Local filesystem paths
|
||||
also need to resolve in every developer/CI environment; they are not portable
|
||||
published plugin versions.
|
||||
|
||||
## Native launch and status UI
|
||||
|
||||
`meteor add mobile-experience` pulls in `mobile-status-bar` and `launch-screen`
|
||||
defaults. It has no JavaScript API of its own. Configure appearance with the
|
||||
documented App preferences/assets for the installed plugin/platform; check
|
||||
actual device behavior when Android system-bar or splash rules change.
|
||||
|
||||
To hold the splash for app readiness, use `LaunchScreen.hold()` in native
|
||||
client code before the normal release point, then call that handle's
|
||||
`release()` once the intended UI is ready. Release every acquired handle,
|
||||
including a deliberate error/fallback path; do not wait forever for an
|
||||
unavailable network resource. Guard native use with `Meteor.isCordova` rather
|
||||
than promising a browser implementation. A rendered web page is not evidence
|
||||
that the native launch screen was released.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/app.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/application-structure/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/autoupdate.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/troubleshooting/hot-code-push.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/mobile-experience.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/launch-screen.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/mobile-status-bar.md
|
||||
@@ -1,307 +0,0 @@
|
||||
# Evaluation cases for `meteor-native`
|
||||
|
||||
Run each prompt in a fresh conversation or disposable project. Keep these
|
||||
criteria hidden until the run finishes; record observable outcomes separately.
|
||||
|
||||
## Case 1: Android setup
|
||||
|
||||
Prompt: "Add Android development to our Meteor 3.5.2 app on Linux. We have JDK 17
|
||||
and SDK 35 installed, but no Android platform in .meteor/platforms yet."
|
||||
|
||||
Pass if the agent checks the app release and adds Android through Meteor, installs
|
||||
SDK Platform 36 and Build Tools 36.0.0 for the 3.5.2 baseline, verifies host paths
|
||||
and prerequisites, and proposes an emulator/device check. Fail if SDK 35 is
|
||||
treated as sufficient or a web build is claimed to validate Android.
|
||||
|
||||
## Case 2: earlier toolchain boundary
|
||||
|
||||
Prompt: "Our Meteor 3.5.1 Android branch must stay pinned. Can we copy all 3.5.2
|
||||
native prerequisites and run cordova platform add android@latest?"
|
||||
|
||||
Pass if the agent preserves Meteor 3.5.1, inspects its platform pins and
|
||||
requirements, and uses Meteor platform commands. Fail if it forces 3.5.2
|
||||
prerequisites or installs the newest standalone Cordova platform.
|
||||
|
||||
## Case 3: physical device endpoint
|
||||
|
||||
Prompt: "Our Meteor 3.5.2 Android app works in the emulator. On my USB phone, it
|
||||
starts but cannot connect. The native build uses http://localhost:3000;
|
||||
DDP_DEFAULT_CONNECTION_URL was also set during the last build."
|
||||
|
||||
Pass if the agent distinguishes device localhost from the host, chooses a
|
||||
reachable LAN endpoint, inspects the embedded DDP override, and verifies the
|
||||
regenerated native configuration. Fail if it uses the standard emulator address as
|
||||
a universal physical-device fix.
|
||||
|
||||
## Case 4: iOS build host
|
||||
|
||||
Prompt: "Our Meteor app has Android and iOS platforms. Linux CI reports build
|
||||
success but produced no IPA. Can --architecture=os.osx.arm64 create it here?"
|
||||
|
||||
Pass if the agent explains that iOS archives require macOS and Xcode and
|
||||
distinguishes server architecture from the native build host. Fail if it claims
|
||||
Linux success proves an IPA exists or that --architecture supplies Xcode.
|
||||
|
||||
## Case 5: persistent native configuration
|
||||
|
||||
Prompt: "Update our existing Meteor Cordova app's display name, splash and Android
|
||||
orientation. Keep its published app ID. My edits to generated config.xml disappear
|
||||
whenever Meteor rebuilds."
|
||||
|
||||
Pass if the agent edits app-root mobile-config.js and source assets, preserves the
|
||||
published ID, and verifies the regenerated native output. Fail if it makes durable
|
||||
changes only in generated config.xml.
|
||||
|
||||
## Case 6: plugin installation and readiness
|
||||
|
||||
Prompt: "I added App.configurePlugin for our chosen camera plugin and called its
|
||||
API at module top level. It is undefined on the phone and breaks web and server
|
||||
startup. This code is shared by all clients."
|
||||
|
||||
Pass if the agent distinguishes plugin declaration, build-time variables, client
|
||||
runtime and permission flow. It uses Meteor.isCordova with Meteor.startup or
|
||||
equivalent readiness and retains browser/server behavior. Fail if configuration
|
||||
alone installs a plugin or a timer replaces readiness.
|
||||
|
||||
## Case 7: narrow generated-state repair
|
||||
|
||||
Prompt: "We changed a Cordova plugin's install variables, but the generated config
|
||||
still has the old values. METEOR_LOCAL_DIR=.meteor/native-local and our local
|
||||
Mongo data matters. Should we delete .meteor/local and try again?"
|
||||
|
||||
Pass if the agent resolves .meteor/native-local/cordova-build, first verifies
|
||||
stale plugin state, and preserves logs and IDE changes before narrowly
|
||||
regenerating it. Fail if it deletes all local state, uses meteor reset --db, or
|
||||
targets the default directory despite METEOR_LOCAL_DIR.
|
||||
|
||||
## Case 8: local plugin paths
|
||||
|
||||
Prompt: "A local Cordova plugin lives in a directory containing spaces, # and %.
|
||||
We have an encoded file URL and a raw legacy path. How should we add it on Meteor
|
||||
3.5.2, and what about our pinned 3.5.1 maintenance branch?"
|
||||
|
||||
Pass if the agent verifies plugin identity and path encoding, explains the 3.5.2
|
||||
fix, and keeps the pinned earlier branch on a simple compatible path or verified
|
||||
fix. Fail if it repeatedly decodes a raw path, passes an unquoted shell-sensitive
|
||||
path, or promises local source changes ship without rebuilding.
|
||||
|
||||
## Case 9: network policy layers
|
||||
|
||||
Prompt: "Our Cordova client needs an HTTPS API, an embedded docs page and an
|
||||
external custom-scheme link. Local Android HCP also logs cleartext denied. Should
|
||||
we use App.accessRule('*') and disable certificate checks everywhere?"
|
||||
|
||||
Pass if the agent distinguishes access, navigation and intent rules from CORS,
|
||||
CSP, runtime permissions and TLS. Any broad Android cleartext allowance is limited
|
||||
to development and verified absent from release output. Fail if it uses wildcard
|
||||
rules or disables certificate checks as a production repair.
|
||||
|
||||
## Case 10: HCP native incompatibility
|
||||
|
||||
Prompt: "The server deploy adds a native plugin that installed clients don't have.
|
||||
Devices say the Cordova platform/plugin versions are incompatible. Can we force
|
||||
AUTOUPDATE_VERSION so everyone gets the new feature immediately?"
|
||||
|
||||
Pass if the agent requires a new binary for the missing native plugin, preserves
|
||||
backend compatibility during rollout, and rejects a blind version override. Fail
|
||||
if AUTOUPDATE_VERSION is presented as delivering missing native code.
|
||||
|
||||
## Case 11: HCP switch and CSS behavior
|
||||
|
||||
Prompt: "Our Meteor Cordova app receives a new HCP version and downloads it, but
|
||||
our custom window.location.reload() still loads old code. CSS-only deploys reload
|
||||
too. How do we diagnose this?"
|
||||
|
||||
Pass if the agent checks pending-bundle selection before custom reload, describes
|
||||
Cordova CSS updates as full client reloads, and treats custom
|
||||
WebAppLocalServer/Reload hooks as version-sensitive. Fail if a plain
|
||||
window.location.reload is assumed to activate a pending bundle or browser CSS HMR
|
||||
is promised on native production.
|
||||
|
||||
## Case 12: native release artifacts
|
||||
|
||||
Prompt: "Prepare release builds for our Meteor 3.5.2 Android/iOS app on a Mac,
|
||||
using https://app.example.com. We need an Android AAB and an iOS archive for
|
||||
review, with the existing signing identities. Do not upload yet."
|
||||
|
||||
Pass if the agent selects the requested endpoint, inspects the Android AAB and
|
||||
Xcode archive with existing app/signing identities, and distinguishes generated
|
||||
projects, signing, device installation and upload. Fail if it claims artifacts or
|
||||
signing were executed without evidence, installs an AAB with adb install, or
|
||||
uploads without authorization.
|
||||
|
||||
## Case 13: settings exposure
|
||||
|
||||
Prompt: "Can mobile-config.js read a value from our mobile settings file to
|
||||
configure a plugin? The same file has a server API secret and public app settings;
|
||||
I want to put the server secret into App.configurePlugin."
|
||||
|
||||
Pass if the agent distinguishes build-time App.settings from public client
|
||||
settings and keeps the server secret out of plugin variables, XML and assets. Fail
|
||||
if a private key is considered secret after embedding in the native app.
|
||||
|
||||
## Case 14: modern output and OS compatibility
|
||||
|
||||
Prompt: "Did Cordova's default bundle become modern in Meteor 3.3.2 or 3.4? We
|
||||
also support a pinned 3.3.1 branch. Will meteor.modern.cordova=false let our 3.5.2
|
||||
Android app run below cordova-android's minimum supported OS?"
|
||||
|
||||
Pass if the agent identifies the 3.3.2 capability/opt-out floor, retains the
|
||||
earlier legacy branch, and notes that affected default configuration must be
|
||||
verified rather than promising all 3.3.2+ tools emit modern output. It
|
||||
distinguishes JavaScript compatibility from the native platform minimum OS. Fail
|
||||
if a legacy bundle is claimed to restore unsupported device OS versions.
|
||||
|
||||
## Case 15: splash readiness
|
||||
|
||||
Prompt: "Our React-based Meteor Cordova app uses mobile-experience. We hold the
|
||||
splash until data arrives, but it stays visible offline. Can I import a mobile-
|
||||
experience API and just wait ten seconds?"
|
||||
|
||||
Pass if the agent treats mobile-experience as a package bundle and uses balanced
|
||||
LaunchScreen.hold/release behavior, including an offline fallback. Fail if it
|
||||
invents a mobile-experience API or hides missing readiness with a fixed delay.
|
||||
|
||||
## Case 16: platform removal
|
||||
|
||||
Prompt: "We are dropping iOS from this Meteor app but retaining Android and the
|
||||
web app. How do we stop Meteor generating the iOS project without losing our
|
||||
shared plugins or application data?"
|
||||
|
||||
Pass if the agent removes only iOS with meteor remove-platform ios and reviews
|
||||
platform declarations. Fail if it removes shared plugins, Android, the web app or
|
||||
local data without a separate reason.
|
||||
|
||||
## Case 17: neighboring stack exclusions
|
||||
|
||||
Prompt: "Two separate tasks: our Expo React Native app consumes a Meteor backend,
|
||||
and sharp fails in the Meteor server's Docker build. Should either task start by
|
||||
adding Meteor's Cordova Android platform?"
|
||||
|
||||
Pass if the agent preserves the Expo stack and routes the server addon/container
|
||||
failure to build or deployment guidance. Fail if it adds Cordova to either
|
||||
project.
|
||||
|
||||
## Case 18: stale HCP manifest
|
||||
|
||||
Prompt: "Our Meteor 3.2.2 iOS app updates locally but stays on the old client
|
||||
behind NGINX in production. Android updates. DDP announces the new version, but
|
||||
the public /__cordova/manifest.json GET has an old version and a cache hit; the
|
||||
origin GET has the new version. Plugins are unchanged. Fix the update path."
|
||||
|
||||
Pass if the agent diagnoses manifest caching, bypasses caching and purges stale
|
||||
content only for the affected manifest route through the deployment workflow,
|
||||
preserves hashed-asset caching, and verifies the next version reaches iOS. Fail if
|
||||
it changes compatibility hashes, TLS policy or native plugins, or disables caching
|
||||
for every asset.
|
||||
|
||||
## Case 19: fresh manifest with plugin mismatch
|
||||
|
||||
Prompt: "Our Meteor 3.5.2 iOS client downloads a fresh /__cordova/manifest.json,
|
||||
whose version matches the origin. Logs reject the update because it adds a plugin
|
||||
missing from installed clients. Should we apply the NGINX no-cache workaround?"
|
||||
|
||||
Pass if the agent rules out stale-manifest caching from the evidence and selects
|
||||
compatible binary rollout. Fail if it repeats the caching workaround or forces HCP
|
||||
past the native mismatch.
|
||||
|
||||
## Case 20: background color migration
|
||||
|
||||
Prompt: "Our Meteor 3.3.2 Android build fails while processing resources. mobile-
|
||||
config.js has App.setPreference('BackgroundColor', '0xff0000ff'). There is also a
|
||||
Gradle property-syntax deprecation warning. Should we change Gradle versions?"
|
||||
|
||||
Pass if the agent checks the invalid preference as the concrete cause, uses a
|
||||
supported # hex value while preserving the intended color, and verifies generated
|
||||
resources/build output. Fail if it blindly changes Gradle or copies an ambiguous
|
||||
color-name assertion from a forum.
|
||||
|
||||
## Case 21: transitive plugin on pinned 3.0.4
|
||||
|
||||
Prompt: "Our Meteor 3.0.4 branch must stay pinned this week. Android meteor build
|
||||
started failing with Cannot find module cordova-android after adding cordova-
|
||||
plugin-screen-orientation@3.0.4. Its plugin.xml declares es6-promise-plugin@4.2.2,
|
||||
but the generated dependencies disappear. What durable workaround fits?"
|
||||
|
||||
Pass if the agent recognizes the incomplete 3.0.4 fix, keeps the release
|
||||
constraint, and explicitly declares only the verified transitive plugin through
|
||||
Meteor. It names 3.1 as the complete tool fix and verifies the next build. Fail if
|
||||
it edits generated package.json permanently, installs an unrelated global Cordova,
|
||||
or claims 3.0.4 already fixed it.
|
||||
|
||||
## Case 22: plugin failure after the tool fix
|
||||
|
||||
Prompt: "A Meteor 3.5.2 Android build cannot find a custom plugin module. The
|
||||
generated Cordova dependencies are present and that plugin has no es6-promise-
|
||||
plugin dependency. Should we add es6-promise-plugin@4.2.2 because a closed Meteor
|
||||
issue says it fixes missing modules?"
|
||||
|
||||
Pass if the agent rejects the historical workaround for this evidence and examines
|
||||
the actual plugin declaration, compatibility and generated source. Fail if it adds
|
||||
the old dependency or treats every missing-module error as issue 13303.
|
||||
|
||||
## Case 23: misleading core-js error
|
||||
|
||||
Prompt: "Our Meteor 3.0.4 Cordova app starts in the browser but shows a white
|
||||
screen after adding accounts-base on Android and iOS. The first exception comes
|
||||
from url/legacy.js and says core-js is missing. Installing core-js in the app did
|
||||
not help. .meteor/versions has url@1.3.4. How do we repair it?"
|
||||
|
||||
Pass if the agent identifies the URLSearchParams integration fix in url@1.3.5
|
||||
shipped with Meteor 3.1, checks compatible package/release selection and
|
||||
overrides, and verifies accounts startup. Fail if it removes accounts, repeatedly
|
||||
installs app-level core-js, or diagnoses every white screen identically.
|
||||
|
||||
## Case 24: runtime iterators versus modern output
|
||||
|
||||
Prompt: "Our Meteor 3.4 Vue Cordova app emits modern JavaScript, but Vue Router
|
||||
and another library fail with Map.entries is not a function or its return value is
|
||||
not iterable. .meteor/versions has ecmascript-runtime-client@0.12.3. The same
|
||||
WebView works when browsing the server URL. Should we downgrade Vue or set
|
||||
modern.cordova=true?"
|
||||
|
||||
Pass if the agent distinguishes runtime constructor replacement from
|
||||
transpilation, inspects the loaded polyfills, and selects the compatible
|
||||
ecmascript-runtime-client@0.13.0 fix shipped in 3.4.1. Fail if it considers modern
|
||||
output alone sufficient or blindly downgrades Vue.
|
||||
|
||||
## Case 25: runtime fix with a release constraint
|
||||
|
||||
Prompt: "Our Meteor 3.2.2 maintenance branch must stay pinned. A Cordova-only
|
||||
Map.entries failure matches the ecmascript-runtime-client fix, and someone
|
||||
suggests editing ~/.meteor/packages or copying the whole devel packages folder.
|
||||
What is the smallest supportable approach?"
|
||||
|
||||
Pass if the agent preserves the release constraint, verifies whether the fixed
|
||||
runtime package can be used compatibly, or scopes a verified app-local backport of
|
||||
the relevant fix. It tests the supported native and browser clients. Fail if it
|
||||
forces a release upgrade, edits the global cache or imports unrelated packages.
|
||||
|
||||
## Case 26: native Rspack proxy failure
|
||||
|
||||
Prompt: "Meteor 3.4 with Atmosphere rspack@1.0.0 works in normal web development.
|
||||
meteor run android-device produces SockJS Invalid frame header errors in both
|
||||
Android and a desktop browser attached to that run. The same deployment proxy
|
||||
works in normal mode. What should we check and change?"
|
||||
|
||||
Pass if the agent matches the native run-mode proxy defect, identifies the fixed
|
||||
Atmosphere rspack@1.1.0 integration shipped in 3.4.1, and verifies compatible
|
||||
package/release selection plus both clients. Fail if it only changes production
|
||||
proxy settings, treats Map errors as the same cause, or promises native Rspack
|
||||
HMR.
|
||||
|
||||
## Case 27: absent modern config on older tools
|
||||
|
||||
Prompt: "Our Meteor 3.5 Cordova app has no meteor.modern field and METEOR_MODERN
|
||||
is unset. The generated web.cordova bundle is still legacy. We want modern Cordova
|
||||
output without changing other build options; another branch intentionally uses
|
||||
modern.cordova=false. A thread says 3.5 fixed the default."
|
||||
|
||||
Pass if the agent distinguishes the 3.3.2 capability from the defaulting defect
|
||||
fixed in 3.5.1, verifies actual output, and suggests a narrow explicit cordova
|
||||
setting on the pinned tool or a fixed release. It preserves other options and the
|
||||
intentional legacy branch, accounting for object-form configuration inheriting
|
||||
enabled defaults. Fail if it treats the reporter statement as proof for 3.5, sets
|
||||
every modern feature true, removes the legacy opt-out, or requires a new binary
|
||||
solely for changing JavaScript output with unchanged native compatibility and
|
||||
supported WebViews.
|
||||
@@ -1,73 +0,0 @@
|
||||
# Native hot code push
|
||||
|
||||
## Decide whether the update can use HCP
|
||||
|
||||
HCP replaces compatible web code/assets in the installed Cordova shell. It
|
||||
does not install new native plugins, upgrade Cordova platforms, or alter
|
||||
native permissions, app identity, icons or signing. A Meteor upgrade can
|
||||
change the native compatibility contract; do not assume every installed
|
||||
binary can accept its client bundle.
|
||||
|
||||
Compare generated native changes, not merely edited filenames or the Meteor
|
||||
release label. The compatibility hash covers platform/plugin versions; it does
|
||||
not capture every native permission or configuration change. Those changes
|
||||
still need a new binary even when the hash is unchanged.
|
||||
|
||||
When a change needs native code/configuration, rebuild and distribute a new
|
||||
binary and preserve backend compatibility for old installations. Do not make
|
||||
`AUTOUPDATE_VERSION` or another compatibility override the default way to
|
||||
silence a platform/plugin mismatch. Such an override needs a verified native
|
||||
and JavaScript API contract across the installed client population.
|
||||
|
||||
## Find the failed stage
|
||||
|
||||
Inspect `.meteor/versions` for HCP packages (`hot-code-push`, `autoupdate`,
|
||||
`reload`) and the native webapp plugin; minimal/custom apps may omit them.
|
||||
The default `meteor-base` setup supplies HCP. Compare an installed native
|
||||
build with its intended server, not just with a successful browser reload.
|
||||
|
||||
| Stage | Evidence and next decision |
|
||||
|---|---|
|
||||
| Backend produced the update | Verify the deployed `web.cordova` bundle and changed version. A `--server-only` deployment can serve HCP; a build excluding that client target cannot. |
|
||||
| Device reached the server | Check the embedded build URL, `--mobile-server` for local work, public `ROOT_URL`, and any DDP override. Distinguish network/TLS/cleartext failures from compatibility. |
|
||||
| Client learned the version | Inspect DDP subscription/device logs and changed version hashes. A fixed `AUTOUPDATE_VERSION` must be changed when intentionally delivering another update. |
|
||||
| Client fetched the current manifest | Compare the version in `/__cordova/manifest.json` through the public proxy/CDN and directly at the origin. Inspect GET response headers and cache hits. If the public manifest is stale, bypass caching for this endpoint and purge its stale copy; keep versioned asset caching separate. |
|
||||
| Native shell accepted it | Read compatibility rejection logs. A platform/plugin mismatch calls for the native-version comparison and binary rollout above. |
|
||||
| Assets downloaded | Check the failing URL, response, connectivity and device storage. Large `public/` files can block update downloads; relocate only confirmed problem assets as the app requires. |
|
||||
| Pending version became active | Verify download completion, pending-version selection and reload. Custom reload code can reload the old bundle if it bypasses the native switch. |
|
||||
| New client started | Capture the first startup failure or rollback on the device. A version notification or download alone does not prove successful startup. |
|
||||
|
||||
An iOS-only production failure can be a cached manifest even when development
|
||||
and Android update correctly. A [Meteor 3.2.2 reporter confirmed this repair](https://forums.meteor.com/t/cordova-ios-hot-push-code/63707/6).
|
||||
Meteor marks its manifest non-cacheable; a proxy must preserve that behavior.
|
||||
Verify a subsequent deployment changes the public manifest version and reaches
|
||||
the device. A fresh manifest with a real plugin mismatch still requires the
|
||||
compatibility decision above. Use `meteor-deployment` for the proxy change.
|
||||
|
||||
Use selected version values and stage transitions for diagnostics. Never log
|
||||
full runtime settings, session credentials or private payloads to inspect HCP.
|
||||
Collect native logs through Android Studio/Xcode and WebView debugging when
|
||||
needed; use `meteor-debugging` if the failure still spans unknown layers.
|
||||
|
||||
## Reload behavior
|
||||
|
||||
Cordova HCP reloads the whole client even for CSS-only changes. Browser CSS
|
||||
refresh and development HMR are different paths; do not promise state-preserving
|
||||
CSS HMR in a production native app merely because a browser supports it.
|
||||
|
||||
Prefer the built-in reload path. When an app already customizes reloads,
|
||||
inspect that code against its resolved Meteor/reload/webapp-plugin versions:
|
||||
the native pending bundle must be selected before a forced page reload. The
|
||||
docs describe `WebAppLocalServer.switchToPendingVersion` and the retry callback
|
||||
of `Reload._onMigrate`; these are version-sensitive integration hooks, not a
|
||||
reason to add custom reloader code to every app. Preserve unsaved-state handling
|
||||
and remove temporary instrumentation after reproducing the repair.
|
||||
|
||||
For local HTTP failures, see
|
||||
[configuration and plugins](configuration-and-plugins.md). A development-only
|
||||
network exception is not a production compatibility or TLS repair.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/troubleshooting/hot-code-push.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/autoupdate.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/cordova.md
|
||||
@@ -1,172 +0,0 @@
|
||||
# Toolchain and development
|
||||
|
||||
## Resolve versions before installation
|
||||
|
||||
Read the app release and existing platform declarations. Meteor pins Cordova
|
||||
platforms independently of its Cordova library version. Use Meteor commands
|
||||
at the app root; a global `cordova` executable is not the authority for the
|
||||
Meteor-generated project.
|
||||
|
||||
Meteor 3.5.2 uses `cordova-lib@13.0.0`; verify Meteor's bundled Cordova tooling
|
||||
alongside its platform pins when diagnosing a toolchain mismatch.
|
||||
|
||||
| Target | Meteor 3.5.2 baseline | Verification |
|
||||
|---|---|---|
|
||||
| Android | `cordova-android@15.1.0`, JDK 17, SDK Platform 36, Build Tools 36.0.0, Android command-line tools; Gradle available for project setup | `java -version`, `gradle --version`, SDK Manager, actual generated Gradle/platform output |
|
||||
| iOS | `cordova-ios@7.1.1`; macOS with Xcode, command-line tools, accepted Xcode license and CocoaPods | `xcode-select -p`, `xcodebuild -version`, `pod --version`, selected simulator/device and signing team |
|
||||
|
||||
On earlier Meteor releases, inspect that release's native platform pins and
|
||||
the corresponding Cordova requirements. For example, a branch pinned to
|
||||
Meteor 3.5.1 does not acquire 3.5.2's SDK 36 requirement. Preserve a requested
|
||||
release constraint. A platform upgrade may also raise minimum device OS
|
||||
support; JavaScript transpilation cannot reverse that change.
|
||||
|
||||
For the 3.5.2 Android baseline, install missing SDK components with SDK Manager
|
||||
or:
|
||||
|
||||
```bash
|
||||
sdkmanager 'platforms;android-36' 'build-tools;36.0.0'
|
||||
```
|
||||
|
||||
Resolve `JAVA_HOME` and `ANDROID_HOME` to the actual host installations;
|
||||
`ANDROID_SDK_ROOT`, if set, must agree. Add the required command-line tools,
|
||||
platform-tools and emulator directories to PATH. Do not copy a macOS SDK path
|
||||
onto Linux or Windows. Keep the generated project's compatible Gradle wrapper
|
||||
and Android Gradle Plugin pairing rather than accepting an unrelated IDE
|
||||
upgrade suggestion.
|
||||
|
||||
For iOS, a Linux/Windows build cannot produce the Xcode archive or signed IPA.
|
||||
Use the project's macOS workstation or runner. Native platform requirements
|
||||
and current store submission requirements are separate; check Apple's current
|
||||
requirements when preparing an upload.
|
||||
|
||||
## Platform lifecycle
|
||||
|
||||
```bash
|
||||
meteor list-platforms
|
||||
meteor add-platform android
|
||||
meteor run android
|
||||
```
|
||||
|
||||
Use `meteor add-platform ios` and `meteor run ios` on macOS. The run targets
|
||||
`android` and `ios` select an emulator/simulator; `android-device` and
|
||||
`ios-device` select a physical-device workflow. Ensure the device is visible
|
||||
and authorized in Android Studio/ADB or Xcode before blaming app startup.
|
||||
|
||||
To stop targeting a native platform, use `meteor remove-platform android` or
|
||||
`meteor remove-platform ios` and review `.meteor/platforms`. Do not remove the
|
||||
shared application or plugins still needed by another platform. Meteor
|
||||
regenerates its native project from app-level state; running standalone
|
||||
`cordova platform add/remove` inside generated output is not a durable
|
||||
replacement for these declarations.
|
||||
|
||||
## Device networking and native IDEs
|
||||
|
||||
For the standard Android emulator, `10.0.2.2` reaches the host machine:
|
||||
|
||||
```bash
|
||||
meteor run android --mobile-server=http://10.0.2.2:3000
|
||||
```
|
||||
|
||||
For a physical device, use the development machine's reachable LAN address
|
||||
and port, for example:
|
||||
|
||||
```bash
|
||||
meteor run android-device --mobile-server=http://192.168.1.4:3000
|
||||
```
|
||||
|
||||
Replace that address with the real endpoint. Verify network reachability,
|
||||
server bind address/firewall, device authorization, and the URL embedded by the
|
||||
current native build. A custom `DDP_DEFAULT_CONNECTION_URL` can override the
|
||||
DDP endpoint independently; inspect it when HTTP and subscriptions disagree.
|
||||
Do not change `--cordova-server-port` expecting it to repair the backend URL.
|
||||
For cleartext rejection, use the scoped guidance in
|
||||
[configuration and plugins](configuration-and-plugins.md).
|
||||
|
||||
Open the generated project for device logs and native diagnostics:
|
||||
|
||||
| Platform | Default development path |
|
||||
|---|---|
|
||||
| Android Studio | `.meteor/local/cordova-build/platforms/android/` |
|
||||
| Xcode | `.meteor/local/cordova-build/platforms/ios/`; prefer the generated `.xcworkspace` when present |
|
||||
|
||||
Resolve custom local state first. Preserve useful IDE evidence, then express
|
||||
durable native changes in `mobile-config.js` or the app's build overrides.
|
||||
|
||||
## WebView JavaScript compatibility
|
||||
|
||||
Meteor 3.3.2 introduced modern Cordova output with a legacy opt-out. Earlier
|
||||
Meteor 3 releases used the legacy default. On 3.3.2+, an app that still needs
|
||||
legacy JavaScript can merge this setting into its existing `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"modern": { "cordova": false }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Preserve the other options' effective values; modern objects enable omitted
|
||||
options, as detailed below. Test the actual supported WebView and
|
||||
plugins; this setting neither restores OS support dropped by a native platform
|
||||
nor creates separate modern/legacy Cordova binaries. Web-only development
|
||||
architecture exclusions are a separate build concern: verify `web.cordova`
|
||||
is produced when developing native apps or serving HCP.
|
||||
|
||||
Check the effective bundle rather than inferring it from the release alone.
|
||||
Affected 3.3.2 through 3.5 tools can normalize an absent modern setting to
|
||||
legacy; Meteor 3.5.1 fixes that defaulting defect. Inspect `METEOR_MODERN` and
|
||||
`meteor.modern` overrides first. On an affected pinned release, explicitly set
|
||||
`meteor.modern.cordova` to `true` when the supported WebViews allow modern
|
||||
output, preserving the other effective settings. Objects inherit enabled
|
||||
defaults, so `{ "cordova": true }` also enables omitted modern options. For an
|
||||
affected app with no modern setting and no environment override, preserve its
|
||||
otherwise disabled options with:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"modern": {
|
||||
"transpiler": false,
|
||||
"minifier": false,
|
||||
"webArchOnly": false,
|
||||
"watcher": false,
|
||||
"cordova": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Merge this into the existing `meteor` object. If the app already configures
|
||||
modern options, preserve their effective values instead of copying those
|
||||
four `false` values. Preserve a deliberate Cordova legacy requirement.
|
||||
[Fix and regression coverage](https://github.com/meteor/meteor/pull/14411).
|
||||
|
||||
Changing only JavaScript output does not itself require a new native binary.
|
||||
Verify the installed WebViews support that output and the native compatibility
|
||||
hash is unchanged before using HCP; a release upgrade can separately change
|
||||
platform/plugin pins. See [hot code push](hot-code-push.md).
|
||||
|
||||
## Version-specific startup failures
|
||||
|
||||
Match the first exception and resolved package before selecting a repair.
|
||||
Inspect `.meteor/versions` and app-local `packages/` overrides; npm dependencies
|
||||
and the Meteor release label alone do not identify the loaded Atmosphere code.
|
||||
|
||||
| Confirmed signature | Fixed package / release | Decision |
|
||||
|---|---|---|
|
||||
| Early Meteor 3 Cordova startup fails after adding accounts, with a misleading missing `core-js` error from `url/legacy.js` | `url@1.3.5`, shipped in Meteor 3.1 | Check for a shadowing `packages/url` override before choosing a compatible fixed package/release, then verify account startup. Adding app-level `core-js` or removing accounts does not repair the URLSearchParams integration. [Fix](https://github.com/meteor/meteor/pull/13459) |
|
||||
| `Map.keys`, `Map.entries` or iteration fails in a modern library only in the Cordova bundle | `ecmascript-runtime-client@0.13.0`, shipped in Meteor 3.4.1 | Check whether legacy polyfills replaced native Map/Set/Symbol. Modern transpilation alone is not this fix. Use the compatible fixed package/release; for a constrained branch, verify an app-local backport against its supported WebViews. Do not edit the global Meteor cache or downgrade unrelated UI libraries. [Meteor 3 confirmation](https://forums.meteor.com/t/solved-vue3-does-not-work-with-cordova/61109/10) |
|
||||
| Meteor 3.4 Rspack `android-device`/iOS development produces SockJS `Invalid frame header` or proxy errors, including in a desktop browser attached to that native run | Atmosphere `rspack@1.1.0`, shipped in Meteor 3.4.1 | Use the fixed native integration that skips the desktop HMR bootstrap/proxy. Confirm the native run-mode reproduction and resolved package; healthy fixed versions or production proxy failures need separate diagnosis. [Fix](https://github.com/meteor/meteor/pull/14226) |
|
||||
|
||||
On earlier constrained releases, verify package compatibility before a
|
||||
selective update or backport. Retest both the native client and any affected
|
||||
browser clients. Do not force a framework upgrade contrary to the app's
|
||||
release constraint or apply these repairs to an unexplained white screen.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/cordova.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/index.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/cli/environment-variables.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.3.2.md
|
||||
@@ -1,153 +0,0 @@
|
||||
---
|
||||
name: meteor-pubsub
|
||||
description: >
|
||||
Use when authoring or debugging Meteor publications and subscriptions
|
||||
(Meteor.publish, Meteor.subscribe). Triggers on publication strategies
|
||||
(SERVER_MERGE, NO_MERGE, NO_MERGE_NO_HISTORY), the low-level publish API
|
||||
(added/changed/removed), cursor authorization, reactive joins, leaked
|
||||
documents. Use this skill when the user asks about pub/sub or asks about
|
||||
reactive data fetching.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: data
|
||||
tagline: "Author and debug publications/subscriptions (publish strategies, low-level `added/changed/removed`, authorization, reactive joins)."
|
||||
bundle: ["essentials", "fullstack"]
|
||||
docs_synced_at: "2026-08-25"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor publications and subscriptions
|
||||
|
||||
Publications stream a set of documents to subscribed clients and keep them
|
||||
live. The publication is the only place server-side authorization can
|
||||
filter rows before they reach the client.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Does the client need this data reactively? If no, prefer a method (one-shot
|
||||
read). If yes, use a publication.
|
||||
2. Is the data user-specific? Filter by `this.userId` inside the publish
|
||||
function. Without that filter, documents leak across users.
|
||||
3. Can the publication be expressed as a single cursor? Return it directly.
|
||||
4. Does it need one async lookup before choosing a cursor? Use an async
|
||||
publish handler, await the lookup, then return the cursor.
|
||||
5. Does it need per-document async joins, custom aggregation output, or an
|
||||
external reactive source? Drop to the low-level `this.added` /
|
||||
`this.changed` / `this.removed` API.
|
||||
|
||||
## Scaffold
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Items } from "/imports/api/items";
|
||||
|
||||
Meteor.publish("items.mine", function () {
|
||||
if (!this.userId) {
|
||||
return this.ready();
|
||||
}
|
||||
return Items.find(
|
||||
{ ownerId: this.userId },
|
||||
{ fields: { title: 1, qty: 1, updatedAt: 1 }, sort: { updatedAt: -1 } },
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
Project `fields` whenever the collection contains columns the subscriber
|
||||
must not receive.
|
||||
|
||||
Async publish handlers may also return a cursor:
|
||||
|
||||
```javascript
|
||||
Meteor.publish("items.byTeam", async function (teamId) {
|
||||
const member = await Memberships.findOneAsync({
|
||||
teamId,
|
||||
userId: this.userId,
|
||||
});
|
||||
if (!member) return this.ready();
|
||||
return Items.find({ teamId }, { fields: { title: 1, qty: 1 } });
|
||||
});
|
||||
```
|
||||
|
||||
Meteor awaits the handler before processing the returned cursor.
|
||||
|
||||
## Subscribing
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
|
||||
const handle = Meteor.subscribe("items.mine");
|
||||
// React / Blaze / Svelte hooks observe handle.ready() and the local cursor.
|
||||
handle.stop();
|
||||
```
|
||||
|
||||
## Publication strategies
|
||||
|
||||
Set per-collection with `Meteor.server.setPublicationStrategy`. Three options:
|
||||
|
||||
```javascript
|
||||
import { DDPServer } from "meteor/ddp-server";
|
||||
|
||||
Meteor.server.setPublicationStrategy(
|
||||
"items",
|
||||
DDPServer.publicationStrategies.NO_MERGE,
|
||||
);
|
||||
```
|
||||
|
||||
| Strategy | When to use |
|
||||
|----------------------|-----------------------------------------------------------------------------|
|
||||
| `SERVER_MERGE` | Default. Tracks merged document fields across publications and sends deltas. |
|
||||
| `NO_MERGE` | Tracks sent document IDs so unsubscribe can remove them. Use when the collection is owned by one publication. |
|
||||
| `NO_MERGE_NO_HISTORY`| Remembers nothing and sends no removals on stop. Reserve for send-and-forget queues where stale client documents are intentional. |
|
||||
|
||||
See `references/publication-strategies.md`.
|
||||
|
||||
## Low-level publish API
|
||||
|
||||
For joins or async work:
|
||||
|
||||
```javascript
|
||||
Meteor.publish("feed", async function () {
|
||||
const cursor = Posts.find({}, { fields: { title: 1, authorId: 1 } });
|
||||
const observer = await cursor.observeChangesAsync({
|
||||
added: async (id, doc) => {
|
||||
const author = await Users.findOneAsync(doc.authorId, {
|
||||
fields: { username: 1 },
|
||||
});
|
||||
this.added("feed", id, { ...doc, authorName: author?.username });
|
||||
},
|
||||
changed: (id, changes) => this.changed("feed", id, changes),
|
||||
removed: (id) => this.removed("feed", id),
|
||||
});
|
||||
|
||||
this.ready();
|
||||
this.onStop(() => observer.stop());
|
||||
});
|
||||
```
|
||||
|
||||
Note: cursor `transform` functions remain synchronous. Use a separate
|
||||
publication or the low-level API for per-document async joins.
|
||||
|
||||
Live observer delivery does not wait for one async callback before later
|
||||
changes arrive. If ordering or backpressure matters, serialize the work with a
|
||||
per-subscription Promise queue. Attach an error policy and stop the observer
|
||||
from `this.onStop`; see `references/low-level-publish-api.md`.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Publish without a `this.userId` filter when data is user-specific.
|
||||
- Publish sensitive or unnecessary columns. Add a `fields` projection when
|
||||
the full document is not part of the publication contract.
|
||||
- Confuse an async publish handler with an async cursor transform. Meteor
|
||||
awaits the handler Promise, but each transform callback must return a
|
||||
document synchronously.
|
||||
- Use cursor transforms for async joins. Transforms are synchronous; the
|
||||
low-level API is the right tool.
|
||||
- Subscribe to large unbounded collections. Page the data with `limit`/`skip`.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/publication-strategies.md`
|
||||
- `references/low-level-publish-api.md`
|
||||
- `references/eval-cases.md`
|
||||
@@ -1,71 +0,0 @@
|
||||
# Evaluation cases for `meteor-pubsub`
|
||||
|
||||
## Case 1: missing auth filter
|
||||
|
||||
Prompt: "Why are documents from other users showing up in my client when I
|
||||
subscribe to this publication?"
|
||||
|
||||
```javascript
|
||||
Meteor.publish("items", function () {
|
||||
return Items.find({});
|
||||
});
|
||||
```
|
||||
|
||||
Pass if the agent adds `this.userId` filtering and an `ownerId` selector.
|
||||
|
||||
## Case 2: async join
|
||||
|
||||
Prompt: "I want my feed publication to include the author username. The
|
||||
cursor transform crashed with 'returned a Promise'."
|
||||
|
||||
Pass if the agent rewrites to the low-level publish API with
|
||||
`observeChangesAsync`.
|
||||
|
||||
## Case 3: strategy choice
|
||||
|
||||
Prompt: "My server runs out of memory under load. I publish a real-time
|
||||
activity feed to every user."
|
||||
|
||||
Pass if the agent chooses `NO_MERGE` only when the collection is owned by one
|
||||
publication and explains that it tracks sent IDs for removals on unsubscribe.
|
||||
It may choose `NO_MERGE_NO_HISTORY` only for a send-and-forget queue whose
|
||||
consumer owns cleanup, and must warn that no removals are sent on stop. Fail if
|
||||
it calls either strategy stateless without qualification.
|
||||
|
||||
## Case 4: unsubscribe
|
||||
|
||||
Prompt: "How do I stop the subscription when the user leaves the page?"
|
||||
|
||||
Pass if the agent stores the handle and calls `.stop()` in unmount/cleanup.
|
||||
|
||||
## Case 5: async handler returning a cursor
|
||||
|
||||
Prompt: "My publication awaits a membership lookup and then returns
|
||||
`Items.find({ teamId })`. Does an async `Meteor.publish` handler require the
|
||||
low-level API?"
|
||||
|
||||
Pass if the agent says Meteor awaits async publish handlers and accepts the
|
||||
returned cursor. Fail if it rejects the handler only because it returns a
|
||||
Promise. It may recommend the low-level API only for custom or per-document
|
||||
async output.
|
||||
|
||||
## Case 6: ordered async join
|
||||
|
||||
Prompt: "My `observeChangesAsync` `added` callback awaits a user lookup. Under
|
||||
bursty updates, later changes overtake earlier joins and rejected lookups only
|
||||
appear in logs."
|
||||
|
||||
Pass if the agent explains that live delivery does not await each callback,
|
||||
serializes dependent work with a per-subscription Promise queue, registers
|
||||
observer teardown with `this.onStop`, and defines a terminal error policy such
|
||||
as `this.error`. Fail if it assumes `async added()` alone provides
|
||||
backpressure.
|
||||
|
||||
## Case 7: publication error lifecycle
|
||||
|
||||
Prompt: "Can I call `this.error(err)` to report a warning and keep the
|
||||
subscription alive?"
|
||||
|
||||
Pass if the agent says `this.error` stops the subscription and sends the error
|
||||
to the client. It should recommend a separate data or logging channel for a
|
||||
non-fatal warning.
|
||||
@@ -1,73 +0,0 @@
|
||||
# Low-level publish API
|
||||
|
||||
When a publish function needs to join, transform asynchronously, or react to
|
||||
external sources, return nothing and drive the publication imperatively.
|
||||
|
||||
## Methods on `this`
|
||||
|
||||
- `this.added(collectionName, id, fields)`: announce a document.
|
||||
- `this.changed(collectionName, id, fields)`: update fields.
|
||||
- `this.removed(collectionName, id)`: drop a document.
|
||||
- `this.ready()`: signal initial population complete.
|
||||
- `this.onStop(fn)`: register a teardown.
|
||||
- `this.error(err)`: stop the subscription and send the error to the client.
|
||||
- `this.stop()`: end the subscription.
|
||||
- `this.userId`, `this.connection`: identity.
|
||||
|
||||
## Pattern
|
||||
|
||||
```javascript
|
||||
Meteor.publish("feed", async function () {
|
||||
const handle = await Posts.find().observeChangesAsync({
|
||||
added: (id, doc) => this.added("posts", id, doc),
|
||||
changed: (id, doc) => this.changed("posts", id, doc),
|
||||
removed: (id) => this.removed("posts", id),
|
||||
});
|
||||
this.ready();
|
||||
this.onStop(() => handle.stop());
|
||||
});
|
||||
```
|
||||
|
||||
Always pair `observeChangesAsync` with `onStop`. Leaks otherwise.
|
||||
|
||||
## Async callback ordering
|
||||
|
||||
Initial `added` callbacks can be awaited while the observer is attaching, but
|
||||
live notifications do not wait for an async callback before scheduling later
|
||||
changes. Returning a Promise gives Meteor a rejection to log; it does not add
|
||||
live-event backpressure. Serialize dependent work yourself:
|
||||
|
||||
```javascript
|
||||
Meteor.publish("feed", async function () {
|
||||
let work = Promise.resolve();
|
||||
const enqueue = (task) => {
|
||||
work = work.then(task).catch((error) => this.error(error));
|
||||
return work;
|
||||
};
|
||||
|
||||
const handle = await Posts.find().observeChangesAsync({
|
||||
added: (id, doc) => enqueue(async () => {
|
||||
const author = await Users.findOneAsync(doc.authorId, {
|
||||
fields: { username: 1 },
|
||||
});
|
||||
this.added("feed", id, { ...doc, authorName: author?.username });
|
||||
}),
|
||||
changed: (id, fields) => enqueue(async () => {
|
||||
this.changed("feed", id, fields);
|
||||
}),
|
||||
removed: (id) => enqueue(async () => {
|
||||
this.removed("feed", id);
|
||||
}),
|
||||
});
|
||||
|
||||
this.ready();
|
||||
this.onStop(() => handle.stop());
|
||||
});
|
||||
```
|
||||
|
||||
Keep independent callbacks synchronous when no asynchronous join is needed.
|
||||
If one queued task fails, `this.error` terminates the subscription instead of
|
||||
leaving the client with partially joined data.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/meteor.md#publish-and-subscribe
|
||||
@@ -1,50 +0,0 @@
|
||||
# Publication strategies
|
||||
|
||||
## `SERVER_MERGE` (default)
|
||||
|
||||
The server maintains a per-client view of every published document and only
|
||||
sends diffs. Highest memory cost; lowest bandwidth. Right for typical apps
|
||||
where the working set per client is small.
|
||||
|
||||
## `NO_MERGE`
|
||||
|
||||
The server does not merge fields across publications, but it remembers the
|
||||
document IDs sent by this subscription. It can therefore send removals when
|
||||
the subscription stops. Client handling is forgiving: duplicate `added`
|
||||
messages become changes, a `changed` for an unknown ID becomes an add, and a
|
||||
`removed` for an unknown ID is ignored.
|
||||
|
||||
Use this when a collection is supplied by only one publication. It uses less
|
||||
server state than `SERVER_MERGE`, but multiple publications for the same
|
||||
collection can overwrite each other's document view.
|
||||
|
||||
## `NO_MERGE_NO_HISTORY`
|
||||
|
||||
The server remembers nothing about sent documents and does not send removals
|
||||
when the subscription stops. Use only for special send-and-forget queues where
|
||||
the consumer handles retention and stale client documents are intentional.
|
||||
|
||||
## Setting the strategy
|
||||
|
||||
Strategies are set per collection name, not per publication.
|
||||
|
||||
```javascript
|
||||
import { DDPServer } from "meteor/ddp-server";
|
||||
|
||||
Meteor.server.setPublicationStrategy(
|
||||
"feed",
|
||||
DDPServer.publicationStrategies.NO_MERGE,
|
||||
);
|
||||
|
||||
// Read it back
|
||||
Meteor.server.getPublicationStrategy("feed");
|
||||
```
|
||||
|
||||
## Choosing
|
||||
|
||||
- Default app (collaborative editor, dashboards): `SERVER_MERGE`.
|
||||
- Collection owned by one publication, with unsubscribe cleanup: `NO_MERGE`.
|
||||
- Send-and-forget queue with application-owned cleanup: `NO_MERGE_NO_HISTORY`.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/meteor.md#publication-strategies
|
||||
@@ -1,205 +0,0 @@
|
||||
---
|
||||
name: meteor-security
|
||||
description: >
|
||||
Use when auditing or hardening a Meteor 3 application. Triggers on
|
||||
missing check() on method arguments, missing this.userId guards on
|
||||
publications, browser-policy CSP, DDPRateLimiter rules, oauth-encryption
|
||||
via Accounts.config oauthSecretKey, audit-argument-checks, allow/deny
|
||||
legacy patterns, BrowserPolicy.content.disallowInlineScripts,
|
||||
BrowserPolicy.framing.disallow. Use this skill when the user asks about
|
||||
hardening, asks about a security review, or asks about CSP for a
|
||||
third-party script (Stripe, Google Maps, fonts).
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: security
|
||||
tagline: "Audit and harden Meteor 3 apps (`check()` coverage, `this.userId` guards, browser-policy CSP, rate limits, oauth-encryption)."
|
||||
bundle: ["essentials", "fullstack"]
|
||||
docs_synced_at: "2026-08-25"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Meteor security
|
||||
|
||||
Meteor's security model is opinionated: the server holds authority, the
|
||||
client cannot be trusted, and the only places that filter data before it
|
||||
reaches users are methods (write paths) and publications (read paths).
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Audit every method: does it `check()` every argument and guard on
|
||||
`this.userId` or `Meteor.userId()` when authentication matters?
|
||||
2. Audit every publication: does it filter by `this.userId` (when
|
||||
user-specific) and project columns with `fields`?
|
||||
3. Add `audit-argument-checks` in dev to catch missing `check()`.
|
||||
4. Add `browser-policy` and configure CSP.
|
||||
5. Add `DDPRateLimiter` rules for sensitive methods (login, password
|
||||
reset, resource creation).
|
||||
6. If the app uses OAuth, set `oauthSecretKey` to encrypt provider
|
||||
secrets at rest.
|
||||
7. Remove `allow` / `deny` rules. They are legacy and easy to misuse;
|
||||
use methods instead.
|
||||
|
||||
## Method guard checklist
|
||||
|
||||
```javascript
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { check, Match } from "meteor/check";
|
||||
|
||||
Meteor.methods({
|
||||
async updateProfile(payload) {
|
||||
check(payload, { displayName: String, bio: Match.Optional(String) });
|
||||
if (!this.userId) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
await Meteor.users.updateAsync(this.userId, { $set: { profile: payload } });
|
||||
},
|
||||
async updateAddress(payload) {
|
||||
check(payload, String);
|
||||
if (!Meteor.userId()) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
await Meteor.users.updateAsync(Meteor.userId(), { $set: { address: payload } });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Reject any method that does not match: `check` on every argument, userId
|
||||
gate when needed, `Meteor.Error(code, reason)` for failures, `*Async`
|
||||
Mongo on the server.
|
||||
|
||||
## Publication guard checklist
|
||||
|
||||
```javascript
|
||||
Meteor.publish("items.mine", function () {
|
||||
if (!this.userId) return this.ready();
|
||||
return Items.find(
|
||||
{ ownerId: this.userId },
|
||||
{ fields: { title: 1, qty: 1 }, limit: 200 },
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
Reject any publication that returns an unbounded cursor, omits the field
|
||||
projection, or skips a userId filter on user-specific data.
|
||||
|
||||
## CSP via `browser-policy`
|
||||
|
||||
```bash
|
||||
meteor add browser-policy
|
||||
```
|
||||
|
||||
```javascript
|
||||
// server top-level or inside Meteor.startup
|
||||
import { BrowserPolicy } from "meteor/browser-policy-common";
|
||||
import { Meteor } from "meteor/meteor";
|
||||
|
||||
Meteor.startup(async () => {
|
||||
await BrowserPolicy.content.disallowInlineScripts();
|
||||
BrowserPolicy.content.disallowEval();
|
||||
BrowserPolicy.framing.disallow();
|
||||
});
|
||||
```
|
||||
|
||||
`BrowserPolicy` is server-only. Configure it during module initialization or
|
||||
startup so every request receives one deterministic process-wide policy. The
|
||||
current implementation invalidates its cached CSP after a mutation, but do not
|
||||
mutate this global policy per request or per user. See
|
||||
`references/browser-policy-csp.md` for recipes (Stripe, Google Maps,
|
||||
fonts, inline-style allowance).
|
||||
|
||||
## DDPRateLimiter for sensitive methods
|
||||
|
||||
```javascript
|
||||
import { DDPRateLimiter } from "meteor/ddp-rate-limiter";
|
||||
|
||||
DDPRateLimiter.addRule(
|
||||
{
|
||||
type: "method",
|
||||
name: "login",
|
||||
clientAddress: () => true,
|
||||
},
|
||||
5,
|
||||
60000, // 5 attempts per 60s, per IP
|
||||
);
|
||||
```
|
||||
|
||||
Only matcher fields contribute to the rate-limit bucket key. Without
|
||||
`clientAddress`, `connectionId`, or `userId`, every matching caller shares one
|
||||
global bucket. Meteor 3.5+ permits async matcher functions for database-backed
|
||||
decisions; keep their queries fast because the connection waits for them. On
|
||||
Meteor 3.0 through 3.4, matchers must stay synchronous. Use a fixed rule,
|
||||
precomputed synchronous state, or upgrade rather than awaiting Mongo there.
|
||||
|
||||
The default rule (5 in 10s for login / signup / password reset) ships
|
||||
with `accounts-base`. Remove with `Accounts.removeDefaultRateLimit()`
|
||||
only if you replace it.
|
||||
|
||||
## OAuth secret encryption
|
||||
|
||||
Add `oauth-encryption` and pass a 16-byte base64 key (NOT 32 bytes) to
|
||||
`Accounts.config` at module top level (not inside `Meteor.startup`):
|
||||
|
||||
```bash
|
||||
meteor node -e "console.log(require('crypto').randomBytes(16).toString('base64'))"
|
||||
```
|
||||
|
||||
```javascript
|
||||
import { Accounts } from "meteor/accounts-base";
|
||||
|
||||
Accounts.config({
|
||||
oauthSecretKey: Meteor.settings.oauthSecretKey,
|
||||
});
|
||||
```
|
||||
|
||||
At startup, `accounts-oauth` seals an unsealed provider application secret at
|
||||
`ServiceConfiguration.configurations.secret`. Provider packages also seal
|
||||
supported per-user token fields, such as `services.github.accessToken` or
|
||||
Twitter's `accessTokenSecret`. There is no generic
|
||||
`Meteor.users.services.<provider>.secret` field. Inspect the provider schema
|
||||
before asserting which user credential is encrypted.
|
||||
|
||||
## `audit-argument-checks`
|
||||
|
||||
```bash
|
||||
meteor add audit-argument-checks
|
||||
```
|
||||
|
||||
Throws if any method or publication runs without `check()` covering
|
||||
every argument. Methods that legitimately accept arbitrary input declare
|
||||
this explicitly:
|
||||
|
||||
```javascript
|
||||
Meteor.methods({
|
||||
rawLog(...args) {
|
||||
check(args, [Match.Any]);
|
||||
// ...
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- `Collection.allow` / `Collection.deny` rules. Legacy; easy to combine
|
||||
into a soft-fail. Replace with methods.
|
||||
- `Meteor.settings.public.<secret>`. The client sees `public`. Move
|
||||
secrets to the top level of `settings.json`.
|
||||
- Publish the entire `Meteor.users` collection. Always project (e.g.
|
||||
`fields: { username: 1, profile: 1 }`) and filter. Publish email only to
|
||||
the owning user or another explicitly authorized audience.
|
||||
- Use `BrowserPolicy.content.allowOriginForAll` for a third-party script. It
|
||||
grants the origin to every current content directive. Allow only the script,
|
||||
frame, connect, image, style, or font directives the integration needs.
|
||||
- Methods that accept callback-shaped arguments. Functions cannot travel
|
||||
over DDP.
|
||||
- Call `Accounts.config({ oauthSecretKey })` inside `Meteor.startup`.
|
||||
Must be at module top level so it loads before the OAuth packages
|
||||
read it.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/method-and-publish-guards.md`
|
||||
- `references/browser-policy-csp.md`
|
||||
- `references/eval-cases.md`
|
||||
- Related skills: `meteor-methods`, `meteor-pubsub`, `meteor-accounts`.
|
||||
@@ -1,88 +0,0 @@
|
||||
# `browser-policy` CSP recipes
|
||||
|
||||
`BrowserPolicy` is server-only. Call its functions at module top level or
|
||||
inside `Meteor.startup` so policy initialization is deterministic. The policy
|
||||
is process-global, not request-specific. Current implementations invalidate
|
||||
the cached CSP when it changes, but do not use runtime mutation for per-user or
|
||||
per-route authorization.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
meteor add browser-policy
|
||||
```
|
||||
|
||||
Pulls in both `browser-policy-content` (CSP) and `browser-policy-framing`
|
||||
(X-Frame-Options). Add either standalone for a smaller surface.
|
||||
|
||||
## Tight default
|
||||
|
||||
```javascript
|
||||
import { BrowserPolicy } from "meteor/browser-policy-common";
|
||||
|
||||
await BrowserPolicy.content.disallowInlineScripts();
|
||||
BrowserPolicy.content.disallowEval();
|
||||
BrowserPolicy.framing.disallow();
|
||||
```
|
||||
|
||||
`disallowInlineScripts`, `allowInlineScripts`, and `setPolicy` are async in
|
||||
current Meteor. Await them from an async startup callback when startup order
|
||||
matters.
|
||||
|
||||
Removes `eval`, inline `<script>` blocks, and embedding by other sites.
|
||||
|
||||
## Stripe Checkout / Elements
|
||||
|
||||
```javascript
|
||||
BrowserPolicy.content.allowScriptOrigin("https://js.stripe.com");
|
||||
BrowserPolicy.content.allowFrameOrigin("https://js.stripe.com");
|
||||
BrowserPolicy.content.allowFrameOrigin("https://hooks.stripe.com");
|
||||
BrowserPolicy.content.allowConnectOrigin("https://api.stripe.com");
|
||||
```
|
||||
|
||||
Inspect CSP violation reports for the Stripe features actually enabled. Add a
|
||||
new origin only to the directive named by the violation.
|
||||
|
||||
## Google Maps / Fonts / GTM
|
||||
|
||||
```javascript
|
||||
BrowserPolicy.content.allowScriptOrigin("https://maps.googleapis.com");
|
||||
BrowserPolicy.content.allowConnectOrigin("https://maps.googleapis.com");
|
||||
BrowserPolicy.content.allowStyleOrigin("https://fonts.googleapis.com");
|
||||
BrowserPolicy.content.allowFontOrigin("https://fonts.gstatic.com");
|
||||
BrowserPolicy.content.allowScriptOrigin("https://www.googletagmanager.com");
|
||||
```
|
||||
|
||||
Do not replace these calls with `allowOriginForAll`. That helper adds the
|
||||
origin to every directive already in the policy, including resource types the
|
||||
provider does not need.
|
||||
|
||||
## Inline styles (framework injects them)
|
||||
|
||||
```javascript
|
||||
BrowserPolicy.content.allowInlineStyles();
|
||||
```
|
||||
|
||||
Tradeoff: weakens style protection. Use only when the framework (e.g.
|
||||
Material UI, styled-components) genuinely needs it.
|
||||
|
||||
## Frame-ancestors (Chrome / Safari)
|
||||
|
||||
`X-Frame-Options` is partly ignored by Chrome / Safari. To restrict
|
||||
framing across browsers, use the CSP `frame-ancestors` directive:
|
||||
|
||||
```javascript
|
||||
BrowserPolicy.content.allowFrameAncestorsOrigin("https://example.com");
|
||||
```
|
||||
|
||||
## Reset
|
||||
|
||||
```javascript
|
||||
await BrowserPolicy.content.setPolicy(...) // override entire content policy
|
||||
BrowserPolicy.framing.allowAll() // unset X-Frame-Options
|
||||
```
|
||||
|
||||
Used in tests where the default policy interferes.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/browser-policy.md
|
||||
@@ -1,110 +0,0 @@
|
||||
# Evaluation cases for `meteor-security`
|
||||
|
||||
## Case 1: missing `check()`
|
||||
|
||||
Prompt: "Audit this method:
|
||||
|
||||
```javascript
|
||||
Meteor.methods({ async addItem(p) { await Items.insertAsync(p); } });
|
||||
```
|
||||
"
|
||||
|
||||
Pass if the agent flags missing `check()`, missing `this.userId` guard,
|
||||
and rewrites with `check(p, { title: String, qty: Match.Integer })` plus
|
||||
a userId gate.
|
||||
|
||||
## Case 2: leaky publication
|
||||
|
||||
Prompt: "What's wrong with this publication?
|
||||
|
||||
```javascript
|
||||
Meteor.publish('items', function () { return Items.find({}); });
|
||||
```
|
||||
"
|
||||
|
||||
Pass if the agent flags missing `this.userId` filter, missing `fields`
|
||||
projection, and missing `limit` on an unbounded cursor.
|
||||
|
||||
## Case 3: Stripe CSP
|
||||
|
||||
Prompt: "Add a CSP that lets Stripe Checkout load."
|
||||
|
||||
Pass if the agent uses `browser-policy`, calls
|
||||
`BrowserPolicy.content.allowScriptOrigin("https://js.stripe.com")`, and
|
||||
adds `BrowserPolicy.content.allowFrameOrigin("https://js.stripe.com")`
|
||||
and `"https://hooks.stripe.com"`. It may add
|
||||
`allowConnectOrigin("https://api.stripe.com")` when the integration needs it.
|
||||
Fail if it uses `allowOriginForAll`.
|
||||
|
||||
## Case 4: OAuth secret in plaintext
|
||||
|
||||
Prompt: "My Google application secret in
|
||||
`ServiceConfiguration.configurations.secret` is plaintext, and I also want
|
||||
supported per-user OAuth tokens encrypted at rest."
|
||||
|
||||
Pass if the agent adds `oauth-encryption`, generates a 16-byte (not 32)
|
||||
base64 key, and configures
|
||||
`Accounts.config({ oauthSecretKey: Meteor.settings.oauthSecretKey })`
|
||||
at module top level (not inside `Meteor.startup`). It must distinguish the
|
||||
provider application secret from provider-specific user fields and reject a
|
||||
generic `services.<provider>.secret` path.
|
||||
|
||||
## Case 5: allow/deny in legacy code
|
||||
|
||||
Prompt: "I have `Items.allow({ insert: () => true });` in my code. Is
|
||||
that ok?"
|
||||
|
||||
Pass if the agent rejects allow/deny as a legacy pattern and rewrites the
|
||||
mutation as a `Meteor.method` with `check()` + `this.userId` guard.
|
||||
|
||||
## Case 6: async publication authorization
|
||||
|
||||
Prompt: "Audit this publication. It awaits an organization membership check
|
||||
and then returns a filtered cursor from an async publish handler."
|
||||
|
||||
Pass if the agent validates the authorization selector and projection while
|
||||
accepting the async handler. Fail if it requires the low-level publish API
|
||||
only because the handler returns a Promise.
|
||||
|
||||
## Case 7: per-IP limiter is accidentally global
|
||||
|
||||
Prompt: "I limited the `login` method with `{ type: 'method', name: 'login' }`,
|
||||
but one client's failures block every user. I wanted five attempts per IP."
|
||||
|
||||
Pass if the agent explains that only matcher fields form the bucket key and
|
||||
adds `clientAddress: () => true`. It should test two addresses with independent
|
||||
counters. Fail if it changes only the numeric limit.
|
||||
|
||||
## Case 8: database-backed rate decision
|
||||
|
||||
Prompt: "On Meteor 3.5, apply a stricter method limit to free-tier users. The
|
||||
tier is in `Meteor.users`."
|
||||
|
||||
Pass if the agent uses a projected `findOneAsync` inside an async `userId`
|
||||
matcher, warns that it delays message processing on the connection, and
|
||||
defines behavior for a rejected matcher Promise.
|
||||
|
||||
## Case 9: audit argument checks
|
||||
|
||||
Prompt: "How can I detect methods and publications that forgot to validate
|
||||
all DDP arguments?"
|
||||
|
||||
Pass if the agent adds `audit-argument-checks`, validates every argument with
|
||||
`check`, and uses `check(args, [Match.Any])` only when arbitrary arguments are
|
||||
intentional. Fail if it treats the package as a replacement for authorization.
|
||||
|
||||
## Case 10: user directory email leak
|
||||
|
||||
Prompt: "Publish usernames and profiles for our member directory. Should I
|
||||
include every member's `emails` field too?"
|
||||
|
||||
Pass if the agent defaults to `{ username: 1, profile: 1 }`, filters and limits
|
||||
the directory, and includes email only for a concrete authorized requirement.
|
||||
|
||||
## Case 11: database-backed limiter before Meteor 3.5
|
||||
|
||||
Prompt: "On Meteor 3.4, make a DDP rate-limit matcher await a user plan lookup."
|
||||
|
||||
Pass if the agent says async matchers begin in Meteor 3.5, rejects the awaited
|
||||
matcher on 3.4, and offers a synchronous fixed rule, precomputed state, or a
|
||||
framework upgrade. Fail if it applies the current 3.5 API unconditionally.
|
||||
@@ -1,89 +0,0 @@
|
||||
# Method and publish guards
|
||||
|
||||
The two attack surfaces an agent must audit on every PR.
|
||||
|
||||
## Method checklist
|
||||
|
||||
For every `Meteor.methods({ ... })` entry:
|
||||
|
||||
- [ ] `check()` on every argument.
|
||||
- [ ] `this.userId` guard when authentication is required.
|
||||
- [ ] Role check when elevated privileges are required (e.g.
|
||||
`alanning:roles`).
|
||||
- [ ] `Meteor.Error(code, reason, details?)` thrown on failure; never a
|
||||
plain `Error` (the client gets `"Internal server error"`).
|
||||
- [ ] `*Async` Mongo on the server. Sync Mongo is removed in Meteor 3.
|
||||
- [ ] `DDPRateLimiter.addRule` if the method is rate-sensitive (login,
|
||||
password reset, resource creation, expensive queries).
|
||||
|
||||
```javascript
|
||||
Meteor.methods({
|
||||
async addItem(payload) {
|
||||
check(payload, { title: String, qty: Match.Integer });
|
||||
if (!this.userId) throw new Meteor.Error("not-authorized");
|
||||
|
||||
return await Items.insertAsync({
|
||||
...payload,
|
||||
ownerId: this.userId,
|
||||
createdAt: new Date(),
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Publication checklist
|
||||
|
||||
For every `Meteor.publish(...)`:
|
||||
|
||||
- [ ] `this.userId` filter when data is user-specific.
|
||||
- [ ] `fields` projection limiting columns.
|
||||
- [ ] `limit` and `sort` on unbounded collections.
|
||||
- [ ] An async publish handler may await authorization or setup work and
|
||||
return a cursor. Cursor `transform` callbacks remain synchronous; use
|
||||
the low-level API for per-document async output.
|
||||
|
||||
```javascript
|
||||
Meteor.publish("items.mine", function () {
|
||||
if (!this.userId) return this.ready();
|
||||
return Items.find(
|
||||
{ ownerId: this.userId },
|
||||
{
|
||||
fields: { title: 1, qty: 1, updatedAt: 1 },
|
||||
sort: { updatedAt: -1 },
|
||||
limit: 200,
|
||||
},
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
## Sensitive-fields denylist
|
||||
|
||||
For `Meteor.users`:
|
||||
|
||||
```javascript
|
||||
Meteor.publish("users.public", function () {
|
||||
if (!this.userId) return this.ready();
|
||||
return Meteor.users.find(
|
||||
{},
|
||||
{ fields: { username: 1, profile: 1 }, limit: 200 },
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
Never publish `services.*`. That subtree holds OAuth secrets, password
|
||||
bcrypt hashes, and resume tokens. Do not publish every user's `emails` field by
|
||||
default. Publish an email only to the owning user or to a narrowly selected,
|
||||
explicitly authorized audience.
|
||||
|
||||
## Audit packages
|
||||
|
||||
```bash
|
||||
meteor add audit-argument-checks
|
||||
```
|
||||
|
||||
Crashes the request when a method or publish handler runs without
|
||||
`check()` covering every argument. Dev-time signal; safe to leave on in
|
||||
production too.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/security/security.md
|
||||
@@ -1,238 +0,0 @@
|
||||
---
|
||||
name: meteor-testing
|
||||
description: >
|
||||
Use when setting up, designing, writing, or repairing tests and test
|
||||
harnesses in a Meteor 3 app. Triggers on
|
||||
meteortesting:mocha, --driver-package, TEST_WATCH, TEST_BROWSER_DRIVER,
|
||||
MOCHA_GREP, meteor.testModule, focused tests, .only,
|
||||
Meteor.server.method_handlers, Meteor.server.publish_handlers,
|
||||
DDP.connect, --full-app integration mode, sinon, async test signatures,
|
||||
Playwright/Cypress E2E. Use this skill when the user asks about test
|
||||
runners, asks about testing publications, or asks about Jest vs Mocha
|
||||
in Meteor. For a failing, hanging, or flaky test whose failing layer or root
|
||||
cause is unknown, use meteor-debugging before changing the test or app.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: testing
|
||||
tagline: "Set up and write Meteor 3 tests (`meteortesting:mocha`, async signatures, methods/publications, Playwright/Cypress E2E)."
|
||||
bundle: ["fullstack"]
|
||||
docs_synced_at: "2026-09-11"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Testing Meteor 3 apps
|
||||
|
||||
`meteortesting:mocha` is the canonical Meteor test driver. It boots the
|
||||
app in test mode (no app code runs except the test files) and reports
|
||||
results in the server console.
|
||||
|
||||
If an existing test fails, hangs, or flakes and the failing layer is unknown,
|
||||
use `meteor-debugging` to isolate the cause. Return here when evidence points to
|
||||
test setup, design, driver behavior, fixtures, or regression coverage.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Unknown failure in an existing test? Use `meteor-debugging` to classify
|
||||
application, data, harness, browser, environment, or shared-state causes.
|
||||
2. Pure logic, no Meteor APIs? Plain Mocha or any test runner; nothing
|
||||
Meteor-specific.
|
||||
3. Method or publication? Integration test it with `meteortesting:mocha`
|
||||
using `Meteor.server.method_handlers[name].apply(ctx, args)` or
|
||||
`publish_handlers`.
|
||||
4. Need to drive a real DDP client (cross-process or end-to-end DDP
|
||||
semantics)? Use `--full-app` mode and `DDP.connect`.
|
||||
5. UI flow / browser interaction? Start the normal app with deterministic
|
||||
test settings and run Playwright or Cypress against it. Use
|
||||
`meteor test --full-app` only when the browser flow must load app-test
|
||||
modules.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
meteor add meteortesting:mocha
|
||||
meteor npm install --save-dev @types/mocha
|
||||
```
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "TEST_WATCH=1 meteor test --driver-package meteortesting:mocha",
|
||||
"test:ci": "meteor test --once --driver-package meteortesting:mocha",
|
||||
"test:full": "meteor test --full-app --driver-package meteortesting:mocha"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Test-mode conventions:
|
||||
|
||||
- Normal test mode eagerly loads `*.test[s].*` and `*.spec[s].*` files, while
|
||||
ordinary application code loads only when imported by a test.
|
||||
- Filename discovery ignores `tests/` directories. A configured
|
||||
`meteor.testModule` instead loads its explicit entry module and imports.
|
||||
- `--full-app` eagerly loads the normal app plus `*.app-test[s].*` and
|
||||
`*.app-spec[s].*` files, and sets `Meteor.isAppTest`.
|
||||
|
||||
For Meteor 3.5.2 Rspack full-app/TLA behavior, parent-`private` discovery
|
||||
failures, and the jQuery harness regression fixed in Meteor 3.6-beta.0, read
|
||||
[release-specific test setup](references/meteor-3.5.2-testing.md). Check
|
||||
resolved packages and suite counts before applying a version-specific fix.
|
||||
|
||||
To focus an existing test, prefer a supported driver filter such as
|
||||
`MOCHA_GREP` after checking the installed driver in `.meteor/versions`; use
|
||||
`.only` only temporarily. These select registered tests but do not prevent
|
||||
other test modules from evaluating. If loading itself causes interference,
|
||||
inspect `meteor.testModule` and read `references/focused-runs.md` before
|
||||
narrowing entrypoint imports. Restore every temporary focus or import change,
|
||||
then run the normal affected suite. Read the configured entrypoint paths from
|
||||
the project; do not invent paths, scripts, ports, or helpers.
|
||||
|
||||
## Method test (server-side)
|
||||
|
||||
```javascript
|
||||
import assert from "node:assert/strict";
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Items } from "/imports/api/items";
|
||||
|
||||
if (Meteor.isServer) {
|
||||
describe("items.add", function () {
|
||||
beforeEach(async function () {
|
||||
await Items.removeAsync({});
|
||||
});
|
||||
|
||||
it("inserts when authed", async function () {
|
||||
const _id = await Meteor.server.method_handlers["items.add"].apply(
|
||||
{ userId: "u1" },
|
||||
[{ title: "x", qty: 1 }],
|
||||
);
|
||||
const doc = await Items.findOneAsync(_id);
|
||||
assert.equal(doc.title, "x");
|
||||
});
|
||||
|
||||
it("rejects when unauthed", async function () {
|
||||
await assert.rejects(() =>
|
||||
Meteor.server.method_handlers["items.add"].apply({ userId: null }, [{}]),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
`.apply(context, argsArray)` is the documented form;
|
||||
`Meteor.server.method_handlers[name]` is the registered method
|
||||
implementation. Pass a stub `this` with `userId` (and `unblock`,
|
||||
`connection`, etc. when needed).
|
||||
|
||||
## Publication test (server-side)
|
||||
|
||||
```javascript
|
||||
if (Meteor.isServer) {
|
||||
describe("items.mine publication", function () {
|
||||
it("only ships the subscribing user's items", async function () {
|
||||
await Items.removeAsync({});
|
||||
await Items.insertAsync({ _id: "a", ownerId: "u1" });
|
||||
await Items.insertAsync({ _id: "b", ownerId: "u2" });
|
||||
|
||||
const cursor = await Meteor.server.publish_handlers["items.mine"]
|
||||
.apply({ userId: "u1" }, []);
|
||||
const docs = await cursor.fetchAsync();
|
||||
assert.deepEqual(docs.map((d) => d._id), ["a"]);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
For publications using the low-level `this.added` / `this.changed` API,
|
||||
test with a real DDP client via `--full-app` mode (next section).
|
||||
|
||||
Always await the direct publish handler. Conventional handlers return the
|
||||
cursor immediately; async handlers return a Promise of the cursor.
|
||||
|
||||
## End-to-end DDP test (`--full-app` mode)
|
||||
|
||||
```javascript
|
||||
import { DDP } from "meteor/ddp-client";
|
||||
import { Mongo } from "meteor/mongo";
|
||||
import { Tracker } from "meteor/tracker";
|
||||
|
||||
const conn = DDP.connect(Meteor.absoluteUrl());
|
||||
const RemoteItems = new Mongo.Collection("items", { connection: conn });
|
||||
|
||||
function ready(sub) {
|
||||
return new Promise((resolve) => {
|
||||
const computation = Tracker.autorun((c) => {
|
||||
if (sub.ready()) {
|
||||
c.stop();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const sub = conn.subscribe("items.mine");
|
||||
await ready(sub);
|
||||
const docs = RemoteItems.find().fetch();
|
||||
```
|
||||
|
||||
Run with `meteor test --full-app --driver-package meteortesting:mocha`.
|
||||
|
||||
## Client unit test (Minimongo)
|
||||
|
||||
```javascript
|
||||
if (Meteor.isClient) {
|
||||
describe("Items minimongo", function () {
|
||||
beforeEach(function () { Items.remove({}); });
|
||||
|
||||
it("filters by ownerId", function () {
|
||||
Items.insert({ _id: "a", ownerId: "u1" });
|
||||
Items.insert({ _id: "b", ownerId: "u2" });
|
||||
assert.equal(Items.find({ ownerId: "u1" }).count(), 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Client tests run in the browser the driver spawns. With
|
||||
`TEST_BROWSER_DRIVER=puppeteer`, the browser is headless Chromium and
|
||||
results flow back to the server console.
|
||||
|
||||
Do not treat a server-only green run as complete client coverage. The driver
|
||||
prints a message when no browser is connected; configure
|
||||
`TEST_BROWSER_DRIVER` in CI and confirm client test counts are present.
|
||||
|
||||
## Browser E2E
|
||||
|
||||
Run Playwright or Cypress against the normal application unless the test
|
||||
needs Meteor's app-test modules. The server command must work from a clean
|
||||
clone with a tracked, nonsecret settings fixture or fully documented test
|
||||
environment variables. Do not point it at an ignored developer settings file.
|
||||
|
||||
Cover at least one complete mutation flow and one rejected server action.
|
||||
Basic page-title checks do not exercise async method stubs, authorization, or
|
||||
publication readiness.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Reach for Jest. Jest does not understand Meteor's build system. Use
|
||||
`meteortesting:mocha`.
|
||||
- Mock Mongo. Run the real driver against a clean DB.
|
||||
- Forget `if (Meteor.isServer) { ... }` guards. Server tests crash if
|
||||
they run in the browser harness.
|
||||
- Skip `beforeEach` cleanup. Tests leak state across runs.
|
||||
- Catch and log a `beforeEach` failure without rethrowing. The test then runs
|
||||
against unknown state and can report a misleading assertion.
|
||||
- Assert only the database postcondition for a rejected method. Also require
|
||||
the Promise to reject with the expected `Meteor.Error`.
|
||||
- Replace `Meteor.userId` or another global without restoring it in
|
||||
`afterEach`.
|
||||
- Use `Meteor.call` with callbacks in async test code. Use
|
||||
`Meteor.callAsync` or unwrap `method_handlers` directly.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/mocha-setup.md`
|
||||
- `references/focused-runs.md`
|
||||
- `references/ddp-test-helpers.md`
|
||||
- `references/eval-cases.md`
|
||||
@@ -1,88 +0,0 @@
|
||||
# DDP-based test helpers
|
||||
|
||||
`--full-app` mode runs the whole app alongside tests. A second DDP
|
||||
connection lets you drive the app like a client would and inspect its
|
||||
local state.
|
||||
|
||||
## Connect to the running app
|
||||
|
||||
```javascript
|
||||
import { DDP } from "meteor/ddp-client";
|
||||
|
||||
const conn = DDP.connect(Meteor.absoluteUrl());
|
||||
```
|
||||
|
||||
`conn` is a stand-alone DDP client. It has its own resume token, its own
|
||||
collections, its own subscription handles.
|
||||
|
||||
Register each named collection against that connection before subscribing:
|
||||
|
||||
```javascript
|
||||
import { Mongo } from "meteor/mongo";
|
||||
|
||||
const RemoteItems = new Mongo.Collection("items", { connection: conn });
|
||||
```
|
||||
|
||||
## Wait for a subscription to be ready
|
||||
|
||||
```javascript
|
||||
import { Tracker } from "meteor/tracker";
|
||||
|
||||
function ready(sub) {
|
||||
return new Promise((resolve) => {
|
||||
const computation = Tracker.autorun((c) => {
|
||||
if (sub.ready()) {
|
||||
c.stop();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const sub = conn.subscribe("items.mine");
|
||||
await ready(sub);
|
||||
```
|
||||
|
||||
## Inspect the resulting documents
|
||||
|
||||
```javascript
|
||||
const docs = RemoteItems.find().fetch();
|
||||
```
|
||||
|
||||
Do not inspect `conn._stores`, `._docs`, or `conn.connection`. The first two
|
||||
are private internals, and `DDP.connect` returns the connection directly, so
|
||||
there is no nested `.connection`. A collection constructed with
|
||||
`{ connection: conn }` is the supported local-cache interface.
|
||||
|
||||
## Method invocation on a separate connection
|
||||
|
||||
```javascript
|
||||
await conn.callAsync("items.add", { title: "x", qty: 1 });
|
||||
```
|
||||
|
||||
This goes over the wire, hits the real method handler, and the result is
|
||||
the value the method resolved to.
|
||||
|
||||
## Disconnect
|
||||
|
||||
```javascript
|
||||
conn.disconnect();
|
||||
```
|
||||
|
||||
Call this in `after` / `afterEach` so the test process exits cleanly.
|
||||
|
||||
## When to use which
|
||||
|
||||
| Need | Use |
|
||||
|-----------------------------------------|------------------------------------------------------------------|
|
||||
| Test a method's logic | `Meteor.server.method_handlers[name].apply(ctx, args)` directly. |
|
||||
| Test a publication's cursor | `Meteor.server.publish_handlers[name].apply({ userId }, [])`. |
|
||||
| Test the full DDP path (auth, ratelimits, multi-user merge) | `DDP.connect(Meteor.absoluteUrl())` + `--full-app`. |
|
||||
| Test client reactivity through DDP | `--full-app` + `DDP.connect` + Tracker autorun. |
|
||||
|
||||
Direct `method_handlers` / `publish_handlers` invocation is the fast
|
||||
default. Reach for `--full-app` and `DDP.connect` only when the path
|
||||
under test actually depends on the network round trip.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/testing/testing.md
|
||||
@@ -1,190 +0,0 @@
|
||||
# Evaluation cases for `meteor-testing`
|
||||
|
||||
## Case 1: setup from zero
|
||||
|
||||
Prompt: "Set up Mocha tests for my Meteor 3 app."
|
||||
|
||||
Pass if the agent adds `meteortesting:mocha`, writes the `package.json`
|
||||
scripts (with `--once` for CI and `TEST_WATCH=1` for dev), and shows a
|
||||
`.test.js` example with `if (Meteor.isServer)` guards.
|
||||
|
||||
## Case 2: method handler test
|
||||
|
||||
Prompt: "Write a test for my `items.add` method."
|
||||
|
||||
Pass if the agent uses
|
||||
`Meteor.server.method_handlers["items.add"].apply({ userId: "u1" }, [args])`
|
||||
with a stubbed userId and awaits the Mongo result. Avoids
|
||||
`Meteor.call`/`callAsync` from the test (which goes over the wire and
|
||||
adds DDP overhead).
|
||||
|
||||
## Case 3: publication test
|
||||
|
||||
Prompt: "Test that my `items.mine` publication only ships items owned by
|
||||
the subscribing user."
|
||||
|
||||
Pass if the agent uses
|
||||
`await Meteor.server.publish_handlers["items.mine"].apply(
|
||||
{ userId: "u1" }, [])`, calls `.fetchAsync()` on the resolved cursor, and
|
||||
asserts on the returned `_id`s. The `await` is required so the test also
|
||||
works when the publication handler is async.
|
||||
|
||||
## Case 4: --full-app DDP test
|
||||
|
||||
Prompt: "I need to test that an unauthed client cannot see my admin
|
||||
publication's documents even over DDP."
|
||||
|
||||
Pass if the agent uses `meteor test --full-app`, then `DDP.connect` to a
|
||||
second client and `subscribe` without logging in, and asserts on the
|
||||
empty named collection created with
|
||||
`new Mongo.Collection(name, { connection: conn })`. Fail if it reads
|
||||
`conn.connection._stores`, `conn._stores`, or another private cache.
|
||||
|
||||
## Case 5: Jest detour
|
||||
|
||||
Prompt: "Can I use Jest instead of Mocha?"
|
||||
|
||||
Pass if the agent steers away from Jest, explains Meteor's build system
|
||||
exposes a test-driver hook that Jest does not implement, and recommends
|
||||
`meteortesting:mocha` (or any other Meteor test-driver package).
|
||||
|
||||
## Case 6: swallowed async setup failure
|
||||
|
||||
Prompt: "My `beforeEach` catches and logs `removeAsync` and `insertAsync`
|
||||
errors, but later assertions fail with unexpected document counts."
|
||||
|
||||
Pass if the agent removes the catch or rethrows, requires setup to reject the
|
||||
test, and isolates startup seeding from the test database.
|
||||
|
||||
## Case 7: negative method assertion
|
||||
|
||||
Prompt: "This authorization test only checks that the document count did not
|
||||
change after `callAsync`. Is that enough?"
|
||||
|
||||
Pass if the agent also asserts that `callAsync` rejects with the expected
|
||||
`Meteor.Error`, while retaining the postcondition as a second assertion.
|
||||
|
||||
## Case 8: client tests silently skipped
|
||||
|
||||
Prompt: "All server tests pass, but the runner says to load the app in a
|
||||
browser. Can CI still be green?"
|
||||
|
||||
Pass if the agent says client tests were not executed, configures
|
||||
`TEST_BROWSER_DRIVER`, and checks that client test results appear in CI.
|
||||
|
||||
## Case 9: Playwright clean-checkout server
|
||||
|
||||
Prompt: "Playwright's webServer uses `private/settings.dev.json`, which is
|
||||
ignored and missing in CI. How should I validate the migration?"
|
||||
|
||||
Pass if the agent introduces a tracked nonsecret test fixture or explicit
|
||||
environment setup, starts the normal app deterministically, and covers a
|
||||
mutation plus a rejected action rather than only static page checks.
|
||||
|
||||
## Case 10: ignored tests directory
|
||||
|
||||
Prompt: "Why does `meteor test` ignore `tests/users.test.js`, and what filename
|
||||
should I use for a full-app test?"
|
||||
|
||||
Pass if the agent explains that every `tests/` directory is ignored by the
|
||||
Meteor build tool, moves a normal test to a non-ignored path matching
|
||||
`*.test[s].*` or `*.spec[s].*`, and uses `*.app-test[s].*` or
|
||||
`*.app-spec[s].*` for `--full-app`. Fail if it says the directory itself is a
|
||||
discovery convention.
|
||||
|
||||
## Case 11: CI Node for Meteor 3.3
|
||||
|
||||
Prompt: "Configure the CI Node version for a Meteor 3.3 test job. Can it reuse
|
||||
Node 20 from Meteor 3.0?"
|
||||
|
||||
Pass if the agent selects Node 22 for Meteor 3.3, explains that only Meteor 3.0
|
||||
uses Node 20 while 3.1 through 3.4 use Node 22, and recommends `meteor node -v`
|
||||
to verify the exact target. Fail if it treats all pre-3.4 releases as Node 20.
|
||||
|
||||
## Case 12: unexplained failing-test near miss
|
||||
|
||||
Prompt: "A full-app Meteor test hangs only in CI. I do not know whether the
|
||||
problem is its DDP subscription, database cleanup, browser driver, or product
|
||||
code. Rewrite the test to make it pass."
|
||||
|
||||
Pass if the agent routes first to `meteor-debugging` to preserve the failure,
|
||||
compare local and CI evidence, and isolate the application, data, harness,
|
||||
browser, environment, or shared-state boundary. It should return to
|
||||
`meteor-testing` only after evidence identifies test setup, design, driver,
|
||||
fixture, or regression work. Fail if it rewrites the test or raises timeouts
|
||||
before classifying the failure.
|
||||
|
||||
## Case 13: focus one test through the Meteor driver
|
||||
|
||||
Prompt: "I use `meteortesting:mocha`. How can I repeatedly run only the
|
||||
`items.add` unauthenticated case without changing which modules Meteor loads?"
|
||||
|
||||
Pass if the agent checks the installed driver version and uses `MOCHA_GREP`
|
||||
with a quoted regular expression matching the full test title. It may offer
|
||||
temporary `it.only`, but requires cleanup and an affected-suite run. Fail if it
|
||||
invents an unsupported `meteor test --grep` flag, requires `.only` on every
|
||||
ancestor, or edits the test module graph for ordinary execution focus.
|
||||
|
||||
## Case 14: focus test module loading
|
||||
|
||||
Prompt: "Our `meteor.testModule` entrypoints import every spec. `MOCHA_GREP`
|
||||
focuses the assertion, but module-scope setup from unrelated imports still
|
||||
runs. How can I isolate this safely?"
|
||||
|
||||
Pass if the agent distinguishes execution filtering from module loading and
|
||||
temporarily narrows the configured entrypoint import graph only because
|
||||
load-time behavior is the problem. It preserves and restores the imports,
|
||||
removes focus markers, and runs the normal affected suite. Fail if it claims
|
||||
the title filter prevents module evaluation, changes private runner internals,
|
||||
or gives project-specific paths, ports, helpers, or scripts.
|
||||
|
||||
## Case 15: full-app tests with a server-only test entry
|
||||
|
||||
Prompt: "On Meteor 3.5.2 with its paired Rspack packages, mainModule has client
|
||||
and server entries, testModule has only a server entry, and the server imports
|
||||
a module with top-level await. How should full-app tests load this app?"
|
||||
|
||||
Pass if the agent keeps the configured application client/server bundles,
|
||||
awaits the module initialization, and separates client bundle compilation from
|
||||
client test execution. Fail if it removes the app client entry, adds a sleep,
|
||||
or guarantees every detached Promise or async startup callback has settled.
|
||||
|
||||
## Case 16: zero full-app tests below a parent private path
|
||||
|
||||
Prompt: "A Meteor 3.5.1 Rspack app under /workspace/private/my-app runs zero
|
||||
full-app tests; the same commit elsewhere discovers them. Should I remove all
|
||||
private-directory exclusions?"
|
||||
|
||||
Pass if the agent checks the 3.5.2 eager-discovery fix and the app-relative test
|
||||
patterns and entrypoints, proposes a paired upgrade or a disposable path
|
||||
reproduction, and preserves the app's private-assets exclusion. Fail if it
|
||||
accepts zero passing tests as validation or includes private assets as tests.
|
||||
|
||||
## Case 17: package test lost transitive jQuery
|
||||
|
||||
Prompt: "After test-in-browser updated to 1.6.0 with Meteor 3.5.2, my package's
|
||||
client tests fail because they use jQuery. Where should I declare it?"
|
||||
|
||||
Pass if the agent adds `jquery` to the existing `Package.onTest` client
|
||||
dependencies or uses `meteor test-packages --extra-packages=jquery` with the
|
||||
real package target. Fail if it changes unrelated production app dependencies.
|
||||
|
||||
## Case 18: jQuery-free tests and earlier packages
|
||||
|
||||
Prompt: "One branch uses test-in-browser 1.5.x; another uses 1.6.0. Neither
|
||||
branch's tests uses jQuery. Must I add jquery to both apps for Meteor 3.5.2?"
|
||||
|
||||
Pass if the agent rejects adding production dependencies, distinguishes the
|
||||
1.6.0 harness regression from the package's own jQuery-free tests, and checks
|
||||
whether the browser UI starts. It offers an invocation-only extra package or
|
||||
compatible fixed driver for a failing 1.6.0 harness, not for working 1.5.x.
|
||||
Fail if it claims jQuery-free tests prove driver 1.6.0 cannot need jQuery.
|
||||
|
||||
## Case 19: restored driver in the 3.6 beta
|
||||
|
||||
Prompt: "Meteor 3.6-beta.0 resolves test-in-browser 1.6.1-beta360.0. My package
|
||||
tests do not use jQuery. Should I add it to the app before running test-packages?"
|
||||
|
||||
Pass if the agent recognizes the restored driver dependency, adds no app or
|
||||
unneeded package-test dependency, and verifies the UI and expected client/server
|
||||
assertions. Fail if it repeats the 1.6.0 workaround unconditionally.
|
||||
@@ -1,51 +0,0 @@
|
||||
# Focused Meteor test runs
|
||||
|
||||
Use two separate controls. Do not confuse test execution with module loading.
|
||||
|
||||
| Need | Control |
|
||||
|---|---|
|
||||
| Run selected registered tests | Driver filter such as `MOCHA_GREP`, or temporary Mocha `.only` |
|
||||
| Prevent unrelated test modules from evaluating | `meteor.testModule` entrypoints and their import graph |
|
||||
|
||||
## Focus test execution
|
||||
|
||||
For an installed `meteortesting:mocha` version that supports it, set
|
||||
`MOCHA_GREP` to a regular expression matching the full Mocha title:
|
||||
|
||||
```bash
|
||||
MOCHA_GREP='items\.add.*rejects unauthenticated' \
|
||||
meteor test --once --driver-package meteortesting:mocha
|
||||
```
|
||||
|
||||
Use `MOCHA_INVERT=1` to exclude matching titles. Use `TEST_SERVER=0` or
|
||||
`TEST_CLIENT=0` only when isolating one runtime side preserves what the test
|
||||
proves. Inspect `.meteor/versions` and the
|
||||
[`meteortesting:mocha` run options](https://github.com/Meteor-Community-Packages/meteor-mocha#run-tests-inclusively-grep-or-exclusively-invert)
|
||||
before relying on package-specific behavior.
|
||||
|
||||
`describe.only` and `it.only` are temporary source-local alternatives. They do
|
||||
not require `.only` on every ancestor, and they are incompatible with Mocha
|
||||
parallel mode. Remove every focus marker before handoff and run the affected
|
||||
suite. See [Mocha exclusive tests](https://mochajs.org/declaring/exclusive-tests/).
|
||||
|
||||
## Control the loaded test graph
|
||||
|
||||
Configure explicit entry modules when the project needs deterministic test
|
||||
loading. `meteor.testModule` accepts one shared entry-module string or separate
|
||||
`client` and `server` values. Read those values from the project's
|
||||
`package.json`; do not invent an entrypoint path. Each entry module imports the
|
||||
tests for its runtime.
|
||||
|
||||
With `meteor.testModule`, Meteor eagerly loads only the configured entry module
|
||||
for that runtime, then normal imports determine the remaining graph. Without
|
||||
it, Meteor's filename patterns determine which test modules are eager.
|
||||
|
||||
`MOCHA_GREP` and `.only` filter registered test execution. They do not prevent
|
||||
loaded modules from running module-scope code, declaring suites, or registering
|
||||
hooks. Narrow an entrypoint's imports only when evidence shows module loading
|
||||
itself causes interference or dominates the focused run. Preserve the original
|
||||
imports, make the smallest temporary change, restore it immediately, and run
|
||||
the normal affected suite. Never commit a narrowed test graph or a focus marker.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/modules.md
|
||||
@@ -1,77 +0,0 @@
|
||||
# Meteor 3.5.2 and 3.6 beta testing boundaries
|
||||
|
||||
## Rspack full-app tests
|
||||
|
||||
Meteor 3.5.2 pairs `rspack@1.3.0` and `@meteorjs/rspack@2.2.0`. Its full-app
|
||||
fixes preserve configured `meteor.mainModule` client and server bundles even
|
||||
when `meteor.testModule` defines only server tests:
|
||||
|
||||
```bash
|
||||
meteor test --full-app --once --driver-package meteortesting:mocha
|
||||
```
|
||||
|
||||
The server module graph can use top-level `await`; awaited module dependencies
|
||||
settle before their consumers and app tests run. Keep required initialization
|
||||
in that awaited graph or an explicit awaited test setup. This does not imply
|
||||
that detached Promises, timers, or every async `Meteor.startup` callback under
|
||||
every driver finish before tests. Inspect the installed driver and verify the
|
||||
specific readiness condition instead of adding a sleep.
|
||||
|
||||
A built client application bundle does not mean client tests executed. Use a
|
||||
browser driver when testing browser behavior, and inspect both server and
|
||||
client suite counts. Keep an existing application client entry for full-app
|
||||
tests even when there is no client test entry. On earlier integrations,
|
||||
reproduce and upgrade the paired release before relying on the 3.5.2 fixes.
|
||||
|
||||
## Zero tests under a parent `private` directory
|
||||
|
||||
`@meteorjs/rspack@2.2.0` fixes eager-test exclusion when an app's absolute
|
||||
parent path contains `private`, for example a checkout at
|
||||
`/workspace/private/my-app`. That parent segment is not the application's
|
||||
private-assets folder. Earlier versions can silently discover zero tests there.
|
||||
Check the app-relative filename pattern, `meteor.testModule`, ignore rules,
|
||||
and expected suite count. Prefer upgrading; if an older release is fixed in
|
||||
scope, moving a disposable checkout out of that parent path can isolate the
|
||||
known regression. Do not remove the actual app `private/` asset exclusion.
|
||||
|
||||
## Package tests and the browser harness
|
||||
|
||||
`test-in-browser@1.6.0`, shipped with Meteor 3.5.2, removes transitive jQuery.
|
||||
Its released Blaze test UI can still require jQuery even when the package's
|
||||
own tests do not. Meteor 3.6-beta.0 restores the driver's client dependency in
|
||||
`test-in-browser@1.6.1-beta360.0`. Inspect the resolved driver independently of
|
||||
the Meteor release and distinguish a harness startup failure from a failed
|
||||
application assertion.
|
||||
|
||||
If package tests themselves use jQuery, declare it in the existing
|
||||
`Package.onTest` callback:
|
||||
|
||||
```javascript
|
||||
Package.onTest((api) => {
|
||||
// Keep the package's existing test dependencies and entrypoint.
|
||||
api.use("jquery", "client");
|
||||
});
|
||||
```
|
||||
|
||||
Or supply it for the test invocation:
|
||||
|
||||
```bash
|
||||
meteor test-packages --extra-packages=jquery ./packages/my-package
|
||||
```
|
||||
|
||||
Use the actual local package path. On a branch pinned to driver 1.6.0, the
|
||||
invocation-only extra package also works around the harness regression when
|
||||
the tests themselves are jQuery-free. Prefer the fixed driver through a
|
||||
compatible release when an upgrade is in scope. Do not add a production app
|
||||
dependency to repair the test harness.
|
||||
|
||||
Earlier 1.5.x and the fixed 1.6.1 beta driver supply jQuery themselves; a
|
||||
jQuery-free package does not need a new test dependency there. Tests that do
|
||||
use jQuery should declare it explicitly regardless of transitive availability.
|
||||
Confirm the browser UI loads and expected client and server assertions run;
|
||||
an empty or crashed UI is not a passing test suite.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/packages/7.writing-atmosphere-packages.md
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/generators/changelog/versions/3.6.0.md
|
||||
@@ -1,97 +0,0 @@
|
||||
# `meteortesting:mocha` setup
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
meteor add meteortesting:mocha
|
||||
meteor npm install --save-dev @types/mocha
|
||||
```
|
||||
|
||||
## Env vars
|
||||
|
||||
| Var | Purpose |
|
||||
|------------------------|----------------------------------------------------------------------|
|
||||
| `TEST_WATCH=1` | Re-run on file change. Use in dev. |
|
||||
| `TEST_BROWSER_DRIVER` | Run client tests in a headless browser. `puppeteer`, `playwright`. |
|
||||
| `TEST_SERVER=0` | Skip server tests. |
|
||||
| `TEST_CLIENT=0` | Skip client tests. |
|
||||
| `MOCHA_GREP` | Run titles matching a regular expression. |
|
||||
| `MOCHA_INVERT=1` | Exclude titles matching `MOCHA_GREP`. |
|
||||
| `MONGO_URL` | External Mongo for tests (e.g. `mongodb://localhost:27017/test`). |
|
||||
|
||||
These driver options depend on the installed `meteortesting:mocha` version.
|
||||
Inspect `.meteor/versions`, then use
|
||||
[`meteortesting:mocha`'s documented options](https://github.com/Meteor-Community-Packages/meteor-mocha#run-tests-inclusively-grep-or-exclusively-invert).
|
||||
|
||||
## Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "TEST_WATCH=1 meteor test --driver-package meteortesting:mocha",
|
||||
"test:once": "meteor test --once --driver-package meteortesting:mocha",
|
||||
"test:ci": "TEST_BROWSER_DRIVER=puppeteer meteor test --once --driver-package meteortesting:mocha",
|
||||
"test:full": "meteor test --full-app --driver-package meteortesting:mocha"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`--once`: exit after the first run (CI). Without it, the runner stays
|
||||
alive and re-runs on file change.
|
||||
|
||||
`--full-app`: runs the whole app plus tests. Use this when tests need to
|
||||
hit live publications, methods, or HTTP endpoints over DDP. Server and
|
||||
client tests both run; you can `DDP.connect(Meteor.absoluteUrl())` from a
|
||||
test file.
|
||||
|
||||
## GitHub Actions example
|
||||
|
||||
```yaml
|
||||
name: test
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
mongo:
|
||||
image: mongo:7
|
||||
ports: ["27017:27017"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 22 }
|
||||
|
||||
- name: Install Meteor
|
||||
run: curl https://install.meteor.com/ | sh
|
||||
|
||||
- run: meteor npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
TEST_BROWSER_DRIVER=puppeteer MONGO_URL=mongodb://localhost:27017/test \
|
||||
meteor test --once --driver-package meteortesting:mocha
|
||||
```
|
||||
|
||||
Node version must match the bundled Node.js for the Meteor version: 3.0 uses
|
||||
Node 20, 3.1 through 3.4 use Node 22, and 3.5+ uses Node 24. Run
|
||||
`meteor node -v` to verify the exact version used by the target release.
|
||||
|
||||
## Test discovery
|
||||
|
||||
- Normal test mode: `*.test[s].*` and `*.spec[s].*` outside ignored
|
||||
`tests/` directories.
|
||||
- Full-app mode: `*.app-test[s].*` and `*.app-spec[s].*` outside ignored
|
||||
`tests/` directories.
|
||||
- Every `tests/` directory is ignored by Meteor's build tool. Reserve it for
|
||||
an external test runner.
|
||||
|
||||
Server-only modules stay server-only when imported from tests. Client
|
||||
tests run in a browser instance the driver spawns.
|
||||
|
||||
For focused execution and the separate `meteor.testModule` loading boundary,
|
||||
read [Focused Meteor test runs](focused-runs.md).
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/tutorials/testing/testing.md
|
||||
@@ -1,145 +0,0 @@
|
||||
---
|
||||
name: migrate-to-meteor-3
|
||||
description: >
|
||||
Use when migrating a Meteor 2.x application to Meteor 3.x. Triggers on
|
||||
callAsync, *Async Mongo, removed Fibers, implicit-global ReferenceError,
|
||||
lost Blaze reactivity, a publish function returning a Promise, a scheduler
|
||||
dropping a Promise, a read API receiving update modifiers, async allow/deny,
|
||||
an Iron Router controller not running, "Method stub took too long",
|
||||
Atmosphere resolution, Express 5 WebApp handlers, lost async context,
|
||||
rawCollection callbacks, meteor/* TypeScript types, useTracker, and
|
||||
useSubscribe. Use this skill when the user asks about upgrading Meteor,
|
||||
async caller propagation, iterators with await, zodern:types, or replacing
|
||||
and forking packages.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.0"
|
||||
area: migration
|
||||
tagline: "Migrate a Meteor 2.x app to 3.x (`callAsync`, async Mongo, Fibers removal, Blaze reactivity, Express 5, Atmosphere resolution)."
|
||||
bundle: ["migration"]
|
||||
docs_synced_at: "2026-08-25"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Migrate a Meteor 2.x application to Meteor 3.x
|
||||
|
||||
Meteor 3 removed Fibers. Server-side Mongo APIs are async. The module system
|
||||
enforces strict mode. Client reactivity inside async code needs care.
|
||||
Atmosphere packages often need forking or replacement. Approach the migration
|
||||
in phases. Do not flip the framework version flag first.
|
||||
|
||||
## Recommended strategy
|
||||
|
||||
1. Update the project to the latest 2.x release.
|
||||
2. Run the app with `WARN_WHEN_USING_OLD_API=true meteor run`. The console
|
||||
logs every sync-API call that needs an async sibling, giving you a
|
||||
to-do list before the framework flip.
|
||||
3. Migrate server-side sync Mongo calls to `*Async` siblings while still
|
||||
on 2.x. Trace each changed function through every server-side caller:
|
||||
await where the caller consumes the value, forward Promises deliberately,
|
||||
and restructure sync-only boundaries. Stop only at an async-capable
|
||||
framework boundary. See `references/async-rewrites.md` and
|
||||
`references/call-vs-callAsync.md`. A community jscodeshift codemod automates
|
||||
the easy cases, but it misses non-standard collection imports (for example,
|
||||
`meteor/<publisher>:collections`). Review the diff by hand, then audit
|
||||
callback Promise ownership and collection argument shapes.
|
||||
4. Audit Atmosphere packages. Find replacements or fork outdated ones;
|
||||
pin `api.versionsFrom(['2.x', '3.0'])`. See
|
||||
`references/package-triage.md`. Save `.meteor/versions` and npm lockfile
|
||||
checkpoints so package-major changes remain distinguishable from Meteor.
|
||||
5. Upgrade to Meteor 3.x.
|
||||
6. Sweep implicit globals; rewrite to `const` or `export` / `import`.
|
||||
See `references/module-system.md`.
|
||||
7. Audit Blaze helpers and `Tracker.autorun` blocks for lost reactivity
|
||||
after `await`. See `references/client-reactivity.md`.
|
||||
8. Replace iterators that contain `await` (`forEach`, `map`, `filter`)
|
||||
with `for...of` or `Promise.all`. See `references/js-iterators.md`.
|
||||
9. Audit publications using internal cursor APIs (`_cursorDescription`,
|
||||
manual `sub.added`) and framework handlers that read invocation `this`.
|
||||
Both synchronous and async publish handlers may return cursors; keep cursor
|
||||
transforms synchronous and use ordinary functions when Meteor must bind
|
||||
`this`. When a package patches `Meteor.publish` with an
|
||||
`EnvironmentVariable`, scope `publish.call` at the wrapper's top level,
|
||||
not inside the invoked handler. Verify invocation context before and after
|
||||
`await`. See `references/publications.md` and
|
||||
`references/other-breaking-changes.md`.
|
||||
10. For TypeScript projects, install `zodern:types` and update
|
||||
`tsconfig.json`. See `references/typescript-migration.md`.
|
||||
11. For React projects, decide whether to adopt the Suspense-aware
|
||||
`react-meteor-data` import. See `references/react-migration.md`, then use
|
||||
`meteor-react` for current hook, scaffold, and build guidance.
|
||||
|
||||
## Symptom router
|
||||
|
||||
| Symptom | Reference |
|
||||
|------------------------------------------------------|----------------------------------------|
|
||||
| `TypeError: Collection.findOne is not a function` | `references/async-rewrites.md` |
|
||||
| `Method returns undefined` or returns a `Promise` | `references/async-rewrites.md` |
|
||||
| Downstream caller receives or reads from a `Promise` | `references/async-rewrites.md` |
|
||||
| Cron, hook, timer, or event callback drops a Promise | `references/async-rewrites.md` |
|
||||
| Read method receives `$set`, `$push`, or another modifier | `references/async-rewrites.md` |
|
||||
| `allow` / `deny` validator needs an async database read | `references/async-rewrites.md` |
|
||||
| `Meteor.call` callback never fires | `references/call-vs-callAsync.md` |
|
||||
| `ReferenceError: X is not defined` at startup | `references/module-system.md` |
|
||||
| Template renders, no data, Minimongo empty | `references/module-system.md` |
|
||||
| Iron Router controller silently does not run | `references/module-system.md` |
|
||||
| `{{> partial}}` renders nothing in Blaze | `references/module-system.md` |
|
||||
| Page renders but live data never updates | `references/client-reactivity.md` |
|
||||
| Blaze helper returns a `Promise` | `references/client-reactivity.md` |
|
||||
| Cursor `transform` errors with "returned a Promise" | `references/publications.md` |
|
||||
| `sub.added` writes never reach the client | `references/publications.md` |
|
||||
| Method or publication loses `this.userId` | `references/publications.md` |
|
||||
| Atmosphere package fails to resolve or build | `references/package-triage.md` |
|
||||
| `forEach`/`map`/`filter` with `await` skips items | `references/js-iterators.md` |
|
||||
| Middleware on `WebApp.connectHandlers` not firing | `references/webapp-express.md` |
|
||||
| Route uses an unnamed wildcard after Meteor 3.1 | `references/webapp-express.md` |
|
||||
| `rawCollection` callback never fires | `references/other-breaking-changes.md` |
|
||||
| Patched publication loses `Meteor.userId()` or async context | `references/other-breaking-changes.md` |
|
||||
| `meteor reset` did not wipe the local Mongo | `references/other-breaking-changes.md` |
|
||||
| `Method stub (X) took too long` console warning | `references/call-vs-callAsync.md` |
|
||||
| "Cannot enlarge memory array" during `meteor update` | `references/other-breaking-changes.md` |
|
||||
| External callback lost `this.userId` or env vars | `references/other-breaking-changes.md` |
|
||||
| Monkey-patched `Meteor.publish` never runs | `references/other-breaking-changes.md` |
|
||||
| `meteor/*` imports resolve to `any` in TypeScript | `references/typescript-migration.md` |
|
||||
| `useTracker` or `useSubscribe` not re-running | `references/react-migration.md` |
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Do not run `meteor update --release=3` first. Async-convert and
|
||||
package-triage on 2.x first.
|
||||
- Do not global-replace `findOne` with `findOneAsync`. Many callers need
|
||||
rewriting, not just `await`.
|
||||
- Do not mechanically rewrite client Minimongo calls to async. Both APIs work
|
||||
on the client. Prefer sync calls in naturally synchronous Blaze and Tracker
|
||||
code; use async calls in shared or already-async flows. Wrap reactive reads
|
||||
after an `await` with `Tracker.withComputation`.
|
||||
- Do not rely on Iron Router controller naming-convention lookup. Pass
|
||||
`controller:` explicitly on every route.
|
||||
- Do not mix `await` and `.then()` in the same function. Pick one.
|
||||
- Do not assume implicit globals work. Every top-level identifier in 3.x
|
||||
must be `const`, `let`, or `export`-ed.
|
||||
- Do not invent async replacements. `Meteor.userId()` remains synchronous
|
||||
inside methods and publications; there is no `Meteor.userIdAsync()`.
|
||||
- Do not use an arrow as a method or publication handler when it reads
|
||||
framework-bound `this`. An arrow ignores the invocation context Meteor
|
||||
supplies.
|
||||
- Do not rewrite `api.addFiles` or `api.export` only because the app moved to
|
||||
Meteor 3. They remain supported for Atmosphere packages.
|
||||
|
||||
## See also
|
||||
|
||||
- Async: `async-rewrites.md`, `call-vs-callAsync.md`, `async-cheatsheet.md`,
|
||||
`js-iterators.md`, `removed-functions.md`.
|
||||
- Runtime: `module-system.md`, `client-reactivity.md`, `publications.md`,
|
||||
`webapp-express.md`, `other-breaking-changes.md`.
|
||||
- Project: `package-triage.md`, `typescript-migration.md`,
|
||||
`react-migration.md`, `eval-cases.md`.
|
||||
- Current Meteor React integration after the upgrade: `meteor-react`.
|
||||
|
||||
## Further reading (optional)
|
||||
|
||||
Real-world migration write-ups for context, not for fixing specific
|
||||
issues. The symptom router above is sufficient on its own. Open
|
||||
`references/community-case-studies.md` only when the user asks for
|
||||
narrative case studies or wants to calibrate effort and timeline.
|
||||
@@ -1,32 +0,0 @@
|
||||
# Async cheatsheet
|
||||
|
||||
Quick lookup for the sync-to-async rewrite Meteor 3 requires on the server.
|
||||
|
||||
| Surface | Sync (2.x, server) | Async (3.x, server) |
|
||||
|------------------------|---------------------------------|-----------------------------------------|
|
||||
| Mongo read | `c.find(q).fetch()` | `await c.find(q).fetchAsync()` |
|
||||
| Mongo single read | `c.findOne(q)` | `await c.findOneAsync(q)` |
|
||||
| Mongo write | `c.insert(d)` | `await c.insertAsync(d)` |
|
||||
| Mongo update | `c.update(q, m)` | `await c.updateAsync(q, m)` |
|
||||
| Mongo delete | `c.remove(q)` | `await c.removeAsync(q)` |
|
||||
| Mongo upsert | `c.upsert(q, m)` | `await c.upsertAsync(q, m)` |
|
||||
| Cursor enumeration | `cursor.forEach(fn)` | `await cursor.forEachAsync(fn)` |
|
||||
| Cursor count | `cursor.count()` | `await cursor.countAsync()` |
|
||||
| Cursor map | `cursor.map(fn)` | `await cursor.mapAsync(fn)` |
|
||||
| RPC | `Meteor.call('m', ...args, cb)` | `await Meteor.callAsync('m', ...args)` |
|
||||
| RPC with options | `Meteor.apply(...)` | `await Meteor.applyAsync(...)` |
|
||||
| User identity (server) | `Meteor.user()` | `await Meteor.userAsync()` |
|
||||
| Accounts create (server) | `Accounts.createUser(o)` | `await Accounts.createUserAsync(o)` |
|
||||
| Accounts password set | `Accounts.setPassword(...)` | `await Accounts.setPasswordAsync(...)` |
|
||||
| Accounts add email | `Accounts.addEmail(uid, addr)` | `await Accounts.addEmailAsync(uid, addr)` |
|
||||
| Email | `Email.send(opts)` | `await Email.sendAsync(opts)` |
|
||||
| Mongo index | `Collection._ensureIndex(spec)` | `await Collection.createIndexAsync(spec)` |
|
||||
| Asset, text | `Assets.getText(path)` | `await Assets.getTextAsync(path)` |
|
||||
| Asset, binary | `Assets.getBinary(path)` | `await Assets.getBinaryAsync(path)` |
|
||||
|
||||
Client Minimongo keeps its synchronous API. Client RPC may still move from a
|
||||
callback to `callAsync`, and `Accounts.createUserAsync` is available, but the
|
||||
callback-shaped client Accounts APIs were not removed.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/migrating-to-async-in-v2/index.md
|
||||
@@ -1,224 +0,0 @@
|
||||
# Sync-to-async rewrite mechanics
|
||||
|
||||
Meteor 3 removed the synchronous Mongo API on the server. Replace each sync
|
||||
Mongo call with its `*Async` sibling. Every caller that consumes the resulting
|
||||
value must await it. A function that only returns the Promise can forward it
|
||||
without adding `async` or `await`. Promise handling propagates up the call stack
|
||||
until it reaches a method, publication, middleware, or another async-capable
|
||||
framework boundary.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Rewrite the leaf server API to its `*Async` sibling.
|
||||
2. Find every caller of the changed function, including indirect callers.
|
||||
3. Caller consumes the resolved value: mark it `async` and add `await`.
|
||||
4. Caller only returns the Promise: return it directly; `return await` is not
|
||||
required unless local error handling needs it.
|
||||
5. Caller is a synchronous-only boundary: restructure it around an async
|
||||
factory, preloaded value, or an async-capable outer boundary.
|
||||
6. Continue until all paths reach a framework boundary that accepts Promises.
|
||||
7. Client-side Minimongo supports both sync and async APIs. Keep sync calls
|
||||
when they simplify naturally synchronous reactive UI code. Use async calls
|
||||
in shared or already-async flows; reactive reads after an `await` require
|
||||
`Tracker.withComputation`. See `client-reactivity.md`.
|
||||
8. Inside a method or publication, prefer `this.userId` over
|
||||
`Meteor.userId()`. The async server context can lose the implicit user.
|
||||
|
||||
## Propagate through the caller chain
|
||||
|
||||
Before migration, each caller receives a resolved value synchronously:
|
||||
|
||||
```javascript
|
||||
function findOrder(id) {
|
||||
return Orders.findOne(id);
|
||||
}
|
||||
|
||||
function calculateTotal(id) {
|
||||
const order = findOrder(id);
|
||||
return order.lines.reduce((total, line) => total + line.amount, 0);
|
||||
}
|
||||
|
||||
function buildInvoice(id) {
|
||||
return { orderId: id, total: calculateTotal(id) };
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
createInvoice(id) {
|
||||
return buildInvoice(id);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
After converting the leaf API, propagate Promise handling through every caller
|
||||
that consumes the result:
|
||||
|
||||
```javascript
|
||||
function findOrder(id) {
|
||||
return Orders.findOneAsync(id);
|
||||
}
|
||||
|
||||
async function calculateTotal(id) {
|
||||
const order = await findOrder(id);
|
||||
return order.lines.reduce((total, line) => total + line.amount, 0);
|
||||
}
|
||||
|
||||
async function buildInvoice(id) {
|
||||
const total = await calculateTotal(id);
|
||||
return { orderId: id, total };
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
async createInvoice(id) {
|
||||
return buildInvoice(id);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
`findOrder` only forwards the Promise, so it does not need the `async` keyword.
|
||||
The next two functions inspect resolved values, so both must be async and await
|
||||
their callees. The method is the framework boundary and can return the final
|
||||
Promise. When independent calls exist at one level, use `Promise.all` instead
|
||||
of introducing unnecessary sequential waits.
|
||||
|
||||
## Synchronous-only boundaries
|
||||
|
||||
Constructors cannot be async. Move loading into an async factory and keep the
|
||||
constructor synchronous:
|
||||
|
||||
```javascript
|
||||
class Invoice {
|
||||
constructor(order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
static async create(orderId) {
|
||||
const order = await Orders.findOneAsync(orderId);
|
||||
return new Invoice(order);
|
||||
}
|
||||
}
|
||||
|
||||
const invoice = await Invoice.create(orderId);
|
||||
```
|
||||
|
||||
Apply the same rule to callbacks. Audit timers, event emitters, streams, cron
|
||||
and queue libraries, hooks, observers, middleware, and package callbacks.
|
||||
Confirm from source or documentation whether the owner awaits a returned
|
||||
Promise. If it does not, handle rejection inside the callback or bridge the work
|
||||
to an awaited application lifecycle. Treat `void task().catch(report)` as
|
||||
intentional fire-and-forget only when the failure policy is explicit. Force one
|
||||
controlled rejection at each critical boundary to verify its behavior.
|
||||
|
||||
## Audit operation semantics after codemods
|
||||
|
||||
Do not validate a mechanical rewrite only by checking that the new method ends
|
||||
in `Async`. Compare the operation and arguments with the original call.
|
||||
|
||||
- Flag read methods such as `findOneAsync` when an options argument contains
|
||||
update operators such as `$set`, `$unset`, `$push`, `$pull`, or `$inc`.
|
||||
- Flag write methods whose selector, modifier, or options shape matches a read.
|
||||
- Flag changed async calls whose Promise is neither awaited, returned, caught,
|
||||
nor deliberately detached with a documented failure policy.
|
||||
- Exercise each changed write path and read the record back from the database.
|
||||
|
||||
Do not auto-edit a computed argument shape that cannot be resolved statically.
|
||||
Report it for review.
|
||||
|
||||
## `allow` and `deny` during a staged migration
|
||||
|
||||
Prefer replacing `Collection.allow` and `Collection.deny` with authenticated
|
||||
methods. When legacy rules must survive, treat them as a version boundary. Keep
|
||||
validators compatible with the active Meteor 2 release during preparation,
|
||||
then convert database reads inside validators to async functions for Meteor 3.
|
||||
Meteor 3 awaits Promise-returning validators, as documented by the
|
||||
[collection API](https://docs.meteor.com/api/collections). Test one allowed and
|
||||
one denied client mutation after the release flip. Validators without database
|
||||
access may remain synchronous.
|
||||
|
||||
## Async framework boundaries
|
||||
|
||||
Meteor methods and publish handlers may return Promises. Meteor also awaits a
|
||||
Promise returned by a server `Meteor.startup` hook. Propagate critical startup
|
||||
work to that boundary instead of starting it and returning `undefined`:
|
||||
|
||||
```javascript
|
||||
Meteor.startup(async () => {
|
||||
try {
|
||||
await Migrations.migrateTo("latest");
|
||||
} catch (error) {
|
||||
console.error("Migration failed", error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Do not catch and swallow a failure that must stop startup. Browser event
|
||||
systems usually do not await an async handler, so catch rejected method calls
|
||||
inside the handler or deliberately forward them to application error state.
|
||||
|
||||
## Server rewrites
|
||||
|
||||
```javascript
|
||||
const doc = await Posts.findOneAsync(id);
|
||||
const list = await Posts.find(q, { fields, sort, limit }).fetchAsync();
|
||||
const _id = await Posts.insertAsync(doc);
|
||||
await Posts.updateAsync(q, mod);
|
||||
await Posts.removeAsync(q);
|
||||
await Posts.upsertAsync(q, mod);
|
||||
```
|
||||
|
||||
Cursor methods on the server are async too:
|
||||
|
||||
```javascript
|
||||
await cursor.forEachAsync(fn);
|
||||
await cursor.mapAsync(fn);
|
||||
await cursor.countAsync();
|
||||
```
|
||||
|
||||
## Iterators with await
|
||||
|
||||
Naive `forEach` / `map` / `filter` callbacks marked `async` do not block the
|
||||
iterator. See `js-iterators.md`.
|
||||
|
||||
## Fibers helpers
|
||||
|
||||
The Fibers-era helpers are gone:
|
||||
|
||||
| Removed | Replacement |
|
||||
|--------------------------|------------------------------------------------------|
|
||||
| `Meteor._sleepForMs(ms)` | `await new Promise(r => setTimeout(r, ms))` |
|
||||
| `Meteor.wrapAsync(fn)` | Call the underlying async API directly. |
|
||||
| `Promise.await(promise)` | `await promise` |
|
||||
| `Future` (`fibers/future`) | The package no longer ships. Refactor to async. |
|
||||
|
||||
## Common errors
|
||||
|
||||
- `TypeError: Collection.findOne is not a function`: server-side sync API
|
||||
removed. Use `findOneAsync` and `await`.
|
||||
- Application code receives a Promise where it expects a document: the
|
||||
consuming caller is not awaiting. Mark that caller `async` and await the
|
||||
call.
|
||||
- `Meteor.call` returns `undefined` on the client: use
|
||||
`await Meteor.callAsync(...)` or provide a callback.
|
||||
- `ReferenceError: Fiber is not defined`: a package or app file still
|
||||
references Fibers. Remove the dependency and rewrite the function.
|
||||
|
||||
## HTTP and timers
|
||||
|
||||
`HTTP.get`/`HTTP.post` are removed. Use native `fetch`:
|
||||
|
||||
```javascript
|
||||
const res = await fetch(url, { headers });
|
||||
const data = await res.json();
|
||||
```
|
||||
|
||||
Fetch resolves for HTTP error statuses. Check `res.ok` or the expected status
|
||||
before treating the request as successful. Review body serialization, response
|
||||
parsing, redirects, cookies, timeout or cancellation via `AbortSignal`, proxy
|
||||
behavior, and custom TLS or CA configuration. Preserve the error contract that
|
||||
callers expect. Test success, non-2xx, malformed response, and network failure.
|
||||
|
||||
`Meteor.defer(fn)` for fire-and-forget work survives, but for bulk fan-out
|
||||
prefer `await Promise.all(items.map(processOne))`.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/migrating-to-async-in-v2/index.md
|
||||
@@ -1,77 +0,0 @@
|
||||
# `Meteor.call` vs `Meteor.callAsync`
|
||||
|
||||
In Meteor 2.x, `Meteor.call('name', ...args, callback)` was the canonical client
|
||||
invocation. In Meteor 3.x, prefer `Meteor.callAsync('name', ...args)`, which
|
||||
returns a `Promise`.
|
||||
|
||||
## Client-side rewrites
|
||||
|
||||
| 2.x | 3.x |
|
||||
|--------------------------------------------------|------------------------------------------------------|
|
||||
| `Meteor.call('m', a, b, (err, res) => ...)` | `try { const res = await Meteor.callAsync('m', a, b) } catch (err) { ... }` |
|
||||
| `Meteor.call('m', a, b)` (fire-and-forget) | `Meteor.callAsync('m', a, b).catch(console.error)` |
|
||||
| `Meteor.apply('m', args, opts, cb)` | `await Meteor.applyAsync('m', args, opts)` |
|
||||
|
||||
## Server-side rewrites
|
||||
|
||||
On the server, `Meteor.call` runs inline (no DDP round trip). Use `callAsync`
|
||||
for consistency and to make the call site `await`-able.
|
||||
|
||||
## Optimistic UI
|
||||
|
||||
`callAsync` participates in latency compensation the same way `call` did. If
|
||||
the method has a client-side stub, the stub runs immediately and the local
|
||||
collection writes are visible before the server round trip resolves.
|
||||
|
||||
## Error shape
|
||||
|
||||
Intentional client-visible server failures should throw `Meteor.Error`, whose
|
||||
rejection exposes `.error`, `.reason`, and `.details`. Do not assume every
|
||||
rejection has that shape. A local stub exception, API misuse, or transport
|
||||
failure can produce a native or arbitrary error. Narrow the value first:
|
||||
|
||||
```javascript
|
||||
try {
|
||||
await Meteor.callAsync('orders.create', input);
|
||||
} catch (error) {
|
||||
if (error && typeof error === 'object' && 'error' in error) {
|
||||
reportMeteorError(error.error, error.reason, error.details);
|
||||
} else {
|
||||
reportUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## When to keep `Meteor.call`
|
||||
|
||||
Only when interoperating with a library that requires a callback. New code
|
||||
should always use `callAsync`.
|
||||
|
||||
## Method stub macrotask ban
|
||||
|
||||
In Meteor 3 the client-side stub of a method must complete within one
|
||||
microtask tick. The runtime watches for stubs that yield to a macrotask
|
||||
and logs:
|
||||
|
||||
```
|
||||
Method stub (<method name>) took too long and could cause unexpected problems.
|
||||
```
|
||||
|
||||
These APIs are banned inside a stub body:
|
||||
|
||||
- `fetch` and `XMLHttpRequest`
|
||||
- `setTimeout`, `setInterval`, `setImmediate`
|
||||
- `indexedDB`
|
||||
- Web Workers and `Worker.postMessage`
|
||||
|
||||
Async stubs are supported. They may await work that settles without yielding
|
||||
to a browser macrotask, including `*Async` Minimongo writes used by a shared
|
||||
client/server method definition. Do external I/O after `callAsync` resolves.
|
||||
Keep the stub limited to deterministic local state changes.
|
||||
|
||||
Symptom: the optimistic update flashes (the local write is reverted)
|
||||
even though the server method succeeds. The stub yielded to a macrotask
|
||||
and Meteor discarded its writes.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/breaking-changes/call-x-callAsync.md
|
||||
@@ -1,148 +0,0 @@
|
||||
# Client reactivity inside async code
|
||||
|
||||
In Meteor 2.x, `Collection.findOne` on the client was synchronous and
|
||||
reactive. Inside a Blaze helper or `Tracker.autorun`, calling it registered
|
||||
a dependency that re-ran the computation when the underlying data changed.
|
||||
|
||||
In Meteor 3.x the sync Minimongo API still exists on the client, and the
|
||||
`*Async` siblings (`findOneAsync`, `fetchAsync`) also work there. A reactive
|
||||
read executed before the first `await`, including the first async query, can
|
||||
register a Tracker dependency. Code after an `await` loses
|
||||
`Tracker.currentComputation` unless the reactive read is wrapped with
|
||||
`Tracker.withComputation`.
|
||||
|
||||
## The trap
|
||||
|
||||
```javascript
|
||||
// BROKEN: the reactive query runs after an await without its computation.
|
||||
Template.profile.helpers({
|
||||
async user() {
|
||||
await Meteor.callAsync('profiles.prepare', this.userId);
|
||||
return Meteor.users.findOneAsync(this.userId);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Blaze can unwrap the returned Promise, but the query runs after the first
|
||||
`await`. It cannot register the helper's Tracker dependency, so subsequent
|
||||
document changes do not re-run the helper.
|
||||
|
||||
## The rule
|
||||
|
||||
On the server, use the `*Async` API. On the client, choose based on the calling
|
||||
code:
|
||||
|
||||
- Prefer sync Minimongo in naturally synchronous Blaze helpers, render paths,
|
||||
and Tracker computations. It avoids Promise state and unnecessary async
|
||||
propagation while retaining normal reactivity.
|
||||
- Prefer async Minimongo in shared client/server modules and code that is
|
||||
already async.
|
||||
- A reactive query before the first `await` can register dependencies. Wrap
|
||||
each reactive query after an `await` with `Tracker.withComputation`.
|
||||
|
||||
```javascript
|
||||
// Simple and reactive: sync Minimongo in synchronous UI code.
|
||||
Template.profile.helpers({
|
||||
user() {
|
||||
return Meteor.users.findOne(this.userId);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Async helpers that need reactivity
|
||||
|
||||
An async Minimongo call made before any `await` can also be reactive:
|
||||
|
||||
```javascript
|
||||
Tracker.autorun(async () => {
|
||||
const users = await Meteor.users.find().fetchAsync();
|
||||
renderUsers(users);
|
||||
});
|
||||
```
|
||||
|
||||
If unrelated async work happens first, save the computation and restore it
|
||||
around the later reactive read:
|
||||
|
||||
```javascript
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
|
||||
Template.profile.helpers({
|
||||
enriched() {
|
||||
const computation = Tracker.currentComputation;
|
||||
return (async () => {
|
||||
const more = await Meteor.callAsync('users.enrich', this.userId);
|
||||
const doc = await Tracker.withComputation(
|
||||
computation,
|
||||
() => Meteor.users.findOneAsync(this.userId),
|
||||
);
|
||||
return { ...doc, ...more };
|
||||
})();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Code before the first `await` keeps the current computation. Code after it does
|
||||
not. Wrap only the reactive reads that need the saved computation;
|
||||
`Tracker.withComputation` has a performance cost.
|
||||
|
||||
## Blaze async helpers (Blaze 2.7+)
|
||||
|
||||
Blaze 2.7+ understands Promises returned by helpers and exposes three
|
||||
state directives inside `{{#let}}`:
|
||||
|
||||
- `@resolved "<name>"`: true once the named `let` binding has settled.
|
||||
- `@pending "<name>"`: true while the named `let` binding is still
|
||||
awaiting.
|
||||
- `@rejected "<name>"`: true if the named `let` binding threw or its
|
||||
Promise rejected.
|
||||
|
||||
```handlebars
|
||||
{{#let user=getUserAsync}}
|
||||
{{#if @pending "user"}}<Spinner />{{/if}}
|
||||
{{#if @rejected "user"}}<Error msg="Could not load user" />{{/if}}
|
||||
{{#if @resolved "user"}}
|
||||
{{> profile data=user}}
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
```
|
||||
|
||||
This gives the same surface as React Suspense: a spinner during the
|
||||
await, an error region on rejection, the resolved value once ready.
|
||||
|
||||
## Async iteration in Blaze
|
||||
|
||||
`{{#each}}` accepts an async helper that returns a Promise of an array
|
||||
or cursor. Pair it with `{{else}}` for an empty-state branch:
|
||||
|
||||
```handlebars
|
||||
{{#each user in getUsersAsync}}
|
||||
{{> userRow user=user}}
|
||||
{{else}}
|
||||
<p>No users yet.</p>
|
||||
{{/each}}
|
||||
```
|
||||
|
||||
The minimum Blaze version for these directives is 2.7. If your project
|
||||
pins an older Blaze, upgrade `blaze-html-templates` and the
|
||||
`blaze` runtime packages before relying on `@pending`/`@rejected`.
|
||||
|
||||
## Symptoms
|
||||
|
||||
- Page renders correctly on initial load. Subsequent changes to the data
|
||||
never appear. A reactive query runs after an `await` without
|
||||
`Tracker.withComputation`.
|
||||
- A Blaze partial logs `[object Promise]` instead of the value. The helper
|
||||
returned a Promise without `@resolved` gating.
|
||||
- `Tracker.autorun` runs once. Subsequent invalidations are silent. Its
|
||||
reactive reads occur only after an `await` without restoring the
|
||||
computation.
|
||||
|
||||
## Two-phase data patterns
|
||||
|
||||
When a publication ships a base document and a second subscription
|
||||
enriches it, the enrichment runs in a separate `Tracker.autorun`. Keep
|
||||
both reads sync (minimongo) inside the helper. Use the explicit
|
||||
`Meteor.subscribe` handle and `subscription.ready()` to gate rendering.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/front-end/blaze.md
|
||||
@@ -1,76 +0,0 @@
|
||||
# Community case studies
|
||||
|
||||
Real-world Meteor 2.x to 3.x migration write-ups. Skim these to calibrate
|
||||
effort, anticipate edge cases, and cross-check the patterns documented in
|
||||
this skill's other references. Each entry notes which failure modes it
|
||||
covers and which references in this skill expand on them.
|
||||
|
||||
## Production Blaze app on Meteor 3.4 with Rspack
|
||||
|
||||
[Migrating a Production Blaze App from Meteor 2 to 3.4 with Rspack](https://blog.galaxycloud.app/meteorjs-2-to-3-blaze-migration-rspack/)
|
||||
on the Galaxy blog.
|
||||
|
||||
Covers: incremental migration into a fresh Meteor 3 project, local packages
|
||||
first, the Iron Router controller silent-failure trap, implicit-global
|
||||
sweep with a grep recipe, lost reactivity inside async Blaze helpers,
|
||||
publication cursor internals (`_cursorDescription`), iterators with
|
||||
`await`, and per-package replacement strategy. The author also reports
|
||||
roughly halved bundle size after the Rspack switch.
|
||||
|
||||
Maps to: `module-system.md`, `client-reactivity.md`, `publications.md`,
|
||||
`js-iterators.md`, `package-triage.md`.
|
||||
|
||||
## Solo developer migration over 18 months
|
||||
|
||||
[Migrating to Meteor 3: a solo developer story](https://dev.to/meteor/migrating-to-meteor-3-a-solo-developer-story-1nek)
|
||||
on the Meteor publication on dev.to.
|
||||
|
||||
Covers: a phased two-stage plan (pre-upgrade async sweep plus unit-test
|
||||
harness, then post-upgrade dependency reinstall and integration tests),
|
||||
isomorphic-code segregation patterns (server-only vs client-only helpers),
|
||||
auto-generated test seeding from schema metadata, package fork inventory,
|
||||
and the Tracker reactivity-after-`await` pattern using
|
||||
`Tracker.withComputation`. Useful as a worked example of test-first
|
||||
migration strategy.
|
||||
|
||||
Maps to: `async-rewrites.md`, `client-reactivity.md`, `package-triage.md`.
|
||||
|
||||
## Gradual upgrade strategy and dependency triage
|
||||
|
||||
[Gradually upgrading a Meteor.js project to 3.0](https://dev.to/meteor/gradually-upgrading-a-meteorjs-project-to-30-5aj0)
|
||||
on the Meteor publication on dev.to.
|
||||
|
||||
Covers: an explicit generic strategy (branch hygiene, prepare project
|
||||
structure, update on 2.x first, then per-package triage), the
|
||||
clone-into-`lib`-and-link-into-`packages` workflow, `api.versionsFrom`
|
||||
dual-version pinning, and the multi-version `api.use('mongo@1.16.0 || 2.0.0')`
|
||||
syntax.
|
||||
|
||||
Maps to: `package-triage.md` (the most directly relevant), plus the
|
||||
strategy phases in the top-level `SKILL.md`.
|
||||
|
||||
## Large-team migration over a year
|
||||
|
||||
[The Meteor 3.0 Migration: A Space Exploration Mission](https://dev.to/meteor/the-meteor-30-migration-a-space-exploration-mission-3gb5)
|
||||
on the Meteor publication on dev.to.
|
||||
|
||||
Covers: ecosystem-wide migration coordination (which packages had to ship
|
||||
3.x releases before app code could move), keeping critical cornerstone
|
||||
packages on a working version even if it means temporarily disabling
|
||||
features, the value of a robust test suite when introducing many small
|
||||
PRs in sequence, and a deployment-time MINISAT memory error that surfaces
|
||||
when a large app tries to run `meteor update --release=3` straight from
|
||||
2.x. Reinforces the rule: do not flip the version flag first.
|
||||
|
||||
Maps to: `package-triage.md`, the strategy section of `SKILL.md`.
|
||||
|
||||
## How to use these
|
||||
|
||||
Read in this order when planning a migration:
|
||||
|
||||
1. Start with the gradual-upgrade article for the high-level strategy.
|
||||
2. Read the solo-developer story for the test-first angle.
|
||||
3. Read the production-Blaze article for the implicit-global, Iron Router,
|
||||
and Rspack details.
|
||||
4. Read the space-mission article last to set expectations for
|
||||
ecosystem-level coordination on large apps.
|
||||
@@ -1,405 +0,0 @@
|
||||
# Evaluation cases for `migrate-to-meteor-3`
|
||||
|
||||
A human runs these prompts against Claude Code and Cursor with the skill
|
||||
installed and verifies the agent loads the skill and produces the expected
|
||||
output.
|
||||
|
||||
## Case 1: missing await on server-side find
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
I just upgraded to Meteor 3. This method returns undefined on the server,
|
||||
but it worked in 2.x:
|
||||
|
||||
Meteor.methods({
|
||||
listPosts() {
|
||||
return Posts.find({ published: true }).fetch();
|
||||
},
|
||||
});
|
||||
|
||||
What did I miss?
|
||||
```
|
||||
|
||||
Pass if the agent suggests `await Posts.find(...).fetchAsync()` and marks
|
||||
the method `async`. Bonus pass if the agent points at
|
||||
`references/async-rewrites.md`.
|
||||
|
||||
## Case 2: implicit global ReferenceError
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
After updating to Meteor 3 my server crashes on boot with
|
||||
ReferenceError: PostsShowController is not defined. The file that defines
|
||||
it just has `PostsShowController = RouteController.extend({...})` at the top.
|
||||
```
|
||||
|
||||
Pass if the agent identifies the implicit-global pattern, suggests
|
||||
`const PostsShowController = ...` (or `export`), and points at
|
||||
`references/module-system.md`.
|
||||
|
||||
## Case 3: Iron Router silent failure
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
Some of my Iron Router routes load the template but the data is missing.
|
||||
No errors. The publication never starts. I'm on Meteor 3.
|
||||
```
|
||||
|
||||
Pass if the agent identifies the controller naming-convention lookup
|
||||
breakage and suggests adding `controller: <Name>` explicitly to the
|
||||
route definition.
|
||||
|
||||
## Case 4: lost reactivity after async helper rewrite
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
After migrating this Blaze helper, the page renders once and never updates
|
||||
when the underlying user document changes:
|
||||
|
||||
async user() {
|
||||
await Meteor.callAsync('profiles.prepare', this.userId);
|
||||
return Meteor.users.findOneAsync(this.userId);
|
||||
}
|
||||
```
|
||||
|
||||
Pass if the agent explains that client Minimongo supports both sync and async
|
||||
APIs, and that the query loses the computation because it runs after the first
|
||||
`await`. Accept either simplifying the helper to synchronous Minimongo when
|
||||
the preparation step is unnecessary, or wrapping the later query with
|
||||
`Tracker.withComputation`. Fail if it claims all async Minimongo queries are
|
||||
nonreactive.
|
||||
|
||||
## Case 5: forEach with await skips items
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
This loop runs but my insertedIds is empty afterwards:
|
||||
|
||||
const insertedIds = [];
|
||||
items.forEach(async (item) => {
|
||||
const id = await Items.insertAsync(item);
|
||||
insertedIds.push(id);
|
||||
});
|
||||
return insertedIds;
|
||||
```
|
||||
|
||||
Pass if the agent identifies that `forEach` does not await the callback,
|
||||
and rewrites to `for...of` or `Promise.all`.
|
||||
|
||||
## Case 6: cursor transform errors out
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
My publication errors with "publish function returned a Promise":
|
||||
|
||||
Meteor.publish('feed', function () {
|
||||
return Posts.find({}, { transform: async (doc) => {
|
||||
doc.author = await Users.findOneAsync(doc.authorId);
|
||||
return doc;
|
||||
}});
|
||||
});
|
||||
```
|
||||
|
||||
Pass if the agent calls out that cursor `transform` must be synchronous
|
||||
and proposes either a separate publication for users or the low-level
|
||||
publish API.
|
||||
|
||||
## Case 7: Atmosphere package fails to resolve
|
||||
|
||||
Prompt:
|
||||
|
||||
```
|
||||
After `meteor update --release=3` my build fails because
|
||||
old-atmosphere-package needs api.versionsFrom('1.5') and there is no
|
||||
3.x-compatible version on Packosphere.
|
||||
```
|
||||
|
||||
Pass if the agent walks through the triage matrix (replace, fork, remove)
|
||||
and describes how to fork minimally, update `api.versionsFrom`, and link
|
||||
from `lib/` into `packages/`.
|
||||
|
||||
## Case 8: async propagation through callers
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
function findOrder(id) {
|
||||
return Orders.findOne(id);
|
||||
}
|
||||
|
||||
function calculateTotal(id) {
|
||||
return findOrder(id).total;
|
||||
}
|
||||
|
||||
function buildInvoice(id) {
|
||||
return { total: calculateTotal(id) };
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
createInvoice(id) {
|
||||
return buildInvoice(id);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
"Migrate this call chain to Meteor 3. Do not change only the Mongo call."
|
||||
|
||||
Pass if the agent traces the complete caller chain, replaces `findOne` with
|
||||
`findOneAsync`, awaits the result before reading `.total`, propagates Promise
|
||||
handling through `buildInvoice`, and stops at the method boundary. Accept
|
||||
direct Promise forwarding where no resolved value is consumed. Fail if any
|
||||
caller still treats a Promise as the resolved value.
|
||||
|
||||
## Case 9: synchronous constructor boundary
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
class Invoice {
|
||||
constructor(orderId) {
|
||||
this.order = Orders.findOne(orderId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
"Migrate this class to Meteor 3 while preserving construction correctness."
|
||||
|
||||
Pass if the agent does not mark the constructor async. It must introduce an
|
||||
async factory or require a preloaded order, await `findOneAsync` outside the
|
||||
constructor, and keep object construction synchronous.
|
||||
|
||||
## Case 10: async publication returning a cursor
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
Meteor.publish("posts.byTeam", async function (teamId) {
|
||||
const member = await Memberships.findOneAsync({ teamId, userId: this.userId });
|
||||
if (!member) return this.ready();
|
||||
return Posts.find({ teamId });
|
||||
});
|
||||
```
|
||||
|
||||
"Does returning this Promise break the publication in Meteor 3?"
|
||||
|
||||
Pass if the agent says the async handler is supported and Meteor awaits it
|
||||
before processing the cursor. Fail if it requires the low-level publish API
|
||||
only because the handler returns a Promise.
|
||||
|
||||
## Case 11: userId outside an invocation
|
||||
|
||||
Prompt: "A background job calls `Meteor.userId()` and throws. Should I replace
|
||||
it with `await Meteor.userIdAsync()`?"
|
||||
|
||||
Pass if the agent states that `Meteor.userIdAsync()` does not exist, explains
|
||||
that `Meteor.userId()` reads method/publication invocation context, and passes
|
||||
the user ID explicitly into the background job.
|
||||
|
||||
## Case 12: client Accounts callback locus
|
||||
|
||||
Prompt: "After moving to Meteor 3.4, must I replace client
|
||||
`Accounts.createUser(options, callback)` and
|
||||
`Meteor.loginWithPassword(user, password, callback)`?"
|
||||
|
||||
Pass if the agent says both callback forms remain supported on the client,
|
||||
mentions `Accounts.createUserAsync`, and does not suggest
|
||||
`Meteor.loginWithPasswordAsync` before Meteor 3.5.
|
||||
|
||||
## Case 13: Atmosphere package file APIs
|
||||
|
||||
Prompt: "My Meteor 3 package still uses `api.addFiles` and `api.export`. Are
|
||||
those APIs removed, and must I convert it to `api.mainModule`?"
|
||||
|
||||
Pass if the agent says all three APIs remain supported, treats
|
||||
`api.mainModule` as a modular design choice, and avoids an unnecessary
|
||||
rewrite.
|
||||
|
||||
## Case 14: startup migration propagation
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
Meteor.startup(() => {
|
||||
Migrations.migrateTo("latest").catch(console.error);
|
||||
});
|
||||
```
|
||||
|
||||
"Why can requests run before the migration finishes?"
|
||||
|
||||
Pass if the agent returns or awaits the migration Promise from the startup
|
||||
hook and does not swallow a migration failure that should stop startup.
|
||||
|
||||
## Case 15: scheduler discards a Promise
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
cron.schedule("0 * * * *", () => {
|
||||
runCleanupAsync();
|
||||
});
|
||||
```
|
||||
|
||||
"The cleanup rejects, but my local try/catch never sees it and the process
|
||||
sometimes exits. Is marking the callback async enough?"
|
||||
|
||||
Pass if the agent checks whether this scheduler observes returned Promises,
|
||||
requires explicit rejection handling when it does not, and proposes forcing a
|
||||
rejection to validate the failure policy. Fail if it adds `async` without
|
||||
examining the callback contract.
|
||||
|
||||
## Case 16: semantically wrong async rewrite
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
await Meteor.users.findOneAsync(
|
||||
{ "services.ldap.id": ldapId },
|
||||
{ $set: { username } },
|
||||
);
|
||||
```
|
||||
|
||||
"This was produced while converting Mongo calls for Meteor 3. It runs without
|
||||
a syntax error, but the username is unchanged."
|
||||
|
||||
Pass if the agent identifies that a read API was given an update modifier,
|
||||
rewrites it to the appropriate `updateAsync` operation, and reads the document
|
||||
back in the validation. Fail if it treats the `Async` suffix as sufficient.
|
||||
|
||||
## Case 17: database-backed allow rule
|
||||
|
||||
Prompt: "A legacy `Collection.allow` rule performs a server database lookup.
|
||||
Can I keep it while moving from Meteor 2.16 to Meteor 3.4?"
|
||||
|
||||
Pass if the agent prefers a method migration, distinguishes the Meteor 2
|
||||
preparation stage from the Meteor 3 boundary, confirms that Meteor 3 awaits an
|
||||
async validator, and tests both an allowed and denied client mutation.
|
||||
|
||||
## Case 18: arrow handler loses invocation context
|
||||
|
||||
Prompt:
|
||||
|
||||
```javascript
|
||||
Meteor.publish('items.mine', () => {
|
||||
if (!this.userId) return this.ready();
|
||||
return Items.find({ ownerId: this.userId });
|
||||
});
|
||||
```
|
||||
|
||||
"The publication compiles after the Meteor 3 migration, but every subscriber
|
||||
looks logged out. Should I replace every arrow inside the function?"
|
||||
|
||||
Pass if the agent changes the outer publication handler to an ordinary
|
||||
function, explains that Meteor supplies its invocation context through `this`,
|
||||
and preserves nested arrows that intentionally capture that context. It must
|
||||
validate authenticated and unauthenticated subscriptions. Fail if it rewrites
|
||||
all arrows indiscriminately or replaces `this.userId` with a nonexistent async
|
||||
API.
|
||||
|
||||
## Case 19: callback RPC to `callAsync`
|
||||
|
||||
Prompt: "Migrate this client call without losing its error handling:
|
||||
`Meteor.call('orders.create', input, (error, id) => saveResult(error, id))`."
|
||||
|
||||
Pass if the agent uses `await Meteor.callAsync` inside `try`/`catch`, passes the
|
||||
resolved ID to the success path, and passes the rejection to the existing
|
||||
error path. It should keep `Meteor.call` only when a callback-only consumer
|
||||
requires it.
|
||||
|
||||
## Case 20: Express 5 WebApp route
|
||||
|
||||
Prompt: "After Meteor 3.1, my `WebApp.connectHandlers` route with `/files/*`
|
||||
stopped matching. Migrate it to the current API."
|
||||
|
||||
Pass if the agent moves new code to `WebApp.handlers`, replaces the unnamed
|
||||
wildcard with an Express 5 named wildcard, and preserves middleware order.
|
||||
Fail if it says the deprecated alias was removed outright.
|
||||
|
||||
## Case 21: async EnvironmentVariable wrapper
|
||||
|
||||
Prompt: "A Meteor 2 package patches `Meteor.publish` by nesting
|
||||
`EnvironmentVariable.withValue` inside the publication handler. After moving
|
||||
to Meteor 3, code after an `await` loses the `Meteor.userId()` publication
|
||||
context. Diagnose it and update the wrapper to the current v3-docs placement."
|
||||
|
||||
Pass if the agent places `withValue` at the patch wrapper's top level around
|
||||
the original `publish.call`, returns the scoped result, and leaves the invoked
|
||||
handler to call the original function without another `withValue`. It must
|
||||
validate `Meteor.userId()` or the publication invocation before and after an
|
||||
`await`. Fail if it keeps the nested scope inside the invoked handler.
|
||||
|
||||
## Case 22: raw Mongo callback
|
||||
|
||||
Prompt: "This Meteor 2 code never calls its callback on Meteor 3:
|
||||
`Posts.rawCollection().findOne({ _id }, callback)`."
|
||||
|
||||
Pass if the agent explains that MongoDB driver 6 removed callback overloads
|
||||
and rewrites the operation to `await Posts.rawCollection().findOne({ _id })`
|
||||
with `try`/`catch` at the owning async boundary.
|
||||
|
||||
## Case 23: Meteor TypeScript imports become `any`
|
||||
|
||||
Prompt: "After moving to Meteor 3, every `meteor/*` TypeScript import is `any`
|
||||
and the editor reports duplicate identifiers."
|
||||
|
||||
Pass if the agent adds `zodern:types`, enables `preserveSymlinks`, maps
|
||||
`meteor/*` to `.meteor/local/types/packages.d.ts`, and restarts the TypeScript
|
||||
server. It must keep generated types out of source control.
|
||||
|
||||
## Case 24: React Suspense is optional
|
||||
|
||||
Prompt: "Must every Meteor 3 React component switch from
|
||||
`meteor/react-meteor-data` to the `/suspense` import?"
|
||||
|
||||
Pass if the agent says the classic hooks remain supported, requires an
|
||||
upstream Suspense boundary only when choosing the suspense import, and uses a
|
||||
stable key for suspense `useTracker`. It must inspect `.meteor/versions`, note
|
||||
that Suspense began in `react-meteor-data` 2.7.0 and Meteor 3 compatibility in
|
||||
3.0.0, and prefer 3.0.0+ for the migrated app. If it converts `useFind`, it
|
||||
must change the signature. Fail if it rewrites every client Minimongo read to
|
||||
an async API or claims async reads always lose reactivity.
|
||||
|
||||
## Case 25: `bindEnvironment` capture timing
|
||||
|
||||
Prompt: "A global event emitter is wrapped with `Meteor.bindEnvironment` at
|
||||
server startup. Later, events created by logged-in methods still see no
|
||||
`Meteor.userId()`. Why?"
|
||||
|
||||
Pass if the agent explains that the wrapper captured the startup environment,
|
||||
not a future method invocation. It should pass `this.userId` explicitly in the
|
||||
event/job data or create the wrapper inside the invocation. It must not claim
|
||||
that `bindEnvironment` invents invocation context or changes arrow-function
|
||||
`this`.
|
||||
|
||||
## Case 26: non-Meteor `callAsync` rejection
|
||||
|
||||
Prompt: "After migrating to `callAsync`, a client stub throws `TypeError` and
|
||||
the catch block fails again while reading `error.error`."
|
||||
|
||||
Pass if the agent keeps `Meteor.Error` for intentional server-visible failures
|
||||
but explains that local, misuse, and transport rejections may have another
|
||||
shape. It must narrow the caught value before reading Meteor-specific fields.
|
||||
|
||||
## Case 27: installer alternative
|
||||
|
||||
Prompt: "Our Linux setup uses `curl https://install.meteor.com/ | sh`. Must we
|
||||
replace it because Meteor 3 phased it out?"
|
||||
|
||||
Pass if the agent says `npx meteor` is the primary cross-platform command but
|
||||
curl remains a documented Linux and macOS alternative. It checks the selected
|
||||
CLI's host Node prerequisite and does not add the installer to project
|
||||
dependencies.
|
||||
|
||||
## Case 28: fresh CLI installation near miss
|
||||
|
||||
Prompt: "There is no Meteor application yet. Install the Meteor 3 CLI on this
|
||||
new Windows workstation and make sure PATH works."
|
||||
|
||||
Pass if the agent routes the fresh workstation and PATH workflow to
|
||||
`meteor-cli-installation`. Fail if it starts an application code migration or
|
||||
offers the Linux and macOS shell installer on Windows.
|
||||
@@ -1,122 +0,0 @@
|
||||
# Iterators with `await`
|
||||
|
||||
Naive `Array.prototype.forEach`, `Array.prototype.map`, `Array.prototype.filter`,
|
||||
and `Array.prototype.find` do **not** make their containing function async
|
||||
just because the callback is marked `async`. The iterator returns synchronously;
|
||||
the callback's Promise is discarded.
|
||||
|
||||
## `forEach`
|
||||
|
||||
```javascript
|
||||
// BROKEN: returns before any awaited work resolves
|
||||
items.forEach(async (item) => {
|
||||
await processItem(item);
|
||||
});
|
||||
```
|
||||
|
||||
Replace with `for...of`:
|
||||
|
||||
```javascript
|
||||
for (const item of items) {
|
||||
await processItem(item);
|
||||
}
|
||||
```
|
||||
|
||||
This runs the items serially. If order does not matter and you want
|
||||
concurrency, use `Promise.all`:
|
||||
|
||||
```javascript
|
||||
await Promise.all(items.map((item) => processItem(item)));
|
||||
```
|
||||
|
||||
## `map`
|
||||
|
||||
```javascript
|
||||
// BROKEN: result is an array of Promises, not values
|
||||
const ids = users.map(async (u) => await Users.insertAsync(u));
|
||||
```
|
||||
|
||||
Two correct shapes:
|
||||
|
||||
```javascript
|
||||
// concurrent
|
||||
const ids = await Promise.all(
|
||||
users.map((u) => Users.insertAsync(u)),
|
||||
);
|
||||
|
||||
// serial
|
||||
const ids = [];
|
||||
for (const u of users) {
|
||||
ids.push(await Users.insertAsync(u));
|
||||
}
|
||||
```
|
||||
|
||||
For large arrays, prefer the serial form to avoid hammering Mongo with N
|
||||
parallel writes.
|
||||
|
||||
## `filter`
|
||||
|
||||
`Array.prototype.filter` cannot be awaited. Two patterns:
|
||||
|
||||
```javascript
|
||||
// concurrent then prune
|
||||
const checks = await Promise.all(
|
||||
items.map(async (it) => ({ it, keep: await predicate(it) })),
|
||||
);
|
||||
const kept = checks.filter((c) => c.keep).map((c) => c.it);
|
||||
|
||||
// serial
|
||||
const kept = [];
|
||||
for (const it of items) {
|
||||
if (await predicate(it)) kept.push(it);
|
||||
}
|
||||
```
|
||||
|
||||
## `find`
|
||||
|
||||
```javascript
|
||||
// BROKEN
|
||||
const hit = items.find(async (it) => await match(it));
|
||||
```
|
||||
|
||||
Replace with `for...of`:
|
||||
|
||||
```javascript
|
||||
let hit;
|
||||
for (const it of items) {
|
||||
if (await match(it)) {
|
||||
hit = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `reduce`
|
||||
|
||||
Reduce with an async callback usually wants an accumulator that is itself
|
||||
a Promise:
|
||||
|
||||
```javascript
|
||||
// serial reduce
|
||||
const sum = await items.reduce(async (accP, item) => {
|
||||
const acc = await accP;
|
||||
return acc + await score(item);
|
||||
}, Promise.resolve(0));
|
||||
```
|
||||
|
||||
For readability, prefer `for...of` with an explicit accumulator.
|
||||
|
||||
## Cursor methods are different
|
||||
|
||||
Meteor cursor iterators on the server already have async siblings. Use
|
||||
those instead of converting a `cursor.fetch()` array to a Promise loop:
|
||||
|
||||
```javascript
|
||||
await cursor.forEachAsync(async (doc) => { /* ... */ });
|
||||
const mapped = await cursor.mapAsync(async (doc) => { /* ... */ });
|
||||
```
|
||||
|
||||
These properly await each callback.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/migrating-to-async-in-v2/index.md
|
||||
@@ -1,119 +0,0 @@
|
||||
# Module system, strict mode, implicit globals
|
||||
|
||||
Meteor 3 enforces ES module semantics on every file that uses `import`,
|
||||
`export`, or top-level `await`. Strict mode is the default. Implicit
|
||||
file-scoped globals (assignment without `var` / `let` / `const`) no longer
|
||||
become visible to other files. Apps that relied on the pre-1.7 eager-loading
|
||||
behavior surface a lot of `ReferenceError: X is not defined` at startup.
|
||||
|
||||
## The implicit-global pattern
|
||||
|
||||
Pre-3 Meteor allowed:
|
||||
|
||||
```javascript
|
||||
// pre-3: visible to every file that loaded later
|
||||
PostsShowController = RouteController.extend({ /* ... */ });
|
||||
Search = { query: function () { /* ... */ } };
|
||||
SearchResults = function (params) { /* ... */ };
|
||||
```
|
||||
|
||||
After the upgrade, every line above throws `ReferenceError` at runtime.
|
||||
|
||||
## The fix
|
||||
|
||||
For file-local symbols, declare with `const` / `let`:
|
||||
|
||||
```javascript
|
||||
const PostsShowController = RouteController.extend({ /* ... */ });
|
||||
const Search = { query: async function () { /* ... */ } };
|
||||
```
|
||||
|
||||
For symbols shared across files, export and import:
|
||||
|
||||
```javascript
|
||||
// lib/search-results.js
|
||||
export function SearchResults(params) { /* ... */ }
|
||||
|
||||
// client/main.js
|
||||
import { SearchResults } from '../lib/search-results';
|
||||
```
|
||||
|
||||
## Finding the offenders
|
||||
|
||||
Grep for assignments at the start of a line that start with a capital letter
|
||||
and have no declaration:
|
||||
|
||||
```bash
|
||||
grep -nE '^[A-Z][A-Za-z0-9_]+ = ' -- 'client/**/*.js' 'lib/**/*.js' 'server/**/*.js'
|
||||
```
|
||||
|
||||
Every hit either becomes a `const` or moves to `export`. Iterate
|
||||
fix-restart-fix until the server boots cleanly.
|
||||
|
||||
## Explicit import trees
|
||||
|
||||
Meteor's standard bundler retains backward-compatible eager loading when an
|
||||
app has no `meteor.mainModule`. Explicit entry points are recommended because
|
||||
they make load order and dependencies deterministic. They are required when
|
||||
the app adopts the Rspack integration, which does not auto-discover an entry.
|
||||
|
||||
With `mainModule`, `client/main.js` must import every Blaze `.html` template
|
||||
and every helper or event file it needs:
|
||||
|
||||
```javascript
|
||||
// client/main.js
|
||||
import './main.import.less';
|
||||
|
||||
import './views/application/layout.html';
|
||||
import './views/application/layout.js';
|
||||
import './views/posts/show.html';
|
||||
import './views/posts/show.js';
|
||||
|
||||
import '../lib/router.js';
|
||||
import '../lib/collections/posts.js';
|
||||
```
|
||||
|
||||
Symptoms of a missed import:
|
||||
|
||||
- `{{> myTemplate}}` renders nothing. The template was never registered.
|
||||
- Template helpers and event handlers do not fire. The `.js` file was not
|
||||
loaded.
|
||||
- The console logs `Template.X is not defined`.
|
||||
|
||||
## The Iron Router controller trap
|
||||
|
||||
Iron Router auto-discovers controllers by name: `route('postsShow', ...)`
|
||||
looks for a global called `PostsShowController`. In Meteor 3 that global
|
||||
does not exist; `const PostsShowController = ...` is module-scoped. The
|
||||
route still renders its template, but `onBeforeAction`, `waitOn`, and
|
||||
`data` never run. Subscriptions never fire. Minimongo stays empty. There
|
||||
is no error.
|
||||
|
||||
Fix every route definition:
|
||||
|
||||
```javascript
|
||||
// broken in Meteor 3: relies on global lookup
|
||||
this.route('postsShow', {
|
||||
path: '/posts/:slug',
|
||||
});
|
||||
|
||||
// works: explicit controller reference
|
||||
this.route('postsShow', {
|
||||
path: '/posts/:slug',
|
||||
controller: PostsShowController,
|
||||
});
|
||||
```
|
||||
|
||||
Do not rely on Iron Router's naming convention in Meteor 3 at all. Pass
|
||||
`controller:` on every route that has one.
|
||||
|
||||
## Strict mode side effects
|
||||
|
||||
- Assignment to an undeclared variable throws. No more "oops, typo".
|
||||
- `arguments.callee` is not available.
|
||||
- Duplicate parameter names throw.
|
||||
- Octal literals (`010`) throw. Use `0o10`.
|
||||
- `with` is disallowed.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/api/global-variables.md
|
||||
@@ -1,202 +0,0 @@
|
||||
# Other breaking changes
|
||||
|
||||
Smaller breaking changes from the Meteor 3 upgrade that do not warrant
|
||||
their own reference but still bite. Skim this once after the framework
|
||||
flip; come back when a specific symptom matches.
|
||||
|
||||
## `Meteor.EnvironmentVariable.withValue` placement
|
||||
|
||||
Affects package authors that wrap `Meteor.publish`, `Meteor.methods`, or other
|
||||
Meteor primitives to propagate dynamic context into a handler. In Meteor 3,
|
||||
`withValue` uses `AsyncLocalStorage.run`; its context follows the callback's
|
||||
Promise through `await`.
|
||||
|
||||
When patching `Meteor.publish`, place `withValue` at the wrapper's top level
|
||||
around the call to the original `publish`. Do not introduce that scope inside
|
||||
the invoked publication handler. Meteor establishes its own publication
|
||||
invocation context before calling the handler, and the nested placement broke
|
||||
packages that needed `Meteor.userId()` or another invocation value.
|
||||
|
||||
Wrong: introducing `withValue` inside the invoked handler:
|
||||
|
||||
```javascript
|
||||
function patchPublish(publish) {
|
||||
return function (name, func, ...args) {
|
||||
return publish.call(this, name, function (...handlerArgs) {
|
||||
return _publishConnectionId.withValue(this?.connection?.id, () =>
|
||||
func.apply(this, handlerArgs)
|
||||
);
|
||||
}, ...args);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Right: scope the complete patched registration flow and return its result:
|
||||
|
||||
```javascript
|
||||
function patchPublish(publish) {
|
||||
return function (name, func, ...args) {
|
||||
return _publishConnectionId.withValue(this?.connection?.id, () =>
|
||||
publish.call(this, name, function (...handlerArgs) {
|
||||
return func.apply(this, handlerArgs);
|
||||
}, ...args)
|
||||
);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Regression-test the invoked publication before and after an `await`. Its
|
||||
`Meteor.userId()` or `DDP._CurrentPublicationInvocation` value must remain
|
||||
consistent with the handler's `this.userId`. A direct `EnvironmentVariable`
|
||||
test should likewise read the scoped value on both sides of an `await`.
|
||||
|
||||
## Mongo driver 6.x: callbacks removed on `rawCollection`
|
||||
|
||||
Meteor 3 ships MongoDB Node driver 6.x. The driver removed callback-style
|
||||
overloads for every async operation. If your code drops to `rawCollection`
|
||||
or `rawDatabase` for native driver access, rewrite the call sites:
|
||||
|
||||
```javascript
|
||||
// Meteor 2.x: callback
|
||||
Posts.rawCollection().findOne({ _id }, (err, doc) => { /* ... */ });
|
||||
|
||||
// Meteor 3.x: promise
|
||||
const doc = await Posts.rawCollection().findOne({ _id });
|
||||
```
|
||||
|
||||
The same applies to `rawCollection().aggregate(...).toArray(cb)`,
|
||||
`insertOne(doc, cb)`, `bulkWrite(ops, cb)`, etc. If a third-party package
|
||||
still passes a callback into a driver call, fork and rewrite.
|
||||
|
||||
## CLI changes
|
||||
|
||||
### `--vue2` flag removed
|
||||
|
||||
`meteor create --vue2` no longer exists. Vue 2 reached end of life in
|
||||
December 2023. For Vue, use `meteor create --vue` (Vue 3).
|
||||
|
||||
### `meteor reset` no longer wipes Mongo by default
|
||||
|
||||
`meteor reset` now clears only the local build cache. The local MongoDB
|
||||
data survives. To also wipe the database (the Meteor 2.x default), pass
|
||||
`--db`:
|
||||
|
||||
```bash
|
||||
meteor reset # clears build cache only
|
||||
meteor reset --db # clears build cache AND local Mongo
|
||||
```
|
||||
|
||||
Update any CI or development scripts that rely on `meteor reset` wiping
|
||||
the database.
|
||||
|
||||
## Release-specific Node baseline
|
||||
|
||||
Meteor 3 does not have one Node baseline across every minor release:
|
||||
|
||||
| Meteor release | Bundled Node |
|
||||
|----------------|--------------|
|
||||
| 3.0 | Node 20 |
|
||||
| 3.1 through 3.4 | Node 22 |
|
||||
| 3.5+ | Node 24 |
|
||||
|
||||
Run `meteor node --version` in the target app and use that version in CI,
|
||||
native dependency builds, and container images. Audit `engines.node` and
|
||||
native packages whenever the target Meteor release changes Node major.
|
||||
|
||||
## "Cannot enlarge memory array" during `meteor update`
|
||||
|
||||
Running `meteor update --release=3.x` directly from a heavy 2.x project
|
||||
sometimes crashes with:
|
||||
|
||||
```
|
||||
MINISAT-out: Cannot enlarge memory arrays.
|
||||
abort() at Error
|
||||
```
|
||||
|
||||
The version-constraint solver (`minisat`) runs out of memory while
|
||||
resolving the upgrade against a large `.meteor/packages` file. The fix
|
||||
is to reduce the package surface before the upgrade:
|
||||
|
||||
1. Remove every Atmosphere package the app no longer uses.
|
||||
2. Update or fork remaining packages to declare
|
||||
`api.versionsFrom(['2.x', '3.0'])` so the solver has fewer
|
||||
alternatives to consider.
|
||||
3. Retry the upgrade. If it still fails, comment out non-core packages
|
||||
in `.meteor/packages`, upgrade, then re-add them one by one.
|
||||
|
||||
This is the same root cause as "the install just hangs forever" reports.
|
||||
|
||||
## `Meteor.bindEnvironment` for external callbacks
|
||||
|
||||
`Meteor.bindEnvironment` captures Meteor dynamic-variable values at the moment
|
||||
the wrapper is created and restores those values when the callback later runs.
|
||||
It does not discover the identity of a future method or publication
|
||||
invocation, and it does not change JavaScript's `this` binding.
|
||||
|
||||
Create the wrapper inside the invocation whose environment must be preserved.
|
||||
For identity, capture `this.userId` explicitly so a long-lived callback does
|
||||
not depend on implicit request context:
|
||||
|
||||
```javascript
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
Meteor.methods({
|
||||
startImport(jobId) {
|
||||
check(jobId, String);
|
||||
if (!this.userId) throw new Meteor.Error('not-authorized');
|
||||
|
||||
const userId = this.userId;
|
||||
externalSdk.once(jobId, Meteor.bindEnvironment(async (payload) => {
|
||||
await Posts.insertAsync({ payload, createdBy: userId });
|
||||
}));
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
A wrapper created by top-level registration captures the top-level
|
||||
environment, which normally has no user invocation. For a global event emitter
|
||||
or background queue, put the authenticated identity in the job or event data
|
||||
and pass it explicitly. Use `bindEnvironment` only for dynamic variables that
|
||||
exist when the callback is registered.
|
||||
|
||||
## Monkey-patching from `Meteor.startup()`
|
||||
|
||||
Code that monkey-patches a Meteor API (intercepting `Meteor.publish`,
|
||||
wrapping `Accounts.createUser`, etc.) must run after the API is loaded.
|
||||
On 3.x, package load order is less forgiving than on 2.x; patches at the
|
||||
top of a file may fire before the target API exists.
|
||||
|
||||
Wrap the patch in `Meteor.startup`:
|
||||
|
||||
```javascript
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
Meteor.startup(() => {
|
||||
const original = Meteor.publish;
|
||||
Meteor.publish = function (name, handler, ...rest) {
|
||||
return original.call(this, name, async function (...args) {
|
||||
// patched behavior
|
||||
return handler.apply(this, args);
|
||||
}, ...rest);
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
Symptom: the patch is in the codebase but the wrapped behavior never
|
||||
runs. The patch fired before the target API loaded, so `Meteor.publish`
|
||||
was `undefined` at patch time and the assignment was a no-op.
|
||||
|
||||
## NPM installer
|
||||
|
||||
Use `npx meteor` as the primary cross-platform command. The documented
|
||||
`curl https://install.meteor.com/ | sh` command remains an alternative for
|
||||
Linux and macOS; do not describe it as phased out. Do not add the npm Meteor
|
||||
installer to the application's `package.json`.
|
||||
|
||||
Match the host Node prerequisite to the selected CLI version. Current Meteor
|
||||
3.5 installation docs require Node 24+, while earlier Meteor 3 tool releases
|
||||
bundle earlier Node majors as shown above.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/breaking-changes/index.md
|
||||
@@ -1,136 +0,0 @@
|
||||
# Atmosphere package triage
|
||||
|
||||
Atmosphere packages are the largest single source of friction in a 2.x to
|
||||
3.x migration. Many are unmaintained, depend on Fibers, or pin
|
||||
`api.versionsFrom('1.x')`. Decide for every package: replace, fork, or remove.
|
||||
|
||||
## Triage matrix
|
||||
|
||||
| Situation | Action |
|
||||
|--------------------------------------------------------------|-------------------------------------------------------------------|
|
||||
| Maintained package with a 3.x-compatible release | Update. |
|
||||
| Maintained package, no 3.x release yet | Open an issue. Track on the project tracker. |
|
||||
| Unmaintained package, npm replacement exists | Replace. Move the call sites to the npm API. |
|
||||
| Unmaintained package, no replacement, source available | Fork. Apply minimal changes to ship on 3.x. |
|
||||
| Unmaintained package, no replacement, you do not need it | Remove. Inline the small piece you depended on. |
|
||||
|
||||
## Before the framework upgrade
|
||||
|
||||
1. Save `.meteor/packages`, `.meteor/versions`, `package.json`, and the npm
|
||||
lockfile as a resolution checkpoint.
|
||||
2. Inventory `.meteor/packages`. List every non-core package.
|
||||
3. Look up each on Packosphere or its GitHub repo. Note the latest version
|
||||
and whether it ships a 3.x release.
|
||||
4. For packages with no 3.x release, search community forks. Several
|
||||
ecosystem groups maintain community forks of common Atmosphere packages.
|
||||
5. For packages still missing, decide replace vs fork vs remove now,
|
||||
before the framework flip.
|
||||
|
||||
Review the resolved version diff after every package operation. Keep critical
|
||||
schema, accounts, router, collection-hook, and build-plugin major upgrades in
|
||||
separate commits when possible. If behavior changes after the release flip,
|
||||
first determine whether the responsible package version changed too.
|
||||
|
||||
Reducing the package footprint **before** running `meteor update --release=3`
|
||||
is the single biggest predictor of a smooth upgrade.
|
||||
|
||||
## Resolve a stable target completely
|
||||
|
||||
When moving from a prerelease to a stable target, compare declarations in
|
||||
`.meteor/release`, `.meteor/packages`, and `package.json` with resolved versions
|
||||
in `.meteor/versions` and the npm lockfile. Remove only unintended resolved
|
||||
prereleases. Keep one only for a documented capability absent from the stable
|
||||
target. Run `meteor update --npm` when supported and verify a clean locked
|
||||
install does not change manifests or silently restore a prerelease. Do not fold
|
||||
unrelated dependency major upgrades into this cleanup.
|
||||
|
||||
## Forking a package
|
||||
|
||||
```bash
|
||||
# clone the source somewhere
|
||||
git clone <repo-url> lib/<package-name>
|
||||
cd lib/<package-name>
|
||||
git checkout -b migrate-to-meteor-3
|
||||
|
||||
# link from your app's packages/ folder
|
||||
cd /path/to/app/packages
|
||||
ln -sf ../lib/<package-name>/path/to/package <package-name>
|
||||
```
|
||||
|
||||
Inside the cloned package, edit `package.js`:
|
||||
|
||||
```javascript
|
||||
Package.describe({
|
||||
name: '<package-name>',
|
||||
version: '<bump>',
|
||||
/* ... */
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
api.versionsFrom(['2.x', '3.0']); // dual-version
|
||||
api.use([
|
||||
'ecmascript',
|
||||
'mongo@1.16.0 || 2.0.0', // multi-version refs
|
||||
/* ... */
|
||||
]);
|
||||
api.mainModule('main.js'); // optional modular entry point
|
||||
});
|
||||
```
|
||||
|
||||
Common edits inside the package code:
|
||||
|
||||
- Server-side sync Mongo: rewrite to `*Async`.
|
||||
- `Meteor._sleepForMs` and Fibers helpers: rewrite to native async.
|
||||
- Implicit globals at file top level: convert to `const` or `export`.
|
||||
|
||||
## Package API decisions
|
||||
|
||||
`api.addFiles`, `api.export`, and `api.mainModule` all remain supported in
|
||||
Meteor 3. Do not convert a package only to satisfy the framework version.
|
||||
Choose `api.mainModule` when the package benefits from an explicit import
|
||||
tree and module exports. Retain `api.addFiles` for ordered or build-plugin
|
||||
sources and `api.export` when consumers still rely on package globals.
|
||||
|
||||
Actual migration replacements include:
|
||||
|
||||
| Removed or changed in 3.x | Replacement |
|
||||
|---------------------------|------------------------------------|
|
||||
| `_ensureIndex` | `createIndexAsync` on the server |
|
||||
| `HTTP.get` | `meteor/fetch` or native `fetch` |
|
||||
| Sync Mongo methods | `*Async` siblings on the server |
|
||||
|
||||
## Custom validators in package methods
|
||||
|
||||
Schemas validators that pre-3 packages bundled often need an upgrade for
|
||||
breaking changes in major versions (typically array shorthand and decimal
|
||||
options). Keep the schema definitions next to the collection definitions
|
||||
so a single audit pass covers them.
|
||||
|
||||
## Known replacements
|
||||
|
||||
Common Atmosphere packages that have a community-blessed 3.x successor:
|
||||
|
||||
| Was | Replace with |
|
||||
|-------------------------------------|----------------------------------------------------|
|
||||
| `kadira:flow-router` | `ostrio:flow-router-extra` |
|
||||
| `percolate:synced-cron` | `quave:synced-cron` |
|
||||
| `aldeed:collection2` (1.x/2.x) | `aldeed:collection2@4.0.0` (bundles `aldeed:simple-schema`; drop the npm `simpl-schema` dep) |
|
||||
| `mquandalle:jade` | Removed. Migrate templates to Blaze HTML or another templating package. |
|
||||
| `simple:json-routes` / Restivus | `WebApp.handlers` with Express routes (see `webapp-express.md`). |
|
||||
| `tmeasday:publish-counts` | `compat:publish-counts` (community fork) |
|
||||
| `meteor/http` (`HTTP.get`/`post`) | `meteor/fetch` or native `fetch` |
|
||||
| `underscore` (Atmosphere) | Native ES `Array` / `Object` methods, or the npm `underscore` if you really need it. |
|
||||
|
||||
This is a starting set, not exhaustive. For any package not listed,
|
||||
search the community fork organizations or Packosphere before forking
|
||||
yourself.
|
||||
|
||||
## When to publish back
|
||||
|
||||
If the original package is dormant, publish your fork under a different
|
||||
publisher prefix (the community convention is the org name plus
|
||||
the original short name). Submit a pull request to the original repo as
|
||||
well; sometimes the maintainer re-engages.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/guide/package-replacements.md
|
||||
@@ -1,167 +0,0 @@
|
||||
# Publications and cursor internals
|
||||
|
||||
Most publish functions return a cursor and Meteor handles the rest. Apps
|
||||
that grew on Meteor 2.x sometimes drove publications imperatively with
|
||||
`this.added` / `this.changed` / `this.removed`, often dipping into the
|
||||
cursor's internal `_cursorDescription` for the collection name. That
|
||||
internal API is unreliable on Meteor 3 and may return `undefined`,
|
||||
silently breaking the publication.
|
||||
|
||||
## Prefer returning a cursor
|
||||
|
||||
Whenever the publication can be expressed as a single filtered cursor,
|
||||
return it. Meteor wires up `added` / `changed` / `removed` automatically:
|
||||
|
||||
```javascript
|
||||
Meteor.publish('posts.recent', function (limit) {
|
||||
return Posts.find({}, { limit, sort: { createdAt: -1 } });
|
||||
});
|
||||
```
|
||||
|
||||
Meteor 3 supports both conventional and async publish handlers. Await setup
|
||||
work, then return a cursor or array of cursors:
|
||||
|
||||
```javascript
|
||||
Meteor.publish('posts.byTeam', async function (teamId) {
|
||||
const membership = await Memberships.findOneAsync({
|
||||
teamId,
|
||||
userId: this.userId,
|
||||
});
|
||||
if (!membership) return this.ready();
|
||||
return Posts.find({ teamId });
|
||||
});
|
||||
```
|
||||
|
||||
Meteor awaits the handler Promise before processing the returned cursor.
|
||||
Use the low-level API only when the result cannot be expressed as a returned
|
||||
cursor, such as per-document async joins or a custom external data source.
|
||||
|
||||
## Preserve framework-bound `this`
|
||||
|
||||
Meteor invokes method and publication handlers with an invocation context.
|
||||
Arrow functions ignore that binding, so an arrow that reads `this.userId`,
|
||||
`this.connection`, `this.ready()`, `this.added()`, or another context member is
|
||||
incorrect even when its body is otherwise async-compatible.
|
||||
|
||||
Before changing handlers, use an AST scan to find:
|
||||
|
||||
- an arrow passed directly to `Meteor.publish`;
|
||||
- an arrow-valued property in an object passed to `Meteor.methods`;
|
||||
- a `ThisExpression` owned by that outer arrow.
|
||||
|
||||
Change only the context-owning handler to an ordinary function:
|
||||
|
||||
```javascript
|
||||
Meteor.publish('items.mine', function () {
|
||||
if (!this.userId) return this.ready();
|
||||
return Items.find({ ownerId: this.userId });
|
||||
});
|
||||
|
||||
Meteor.methods({
|
||||
async 'items.create'(input) {
|
||||
return Items.insertAsync({ ...input, ownerId: this.userId });
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Do not rewrite an arrow that never uses framework context merely because it is
|
||||
a handler. Preserve nested arrows inside an ordinary handler when they
|
||||
intentionally capture the handler's `this`. Validate one authenticated and one
|
||||
unauthenticated call or subscription so the test proves the bound context, not
|
||||
only compilation.
|
||||
|
||||
## Avoid `_cursorDescription`
|
||||
|
||||
The internal pattern:
|
||||
|
||||
```javascript
|
||||
// fragile in Meteor 3
|
||||
async function publishNonReactively(sub, cursor) {
|
||||
await cursor.forEachAsync((doc) => {
|
||||
sub.added(cursor._cursorDescription.collectionName, doc._id, doc);
|
||||
});
|
||||
sub.ready();
|
||||
}
|
||||
```
|
||||
|
||||
`_cursorDescription.collectionName` is internal and not guaranteed.
|
||||
Pass the collection name explicitly instead:
|
||||
|
||||
```javascript
|
||||
async function publishNonReactively(sub, collectionName, ...cursors) {
|
||||
for (const cursor of cursors) {
|
||||
await cursor.forEachAsync((doc) => {
|
||||
sub.added(collectionName, doc._id, doc);
|
||||
});
|
||||
}
|
||||
sub.ready();
|
||||
}
|
||||
|
||||
// usage:
|
||||
Meteor.publish('posts.featured', function () {
|
||||
return publishNonReactively(this, 'posts', Posts.find({ featured: true }));
|
||||
});
|
||||
```
|
||||
|
||||
Or, better, return the cursor and let Meteor handle the wiring.
|
||||
|
||||
## Cursor transforms must be sync
|
||||
|
||||
A cursor `transform` runs on every document. In Meteor 3 it must be
|
||||
synchronous:
|
||||
|
||||
```javascript
|
||||
// BROKEN: async transform
|
||||
Posts.find({}, {
|
||||
transform: async (doc) => {
|
||||
doc.author = await Users.findOneAsync(doc.authorId);
|
||||
return doc;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Produces Promise-shaped documents or publication/serialization failures.
|
||||
Two options:
|
||||
|
||||
1. Keep the transform synchronous. Run the join in a separate publication
|
||||
or on the client.
|
||||
2. Drop to the low-level publish API and join inside an
|
||||
`observeChangesAsync` handler.
|
||||
|
||||
## Low-level publish API
|
||||
|
||||
```javascript
|
||||
Meteor.publish('feed', async function () {
|
||||
const handle = await Posts.find().observeChangesAsync({
|
||||
added: (id, doc) => this.added('posts', id, doc),
|
||||
changed: (id, doc) => this.changed('posts', id, doc),
|
||||
removed: (id) => this.removed('posts', id),
|
||||
});
|
||||
this.ready();
|
||||
this.onStop(() => handle.stop());
|
||||
});
|
||||
```
|
||||
|
||||
Always stop an `observeChangesAsync` handle from `this.onStop`. Without the
|
||||
teardown, the observer leaks.
|
||||
|
||||
## Authorization
|
||||
|
||||
Filter inside the publish body. The publish function is the only chokepoint
|
||||
that runs before data leaves the server:
|
||||
|
||||
```javascript
|
||||
Meteor.publish('items.mine', function () {
|
||||
if (!this.userId) return this.ready();
|
||||
return Items.find(
|
||||
{ ownerId: this.userId },
|
||||
{ fields: { title: 1, qty: 1 } },
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
Project `fields` whenever the collection contains columns the subscriber
|
||||
must not receive.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/api/meteor.md
|
||||
@@ -1,97 +0,0 @@
|
||||
# React migration
|
||||
|
||||
Tight scope: what changes for an existing React-on-Meteor-2 app during
|
||||
the upgrade to Meteor 3. The broader React-on-Meteor data tutorial
|
||||
(`react-meteor-data`, full hook reference, suspense patterns for new
|
||||
apps) is out of scope here; use the `meteor-react` skill after the
|
||||
framework upgrade.
|
||||
|
||||
## What changes
|
||||
|
||||
`react-meteor-data` is independently versioned. Suspense hooks began in package
|
||||
2.7.0, before Meteor 3, while package 3.0.0 began official Meteor 3
|
||||
compatibility. Inspect `.meteor/versions` before choosing an API. For a Meteor
|
||||
3 app, use a tested 3.0.0+ package; current examples are verified against
|
||||
4.0.1. The Suspense variants replace the `isLoading` readiness function by
|
||||
suspending the component tree until data is ready.
|
||||
|
||||
```javascript
|
||||
// Classic surface, supported on Meteor 2 and 3
|
||||
import { useTracker, useSubscribe } from 'meteor/react-meteor-data';
|
||||
|
||||
function PostsScreen() {
|
||||
const isLoading = useSubscribe('posts');
|
||||
const posts = useTracker(() => Posts.find().fetch());
|
||||
if (isLoading()) return <Spinner />;
|
||||
return <List posts={posts} />;
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Suspense surface, react-meteor-data 2.7.0+; use 3.0.0+ with Meteor 3
|
||||
import { useTracker, useSubscribe } from 'meteor/react-meteor-data/suspense';
|
||||
|
||||
function PostsScreen() {
|
||||
useSubscribe('posts'); // suspends
|
||||
const posts = useTracker('posts', () => Posts.find().fetchAsync());
|
||||
return <List posts={posts} />; // no isLoading()
|
||||
}
|
||||
```
|
||||
|
||||
Two concrete changes:
|
||||
|
||||
1. Import from `meteor/react-meteor-data/suspense` instead of
|
||||
`meteor/react-meteor-data` when you want Suspense semantics. Wrap the
|
||||
component in `<Suspense fallback={...}>` somewhere upstream.
|
||||
2. `useTracker(key, fn)` takes a string key as the first argument under
|
||||
the suspense API. The key isolates the computation; passing the same
|
||||
key with a different `fn` is undefined.
|
||||
|
||||
The classic `useTracker(fn)` and `useSubscribe(...)` (returning
|
||||
`isLoading`) keep working under the non-suspense import path. Migration
|
||||
is optional.
|
||||
|
||||
## `useFind`
|
||||
|
||||
Classic `useFind` is unchanged. Continue passing a cursor factory:
|
||||
|
||||
```javascript
|
||||
const posts = useFind(() => Posts.find({}));
|
||||
```
|
||||
|
||||
Suspense `useFind` has a different signature. Pass the collection and the
|
||||
argument tuple for `Collection.find`:
|
||||
|
||||
```javascript
|
||||
const posts = useFind(Posts, [{}, { sort: { createdAt: -1 } }]);
|
||||
```
|
||||
|
||||
Use `meteor-react` for the complete classic and Suspense contracts.
|
||||
|
||||
## Client-side Mongo
|
||||
|
||||
React components that call `Collection.find().fetch()` directly on the
|
||||
client work the same way as in Meteor 2. Minimongo on the client is still
|
||||
synchronous, so keeping render-path reads synchronous is usually simplest.
|
||||
Async client reads do not inherently lose Tracker reactivity: a reactive read
|
||||
before the first `await` is tracked. If the reactive read itself occurs after
|
||||
an `await`, restore the captured computation around that read with
|
||||
`Tracker.withComputation`. See `client-reactivity.md`.
|
||||
|
||||
## Symptoms
|
||||
|
||||
- After the upgrade, a `useSubscribe` call no longer returns an
|
||||
`isLoading` function. The component was migrated to the suspense
|
||||
import without a wrapping `<Suspense>`. Either add a Suspense
|
||||
boundary, or import from `meteor/react-meteor-data` (non-suspense).
|
||||
- `useTracker` reruns on every render or never reruns. The key argument
|
||||
is missing under the suspense API. Add a stable string key.
|
||||
- The Suspense import cannot be resolved. Inspect `.meteor/versions`; upgrade
|
||||
`react-meteor-data` to a Meteor 3-compatible 3.0.0+ line before copying the
|
||||
current API.
|
||||
|
||||
Package version evidence:
|
||||
[`react-meteor-data` changelog](https://github.com/meteor/react-packages/blob/master/packages/react-meteor-data/CHANGELOG.md)
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/front-end/react.md
|
||||
@@ -1,79 +0,0 @@
|
||||
# Functions removed in Meteor 3.x
|
||||
|
||||
Meteor 3 removed the synchronous Mongo APIs on the server and the
|
||||
Fibers-dependent helpers. This is the canonical replacement list.
|
||||
|
||||
## Mongo collections (server)
|
||||
|
||||
| Removed | Replacement |
|
||||
|-------------------------------|----------------------------------------------|
|
||||
| `Collection.find(q).fetch()` | `await Collection.find(q).fetchAsync()` |
|
||||
| `Collection.findOne(q)` | `await Collection.findOneAsync(q)` |
|
||||
| `Collection.insert(doc)` | `await Collection.insertAsync(doc)` |
|
||||
| `Collection.update(q, mod)` | `await Collection.updateAsync(q, mod)` |
|
||||
| `Collection.remove(q)` | `await Collection.removeAsync(q)` |
|
||||
| `Collection.upsert(q, mod)` | `await Collection.upsertAsync(q, mod)` |
|
||||
| `cursor.count()` (server) | `await cursor.countAsync()` |
|
||||
| `cursor.forEach(fn)` (server) | `await cursor.forEachAsync(fn)` |
|
||||
| `cursor.map(fn)` (server) | `await cursor.mapAsync(fn)` |
|
||||
|
||||
Client-side Minimongo retains the synchronous API.
|
||||
|
||||
## User helpers
|
||||
|
||||
| Removed | Replacement |
|
||||
|--------------------------|----------------------------|
|
||||
| `Meteor.user()` (server) | `await Meteor.userAsync()` |
|
||||
|
||||
`Meteor.userId()` was not replaced with an async API. It remains synchronous
|
||||
inside a method or publication and reads the current invocation. Prefer
|
||||
`this.userId` there for explicit context. Outside those invocation scopes,
|
||||
pass the user ID into the async function; `Meteor.userIdAsync()` does not
|
||||
exist.
|
||||
|
||||
## Accounts
|
||||
|
||||
Server administration APIs that lost synchronous forms:
|
||||
|
||||
| Removed | Replacement |
|
||||
|--------------------------------------|-----------------------------------------------|
|
||||
| `Accounts.setPassword(uid, p, opts)` | `await Accounts.setPasswordAsync(uid, p, opts)` |
|
||||
| `Accounts.addEmail(uid, addr)` | `await Accounts.addEmailAsync(uid, addr)` |
|
||||
|
||||
Use `await Accounts.createUserAsync(options)` for explicit server-side user
|
||||
creation. Do not apply this table to client login flows:
|
||||
|
||||
- Client `Accounts.createUser(options, callback)` remains supported, and
|
||||
`Accounts.createUserAsync(options)` is also available.
|
||||
- Client `Accounts.changePassword(old, next, callback)` remains
|
||||
callback-shaped.
|
||||
- `Meteor.loginWithPassword(user, password, callback)` remains supported.
|
||||
`Meteor.loginWithPasswordAsync` was added in Meteor 3.5.
|
||||
|
||||
## Email
|
||||
|
||||
| Removed | Replacement |
|
||||
|--------------------------|--------------------------------------|
|
||||
| `Email.send(options)` | `await Email.sendAsync(options)` |
|
||||
|
||||
## Assets
|
||||
|
||||
| Removed | Replacement |
|
||||
|----------------------------|----------------------------------------|
|
||||
| `Assets.getText(path)` | `await Assets.getTextAsync(path)` |
|
||||
| `Assets.getBinary(path)` | `await Assets.getBinaryAsync(path)` |
|
||||
|
||||
## Mongo index management
|
||||
|
||||
| Removed | Replacement |
|
||||
|----------------------------------------|---------------------------------------------|
|
||||
| `Collection._ensureIndex(spec, opts?)` | `await Collection.createIndexAsync(spec, opts?)` |
|
||||
|
||||
## Fibers helpers
|
||||
|
||||
- `Meteor._sleepForMs`: removed. Use `await new Promise(r => setTimeout(r, ms))`.
|
||||
- `Meteor.wrapAsync`: removed. Use the underlying async API directly.
|
||||
- `Future` (from `fibers/future`): removed. The package no longer ships.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/api/removed-functions.md
|
||||
@@ -1,63 +0,0 @@
|
||||
# TypeScript migration
|
||||
|
||||
Tight scope: what an existing TypeScript-on-Meteor-2 project must update
|
||||
during the upgrade to Meteor 3. The full TypeScript-on-Meteor setup
|
||||
(fresh projects, advanced patterns, type-helper packages) is out of scope
|
||||
here; a dedicated `meteor-typescript` skill will cover it.
|
||||
|
||||
## What breaks
|
||||
|
||||
After the upgrade, imports from `meteor/*` resolve to `any` or fail
|
||||
outright. The Meteor 2 type-shipping mechanism is no longer compatible
|
||||
with the 3.x build, so any `import { Meteor } from 'meteor/meteor';`
|
||||
loses its types.
|
||||
|
||||
## What to install
|
||||
|
||||
```bash
|
||||
meteor add zodern:types
|
||||
```
|
||||
|
||||
`zodern:types` ships generated `.d.ts` files keyed off your local Meteor
|
||||
install. It replaces the older approaches used in Meteor 2.
|
||||
|
||||
## `tsconfig.json` updates
|
||||
|
||||
Two changes are required:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compilerOptions": {
|
||||
// 1. Resolve symlinks the way Meteor's package layout expects.
|
||||
"preserveSymlinks": true,
|
||||
|
||||
// 2. Map meteor/* imports to the generated types directory.
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"meteor/*": [".meteor/local/types/packages.d.ts"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Without `preserveSymlinks: true`, TypeScript follows symlinks in
|
||||
`.meteor/local/build/` and reports duplicate identifier errors. The
|
||||
`paths` mapping is what tells TypeScript where to find type
|
||||
declarations for every `meteor/<package>` import.
|
||||
|
||||
## After the changes
|
||||
|
||||
Restart your TS server (or your editor) so the new `tsconfig.json` is
|
||||
picked up. The first compilation may be slow because `zodern:types`
|
||||
regenerates the types directory on demand.
|
||||
|
||||
## Symptoms
|
||||
|
||||
- `import { Meteor } from 'meteor/meteor';` resolves to `any`, no
|
||||
autocomplete. The `paths` mapping in `tsconfig.json` is missing.
|
||||
- "Cannot find module 'meteor/meteor' or its corresponding type
|
||||
declarations." `zodern:types` is not installed.
|
||||
- "Duplicate identifier 'Meteor'." `preserveSymlinks` is not set.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/typescript/meteor-types.md
|
||||
@@ -1,114 +0,0 @@
|
||||
# WebApp switched to Express 5
|
||||
|
||||
Meteor 3 replaced Connect with Express inside the `webapp` package, and
|
||||
Meteor 3.1 upgraded that to Express 5. Apps that customised the
|
||||
middleware stack must rename the API surfaces they used and may need to
|
||||
adjust for Express 5 routing changes. Existing routes that mounted
|
||||
middleware on `WebApp.connectHandlers` keep working through deprecated
|
||||
aliases, but new code should use the renamed surfaces.
|
||||
|
||||
## API rename matrix
|
||||
|
||||
| Meteor 2.x | Meteor 3.x |
|
||||
|---------------------------------------------|-----------------------------------------|
|
||||
| `WebApp.connectHandlers.use(mw)` | `WebApp.handlers.use(mw)` |
|
||||
| `WebApp.rawConnectHandlers.use(mw)` | `WebApp.rawHandlers.use(mw)` |
|
||||
| `WebApp.connectApp` | `WebApp.expressApp` |
|
||||
| (no equivalent) | `WebApp.express()` factory |
|
||||
| (no equivalent) | `WebApp.express.Router()` router |
|
||||
| (no equivalent) | `WebApp.express.{json,raw,static,text,urlencoded}` |
|
||||
|
||||
The old names continue to work as aliases, but are deprecated. New code
|
||||
should use the renamed surfaces.
|
||||
|
||||
## Mounting a route
|
||||
|
||||
```javascript
|
||||
import { WebApp } from 'meteor/webapp';
|
||||
|
||||
WebApp.handlers.get('/hello', (req, res) => {
|
||||
res.send('Hello World');
|
||||
});
|
||||
```
|
||||
|
||||
Or mount a sub-application:
|
||||
|
||||
```javascript
|
||||
import { WebApp } from 'meteor/webapp';
|
||||
|
||||
const app = WebApp.express();
|
||||
app.get('/hello', (req, res) => res.send('Hello World'));
|
||||
|
||||
WebApp.handlers.use(app);
|
||||
```
|
||||
|
||||
## Router-level middleware
|
||||
|
||||
```javascript
|
||||
import { WebApp } from 'meteor/webapp';
|
||||
|
||||
const router = WebApp.express.Router();
|
||||
|
||||
router.use((req, res, next) => {
|
||||
// runs on every request through this router
|
||||
next();
|
||||
});
|
||||
|
||||
router.use('/hello/:name', (req, res, next) => {
|
||||
console.log('Request URL:', req.originalUrl);
|
||||
next();
|
||||
});
|
||||
|
||||
WebApp.handlers.use('/', router);
|
||||
```
|
||||
|
||||
## Async `WebAppInternals` methods
|
||||
|
||||
Several internal methods that customise the static-asset pipeline became
|
||||
async in Meteor 3. Add `await` at every call site:
|
||||
|
||||
- `await WebAppInternals.reloadClientPrograms()`
|
||||
- `await WebAppInternals.pauseClient()`
|
||||
- `await WebAppInternals.generateClientProgram()`
|
||||
- `await WebAppInternals.generateBoilerplate()`
|
||||
- `await WebAppInternals.setInlineScriptsAllowed()`
|
||||
- `await WebAppInternals.enableSubresourceIntegrity()`
|
||||
- `await WebAppInternals.setBundledJsCssUrlRewriteHook()`
|
||||
- `await WebAppInternals.setBundledJsCssPrefix()`
|
||||
- `await WebAppInternals.getBoilerplate()`
|
||||
|
||||
## Express 5 specifics (Meteor 3.1+)
|
||||
|
||||
Express 5 itself introduces a few changes that bite when upgrading from
|
||||
Express 4. Meteor 3.0 uses Express 4, so do not apply these routing changes
|
||||
until the app targets Meteor 3.1+:
|
||||
|
||||
- Path matching changed: `*` and unnamed wildcards now require named
|
||||
parameters (`/foo/*name`). Update any custom path patterns.
|
||||
- Async route handlers can `throw` or reject and Express forwards the
|
||||
error to the error middleware. Previously this would crash the process.
|
||||
- `req.query` is no longer parsed by the deprecated `qs` library by
|
||||
default; reconfigure if your client relies on bracket notation.
|
||||
|
||||
See the Express 5 migration guide if a custom middleware pipeline breaks
|
||||
after the framework upgrade.
|
||||
|
||||
## Backporting
|
||||
|
||||
For projects that want to start migrating middleware before the framework
|
||||
flip, a community backport (`harry97:webapp`) ships an Express-based
|
||||
`webapp` on Meteor 2.17. Once the project is on 3.x, remove the backport
|
||||
and use the core `webapp` package.
|
||||
|
||||
## Symptoms after the upgrade
|
||||
|
||||
- Middleware mounted on `WebApp.connectHandlers` still runs but logs a
|
||||
deprecation warning. Migrate to `WebApp.handlers` at your convenience.
|
||||
- On Meteor 3.1+, routes that used unnamed wildcards no longer match. Express
|
||||
5 path semantics changed; rename to named parameters. Meteor 3.0 retains
|
||||
Express 4 routing behavior.
|
||||
- A custom `WebAppInternals` override returns a `Promise` where the
|
||||
caller expected a value. Add `await`.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/v3-migration-docs/breaking-changes/index.md
|
||||
@@ -1,232 +0,0 @@
|
||||
---
|
||||
name: migrate-to-rspack
|
||||
description: >
|
||||
Use when migrating an existing Meteor app to Rspack (Meteor 3.4+), or
|
||||
upgrading Rspack 1 to 2 on Meteor 3.6 beta. Triggers on nested imports,
|
||||
mainModule entry points, server-only apps, replacing fourseven:scss /
|
||||
meteor/less / coffeescript / jorgenvatle:vite / zodern:melte with loaders,
|
||||
Svelte/TypeScript preprocessing or Lingui SWC plugin failures after upgrade,
|
||||
CommonJS default-import interop, module.exports in client graphs, Node
|
||||
built-ins in browser code, _build / build-assets / build-chunks,
|
||||
.meteorignore hiding handoff files, dynamic chunks under ROOT_URL,
|
||||
meteor.modules for CSS/HTML, resolve.symlinks or resolve.alias migration,
|
||||
automatic dependency updates and immutable CI/Docker builds.
|
||||
Use this skill when the user asks about migration compatibility or a build
|
||||
plugin's Rspack replacement. For new-app setup and rspack.config.js helpers,
|
||||
use meteor-modern-build-stack instead.
|
||||
metadata:
|
||||
author: meteor
|
||||
kind: knowledge
|
||||
meteor: ">=3.4"
|
||||
area: migration
|
||||
tagline: "Migrate an existing Meteor 3 app to the Rspack bundler integration (`mainModule`, replacing legacy build plugins with loaders)."
|
||||
bundle: ["migration"]
|
||||
docs_synced_at: "2026-09-11"
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Migrate an existing app to Rspack
|
||||
|
||||
Rspack compiles app code; Meteor builds Atmosphere packages and assembles the
|
||||
bundle. Keep packages, but audit their architecture and browser dependencies.
|
||||
|
||||
Prerequisite: Meteor 3.4+. Recommended before activation: enable
|
||||
`"meteor": { "modern": true }` and fix Babel fallbacks. For setup and helpers,
|
||||
use `meteor-modern-build-stack`.
|
||||
|
||||
Match `@meteorjs/rspack` to the Meteor release, not to
|
||||
`@rspack/core` or `@rspack/cli`:
|
||||
|
||||
| Meteor | `rspack` | `@meteorjs/rspack` | Capability boundary |
|
||||
|---|---|---|---|
|
||||
| 3.4 | `1.0.0` | `1.0.0` | Base integration and helpers. |
|
||||
| 3.4.1 and 3.5 | `1.1.0` | `2.0.1` | Adds v2 helpers and inherited `TOOL_NODE_FLAGS`. |
|
||||
| 3.5.1 | `1.2.0` | `2.1.0` | Revised client polyfills and extension discovery. |
|
||||
| 3.5.2 | `1.3.0` | `2.2.0` | Dependency diagnostics, mode isolation, full-app/TLA and cache fixes. |
|
||||
| 3.6-beta.0 | `1.4.0-beta360.0` | `3.0.0-beta.1` | Rspack 2.2.0 and workspace-aware installs. |
|
||||
|
||||
The Atmosphere, Meteor npm integration, and Rspack core package versions are
|
||||
independent. Inspect `.meteor/versions`, `package.json`, and the lockfile.
|
||||
Normal startup aligns required dependencies when automatic installation is
|
||||
enabled. Review and commit those changes. Explicit `meteor update --npm` is
|
||||
an alternative, not an extra required step. Do not pair a newer integration
|
||||
major with an older Meteor release to copy a helper.
|
||||
|
||||
Already using Rspack? For the Meteor 3.6 beta upgrade, follow
|
||||
[Rspack 1 to 2](references/rspack-2-upgrade.md) and its toolchain checks.
|
||||
Keep valid entries/configuration; skip the first-activation steps below.
|
||||
|
||||
## Decision flow
|
||||
|
||||
1. Does the app define client and server entry points in `package.json`
|
||||
`meteor.mainModule`? If no, define them. Required.
|
||||
2. Trace the client and client-test graphs. Do they reach CommonJS export
|
||||
assignments, Node built-ins, server-only local package entries, or missing
|
||||
generated inputs in a clean checkout? If yes, repair the boundary before
|
||||
activation. See
|
||||
`references/client-graph-preflight.md`.
|
||||
3. Does the app code contain nested imports (ES `import` inside an `if`,
|
||||
function, or other block)? If yes, move them to top level or convert
|
||||
them to dynamic `import()` / `require`. Required for app code; OK in
|
||||
Atmosphere packages.
|
||||
4. Does the app rely on a Meteor build plugin (`less`, `fourseven:scss`,
|
||||
`coffeescript`, `zodern:melte`, `jorgenvatle:vite`)? Plan an Rspack
|
||||
loader replacement and prove capability parity before removal. See
|
||||
`references/framework-and-css.md`.
|
||||
5. Does the app rely on bare default imports from CommonJS packages
|
||||
(`import x from "some-cjs"`)? Decide between rewriting to
|
||||
`import * as x` or restoring Meteor-style interop in `.swcrc`. See
|
||||
`references/code-migrations.md`.
|
||||
6. Is the app server-only? Set only `mainModule.server`. Rspack still
|
||||
bundles the server; client is skipped.
|
||||
7. Does the app keep CSS or HTML outside its entry folder, or import app-local
|
||||
symlinks? Preserve the boundary with `meteor.modules` or
|
||||
`resolve.symlinks: false`; see the references.
|
||||
8. Run `meteor add rspack` and watch the verbose `[Transpiler]` log for
|
||||
remaining `(app)` failures.
|
||||
|
||||
## Required: entry points
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"mainModule": {
|
||||
"client": "client/main.js",
|
||||
"server": "server/main.js"
|
||||
},
|
||||
"testModule": "tests.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Without `mainModule`, Rspack has no entry. Meteor's eager-loading model
|
||||
does not apply: Rspack does not auto-discover modules. See
|
||||
`references/framework-and-css.md` for CSS and HTML routing.
|
||||
|
||||
## Required: no nested imports in app code
|
||||
|
||||
```javascript
|
||||
// app code: NOT allowed under Rspack
|
||||
if (condition) {
|
||||
import { a as b } from "./c";
|
||||
console.log(b);
|
||||
}
|
||||
```
|
||||
|
||||
Three fixes:
|
||||
|
||||
```javascript
|
||||
// 1. Move to top
|
||||
import { a as b } from "./c";
|
||||
if (condition) console.log(b);
|
||||
|
||||
// 2. Dynamic import (standardized, supported)
|
||||
if (condition) {
|
||||
const { a: b } = await import("./c");
|
||||
console.log(b);
|
||||
}
|
||||
|
||||
// 3. require (CommonJS interop)
|
||||
if (condition) {
|
||||
const { a: b } = require("./c");
|
||||
console.log(b);
|
||||
}
|
||||
```
|
||||
|
||||
Diagnose with verbose mode and look for `(app)` files failing with
|
||||
`Error: 'import' and 'export' cannot be used outside of module code`.
|
||||
`(package)` failures are fine; Atmosphere packages are not bundled by Rspack.
|
||||
|
||||
## Required: reserve build folders
|
||||
|
||||
The integration writes to `_build/`, `public/build-assets/`,
|
||||
`public/build-chunks/`, `private/build-assets/`. Auto-added to `.gitignore`.
|
||||
If the project already uses any of these names, rename in `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"buildContext": "build",
|
||||
"assetsContext": "assets",
|
||||
"chunksContext": "chunks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not edit any file under those folders. Exclude them from IDE indexing and
|
||||
from every recursive formatter, linter, typechecker, test-discovery, and
|
||||
coverage scan. `.gitignore` does not configure those tools.
|
||||
|
||||
Do not match the active build context in `.meteorignore` or `METEOR_IGNORE`.
|
||||
Rspack writes Meteor-facing entry modules there, then Meteor reads them to
|
||||
assemble the final bundle. Resolve renamed contexts before auditing ignores.
|
||||
|
||||
## Replacing build plugins
|
||||
|
||||
Most app-file build plugins move to Rspack loaders. Prove capability parity
|
||||
before removal; make conflicting activation and removal one reversible change.
|
||||
See `references/framework-and-css.md`.
|
||||
|
||||
| Old plugin | Replacement |
|
||||
|---------------------------|----------------------------------------------------------------------|
|
||||
| `meteor/less` | `less-loader`. See `references/framework-and-css.md`. |
|
||||
| `fourseven:scss` | `sass-loader` + `sass-embedded`. See refs. Skeleton in `meteor create --full`. |
|
||||
| `meteor/coffeescript` | `coffee-loader` (optionally chained with `swc-loader`). |
|
||||
| `zodern:melte` (Svelte) | Official Rspack Svelte loader. |
|
||||
| `jorgenvatle:vite` (Vue/Solid) | Native Rspack Vue/Solid loaders. |
|
||||
| `babel-plugin-react-compiler` | SWC on the 3.6 beta pairing; earlier integrations retain Babel. See framework reference. |
|
||||
| `zodern:types` | Still compatible. Keep it. |
|
||||
|
||||
Plugins acting only on Atmosphere package files can stay. Plugins acting on
|
||||
app-folder files (entry folder excluded) must move to Rspack.
|
||||
|
||||
## CommonJS default-import interop
|
||||
|
||||
Old Meteor accepted `import x from "some-cjs-lib"` for a `module.exports = ...`
|
||||
package. Rspack + SWC do not by default. Two options:
|
||||
|
||||
```javascript
|
||||
// preferred: switch to namespace import
|
||||
import * as x from "some-cjs-lib";
|
||||
```
|
||||
|
||||
Or restore interop in `.swcrc`:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": {
|
||||
"type": "commonjs",
|
||||
"noInterop": false,
|
||||
"importInterop": "node"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This emits CommonJS, defeating tree-shaking and static analysis app-wide.
|
||||
Migrate imports instead unless you cannot.
|
||||
|
||||
## CI and Docker
|
||||
|
||||
Resolve required npm updates locally and commit `package.json` and the lockfile.
|
||||
Use the existing manager's frozen install with dev dependencies, then build.
|
||||
On `rspack@1.3.0` (Meteor 3.5.2), `meteor.autoInstallDeps: false` still reports
|
||||
missing/outdated dependencies and manual commands; earlier opt-out behavior
|
||||
can skip those checks. Inspect the first dependency/config error and the actual
|
||||
project root before choosing a fix. See `references/troubleshooting.md`.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Add Rspack before fixing Babel fallbacks. Find them with
|
||||
`"meteor": { "modern": { "transpiler": { "verbose": true } } }` and fix
|
||||
them while still on the optimization-only stack.
|
||||
- Restore CJS interop globally in `.swcrc` to avoid migrating a handful of
|
||||
imports. Trades real bundle-size wins for short-term convenience.
|
||||
- Commit `_build/`, `public/build-assets/`, `public/build-chunks/`,
|
||||
`private/build-assets/`. Autogenerated.
|
||||
- Change the release without reviewing its paired dependencies and committing
|
||||
the authoritative lockfile. Validate a clean install and production build.
|
||||
|
||||
## See also
|
||||
|
||||
- `references/eval-cases.md`
|
||||
- For setup, helpers, and `rspack.config.js` API: `meteor-modern-build-stack`.
|
||||
@@ -1,94 +0,0 @@
|
||||
# Client graph preflight
|
||||
|
||||
Rspack compiles application modules while Meteor still compiles Atmosphere
|
||||
packages and assembles the final bundle. Audit both systems at the boundaries
|
||||
that shape the browser graph.
|
||||
|
||||
## Build separate reachability graphs
|
||||
|
||||
Start from every configured root:
|
||||
|
||||
- `meteor.mainModule.client`;
|
||||
- `meteor.testModule.client`, or the client side of `testModule`;
|
||||
- client entry points declared by local Atmosphere packages.
|
||||
|
||||
Follow static imports, re-exports, and literal `require()` calls. Record dynamic
|
||||
`import()` edges separately because they are intentional split points. Do not
|
||||
classify a module only from `client/`, `server/`, or `imports/` in its path.
|
||||
|
||||
## Resolve clean-checkout inputs
|
||||
|
||||
Resolve every static edge from each client and client-test root in a clean
|
||||
checkout before activation. A missing module can be:
|
||||
|
||||
- a checked-in source file;
|
||||
- a generated file excluded by Git;
|
||||
- a virtual module supplied by a loader or plugin;
|
||||
- an alias resolved by Rspack, TypeScript, Babel, or SWC;
|
||||
- a package export selected by browser conditions.
|
||||
|
||||
Do not require every import target to exist as a physical file. First apply the
|
||||
active aliases, package exports, extensions, and loader rules. When a target is
|
||||
generated, find its producer and require a deterministic command before
|
||||
development, test, CI, and production builds that consume it. Do not commit
|
||||
generated output automatically. Reproduce from a clean checkout with caches
|
||||
empty and fail preflight if no documented producer can create the input.
|
||||
|
||||
Server unit tests do not prove this graph compiles. Run test-mode client
|
||||
compilation or a browser-backed client suite, plus a production client build.
|
||||
|
||||
## Flag risky client-reachable modules
|
||||
|
||||
| Finding | Interpretation | Action |
|
||||
|---------|----------------|--------|
|
||||
| `module.exports` or `exports.*` in an ESM graph | Mixed module ownership can abort evaluation or defeat static analysis. | Convert the module consistently to ESM or move it behind a server boundary. |
|
||||
| Node built-in import | Browser code may be reaching server-only behavior. Rspack does not add Node polyfills automatically. | Move the module server-side or document and configure an intentional browser polyfill. |
|
||||
| Local package main module has no architecture | Meteor may load server dependencies on the client. | Add the correct `client` or `server` architecture in `package.js`. |
|
||||
| Meteor package shim writes CommonJS exports | A compatibility shim can become the first failed module in the client chain. | Export valid ESM or keep the shim outside the Rspack client graph. |
|
||||
|
||||
Node built-ins to inspect include bare and `node:` forms of `fs`, `path`,
|
||||
`crypto`, `stream`, `buffer`, `process`, `os`, `child_process`, `net`, `tls`,
|
||||
`http`, `https`, `zlib`, `vm`, and `worker_threads`.
|
||||
[Rspack does not automatically polyfill Node built-ins](https://rspack.dev/config/resolve#resolvefallback)
|
||||
for a web target.
|
||||
|
||||
Do not flag these automatically as application defects:
|
||||
|
||||
- Rspack config files and Node-only scripts;
|
||||
- server and server-test graph nodes;
|
||||
- npm packages with browser exports that remove the built-in edge;
|
||||
- explicit `resolve.fallback` or polyfill configuration;
|
||||
- native or worker dependencies intentionally passed to
|
||||
`Meteor.compileWithMeteor`.
|
||||
|
||||
Inspect the resolved graph before editing an indirect dependency.
|
||||
|
||||
## Preserve lazy boundaries
|
||||
|
||||
Inventory existing `import()` callsites before converting modules. Mark routes,
|
||||
locales, editors, and other features that must remain lazy. Do not replace those
|
||||
calls with static imports or synchronous `require()` unless eager loading is an
|
||||
explicit, measured decision. Compare build chunks before and after migration.
|
||||
[Rspack treats dynamic `import()` as an async split point](https://rspack.dev/guide/optimization/code-splitting#dynamic-imports).
|
||||
|
||||
For deployments beneath a URL path, start a production bundle with the real
|
||||
`ROOT_URL` shape and request at least one lazy chunk. Reject duplicated or
|
||||
missing asset path segments.
|
||||
|
||||
## Protect Meteor's handoff
|
||||
|
||||
Resolve `meteor.buildContext`, `meteor.assetsContext`, and
|
||||
`meteor.chunksContext`, including any suffix derived from `METEOR_LOCAL_DIR`.
|
||||
Generated contexts belong in `.gitignore` and in unrelated tool ignores, but
|
||||
the active build context MUST NOT match `.meteorignore` or `METEOR_IGNORE`.
|
||||
Rspack writes the Meteor-facing main and test modules there, then Meteor reads
|
||||
them during final assembly.
|
||||
|
||||
Separately compare top-level directory size and file count with `.gitignore`
|
||||
and `.meteorignore`. Report unrelated repositories, toolchains, generated test
|
||||
artifacts, caches, or fixtures that Git ignores but Meteor still scans. Use
|
||||
anchored ignore rules and rerun tests to ensure a broad rule did not hide client
|
||||
or server test modules.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
@@ -1,242 +0,0 @@
|
||||
# Code migrations for Rspack
|
||||
|
||||
This file covers the app-code changes the integration needs.
|
||||
|
||||
## Entry points
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"mainModule": {
|
||||
"client": "client/main.js",
|
||||
"server": "server/main.js"
|
||||
},
|
||||
"testModule": "tests.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Required for Rspack; recommended even on Meteor-only. Without it, Meteor
|
||||
loads every file eagerly and Rspack has nothing to anchor on.
|
||||
|
||||
Loading order belongs in the entry file. Imports cascade from there. See
|
||||
[Modular application structure](https://docs.meteor.com/packages/modules).
|
||||
|
||||
### Server-only apps
|
||||
|
||||
If the app has no client UI (API servers, microservices, workers), set
|
||||
only `mainModule.server`:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"mainModule": {
|
||||
"server": "server/main.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rspack builds the server bundle; the client side is skipped.
|
||||
|
||||
## Nested imports
|
||||
|
||||
Detection: enable verbose mode and watch for `(app)` files failing with
|
||||
`Error: 'import' and 'export' cannot be used outside of module code`.
|
||||
|
||||
```json
|
||||
"meteor": {
|
||||
"modern": { "transpiler": { "verbose": true } }
|
||||
}
|
||||
```
|
||||
|
||||
`(package)` files are out of scope. Atmosphere packages stay on the Meteor
|
||||
bundler under the integration.
|
||||
|
||||
### Rewrites
|
||||
|
||||
```javascript
|
||||
// 1. Top-level
|
||||
import { a as b } from "./c";
|
||||
if (condition) console.log(b);
|
||||
|
||||
// 2. Dynamic import. Returns a Promise; the function becomes async.
|
||||
if (condition) {
|
||||
const { a: b } = await import("./c");
|
||||
console.log(b);
|
||||
}
|
||||
|
||||
// 3. require
|
||||
if (condition) {
|
||||
const { a: b } = require("./c");
|
||||
console.log(b);
|
||||
}
|
||||
```
|
||||
|
||||
Use the dynamic-import form when the goal was code-splitting (the original
|
||||
Meteor nested-import use case). Use `require` for purely synchronous
|
||||
loading in a sync scope. Inventory intentional `import()` split points before
|
||||
cleanup and compare generated chunks afterward. Do not silently convert a lazy
|
||||
boundary into an eager import.
|
||||
|
||||
## Default-import interop for CommonJS
|
||||
|
||||
Old Meteor accepted `import x from "some-cjs"` for a package whose source
|
||||
is `module.exports = ...`. Rspack + SWC do not by default.
|
||||
|
||||
```javascript
|
||||
// before
|
||||
import x from "some-cjs-lib";
|
||||
|
||||
// after, preferred
|
||||
import * as x from "some-cjs-lib";
|
||||
```
|
||||
|
||||
If the upstream package shape makes namespace import wrong (e.g. a single
|
||||
default export reshaped to namespace), the SWC interop knob restores
|
||||
Meteor's old behavior:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": {
|
||||
"type": "commonjs",
|
||||
"noInterop": false,
|
||||
"importInterop": "node"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Cost: SWC emits CommonJS everywhere. Rspack loses ES module boundaries,
|
||||
so tree-shaking and static analysis are off across the app. Migrate the
|
||||
handful of imports instead unless there is no alternative.
|
||||
|
||||
## Aliases
|
||||
|
||||
Three places to keep in sync:
|
||||
|
||||
```javascript
|
||||
// rspack.config.js
|
||||
const { defineConfig } = require('@meteorjs/rspack');
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
resolve: {
|
||||
alias: {
|
||||
'@ui': '/imports/ui',
|
||||
'@api': '/imports/api',
|
||||
},
|
||||
},
|
||||
}));
|
||||
```
|
||||
|
||||
```json
|
||||
// tsconfig.json (IDE + ESLint)
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@ui/*": ["imports/ui/*"],
|
||||
"@api/*": ["imports/api/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
// .swcrc (only if SWC needs to resolve the alias during transpile)
|
||||
{
|
||||
"jsc": {
|
||||
"baseUrl": "./",
|
||||
"paths": { "@ui/*": ["imports/ui/*"] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Limits:
|
||||
|
||||
- SWC `paths` resolve `import` only, not `require(...)`.
|
||||
- Rspack `resolve.alias` resolves both `import` and `require`. Prefer
|
||||
Rspack when both forms are in use.
|
||||
|
||||
For dynamic aliases by env, use `swc.config.js` (a function that returns
|
||||
the SWC config).
|
||||
|
||||
## Symlinks and monorepos
|
||||
|
||||
Choose resolution from how shared code is consumed:
|
||||
|
||||
| Shared-code model | Rspack behavior | Action |
|
||||
|-------------------|-----------------|--------|
|
||||
| npm, pnpm, or Yarn workspace package imported by package name | Default package resolution follows the real package. | Keep the default. |
|
||||
| App-local source symlink imported by its path inside the app | Default resolution follows the real path and can lose the app-local import context. | Set `resolve.symlinks: false`. |
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
resolve: { symlinks: false },
|
||||
}));
|
||||
```
|
||||
|
||||
Do not disable symlink resolution for every monorepo. Apply it only when the
|
||||
application intentionally shares source by symlink location instead of package
|
||||
name. Validate imports, file watching, a development rebuild, and a production
|
||||
build from the consumer app.
|
||||
|
||||
## Reserved build folders
|
||||
|
||||
Do not commit, edit, or import from:
|
||||
|
||||
```text
|
||||
_build/ # Rspack entry + intermediate app code
|
||||
public/build-assets/ # client static assets
|
||||
public/build-chunks/ # dynamic-import code splits
|
||||
private/build-assets/ # server assets
|
||||
```
|
||||
|
||||
Auto-added to `.gitignore` the first time. If the project already uses
|
||||
these names, rename:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"buildContext": "build",
|
||||
"assetsContext": "assets",
|
||||
"chunksContext": "chunks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`.gitignore` is not a tool ignore. Add the active folder names to every
|
||||
recursive tool that scans the repository, including Biome or ESLint,
|
||||
TypeScript, test discovery, coverage, and IDE indexing. Run those tools once
|
||||
after an Rspack build so generated files cannot hide a missing exclusion.
|
||||
|
||||
Do not add the active build context to `.meteorignore` or `METEOR_IGNORE`.
|
||||
Meteor consumes the Rspack-generated main and test modules from that directory.
|
||||
See `client-graph-preflight.md` for renamed contexts and source-tree scanning.
|
||||
|
||||
## Verifying a migration
|
||||
|
||||
Verify from a clean clone, not only from a developer tree with cached files
|
||||
or ignored settings:
|
||||
|
||||
1. The existing manager's frozen install preserves its lockfile: `meteor npm ci`
|
||||
for npm, root `pnpm install --frozen-lockfile` for pnpm workspaces, or the
|
||||
installed Yarn version's immutable/frozen command.
|
||||
2. `"meteor": { "modern": true }` is set and the documented development
|
||||
command starts with a tracked, nonsecret settings fixture.
|
||||
3. `meteor add rspack` has produced a committed `rspack.config.*` and the
|
||||
required npm dependency changes.
|
||||
4. Verbose mode shows app code running through Rspack/SWC; only Atmosphere
|
||||
`(package)` files run through the Meteor bundler.
|
||||
5. Server tests, browser-backed client tests, and the app's E2E command pass.
|
||||
6. Formatters, linters, typecheckers, and test discovery still pass after
|
||||
`_build` and asset/chunk folders exist.
|
||||
7. `meteor build --architecture os.linux.x86_64 /tmp/out` produces a bundle
|
||||
and no warnings about reserved Rspack config keys.
|
||||
8. `git status --short` remains clean after the complete sequence.
|
||||
|
||||
Then boot the extracted production bundle and load it in a browser. Assert that
|
||||
the expected test suites executed rather than accepting a compile-only or
|
||||
zero-test result. Use `validation-matrix.md` for conditional paths such as lazy
|
||||
chunks, subpath deployment, legacy browsers, and long watch sessions.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
@@ -1,359 +0,0 @@
|
||||
# Evaluation cases for `migrate-to-rspack`
|
||||
|
||||
## Case 1: nested-import diagnosis
|
||||
|
||||
Prompt: "After `meteor add rspack`, my build fails with `Error: 'import'
|
||||
and 'export' cannot be used outside of module code` on `imports/app.js`.
|
||||
What do I do?"
|
||||
|
||||
Pass if the agent identifies a nested import (an ES `import` inside a
|
||||
conditional, function, or block), explains it is not standard syntax, and
|
||||
shows the three fixes: move to top, dynamic `import()`, or `require`.
|
||||
Bonus: mentions verbose mode for finding more `(app)` failures.
|
||||
|
||||
## Case 2: SCSS plugin replacement
|
||||
|
||||
Prompt: "I use `fourseven:scss` and want to add Rspack. How do I migrate
|
||||
my SCSS?"
|
||||
|
||||
Pass if the agent removes `fourseven:scss` from `.meteor/packages`,
|
||||
installs `sass-embedded` and `sass-loader`, and adds an SCSS rule to
|
||||
`rspack.config.js` using `type: 'css/auto'` and the
|
||||
`api: 'modern-compiler'` option. Bonus: notes that `meteor create --full`
|
||||
on 3.4.1+ ships this exact setup.
|
||||
|
||||
## Case 3: default-import breaks after migration
|
||||
|
||||
Prompt: "After enabling Rspack, `import x from "some-cjs-lib"` returns
|
||||
undefined. The package uses `module.exports = ...`. What changed?"
|
||||
|
||||
Pass if the agent explains that Rspack + SWC do not provide the old
|
||||
Meteor default-import interop, and proposes `import * as x` as the first
|
||||
fix. If the agent also explains the `.swcrc` `noInterop: false`
|
||||
workaround, it must call out the tree-shaking cost.
|
||||
|
||||
## Case 4: CI cannot find rspack.config.js
|
||||
|
||||
Prompt: "Local builds work but Docker fails with `Could not find
|
||||
rspack.config.js`. What's missing?"
|
||||
|
||||
Pass if the agent checks the project root, config file and earlier dependency
|
||||
errors, treating an incomplete npm upgrade as a hypothesis. It should prefer
|
||||
resolving required dependencies locally, committing `package.json` and the
|
||||
lockfile, then using `meteor npm ci` with build-time dev dependencies in Docker.
|
||||
Fail if it asserts the cause from this error alone or suppresses install errors.
|
||||
|
||||
## Case 5: server-only app
|
||||
|
||||
Prompt: "I have a background-worker Meteor app with no UI. Can I use
|
||||
Rspack? How do I configure it?"
|
||||
|
||||
Pass if the agent confirms it works, shows a `package.json` with only
|
||||
`mainModule.server`, and notes that Rspack will skip the client build
|
||||
entirely.
|
||||
|
||||
## Case 6: integration major mismatch
|
||||
|
||||
Prompt: "I upgraded from Meteor 3.4 to 3.4.1 but kept
|
||||
`@meteorjs/rspack@^1.0.0`. The config now fails in a clean build. Should I
|
||||
align it with my `@rspack/core` major?"
|
||||
|
||||
Pass if the agent requires `@meteorjs/rspack` v2 for Meteor 3.4.1, explains
|
||||
that Meteor 3.4.1 pairs `rspack@1.1.0` with `@meteorjs/rspack@2.0.1`, keeps its
|
||||
version independent from core/CLI, and uses startup auto-install or explicit
|
||||
`meteor update --npm` to update and commit the dependency files.
|
||||
|
||||
## Case 7: generated files break Biome
|
||||
|
||||
Prompt: "The app builds with Rspack, but `biome check .` now reports errors
|
||||
inside `_build/main-dev`. The directory is already in `.gitignore`."
|
||||
|
||||
Pass if the agent explains that Git ignores do not necessarily configure
|
||||
Biome and adds all active Rspack output folders to the tool's own ignore.
|
||||
It should rerun Biome after a build.
|
||||
|
||||
## Case 8: cached migration passes, clean clone fails
|
||||
|
||||
Prompt: "Rspack works in my existing checkout, but a fresh clone cannot
|
||||
start because an ignored settings file is missing. Is the migration done?"
|
||||
|
||||
Pass if the agent rejects the cached-checkout result, requires a tracked
|
||||
nonsecret settings fixture or documented environment setup, and verifies
|
||||
development, tests, E2E, production build, and clean Git status from a fresh
|
||||
clone.
|
||||
|
||||
## Case 9: CommonJS assignment in the client graph
|
||||
|
||||
Prompt: "After Rspack, every page is blank. A helper imported through a shared
|
||||
model uses `module.exports`, but the file lives outside `client/`. Server tests
|
||||
pass. Should I enable global CommonJS interop?"
|
||||
|
||||
Pass if the agent traces reachability from the client entry, distinguishes this
|
||||
from default-import interop, and either converts the reachable module to
|
||||
consistent ESM or moves it behind a server boundary. Fail if it classifies the
|
||||
file by pathname or changes `.swcrc` globally without inspecting the graph.
|
||||
|
||||
## Case 10: Node built-in enters the browser
|
||||
|
||||
Prompt: "The client build now fails on `crypto` and `stream`. The import comes
|
||||
from a local Atmosphere package whose `api.mainModule('index.js')` contains
|
||||
server lockout logic."
|
||||
|
||||
Pass if the agent inspects the package architecture, restricts the entry to
|
||||
`server` when appropriate, and verifies a browser production smoke. Accept a
|
||||
polyfill only when the behavior is intentionally browser-compatible.
|
||||
|
||||
## Case 11: `_build` added to `.meteorignore`
|
||||
|
||||
Prompt: "I copied generated paths from `.gitignore` into `.meteorignore`. Now
|
||||
Meteor says it cannot find `_build/main-prod/server-meteor.js`."
|
||||
|
||||
Pass if the agent identifies `_build` as the Rspack-to-Meteor handoff, removes
|
||||
the active build context from `.meteorignore`, checks renamed contexts, and
|
||||
keeps the path ignored only by Git and unrelated recursive tools.
|
||||
|
||||
## Case 12: lazy chunks under a path prefix
|
||||
|
||||
Prompt: "The production app works at `/`, but under `ROOT_URL=https://host/app`
|
||||
opening a lazy route requests `build-chunks/build-chunks/x.js`."
|
||||
|
||||
Pass if the agent tests a real dynamic import under the deployed URL prefix,
|
||||
fixes the public base without making the import static, and verifies that the
|
||||
chunk loads and executes.
|
||||
|
||||
## Case 13: server healthy, browser blank
|
||||
|
||||
Prompt: "The Rspack production bundle builds, starts, and returns HTTP 200, but
|
||||
the browser page is blank. Can I call the migration complete?"
|
||||
|
||||
Pass if the agent rejects server health as sufficient, finds the first browser
|
||||
module exception, inspects the client graph, and requires a browser smoke
|
||||
against the extracted production bundle.
|
||||
|
||||
## Case 14: CSS outside the entry folder
|
||||
|
||||
Prompt: "After defining `client/main.js` for Rspack, a global stylesheet in
|
||||
`styles/main.css` is no longer included. I need Meteor to keep compiling it and
|
||||
do not want to import it through an Rspack loader."
|
||||
|
||||
Pass if the agent adds the stylesheet to `meteor.modules`, does not add
|
||||
JavaScript there, and verifies the final stylesheet output. Bonus if it explains
|
||||
that importing through an Rspack loader is the faster-HMR alternative.
|
||||
|
||||
## Case 15: app-local source symlink
|
||||
|
||||
Prompt: "My Meteor app imports `imports/shared` through a source-directory
|
||||
symlink. Rspack resolves the real directory outside the app and breaks relative
|
||||
imports. Should every pnpm workspace set `resolve.symlinks: false`?"
|
||||
|
||||
Pass if the agent distinguishes app-local source symlinks from package-name
|
||||
workspace imports, sets `resolve.symlinks: false` only for the former, and
|
||||
validates watching and production bundling from the consumer app.
|
||||
|
||||
## Case 16: CSS delegation depends on Meteor version
|
||||
|
||||
Prompt: "I configured `postcss-loader` while migrating a Meteor 3.4.0 app to
|
||||
Rspack. Meteor and Rspack both emit the stylesheet. Should I add every generated
|
||||
folder to `.meteorignore`?"
|
||||
|
||||
Pass if the agent identifies automatic stylesheet delegation as Meteor 3.4.1+
|
||||
behavior, prefers upgrading, and uses only a narrow temporary stylesheet ignore
|
||||
when 3.4.0 is an intentional constraint. It must protect the active build
|
||||
context and verify the expected CSS appears exactly once in development and
|
||||
production.
|
||||
|
||||
## Case 17: custom build plugin has hidden behavior
|
||||
|
||||
Prompt: "A custom Meteor build plugin compiles `.theme` files, copies fonts in
|
||||
production, and injects an alias in tests. Rspack has a loader for `.theme`, so
|
||||
can I remove the plugin now?"
|
||||
|
||||
Pass if the agent inventories all three capabilities, configures equivalent
|
||||
Rspack behavior, and validates development, test, and production outputs before
|
||||
removal. If the two pipelines conflict, it must use a checkpoint and one
|
||||
reversible activation/removal change. Fail if it treats the matching extension
|
||||
as complete parity or upgrades the UI framework unnecessarily.
|
||||
|
||||
## Case 18: ignored generated module in the client graph
|
||||
|
||||
Prompt: "Server tests pass, but a clean production client build cannot resolve
|
||||
`./generated/schema.json`. The file is Gitignored and exists on developer
|
||||
machines after another tool runs. Should I commit it?"
|
||||
|
||||
Pass if the agent traces the client and client-test graph, identifies and runs
|
||||
the deterministic producer before every consuming path, and validates clean
|
||||
test-mode and production client builds. It must not commit generated output
|
||||
automatically. Fail if it accepts server tests as client compilation evidence.
|
||||
|
||||
## Case 19: successful test command runs no client tests
|
||||
|
||||
Prompt: "`meteor test --once` exits zero and reports six server tests, followed
|
||||
by `browser client tests were not run`. The Rspack changes are client-only. Can
|
||||
I merge?"
|
||||
|
||||
Pass if the agent requires a browser driver or browser-backed client suite,
|
||||
checks expected suite counts, compiles the real test-mode client entry, and
|
||||
retains a production browser smoke. Fail if it treats exit zero or server-only
|
||||
tests as sufficient.
|
||||
|
||||
## Case 20: current helper copied into Meteor 3.4.0
|
||||
|
||||
Prompt: "A current Rspack example uses `Meteor.persistDevFiles`,
|
||||
`Meteor.replaceSwcConfig`, and `Meteor.enablePortableBuild`. My migration is
|
||||
fixed on Meteor 3.4.0. Can I paste those helpers?"
|
||||
|
||||
Pass if the agent identifies Meteor 3.4.1 and `@meteorjs/rspack` v2 as the
|
||||
minimum for all three helpers, checks the resolved Atmosphere and npm package
|
||||
versions, and either upgrades the paired Meteor integration or designs and
|
||||
tests direct Rspack equivalents. Fail if it installs v2 alone or assumes
|
||||
current `devel` helper availability applies to Meteor 3.4.0.
|
||||
|
||||
## Case 21: cache panic with valuable local data
|
||||
|
||||
Prompt: "Meteor 3.5.2 Rspack exits before its first compile and reports an
|
||||
incompatible persistent cache. I have valuable data in local Mongo. Give me
|
||||
the smallest recovery step."
|
||||
|
||||
Pass if the agent preserves the first error, stops affected build processes,
|
||||
resolves and clears only the Rspack cache, and retries. It may escalate to
|
||||
`meteor reset` only after checking its release behavior. Fail if it deletes
|
||||
`.meteor/local`, uses `--db`, disables cache permanently, or raises heap limits
|
||||
without evidence of OOM.
|
||||
|
||||
## Case 22: cache recovery on an earlier integration
|
||||
|
||||
Prompt: "Our Rspack migration must remain on Meteor 3.4.0. The first compile
|
||||
hangs after a child-process error. Can I rely on the 3.5.2 fail-fast behavior
|
||||
and delete .meteor/local to reset it?"
|
||||
|
||||
Pass if the agent captures the child error, identifies the later fail-fast fix,
|
||||
honors the pinned release, and protects local Mongo. It checks reset semantics
|
||||
or chooses targeted cache recovery only when cache evidence supports it.
|
||||
|
||||
## Case 23: upgrade with immutable CI dependencies
|
||||
|
||||
Prompt: "We migrated to Meteor 3.5.2 and opted out of npm auto-install. A
|
||||
clean Docker build lists outdated Rspack dependencies. Prepare the dependency
|
||||
workflow without letting CI rewrite our lockfile."
|
||||
|
||||
Pass if the agent checks the 1.3.0/2.2.0 integration pairing and reported
|
||||
minimums, resolves and reviews the dependency files locally, preserves runtime
|
||||
helpers and build-time dev dependencies, and verifies a clean immutable build.
|
||||
|
||||
## Case 24: Rspack 2 config migration
|
||||
|
||||
Prompt: "Upgrade our Meteor 3.5.2 Rspack app to 3.6-beta.0. Its config uses experiments.css, experiments.cache, output.libraryTarget, webpack-merge, and .swcrc. What must change?"
|
||||
|
||||
Pass if the agent: Uses the beta package pairing, removes obsolete CSS experiment, moves cache top-level, reviews library.type while preserving Meteor output, replaces webpack-merge with rspack-merge, and preserves Meteor wrapper .swcrc discovery despite raw Rspack 2 behavior.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 25: npm peer transition warning
|
||||
|
||||
Prompt: "On Meteor 3.6-beta.0 autoInstallDeps is false and installed Rspack core/CLI/React Refresh are 1.x. The printed npm update command hits old peer constraints. Should we set legacy-peer-deps globally?"
|
||||
|
||||
Pass if the agent: Rejects a global bypass, verifies the coordinated Rspack 2 transition, permits a scoped npm --legacy-peer-deps invocation for confirmed old peers, and notes the beta manual warning may omit the flag. Does not apply the flag to pnpm or Yarn.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 26: preserve an existing Workbox migration
|
||||
|
||||
Prompt: "We are moving an existing Meteor app to the 3.6 beta Rspack pairing. It uses a Workbox-generated service worker. Must we discard it for the new Blaze PWA scaffold?"
|
||||
|
||||
Pass if the agent: Treats Workbox as optional but valid, inventories generation and cache/update behavior, proves migration parity, and does not overwrite the existing app or promise offline data.
|
||||
Fail if it contradicts these boundaries or invents unsupported commands.
|
||||
|
||||
## Case 27: automatic upgrade of an existing Rspack app
|
||||
|
||||
Prompt: "Our existing Meteor 3.5.2 app already uses Rspack and automatic npm installation is enabled. Upgrade to 3.6-beta.0. Must we run meteor update --npm separately, re-add rspack, or regenerate our working config?"
|
||||
|
||||
Pass if the agent gives the release update then normal `meteor run`, explains
|
||||
startup's paired dependency update, and reviews/commits the resulting version
|
||||
files and authoritative lockfile. It keeps valid entries/configuration and
|
||||
checks custom tooling separately. Fail if it requires the extra npm command,
|
||||
re-adds Rspack or promises automatic rewriting of all custom configuration.
|
||||
|
||||
## Case 28: beta startup with deliberate auto-install opt-out
|
||||
|
||||
Prompt: "We are upgrading our Rspack app to Meteor 3.6-beta.0, but meteor.autoInstallDeps is false and CI must never rewrite dependencies. Will normal startup still upgrade everything? Give the local preparation and CI boundary."
|
||||
|
||||
Pass if the agent respects the opt-out, prepares the coordinated dependency
|
||||
set locally, reviews and commits changes, then uses the existing manager's
|
||||
frozen install with build-time dev dependencies. It explains that explicit
|
||||
`meteor update --npm` overrides the opt-out for that invocation. Fail if it
|
||||
silently enables auto-install, mutates locks in CI or treats opt-out as success
|
||||
despite unresolved required dependencies.
|
||||
|
||||
## Case 29: Svelte preprocessing after the beta upgrade
|
||||
|
||||
Prompt: "After upgrading to Meteor 3.6-beta.0/Rspack 2, a Skeleton Svelte component fails during TypeScript preprocessing. We use svelte-loader and svelte-preprocess with PostCSS. Our tsconfig has extends and path aliases. What can we learn from Complex Todos without replacing our build setup?"
|
||||
|
||||
Pass if the agent checks resolved compiler/loader/preprocessor versions and
|
||||
the first error, describes the example's Svelte update and TypeScript dev
|
||||
dependency/configuration, and merges relevant `target`/`verbatimModuleSyntax`
|
||||
options while preserving existing settings. It retains needed PostCSS and
|
||||
verifies an affected component and CSS in development and production. Fail if
|
||||
it treats observed versions as universal minimums, overwrites the config or
|
||||
migrates the app to Vite/SvelteKit.
|
||||
|
||||
## Case 30: Lingui plugin major differs from the application toolchain
|
||||
|
||||
Prompt: "On Meteor 3.6-beta.0 with @rspack/core 2.2.0, our builtin:swc-loader fails loading @lingui/swc-plugin 5.11.0. The other Lingui tools are 5.x. Should I update only @swc/core, remove the plugin, or upgrade every Lingui package to 6? Notes Offline changed the plugin to 6.7.0."
|
||||
|
||||
Pass if the agent identifies Rspack's embedded SWC as the relevant host,
|
||||
checks resolved plugin/runtime compatibility, and treats the example's
|
||||
plugin update as a candidate rather than a universal pin. It preserves
|
||||
required macro transforms, explains independently versioned tooling, and
|
||||
verifies representative transformed and translated output. Fail if any of the
|
||||
three proposed shortcuts is presented as sufficient without that evidence.
|
||||
|
||||
## Case 31: newer example fix on a pinned older compiler
|
||||
|
||||
Prompt: "Our Meteor 3.5.2 app must keep Rspack 1 for now. Lingui builds correctly. Should we copy Notes Offline's @lingui/swc-plugin 6.7.0 upgrade to prepare for Meteor 3.6?"
|
||||
|
||||
Pass if the agent preserves the working release/integration pairing, rejects
|
||||
a speculative plugin upgrade and requires compatibility with the actual
|
||||
resolved compiler before any later change. Fail if it treats the PR's plugin
|
||||
version as a Meteor-wide floor or silently moves this app to Rspack 2.
|
||||
|
||||
## Case 32: raw Rspack 2 advice versus Meteor configuration
|
||||
|
||||
Prompt: "The Rspack 2 guide says its packages are pure ESM, dev-server is explicit, and resolve.roots defaults to empty. After upgrading our Meteor app to 3.6-beta.0, should I replace our working CommonJS rspack.config.js with a standalone ESM config and rebuild all resolution rules? Our host CI image still uses Node 18."
|
||||
|
||||
Pass if the agent distinguishes host Node from Meteor's build runtime,
|
||||
checks Rspack 2's supported Node floor, preserves valid Meteor CommonJS
|
||||
configuration/output and notes that Meteor supplies dev-server and project
|
||||
roots. It inspects effective configuration and custom overrides before
|
||||
changing resolution. Fail if it assumes raw defaults replace Meteor's values,
|
||||
converts the project to ESM unconditionally or ignores the old host runtime.
|
||||
Also fail if it calls host Node 18 the proven build blocker without checking
|
||||
whether the command uses Meteor's supported bundled Node instead.
|
||||
|
||||
## Case 33: beta feedback without overstating validation
|
||||
|
||||
Prompt: "All five examples in PR #50 started, so can we say every plugin and offline/production behavior is verified? My beta app still fails in a custom loader. Help me prepare feedback; do not post anything."
|
||||
|
||||
Pass if the agent limits the PR claim to reported migration/startup, requires
|
||||
the affected feature and applicable production/offline checks, and drafts a
|
||||
redacted reproduction checklist with releases, resolved toolchain, runtime,
|
||||
config, command/mode, expected/actual result and first error. It distinguishes
|
||||
base integration from app tooling without assigning unproven blame. Fail if
|
||||
it claims tests were run, dismisses all plugin issues as outside Meteor, or
|
||||
posts a report.
|
||||
|
||||
## Case 34: new-app setup is not a migration
|
||||
|
||||
Prompt: "I'm creating a new Meteor 3.6-beta.0 app, not upgrading an existing one. I need the initial Rspack setup and an explanation of defineConfig versus extendConfig. Which skill owns this?"
|
||||
|
||||
Pass if the agent selects `meteor-modern-build-stack` for setup/configuration
|
||||
helpers, reserving `migrate-to-rspack` for existing-app migration compatibility.
|
||||
Fail if it requires a legacy-plugin removal or Rspack 1-to-2 migration first.
|
||||
|
||||
## Case 35: a working older plugin on Rspack 2
|
||||
|
||||
Prompt: "We use Rspack 2.2.0 and @lingui/swc-plugin 5.11.0. A simple macro compiles and renders correctly. Must we upgrade to 6.7.0 because Notes Offline did? Does our smoke prove its reported failure was wrong?"
|
||||
|
||||
Pass if the agent rejects both inferences: it preserves compatible working
|
||||
tooling without a speculative upgrade and limits the smoke to its actual
|
||||
input/mode. It requires reproduction through the affected JSX/catalog/loader
|
||||
path and applicable development/production checks before a broader claim.
|
||||
Fail if it declares all plugin 5.x versions broken on Rspack 2, forces the
|
||||
example pin, or dismisses a different project's failure from this one smoke.
|
||||
@@ -1,298 +0,0 @@
|
||||
# Framework and CSS migration
|
||||
|
||||
Rspack replaces most Meteor build plugins that act on app files. Atmosphere
|
||||
package internals can keep their old plugin. Framework-specific notes
|
||||
below; each links to the underlying Rspack guide.
|
||||
|
||||
## React
|
||||
|
||||
Works out of the box. `meteor add rspack` detects React in
|
||||
`package.json` and registers `react-refresh` automatically.
|
||||
|
||||
Skeleton: `meteor create --react`.
|
||||
|
||||
## Preact
|
||||
|
||||
Detected the same way as React. When Preact is in `package.json`, Meteor
|
||||
skips adding React-only dependencies (no `react-refresh`). No extra config.
|
||||
|
||||
## React Compiler
|
||||
|
||||
On Meteor 3.6-beta.0's Rspack 2.2.0 / `@meteorjs/rspack@3.0.0-beta.1`
|
||||
pairing, prefer the built-in SWC compiler through `Meteor.extendSwcConfig`.
|
||||
Use `meteor-react` for React 19 and React 17/18 target/runtime setup.
|
||||
Earlier integrations retain a Babel loader scoped to `.jsx`/`.tsx`; Babel
|
||||
also remains valid for options unsupported by SWC. Do not remove a custom
|
||||
Babel pipeline until its other transforms and runtime behavior are preserved.
|
||||
See the [Rspack React Compiler guide](https://rspack.rs/guide/tech/react#react-compiler).
|
||||
|
||||
## Vue
|
||||
|
||||
Native Rspack Vue loader, no `jorgenvatle:vite` needed. Remove
|
||||
`jorgenvatle:vite` from `package.json` after adding `rspack`.
|
||||
|
||||
Skeleton: `meteor create --vue`.
|
||||
|
||||
## Solid
|
||||
|
||||
Native Rspack Solid loader, no `jorgenvatle:vite` needed.
|
||||
|
||||
Skeleton: `meteor create --solid`.
|
||||
|
||||
## Svelte
|
||||
|
||||
Use the official Rspack Svelte integration. `zodern:melte` does not work
|
||||
with the integration. If the codebase relied on melte-specific helpers
|
||||
like `$` or `$m`, replace them with standard Svelte equivalents or
|
||||
project-local abstractions.
|
||||
|
||||
Skeleton: `meteor create --svelte`.
|
||||
|
||||
## CoffeeScript
|
||||
|
||||
Combine `coffee-loader` with `swc-loader` to keep app code on SWC.
|
||||
|
||||
```bash
|
||||
npm install --save-dev coffeescript swc-loader coffee-loader
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { defineConfig } = require('@meteorjs/rspack');
|
||||
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.coffee$/i,
|
||||
use: [
|
||||
{ loader: 'swc-loader', options: Meteor.swcConfigOptions },
|
||||
{ loader: 'coffee-loader' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: { extensions: ['.coffee'] },
|
||||
}));
|
||||
```
|
||||
|
||||
Skeleton: `meteor create --coffeescript`.
|
||||
|
||||
## Angular
|
||||
|
||||
Experimental. Builds and runs in dev, prod, and test mode.
|
||||
|
||||
Skeleton: `meteor create --angular`.
|
||||
|
||||
## Babel as the app transpiler
|
||||
|
||||
Rspack supports Babel as an alternative to SWC. Slower. Useful for
|
||||
Babel-only plugins or compiler requirements unsupported by SWC. If a single
|
||||
file needs Babel, restrict the loader to that file rather than the whole
|
||||
app.
|
||||
|
||||
Skeleton: `meteor create --babel`.
|
||||
|
||||
## CSS and HTML outside the entry folder
|
||||
|
||||
Rspack requires JavaScript entry points, but Meteor can keep processing selected
|
||||
CSS or HTML outside the entry folder. List those paths under `meteor.modules`:
|
||||
|
||||
```json
|
||||
{
|
||||
"meteor": {
|
||||
"modules": ["styles/main.css", "imports/shell.html"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use this when a Meteor HTML or stylesheet compiler must retain ownership. Do
|
||||
not add JavaScript expecting Meteor to compile it; Rspack owns app scripts. If
|
||||
the file can be imported through a configured Rspack loader, prefer that path
|
||||
for faster HMR. Validate that every listed path exists and that the final HTML
|
||||
or stylesheet contains its output.
|
||||
|
||||
## Replace build plugins by capability
|
||||
|
||||
Before removing a Meteor build plugin, identify what it actually provides:
|
||||
|
||||
```text
|
||||
handled extensions and source roots
|
||||
loader or transform order
|
||||
development and production branches
|
||||
generated files and copied assets
|
||||
injected globals, aliases, or virtual modules
|
||||
source maps and minification behavior
|
||||
```
|
||||
|
||||
Configure the matching Rspack loaders and plugins before removing the old
|
||||
owner. Compare representative development and production outputs, including
|
||||
generated CSS or assets and test-mode compilation. Remove the old plugin only
|
||||
after output and runtime parity hold. If both owners cannot coexist, checkpoint
|
||||
the working build and combine activation plus removal in one reversible change.
|
||||
Revert that change when parity fails instead of stacking unrelated dependency
|
||||
or framework upgrades.
|
||||
|
||||
Do not remove a plugin that acts only on Atmosphere package internals. Rspack
|
||||
owns app code, while Meteor still compiles Atmosphere packages and assembles
|
||||
the final bundle.
|
||||
|
||||
## CSS (default)
|
||||
|
||||
Built in. Any imported CSS file is processed and added to the HTML
|
||||
skeleton. Any CSS file colocated with the entry point becomes a global
|
||||
stylesheet without an explicit import.
|
||||
|
||||
On Meteor 3.4.1 and later, when `rspack.config.js` declares a CSS rule (via
|
||||
`postcss-loader`, `type: "css"`, or another CSS loader), Meteor detects the
|
||||
handled extensions after the first compilation and stops processing those
|
||||
files. No `.meteorignore` change is required. The same auto-delegation applies
|
||||
to Less and SCSS once their loaders are configured.
|
||||
|
||||
Meteor 3.4.0 predates automatic stylesheet delegation. Prefer upgrading to
|
||||
3.4.1 or later before migrating the style pipeline. If the app must remain on
|
||||
3.4.0, use only the narrow ignore required to prevent duplicate compilation,
|
||||
verify that the exact styles still appear once in development and production,
|
||||
and remove the workaround immediately after upgrading. Never ignore the active
|
||||
Rspack build context.
|
||||
|
||||
If no CSS rule is present, Meteor keeps handling stylesheets the legacy
|
||||
way. Meteor 3.6-beta.0's paired integration supplies a `css/auto` rule by
|
||||
default; inspect the effective rules before diagnosing duplicate CSS owners.
|
||||
|
||||
## CSS Modules
|
||||
|
||||
Files named `*.module.css` are auto-scoped. Default export style is
|
||||
named:
|
||||
|
||||
```javascript
|
||||
import { app } from './App.module.css';
|
||||
```
|
||||
|
||||
For default-import style:
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
module: {
|
||||
parser: {
|
||||
'css/auto': { namedExports: false },
|
||||
'css/module': { namedExports: false },
|
||||
},
|
||||
},
|
||||
}));
|
||||
```
|
||||
|
||||
```javascript
|
||||
import styles from './App.module.css';
|
||||
```
|
||||
|
||||
TypeScript declaration (e.g. `imports/css-modules.d.ts`):
|
||||
|
||||
```typescript
|
||||
declare module '*.module.css' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
```
|
||||
|
||||
## Less
|
||||
|
||||
Replaces the `meteor/less` Meteor plugin for app files.
|
||||
|
||||
```bash
|
||||
npm i -D less less-loader
|
||||
```
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [{ loader: 'less-loader' }],
|
||||
type: 'css/auto',
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
```
|
||||
|
||||
## SCSS
|
||||
|
||||
Replaces the `fourseven:scss` Meteor plugin for app files.
|
||||
|
||||
```bash
|
||||
npm i -D sass-embedded sass-loader
|
||||
```
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.scss$/i,
|
||||
use: [{
|
||||
loader: 'sass-loader',
|
||||
options: {
|
||||
api: 'modern-compiler',
|
||||
implementation: require.resolve('sass-embedded'),
|
||||
},
|
||||
}],
|
||||
type: 'css/auto',
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
```
|
||||
|
||||
Meteor 3.4.1's `meteor create --full` skeleton ships this exact setup.
|
||||
|
||||
## Tailwind and PostCSS
|
||||
|
||||
Supported out of the box. Follow the [Rspack Tailwind guide](https://tailwindcss.com/docs/installation/framework-guides/rspack/react).
|
||||
|
||||
Skeleton: `meteor create --tailwind`.
|
||||
|
||||
## Service Worker
|
||||
|
||||
For an existing Workbox integration or a generated worker, use
|
||||
`workbox-webpack-plugin`'s `GenerateSW`. Meteor 3.6-beta.0 also supplies a
|
||||
dependency-free Blaze worker via `meteor create --pwa`; use `meteor-blaze`
|
||||
for that scaffold and preserve an existing worker when migrating. Neither
|
||||
approach supplies offline data synchronization. For Workbox:
|
||||
|
||||
1. `exclude: [/./]` to skip precaching the build output. Use
|
||||
`runtimeCaching` rules for dynamic bundles.
|
||||
2. Match HMR with `/\.hot-update\./` and set it to `NetworkOnly`.
|
||||
3. Cache `Meteor.assetsContext` and `Meteor.chunksContext` paths with
|
||||
`StaleWhileRevalidate`. They contain build output Meteor serves.
|
||||
|
||||
For a custom `sw.js` filename, persist it once to disk in dev:
|
||||
|
||||
```javascript
|
||||
...Meteor.persistDevFiles({ once: ['service-worker.js'] }),
|
||||
```
|
||||
|
||||
HTML files persist automatically.
|
||||
|
||||
Service Worker support added in Meteor 3.4.1.
|
||||
|
||||
## HTML
|
||||
|
||||
A `client/main.html` (or whatever the entry folder uses) is processed by
|
||||
Meteor's HTML pipeline as before. For deeper customization use the
|
||||
integration's `HtmlRspackPlugin`:
|
||||
|
||||
```javascript
|
||||
module.exports = defineConfig(Meteor => ({
|
||||
plugins: [
|
||||
Meteor.HtmlRspackPlugin({
|
||||
meta: {
|
||||
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
|
||||
},
|
||||
}),
|
||||
],
|
||||
}));
|
||||
```
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
@@ -1,99 +0,0 @@
|
||||
# Rspack 1 to 2 in Meteor
|
||||
|
||||
Use this branch for Meteor 3.6, verified on `3.6-beta.0`, with
|
||||
`rspack@1.4.0-beta360.0` and `@meteorjs/rspack@3.0.0-beta.1`.
|
||||
Meteor 3.5.2 keeps `rspack@1.3.0`, `@meteorjs/rspack@2.2.0` and Rspack 1.x.
|
||||
Do not force Rspack 2 into a constrained older release.
|
||||
|
||||
## Upgrade the coordinated dependency set
|
||||
|
||||
1. Checkpoint `.meteor/release`, `.meteor/versions`, app/workspace manifests,
|
||||
the authoritative lockfile and custom `rspack.config.*`.
|
||||
2. With default `meteor.autoInstallDeps` enabled, update then start normally:
|
||||
|
||||
```bash
|
||||
meteor update --release 3.6-beta.0
|
||||
meteor run
|
||||
```
|
||||
|
||||
Startup checks and updates the required Rspack project dependencies. A
|
||||
separate `meteor update --npm` is unnecessary. Review the resulting
|
||||
manifests, Meteor version files and lockfile before committing them.
|
||||
If `meteor.autoInstallDeps: false`, respect that choice: prepare the paired
|
||||
dependencies explicitly in an authorized local workflow, then commit and
|
||||
test a frozen install. `meteor update --npm` overrides the opt-out for that
|
||||
invocation; do not put a lockfile-rewriting step in immutable CI.
|
||||
3. The beta's required npm minimums are core/CLI/dev-server 2.2.0, Meteor integration
|
||||
3.0.0-beta.1, SWC core 1.15.32, helpers 0.5.23 and Rsdoctor 1.5.9.
|
||||
Keep helpers in runtime dependencies, the bundler tools in dev dependencies.
|
||||
Detected React adds refresh plugin 2.0.0 and refresh runtime 0.17.0.
|
||||
Record the resolved versions: compatible newer patches can satisfy these
|
||||
minimums without matching the original examples' lockfiles exactly.
|
||||
4. With npm and installed Rspack 1.x peers, the automatic upgrade uses
|
||||
`--legacy-peer-deps`. The beta's manual warning can omit it. If that exact
|
||||
coordinated update is rejected for stale peers, use the flag for that
|
||||
invocation, review the lockfile and validate the installed majors. Do not
|
||||
use `--force`, a global peer bypass or a flag copied into pnpm/Yarn.
|
||||
5. Keep pnpm/Yarn workspace ownership. Resolve the manager at the workspace
|
||||
root, add dependencies from the nested Meteor app, and commit its manifest
|
||||
plus the root lockfile. Preserve intentional local dependency protocols.
|
||||
|
||||
## Review app-owned overrides
|
||||
|
||||
Meteor composes its base integration configuration and creates a default file
|
||||
if none exists. It does not rewrite an existing `rspack.config.*` or migrate
|
||||
every third-party loader/plugin. Inspect the effective merged configuration
|
||||
before applying raw Rspack advice.
|
||||
|
||||
| Existing customization | Action on the beta pairing |
|
||||
|---|---|
|
||||
| `experiments.css` | Remove the obsolete option; the integration already supplies CSS rules with `type: "css/auto"`. Test CSS Modules and loader output. |
|
||||
| `experiments.cache` | Use top-level `cache`; normally retain Meteor's persistent-cache defaults or `Meteor.setCache(false)` for a measured diagnostic. |
|
||||
| `output.libraryTarget` | The upstream form is `output.library.type`, but Meteor owns final output. Remove an unnecessary override rather than replacing Meteor's output object. |
|
||||
| `webpack-merge` in app-owned configuration | Use a compatible `rspack-merge` or Meteor's `extendConfig`; install a direct dependency if the app imports it. Preserve nested rules. |
|
||||
| Missing TypeScript re-export diagnostic | Meteor defaults `module.parser.javascript.exportsPresence` to `"warn"` for SWC-stripped type exports. Inspect a custom strict override and distinguish types from missing runtime exports; do not disable checks globally. |
|
||||
| `.swcrc`, `swc.config.js`, `swc.config.ts` | Keep valid Meteor configuration: the integration reads it and passes loader options even though raw Rspack 2 no longer auto-loads `.swcrc`. |
|
||||
| Manual React Refresh plugin/bootstrap | Verify Meteor's automatic injection first; do not introduce a second refresh stack. |
|
||||
|
||||
Also check these [upstream migration boundaries](https://www.rspack.dev/guide/migration/rspack_1.x):
|
||||
|
||||
| Surface | Migration check |
|
||||
|---|---|
|
||||
| Node and ESM | Rspack 2 requires Node `^20.19.0 \|\| >=22.12.0`. Meteor 3.6-beta.0 bundles Node 24.15.0; host Node 18 alone does not prove a Meteor build incompatibility. Identify which binary actually invokes each tool before upgrading that runtime. Keep valid Meteor CommonJS configs/output despite pure-ESM Rspack packages. |
|
||||
| Dev server | `@rspack/dev-server` is now explicit; Meteor's dependency check supplies it. Review custom `devServer.proxy` and `watchFiles` against the v2 guide before reusing old shapes. |
|
||||
| Resolution | Upstream changes cover `.wasm` extension lookup, CSS `@import` conditions and empty `resolve.roots`. Meteor supplies explicit extensions and project roots. Inspect `resolve.byDependency` and custom overrides; test the failing import before changing resolution globally. |
|
||||
| Custom plugins | Review the plugin's Rspack 2 support and the [2.0 breaking-change overview](https://www.rspack.dev/blog/announcing-2-0), including compiler hook and stats API changes when used. |
|
||||
|
||||
Apply changes to app-owned overrides, not generated `_build` output or a
|
||||
replacement standalone configuration. For framework loaders, Svelte
|
||||
preprocessors and Lingui/SWC plugins, use
|
||||
[toolchain compatibility](toolchain-compatibility.md).
|
||||
|
||||
React Compiler can use the built-in SWC loader on this pairing; see
|
||||
[framework migration](framework-and-css.md). Retain Babel for an older
|
||||
integration or requirements unsupported by the SWC compiler path.
|
||||
|
||||
## Prove the result
|
||||
|
||||
Use `meteor npm ci` for an npm lockfile, `pnpm install --frozen-lockfile` at
|
||||
the pnpm workspace root, or the installed Yarn version's frozen/immutable
|
||||
install. Keep dev dependencies in the build stage. If an npm lockfile created
|
||||
with the transition flag requires it for `ci`, document that project-local
|
||||
requirement and retest after peer cleanup. Do not convert managers to fix CI.
|
||||
|
||||
Run development, a rebuild, actual client/server tests, and a production
|
||||
bundle. Exercise CSS, lazy imports, local/workspace packages and custom
|
||||
loaders when present. Boot the extracted bundle and load the browser page.
|
||||
Follow the [validation matrix](validation-matrix.md); reported example startup
|
||||
is not proof that your translations, UI components or offline updates work.
|
||||
For a failure, capture the [migration report](troubleshooting.md#reporting-issues)
|
||||
before applying another workaround.
|
||||
|
||||
On the beta's `rspack` package, HMR bootstrap belongs only to non-native
|
||||
client development under `meteor run`, outside test mode. A `meteor build`
|
||||
with `NODE_ENV=development` still has no dev-server HMR runtime. Verify the
|
||||
generated and final artifacts, then rebuild from source; never repair them by
|
||||
editing generated bootstrap files. Native HCP is a separate workflow.
|
||||
|
||||
---
|
||||
Source: https://github.com/meteor/meteor/blob/devel/v3-docs/docs/about/modern-build-stack/rspack-bundler-integration.md
|
||||
Loaded 100 of 4900 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user