diff --git a/README.md b/README.md index 7ff1089850..9cb1309dc0 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Use the same code whether you’re developing for web, iOS, Android, or desktop How about trying a getting started tutorial in your favorite technology? -| [ React](https://react-tutorial.meteor.com/) | +| [ React](https://react-tutorial.meteor.com/) | | - | | [ Blaze](https://blaze-tutorial.meteor.com/) | | [ Vue](https://vue-tutorial.meteor.com/) | diff --git a/docs/_config.yml b/docs/_config.yml index 323a85778f..adee7746f6 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,6 +1,7 @@ title: Meteor API Docs subtitle: API Docs versions: + - '2.13' - '2.12' - '2.11' - '2.10' diff --git a/docs/generators/changelog/versions/2.13.md b/docs/generators/changelog/versions/2.13.md new file mode 100644 index 0000000000..52751ecae3 --- /dev/null +++ b/docs/generators/changelog/versions/2.13.md @@ -0,0 +1,67 @@ +## v2.13.0, 2023-07-26 + +### Highlights + +* Handled implicit collection creation oplog message by [radekmie](https://github.com/radekmie) [PR](https://github.com/meteor/meteor/pull/12643). +* Fix upsert logs when using WARN_WHEN_USING_OLD_API flag by [Grubba27](https://github.com/Grubba27) [PR](https://github.com/meteor/meteor/pull/12640). +* Updating mongo types by [Grubba27](https://github.com/Grubba27) [PR](https://github.com/meteor/meteor/pull/12639). +* Fix solid skeleton by [fredmaiaarantes](https://github.com/fredmaiaarantes) [PR](https://github.com/meteor/meteor/pull/12637). +* Setting The Viewport meta tag on skeletons [fredmaiaarantes](https://github.com/fredmaiaarantes) [PR](https://github.com/meteor/meteor/pull/12636). +* Update mongo.d.ts with projection [StorytellerCZ](https://github.com/StorytellerCZ) [PR](https://github.com/meteor/meteor/pull/12635). +* Update guide code for GraphQL [StorytellerCZ](https://github.com/StorytellerCZ) [PR](https://github.com/meteor/meteor/pull/12619). +* Twitter Whitelist issue resolved [Atharshoyeb](https://github.com/Atharshoyeb) [PR](https://github.com/meteor/meteor/pull/12369). +* Node security patch (14.21.4) [PR](https://github.com/meteor/node-v14-esm/pull/1). +* Updated deprecated reference in mongo package by [StorytellerCZ](https://github.com/StorytellerCZ) [PR](https://github.com/meteor/meteor/pull/12653/files). +* Updated BlazeJS git ref in core meteor to 2.7.1 by [Grubba27](https://github.com/Grubba27) [PR](https://github.com/meteor/meteor/pull/12651). +* Added `Meteor.applyAsync` types by [Julusian](https://github.com/Julusian) [PR](https://github.com/meteor/meteor/pull/12645). + + +#### Breaking Changes + +N/A + +#### Internal changes + +* `ddp-server@get-version`: + - Updated livedata server test to be more easily debbuged. + +* `mongo@get-version`: + - Updated deprecated reference in Mongo package. + +#### Migration Steps + +N/A + +#### Meteor Version Release + + +* `Command line`: + - Updated metatags for skeletons. + - Updated solidjs skeleton to be more idiomatic. + +* `meteor@1.11.3`: + - Added types for applyAsync and added more documentation for applyAsync options. + +* `mongo@1.16.7`: + - Updated types with projection. + - Fixed wrong upsert logs when using WARN_WHEN_USING_OLD_API flag. + - Handled implicit collection creation oplog message. + +* `test-in-console@1.2.5`: + - Adjusted log indentation. + - All errors will be logged to console. + - Will always use puppeteer@20.4.0 + +* `twitter-oauth@1.3.3`: + - Fixed twitter whitelist issue. + + +#### Special thanks to + +- [@radekmie](https://github.com/radekmie). +- [@Grubba27](https://github.com/Grubba27). +- [@fredmaiaarantes](https://github.com/fredmaiaarantes). +- [@StorytellerCZ](https://github.com/StorytellerCZ). +- [@Atharshoyeb](https://github.com/Atharshoyeb). +- [@Julusian](https://github.com/Julusian). + diff --git a/docs/generators/changelog/versions/3.0.md b/docs/generators/changelog/versions/3.0.md index 972ff5cef8..d0db4c536c 100644 --- a/docs/generators/changelog/versions/3.0.md +++ b/docs/generators/changelog/versions/3.0.md @@ -356,7 +356,7 @@ - `meteor-tool@3.0.0`: - - Package was bumped due to a dependency update. No code changes were made. + - Changes to how meteor apps are being created [PR](https://github.com/meteor/meteor/pull/12697) - `meteor@2.0.0`: diff --git a/docs/history.md b/docs/history.md index 8c58ca49b0..7618046fbd 100644 --- a/docs/history.md +++ b/docs/history.md @@ -799,6 +799,839 @@ Package was bumped due to a dependency update. No code changes were made. +## v3.0, TBD + +### Highlights + +#### Breaking Changes + +- `accounts-2fa@3.0.0`: + + - Some methods are now async. See below: + - `Accounts._is2faEnabledForUser` + - `(Meteor Method) - generate2faActivationQrCode` + - `(Meteor Method) - enableUser2fa` + - `(Meteor Method) - disableUser2fa` + - `(Meteor Method) - has2faEnabled` + +- `accounts-base@3.0.0`: + + - `methods.removeOtherTokens` is now async + - `Accounts.destroyToken` is now async + - `Accounts.insertUserDoc` is now async + - `Accounts.updateOrCreateUserFromExternalService` is now async + - `Accounts.expirePasswordToken` is now async + - `Accounts.setupUsersCollection` is now async + +- `accounts-password@3.0.0`: + + - Some server methods are now async: + - `Accounts.sendResetPasswordEmail` + - `Accounts.sendEnrollmentEmail` + - `Accounts.sendVerificationEmail` + - `Accounts.addEmail` + - `Accounts.removeEmail` + - `Accounts.verifyEmail` + - `Accounts.createUserVerifyingEmail` + - `Accounts.createUser` + - `Accounts.generateVerificationToken` + - `Accounts.generateResetToken` + - `Accounts.forgotPassword` + - `Accounts.setPassword` + - `Accounts.changePassword` + - `Accounts.setUsername` + - `Accounts.findUserByEmail` + - `Accounts.findUserByUsername` + +- `accounts-passwordless@3.0.0`: + + - `Accounts.sendLoginTokenEmail` is now async. + +- `allow-deny@2.0.0`: + + - Updated to accept async functions. + +- `appcache@2.0.0`: + + - Updated internal api to use `expressHandlers` + +- `autoupdate@2.0.0`: + + - Updated api to be async, with asyncronous queueing. + +- `babel-compiler@8.0.0`: + + - Removed `Promise.await` default transform. + - Added top-level-await to packages. + +- `boilerplate-generator@2.0.0`: + + - `toHTML` is no longer available (it was already deprecated). Use `toHTMLStream` instead. + - Updated to use `expressHandlers` + +- `browser-policy-common@2.0.0`: + + - Updated to use `expressHandlers` + +- `browser-policy-content@2.0.0`: + + - Some methods are now async. See below: + - `BrowserPolicy.content.setPolicy` + - `BrowserPolicy.content.allowInlineScripts` + - `BrowserPolicy.content.disallowInlineScripts` + - `BrowserPolicy.content.disallowAll` + - `BrowserPolicy.setDefaultPolicy` + +- `browser-policy@2.0.0`: + Updated to use async methods from `browser-policy-common` and `browser-policy-content`. + +- `caching-compiler@2.0.0`: + + - `afterLink` is now async. + - Updated to use now async API. + +- `callback-hook@2.0.0`: + + - Added `forEachAsync` method. + +- `check@2.0.0`: + + - Removed `fibers` related tests. + +- `constraint-solver@2.0.0`: + + - Some methods are now async. See below: + + - `ConstraintSolver.getVersionCostSteps` + - `ConstraintSolver.analyze` + - `ConstraintSolver.resolve` + + - Updated tests to be async. + - Removed a few underscore usage. + - Added updated to use async methods + +- `context@1.0.0`: + + - Removed `fibers` from package. + +- `core-runtime@2.0.0`: + + - Created package to load packages and the app. + - This is the pakcages that sets up the Runtime. + +- `ddp-client@3.0.0`: + + - Added `isAsyncCall` method to know if call is being made by a async method. + - Removed `fibers` from package. + - Updated tests to use async methods. + +- `ddp-common@2.0.0`: + + - Added `.fence` option. + +- `ddp-server@3.0.0`: + + - Updated to use async methods. + - Removed `fibers` from package. + - Updated tests to use async methods. + - Turned server implementation to async. + +`deprecated`: + +- `http`: + - Updated handlers to use `expressHandlers` +- `spiderable`: + + - Updated handlers to use `expressHandlers` + - removed `fibers` usage if flag is set to `true` + +- `ecmascript-runtime@1.0.0`: + + - Added dependency to `@babel/runtime`. + +- `ecmascript@1.0.0`: + + - Added dependency to `@babel/runtime`. + - Moved runtime tests. + +- `email@3.0.0`: + + - `Email.send` is no longer available. Use `Email.sendAsync` instead. + - Updated types to reflext async methods and `Email.send` depracation. + +- `facts-base@2.0.0`: + + - turned unorderd deps on `ddp` to false. + +- `id-map@2.0.0`: + + - Added `forEachAsync` method. + +- `logging@2.0.0`: + + - Added dependency to `@babel/runtime`. + +- `logic-solver@3.0.0`: + `Logic.disablingAssertions` is now async. + `minMaxWS` is now async. + +- `meteor@2.0.0`: + + - Async local storage was added to help deal with async methods. + - Added `promiseEmmiter` to help with async methods. + - Removed `fibers` from package. + +- `minifier-css@2.0.0`: + + - `minifyCss` is now async. + - Removed `fibers` from package. + +- `minifier-js@3.0.0`: + + - `minifyJs` is now async. + - `terserMinify` no longer takes callbacks + - Removed `fibers` from package. + +* `minimongo@2.0.0`: + - `cursor.observe` now returns `isReady` and `isReadyPromise` wich indicates + if the cursor is ready and if the callbacks are have been called. + If you only use it in the `Client` or as a `LocalCollection` things have not + changed. + +- `modules@1.0.0`: + + - Updated `reify` version. + +- `mongo@2.0.0`: + + - Updated to unify methods, `update`,`insert`,`remove`, `fetch` are now async, they are + the same as their `*Async` counterpart. + - `ensureIndex` and `createIndex` are now async. + +- `blaze@3.0.0`: +- TODO + +- `mongo-decimal@`: + + - Updated to use `async` methods. + +- `oauth`: + + - `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before + - the following server methods are now async: + - `OAuth._renderOauthResults` + - `OAuth._endOfLoginResponse` + - `OAuth.renderEndOfLoginResponse` + - `OAuth._storePendingCredential` + - `OAuth._retrievePendingCredential` + - `ensureConfigured` + - `_cleanStaleResults` + +- `oauth1`: + + - the following server methods are now async: + - `OAuth._storeRequestToken` + - `OAuth._retrieveRequestToken` + +- `oauth2`: + + - `OAuth._requestHandlers['2']` is now async. + +- `ordered-dict@2.0.0`: + + - Added `forEachAsync` method. + +- `promise@1.0.0`: + + - Removed `fibers` usage + +- `reload-safetybelt@2.0.0`: + + - Added `ecmascript` package to `package.js` + +- `server-render@1.0.0`: + + - Updated usage with `getBoilerplate` that are now `async`. + +- `service-configuration@2.0.0`: + + - Updated to use `createIndexAsync`. + +- `shell-server@1.0.0`: + + - Updated to handle promises results. + +- `socket-stream-client@1.0.0`: + + - Updated tests to handle `async` code. + +- `standard-minifier-js@3.0.0`: + + - `processFilesForBundle` is now `async`. + +- `test-helpers@2.0.0`: + + - Updated to use `async` methods. + - Removed `fibers` usage. + - Added possibliy to use `async` tests. + +- `test-in-browser@2.0.0`: + + - Updated css to be in dark mode. + +- `test-in-console@2.0.0`: + + - Updated log identation. + +- `tinytest@2.0.0`: + + - Added `test name` to logs. + - Removed `fibers` usage. + +- `underscore@2.0.0`: + + - Removed dependency in meteor package. + +- `webapp@2.0.0`: + + - These methods are now async: + + - `WebAppInternals.reloadClientPrograms()` + - `WebAppInternals.pauseClient()` + - `WebAppInternals.generateClientProgram()` + - `WebAppInternals.generateBoilerplate()` + - `WebAppInternals.setInlineScriptsAllowed()` + - `WebAppInternals.enableSubresourceIntegrity()` + - `WebAppInternals.setBundledJsCssUrlRewriteHook()` + - `WebAppInternals.setBundledJsCssPrefix()` + - `WebAppInternals.getBoilerplate` + + - Changed engine from connect to express and changed api naming to match express. See below: + - `WebApp.connectHandlers.use(middleware)` is now `WebApp.expressHandlers.use(middleware)` + - `WebApp.rawConnectHandlers.use(middleware)` is now `WebApp.rawExpressHandlers.use(middleware)` + - `WebApp.connectApp` is now `WebApp.expressApp` + + + - `accounts-facebook@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-github@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-google@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-meetup@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-meteor-developer@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-twitter@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-ui-unstyled@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `accounts-weibo@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `audit-argument-checks@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `autopublish@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `babel-runtime@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `base64@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `binary-heap@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `boilerplate-generator-tests@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `crosswalk@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `ddp@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `ddp-rate-limiter@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + + - `diff-sequence@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `disable-oplog@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `ecmascript-runtime-client@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `ecmascript-runtime-server@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `ejson@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `es5-shim@5.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `facebook-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `facebook-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `facts-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `fetch@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `force-ssl@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `force-ssl-common@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `geojson-utils@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `github-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `github-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `google-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `google-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `hot-code-push@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `insecure@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `inter-process-messaging@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `launch-screen@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `localstorage@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `meetup-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `meetup-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `meteor-base@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `meteor-developer-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `meteor-developer-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `meteor-tool@3.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `mobile-experience@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `mobile-status-bar@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `modern-browsers@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `modules-runtime@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `mongo-dev-server@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `mongo-id@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `mongo-livedata@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + + - `npm-mongo@5.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `oauth@3.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `oauth-encryption@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `oauth1@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `oauth2@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `package-stats-opt-out@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `package-version-parser@4.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `random@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `rate-limit@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `reactive-dict@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `reactive-var@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `reload@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `retry@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `routepolicy@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `session@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `sha@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `standard-minifier-css@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `standard-minifiers@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `static-html@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `test-server-tests-in-console-once@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `tinytest-harness@1.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `twitter-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `twitter-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `typescript@5.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `underscore-tests@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `url@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `webapp-hashing@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `weibo-config-ui@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + + - `weibo-oauth@2.0.0`: + +Package was bumped due to a dependency update. No code changes were made. + + +#### New Public API + +- `accounts-base`: (2.9+) + + - `Meteor.userAsync()` + +- `callback-hook`:forEachAsync + + - `forEachAsync` + +- `ddp-server`: (2.8+) + + - `Meteor.callAsync()` + +- `minifier-css`: (2.9+) + + - `CssTools.minifyCssAsync()` + +- `mongo`: + + - `Mongo.Collection`: (2.8+) + - `createCappedCollectionAsync` + - `createIndexAsync` + - `dropCollectionAsync` + - `dropIndexAsync` + - `findOneAsync` + - `insertAsync` + - `removeAsync` + - `updateAsync` + - `upsertAsync` + - `Collection.Cursor`: (2.8+) + - `countAsync` + - `fetchAsync` + - `forEachAsync` + - `mapAsync` + - `[Symbol.asyncIterator]` so this code should work: + ```js + for await (const document of collection.find(query, options)) /* ... */ + ``` + +#### Internal API changes + +`accounts-base`: + +- `_attemptLogin` +- `_loginMethod` +- `_runLoginHandlers` + +#### New Internal API + +`accounts-password`: + +- `Accounts._checkPasswordAsync` + + +#### Special thanks to + + + +## v2.13.0, 2023-05-XX + +### Highlights + +* Handled implicit collection creation oplog message by [radekmie](https://github.com/radekmie) [PR](https://github.com/meteor/meteor/pull/12643). +* Fix upsert logs when using WARN_WHEN_USING_OLD_API flag by [Grubba27](https://github.com/Grubba27) [PR](https://github.com/meteor/meteor/pull/12640). +* Updating mongo types by [Grubba27](https://github.com/Grubba27) [PR](https://github.com/meteor/meteor/pull/12639). +* Fix solid skeleton by [fredmaiaarantes](https://github.com/fredmaiaarantes) [PR](https://github.com/meteor/meteor/pull/12637). +* Setting The Viewport meta tag on skeletons [fredmaiaarantes](https://github.com/fredmaiaarantes) [PR](https://github.com/meteor/meteor/pull/12636). +* Update mongo.d.ts with projection [StorytellerCZ](https://github.com/StorytellerCZ) [PR](https://github.com/meteor/meteor/pull/12635). +* Update guide code for GraphQL [StorytellerCZ](https://github.com/StorytellerCZ) [PR](https://github.com/meteor/meteor/pull/12619). +* Twitter Whitelist issue resolved [Atharshoyeb](https://github.com/Atharshoyeb) [PR](https://github.com/meteor/meteor/pull/12369). + +#### Breaking Changes + +N/A + +#### Internal API changes + +N/A + +#### Migration Steps + +TODO + +#### Meteor Version Release + + +* `Command line`: + - Updated metatags for skeletons. + - Updated solidjs skeleton to be more idiomatic. + +* `mongo@1.16.7`: + TODO + + +#### Special thanks to + +- [@radekmie](https://github.com/radekmie). +- [@Grubba27](https://github.com/Grubba27). +- [@fredmaiaarantes](https://github.com/fredmaiaarantes). +- [@StorytellerCZ](https://github.com/StorytellerCZ). +- [@Atharshoyeb](https://github.com/Atharshoyeb). + ## v2.12.0, 2023-04-28 ### Highlights @@ -832,7 +1665,7 @@ N/A #### Migration Steps -Now if you want to check where do you call old-style api methods +Now if you want to check where do you call old-style api methods you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. @@ -841,7 +1674,7 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. * `accounts-base@2.2.8`: - Added `loginServiceConfiguration` type. - Added the `collection` option property, in order to be able to set the collection for Accounts, - more can be seen in the [discussion](https://github.com/meteor/meteor/discussions/12544#discussioncomment-5240763) + more can be seen in the [discussion](https://github.com/meteor/meteor/discussions/12544#discussioncomment-5240763) and in the [related issue](https://github.com/meteor/meteor-feature-requests/issues/20). - `onCreateUserHook` now accept promises and wait if necessary. @@ -853,7 +1686,7 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. * `browser-policy-framing@1.1.2`: - Added `es5` compatible syntax. - + * `browser-policy@1.1.2`: - Updated test name. @@ -903,7 +1736,7 @@ you can use ```WARN_WHEN_USING_OLD_API``` before starting your meteor process. * `mongo@1.16.6`: - Added `countDocuments` and `estimatedDocumentCount` types. - - Added warning for when old style apis are being used, to use this feature, + - Added warning for when old style apis are being used, to use this feature, use the variable`WARN_WHEN_USING_OLD_API=true` before starting the Meteor process. - Oplog driver updated to not throw error when MongoDB server and Meteor client mismatch. [issue](https://github.com/meteor/meteor/issues/12516) diff --git a/docs/source/commandline.md b/docs/source/commandline.md index 0fec5f634d..7ba58d166c 100644 --- a/docs/source/commandline.md +++ b/docs/source/commandline.md @@ -87,9 +87,17 @@ Create a new Meteor project. By default, it uses [React](https://guide.meteor.co and makes a subdirectory named *name* and copies in the template app. You can pass an absolute or relative path. -

Flags

+_This command requires an Internet connection and having git installed._ -**Flags for default packages** +

Cloning from project

+ +You can also create a new Meteor project by cloning an existing project. You can +list them using the command `meteor create --list` it will list all the available +templates. You can then clone them using the command `meteor create --example ` +Or you can use the `--from` flag to clone a project from a git repository. For example +`meteor create --from "https://github.com/meteor/skel-react" ` + +

Flags

`--prototype` @@ -100,6 +108,7 @@ For more information about security you can check it [here](https://guide.meteor.com/security.html#checklist) It can be used together with other flags that create apps such as `--react` or `--typescript`. +**Flags for default packages** `--bare` diff --git a/guide/_config.yml b/guide/_config.yml index 9bf7c889bc..f02bb44979 100644 --- a/guide/_config.yml +++ b/guide/_config.yml @@ -3,8 +3,9 @@ subtitle: The Official Guide github_repo: 'meteor/meteor' edit_branch: 'devel' edit_path: 'guide' -content_root: 'content' +content_root: 'source' versions: + - '2.13' - '2.12' - '2.11' - '2.10' @@ -30,7 +31,7 @@ versions: - '1.3' - '1.2' versioned-netlify-redirects: - netlify_site_id: meteor-guide + netlify_site_id: meteor-guide logo: title: @@ -56,6 +57,8 @@ sidebar_categories: - react - angular - vue + Integrations: + - flowbite Mobile: - cordova - react-native @@ -88,7 +91,7 @@ redirects: '/using-packages.html#using-npm': using-npm-packages.html#using-npm '/using-packages.html#npm-styles': using-npm-packages.html#npm-styles '/using-packages.html#npm-shrinkwrap': using-npm-packages.html#npm-shrinkwrap - '/using-packages.html#atmosphere': using-atmosphere-packages.html + '/using-packages.html#atmosphere': using-atmosphere-packages.html '/using-packages.html#atmosphere-searching': using-atmosphere-packages.html#atmosphere-searching '/using-packages.html#atmosphere-naming': using-atmosphere-packages.html#atmosphere-naming '/using-packages.html#installing-atmosphere': using-atmosphere-packages.html#installing-atmosphere @@ -100,7 +103,7 @@ redirects: '/using-packages.html#bind-environment': using-npm-packages.html#bind-environment '/using-packages.html#wrap-async': using-npm-packages.html#wrap-async '/using-packages.html#promises': using-npm-packages.html#promises - '/using-packages.html#overriding-packages': writing-npm-packages.html#overriding-npm-packages + '/using-packages.html#overriding-packages': writing-npm-packages.html#overriding-npm-packages '/using-packages.html#npm-overriding': writing-npm-packages.html#overriding-npm-packages '/using-packages.html#atmosphere-overriding': writing-atmosphere-packages.html#overriding-atmosphere-packages '/using-packages.html#npm-shrinkpack': using-npm-packages.html#npm-shrinkpack diff --git a/guide/source/2.13-migration.md b/guide/source/2.13-migration.md new file mode 100644 index 0000000000..5dba0f0102 --- /dev/null +++ b/guide/source/2.13-migration.md @@ -0,0 +1,48 @@ +--- +title: Migrating to Meteor 2.13 +description: How to migrate your application to Meteor 2.13. +--- + +Most of the new features in Meteor 2.13 are either applied directly behind the +scenes (in a backwards compatible manner) or are opt-in. For a complete +breakdown of the changes, please refer to the [changelog](http://docs.meteor.com/changelog.html). + +For this release all the changes are for quality of life improvements and +there are no breaking changes. + +for more information on the changes in this release, please refer to the +[changelog](http://docs.meteor.com/changelog.html). + + +

Migrating from a version older than 2.12?

+ +If you're migrating from a version of Meteor older than Meteor 2.12, there may +be important considerations not listed in this guide. + Please review the older migration guides for details: + +* [Migrating to Meteor 2.12](2.12-migration.html) (from 2.11) +* [Migrating to Meteor 2.11](2.11-migration.html) (from 2.10) +* [Migrating to Meteor 2.10](2.10-migration.html) (from 2.9) +* [Migrating to Meteor 2.9](2.9-migration.html) (from 2.8) +* [Migrating to Meteor 2.8](2.8-migration.html) (from 2.7) +* [Migrating to Meteor 2.7](2.7-migration.html) (from 2.6) +* [Migrating to Meteor 2.6](2.6-migration.html) (from 2.5) +* [Migrating to Meteor 2.5](2.5-migration.html) (from 2.4) +* [Migrating to Meteor 2.4](2.4-migration.html) (from 2.3) +* [Migrating to Meteor 2.3](2.3-migration.html) (from 2.2) +* [Migrating to Meteor 2.2](2.2-migration.html) (from 2.0) +* [Migrating to Meteor 2.0](2.0-migration.html) (from 1.12) +* [Migrating to Meteor 1.12](1.12-migration.html) (from 1.11) +* [Migrating to Meteor 1.11](1.11-migration.html) (from 1.10.2) +* [Migrating to Meteor 1.10.2](1.10.2-migration.html) (from 1.10) +* [Migrating to Meteor 1.10](1.10-migration.html) (from 1.9.3) +* [Migrating to Meteor 1.9.3](1.9.3-migration.html) (from 1.9) +* [Migrating to Meteor 1.9](1.9-migration.html) (from 1.8.3) +* [Migrating to Meteor 1.8.3](1.8.3-migration.html) (from 1.8.2) +* [Migrating to Meteor 1.8.2](1.8.2-migration.html) (from 1.8) +* [Migrating to Meteor 1.8](1.8-migration.html) (from 1.7) +* [Migrating to Meteor 1.7](1.7-migration.html) (from 1.6) +* [Migrating to Meteor 1.6](1.6-migration.html) (from 1.5) +* [Migrating to Meteor 1.5](1.5-migration.html) (from 1.4) +* [Migrating to Meteor 1.4](1.4-migration.html) (from 1.3) +* [Migrating to Meteor 1.3](1.3-migration.html) (from 1.2) diff --git a/guide/source/apollo.md b/guide/source/apollo.md index 5bdbfde4c8..3364cf3a03 100644 --- a/guide/source/apollo.md +++ b/guide/source/apollo.md @@ -73,18 +73,37 @@ meteor add apollo On server you import `getUser` function and include it into the context option when setting up Apollo server: ```javascript -import { ApolloServer } from 'apollo-server-express'; +import { ApolloServer } from '@apollo/server'; +import { WebApp } from 'meteor/webapp'; import { getUser } from 'meteor/apollo'; import typeDefs from '/imports/apollo/schema.graphql'; import { resolvers } from '/server/resolvers'; +import express from 'express'; +import { expressMiddleware } from '@apollo/server/express4'; +import { json } from 'body-parser' + +const context = async ({ req }) => ({ + user: await getUser(req.headers.authorization) +}) const server = new ApolloServer({ + cache: 'bounded', typeDefs, resolvers, - context: async ({ req }) => ({ - user: await getUser(req.headers.authorization) - }) }); + +export async function startApolloServer() { + await server.start(); + + WebApp.connectHandlers.use( + '/graphql', // Configure the path as you want. + express() // Create new Express router. + .disable('etag') // We don't server GET requests, so there's no need for that. + .disable('x-powered-by') // A small safety measure. + .use(json()) // From `body-parser`. + .use(expressMiddleware(server, { context })), // From `@apollo/server/express4`. + ) +} ``` This will make user data available (if user is logged in) as the option in the query: diff --git a/guide/source/collections.md b/guide/source/collections.md index f3aa7d0dad..c4b126787b 100644 --- a/guide/source/collections.md +++ b/guide/source/collections.md @@ -104,6 +104,8 @@ This example from the Todos app defines a schema with a few simple rules: 3. We specify the `incompleteCount` is a number, which on insertion is set to `0` if not otherwise specified. 4. We specify that the `userId`, which is optional, must be a string that looks like the ID of a user document. +We're using the SimpleSchema for Meteor related funcitonality, like IDs, but we encourage you to create custom regEx expressions for security reasons, for fields like `email` or `name`. Check out the [Simple Schema docs](https://github.com/longshotlabs/simpl-schema#regex) for more information. + We attach the schema to the namespace of `Lists` directly, which allows us to check objects against this schema directly whenever we want, such as in a form or [Method](methods.html). In the [next section](#schemas-on-write) we'll see how to use this schema automatically when writing to the collection. You can see that with relatively little code we've managed to restrict the format of a list significantly. You can read more about more complex things that can be done with schemas in the [Simple Schema docs](https://www.npmjs.com/package/simpl-schema). diff --git a/guide/source/flowbite.md b/guide/source/flowbite.md new file mode 100644 index 0000000000..b1568fd80f --- /dev/null +++ b/guide/source/flowbite.md @@ -0,0 +1,167 @@ +--- +title: Flowbite UI +description: Learn how to install Tailwind CSS with Flowbite for your Meteor.js project to build full-stack JavaScript or TypeScript web, mobile, and desktop applications +--- + +## Introduction + +[Flowbite](https://flowbite.com/) is an open-source library of UI components based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, templates, and more. + +It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, but also some more advanced interactive elements such as datepickers. + +Using both Meteor.js, Tailwind CSS and Flowbite can help you get started building modern UI web applications by leveraging the extensive framework features of Meteor.js, the utility-first approach of the Tailwind CSS framework and the open-source UI components from the Flowbite Library. + +## Requirements + +Make sure that you have [Node.js v14](https://nodejs.org/en/) installed on your computer to be able to install Meteor.js, Tailwind CSS and Flowbite using NPX and NPM. +For more information on how to install Meteor.js, check out the [official installation guide](https://docs.meteor.com/install.html#prereqs). + +## Create a new meteor project + +#### Create a new `meteor` starter project: + +The easiest way to create a new Meteor.js project is by first installed the CLI globally: + +```bash +npm install -g meteor +``` + +After you have `meteor` installed globally you can go ahead and create a new project: + +```sh +meteor create flowbite-app --tailwind +cd flowbite-app +``` + +This will create a new `meteor` project with `tailwindcss` support. + +No extra configuration needed as we added the `--tailwind` flag when setting up the project. + +Now that you have created a new Meteor.js project with Tailwind CSS configured automatically we can proceed with installing Flowbite and Flowbite React to start leveraging the open-source UI components. + +## Install Flowbite + +1. Install Flowbite and Flowbite React via NPM: + +```bash +npm install --save flowbite flowbite-react +``` + +2. Make sure that you set up the Flowbite plugin and template paths in your `tailwind.config.js` file: + +```js +module.exports = { + content: [ + './imports/ui/**/*.{js,jsx,ts,tsx}', + './client/*.html', + 'node_modules/flowbite-react/**/*.{js,jsx,ts,tsx}', + ], + theme: { + extend: {}, + }, + plugins: [require('flowbite/plugin')], +}; +``` + +3. Now that you have installed the packages you can start importing the UI components: + +```js +import { Alert } from 'flowbite-react'; + +export default function MyPage() { + return Alert!; +} +``` + +The code above will import the `` component that you can use to send feedback messages. + +## Flowbite UI components + +To get you started you can check out the full collection of React components from the [Flowbite React website](https://flowbite-react.com/) and browse the documentation for the source code of each component. + +Here's an example of how you can use the modal and button components by importing them from the Flowbite React package inside your Meteor.js project: + +```javascript +import { Button, Modal } from 'flowbite-react'; + +export default function DefaultModal() { + const [openModal, setOpenModal] = useState(); + const props = { openModal, setOpenModal }; + + return ( + <> + + props.setOpenModal(undefined)}> + Terms of Service + +
+

+ With less than a month to go before the European Union enacts new consumer privacy laws for its citizens, + companies around the world are updating their terms of service agreements to comply. +

+

+ The European Union’s General Data Protection Regulation (G.D.P.R.) goes into effect on May 25 and is meant to + ensure a common set of data rights in the European Union. It requires organizations to notify users as soon as + possible of high-risk data breaches that could personally affect them. +

+
+
+ + + + +
+ + ) +} +``` + +Here's another example of how you can use the dropdown component: + +```javascript +import { Dropdown } from 'flowbite-react'; + + + Dashboard + Settings + Earnings + Sign out +; +``` + +Finally, another example on how you can use the navbar component: + +```javascript +import { Navbar } from 'flowbite-react'; + + + + Flowbite Logo + + Flowbite + + + + + + Home + + About + Services + Pricing + Contact + +; +``` + +To learn more about Flowbite React make sure to check out to the [repository](https://github.com/themesberg/flowbite-react) and the [main website](https://flowbite-react.com/). + +## Meteor.js starter project + +The Flowbite community has created an open-source Meteor.js starter project that has Tailwind CSS and Flowbite React set up beforehand and you can go ahead and clone it by checking out the [repository on GitHub](https://github.com/meteor/flowbite-meteor-starter). diff --git a/guide/source/methods.md b/guide/source/methods.md index 0aa2bc07b8..a9689a2ef1 100644 --- a/guide/source/methods.md +++ b/guide/source/methods.md @@ -276,15 +276,19 @@ if (!this.isSimulation) { The main thing enabled by the `ValidationError` convention is integration between Methods and the forms that call them. In general, your app is likely to have a one-to-one mapping of forms in the UI to Methods. First, let's define a Method for our business logic: ```js +// Define a regular expression for email and amount validation. +const emailRegEx = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g; +const amountRegEx = /^\d*\.(\d\d)?$/; + // This Method encodes the form validation requirements. // By defining them in the Method, we do client and server-side // validation in one place. export const insert = new ValidatedMethod({ name: 'Invoices.methods.insert', validate: new SimpleSchema({ - email: { type: String, regEx: SimpleSchema.RegEx.Email }, + email: { type: String, regEx: emailRegEx }, description: { type: String, min: 5 }, - amount: { type: String, regEx: /^\d*\.(\d\d)?$/ } + amount: { type: String, regEx: amountRegEx } }).validator(), run(newInvoice) { // In here, we can be sure that the newInvoice argument is @@ -300,6 +304,8 @@ export const insert = new ValidatedMethod({ }); ``` +We encourage you to create custom regEx expressions for security reasons, for fields like `email` and `amout`. For Meteor related functionality, like `IDs`, you can use the `SimpleSchema.RegEx.Id` expression. Check out the [Simple Schema docs](https://github.com/longshotlabs/simpl-schema#regex) for more information. + Let's define an HTML form: ```html diff --git a/guide/source/structure.md b/guide/source/structure.md index cbadb202c6..2dd23c34c3 100644 --- a/guide/source/structure.md +++ b/guide/source/structure.md @@ -316,7 +316,7 @@ The primary challenge is properly sharing code between the different application If you want to create Meteor applications with separate code, you'll have some modules that you'd like to share between them. If those modules are something the wider world could use, you should consider [publishing them to a package system](writing-packages.html), either npm or Atmosphere, depending on whether the code is Meteor-specific or otherwise. -If the code is private, or of no interest to others, it typically makes sense to include the same module in both applications (you *can* do this with [private npm modules](https://www.npmjs.com/private-modules)). There are several ways to do this: +If the code is private, or of no interest to others, it typically makes sense to include the same module in both applications (you *can* do this with [private npm modules](https://docs.npmjs.com/about-private-packages)). There are several ways to do this: - a straightforward approach is to include the common code as a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) of both applications. diff --git a/npm-packages/meteor-installer/README.md b/npm-packages/meteor-installer/README.md index e3c5bb6110..a83364d492 100644 --- a/npm-packages/meteor-installer/README.md +++ b/npm-packages/meteor-installer/README.md @@ -14,6 +14,7 @@ npm install -g meteor | NPM Package | Meteor Official Release | |-------------|-------------------------| +| 2.13.0 | 2.13.0 | | 2.12.1 | 2.12.0 | | 2.12.0 | 2.12.0 | | 2.11.0 | 2.11.0 | diff --git a/npm-packages/meteor-installer/config.js b/npm-packages/meteor-installer/config.js index 71e5ff0082..d1306a11ef 100644 --- a/npm-packages/meteor-installer/config.js +++ b/npm-packages/meteor-installer/config.js @@ -1,7 +1,7 @@ const os = require('os'); const path = require('path'); -const METEOR_LATEST_VERSION = '2.12'; +const METEOR_LATEST_VERSION = '2.13'; const sudoUser = process.env.SUDO_USER || ''; function isRoot() { return process.getuid && process.getuid() === 0; diff --git a/npm-packages/meteor-installer/package.json b/npm-packages/meteor-installer/package.json index 3fd7d4a177..f3e5669f1b 100644 --- a/npm-packages/meteor-installer/package.json +++ b/npm-packages/meteor-installer/package.json @@ -1,6 +1,6 @@ { "name": "meteor", - "version": "2.12.1", + "version": "2.13.0", "description": "Install Meteor", "main": "install.js", "scripts": { diff --git a/packages/ddp-rate-limiter/ddp-rate-limiter.js b/packages/ddp-rate-limiter/ddp-rate-limiter.js index c1cb53883e..15922cbe94 100644 --- a/packages/ddp-rate-limiter/ddp-rate-limiter.js +++ b/packages/ddp-rate-limiter/ddp-rate-limiter.js @@ -74,7 +74,7 @@ DDPRateLimiter.setErrorMessageOnRule = (ruleId, message) => { * - `connectionId`: A string representing the user's DDP connection * - `clientAddress`: The IP address of the user * - * Returns unique `ruleId` that can be passed to `removeRule`. + * Returns unique `ruleId` that can be passed to `removeRule` and `setErrorMessageOnRule` * * @param {Object} matcher * Matchers specify which events are counted towards a rate limit. A matcher diff --git a/packages/ddp-server/livedata_server_async_tests.js b/packages/ddp-server/livedata_server_async_tests.js index 495c9c88a5..cca7f92845 100644 --- a/packages/ddp-server/livedata_server_async_tests.js +++ b/packages/ddp-server/livedata_server_async_tests.js @@ -101,7 +101,7 @@ Meteor.publish({ async publicationObjectAsync() { await sleep(50); let callback = onSubscriptions; - if (callback) callback(); + if (callback) callback("publicationObjectAsync"); this.stop(); }, }); @@ -110,7 +110,7 @@ Meteor.publish({ publication_object_async: async function() { await sleep(50); let callback = onSubscriptions; - if (callback) callback(); + if (callback) callback("publication_object_async"); this.stop(); }, }); @@ -118,7 +118,7 @@ Meteor.publish({ Meteor.publish('publication_compatibility_async', async function() { await sleep(50); let callback = onSubscriptions; - if (callback) callback(); + if (callback) callback("publication_compatibility_async"); this.stop(); }); @@ -130,10 +130,12 @@ Tinytest.addAsync('livedata server - async publish object', function( let testsLength = 0; onSubscriptions = function(subscription) { - delete onSubscriptions; - clientConn.disconnect(); + // for debugging + // console.log('subscription is ok:', subscription) testsLength++; - if (testsLength == 3) { + delete onSubscriptions; + if (testsLength === 3) { + clientConn.disconnect(); onComplete(); } }; diff --git a/packages/meteor/meteor.d.ts b/packages/meteor/meteor.d.ts index f47722eb15..8ebc07618b 100644 --- a/packages/meteor/meteor.d.ts +++ b/packages/meteor/meteor.d.ts @@ -159,6 +159,41 @@ export namespace Meteor { */ function callAsync(name: string, ...args: any[]): Promise; + interface MethodApplyOptions { + /** + * (Client only) If true, don't send this method until all previous method calls have completed, and don't send any subsequent method calls until this one is completed. + */ + wait?: boolean | undefined; + /** + * (Client only) This callback is invoked with the error or result of the method (just like `asyncCallback`) as soon as the error or result is available. The local cache may not yet reflect the writes performed by the method. + */ + onResultReceived?: + | (( + error: global_Error | Meteor.Error | undefined, + result?: Result + ) => void) + | undefined; + /** + * (Client only) if true, don't send this method again on reload, simply call the callback an error with the error code 'invocation-failed'. + */ + noRetry?: boolean | undefined; + /** + * (Client only) If true then in cases where we would have otherwise discarded the stub's return value and returned undefined, instead we go ahead and return it. Specifically, this is any time other than when (a) we are already inside a stub or (b) we are in Node and no callback was provided. Currently we require this flag to be explicitly passed to reduce the likelihood that stub return values will be confused with server return values; we may improve this in future. + */ + returnStubValue?: boolean | undefined; + /** + * (Client only) If true, exceptions thrown by method stubs will be thrown instead of logged, and the method will not be invoked on the server. + */ + throwStubExceptions?: boolean | undefined; + } + + /** + * Invokes a method with a sync stub, passing any number of arguments. + * @param name Name of method to invoke + * @param args Method arguments + * @param options Optional execution options + * @param asyncCallback Optional callback + */ function apply< Result extends | EJSONable @@ -168,26 +203,35 @@ export namespace Meteor { >( name: string, args: ReadonlyArray, - options?: { - wait?: boolean | undefined; - onResultReceived?: - | (( - error: global_Error | Meteor.Error | undefined, - result?: Result - ) => void) - | undefined; - /** - * (Client only) if true, don't send this method again on reload, simply call the callback an error with the error code 'invocation-failed'. - */ - noRetry?: boolean | undefined; - returnStubValue?: boolean | undefined; - throwStubExceptions?: boolean | undefined; - }, + options?: MethodApplyOptions, asyncCallback?: ( error: global_Error | Meteor.Error | undefined, result?: Result ) => void ): any; + + /** + * Invokes a method with an async stub, passing any number of arguments. + * @param name Name of method to invoke + * @param args Method arguments + * @param options Optional execution options + * @param asyncCallback Optional callback + */ + function applyAsync< + Result extends + | EJSONable + | EJSONable[] + | EJSONableProperty + | EJSONableProperty[] + >( + name: string, + args: ReadonlyArray, + options?: MethodApplyOptions, + asyncCallback?: ( + error: global_Error | Meteor.Error | undefined, + result?: Result + ) => void + ): Promise; /** Method **/ /** Url **/ diff --git a/packages/minimongo/cursor.js b/packages/minimongo/cursor.js index c8cb2f9b7a..eedb89988d 100644 --- a/packages/minimongo/cursor.js +++ b/packages/minimongo/cursor.js @@ -538,7 +538,6 @@ ASYNC_CURSOR_METHODS.forEach(method => { const asyncName = getAsyncMethodName(method); Cursor.prototype[asyncName] = function(...args) { try { - this[method].isCalledFromAsync = true; return Promise.resolve(this[method].apply(this, args)); } catch (error) { return Promise.reject(error); diff --git a/packages/mongo/collection.js b/packages/mongo/collection.js index 8b563c6475..73d8590563 100644 --- a/packages/mongo/collection.js +++ b/packages/mongo/collection.js @@ -6,24 +6,7 @@ import { } from "meteor/minimongo/constants"; import { normalizeProjection } from "./mongo_utils"; -export function warnUsingOldApi ( - methodName, - collectionName, - isCalledFromAsync - ){ - if ( - process.env.WARN_WHEN_USING_OLD_API && // also ensures it is on the server - !isCalledFromAsync // must be true otherwise we should log - ) { - if (collectionName === undefined || collectionName.includes('oplog')) return - console.warn(` - - Calling method ${collectionName}.${methodName} from old API on server. - This method will be removed, from the server, in version 3. - Trace is below:`) - console.trace() - }; -} + /** * @summary Namespace for MongoDB-related items * @namespace @@ -671,14 +654,6 @@ Object.assign(Mongo.Collection.prototype, { throw new Error('insert requires an argument'); } - // [FIBERS] - // TODO: Remove this when 3.0 is released. - warnUsingOldApi( - "insert", - this._name, - this.insert.isCalledFromAsync - ); - this.insert.isCalledFromAsync = false; // Make a shallow clone of the document, preserving its prototype. doc = Object.create( @@ -962,15 +937,6 @@ Object.assign(Mongo.Collection.prototype, { } } - // [FIBERS] - // TODO: Remove this when 3.0 is released. - warnUsingOldApi( - "update", - this._name, - this.update.isCalledFromAsync - ); - this.update.isCalledFromAsync = false; - selector = Mongo.Collection._rewriteSelector(selector, { fallbackId: insertedId, }); @@ -1043,14 +1009,7 @@ Object.assign(Mongo.Collection.prototype, { return this._callMutatorMethod('remove', [selector]); } - // [FIBERS] - // TODO: Remove this when 3.0 is released. - warnUsingOldApi( - "remove", - this._name, - this.remove.isCalledFromAsync - ); - this.remove.isCalledFromAsync = false; + // it's my collection. descend into the collection1 object // and propagate any exception. return this._collection.remove(selector); @@ -1153,14 +1112,7 @@ Object.assign(Mongo.Collection.prototype, { var self = this; if (!self._collection.createIndexAsync) throw new Error('Can only call createIndexAsync on server collections'); - // [FIBERS] - // TODO: Remove this when 3.0 is released. - warnUsingOldApi( - "createIndex", - self._name, - self.createIndex.isCalledFromAsync - ); - self.createIndex.isCalledFromAsync = false; + try { await self._collection.createIndexAsync(index, options); } catch (e) { @@ -1292,7 +1244,7 @@ Mongo.Collection.ObjectID = Mongo.ObjectID; Meteor.Collection = Mongo.Collection; // Allow deny stuff is now in the allow-deny package -Object.assign(Meteor.Collection.prototype, AllowDeny.CollectionPrototype); +Object.assign(Mongo.Collection.prototype, AllowDeny.CollectionPrototype); function popCallbackFromArgs(args) { // Pull off any callback (or perhaps a 'callback' variable that was passed diff --git a/packages/mongo/collection_tests.js b/packages/mongo/collection_tests.js index e298789151..b8084aa783 100644 --- a/packages/mongo/collection_tests.js +++ b/packages/mongo/collection_tests.js @@ -471,6 +471,7 @@ Meteor.isServer && Tinytest.addAsync('collection - simple add', async function(t var collection = new Mongo.Collection(collectionName); var id = await collection.insertAsync({a: 1}); test.equal((await collection.findOneAsync(id)).a, 1); + await collection.upsertAsync(id, {$set: {a: 2}}); id = await collection.insertAsync({a: 2}); test.equal((await collection.findOneAsync(id)).a, 2); await collection.removeAsync({}); diff --git a/packages/mongo/mongo.d.ts b/packages/mongo/mongo.d.ts index ab1697aac0..72199e0267 100644 --- a/packages/mongo/mongo.d.ts +++ b/packages/mongo/mongo.d.ts @@ -30,8 +30,13 @@ export namespace Mongo { skip?: number | undefined; /** Maximum number of results to return */ limit?: number | undefined; - /** Dictionary of fields to return or exclude. */ + /** + * Dictionary of fields to return or exclude. + * @deprecated use projection instead + */ fields?: FieldSpecifier | undefined; + /** Dictionary of fields to return or exclude. */ + projection?: FieldSpecifier | undefined; /** (Server only) Overrides MongoDB's default index selection and query optimization process. Specify an index to force its use, either by its name or index specification. */ hint?: NpmModuleMongodb.Hint | undefined; /** (Client only) Default `true`; pass `false` to disable reactivity */ @@ -176,12 +181,12 @@ export namespace Mongo { * @param selector The query for filtering the set of documents to count * @param options All options are listed in [MongoDB documentation](https://mongodb.github.io/node-mongodb-native/4.11/interfaces/CountDocumentsOptions.html). Please note that not all of them are available on the client. */ - countDocuments(selector?: Selector | ObjectID | string, options?: MongoNpmModule.CountDocumentsOptions): Promise; + countDocuments(selector?: Selector | ObjectID | string, options?: NpmModuleMongodb.CountDocumentsOptions): Promise; /** * Gets an estimate of the count of documents in a collection using collection metadata. For an exact count of the documents in a collection see `countDocuments`. * @param options All options are listed in [MongoDB documentation](https://mongodb.github.io/node-mongodb-native/4.11/interfaces/CountDocumentsOptions.html). Please note that not all of them are available on the client. */ - estimatedDocumentCount(options?: MongoNpmModule.EstimatedDocumentCountOptions): Promise; + estimatedDocumentCount(options?: NpmModuleMongodb.EstimatedDocumentCountOptions): Promise; /** * Insert a document in the collection. Returns its unique _id. * @param doc The document to insert. May not yet have an _id attribute, in which case Meteor will generate one for you. diff --git a/packages/mongo/mongo_driver.js b/packages/mongo/mongo_driver.js index 4cdd17f6cd..0c2e021036 100644 --- a/packages/mongo/mongo_driver.js +++ b/packages/mongo/mongo_driver.js @@ -212,6 +212,7 @@ MongoConnection = function (url, options) { self._oplogHandle = new OplogHandle(options.oplogUrl, self.db.databaseName); self._docFetcher = new DocFetcher(self); } + }; MongoConnection.prototype._close = async function() { @@ -886,7 +887,6 @@ Cursor.prototype.countAsync = async function () { const methodNameAsync = getAsyncMethodName(methodName); Cursor.prototype[methodNameAsync] = function (...args) { try { - this[methodName].isCalledFromAsync = true; return Promise.resolve(this[methodName](...args)); } catch (error) { return Promise.reject(error); diff --git a/packages/mongo/oplog_tailing.js b/packages/mongo/oplog_tailing.js index cb7f74d466..5f61d06681 100644 --- a/packages/mongo/oplog_tailing.js +++ b/packages/mongo/oplog_tailing.js @@ -140,8 +140,10 @@ Object.assign(OplogHandle.prototype, { // find a TS that won't show up in the actual tail stream. try { lastEntry = await self._oplogLastEntryConnection.findOneAsync( - OPLOG_COLLECTION, self._baseOplogSelector, - {fields: {ts: 1}, sort: {$natural: -1}}); + OPLOG_COLLECTION, + self._baseOplogSelector, + { projection: { ts: 1 }, sort: { $natural: -1 } } + ); break; } catch (e) { // During failover (eg) if we get an exception we should log and retry @@ -232,7 +234,7 @@ Object.assign(OplogHandle.prototype, { else resolve(result); }); }); - + if (!(isMasterDoc && isMasterDoc.setName)) { throw Error("$MONGO_OPLOG_URL must be set to the 'local' database of " + "a Mongo replica set"); @@ -240,7 +242,10 @@ Object.assign(OplogHandle.prototype, { // Find the last oplog entry. var lastOplogEntry = await self._oplogLastEntryConnection.findOneAsync( - OPLOG_COLLECTION, {}, {sort: {$natural: -1}, fields: {ts: 1}}); + OPLOG_COLLECTION, + {}, + { sort: { $natural: -1 }, projection: { ts: 1 } } + ); var oplogSelector = Object.assign({}, self._baseOplogSelector); if (lastOplogEntry) { @@ -320,6 +325,9 @@ Object.assign(OplogHandle.prototype, { trigger.collection = doc.o.drop; trigger.dropCollection = true; trigger.id = null; + } else if ("create" in doc.o && "idIndex" in doc.o) { + // A collection got implicitly created within a transaction. There's + // no need to do anything about it. } else { throw Error("Unknown command " + EJSON.stringify(doc)); } diff --git a/packages/test-in-console/driver.js b/packages/test-in-console/driver.js index 7b8711ad75..95904e20c5 100644 --- a/packages/test-in-console/driver.js +++ b/packages/test-in-console/driver.js @@ -1,7 +1,7 @@ // Global flag for phantomjs (or other browser) to eval to see if we're done. DONE = false; // Failure count for phantomjs exit code -FAILURES = null; +FAILURES = 0; // Where are the failures WHERE_FAILED = []; // Passed count for phantomjs exit code @@ -9,7 +9,7 @@ PASSED = null; TEST_STATUS = { DONE: false, - FAILURES: null, + FAILURES: 0, PASSED: null, WHERE_FAILED: [] }; @@ -149,6 +149,7 @@ runTests = function () { else log("Test failed with exception"); failed++; + whereFailed.push({ name: name, info: JSON.stringify(event) }); break; case "finish": switch (resultSet[name].status) { diff --git a/packages/test-in-console/puppeteerRunner.js b/packages/test-in-console/puppeteerRunner.js index bf771ac50d..f4735106c1 100644 --- a/packages/test-in-console/puppeteerRunner.js +++ b/packages/test-in-console/puppeteerRunner.js @@ -89,11 +89,7 @@ async function getFailCount(page) { return TEST_STATUS.FAILURES; } - if (typeof FAILURES === 'undefined') { - return 1; - } - - return 0; + return typeof FAILURES !== 'undefined' && FAILURES; }); } diff --git a/packages/twitter-oauth/twitter_server.js b/packages/twitter-oauth/twitter_server.js index 090d455172..a570769997 100644 --- a/packages/twitter-oauth/twitter_server.js +++ b/packages/twitter-oauth/twitter_server.js @@ -13,7 +13,7 @@ var urls = { }; // https://dev.twitter.com/docs/api/1.1/get/account/verify_credentials -Twitter.whitelistedFields = ['profile_image_url', 'profile_image_url_https', 'lang', 'email']; +Twitter.whitelistedFields = ['profile_image_url', 'profile_image_url_https', 'lang', 'email',"name"]; OAuth.registerService('twitter', 1, urls, async function(oauthBinding) { const response = await oauthBinding.getAsync('https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true'); @@ -26,7 +26,7 @@ OAuth.registerService('twitter', 1, urls, async function(oauthBinding) { }; // include helpful fields from twitter - const { identity: fields } = Twitter.whitelistedFields; + const fields = Twitter.whitelistedFields.reduce((o, k) => { if ( identity[k]) o[k] = identity[k]; return o}, {}); Object.assign(serviceData, fields); return { diff --git a/scripts/admin/meteor-release-official.json b/scripts/admin/meteor-release-official.json index dc54967094..65c2ce96a4 100644 --- a/scripts/admin/meteor-release-official.json +++ b/scripts/admin/meteor-release-official.json @@ -1,6 +1,6 @@ { "track": "METEOR", - "version": "2.12", + "version": "2.13", "recommended": false, "official": true, "description": "The Official Meteor Distribution" diff --git a/scripts/build-node-for-dev-bundle.sh b/scripts/build-node-for-dev-bundle.sh index b0644914dc..766715e02a 100755 --- a/scripts/build-node-for-dev-bundle.sh +++ b/scripts/build-node-for-dev-bundle.sh @@ -18,7 +18,7 @@ then NODE_URL="https://github.com/meteor/node/archive/${NODE_COMMIT_HASH}.tar.gz" else echo "Building Node source from ${NODE_VERSION} src tarball..."; - NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}.tar.gz" + NODE_URL="https://static.meteor.com/dev-bundle-node-os/v${NODE_VERSION}/node-v${NODE_VERSION}.tar.gz" fi else NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TGZ}" diff --git a/tools/cli/commands.js b/tools/cli/commands.js index 9bdaaf6994..7bf3068b31 100644 --- a/tools/cli/commands.js +++ b/tools/cli/commands.js @@ -23,6 +23,47 @@ var projectContextModule = require('../project-context.js'); var release = require('../packaging/release.js'); const { Profile } = require("../tool-env/profile"); +const { exec } = require("child_process"); +/** + * Run a command in the shell. + * @param command + * @return {Promise} + */ +const runCommand = async (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.log(red`error: ${ error.message }`); + reject(error); + return; + } + if (stderr) { + console.log(red`stderr: ${ stderr }`); + reject(stderr); + return; + } + resolve(stdout); + }); + }) +} +/** + * + * @param {Promise<() => T>} fn + * @returns {Promise<[T, null]> | Promise<[null, Error]>} + */ +const tryRun = async (fn) => { + try { return [await fn(), null] } catch (e) { return [null, e] } +} + +/** + * + * @param {string} bash command + * @param {[string, null] | [null, Error]}} Result or Error + * @returns + */ +const bash = + (text, ...values) => + tryRun(() => runCommand(String.raw({ raw: text }, ...values))); import { ensureDevBundleDependencies } from '../cordova/index.js'; import { CordovaRunner } from '../cordova/runner.js'; @@ -513,6 +554,31 @@ main.registerCommand({ /////////////////////////////////////////////////////////////////////////////// // create /////////////////////////////////////////////////////////////////////////////// + +/** + * list of all the available skeletons similar to the property below + * { + * clock: { repo: 'https://github.com/meteor/clock' }, + * leaderboard: { repo: 'https://github.com/meteor/leaderboard' }, + * } + * @typedef {Object.} Skeletons + */ +/** + * Resolves into json with + * @returns {Promise<[Skeletons, null]> | Promise<[null, Error]>} + */ +function getExamplesJSON(){ + return tryRun(async () => { + const response = await httpHelpers.request({ + url: "https://cdn.meteor.com/static/meteor.json", + method: "GET", + useSessionHeader: true, + useAuthHeader: true, + }); + return JSON.parse(response.body); + }); +} + const DEFAULT_SKELETON = "react"; export const AVAILABLE_SKELETONS = [ "apollo", @@ -550,7 +616,8 @@ main.registerCommand({ tailwind: { type: Boolean }, 'chakra-ui': { type: Boolean }, solid: { type: Boolean }, - prototype: { type: Boolean } + prototype: { type: Boolean }, + from: { type: String }, }, catalogRefresh: new catalog.Refresh.Never() }, async function (options) { @@ -561,10 +628,12 @@ main.registerCommand({ var packageName = options.args[0]; if (options.prototype) { Console.error( - `The ${Console.command('--prototype')} option is no longer supported for packages.` + `The ${Console.command( + "--prototype" + )} option is no longer supported for packages.` ); Console.error(); - throw new main.ShowUsage; + throw new main.ShowUsage(); } if (options.list || options.example) { Console.error("No package examples exist at this time."); @@ -577,8 +646,9 @@ main.registerCommand({ throw new main.ShowUsage(); } - utils.validatePackageNameOrExit( - packageName, {detailedColonExplanation: true}); + utils.validatePackageNameOrExit(packageName, { + detailedColonExplanation: true, + }); // When we create a package, avoid introducing a colon into the file system // by naming the directory after the package name without the prefix. @@ -593,8 +663,9 @@ main.registerCommand({ // with at least two colons. Therefore we will at least try to // discourage people from putting a ton of colons in their package names // here. - Console.error(packageName + - ": Package names may not have more than one colon."); + Console.error( + packageName + ": Package names may not have more than one colon." + ); return 1; } @@ -603,7 +674,7 @@ main.registerCommand({ var packageDir; if (options.appDir) { - packageDir = files.pathResolve(options.appDir, 'packages', fsName); + packageDir = files.pathResolve(options.appDir, "packages", fsName); } else { packageDir = files.pathResolve(fsName); } @@ -616,8 +687,7 @@ main.registerCommand({ } var transform = async function (x) { - var xn = - x.replace(/~name~/g, packageName).replace(/~fs-name~/g, fsName); + var xn = x.replace(/~name~/g, packageName).replace(/~fs-name~/g, fsName); // If we are running from checkout, comment out the line sourcing packages // from a release, with the latest release filled in (in case they do want @@ -631,7 +701,7 @@ main.registerCommand({ relString = rel ? rel.version : "no-release"; } else { xn = xn.replace(/~cc~/g, ""); - relString = release.current.getDisplayName({noPrefix: true}); + relString = release.current.getDisplayName({ noPrefix: true }); } // If we are not in checkout, write the current release here. @@ -639,35 +709,37 @@ main.registerCommand({ }; try { - await files.cp_r(files.pathJoin(__dirnameConverted, '..', 'static-assets', 'skel-pack'), packageDir, { - transformFilename: function (f) { - return transform(f); - }, - transformContents: async function (contents, f) { - if ((/(\.html|\.[jt]sx?|\.css)/).test(f)) { - return Buffer.from(await transform(contents.toString())); - } else { - return contents; - } - }, - ignore: [/^local$/], - preserveSymlinks: true, - }); + await files.cp_r( + files.pathJoin(__dirnameConverted, "..", "static-assets", "skel-pack"), + packageDir, + { + transformFilename: function (f) { + return transform(f); + }, + transformContents: async function (contents, f) { + if (/(\.html|\.[jt]sx?|\.css)/.test(f)) { + return Buffer.from(await transform(contents.toString())); + } else { + return contents; + } + }, + ignore: [/^local$/], + preserveSymlinks: true, + } + ); } catch (err) { Console.error("Could not create package: " + err.message); return 1; } - var displayPackageDir = - files.convertToOSPath(files.pathRelative(files.cwd(), packageDir)); + var displayPackageDir = files.convertToOSPath( + files.pathRelative(files.cwd(), packageDir) + ); // Since the directory can't have colons, the directory name will often not // match the name of the package exactly, therefore we should tell people // where it was created. - Console.info( - packageName + ": created in", - Console.path(displayPackageDir) - ); + Console.info(packageName + ": created in", Console.path(displayPackageDir)); return 0; } @@ -682,47 +754,33 @@ main.registerCommand({ // (In particular, it's not sufficient to create the new app with // this version of the tools, and then stamp on the correct release // at the end.) - if (! release.current.isCheckout() && !release.forced) { - if (release.current.name !== await release.latestKnown()) { + if (!release.current.isCheckout() && !release.forced) { + if (release.current.name !== (await release.latestKnown())) { throw new main.SpringboardToLatestRelease(); } } if (options.list) { Console.info("Available examples:"); - _.each(EXAMPLE_REPOSITORIES, function (repoInfo, name) { - const branchInfo = repoInfo.branch ? `/tree/${repoInfo.branch}` : ''; + const [json, err] = await getExamplesJSON() + if (err) { + Console.error("Failed to fetch examples:", err.message); + Console.info("Using cached examples.json"); + } + const examples = err ? EXAMPLE_REPOSITORIES : json; + _.each(examples, function (repoInfo, name) { + const branchInfo = repoInfo.branch ? `/tree/${repoInfo.branch}` : ""; Console.info( Console.command(`${name}: ${repoInfo.repo}${branchInfo}`), - Console.options({ indent: 2 })); + Console.options({ indent: 2 }) + ); }); Console.info(); - Console.info("To create an example, simply", Console.command("git clone"), - "the relevant repository and branch (run", - Console.command("'meteor create --example '"), - " to see the full command)."); - return 0; - }; - - if (options.example) { - const repoInfo = EXAMPLE_REPOSITORIES[options.example]; - if (!repoInfo) { - Console.error(`${options.example}: no such example.`); - Console.error( - "List available applications with", - Console.command("'meteor create --list'") + "."); - return 1; - } - - const branchOption = repoInfo.branch ? ` -b ${repoInfo.branch}` : ''; - const path = options.args.length === 1 ? ` ${options.args[0]}` : ''; - - Console.info(`To create the ${options.example} example, please run:`); Console.info( - Console.command(`git clone ${repoInfo.repo}${branchOption}${path}`), - Console.options({ indent: 2 })); - + "To create an example, simply", + Console.command("'meteor create --example '") + ); return 0; } @@ -736,7 +794,8 @@ main.registerCommand({ if (files.findAppDir(appPath)) { Console.error( - "You can't create a Meteor project inside another Meteor project."); + "You can't create a Meteor project inside another Meteor project." + ); return 1; } @@ -748,48 +807,204 @@ main.registerCommand({ appName = files.pathBasename(appPath); } - var transform = function (x) { return x.replace(/~name~/g, appName); }; // These file extensions are usually metadata, not app code - var nonCodeFileExts = ['.txt', '.md', '.json', '.sh']; + var nonCodeFileExts = [".txt", ".md", ".json", ".sh"]; var destinationHasCodeFiles = false; // If the directory doesn't exist, it clearly doesn't have any source code // inside itself if (files.exists(appPath)) { - destinationHasCodeFiles = _.any(files.readdir(appPath), - function thisPathCountsAsAFile(filePath) { - // We don't mind if there are hidden files or directories (this includes - // .git) and we don't need to check for .meteor here because the command - // will fail earlier - var isHidden = /^\./.test(filePath); - if (isHidden) { - // Not code - return false; - } + destinationHasCodeFiles = _.any( + files.readdir(appPath), + function thisPathCountsAsAFile(filePath) { + // We don't mind if there are hidden files or directories (this includes + // .git) and we don't need to check for .meteor here because the command + // will fail earlier + var isHidden = /^\./.test(filePath); + if (isHidden) { + // Not code + return false; + } - // We do mind if there are non-hidden directories, because we don't want - // to recursively check everything to do some crazy heuristic to see if - // we should try to create an app. - var stats = files.stat(files.pathJoin(appPath, filePath)); - if (stats.isDirectory()) { - // Could contain code + // We do mind if there are non-hidden directories, because we don't want + // to recursively check everything to do some crazy heuristic to see if + // we should try to create an app. + var stats = files.stat(files.pathJoin(appPath, filePath)); + if (stats.isDirectory()) { + // Could contain code + return true; + } + + // Check against our file extension white list + var ext = files.pathExtname(filePath); + if (ext == "" || nonCodeFileExts.includes(ext)) { + return false; + } + + // Everything not matched above is considered to be possible source code return true; } - - // Check against our file extension white list - var ext = files.pathExtname(filePath); - if (ext == '' || nonCodeFileExts.includes(ext)) { - return false; - } - - // Everything not matched above is considered to be possible source code - return true; + ); + } + function cmd(text) { + Console.info( + Console.command(text), + Console.options({ + indent: 2, + }) + ); + } + // Setup fn, which is called after the app is created, to print a message + // about how to run the app. + async function setup() { + // We are actually working with a new meteor project at this point, so + // set up its context. + var projectContext = new projectContextModule.ProjectContext({ + projectDir: appPath, + // Write .meteor/versions even if --release is specified. + alwaysWritePackageMap: true, + // examples come with a .meteor/versions file, but we shouldn't take it + // too seriously + allowIncompatibleUpdate: true, }); + await main.captureAndExit( + "=> Errors while creating your project", + async function () { + await projectContext.readProjectMetadata(); + if (buildmessage.jobHasMessages()) { + return; + } + + await projectContext.releaseFile.write( + release.current.isCheckout() ? "none" : release.current.name + ); + if (buildmessage.jobHasMessages()) { + return; + } + + // Also, write package version constraints from the current release + // If we are on a checkout, we don't need to do this as running from + // checkout still pins all package versions and if the user updates + // to a real release, the packages file will subsequently get updated + if (!release.current.isCheckout()) { + projectContext.projectConstraintsFile.updateReleaseConstraints( + release.current._manifest + ); + } + + // Any upgrader that is in this version of Meteor doesn't need to be run on + // this project. + var upgraders = require("../upgraders.js"); + projectContext.finishedUpgraders.appendUpgraders( + upgraders.allUpgraders() + ); + + await projectContext.prepareProjectForBuild(); + } + ); + // No need to display the PackageMapDelta here, since it would include all of + // the packages (or maybe an unpredictable subset based on what happens to be + // in the template's versions file). + + // Since some of the project skeletons include npm `devDependencies`, we need + // to make sure they're included when running `npm install`. + await require("./default-npm-deps.js").install(appPath, { + includeDevDependencies: true, + }); + + var appNameToDisplay = + appPathAsEntered === "." ? "current directory" : `'${appPathAsEntered}'`; + + var message = `Created a new Meteor app in ${appNameToDisplay}`; + + message += "."; + + Console.info(message + "\n"); + + // Print a nice message telling people we created their new app, and what to + // do next. + Console.info("To run your new app:"); + + + + if (appPathAsEntered !== ".") { + // Wrap the app path in quotes if it contains spaces + const appPathWithQuotesIfSpaces = + appPathAsEntered.indexOf(" ") === -1 + ? appPathAsEntered + : `'${appPathAsEntered}'`; + + // Don't tell people to 'cd .' + cmd("cd " + appPathWithQuotesIfSpaces); + } + + cmd("meteor"); + + Console.info(""); + Console.info( + "If you are new to Meteor, try some of the learning resources here:" + ); + Console.info( + Console.url("https://www.meteor.com/tutorials"), + Console.options({ indent: 2 }) + ); + + Console.info(""); + Console.info( + "When you’re ready to deploy and host your new Meteor application, check out Cloud:" + ); + Console.info( + Console.url("https://www.meteor.com/cloud"), + Console.options({ indent: 2 }) + ); + + } + + /** + * + * @param {string} url + */ + const setupExampleByURL = async (url) => { + const [ok, err] = await bash`git -v`; + if (err) throw new Error("git is not installed"); + await bash`git clone --progress ${url} ${appPath} `; + // remove .git folder from the example + await files.rm_recursive_async(files.pathJoin(appPath, ".git")); + await setup(); + }; + + if (options.example) { + const [json, err] = await getExamplesJSON(); + + if (err) { + Console.error("Failed to fetch examples:", err.message); + Console.info("Using cached examples.json"); + } + + const examples = err ? EXAMPLE_REPOSITORIES : json; + const repoInfo = examples[options.example]; + if (!repoInfo) { + Console.error(`${options.example}: no such example.`); + Console.error( + "List available applications with", + Console.command("'meteor create --list'") + "." + ); + return 1; + } + // repoInfo.repo is the URL of the repo, and repoInfo.branch is the branch + await setupExampleByURL(repoInfo.repo); + return 0; + } + + + if (options.from) { + await setupExampleByURL(options.from); + return 0; } var toIgnore = [/^local$/, /^\.id$/]; @@ -799,153 +1014,97 @@ main.registerCommand({ toIgnore.push(/(\.html|\.js|\.css)/); } - const skeletonExplicitOption = AVAILABLE_SKELETONS.find(skeleton => - !!options[skeleton]); - const skeleton = skeletonExplicitOption || DEFAULT_SKELETON; - await files.cp_r(files.pathJoin(__dirnameConverted, '..', 'static-assets', - `skel-${skeleton}`), appPath, { - transformFilename: function (f) { - return transform(f); - }, - transformContents: function (contents, f) { - - // check if this app is just for prototyping if it is then we need to add autopublish and insecure in the packages file - if ((/packages/).test(f)) { - - const prototypePackages = - () => - 'autopublish # Publish all data to the clients (for prototyping)\n' + - 'insecure # Allow all DB writes from clients (for prototyping)'; - - // XXX: if there is the need to add more options maybe we should have a better abstraction for this if-else - if (options.prototype) { - return Buffer.from(contents.toString().replace(/~prototype~/g, prototypePackages())) - } else { - return Buffer.from(contents.toString().replace(/~prototype~/g, '')) - } - } - if ((/(\.html|\.[jt]sx?|\.css)/).test(f)) { - return Buffer.from(transform(contents.toString())); - } else { - return contents; - } - }, - ignore: toIgnore, - preserveSymlinks: true, - }); - - // We are actually working with a new meteor project at this point, so - // set up its context. - var projectContext = new projectContextModule.ProjectContext({ - projectDir: appPath, - // Write .meteor/versions even if --release is specified. - alwaysWritePackageMap: true, - // examples come with a .meteor/versions file, but we shouldn't take it - // too seriously - allowIncompatibleUpdate: true - }); - - await main.captureAndExit("=> Errors while creating your project", async function () { - await projectContext.readProjectMetadata(); - if (buildmessage.jobHasMessages()) { - return; - } - - await projectContext.releaseFile.write( - release.current.isCheckout() ? "none" : release.current.name); - if (buildmessage.jobHasMessages()) { - return; - } - - // Also, write package version constraints from the current release - // If we are on a checkout, we don't need to do this as running from - // checkout still pins all package versions and if the user updates - // to a real release, the packages file will subsequently get updated - if (!release.current.isCheckout()) { - projectContext.projectConstraintsFile - .updateReleaseConstraints(release.current._manifest); - } - - // Any upgrader that is in this version of Meteor doesn't need to be run on - // this project. - var upgraders = require('../upgraders.js'); - projectContext.finishedUpgraders.appendUpgraders(upgraders.allUpgraders()); - - await projectContext.prepareProjectForBuild(); - }); - // No need to display the PackageMapDelta here, since it would include all of - // the packages (or maybe an unpredictable subset based on what happens to be - // in the template's versions file). - - // Since some of the project skeletons include npm `devDependencies`, we need - // to make sure they're included when running `npm install`. - await require("./default-npm-deps.js").install( - appPath, - { includeDevDependencies: true } + const skeletonExplicitOption = AVAILABLE_SKELETONS.find( + (skeleton) => !!options[skeleton] ); + const skeleton = skeletonExplicitOption || DEFAULT_SKELETON; - var appNameToDisplay = appPathAsEntered === "." ? - "current directory" : `'${appPathAsEntered}'`; + try { + // Prototype option should use local skeleton. + // Maybe we should use a different skeleton for prototype + if (options.prototype) throw new Error("Using prototype option"); - var message = `Created a new Meteor app in ${appNameToDisplay}`; + await setupExampleByURL(`https://github.com/meteor/skel-${skeleton}`); + } catch (e) { + + if (e.message !== "Using prototype option") { + // something has happened while creating the app using git clone + Console.error( + `Something has happened while creating your app using git clone. + Will use cached version of skeletons. + Error message: `, e.message); + } - message += "."; - - Console.info(message + "\n"); - - // Print a nice message telling people we created their new app, and what to - // do next. - Console.info("To run your new app:"); - - function cmd(text) { - Console.info(Console.command(text), Console.options({ - indent: 2 - })); + // TODO: decide if this should stay here or not. + await files.cp_r( + files.pathJoin( + __dirnameConverted, + "..", + "static-assets", + `skel-${skeleton}` + ), + appPath, + { + transformFilename: function (f) { + return transform(f); + }, + transformContents: function (contents, f) { + // check if this app is just for prototyping if it is then we need to add autopublish and insecure in the packages file + if (/packages/.test(f)) { + const prototypePackages = () => + "autopublish # Publish all data to the clients (for prototyping)\n" + + "insecure # Allow all DB writes from clients (for prototyping)"; + + // XXX: if there is the need to add more options maybe we should have a better abstraction for this if-else + if (options.prototype) { + return Buffer.from( + contents.toString().replace(/~prototype~/g, prototypePackages()) + ); + } else { + return Buffer.from(contents.toString().replace(/~prototype~/g, "")); + } + } + if (/(\.html|\.[jt]sx?|\.css)/.test(f)) { + return Buffer.from(transform(contents.toString())); + } else { + return contents; + } + }, + ignore: toIgnore, + preserveSymlinks: true, + } + ); + await setup(); } - - if (appPathAsEntered !== ".") { - // Wrap the app path in quotes if it contains spaces - const appPathWithQuotesIfSpaces = appPathAsEntered.indexOf(' ') === -1 ? - appPathAsEntered : - `'${appPathAsEntered}'`; - - // Don't tell people to 'cd .' - cmd("cd " + appPathWithQuotesIfSpaces); - } - - cmd("meteor"); - - Console.info(""); - Console.info("If you are new to Meteor, try some of the learning resources here:"); - Console.info( - Console.url("https://www.meteor.com/tutorials"), - Console.options({ indent: 2 })); - - Console.info(""); - Console.info("When you’re ready to deploy and host your new Meteor application, check out Cloud:"); - Console.info( - Console.url("https://www.meteor.com/cloud"), - Console.options({ indent: 2 })); - if (!!skeletonExplicitOption) { // Notify people about the skeleton options - Console.info([ - "", - "To start with a different app template, try one of the following:", - "", - ].join("\n")); + Console.info( + [ + "", + "To start with a different app template, try one of the following:", + "", + ].join("\n") + ); cmd("meteor create --bare # to create an empty app"); - cmd("meteor create --minimal # to create an app with as few Meteor packages as possible"); - cmd("meteor create --full # to create a more complete scaffolded app"); + cmd( + "meteor create --minimal # to create an app with as few Meteor packages as possible" + ); + cmd( + "meteor create --full # to create a more complete scaffolded app" + ); cmd("meteor create --react # to create a basic React-based app"); cmd("meteor create --vue # to create a basic Vue3-based app"); cmd("meteor create --vue-2 # to create a basic Vue2-based app"); cmd("meteor create --apollo # to create a basic Apollo + React app"); cmd("meteor create --svelte # to create a basic Svelte app"); - cmd("meteor create --typescript # to create an app using TypeScript and React"); + cmd( + "meteor create --typescript # to create an app using TypeScript and React" + ); cmd("meteor create --blaze # to create an app using Blaze"); - cmd("meteor create --tailwind # to create an app using React and Tailwind"); + cmd( + "meteor create --tailwind # to create an app using React and Tailwind" + ); cmd("meteor create --chakra-ui # to create an app Chakra UI and React"); cmd("meteor create --solid # to create a basic Solid app"); } diff --git a/tools/cli/example-repositories.js b/tools/cli/example-repositories.js index 4324daf293..7bf472ec0d 100644 --- a/tools/cli/example-repositories.js +++ b/tools/cli/example-repositories.js @@ -1,26 +1,15 @@ export const EXAMPLE_REPOSITORIES = { - clock: { repo: 'https://github.com/meteor/clock' }, - leaderboard: { repo: 'https://github.com/meteor/leaderboard' }, - localmarket: { repo: 'https://github.com/meteor/localmarket' }, - 'simple-todos': { repo: 'https://github.com/meteor/simple-todos' }, - 'simple-todos-react': { - repo: 'https://github.com/meteor/simple-todos-react' - }, - 'simple-todos-angular': { - repo: 'https://github.com/meteor/simple-todos-angular' - }, - todos: { repo: 'https://github.com/meteor/todos' }, - 'todos-react': { - 'repo': 'https://github.com/meteor/todos', - 'branch': 'react', - }, - 'angular-boilerplate': { - repo: 'https://github.com/Urigo/angular-meteor-base.git' - }, - simpletasks: { repo: 'https://github.com/fredmaiaarantes/simpletasks' }, - chakraui: { repo: 'https://github.com/meteor/examples/blob/main/chakra-ui' }, - tailwindcss: { repo: 'https://github.com/meteor/examples/blob/main/tailwindcss' }, - wantch: { repo: 'https://github.com/filipenevola/wantch' }, - doubleapp: { repo: 'https://github.com/denihs/double-app/' }, - + "vue-2": { "repo": "https://github.com/meteor/skel-vue-2" }, + "vue": { "repo": "https://github.com/meteor/skel-vue" }, + "react": { "repo": "https://github.com/meteor/skel-react" }, + "full": { "repo": "https://github.com/meteor/skel-full" }, + "bare": { "repo": "https://github.com/meteor/skel-bare" }, + "blaze": { "repo": "https://github.com/meteor/skel-blaze" }, + "chakra-ui": { "repo": "https://github.com/meteor/skel-chakra-ui" }, + "apollo": { "repo": "https://github.com/meteor/skel-apollo" }, + "minimal": { "repo": "https://github.com/meteor/skel-minimal" }, + "solid": { "repo": "https://github.com/meteor/skel-solid" }, + "svelte": { "repo": "https://github.com/meteor/skel-svelte" }, + "tailwind": { "repo": "https://github.com/meteor/skel-tailwind" }, + "typescript": { "repo": "https://github.com/meteor/skel-typescript" }, }; diff --git a/tools/cli/help.txt b/tools/cli/help.txt index c5cc820414..920a2ce472 100644 --- a/tools/cli/help.txt +++ b/tools/cli/help.txt @@ -152,6 +152,7 @@ Options: Create a new project. Usage: meteor create [--release ] [--bare|--minimal|--full|--react|--vue|--vue-2|--apollo|--svelte|--blaze|--tailwind|--chakra-ui|--solid] meteor create [--release ] --example [] + meteor create [--release ] --from [] meteor create --list meteor create --package [] @@ -178,6 +179,7 @@ currently no package examples. Options: --package Create a new meteor package instead of an app. --example Example template to use. + --from Clones a meteor project from a url. --list Show list of available examples. --bare Create an empty app. --minimal Create an app with as few Meteor packages as possible. @@ -192,7 +194,7 @@ Options: --tailwind Create a basic react-based app, with tailwind configured. --chakra-ui Create a basic react-based app, with chakra-ui configured. --solid Create a basic solid-based app. - --prototype Create a prototype app with the insecure & autopublish packages. Can be used along with other app commands + --prototype Create a prototype app with the insecure & autopublish packages. Can be used along with other app commands >>> update diff --git a/tools/isobuild/js-analyze.js b/tools/isobuild/js-analyze.js index 24bda2b580..5f2bf258b0 100644 --- a/tools/isobuild/js-analyze.js +++ b/tools/isobuild/js-analyze.js @@ -1,7 +1,7 @@ import { parse } from '@meteorjs/babel'; import { analyze as analyzeScope } from 'escope'; import LRU from "lru-cache"; - +import { Profile } from '../tool-env/profile'; import Visitor from "@meteorjs/reify/lib/visitor.js"; import { findPossibleIndexes } from "@meteorjs/reify/lib/utils.js"; @@ -26,9 +26,23 @@ function tryToParse(source, hash) { } let ast; - try { - ast = parse(source); + Profile.time('jsAnalyze.parse', () => { + ast = parse(source, { + strictMode: false, + sourceType: 'module', + allowImportExportEverywhere: true, + allowReturnOutsideFunction: true, + allowUndeclaredExports: true, + plugins: [ + // Only plugins for stage 3 features are enabled + // Enabling some plugins significantly affects parser performance + 'importAttributes', + 'explicitResourceManagement', + 'decorators' + ] + }); + }); } catch (e) { if (typeof e.loc === 'object') { e.$ParseError = true; @@ -71,7 +85,10 @@ export function findImportedModuleIdentifiers(source, hash) { } const ast = tryToParse(source, hash); - importedIdentifierVisitor.visit(ast, source, possibleIndexes); + Profile.time('findImportedModuleIdentifiersVisitor', () => { + importedIdentifierVisitor.visit(ast, source, possibleIndexes); + }); + return importedIdentifierVisitor.identifiers; } diff --git a/tools/project-context.js b/tools/project-context.js index 1fb15c48f8..a16cefda73 100644 --- a/tools/project-context.js +++ b/tools/project-context.js @@ -1735,6 +1735,9 @@ Object.assign(exports.FinishedUpgraders.prototype, { appendUpgraders: function (upgraders) { var self = this; + /** + * @type {string} + */ var current = null; try { current = files.readFile(self.filename, 'utf8'); diff --git a/tools/static-assets/skel-apollo/client/main.html b/tools/static-assets/skel-apollo/client/main.html index b62c0b83d0..b0e2cf6b26 100644 --- a/tools/static-assets/skel-apollo/client/main.html +++ b/tools/static-assets/skel-apollo/client/main.html @@ -1,5 +1,6 @@ Apollo Skeleton + diff --git a/tools/static-assets/skel-apollo/package.json b/tools/static-assets/skel-apollo/package.json index f0b3fcf289..6295d82ae4 100644 --- a/tools/static-assets/skel-apollo/package.json +++ b/tools/static-assets/skel-apollo/package.json @@ -8,10 +8,10 @@ "visualize": "meteor --production --extra-packages bundle-visualizer" }, "dependencies": { - "@apollo/client": "^3.7.5", - "@apollo/server": "^4.3.2", - "@babel/runtime": "^7.20.13", - "body-parser": "^1.20.1", + "@apollo/client": "^3.7.14", + "@apollo/server": "^4.7.1", + "@babel/runtime": "^7.21.5", + "body-parser": "^1.20.2", "express": "^4.18.2", "graphql": "^16.6.0", "meteor-node-stubs": "^1.2.5", diff --git a/tools/static-assets/skel-blaze/client/main.html b/tools/static-assets/skel-blaze/client/main.html index 5b2ca5252f..e2f29f3248 100644 --- a/tools/static-assets/skel-blaze/client/main.html +++ b/tools/static-assets/skel-blaze/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-chakra-ui/client/main.html b/tools/static-assets/skel-chakra-ui/client/main.html index 27c3712e54..7c3d674342 100644 --- a/tools/static-assets/skel-chakra-ui/client/main.html +++ b/tools/static-assets/skel-chakra-ui/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-minimal/client/main.html b/tools/static-assets/skel-minimal/client/main.html index 19789db4de..2b017f6baf 100644 --- a/tools/static-assets/skel-minimal/client/main.html +++ b/tools/static-assets/skel-minimal/client/main.html @@ -1,5 +1,6 @@ Minimal Meteor app + diff --git a/tools/static-assets/skel-react/client/main.html b/tools/static-assets/skel-react/client/main.html index 27c3712e54..7c3d674342 100644 --- a/tools/static-assets/skel-react/client/main.html +++ b/tools/static-assets/skel-react/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-solid/client/main.html b/tools/static-assets/skel-solid/client/main.html index f6b88dd21d..11616e533c 100644 --- a/tools/static-assets/skel-solid/client/main.html +++ b/tools/static-assets/skel-solid/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-solid/imports/ui/Info.jsx b/tools/static-assets/skel-solid/imports/ui/Info.jsx index cf6f585c2e..ef228ac43c 100644 --- a/tools/static-assets/skel-solid/imports/ui/Info.jsx +++ b/tools/static-assets/skel-solid/imports/ui/Info.jsx @@ -1,36 +1,37 @@ import { LinksCollection } from "../api/links"; -import { createSignal, For } from "solid-js"; +import { createSignal, For, Show } from "solid-js"; import { Tracker } from "meteor/tracker"; import { Meteor } from "meteor/meteor"; export const Info = () => { - const loading = Meteor.subscribe("links"); - const [isLoading, setIsLoading] = createSignal(loading.ready()); + const subscription = Meteor.subscribe("links"); + const [isReady, setIsReady] = createSignal(subscription.ready()); const [links, setLinks] = createSignal([]); - Tracker.autorun(() => { - setIsLoading(loading.ready()); - setLinks(LinksCollection.find().fetch()); + Tracker.autorun(async () => { + setIsReady(subscription.ready()); + setLinks(await LinksCollection.find().fetchAsync()); }); - if (isLoading()) { - return
Loading...
; - } - return ( -
-

Learn Meteor!

- -
+ Loading...} + > +
+

Learn Meteor!

+ +
+
); }; diff --git a/tools/static-assets/skel-svelte/client/main.html b/tools/static-assets/skel-svelte/client/main.html index e0e3fddd46..bcad15b78e 100644 --- a/tools/static-assets/skel-svelte/client/main.html +++ b/tools/static-assets/skel-svelte/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-tailwind/client/main.html b/tools/static-assets/skel-tailwind/client/main.html index f8fa758857..c710d3dbd3 100644 --- a/tools/static-assets/skel-tailwind/client/main.html +++ b/tools/static-assets/skel-tailwind/client/main.html @@ -1,13 +1,6 @@ ~name~ - - - - - + diff --git a/tools/static-assets/skel-typescript/client/main.html b/tools/static-assets/skel-typescript/client/main.html index 27c3712e54..7c3d674342 100644 --- a/tools/static-assets/skel-typescript/client/main.html +++ b/tools/static-assets/skel-typescript/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-vue-2/client/main.html b/tools/static-assets/skel-vue-2/client/main.html index 99c3dfb74c..7a78efb67d 100644 --- a/tools/static-assets/skel-vue-2/client/main.html +++ b/tools/static-assets/skel-vue-2/client/main.html @@ -1,5 +1,6 @@ ~name~ + diff --git a/tools/static-assets/skel-vue/client/main.html b/tools/static-assets/skel-vue/client/main.html index 9e2393399c..ca180ae5b9 100644 --- a/tools/static-assets/skel-vue/client/main.html +++ b/tools/static-assets/skel-vue/client/main.html @@ -1,13 +1,6 @@ ~name~ - - - - - + diff --git a/tools/tests/create.js b/tools/tests/create.js index a054b86365..a6a51eefe9 100644 --- a/tools/tests/create.js +++ b/tools/tests/create.js @@ -46,7 +46,7 @@ selftest.define("create main", async function () { run = s.run("create", "--list"); await run.read('Available'); - await run.match('leaderboard'); + await run.match('react'); await run.expectExit(0); });