mirror of
https://github.com/meteor/meteor.git
synced 2026-01-10 16:18:35 -05:00
Merge branch 'devel' into release-3.2
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
title: Docs
|
||||
---
|
||||
|
||||
> Meteor 2.x uses the deprecated Node.js 14. Meteor 3.0 has been released and runs on Node.js 20. Check out our [v3 docs](https://v3-docs.meteor.com) and [migration guide](https://v3-migration-docs.meteor.com/).
|
||||
> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 has been released with support for the latest Node.js LTS version. For more information, please consult our [migration guide](https://v3-migration-docs.meteor.com/) and the [latest docs](https://v3-docs.meteor.com).
|
||||
|
||||
<!-- XXX: note that this content is somewhat duplicated on the guide, and should be updated in parallel -->
|
||||
<h2 id="what-is-meteor">What is Meteor?</h2>
|
||||
|
||||
@@ -8,7 +8,7 @@ You need to install the Meteor command line tool to create, run, and manage your
|
||||
|
||||
<h3 id="prereqs-node">Node.js version</h3>
|
||||
|
||||
> Meteor 2.x uses the deprecated Node.js 14. Meteor 3.0 has been released and runs on Node.js 20. Check out our [v3 docs](https://v3-docs.meteor.com) and [migration guide](https://v3-migration-docs.meteor.com/).
|
||||
> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 has been released with support for the latest Node.js LTS version. For more information, please consult our [migration guide](https://v3-migration-docs.meteor.com/) and the [latest docs](https://v3-docs.meteor.com).
|
||||
|
||||
- Node.js version >= 10 and <= 14 is required.
|
||||
- We recommend you using [nvm](https://github.com/nvm-sh/nvm) or [Volta](https://volta.sh/) for managing Node.js versions.
|
||||
@@ -30,7 +30,8 @@ You need to install the Meteor command line tool to create, run, and manage your
|
||||
|
||||
Install the latest official version of Meteor.js from your terminal by running one of the commands below. You can check our [changelog](https://docs.meteor.com/changelog.html) for the release notes.
|
||||
|
||||
> Run `node -v` to ensure you are using Node.js 14. Meteor 3.0, currently in its Release Candidate version, runs on Node.js v20.
|
||||
> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 is released with support for the latest Node.js LTS version.
|
||||
> For more information, please consult our [migration guide](https://guide.meteor.com/3.0-migration.html) and the [new docs](https://docs.meteor.com/).
|
||||
|
||||
For Windows, Linux and OS X, you can run the following command:
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Introduction
|
||||
description: This is the guide for using Meteor, a full-stack JavaScript platform for developing modern web and mobile applications.
|
||||
---
|
||||
|
||||
> Meteor 2.x uses the deprecated Node.js 14. Meteor 3.0 has been released and runs on Node.js 20. Check out our [v3 docs](https://v3-docs.meteor.com) and [migration guide](https://v3-migration-docs.meteor.com/).
|
||||
> Meteor 2.x runs on a deprecated Node.js version (14). Meteor 3 has been released with support for the latest Node.js LTS version. For more information, please consult our [migration guide](https://v3-migration-docs.meteor.com/) and the [latest docs](https://v3-docs.meteor.com).
|
||||
|
||||
<!-- XXX: note that this content is somewhat duplicated on the docs, and should be updated in parallel -->
|
||||
<h2 id="what-is-meteor">What is Meteor?</h2>
|
||||
|
||||
@@ -238,9 +238,11 @@ import { Tracker } from 'meteor/tracker';
|
||||
const withDiv = function withDiv(callback) {
|
||||
const el = document.createElement('div');
|
||||
document.body.appendChild(el);
|
||||
let view = null
|
||||
try {
|
||||
callback(el);
|
||||
view = callback(el);
|
||||
} finally {
|
||||
if (view) Blaze.remove(view)
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
};
|
||||
@@ -248,9 +250,10 @@ const withDiv = function withDiv(callback) {
|
||||
export const withRenderedTemplate = function withRenderedTemplate(template, data, callback) {
|
||||
withDiv((el) => {
|
||||
const ourTemplate = isString(template) ? Template[template] : template;
|
||||
Blaze.renderWithData(ourTemplate, data, el);
|
||||
const view = Blaze.renderWithData(ourTemplate, data, el);
|
||||
Tracker.flush();
|
||||
callback(el);
|
||||
return view
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
@@ -8,6 +8,6 @@ It comes with the following packages:
|
||||
|
||||
1. [`meteor`](https://atmospherejs.com/meteor/meteor) - Super basic stuff about the programming environment, and a handler for the `css` file type.
|
||||
2. [`webapp`](https://atmospherejs.com/meteor/webapp) - The actual web server that handles connections, serves files, etc.
|
||||
3. [`underscore`](https://atmospherejs.com/meteor/underscore) - A library with lots of useful utilities that most of Meteor is built on.
|
||||
3. [`es5-shim`](https://atmospherejs.com/meteor/es5-shim) - Compiles code for old browsers like IE 8.
|
||||
4. [`hot-code-push`](https://atmospherejs.com/meteor/hot-code-push) - Refresh the client automatically when the server has new code.
|
||||
5. [`ddp`](https://atmospherejs.com/meteor/ddp) - A protocol for communicating between the client and server. This is what enables `Meteor.methods`, `Meteor.publish`, `Meteor.subscribe`, etc.
|
||||
|
||||
@@ -5,26 +5,14 @@ import metadata from "../generators/meteor-versions/metadata.generated";
|
||||
export default defineConfig({
|
||||
title: "Docs",
|
||||
description: "Meteor.js Docs",
|
||||
head: [
|
||||
["link", { rel: "icon", href: "/logo.png" }],
|
||||
[
|
||||
"script",
|
||||
{
|
||||
async: "",
|
||||
src: "https://widget.kapa.ai/kapa-widget.bundle.js",
|
||||
"data-website-id": "64051b0e-d79f-4fe7-b3ca-ff5c84075693",
|
||||
"data-project-name": "Meteor",
|
||||
"data-project-color": "#36436b",
|
||||
"data-project-logo": "/logo.png",
|
||||
"data-modal-disclaimer":
|
||||
"This is a custom LLM for answering questions about Meteor. Answers are based on the contents of the docs, answered forum posts, YouTube videos and GitHub issues. Please note that answers are generated by AI and may not be fully accurate, so please use your best judgement.",
|
||||
},
|
||||
],
|
||||
],
|
||||
head: [["link", { rel: "icon", href: "/logo.png" }]],
|
||||
lastUpdated: true,
|
||||
sitemap: {
|
||||
hostname: "https://v3-docs.meteor.com",
|
||||
},
|
||||
ignoreDeadLinks: [
|
||||
/^http:\/\/localhost/
|
||||
],
|
||||
themeConfig: {
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
@@ -408,7 +396,10 @@ export default defineConfig({
|
||||
link: "/troubleshooting/expired-certificate",
|
||||
},
|
||||
{ text: "Windows", link: "/troubleshooting/windows" },
|
||||
{ text: "MongoDB Connection", link: "/troubleshooting/mongodb-connection" }
|
||||
{
|
||||
text: "MongoDB Connection",
|
||||
link: "/troubleshooting/mongodb-connection",
|
||||
},
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
|
||||
@@ -8,76 +8,214 @@ command-line tool. This is just an overview and does not mention every command
|
||||
or every option to every command; for more details, use the `meteor help`
|
||||
command.
|
||||
|
||||
## meteor help {meteorhelp}
|
||||
## meteor help {#meteorhelp}
|
||||
|
||||
Get help on meteor command line usage. Running `meteor help` by
|
||||
itself will list the common meteor
|
||||
commands. Running <code>meteor help <i>command</i></code> will print
|
||||
detailed help about the command.
|
||||
Get help on meteor command line usage.
|
||||
|
||||
```bash
|
||||
meteor help
|
||||
```
|
||||
|
||||
## meteor run {meteorrun}
|
||||
Lists the common meteor commands.
|
||||
|
||||
Run a meteor development server in the current project. Searches
|
||||
upward from the current directory for the root directory of a Meteor
|
||||
project. Whenever you change any of the application's source files, the
|
||||
changes are automatically detected and applied to the running
|
||||
application.
|
||||
```bash
|
||||
meteor help <command>
|
||||
```
|
||||
|
||||
You can use the application by pointing your web browser at
|
||||
<a href="http://localhost:3000">localhost:3000</a>. No Internet connection is
|
||||
required.
|
||||
Prints detailed help about the specific command.
|
||||
|
||||
This is the default command. Simply running `meteor` is the
|
||||
same as `meteor run`.
|
||||
## meteor run {#meteorrun}
|
||||
|
||||
To pass additional options to Node.js use the `SERVER_NODE_OPTIONS` environment variable. E.g. for Windows PowerShell:
|
||||
`$env:SERVER_NODE_OPTIONS = '--inspect' | meteor run`. Or for Linux: `SERVER_NODE_OPTIONS=--inspect-brk meteor run`.
|
||||
Run a meteor development server in the current project.
|
||||
|
||||
To specify a port to listen on (instead of the default 3000), use `--port [PORT]`.
|
||||
(The development server also uses port `N+1` for the default MongoDB instance)
|
||||
```bash
|
||||
meteor run
|
||||
```
|
||||
|
||||
For example: `meteor run --port 4000`
|
||||
will run the development server on `http://localhost:4000`
|
||||
and the development MongoDB instance on `mongodb://localhost:4001`.
|
||||
::: tip
|
||||
This is the default command. Simply running `meteor` is the same as `meteor run`.
|
||||
:::
|
||||
|
||||
Run `meteor help run` to see the full list of options.
|
||||
### Features
|
||||
|
||||
## meteor debug {meteordebug}
|
||||
- Automatically detects and applies changes to your application's source files
|
||||
- No Internet connection required
|
||||
- Accesses the application at [localhost:3000](http://localhost:3000) by default
|
||||
- Searches upward from the current directory for the root directory of a Meteor project
|
||||
|
||||
Run the project, but suspend the server process for debugging.
|
||||
### Options
|
||||
|
||||
> **NOTE:** The `meteor debug` command has been superseded by the more flexible
|
||||
> `--inspect` and `--inspect-brk` command-line flags, which work for any `run`,
|
||||
> `test`, or `test-packages` command.
|
||||
>
|
||||
> The syntax of these flags is the same as the equivalent Node.js
|
||||
> [flags](https://nodejs.org/en/docs/inspector/#command-line-options),
|
||||
> with two notable differences:
|
||||
>
|
||||
> * The flags affect the server process spawned by the build process,
|
||||
> rather than affecting the build process itself.
|
||||
>
|
||||
> * The `--inspect-brk` flag causes the server process to pause just after
|
||||
> server code has loaded but before it begins to execute, giving the
|
||||
> developer a chance to set breakpoints in server code.
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--port`, `-p <port>` | Port to listen on (default: 3000). Also uses port N+1 and a port specified by --app-port. Specify as --port=host:port to bind to a specific interface |
|
||||
| `--open`, `-o` | Opens a browser window when the app starts |
|
||||
| `--inspect[-brk][=<port>]` | Enable server-side debugging via debugging clients. With --inspect-brk, pauses at startup (default port: 9229) |
|
||||
| `--mobile-server <url>` | Location where mobile builds connect (defaults to local IP and port). Can include URL scheme (e.g., https://example.com:443) |
|
||||
| `--cordova-server-port <port>` | Local port where Cordova will serve content |
|
||||
| `--production` | Simulate production mode. Minify and bundle CSS and JS files |
|
||||
| `--raw-logs` | Run without parsing logs from stdout and stderr |
|
||||
| `--settings`, `-s <file>` | Set optional data for Meteor.settings on the server |
|
||||
| `--release <version>` | Specify the release of Meteor to use |
|
||||
| `--verbose` | Print all output from builds logs |
|
||||
| `--no-lint` | Don't run linters used by the app on every rebuild |
|
||||
| `--no-release-check` | Don't run the release updater to check for new releases |
|
||||
| `--allow-incompatible-update` | Allow packages to be upgraded or downgraded to potentially incompatible versions |
|
||||
| `--extra-packages <packages>` | Run with additional packages (comma separated, e.g., "package-name1, package-name2@1.2.3") |
|
||||
| `--exclude-archs <archs>` | Don't create bundles for certain web architectures (comma separated, e.g., "web.browser.legacy, web.cordova") |
|
||||
|
||||
The server process will be suspended just before the first statement of
|
||||
server code that would normally execute. In order to continue execution of
|
||||
server code, use either the web-based Node Inspector or the command-line
|
||||
debugger (further instructions will be printed in the console).
|
||||
### Node.js Options
|
||||
|
||||
Breakpoints can be set using the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger" target="_blank">`debugger` keyword</a>, or through the web UI of Node Inspector ("Sources" tab).
|
||||
To pass additional options to Node.js, use the `SERVER_NODE_OPTIONS` environment variable:
|
||||
|
||||
The server process debugger will listen for incoming connections from
|
||||
debugging clients, such as node-inspector, on port 5858 by default. To
|
||||
specify a different port use the `--debug-port <port>` option.
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
$env:SERVER_NODE_OPTIONS = '--inspect' | meteor run
|
||||
```
|
||||
|
||||
The same debugging functionality can be achieved by adding the `--debug-port <port>`
|
||||
option to other `meteor` tool commands, such as `meteor run` and `meteor test-packages`.
|
||||
**Linux/macOS:**
|
||||
```bash
|
||||
SERVER_NODE_OPTIONS=--inspect-brk meteor run
|
||||
```
|
||||
|
||||
> **Note:** Due to a [bug in `node-inspector`](https://github.com/node-inspector/node-inspector/issues/903), pushing "Enter" after a command on the Node Inspector Console will not successfully send the command to the server. If you require this functionality, please consider using Safari or `meteor shell` in order to interact with the server console until the `node-inspector` project [fixes the bug](https://github.com/node-inspector/node-inspector/pull/955). Alternatively, there is a hot-patch available [in this comment](https://github.com/meteor/meteor/issues/7991#issuecomment-266709459) on [#7991](https://github.com/meteor/meteor/issues/7991).
|
||||
### Port Configuration Example
|
||||
|
||||
```bash
|
||||
meteor run --port 4000
|
||||
```
|
||||
|
||||
This command:
|
||||
- Runs the development server on `http://localhost:4000`
|
||||
- Runs the development MongoDB instance on `mongodb://localhost:4001`
|
||||
|
||||
::: info
|
||||
The development server always uses port `N+1` for the default MongoDB instance, where `N` is the application port.
|
||||
:::
|
||||
|
||||
## meteor debug {#meteordebug}
|
||||
|
||||
Run the project with the server process suspended for debugging.
|
||||
|
||||
::: warning Deprecation Notice
|
||||
The `meteor debug` command has been superseded by the more flexible `--inspect` and `--inspect-brk` command-line flags, which work with `run`, `test`, and `test-packages` commands.
|
||||
:::
|
||||
|
||||
### Modern Debugging Approach
|
||||
|
||||
```bash
|
||||
# Debug server with auto-attachment
|
||||
meteor run --inspect
|
||||
|
||||
# Debug server and pause at start
|
||||
meteor run --inspect-brk
|
||||
```
|
||||
|
||||
### Command Usage
|
||||
|
||||
```bash
|
||||
meteor debug [--debug-port <port>]
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
- Server process suspends just before the first statement of server code execution
|
||||
- Debugger listens for incoming connections on port 5858 by default
|
||||
- Use `--debug-port <port>` to specify a different port
|
||||
|
||||
### Setting Breakpoints
|
||||
|
||||
- Use the [`debugger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) keyword in your code
|
||||
- Set breakpoints through the debugging client's UI (e.g., in the "Sources" tab)
|
||||
|
||||
### Debugging Clients
|
||||
|
||||
You can use either:
|
||||
- Web-based Node Inspector
|
||||
- Command-line debugger
|
||||
|
||||
::: details Node Inspector Console Bug
|
||||
Due to a [bug in `node-inspector`](https://github.com/node-inspector/node-inspector/issues/903), pressing "Enter" after a command in the Node Inspector Console may not successfully send the command to the server.
|
||||
|
||||
**Workarounds:**
|
||||
- Use Safari browser
|
||||
- Use `meteor shell` to interact with the server console
|
||||
- Apply the hot-patch available in [this comment](https://github.com/meteor/meteor/issues/7991#issuecomment-266709459)
|
||||
:::
|
||||
|
||||
### Differences from Node.js Flags
|
||||
|
||||
The Meteor `--inspect` and `--inspect-brk` flags work similarly to Node.js flags with two key differences:
|
||||
|
||||
1. They affect the server process spawned by the build process, not the build process itself
|
||||
2. The `--inspect-brk` flag pauses execution after server code has loaded but before it begins to execute
|
||||
|
||||
### Alternative Approach
|
||||
|
||||
The same debugging functionality can be achieved by adding the `--debug-port <port>` option to other Meteor commands:
|
||||
|
||||
```bash
|
||||
meteor run --debug-port 5858
|
||||
meteor test-packages --debug-port 5858
|
||||
```
|
||||
|
||||
## meteor profile {#meteorprofile}
|
||||
|
||||
Run a performance profile for your Meteor application to analyze build and bundling performance.
|
||||
|
||||
```bash
|
||||
meteor profile [<meteor-run-options>...]
|
||||
```
|
||||
|
||||
::: info Availability
|
||||
This command is available from Meteor 3.2 and newer.
|
||||
:::
|
||||
|
||||
### Usage
|
||||
|
||||
This command monitors the bundler process and tracks key performance metrics to help analyze build and bundling performance.
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--size` | Monitor both bundle runtime and size |
|
||||
| `--size-only` | Monitor only the bundle size |
|
||||
|
||||
::: info
|
||||
All other options from `meteor run` are also supported (e.g., `--settings`, `--exclude-archs`).
|
||||
:::
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `METEOR_IDLE_TIMEOUT=<seconds>` | Set a timeout for profiling | 90 seconds |
|
||||
| `METEOR_CLIENT_ENTRYPOINT=<path>` | Set a custom client entrypoint | From package.json |
|
||||
| `METEOR_SERVER_ENTRYPOINT=<path>` | Set a custom server entrypoint | From package.json |
|
||||
| `METEOR_LOG_DIR=<path>` | Set a custom log directory | Default log directory |
|
||||
|
||||
::: tip
|
||||
The default timeout (90s) is usually enough for each build step to complete. If you encounter errors due to early exits, increase the `METEOR_IDLE_TIMEOUT` value.
|
||||
:::
|
||||
|
||||
### Example Usage
|
||||
|
||||
```bash
|
||||
# Basic profile
|
||||
meteor profile
|
||||
|
||||
# Monitor bundle size only
|
||||
meteor profile --size-only
|
||||
|
||||
# Profile with custom settings and timeout
|
||||
METEOR_IDLE_TIMEOUT=120 meteor profile --settings settings.json
|
||||
|
||||
# Profile with custom entrypoints
|
||||
METEOR_CLIENT_ENTRYPOINT=client/main.js METEOR_SERVER_ENTRYPOINT=server/main.js meteor profile
|
||||
```
|
||||
|
||||
::: details Customizing the Profiling Process
|
||||
You can pass any option that works with `meteor run` to customize the profiling process. This allows you to profile your application under specific conditions that match your deployment environment.
|
||||
:::
|
||||
|
||||
## meteor create _app-name_ {meteorcreate}
|
||||
|
||||
@@ -306,7 +444,7 @@ It will generate the following code in ``/imports/api``
|
||||
That will have the following code:
|
||||
|
||||
|
||||
## collection.js {meteorgenerate-collection.js}
|
||||
### collection.js {meteorgenerate-collection.js}
|
||||
|
||||
```js
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
@@ -316,7 +454,7 @@ export const CustomerCollection = new Mongo.Collection('customer');
|
||||
|
||||
|
||||
|
||||
## methods.js {meteorgenerate-methods.js}
|
||||
### methods.js {meteorgenerate-methods.js}
|
||||
|
||||
```js
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
@@ -352,7 +490,7 @@ Meteor.methods({
|
||||
|
||||
|
||||
|
||||
## publication.js {meteorgenerate-publication.js}
|
||||
### publication.js {meteorgenerate-publication.js}
|
||||
|
||||
```js
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
@@ -366,7 +504,7 @@ Meteor.publish('allCustomers', function publishCustomers() {
|
||||
|
||||
|
||||
|
||||
## index.js {meteorgenerate-index.js}
|
||||
### index.js {meteorgenerate-index.js}
|
||||
|
||||
```js
|
||||
export * from './collection';
|
||||
@@ -376,7 +514,7 @@ export * from './publications';
|
||||
|
||||
Also, there is the same version of these methods using TypeScript, that will be shown bellow.
|
||||
|
||||
## path option {meteorgenerate-path}
|
||||
### path option {meteorgenerate-path}
|
||||
|
||||
If you want to create in another path, you can use the ``--path`` option in order to select where to place this boilerplate.
|
||||
It will generate the model in that path. Note that is used TypeScript in this example.
|
||||
@@ -392,7 +530,7 @@ It will generate in ``server/admin`` the another-client code:
|
||||

|
||||
|
||||
|
||||
## collection.ts {meteorgenerate-collection.ts}
|
||||
### collection.ts {meteorgenerate-collection.ts}
|
||||
|
||||
```typescript
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
@@ -406,7 +544,7 @@ export type AnotherCustomer = {
|
||||
export const AnotherCustomerCollection = new Mongo.Collection<AnotherCustomer>('another-customer');
|
||||
```
|
||||
|
||||
## methods.ts {meteorgenerate-methods.ts}
|
||||
### methods.ts {meteorgenerate-methods.ts}
|
||||
|
||||
```typescript
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
@@ -443,7 +581,7 @@ Meteor.methods({
|
||||
|
||||
|
||||
|
||||
## publications.ts {meteorgenerate-publications.ts}
|
||||
### publications.ts {meteorgenerate-publications.ts}
|
||||
|
||||
```typescript
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
@@ -456,7 +594,7 @@ Meteor.publish('allAnotherCustomers', function publishAnotherCustomers() {
|
||||
|
||||
|
||||
|
||||
## index.ts {meteorgenerate-index.ts}
|
||||
### index.ts {meteorgenerate-index.ts}
|
||||
|
||||
```typescript
|
||||
export * from './collection';
|
||||
@@ -467,7 +605,7 @@ export * from './publications';
|
||||
---
|
||||
|
||||
|
||||
## Using the Wizard {meteorgenerate-wizard}
|
||||
### Using the Wizard {meteorgenerate-wizard}
|
||||
|
||||
|
||||
If you run the following command:
|
||||
@@ -485,7 +623,7 @@ It will prompt the following questions.
|
||||
|
||||
---
|
||||
|
||||
## Using your own template {meteorgenerate-templating}
|
||||
### Using your own template {meteorgenerate-templating}
|
||||
|
||||
`--templatePath`
|
||||
|
||||
@@ -500,7 +638,7 @@ meteor generate feed --templatePath=/scaffolds-ts
|
||||
|
||||
You can use your own templates for scaffolding your specific workloads. To do that, you should pass in a template directory URL so that it can copy it with its changes.
|
||||
|
||||
## How to rename things? {meteorgenerate-template-rename}
|
||||
### How to rename things? {meteorgenerate-template-rename}
|
||||
|
||||
Out of the box is provided a few functions such as replacing ``$$name$$``, ``$$PascalName$$`` and ``$$camelName$$``
|
||||
|
||||
@@ -518,7 +656,7 @@ const transformName = (name) => {
|
||||
}
|
||||
```
|
||||
|
||||
## How to bring your own templates? {meteorgenerate-template-faq}
|
||||
### How to bring your own templates? {meteorgenerate-template-faq}
|
||||
|
||||
`--replaceFn`
|
||||
|
||||
@@ -582,81 +720,99 @@ third-party service providers.
|
||||
Once you have your account you can log in and log out from the command line, and
|
||||
check your username with `meteor whoami`.
|
||||
|
||||
## meteor deploy _site_ {meteordeploy}
|
||||
## meteor deploy _site_ {#meteordeploy}
|
||||
|
||||
Deploy the project in your current directory to
|
||||
<a href="https://www.meteor.com/galaxy" target="_blank">Galaxy</a>.
|
||||
Deploys the project in your current directory to [Galaxy](https://www.meteor.com/galaxy).
|
||||
|
||||
Use `--owner` to decide which organization or user account you'd like to deploy
|
||||
a new app to if you are a member of more than one Galaxy-enabled account.
|
||||
### Basic Deployment
|
||||
|
||||
You can deploy in debug mode by passing `--debug`. This
|
||||
will leave your source code readable by your favorite in-browser
|
||||
debugger, just like it is in local development mode.
|
||||
|
||||
|
||||
|
||||
To delete an application you've deployed, specify
|
||||
the `--delete` option along with the site.
|
||||
|
||||
|
||||
|
||||
You can add information specific to a particular deployment of your application
|
||||
by using the `--settings` option. The argument to `--settings` is a file
|
||||
containing any JSON string. The object in your settings file will appear on the
|
||||
server side of your application in [`Meteor.settings`](../api/meteor#Meteor-settings).
|
||||
|
||||
Settings are persistent. When you redeploy your app, the old value will be
|
||||
preserved unless you explicitly pass new settings using the `--settings` option.
|
||||
To unset `Meteor.settings`, pass an empty settings file.
|
||||
|
||||
::: warning
|
||||
`free` and `mongo` options were introduced in Meteor 2.0
|
||||
:::
|
||||
|
||||
You can run your app for free using the option `--free`. But, there are some limitations. The first one is that you cannot use a custom domain to run a free app. Your domain must contain a Meteor domain name (`.meteorapp.com` to US region, `.au.meteorapp.com` to Asia region, or `.eu.meteorapp.com` to Europe region). Second thing you must know is that your free apps have Cold Start enabled. Cold Start means that your app will stop if it has no connection for 10 minutes, and it will go automatically up when someone tries to connect to it. The third thing you must know is that free apps run on one, and just one, Tiny container. This is important to know, because Tiny containers are NOT meant to production environment, so even small apps can crash with a lot of connections. To keep your app on free, you always need to provide this option.
|
||||
|
||||
With the option `--mongo` you can deploy your app without having to pay for a MongoDB provider. By providing this option, Galaxy will create a database for you in our shared cluster and inject the mongo URL on your settings. So with this, you don't even need to provide the settings file anymore (if your settings files just have the mongo URL of course). This is great to test apps, but it shouldn't be used in a production environment, as you will be running in a shared Cluster with limited space. The rules behind this option are: If it is the first deploy of the app, and you provided the option `--mongo`, after the deploy is finished you will receive your mongo URL on your console (you can also see your URL on Galaxy in your app's version). You can put that URL on your settings file if want to. If you try to do a second without the option `--mongo` and without providing a mongo URL on your settings, your deploy will fail as usual. If you provide the option `--mongo` and a mongo URL, the mongo URL on your settings file is the one that will be used by Galaxy to connect your app to a MongoDB. One last thing, you need to have at least one document in your database so Meteor is really going to instantiate it. Then you will be able to access it using any MongoDB client with the provided URI.
|
||||
|
||||
Use the options `--mongo` and `--free` to easily deploy a free app already with a mongo database connected to it.
|
||||
|
||||
::: warning
|
||||
Free apps and MongoDB shared hosting: Meteor Software reserves the right to stop or remove applications we deem to be abusing the free plan offering at any time. Please be advised that the free plan offering is not recommended for production applications. The shared MongoDB cluster that comes configured with the free plan does not provide backups or restoration resources.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
If you want to connect to your free MongoDB shared cluster using your on settings make sure you include this option in your settings in the Mongo package configuration section:
|
||||
```bash
|
||||
meteor deploy your-app.meteorapp.com
|
||||
```
|
||||
packages: {
|
||||
mongo: {
|
||||
options: {
|
||||
tlsAllowInvalidCertificates: true,
|
||||
},
|
||||
},
|
||||
|
||||
### Deployment Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--delete`, `-D` | Permanently delete this deployment |
|
||||
| `--debug` | Deploy in debug mode (don't minify, etc.) |
|
||||
| `--settings`, `-s <file>` | Set optional data for Meteor.settings |
|
||||
| `--free` | Deploy as a free app (with limitations) |
|
||||
| `--mongo` | Create and connect to a free shared MongoDB database |
|
||||
| `--plan <plan>` | Set app plan: `professional`, `essentials`, or `free` |
|
||||
| `--container-size <size>` | Set container size: `tiny`, `compact`, `standard`, `double`, `quad`, `octa`, or `dozen` |
|
||||
| `--owner` | Specify organization or user account to deploy to |
|
||||
| `--cache-build` | Reuse the build if the git commit hash is the same |
|
||||
| `--allow-incompatible-update` | Allow packages to be upgraded or downgraded to potentially incompatible versions |
|
||||
| `--deploy-polling-timeout <ms>` | Time to wait for build/deploy (defaults to 15 minutes) |
|
||||
| `--no-wait` | Exit after code upload instead of waiting for deploy to complete |
|
||||
|
||||
### Free Deployment
|
||||
|
||||
Deploy a free app with MongoDB using:
|
||||
|
||||
```bash
|
||||
meteor deploy your-app.meteorapp.com --free --mongo
|
||||
```
|
||||
|
||||
::: tip Quick Start
|
||||
The combination of `--free` and `--mongo` is the fastest way to deploy an app without any additional configuration.
|
||||
:::
|
||||
|
||||
#### Free App Limitations
|
||||
|
||||
- **Domain**: Must use a Meteor domain (`.meteorapp.com`, `.au.meteorapp.com`, or `.eu.meteorapp.com`)
|
||||
- **Cold Start**: App stops after 30 minutes of inactivity and restarts on next connection
|
||||
- **Resources**: Limited to one Tiny container (not recommended for production use)
|
||||
|
||||
|
||||
### MongoDB Options
|
||||
|
||||
#### Shared MongoDB (Free)
|
||||
|
||||
The `--mongo` option creates a database in Galaxy's shared cluster:
|
||||
|
||||
- On first deploy, you'll receive your MongoDB URI in the console
|
||||
- The URI is also visible in your app's version details in Galaxy
|
||||
- You must create at least one document to fully instantiate the database
|
||||
- The database can be accessed using any MongoDB client with the provided URI
|
||||
|
||||
::: warning
|
||||
Free shared MongoDB is not recommended for production applications. The shared cluster doesn't provide backups or restoration resources.
|
||||
:::
|
||||
|
||||
#### MongoDB Connection Settings
|
||||
|
||||
When connecting to the free MongoDB shared cluster using your own settings, include:
|
||||
|
||||
```json
|
||||
{
|
||||
"packages": {
|
||||
"mongo": {
|
||||
"options": {
|
||||
"tlsAllowInvalidCertificates": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
This is necessary as our database provider does not have certificates installed on every machine and we don't want to force apps to have this certificate. More about this option [here](../api/collections.html#mongo_connection_options_settings)
|
||||
|
||||
::: details Why is this needed?
|
||||
This is necessary because the database provider doesn't have certificates installed on every machine. More about this option [here](../api/collections.html#mongo_connection_options_settings).
|
||||
:::
|
||||
|
||||
### Important Notes
|
||||
|
||||
You can change the app plan by providing argument `--plan` with one of the following values: professional, essentials, or free. Be aware that this argument overwrites the `--free` argument.
|
||||
- Settings persist between deployments unless explicitly changed
|
||||
- Your project should be a git repository (commit hash is used to track code changes)
|
||||
- Free apps and MongoDB shared hosting are not recommended for production use
|
||||
- Meteor Software reserves the right to stop or remove applications that abuse the free plan
|
||||
|
||||
::: warning
|
||||
The `plan` option is available since Meteor 2.1.
|
||||
:::
|
||||
|
||||
Use `--cache-build` to keep the bundle in your temp folder after the deploy is finished, this is helpful when you want to deploy the same code to different environments. For example, a [background job](https://cloud-guide.meteor.com/background-jobs.html) app from the same code as the web app.
|
||||
|
||||
Your project should be a git repository as the commit hash is going to be used to decide if your code is still the same or not in the next deploy.
|
||||
|
||||
::: warning
|
||||
The `cache-build` option is available since Meteor 1.11.
|
||||
:::
|
||||
|
||||
With the argument `--container-size` you can change your app's container size using the deploy command. The valid arguments are: `tiny`, `compact`, `standard`, `double`, `quad`, `octa`, and `dozen`. One more thing to note here is that the `--container-size` flag can only be used when the `--plan` option is already specified, otherwise using the `--container-size` option will throw an error with the message : `Error deploying application: Internal error`. To see more about the difference and prices of each one you can check [here](https://www.meteor.com/cloud#pricing-section).
|
||||
|
||||
::: warning
|
||||
The `--container-size` option is available since Meteor 2.4.1.
|
||||
::: info Version Compatibility
|
||||
- `--free` and `--mongo` options were introduced in Meteor 2.0
|
||||
- `--plan` option was introduced in Meteor 2.1
|
||||
- `--container-size` option was introduced in Meteor 2.4.1
|
||||
- `--cache-build` option is available since Meteor 1.11
|
||||
:::
|
||||
|
||||
## meteor update {meteorupdate}
|
||||
|
||||
93
v3-docs/docs/community-packages/archive.md
Normal file
93
v3-docs/docs/community-packages/archive.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Archive
|
||||
|
||||
- `Who maintains the package` – [Jam](https://github.com/jamauro)
|
||||
|
||||
[[toc]]
|
||||
|
||||
## What is this package?
|
||||
|
||||
Archive is an easy way to add an archive mechanism to your Meteor app. When a document is archived, it's removed from its original collection and placed in an archive collection so that it can be restored if needed. Its key features are:
|
||||
|
||||
* Zero config needed (though you can customize)
|
||||
* Isomorphic so that it works with Optimistic UI
|
||||
* Automatically overrides `removeAsync` to perform an archive (can be turned off)
|
||||
* Explicitly archive with `archiveAsync` collection method (optional)
|
||||
* Restore archived docs with `restoreAsync` collection method
|
||||
* Optionally exclude specific collections
|
||||
* Compatible with Meteor `3.0.2+`
|
||||
|
||||
> **Note:** Alternative to archive is soft deletion. You can use [`jam:soft-delete`](./soft-delete.md) package for that. Be sure to compare those two approaches to pick the solution best suited for your application.
|
||||
|
||||
## How to download it?
|
||||
|
||||
Add the package to your app
|
||||
```bash
|
||||
meteor add jam:archive
|
||||
```
|
||||
|
||||
### Sources
|
||||
|
||||
* [GitHub repository](https://github.com/jamauro/archive)
|
||||
|
||||
## How to use it?
|
||||
|
||||
### Create your Archives collection
|
||||
Create an Archives collection in your app just as you would any other collection.
|
||||
```js
|
||||
const Archives = new Mongo.Collection('archives');
|
||||
```
|
||||
|
||||
Documents in the Archives collection will have this shape:
|
||||
```js
|
||||
{
|
||||
_id, // auto-generated by Meteor as with other collection _ids
|
||||
_collection, // the name of the collection, e.g. 'todos', that the doc belonged to originally
|
||||
archivedAt, // the timestamp when the document was removed from its original collection and inserted into the archive
|
||||
id, // the original doc _id renamed to prevent conflict with the auto-generated one above. when restored, it will be renamed back to _id automatically by this package
|
||||
/*
|
||||
...rest of original doc
|
||||
*/
|
||||
}
|
||||
```
|
||||
|
||||
### Deleting permanently
|
||||
By default, this package overrides the `removeAsync` collection method so that it archives the document(s) rather that removing them from the database. To delete permanently, pass in the option `forever: true`, e.g.:
|
||||
```js
|
||||
Collection.removeAsync(/* your filter */, { forever: true })
|
||||
```
|
||||
|
||||
If you prefer, you can prevent overriding the `removeAsync` by setting `overrideRemove: false`. See [Configuring](#configuring-optional) for more details.
|
||||
|
||||
### Explicitly archiving
|
||||
If you prefer, you can explicity use `archiveAsync`, e.g.:
|
||||
```js
|
||||
Collection.archiveAsync(/* your filter */)
|
||||
```
|
||||
|
||||
### Restoring a document
|
||||
To restore an archived document, use `restoreAsync`, e.g.:
|
||||
```js
|
||||
Collection.restoreAsync(/* your filter */)
|
||||
```
|
||||
|
||||
## Configuring (optional)
|
||||
If you like the defaults, then you won't need to configure anything. But there is some flexibility in how you use this package.
|
||||
|
||||
Here are the global defaults:
|
||||
```js
|
||||
const config = {
|
||||
name: 'archives', // if your Archives collection uses a different name, you'll want to change this
|
||||
overrideRemove: true, // overrides the Collection.removeAsync method to make it an archive instead
|
||||
exclude: ['roles', 'role-assignment'] // exclude specific collections from using archive so that when they are removed, the are permanently removed from the db. defaults to excluding the collections created by the meteor roles package
|
||||
};
|
||||
```
|
||||
|
||||
To change the global defaults, use:
|
||||
```js
|
||||
// put this in a file that's imported on both the client and server
|
||||
import { Archive } from 'meteor/jam:archive';
|
||||
|
||||
Archive.configure({
|
||||
// ... change the defaults here ... //
|
||||
});
|
||||
```
|
||||
@@ -27,3 +27,15 @@ Please bear in mind if you are adding a package to this list, try providing as m
|
||||
#### Method/Subscription helpers
|
||||
|
||||
- [`meteor-rpc`](./meteor-rpc.md), Meteor Methods Evolved with type checking and runtime validation
|
||||
- [`jam:method`](./jam-method.md), An easy way to create Meteor methods with extensions to offline handling
|
||||
- [`jam:pub-sub`](./pub-sub.md), Publish / subscribe using a Method and/or Change Streams, and cache subscriptions for Meteor apps
|
||||
|
||||
#### MongoDB collection extensions
|
||||
|
||||
- [`jam:mongo-transactions`](./mongo-transactions.md), An easy way to use Mongo Transactions for Meteor apps
|
||||
- [`jam:soft-delete`](./soft-delete.md), An easy way to add soft deletes to your Meteor app
|
||||
- [`jam:archive`](./archive.md),
|
||||
|
||||
#### Utilities
|
||||
|
||||
- [`jam:offline`](./offline.md), An easy way to give your Meteor app offline capabilities and make it feel instant
|
||||
|
||||
579
v3-docs/docs/community-packages/jam-method.md
Normal file
579
v3-docs/docs/community-packages/jam-method.md
Normal file
@@ -0,0 +1,579 @@
|
||||
# Jam Method
|
||||
|
||||
- `Who maintains the package` – [Jam](https://github.com/jamauro)
|
||||
|
||||
[[toc]]
|
||||
|
||||
## What is this package?
|
||||
|
||||
Method is an easy way to create Meteor methods with Optimistic UI. It's built with Meteor 3 in mind and is compatible with Meteor 2 to make migration easy. It's meant to be a drop in replacement for Validated Method and comes with additional features:
|
||||
|
||||
* Before and after hooks
|
||||
* Global before and after hooks for all methods
|
||||
* Pipe a series of functions
|
||||
* Authed by default (can be overriden)
|
||||
* Easily configure a rate limit
|
||||
* Optionally run a method on the server only
|
||||
* Attach the methods to Collections (optional)
|
||||
* Validate with one of the supported schema packages or a custom validate function
|
||||
* No need to use .call to invoke the method as with Validated Method
|
||||
|
||||
## How to download it?
|
||||
|
||||
Add the package to your app by running the following in your Meteor project:
|
||||
|
||||
```bash
|
||||
meteor add jam:method
|
||||
```
|
||||
### Sources
|
||||
|
||||
* [GitHub repository](https://github.com/jamauro/method)
|
||||
|
||||
## How to use it?
|
||||
|
||||
### Create a method
|
||||
`name` is required and will be how Meteor's internals identifies it.
|
||||
|
||||
`schema` will automatically validate using a [supported schema](#supported-schemas).
|
||||
|
||||
`run` will be executed when the method is called.
|
||||
|
||||
```js
|
||||
import { createMethod } from 'meteor/jam:method'; // can import { Methods } from 'meteor/jam:method' instead and use Methods.create if you prefer
|
||||
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema, // using jam:easy-schema in this example
|
||||
async run({ text }) {
|
||||
const todo = {
|
||||
text,
|
||||
done: false,
|
||||
createdAt: new Date(),
|
||||
authorId: Meteor.userId(), // can also use this.userId instead of Meteor.userId()
|
||||
}
|
||||
const todoId = await Todos.insertAsync(todo);
|
||||
return todoId;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Supported schemas
|
||||
Currently, these schemas are supported:
|
||||
* [jam:easy-schema](https://github.com/jamauro/easy-schema)
|
||||
* [check](https://docs.meteor.com/api/check.html)
|
||||
* [zod](https://github.com/colinhacks/zod)
|
||||
* [simpl-schema](https://github.com/longshotlabs/simpl-schema)
|
||||
|
||||
If you're using `jam:easy-schema`, be sure to check out [Using with jam:easy-schema](#using-with-jameasy-schema) below for details on a way to write methods with less boilerplate.
|
||||
|
||||
Here's a quick example of each one's syntax. They vary in features so pick the one that best fits your needs.
|
||||
```js
|
||||
// jam:easy-schema. you'll attach to a Collection so you can reference one {Collection}.schema in your methods
|
||||
const schema = {text: String, isPrivate: Optional(Boolean)}
|
||||
// check
|
||||
const schema = {text: String, isPrivate: Match.Maybe(Boolean)}
|
||||
// zod
|
||||
const schema = z.object({text: z.string(), isPrivate: z.boolean().optional()})
|
||||
// simpl-schema
|
||||
const schema = new SimpleSchema({text: String, isPrivate: {type: Boolean, optional: true}})
|
||||
```
|
||||
|
||||
#### Custom validate function
|
||||
If you're not using one of the supported schemas, you can use `validate` to pass in a custom validation function.
|
||||
**`Note`**: `validate` can be an async function if needed.
|
||||
|
||||
```js
|
||||
// import your schema from somewhere
|
||||
// import your validator function from somewhere
|
||||
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
validate(args) {
|
||||
validator(args, schema)
|
||||
},
|
||||
async run({ text }) {
|
||||
const todo = {
|
||||
text,
|
||||
done: false,
|
||||
createdAt: new Date(),
|
||||
authorId: Meteor.userId() // can also use this.userId instead of Meteor.userId()
|
||||
}
|
||||
const todoId = await Todos.insertAsync(todo);
|
||||
return todoId;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Import on the client and use
|
||||
```js
|
||||
import { create } from '/imports/api/todos/methods';
|
||||
|
||||
async function submit() {
|
||||
try {
|
||||
await create({text: 'book flight to Hawaii'})
|
||||
} catch(error) {
|
||||
alert(error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Before and after hooks
|
||||
You can execute functions `before` and / or `after` the method's `run` function. `before` and `after` accept a single function or an array of functions.
|
||||
|
||||
When using `before`, the original input passed into the method will be available. The original input will be returned automatically from a `before` function so that `run` receives what was originally passed into the method.
|
||||
|
||||
A great use case for using `before` is to verify the user has permission. For example:
|
||||
|
||||
```js
|
||||
async function checkOwnership({ _id }) { // the original input passed into the method is available here. destructuring for _id since that's all we need for this function
|
||||
const todo = await Todos.findOneAsync(_id);
|
||||
if (todo.authorId !== Meteor.userId()) {
|
||||
throw new Meteor.Error('not-authorized')
|
||||
}
|
||||
|
||||
return true; // any code executed as a before function will automatically return the original input passed into the method so that they are available in the run function
|
||||
}
|
||||
|
||||
export const markDone = createMethod({
|
||||
name: 'todos.markDone',
|
||||
schema: Todos.schema,
|
||||
before: checkOwnership,
|
||||
async run({ _id, done }) {
|
||||
return await Todos.updateAsync(_id, {$set: {done}});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
When using `after`, the result of the `run` function will be available as the first argument and the second argument will contain the original input that was passed into the method. The result of the `run` function will be automatically returned from an `after` function.
|
||||
|
||||
```js
|
||||
function exampleAfter(result, context) {
|
||||
const { originalInput } = context; // the name of the method is also available here
|
||||
// do stuff
|
||||
|
||||
return 'success'; // any code executed as an after function will automatically return the result of the run function
|
||||
}
|
||||
|
||||
export const markDone = createMethod({
|
||||
name: 'todos.markDone',
|
||||
schema: Todos.schema,
|
||||
before: checkOwnership,
|
||||
async run({ _id, done }) {
|
||||
return await Todos.updateAsync(_id, {$set: {done}});
|
||||
},
|
||||
after: exampleAfter
|
||||
});
|
||||
```
|
||||
|
||||
**`Note`**: If you use arrow functions for `before`, `run`, or `after`, you'll lose access to `this` – the methodInvocation. You may be willing to sacrifice that because `this.userId` can be replaced by `Meteor.userId()` and `this.isSimulation` can be replaced by `Meteor.isClient` but it's worth noting.
|
||||
|
||||
|
||||
### Pipe a series of functions
|
||||
Instead of using `run`, you can compose functions using `.pipe`. Each function's output will be available as an input for the next function.
|
||||
|
||||
```js
|
||||
// you'd define the functions in the pipe and then place them in the order you'd like them to execute within .pipe
|
||||
// be sure that each function in the pipe returns what the next one expects, otherwise you can add an arrow function to the pipe to massage the data, e.g. (input) => manipulate(input)
|
||||
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema
|
||||
}).pipe(
|
||||
checkOwnership,
|
||||
createTodo,
|
||||
sendNotification
|
||||
)
|
||||
```
|
||||
|
||||
### Attach methods to its Collection (optional)
|
||||
Instead of importing each method, you can attach them to the Collection. If you're using [jam:easy-schema](https://github.com/jamauro/easy-schema) be sure to attach the schema before attaching the methods.
|
||||
|
||||
```js
|
||||
// /imports/api/todos/collection
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
import { schema } from './schema';
|
||||
|
||||
export const Todos = new Mongo.Collection('todos');
|
||||
|
||||
Todos.attachSchema(schema); // if you're using jam:easy-schema
|
||||
|
||||
const attach = async () => {
|
||||
const methods = await import('./methods.js') // dynamic import is recommended
|
||||
return Todos.attachMethods(methods); // if you prefer not to use dynamic import, you can simply call attachMethods synchronously
|
||||
};
|
||||
|
||||
attach().catch(error => console.error('Error attaching methods', error))
|
||||
```
|
||||
`attachMethods` accepts the method `options` as an optional second parameter. See [Configuring](#configuring-optional) for a list of the `options`.
|
||||
|
||||
With the methods attached you'll use them like this on the client:
|
||||
```js
|
||||
import { Todos } from '/imports/api/todos/collection';
|
||||
// no need to import each method individually
|
||||
|
||||
async function submit() {
|
||||
try {
|
||||
await Todos.create({text: 'book flight to Hawaii'})
|
||||
} catch(error) {
|
||||
alert(error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Executing code on the server only
|
||||
By default, methods are optimistic meaning they will execute on the client and then on the server. If there's only part of the method that should execute on the server and not on the client, then simply wrap that piece of code in a `if (Meteor.isServer)` block. This way you can still maintain the benefits of Optimistic UI. For example:
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
async run(args) {
|
||||
// rest of your function
|
||||
// code running on both client and server
|
||||
if (Meteor.isServer) {
|
||||
// code running on the server only
|
||||
import { secretCode } from '/server/secretCode'; // since it's in a /server folder the code will not be shipped to the client
|
||||
// do something with secretCode
|
||||
}
|
||||
|
||||
// code running on both client and server
|
||||
return Todos.insertAsync(todo)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
If you prefer, you can force the entire method to execute on the server only by setting `serverOnly: true`. It can be used with `run` or `.pipe`. Here's an example with `run`:
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
serverOnly: true,
|
||||
async run(args) {
|
||||
// all code here will execute only on the server
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
You can also set all methods to be `serverOnly`. See [Configuring](#configuring-optional) below.
|
||||
|
||||
#### Security note
|
||||
**`Important`**: Since Meteor does not currently support tree shaking, the contents of the code inside `run` function or `.pipe` could still be visible to the client even if you use `if (Meteor.isServer)` or `serverOnly: true`. To prevent this, you have these options:
|
||||
|
||||
1. Attach methods to its Collection with a dynamic import as shown above [Attach methods to its Collection (optional)](#attach-methods-to-its-collection-optional)
|
||||
|
||||
2. Import function(s) from a file within a `/server` folder. Any code imported from a `/server` folder will not be shipped to the client. The `/server` folder can be located anywhere within your project's file structure and you can have multiple `/server` folders. For example, you can co-locate with your collection folder, e.g. `/imports/api/todos/server/`, or it can be at the root of your project. See [Secret server code](https://guide.meteor.com/security.html#secret-code) for more info.
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
serverOnly: true,
|
||||
async run(args) {
|
||||
import { serverFunction } from '/server/serverFunction';
|
||||
|
||||
serverFunction(args);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
3. Dynamically import function(s). These do not have to be inside a `/server` folder. This will prevent the code being inspectable via the browser console.
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
serverOnly: true,
|
||||
async run(args) {
|
||||
const { serviceFunction } = await import('./services');
|
||||
|
||||
serviceFunction(args);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Changing authentication rules
|
||||
By default, all methods will be protected by authentication, meaning they will throw an error if there is *not* a logged-in user. You can change this for an individual method by setting `open: true`. See [Configuring](#configuring-optional) below to change it for all methods.
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
open: true,
|
||||
async run({ text }) {
|
||||
// ... //
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Rate limiting
|
||||
Easily rate limit a method by setting its max number of requests – the `limit` – within a given time period (milliseconds) – the `interval`.
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
rateLimit: { // rate limit to a max of 5 requests every second
|
||||
limit: 5,
|
||||
interval: 1000
|
||||
},
|
||||
async run({ text }) {
|
||||
// ... //
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Validate without executing the method
|
||||
There may be occassions where you want to validate without executing the method. In these cases, you can use `.validate`. If you want to validate against only part of the schema, use `.validate.only`.
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
async run({ text }) {
|
||||
// ... //
|
||||
}
|
||||
});
|
||||
|
||||
// validate against the schema without executing the method
|
||||
create.validate({...})
|
||||
|
||||
// validate against only the relevant part of the schema based on the data passed in without executing the method
|
||||
create.validate.only({...})
|
||||
```
|
||||
|
||||
If you're using a custom validate function instead of one of the supported schemas and you'd like to use `.validate.only`, you can simply append an `only` function onto the `validate` function that you supply.
|
||||
|
||||
### Options for Meteor.applyAsync
|
||||
When called, the method uses [Meteor.applyAsync](https://docs.meteor.com/api/methods#Meteor-applyAsync) under the hood to execute your `run` function or `.pipe` function(s). `Meteor.applyAsync` takes a few options which can be used to alter the way Meteor handles the method. If you want to change the defaults or include other supported options, pass in `options` when creating the method.
|
||||
|
||||
```js
|
||||
export const create = createMethod({
|
||||
name: 'todos.create',
|
||||
schema: Todos.schema,
|
||||
options: {
|
||||
// ... //
|
||||
},
|
||||
async run({ text }) {
|
||||
// ... //
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
By default, this package uses the following `options`:
|
||||
```js
|
||||
{
|
||||
// Make it possible to get the ID of an inserted item
|
||||
returnStubValue: true,
|
||||
|
||||
// Don't call the server method if the client stub throws an error, so that we don't end
|
||||
// up doing validations twice
|
||||
throwStubExceptions: true,
|
||||
};
|
||||
```
|
||||
See [Configuring](#configuring-optional) below to set `options` for all methods.
|
||||
|
||||
### Working with the stub result (Meteor 3.0+)
|
||||
In Meteor 3.0+, you can optionally take action with the stub result, i.e. the result when the method simulation is run on the client, before the server has returned with the final result or error. This can come in handy when you want to make your app feel instant for the user and you're relatively sure the action will succeed, e.g. when inserting new documents into the database.
|
||||
|
||||
```js
|
||||
const { stubPromise, serverPromise } = create();
|
||||
const _id = await stubPromise.catch(error => {
|
||||
// optionally handle a stub error
|
||||
});
|
||||
|
||||
// take action with the _id stub result, for example, route to a new page
|
||||
router.go(`/detail/${_id}`)
|
||||
|
||||
await serverPromise.catch(error => {
|
||||
// handle server error, rollback changes as needed, for example route to home
|
||||
router.go('/')
|
||||
alert('sorry, could not create')
|
||||
});
|
||||
```
|
||||
|
||||
### Mocking the method context
|
||||
You can mock the method invocation context, aka the `this` value inside the method, by invoking the method with `.call(context, args)`. This is particularly useful for unit testing to mock the `this.userId`:
|
||||
|
||||
```js
|
||||
const context = {
|
||||
userId: 'fakeUserId',
|
||||
// ... //
|
||||
}
|
||||
|
||||
await create.call(context, {...})
|
||||
```
|
||||
|
||||
## Configuring (optional)
|
||||
If you like the defaults, then you won't need to configure anything. But there is some flexibility in how you use this package.
|
||||
|
||||
Here are the global defaults:
|
||||
```js
|
||||
const config = {
|
||||
before: [], // global before function(s) that will run before all methods
|
||||
after: [], // global after function(s) that will run after all methods
|
||||
serverOnly: false, // globally make all methods serverOnly, aka disable Optimistic UI, by setting to true
|
||||
open: false, // by default all methods will be protected by authentication, override it for all methods by setting this to true
|
||||
loggedOutError: new Meteor.Error('logged-out', 'You must be logged in'), // customize the logged out error
|
||||
options: {
|
||||
returnStubValue: true, // make it possible to get the ID of an inserted item on the client before the server finishes
|
||||
throwStubExceptions: true, // don't call the server method if the client stub throws an error, so that we don't end up doing validations twice
|
||||
}
|
||||
};
|
||||
````
|
||||
|
||||
To change the global defaults, use:
|
||||
```js
|
||||
// put this in a file that's imported on both the client and server
|
||||
import { Methods } from 'meteor/jam:method';
|
||||
|
||||
Methods.configure({
|
||||
// ... change the defaults here ... //
|
||||
});
|
||||
```
|
||||
|
||||
### Global before and after hooks
|
||||
You can create before and/or after functions to run before / after all methods. Both `before` and `after` accept a single function or an array of functions.
|
||||
|
||||
```js
|
||||
import { Methods } from 'meteor/jam:method';
|
||||
|
||||
const hello = () => { console.log('hello') }
|
||||
const there = () => { console.log('there') }
|
||||
const world = () => { console.log('world') }
|
||||
|
||||
Methods.configure({
|
||||
before: [hello, there],
|
||||
after: world
|
||||
});
|
||||
```
|
||||
|
||||
### Helpful utility function to log your methods
|
||||
Here's a helpful utility function - `log` - that you might consider adding. It isn't included in this package but you can copy and paste it into your codebase where you see fit.
|
||||
|
||||
```js
|
||||
// log will simply console.log or console.error when the Method finishes
|
||||
function log(input, pipeline) {
|
||||
pipeline.onResult((result) => {
|
||||
console.log(`Method ${pipeline.name} finished`, input);
|
||||
console.log('Result', result);
|
||||
});
|
||||
|
||||
pipeline.onError((err) => {
|
||||
console.error(`Method ${pipeline.name} failed`);
|
||||
console.error('Error', err);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
Then you could use it like this:
|
||||
```js
|
||||
import { Methods, server } from 'meteor/jam:method';
|
||||
|
||||
Methods.configure({
|
||||
after: server(log)
|
||||
});
|
||||
```
|
||||
|
||||
## Alternative functional-style syntax
|
||||
You can use a functional-style syntax to compose your methods if you prefer. Here's an example.
|
||||
|
||||
```js
|
||||
const fetchGifs = async({ searchTerm, limit }) => {...}
|
||||
|
||||
export const getGifs = createMethod(server(schema({ searchTerm: String, limit: Number })(fetchGifs)))
|
||||
```
|
||||
`getGifs` is callable from the client but will only run on the server. Internally it will be identified as `fetchGifs`
|
||||
|
||||
**`Note`**: if you pass in a named function into `createMethod`, then that will be used to identify the method internally. Otherwise if you pass in an anonymous function, `jam:method` generates a unique name based on its schema to identify it internally.
|
||||
|
||||
### Customizing methods when using functional-style syntax
|
||||
There are a few functions available when you need to customize the method: `schema`, `server`, `open`, `close`. These can be composed when needed.
|
||||
|
||||
#### schema
|
||||
Specify the schema to validate against.
|
||||
|
||||
```js
|
||||
import { schema } from 'meteor/jam:method';
|
||||
|
||||
export const doSomething = schema({thing: String, num: Number})(async ({ thing, num }) => {
|
||||
// ... //
|
||||
});
|
||||
```
|
||||
|
||||
#### server
|
||||
Make the method run on the server only.
|
||||
|
||||
```js
|
||||
import { server } from 'meteor/jam:method';
|
||||
|
||||
export const aServerOnlyMethod = server(async data => {
|
||||
// ... //
|
||||
});
|
||||
```
|
||||
|
||||
#### open
|
||||
Make the method publically available so that a logged-in user isn't required.
|
||||
|
||||
```js
|
||||
import { open } from 'meteor/jam:method';
|
||||
|
||||
export const aPublicMethod = open(async data => {
|
||||
// ... //
|
||||
});
|
||||
```
|
||||
|
||||
#### close
|
||||
Make the method check for a logged-in user.
|
||||
|
||||
**`Note`**: by default, all methods require a logged-in user so if you stick with that default, then you won't need to use this function. See [Configuring](#configuring-optional).
|
||||
|
||||
```js
|
||||
import { close } from 'meteor/jam:method';
|
||||
|
||||
export const closedMethod = close(async data => {
|
||||
// ... //
|
||||
});
|
||||
```
|
||||
|
||||
## Using with `jam:easy-schema`
|
||||
`jam:method` integrates with `jam:easy-schema` and offers a way to reduce boilerplate and make your methods even easier to write (though you can still use `createMethod` if you prefer).
|
||||
|
||||
For example, instead of writing this:
|
||||
```js
|
||||
export const setDone = createMethod({
|
||||
name: 'todos.setDone',
|
||||
schema: Todos.schema,
|
||||
before: checkOwnership,
|
||||
async run({ _id, done }) {
|
||||
return Todos.updateAsync({ _id }, { $set: { done } });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
You can write:
|
||||
```js
|
||||
export const setDone = async ({ _id, done }) => {
|
||||
await checkOwnership({ _id });
|
||||
return Todos.updateAsync({ _id }, { $set: { done } });
|
||||
};
|
||||
```
|
||||
|
||||
**`Note`**: This assumes that you're attaching your methods to its collection. See [Attach methods to its Collection](#attach-methods-to-its-collection-optional).
|
||||
|
||||
When you call `Todos.setDone` from the client, the arguments will be automatically checked against the `Todos.schema`. The method will automatically be named `todos.setDone` internally to identify it for app performance monitoring (APM) purposes.
|
||||
|
||||
You can also compose with the functions available in the [function-style syntax](#alternative-functional-style-syntax). For example:
|
||||
```js
|
||||
export const setDone = server(async ({ _id, done }) => {
|
||||
await checkOwnership({ _id });
|
||||
return Todos.updateAsync({ _id }, { $set: { done } });
|
||||
});
|
||||
```
|
||||
Now when you call `Todos.setDone` from the client it will only run on the server.
|
||||
|
||||
## Using with `jam:offline`
|
||||
`jam:method` integrates with `jam:offline` to automatically queue methods when a user is offline. You don't need to configure anything in `jam:method` for this. 🎉 `jam:offline` will then replay them when the user reconnects. See [jam:offline](https://github.com/jamauro/offline) for more details.
|
||||
|
||||
## Coming from `Validated Method`?
|
||||
You may be familiar with `mixins` and wondering where they are. With the features of this package - authenticated by default, `before` / `after` hooks, `.pipe` - your mixin code may no longer be needed or can be simplified. If you have another use case where your mixin doesn't translate, I'd love to hear it. Open a new discussion and let's chat.
|
||||
86
v3-docs/docs/community-packages/mongo-transactions.md
Normal file
86
v3-docs/docs/community-packages/mongo-transactions.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Mongo-transactions
|
||||
|
||||
- `Who maintains the package` – [Jam](https://github.com/jamauro)
|
||||
|
||||
[[toc]]
|
||||
|
||||
## What is this package?
|
||||
|
||||
`jam:mongo-transactions` enables an easy way to work with Mongo Transactions in Meteor apps. Here are a few of the benefits:
|
||||
|
||||
* Write with the standard Meteor collection methods you're accustomed to. You don't need to worry about using `rawCollection()`, though if you need a particular `rawCollection()` method, you can still use it.
|
||||
* You don't need to worry about passing `session` around. This package takes care of that for you.
|
||||
* Because it's a low-level solution, ID generation works as expected.
|
||||
* Works out-of-the-box with other packages that automatically validate on DB writes, like `jam:easy-schema` and `aldeed:collection2`.
|
||||
* One simple API to use. Mongo has made things complicated with two APIs for Transactions, the Callback API and the Core API. This package defaults to using the Callback API as recommended by Mongo, but allows you to use the Core API by passing in `autoRetry: false`.
|
||||
* Can be used isomorphically.
|
||||
* Compatible with Meteor 2.8.1 and up, including support for Meteor 3.0+
|
||||
|
||||
> **Important**: This package expects that you'll use the promise-based `*Async` Meteor collection methods introduced in `v2.8.1` though it will technically work with the older syntax without the `*Async` suffix as long as you don't use callbacks. It does **not** cover using callbacks with Meteor collection methods.
|
||||
|
||||
## How to download it?
|
||||
Add the package to your app
|
||||
```bash
|
||||
meteor add jam:mongo-transactions
|
||||
```
|
||||
### Sources
|
||||
|
||||
* [GitHub repository](https://github.com/jamauro/mongo-transactions)
|
||||
|
||||
## How to use it?
|
||||
|
||||
### Create a Transaction
|
||||
|
||||
> **Note**: there's no need to pass `session` into the `*Async` collection methods. This package handles that for you.
|
||||
|
||||
```js
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
|
||||
async function purchase(purchaseData) {
|
||||
try {
|
||||
const { invoiceId } = await Mongo.withTransaction(async () => {
|
||||
const invoiceId = await Invoices.insertAsync(purchaseData);
|
||||
const changeQuantity = await Items.updateAsync(purchaseData.itemId, { $set: {...} });
|
||||
return { invoiceId, changeQuantity } // you can return whatever you'd like
|
||||
});
|
||||
return invoiceId;
|
||||
} catch (error) {
|
||||
// something went wrong with the transaction and it could not be automatically retried
|
||||
// handle the error as you see fit
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Passing Transaction options
|
||||
If you want to customize how the Transaction runs, pass in the Transaction options as the second argument, for example:
|
||||
```js
|
||||
await Mongo.withTransaction(async () => {
|
||||
...
|
||||
}, { writeConcern: { w: 1 } });
|
||||
```
|
||||
Refer to the [Mongo Node API docs](https://mongodb.github.io/node-mongodb-native/6.3/interfaces/TransactionOptions.html) for more information about Transaction options.
|
||||
|
||||
### Preventing automatic retries if the Transaction fails
|
||||
Most of the time, you'll want the default behavior where the Transaction is automatically retried for a `TransientTransactionError` or `UnknownTransactionCommitResult` commit error. But if you don't want that behavior, simply pass in `{ autoRetry: false }` like this:
|
||||
|
||||
```js
|
||||
await Mongo.withTransaction(async () => {
|
||||
...
|
||||
}, { autoRetry: false });
|
||||
```
|
||||
|
||||
Setting `{ autoRetry: false }`, means the Transactions Core API will be used rather than the Callback API and you'll be responsible for handling all errors. You can read more about the differences in the [Mongo Docs](https://www.mongodb.com/docs/manual/core/transactions-in-applications/).
|
||||
|
||||
### Determine if you're in a Transaction
|
||||
To determine if the code is currently running in a Transaction, use:
|
||||
```js
|
||||
Mongo.inTransaction(); // returns true or false
|
||||
```
|
||||
|
||||
### Using Isomorphically for Optimistic UI
|
||||
You can write `Mongo.withTransaction` and `Mongo.inTransaction` isomorphically for Optimistic UI however note that the Transaction will only truly be performed on the server.
|
||||
|
||||
As with any isomorphic code, you should be aware that it may fail because the operation can't succeed on the client but will succeed on the server. For example, let's say you're using `.find` within the Transaction and Minimongo on the client doesn't have that particular data, the client will fail but the server should still succeed. You can wrap specific server-only code with `if (Meteor.isServer)`, but in these cases, you'll likely want to avoid isomorphic code and make sure the entire Transaction code only runs on the server.
|
||||
|
||||
## Using Mongo Atlas as your DB?
|
||||
> **Important**: In my experience, you must use a paid tier for Transactions to work as expected with Meteor. The free tier would not tail the oplog for Transactions. So if you're trying this out in production, be sure to use a paid tier.
|
||||
161
v3-docs/docs/community-packages/offline.md
Normal file
161
v3-docs/docs/community-packages/offline.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Offline
|
||||
|
||||
- `Who maintains the package` – [Jam](https://github.com/jamauro)
|
||||
|
||||
[[toc]]
|
||||
|
||||
## What is this package?
|
||||
|
||||
Offline is an easy way to give your Meteor app offline capabilities and make it feel instant. Its key features are:
|
||||
|
||||
* Offline access – Saves Minimongo data in IndexedDB for offline access and instant reloading when reconnected.
|
||||
* Automatic syncing – Syncs offline actions automatically once reconnected.
|
||||
* Cross-Tab syncing – Keeps changes in sync across multiple tabs while offline.
|
||||
* Seamless reconciliation – Reconciles data with the server when reconnected.
|
||||
|
||||
## How to download it?
|
||||
|
||||
Add the package to your app
|
||||
```bash
|
||||
meteor add jam:offline
|
||||
```
|
||||
|
||||
### Sources
|
||||
|
||||
* [GitHub repository](https://github.com/jamauro/offline)
|
||||
|
||||
## How to use it?
|
||||
|
||||
### Keeping data offline
|
||||
By default, offline data will be kept for all collections using the global defaults in [Offline.config](#configuring-optional) without any configuration needed. To change the data that is kept for a specific collection, define `.keep` for the collection in a file that's imported on both client and server.
|
||||
|
||||
If you don't want all collections to be kept, be sure to configure `keepAll: false`. See [Configuring](#configuring-optional) for more details.
|
||||
|
||||
`.keep` accepts a `filter`, and `sort` and `limit` options much like a `.find`. For example:
|
||||
|
||||
```js
|
||||
const Todos = new Mongo.Collection('todos');
|
||||
Todos.keep({ $or: [ { isPrivate: { $ne: true } }, { owner: Meteor.userId() } ]}, { limit: 200 }) // this will override any global defaults
|
||||
```
|
||||
|
||||
If you have specific restrictions on what should be kept, e.g. permissions to a document like in the example above, these should be included in the `.keep` filter. Be aware that when the user comes back online, this filter will be used to reconcile with the server. In general, it's recommended that you only use the `.keep` filter where absolutely needed.
|
||||
|
||||
**`Note`**: You can use `Meteor.userId()` in your `.keep` filter if needed.
|
||||
|
||||
### Clearing offline data for a specific collection
|
||||
If you ever need to clear offline data for a specific collection, call `clear`:
|
||||
|
||||
```js
|
||||
Todos.clear();
|
||||
```
|
||||
|
||||
### Clearing all offline data
|
||||
If you ever need to completely clear all offline data, you can use `clearAll`:
|
||||
|
||||
```js
|
||||
import { clearAll } from 'meteor/jam:offline';
|
||||
|
||||
clearAll();
|
||||
```
|
||||
|
||||
### Queuing methods when offline
|
||||
When a user is offline, you can queue any actions they take for replay when they come back online using `queueMethod`:
|
||||
|
||||
```js
|
||||
import { queueMethod } from 'meteor/jam:offline';
|
||||
|
||||
if (!Meteor.status().connected) { // check that the user is offline
|
||||
queueMethod(name, arg1, arg2...) // the arguments should be the same form that you'd use for Meteor.callAsync
|
||||
}
|
||||
```
|
||||
where name is the method's name and the arguments are what the method expects. You'll still want to call the method when offline and it's recommended that you use [Meteor.applyAsync](https://docs.meteor.com/api/methods.html#Meteor-applyAsync) with the option `noRetry: true` to avoid using Meteor's built-in retry mechanism since we'll be handling replay separately. For this to work as intended, the methods that you call should be isomorphic so that they're availble to the client.
|
||||
|
||||
**`Note`**: If you're using [jam:method](https://github.com/jamauro/method), queuing methods for replay is handled automatically for you. 🎉
|
||||
|
||||
**`Note`**: When queuing methods than involve an `insert` to a collection, make sure the method returns the new document's `_id`. By doing this, you ensure that any subsequent changes made to the document while still offline are handled correctly.
|
||||
|
||||
### Auto syncing
|
||||
By default, the package auto syncs when the user comes back online. This includes:
|
||||
|
||||
1. Replaying queued methods
|
||||
2. Removing offline data for each collection that no longer belongs because it doesn't match the configured `filter` or the collection's `.keep` filter
|
||||
|
||||
The benefit of this sequential-replay syncing strategy is any business logic contained in your methods will be respected. For example, if a user makes changes to a document but loses permission to it while offline, when they come back online, that permission will be respected when the attempted replay occurs. If there are any errors during auto sync, they will be made available in the `handleSyncErrors` function. You can use it to make your user aware that their changes failed. See [Configuring](#configuring-optional) for more details on how to customize this.
|
||||
|
||||
When reconciling with the server, this package assumes that you'll use one of the following mechanisms when removing documents:
|
||||
|
||||
1. `archive`. With this mechanism, when a document is removed from its original collection, it's placed in an `archive` collection. If your app doesn't already employ an archive mechanism, check out the [jam:archive](https://github.com/jamauro/archive) package to make this easy. By simply adding the `jam:archive` package, you won't need to do any further configuration.
|
||||
|
||||
Otherwise, be sure to check out the `archive` configuration options. **`Note`**: it's assumed that the data in your `archive` collection will include the original document data at the root level, e.g.:
|
||||
```js
|
||||
{
|
||||
_id, // auto-generated by Meteor as with other collection _ids
|
||||
_collection, // the name of the collection, e.g. 'todos', that the doc belonged to originally
|
||||
archivedAt, // the timestamp when the document was removed from its original collection and inserted into the archive
|
||||
id, // the original doc _id renamed to prevent conflict with the auto-generated one above. when restored, it will be renamed back to _id automatically by this package
|
||||
/*
|
||||
...rest of original doc
|
||||
*/
|
||||
}
|
||||
```
|
||||
|
||||
2. `soft delete`. If your app doesn't already employ a soft delete mechanism, check out the [jam:soft-delete](https://github.com/jamauro/soft-delete) package to make this easy. If you're using something other than `deleted` as the flag name for your soft deletes, be sure to configure `filter` appropriately. See [Configuring](#configuring-optional) for more details.
|
||||
|
||||
To know when an auto sync is processing, you can use `isSyncing()` which is a reactive variable.
|
||||
|
||||
```js
|
||||
import { isSyncing } from 'meteor/jam:offline';
|
||||
|
||||
isSyncing(); // you can wrap this in a Tracker.autorun to detect when it changes
|
||||
```
|
||||
|
||||
If you prefer not to have the behavior provided by auto sync, be sure to configure `autoSync: false`. When `autoSync` is false, Minimongo data from when the user disconnects will be kept offline so you still benefit from faster reloads on reconnects but you'll be responsible for designing any syncing logic needed. If the user hasn't refreshed the page and has a brief disconnect / reconnect, then you'll still benefit from Meteor's built-in retry mechanism for methods. But if they do refresh or exit the app and come back later, any actions performed while offline will be lost.
|
||||
|
||||
I think it would be great to have better support for custom syncing. If you have ideas here, let me know. At this time, I'm not sure what primitives would be most useful for you.
|
||||
|
||||
## Configuring (optional)
|
||||
If you like the defaults, then you won't need to configure anything. But there is some flexibility in how you use this package. You may want to pay special attention to `filter` and `handleSyncErrors` to customize the experience for your users.
|
||||
|
||||
Here are the global defaults:
|
||||
```js
|
||||
const config = {
|
||||
filter: /** {} or { deleted: false } **/ // filter the documents to keep across all collections. if you're not using jam:archive or don't have the archive config below set, it will assume you're using soft deletes.
|
||||
sort: { updatedAt: -1 }, // keep the most recent documents assuming you have an updatedAt on each doc. if you're using a different field name for timestamps, you'll want to change this.
|
||||
limit: 100, // limit offline documents to a max of 100 for each collection
|
||||
keepAll: true, // keep data for offline use for all collections using the global filter, sort, limit. to keep data for only certain collections, set this to false and then use collection.keep() for the collections you want to use offline.
|
||||
autoSync: true, // auto sync changes made offline when the user comes back online
|
||||
handleSyncErrors: async ({ replayErrors, keepErrors }) => {
|
||||
if (replayErrors) console.error('replay', replayErrors); // if there are errors when the Meteor methods are replayed, they will be in array here with the name of the method, the method's args, and the error itself. you can use it to alert your user, logging purposes, etc.
|
||||
|
||||
if (keepErrors) { // when syncing, if you're using a .keep filter or you have a global filter in the config that isn't an empty object, and there are errors reconciling with the server, they will be in an array here with the name of the collection and the error itself. you can customize how you handle these. by default, we clear the offline database for the collection since it could have stale data and reload the page.
|
||||
await Promise.allSettled(keepErrors.map(({ name }) => clear(name)));
|
||||
console.error('keep', keepErrors)
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
...(Archive && { // Archive is provided by jam:archive. if you're using a different archive mechanism, you'll need to configure these manually
|
||||
archive: {
|
||||
name: 'archives',
|
||||
collectionKey: '_collection',
|
||||
primaryIdKey: 'id',
|
||||
timestampKey: 'archivedAt'
|
||||
}
|
||||
})
|
||||
};
|
||||
````
|
||||
|
||||
To change the global defaults, use:
|
||||
```js
|
||||
// put this in a file that's imported on both the client and server
|
||||
import { Offline } from 'meteor/jam:offline';
|
||||
|
||||
Offline.configure({
|
||||
// ... change the defaults here ... //
|
||||
});
|
||||
```
|
||||
|
||||
## Adding a service worker
|
||||
You'll likely want to add a service worker as well to cache your HTML, CSS, Javascript so your users can continue to use the app offline, even if they accidentally click refresh.
|
||||
|
||||
Follow these [instructions](https://github.com/jamauro/pwa-kit) to add a service worker and go even further by making it a PWA (progressive web app).
|
||||
232
v3-docs/docs/community-packages/pub-sub.md
Normal file
232
v3-docs/docs/community-packages/pub-sub.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# Pub-sub
|
||||
|
||||
- `Who maintains the package` – [Jam](https://github.com/jamauro)
|
||||
|
||||
[[toc]]
|
||||
|
||||
## What is this package?
|
||||
|
||||
`jam:pub-sub` brings three key features to Meteor apps:
|
||||
|
||||
1. Method-based publish / subscribe
|
||||
2. Change Streams-based publish / subscribe
|
||||
3. Subscription caching
|
||||
|
||||
> **Important**: This package expects that you'll use the promise-based `*Async` Meteor collection methods introduced in `v2.8.1`.
|
||||
|
||||
## Method-based publish / subscribe
|
||||
Meteor's traditional `publish / subscribe` is truly wonderful. However, there is a cost to pushing updates reactively to all connected clients – it's resource intensive and will eventually place limits on your ability to scale your app.
|
||||
|
||||
One way to reduce the need for the traditional `publish / subscribe` is to fetch the data via a `Meteor Method` but there's a big problem here: the data **won't** be automatically merged into Minimongo and you completely lose Meteor's magical reactivity. Minimongo is great to work with and makes things easy as the source of truth on the client. Without it, you'll need to create your own stores on the client and essentially duplicate Minimongo.
|
||||
|
||||
With `jam:pub-sub`, you use `Meteor.publish.once` and the same `Meteor.subscribe` to have the data fetched via a Meteor Method and merged automatically in Minimongo so you can work with it as you're accustomed to. It also automatically preserves reactivity for the user when they make database writes. Note that these writes will **not** be broadcast in realtime to all connected clients by design but in many cases you might find that you don't need that feature of Meteor's traditional `publish / subscribe`.
|
||||
|
||||
## How to download it?
|
||||
|
||||
Add the package to your app
|
||||
```bash
|
||||
meteor add jam:pub-sub
|
||||
```
|
||||
### Sources
|
||||
|
||||
* [GitHub repository](https://github.com/jamauro/pub-sub)
|
||||
|
||||
## How to use it?
|
||||
|
||||
## Change Streams-based publish / subscribe
|
||||
**`Alpha`**
|
||||
|
||||
With `jam:pub-sub` and MongoDB Change Streams, you can preserve Meteor's magical reactivity for all clients while opting out of the traditional `publish / subscribe` and its use of the `oplog`. Use `Meteor.publish.stream` instead of using `Meteor.publish` and subscribe using the same `Meteor.subscribe` on the client.
|
||||
|
||||
**Important**: Change Streams will work best when the filter you use can be shared. To that end, if you have a publication that includes a `userId`, this package will filter out that condition when setting up the Change Stream because it will result in too many unique change streams. As an example, lets say you have this publication:
|
||||
|
||||
```js
|
||||
Meteor.publish.stream('todos', function() {
|
||||
return Todos.find({
|
||||
$or: [
|
||||
{ isPrivate: false },
|
||||
{ owner: this.userId }
|
||||
]
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
When this publication is invoked, it will pull all the `Todos` that match the filter above and then begin watching a Change Stream with this filter:
|
||||
```js
|
||||
{ isPrivate: false }
|
||||
```
|
||||
|
||||
For this particular filter, it should behave as you'd expect so you wouldn't need to make changes. However, if you have complex filters involving the `userId`, you'll need to be sure that the behavior you expect remains when using `.stream`. If it's not meeting your needs, you could split the one publication into two publications, using a `.stream` with a filter than can be shared and a `.once` for the `userId`:
|
||||
|
||||
```js
|
||||
Meteor.publish.stream('todos.public', function() {
|
||||
return Todos.find({ isPrivate: false });
|
||||
});
|
||||
|
||||
Meteor.publish.once('todos.owned', function() {
|
||||
return Todos.find({ owner: this.userId });
|
||||
});
|
||||
```
|
||||
|
||||
The downside by splitting into two is it could result in over-fetching but the data will be merged correctly into Minimongo.
|
||||
|
||||
**Note**: In most cases, you'd likely benefit the most from using `Meteor.publish.once` anywhere you can and using `Meteor.publish.stream` only when you really need it and with a filter than can be shared.
|
||||
|
||||
**Note**: If you decide to entirely opt-out of using the traditional `Meteor.publish`, then you'll also want to disable the `oplog` entirely — add the `disable-oplog` package with `meteor add disable-oplog`.
|
||||
|
||||
At the moment, this feature is considered in an `alpha` state. Based on previous [Change Streams experiments](https://github.com/meteor/meteor/discussions/11842#discussioncomment-4061112) by the Meteor Community, it seems that using Change Streams as a wholesale replacement for the traditional `publish / subscribe` could "just work". However, in practice it may be a "Your Mileage May Vary" type of situation depending on the frequency of writes, number of connected clients, how you model your data, and how you set up the cursors inside of `Meteor.publish.stream`. With that said, if you're interested in this feature, I'd encourage you to try it out and share your findings.
|
||||
|
||||
## Subscription caching
|
||||
Normally, when a user moves between routes or components, the subscriptions will be stopped. When a user is navigating back and forth in your app, each time will result in a re-subscribe which means more spinners, a slower experience, and is generally a waste.
|
||||
|
||||
By caching your subscriptions, you can create a better user experience for your users. Since the subscription itself is being cached, the data in Minimongo will be updated in the background until the `cacheDuration` expires for that subscription at which point it will be stopped and the data will be removed from Minimongo as expected.
|
||||
|
||||
## Usage
|
||||
|
||||
### Add the package to your app
|
||||
`meteor add jam:pub-sub`
|
||||
|
||||
### Define a Method-based publication
|
||||
Define a publication using `Meteor.publish.once` and subscribe just as you do currently. `Meteor.publish.once` expects you to return a cursor or an array of cursors just like `Meteor.publish`.
|
||||
|
||||
```js
|
||||
// server
|
||||
Meteor.publish.once('notes.all', function() {
|
||||
return Notes.find();
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// client
|
||||
// Since each view layer (Blaze, React, Svelte, Vue, etc) has a different way of using `Tracker.autorun`, I've omitted it for brevity. You'd subscribe just as you do currently in your view layer of choice.
|
||||
Meteor.subscribe('notes.all')
|
||||
|
||||
// work with the Notes collection in Minimongo as you're accustomed to
|
||||
Notes.find().fetch();
|
||||
```
|
||||
That's it. By using `Meteor.publish.once`, it will fetch the data initally and automatically merge it into Minimongo. Any database writes to the `Notes` collection will be sent reactively to the user that made the write.
|
||||
|
||||
> **Important**: when naming your publications be sure to include the collection name(s) in it. This is generally common practice and this package relies on that convention. If you don't do this and you're caching the subscription, Minimongo data may be unexpectedly removed or retained when the subscription stops. It's recommended that you follow this convention for all publications including `Meteor.publish`. Here are some examples of including the collection name in the publication name:
|
||||
```js
|
||||
// the name you assign inside Mongo.Collection should be in your publication name(s), in this example 'notes'
|
||||
const Notes = new Mongo.Collection('notes')
|
||||
|
||||
// as long as it appears somewhere in your publication name, you're good to go. here are some examples:
|
||||
Meteor.publish.once('notes');
|
||||
Meteor.publish.once('notes.all');
|
||||
Meteor.publish.once('notes/single');
|
||||
Meteor.publish.once('somethingAndNotes');
|
||||
```
|
||||
|
||||
It also works just as you'd expect for an array of cursors:
|
||||
|
||||
```js
|
||||
// server
|
||||
Meteor.publish.once('notes.todos.all', function() {
|
||||
return [Notes.find(), Todos.find()];
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// client
|
||||
Meteor.subscribe('notes.todos.all');
|
||||
|
||||
// work with the Notes collection in Minimongo as you're accustomed to
|
||||
Notes.find().fetch();
|
||||
|
||||
// work with the Todos collection in Minimongo as you're accusomted to
|
||||
Todos.find().fetch();
|
||||
```
|
||||
|
||||
Inside `Meteor.publish.once`, `this.userId` and [this.added](https://docs.meteor.com/api/pubsub.html#Subscription-added) can still be used. The added document will be included in the final result data. The rest of the low-level `publish` API will be disregarded, as they no longer fit into the context of a Method-based data fetch.
|
||||
|
||||
```js
|
||||
Meteor.publish.once('notes.all', function() {
|
||||
// ... //
|
||||
const userId = this.userId;
|
||||
|
||||
this.added('notes', _id, fields);
|
||||
// ... //
|
||||
return Notes.find();
|
||||
})
|
||||
```
|
||||
|
||||
### Define a Change Streams-based publication
|
||||
Define a publication using `Meteor.publish.stream` and subscribe just as you do currently. `Meteor.publish.stream` expects you to return a cursor or an array of cursors just like `Meteor.publish`.
|
||||
|
||||
```js
|
||||
// server
|
||||
Meteor.publish.stream('notes.all', function() {
|
||||
return Notes.find();
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// client
|
||||
// Since each view layer (Blaze, React, Svelte, Vue, etc) has a different way of using `Tracker.autorun`, I've omitted it for brevity. You'd subscribe just as you do currently in your view layer of choice.
|
||||
Meteor.subscribe('notes.all')
|
||||
|
||||
// work with the Notes collection in Minimongo as you're accustomed to
|
||||
Notes.find().fetch();
|
||||
```
|
||||
That's it. By using `Meteor.publish.stream`, any database writes to the `Notes` collection will be sent reactively to **all** connected clients just as with `Meteor.publish`.
|
||||
|
||||
#### Setting the `maxPoolSize` for Change Streams
|
||||
`maxPoolSize` defaults to `100` which may not need adjusting. If you need to adjust it, you can set it in [Meteor.settings](https://docs.meteor.com/api/collections.html#mongo_connection_options_settings) like this:
|
||||
```js
|
||||
{
|
||||
//...//
|
||||
"packages": {
|
||||
"mongo": {
|
||||
"options": {
|
||||
"maxPoolSize": 200 // or whatever is appropriate for your application
|
||||
}
|
||||
}
|
||||
}
|
||||
// ... //
|
||||
}
|
||||
```
|
||||
|
||||
### Turn on subscription caching
|
||||
With `jam:pub-sub`, you can enable subscription caching globally or at a per-subscription level. Subscription caching is turned off by default to preserve the current behavior in Meteor. Any subscription can be cached, regardless of how it's published.
|
||||
|
||||
To enable subscription caching globally for every subscription:
|
||||
```js
|
||||
// put this in a file that's imported on the client at a minimum. it can be used isomorphically but the configuration only applies to the client.
|
||||
import { PubSub } from 'meteor/jam:pub-sub';
|
||||
|
||||
PubSub.configure({
|
||||
cache: true // defaults to false
|
||||
});
|
||||
```
|
||||
|
||||
The global `cacheDuration` is set to `60 seconds` by default. This is from when the subscription was originally set to be stopped, i.e. when the component housing the subscription was destroyed because the user navigated away. If the user comes right back, then the cache will be used. If they don't, after `60 seconds`, the subscription cache will be removed. If you want to change the global `cacheDuration`, change it with a value in `seconds`:
|
||||
|
||||
```js
|
||||
import { PubSub } from 'meteor/jam:pub-sub';
|
||||
|
||||
PubSub.configure({
|
||||
cacheDuration: 5 * 60 // sets the cacheDuration to 5 minutes. defaults to 1 min
|
||||
});
|
||||
```
|
||||
|
||||
You can also configure `cache` and `cacheDuration` for each individual subscription when you use `Meteor.subscribe`. For example:
|
||||
```js
|
||||
Meteor.subscribe('todos.single', _id, { cacheDuration: 30 }) // caches for 30 seconds, overriding the global default
|
||||
Meteor.subscribe('notes.all', { cache: true }) // turns caching on, overriding the global default, and uses the global default cacheDuration
|
||||
```
|
||||
|
||||
> **Note**: the rest of the [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe) API (e.g. `onStop`, `onReady`) works just as you'd expect.
|
||||
|
||||
> **Note**: Because the data will remain in Minimongo while the subscription is cached, you should be mindful of your Minimongo `.find` selectors. Be sure to use specific selectors to `.find` the data you need for that particular subscription. This is generally considered [best practice](https://guide.meteor.com/data-loading#fetching) so this is mainly a helpful reminder.
|
||||
|
||||
#### Clearing the cache
|
||||
Each individual subcription will be automatically removed from the cache when its `cacheDuration` elapses.
|
||||
|
||||
Though it shouldn't be necessary, you can programmatically clear all cached subscriptions:
|
||||
|
||||
```js
|
||||
import { PubSub } from 'meteor/jam:pub-sub';
|
||||
|
||||
PubSub.clearCache();
|
||||
```
|
||||
77
v3-docs/docs/community-packages/soft-delete.md
Normal file
77
v3-docs/docs/community-packages/soft-delete.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Soft-delete
|
||||
|
||||
- `Who maintains the package` – [Jam](https://github.com/jamauro)
|
||||
|
||||
[[toc]]
|
||||
|
||||
## What is this package?
|
||||
|
||||
Soft Delete is an easy way to add soft deletes to your Meteor app. Its key features are:
|
||||
|
||||
* Zero config needed (though you can customize)
|
||||
* Isomorphic so that it works with Optimistic UI
|
||||
* Automatically overrides `removeAsync` to make it a soft delete
|
||||
* Automatically adds the soft delete flag on `insertAsync` and to the filter for your queries, e.g. `.find`, so you don't need to make any changes to them
|
||||
* Recover soft deleted docs with `recoverAsync` collection method
|
||||
* Explicitly soft delete with `softRemoveAsync` collection method (optional)
|
||||
* Optionally add a `deletedAt` timestamp
|
||||
* Optionally exclude specific collections
|
||||
* Compatible with Meteor `2.8.1+` and `3.0+`
|
||||
|
||||
> **Note:** Alternative to soft deletion is to archive documents in your collection. You can use [`jam:archive`](./archive.md) package for that. Be sure to compare those two approaches to pick the solution best suited for your application.
|
||||
|
||||
## How to download it?
|
||||
|
||||
Add the package to your app
|
||||
```bash
|
||||
meteor add jam:soft-delete
|
||||
```
|
||||
### Sources
|
||||
|
||||
* [GitHub repository](https://github.com/jamauro/soft-delete)
|
||||
|
||||
## How to use it?
|
||||
|
||||
### Deleting permanently
|
||||
By default, this package overrides the `removeAsync` collection method so that it soft deletes the document(s) with a boolean flag rather that removing them from the database. To delete permanently, pass in the option `soft: false`, e.g.:
|
||||
```js
|
||||
Collection.removeAsync(/* your filter */, { soft: false })
|
||||
```
|
||||
|
||||
If you prefer, you can prevent overriding the `removeAsync` by setting `overrideRemove: false`. See [Configuring](#configuring-optional) for more details.
|
||||
|
||||
### Explicitly soft deleting
|
||||
If you prefer, you can explicity use `softRemoveAsync`, e.g.:
|
||||
```js
|
||||
Collection.softRemoveAsync(/* your filter */)
|
||||
```
|
||||
|
||||
### Recovering a document
|
||||
To recover a soft deleted document, use `recoverAsync`, e.g.:
|
||||
```js
|
||||
Collection.recoverAsync(/* your filter */)
|
||||
```
|
||||
|
||||
## Configuring (optional)
|
||||
If you like the defaults, then you won't need to configure anything. But there is some flexibility in how you use this package.
|
||||
|
||||
Here are the global defaults:
|
||||
```js
|
||||
const config = {
|
||||
deleted: 'deleted', // the field name used for the boolean flag. you can update to your preference, e.g. 'isDeleted'
|
||||
deletedAt: '', // add the name of the field you'd like to use for a deletedAt timestamp, e.g. 'deletedAt', if you want to include it on your docs
|
||||
autoFilter: true, // automatically adds the { [deleted]: false } filter to your queries
|
||||
overrideRemove: true, // overrides the Collection.removeAsync method to make it a soft delete instead
|
||||
exclude: ['roles', 'role-assignment'] // exclude specific collections from using soft delete. defaults to excluding the collections created the meteor roles package
|
||||
};
|
||||
```
|
||||
|
||||
To change the global defaults, use:
|
||||
```js
|
||||
// put this in a file that's imported on both the client and server
|
||||
import { SoftDelete } from 'meteor/jam:soft-delete';
|
||||
|
||||
SoftDelete.configure({
|
||||
// ... change the defaults here ... //
|
||||
});
|
||||
```
|
||||
Reference in New Issue
Block a user