├── .babelrc ├── .circleci └── config.yml ├── .codeclimate.yml ├── .coveralls.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github └── workflow │ └── nodejs.yml ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── appveyor.yml ├── devEnvSetup.js ├── docs ├── api │ ├── desktop.md │ └── module.md ├── demo.gif ├── devtron_ipc.gif ├── high-level-arch.png └── meteor-desktop.png ├── gh-md-toc ├── lib ├── bin │ └── cli.js ├── binaryModulesDetector.js ├── defaultDependencies.js ├── dependenciesManager.js ├── desktop.js ├── electron.js ├── electronApp.js ├── electronAppScaffold.js ├── electronBuilder.js ├── env.js ├── index.js ├── log.js ├── meteorApp.js ├── meteorManager.js ├── packager.js ├── scripts │ ├── addToScripts.js │ ├── propagateVersion.js │ └── utils │ │ └── addScript.js ├── skeletonDependencies.js └── utils.js ├── package-lock.json ├── package.json ├── plugins ├── bundler │ ├── README.md │ ├── bundler.js │ ├── package.js │ ├── version._desktop_.js │ └── version.desktop └── watcher │ ├── README.md │ ├── package.js │ └── watcher.js ├── scaffold ├── assets │ ├── dmgBackground.png │ ├── loading.gif │ ├── meteor.icns │ ├── meteor.ico │ ├── meteor.png │ ├── splashScreen.png │ └── updating.gif ├── desktop.js ├── desktop.test.js ├── modules │ └── example │ │ ├── example.test.js │ │ ├── index.js │ │ └── module.json └── settings.json ├── skeleton ├── app.js ├── cordova.js ├── desktopPathResolver.js ├── index.js ├── loggerManager.js ├── modules │ ├── autoupdate.js │ ├── autoupdate │ │ ├── assetBundle.js │ │ ├── assetBundleDownloader.js │ │ ├── assetBundleManager.js │ │ ├── assetManifest.js │ │ ├── isDesktopInjector.js │ │ └── utils.js │ ├── dummy.js │ ├── localServer.js │ ├── module.js │ └── storageMigration │ │ └── ioHelper.js ├── preload.js ├── squirrel.js └── windowSettings.js ├── tests ├── fixtures │ ├── .desktop │ │ ├── assets │ │ │ ├── dmgBackground.png │ │ │ ├── loading.gif │ │ │ ├── meteor.icns │ │ │ ├── meteor.ico │ │ │ ├── meteor.png │ │ │ └── splashScreen.png │ │ ├── desktop.js │ │ ├── modules │ │ │ ├── someModule │ │ │ │ ├── module.json │ │ │ │ └── someModule.js │ │ │ └── someModule2 │ │ │ │ ├── module.json │ │ │ │ └── someModule.js │ │ └── settings.json │ ├── autoUpdate │ │ ├── .gitattributes │ │ ├── downloadableVersions │ │ │ ├── 127.0.0.1_root_url │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ │ ├── different_cordova_compatibility_version │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ │ ├── missing_app_id │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ │ ├── missing_cordova_compatibility_version │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ │ ├── missing_root_url │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ │ ├── version1 │ │ │ │ ├── app │ │ │ │ │ ├── 6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map │ │ │ │ │ ├── 979b20f66caf126704c250fbd29ce253c6cb490e.map │ │ │ │ │ ├── mobileapp.js │ │ │ │ │ ├── not-in-manifest │ │ │ │ │ ├── some-data.json │ │ │ │ │ ├── some-file │ │ │ │ │ ├── some-font.woff │ │ │ │ │ ├── some-image.jpg │ │ │ │ │ ├── some-image.png │ │ │ │ │ ├── some-javascript.js │ │ │ │ │ ├── some-page.html │ │ │ │ │ ├── some-stylesheet.css │ │ │ │ │ ├── some-text.txt │ │ │ │ │ ├── some-video.mp4 │ │ │ │ │ └── template.mobileapp.js │ │ │ │ ├── head.html │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ ├── merged-stylesheets.css │ │ │ │ ├── merged-stylesheets.css.map │ │ │ │ └── packages │ │ │ │ │ ├── 57d11a30155349aa5106f8150cee35eac5f4764c.map │ │ │ │ │ └── meteor.js │ │ │ ├── version2 │ │ │ │ ├── 20ae2c8d51b2507244e598844414ecdec2615ce3.map │ │ │ │ ├── app │ │ │ │ │ ├── 3f6275657e6db3a21acb37d0f6c207cf83871e90.map │ │ │ │ │ ├── 6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map │ │ │ │ │ ├── mobileapp.js │ │ │ │ │ ├── some-data.json │ │ │ │ │ ├── some-file │ │ │ │ │ ├── some-font.woff │ │ │ │ │ ├── some-image.jpg │ │ │ │ │ ├── some-image.png │ │ │ │ │ ├── some-javascript.js │ │ │ │ │ ├── some-other-file │ │ │ │ │ ├── some-page.html │ │ │ │ │ ├── some-stylesheet.css │ │ │ │ │ ├── some-text.txt │ │ │ │ │ ├── some-video.mp4 │ │ │ │ │ └── template.mobileapp.js │ │ │ │ ├── head.html │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ ├── merged-stylesheets.css │ │ │ │ └── packages │ │ │ │ │ ├── 57d11a30155349aa5106f8150cee35eac5f4764c.map │ │ │ │ │ └── meteor.js │ │ │ ├── version2_with_invalid_asset │ │ │ │ ├── 20ae2c8d51b2507244e598844414ecdec2615ce3.map │ │ │ │ ├── app │ │ │ │ │ ├── 3f6275657e6db3a21acb37d0f6c207cf83871e90.map │ │ │ │ │ ├── 6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map │ │ │ │ │ ├── mobileapp.js │ │ │ │ │ ├── some-data.json │ │ │ │ │ ├── some-file │ │ │ │ │ ├── some-font.woff │ │ │ │ │ ├── some-image.jpg │ │ │ │ │ ├── some-image.png │ │ │ │ │ ├── some-javascript.js │ │ │ │ │ ├── some-other-file │ │ │ │ │ ├── some-page.html │ │ │ │ │ ├── some-stylesheet.css │ │ │ │ │ ├── some-text.txt │ │ │ │ │ ├── some-video.mp4 │ │ │ │ │ └── template.mobileapp.js │ │ │ │ ├── head.html │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ ├── merged-stylesheets.css │ │ │ │ └── packages │ │ │ │ │ ├── 57d11a30155349aa5106f8150cee35eac5f4764c.map │ │ │ │ │ └── meteor.js │ │ │ ├── version2_with_missing_asset │ │ │ │ ├── 20ae2c8d51b2507244e598844414ecdec2615ce3.map │ │ │ │ ├── app │ │ │ │ │ ├── 3f6275657e6db3a21acb37d0f6c207cf83871e90.map │ │ │ │ │ ├── 6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map │ │ │ │ │ ├── mobileapp.js │ │ │ │ │ ├── some-data.json │ │ │ │ │ ├── some-file │ │ │ │ │ ├── some-font.woff │ │ │ │ │ ├── some-image.jpg │ │ │ │ │ ├── some-image.png │ │ │ │ │ ├── some-javascript.js │ │ │ │ │ ├── some-other-file │ │ │ │ │ ├── some-page.html │ │ │ │ │ ├── some-stylesheet.css │ │ │ │ │ ├── some-text.txt │ │ │ │ │ └── some-video.mp4 │ │ │ │ ├── head.html │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ ├── merged-stylesheets.css │ │ │ │ └── packages │ │ │ │ │ ├── 57d11a30155349aa5106f8150cee35eac5f4764c.map │ │ │ │ │ └── meteor.js │ │ │ ├── version2_with_version_mismatch │ │ │ │ ├── 20ae2c8d51b2507244e598844414ecdec2615ce3.map │ │ │ │ ├── app │ │ │ │ │ ├── 3f6275657e6db3a21acb37d0f6c207cf83871e90.map │ │ │ │ │ ├── 6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map │ │ │ │ │ ├── mobileapp.js │ │ │ │ │ ├── some-data.json │ │ │ │ │ ├── some-file │ │ │ │ │ ├── some-font.woff │ │ │ │ │ ├── some-image.jpg │ │ │ │ │ ├── some-image.png │ │ │ │ │ ├── some-javascript.js │ │ │ │ │ ├── some-other-file │ │ │ │ │ ├── some-page.html │ │ │ │ │ ├── some-stylesheet.css │ │ │ │ │ ├── some-text.txt │ │ │ │ │ ├── some-video.mp4 │ │ │ │ │ └── template.mobileapp.js │ │ │ │ ├── head.html │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ ├── merged-stylesheets.css │ │ │ │ └── packages │ │ │ │ │ ├── 57d11a30155349aa5106f8150cee35eac5f4764c.map │ │ │ │ │ └── meteor.js │ │ │ ├── version3 │ │ │ │ ├── 20ae2c8d51b2507244e598844414ecdec2615ce3.map │ │ │ │ ├── app │ │ │ │ │ ├── 36e96c1d40459ae12164569599c9c0a203b36db7.map │ │ │ │ │ ├── 6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map │ │ │ │ │ ├── mobileapp.js │ │ │ │ │ ├── some-data.json │ │ │ │ │ ├── some-file │ │ │ │ │ ├── some-font.woff │ │ │ │ │ ├── some-image.jpg │ │ │ │ │ ├── some-image.png │ │ │ │ │ ├── some-javascript.js │ │ │ │ │ ├── some-other-file │ │ │ │ │ ├── some-page.html │ │ │ │ │ ├── some-stylesheet.css │ │ │ │ │ ├── some-text.txt │ │ │ │ │ ├── some-video.mp4 │ │ │ │ │ └── template.mobileapp.js │ │ │ │ ├── head.html │ │ │ │ ├── index.html │ │ │ │ ├── manifest.json │ │ │ │ ├── merged-stylesheets.css │ │ │ │ └── packages │ │ │ │ │ ├── 57d11a30155349aa5106f8150cee35eac5f4764c.map │ │ │ │ │ └── meteor.js │ │ │ ├── wrong_app_id │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ │ └── wrong_root_url │ │ │ │ ├── index.html │ │ │ │ └── manifest.json │ │ └── partiallyDownloadedVersions │ │ │ └── version2 │ │ │ ├── app │ │ │ ├── some-file │ │ │ └── some-other-file │ │ │ ├── index.html │ │ │ └── program.json │ ├── localServer │ │ └── bundledWww │ │ │ ├── app │ │ │ ├── mobileapp.js │ │ │ ├── mobileapp.js.map │ │ │ ├── some-data.json │ │ │ ├── some-file │ │ │ ├── some-font.woff │ │ │ ├── some-image.jpg │ │ │ ├── some-image.png │ │ │ ├── some-javascript.js │ │ │ ├── some-page.html │ │ │ ├── some-stylesheet.css │ │ │ ├── some-text.txt │ │ │ ├── some-video.mp4 │ │ │ ├── template.mobileapp.js │ │ │ └── template.mobileapp.js.map │ │ │ ├── cordova.js │ │ │ ├── head.html │ │ │ ├── index.html │ │ │ ├── merged-stylesheets.css │ │ │ ├── merged-stylesheets.css.map │ │ │ ├── not-in-manifest │ │ │ ├── packages │ │ │ ├── meteor.js │ │ │ └── meteor.js.map │ │ │ └── program.json │ ├── meteorProject │ │ ├── .gitignore │ │ ├── .meteor │ │ │ ├── .finished-upgraders │ │ │ ├── .gitignore │ │ │ ├── .id │ │ │ ├── packages │ │ │ ├── platforms │ │ │ ├── release │ │ │ └── versions │ │ ├── client │ │ │ ├── main.css │ │ │ ├── main.html │ │ │ └── main.js │ │ ├── package.json │ │ └── server │ │ │ └── main.js │ └── storages │ │ └── Local Storage │ │ ├── chrome-devtools_devtools_0.localstorage │ │ ├── chrome-devtools_devtools_0.localstorage-journal │ │ ├── http_127.0.0.1_57206.localstorage │ │ ├── http_127.0.0.1_57206.localstorage-journal │ │ ├── http_127.0.0.1_57207.localstorage │ │ ├── http_127.0.0.1_57207.localstorage-journal │ │ ├── http_127.0.0.1_57214.localstorage │ │ └── http_127.0.0.1_57214.localstorage-journal ├── functional │ ├── desktop.test.js │ ├── electronApp.test.js │ ├── electronAppScaffold.test.js │ └── modules │ │ ├── autoupdate.test.js │ │ └── localServer.test.js ├── helpers │ ├── autoupdate │ │ ├── localServer.js │ │ └── meteorServer.js │ ├── clear.js │ ├── meteorDesktop.js │ ├── mockerySettings.js │ └── paths.js ├── integration │ ├── integration.test.js │ └── prepare.js └── unit │ ├── dependenciesManager.test.js │ ├── meteorApp.test.js │ ├── meteorManager.test.js │ ├── modules │ ├── module.test.js │ └── storageManager │ │ └── ioHelper.test.js │ └── skeleton │ ├── app.test.js │ ├── desktopPathResolver.test.js │ └── preload.test.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/env", { 4 | "targets": { 5 | "node": "12" 6 | } 7 | }] 8 | ], 9 | "sourceMaps": true, 10 | "env": { 11 | "test": { 12 | "plugins": ["istanbul"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | test: 4 | docker: 5 | - image: circleci/node:10.16.0-jessie-browsers 6 | steps: 7 | - checkout 8 | - run: 9 | name: Update npm 10 | command: 'sudo npm install -g npm@6' 11 | - restore_cache: 12 | key: dependency-cache-{{ checksum "package.json" }} 13 | - run: 14 | name: Install npm 15 | command: npm install 16 | - save_cache: 17 | key: dependency-cache-{{ checksum "package.json" }} 18 | paths: 19 | - node_modules 20 | - ~/.electron 21 | - ~/.yarn-cache 22 | - run: 23 | name: Test 24 | command: npm run test 25 | test-integration: 26 | docker: 27 | - image: circleci/node:10.16.0-jessie-browsers 28 | steps: 29 | - checkout 30 | - run: 31 | name: Update npm 32 | command: 'sudo npm install -g npm@latest' 33 | - restore_cache: 34 | key: dependency-cache-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} 35 | - run: 36 | name: Install npm 37 | command: npm install 38 | - save_cache: 39 | key: dependency-cache-{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} 40 | paths: 41 | - node_modules 42 | - ~/.electron 43 | - ~/.yarn-cache 44 | - ~/.npm/ 45 | - restore_cache: 46 | key: meteor-cache-{{ checksum "tests/integration/prepare.js" }}-{{ checksum ".circleci/config.yml" }} 47 | - run: 48 | name: restore cached meteor bin 49 | command: | 50 | if [ -e ~/.meteor/meteor-bin ] 51 | then 52 | echo "Cached Meteor bin found, restoring it" 53 | sudo cp ~/.meteor/meteor-bin /usr/local/bin/meteor 54 | else 55 | echo "No cached Meteor bin found." 56 | fi 57 | - run: 58 | name: install Meteor 59 | command: | 60 | # only install meteor if bin isn't found 61 | command -v meteor >/dev/null 2>&1 || curl https://install.meteor.com/?release=1.8.1 | /bin/sh 62 | - run: 63 | name: copy meteor bin to build cache 64 | command: | 65 | cp /usr/local/bin/meteor ~/.meteor/meteor-bin 66 | - run: 67 | name: Prepare test 68 | command: npm run prepare-integration-tests 69 | - run: 70 | name: Test 71 | command: npm run test-integration 72 | - save_cache: 73 | key: meteor-cache-{{ checksum "tests/integration/prepare.js" }}-{{ checksum ".circleci/config.yml" }} 74 | paths: 75 | - ~/.meteor 76 | - tests/.__tmp_int 77 | workflows: 78 | version: 2 79 | build_and_test: 80 | jobs: 81 | - test 82 | - test-integration 83 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - javascript 8 | eslint: 9 | enabled: true 10 | channel: "eslint-3" 11 | fixme: 12 | enabled: true 13 | ratings: 14 | paths: 15 | - "**.js" 16 | exclude_paths: 17 | - "tests/" 18 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: w5scQntQqtAqbRP36Hh7sooqIyqOlbiQm 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*{.,-}min.js 2 | tests/.__tmp 3 | tests/fixtures 4 | plugins/bundler/version._desktop_.js 5 | devEnvSetup.js 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "es6": true, 5 | "browser": true, 6 | "node": true, 7 | "meteor": true, 8 | "mocha": true 9 | }, 10 | "globals": { 11 | "Meteor": true, 12 | "WebAppLocalServer": true, 13 | "Desktop": true, 14 | "Profile": true, 15 | "__METEOR_DESKTOP_BUNDLER": true 16 | }, 17 | "parserOptions": { 18 | "ecmaVersion": 9, 19 | "sourceType": "module" 20 | }, 21 | "settings": { 22 | "import/core-modules": [ 23 | "winston", 24 | "original-fs", 25 | "electron", 26 | "electron-debug", 27 | "rimraf", 28 | "process", 29 | "devtron", 30 | "ava", 31 | "send", 32 | "meteor-desktop-test-suite" 33 | ] 34 | }, 35 | "rules": { 36 | "indent": [ 37 | 2, 38 | 4, 39 | { 40 | "SwitchCase": 1 41 | } 42 | ], 43 | "comma-dangle": [ 44 | 0 45 | ], 46 | "no-bitwise": [ 47 | 2, 48 | { 49 | "allow": [ 50 | "~" 51 | ] 52 | } 53 | ], 54 | "function-paren-newline": ["error", "consistent"], 55 | "no-sequences": "off", 56 | "global-require": "off", 57 | "prefer-promise-reject-errors": "off", 58 | "import/no-dynamic-require": "off", 59 | "import/no-extraneous-dependencies": [ 60 | 2, 61 | { 62 | "devDependencies": [ 63 | "**/*.test.js", 64 | "**/scaffold/**/*.test.js", 65 | "**/integration/**/*.js", 66 | "**/helpers/**/*.js", 67 | "**/skeleton/**/*.js" 68 | ] 69 | } 70 | ] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.github/workflow/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | meteor: [ '1.8.2', '1.9.3', '1.10.2' ] 16 | name: Meteor ${{ matrix.meteor }} sample 17 | 18 | steps: 19 | - uses: actions/checkout@v1 20 | - name: Setup meteor 21 | uses: CanyLink/setup-meteor@v1 22 | with: 23 | meteor-release: ${{ matrix.meteor }} 24 | - run: meteor npm install 25 | - run: meteor npm test 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | dist 4 | tests/_tmp_ 5 | tests/.__tmp_int 6 | .npm 7 | .versions 8 | npm-debug* 9 | coverage 10 | .nyc_output 11 | *.lcov 12 | version 13 | port.cfg 14 | 15 | .reify-cache 16 | tests/.__tmp/autoupdate/Downloading 17 | tests/.__tmp/autoupdate/autoupdate.json 18 | tests/.__tmp/meteorProject 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib 2 | node_modules 3 | .idea 4 | tests 5 | .babelrc 6 | .codeclimate.yml 7 | .coveralls.yml 8 | .editorconfig 9 | .eslintrc 10 | .gitignore 11 | .npmignore 12 | .travis.yml 13 | appveyor.yml 14 | circle.yml 15 | coverage 16 | .nyc_output 17 | plugins 18 | gh-md-toc 19 | docs 20 | .eslintignore 21 | yarn.lock 22 | devEnvSetup.js 23 | *.js___jb_tmp___ 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | os: 4 | - linux 5 | - osx 6 | 7 | env: 8 | - TEST=normal NODE_VERSION=8 9 | - TEST=normal NODE_VERSION=10 10 | - TEST=integration NODE_VERSION=8 11 | - TEST=integration NODE_VERSION=10 12 | 13 | before_install: 14 | - nvm install $NODE_VERSION 15 | - nvm use --delete-prefix $NODE_VERSION || echo 16 | - if [[ $(npm -v) != 6* ]]; then npm i -g npm@6; fi; 17 | - npm install 18 | - if [[ "$TRAVIS_OS_NAME" == "linux" && "$TEST" == "integration" ]]; then 19 | export DISPLAY=:99.0; 20 | sh -e /etc/init.d/xvfb start; 21 | sleep 5; 22 | fi 23 | - if [[ "$TEST" == "integration" ]]; then 24 | export PATH="$HOME/.meteor:$PATH"; 25 | if hash meteor 2>/dev/null; 26 | then 27 | meteor --version; 28 | else 29 | curl https://install.meteor.com/?release=1.8.1 | /bin/sh; 30 | fi; 31 | fi 32 | 33 | 34 | script: 35 | - if [[ "$TEST" == "normal" ]]; then 36 | npm test; 37 | fi 38 | - if [[ "$TEST" == "integration" ]]; then 39 | npm run prepare-integration-tests; 40 | npm run test-integration; 41 | fi 42 | 43 | after_success: 44 | - if [[ "$TEST" == "normal" ]]; then 45 | npm run coverage; 46 | npm run report-coverage; 47 | fi 48 | 49 | cache: 50 | yarn: true 51 | directories: 52 | - node_modules 53 | - $HOME/.electron 54 | - $HOME/.npm 55 | - $HOME/.meteor 56 | - tests/.__tmp_int 57 | 58 | notifications: 59 | email: 60 | on_success: never 61 | on_failure: change 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Bartosz Wojtkowiak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | build: off 2 | 3 | os: unstable 4 | 5 | skip_tags: true 6 | 7 | environment: 8 | matrix: 9 | - nodejs_version: "10" 10 | test: "normal" 11 | platform: x64 12 | - nodejs_version: "10" 13 | test: "integration" 14 | platform: x64 15 | 16 | cache: 17 | - node_modules -> appveyor.yml 18 | - '%APPDATA%\npm\node_modules -> appveyor.yml' 19 | - '%APPDATA%\npm-cache -> appveyor.yml' 20 | - '%USERPROFILE%\.electron -> appveyor.yml' 21 | - '%LOCALAPPDATA%\Yarn -> appveyor.yml' 22 | - '%LOCALAPPDATA%\.meteor -> appveyor.yml' 23 | # - tests/.__tmp_int -> appveyor.yml 24 | 25 | install: 26 | - ps: Install-Product node $env:nodejs_version 27 | - npm install -g npm@6 28 | - npm prune 29 | - npm install 30 | - ps: >- 31 | if ($env:test -eq "integration") { 32 | if ((Get-Command "meteor" -ErrorAction SilentlyContinue) -eq $null) { 33 | choco install meteor --params "'/RELEASE:1.8.1'" 34 | } 35 | } 36 | - ps: refreshenv 37 | - cmd: refreshenv 38 | 39 | # Post-install test scripts. 40 | test_script: 41 | - node --version 42 | - npm --version 43 | - if %test%==integration meteor --version 44 | - if not %test%==integration npm test 45 | - if %test%==integration npm run prepare-integration-tests 46 | - if %test%==integration npm run test-integration 47 | 48 | # 49 | # cache clear 50 | 51 | -------------------------------------------------------------------------------- /docs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/docs/demo.gif -------------------------------------------------------------------------------- /docs/devtron_ipc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/docs/devtron_ipc.gif -------------------------------------------------------------------------------- /docs/high-level-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/docs/high-level-arch.png -------------------------------------------------------------------------------- /docs/meteor-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/docs/meteor-desktop.png -------------------------------------------------------------------------------- /lib/binaryModulesDetector.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import isBinaryFile from 'isbinaryfile'; 3 | import shell from 'shelljs'; 4 | 5 | import Log from './log'; 6 | 7 | shell.config.fatal = true; 8 | /** 9 | * Experimental module for detecting modules containing binary files. 10 | * Based on the same functionality from electron-builder. 11 | * 12 | * @property {MeteorDesktop} $ 13 | * @class 14 | */ 15 | export default class BinaryModulesDetector { 16 | /** 17 | * @constructor 18 | */ 19 | constructor(nodeModulesPath) { 20 | this.log = new Log('binaryModulesDetector'); 21 | this.nodeModulesPath = nodeModulesPath; 22 | } 23 | 24 | // TODO: make asynchronous 25 | detect() { 26 | this.log.verbose('detecting node modules with binary files'); 27 | const files = shell.ls('-RAl', this.nodeModulesPath); 28 | 29 | const extract = []; 30 | 31 | files.forEach((file) => { 32 | const pathSplit = file.name.split(path.posix.sep); 33 | const dir = pathSplit[0]; 34 | const filename = pathSplit.pop(); 35 | 36 | if (extract.indexOf(dir) === -1 && 37 | !BinaryModulesDetector.shouldBeIgnored(dir, filename) 38 | ) { 39 | if (file.isFile()) { 40 | let shouldUnpack = false; 41 | if (file.name.endsWith('.dll') || file.name.endsWith('.exe') || file.name.endsWith('.dylib')) { 42 | shouldUnpack = true; 43 | } else if (path.extname(file.name) === '') { 44 | shouldUnpack = 45 | isBinaryFile.sync(path.join(this.nodeModulesPath, file.name)); 46 | } 47 | if (shouldUnpack) { 48 | this.log.debug(`binary file: ${file.name}`); 49 | extract.push(dir); 50 | } 51 | } 52 | } 53 | }); 54 | if (extract.length > 0) { 55 | this.log.verbose(`detected modules to be extracted: ${extract.join(', ')}`); 56 | } 57 | return extract; 58 | } 59 | 60 | static shouldBeIgnored(dir, filename) { 61 | return dir === '.bin' || filename === '.DS_Store' || filename === 'LICENSE' || filename === 'README'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/defaultDependencies.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | electron: '6.1.7', 3 | 'electron-builder': '21.2.0', 4 | 'electron-packager': '14.0.4' 5 | }; 6 | -------------------------------------------------------------------------------- /lib/electron.js: -------------------------------------------------------------------------------- 1 | import regeneratorRuntime from 'regenerator-runtime/runtime'; 2 | import spawn from 'cross-spawn'; 3 | 4 | import Log from './log'; 5 | import defaultDependencies from './defaultDependencies'; 6 | 7 | /** 8 | * Simple Electron runner. Runs the project with the bin provided by the 'electron' package. 9 | * @class 10 | */ 11 | export default class Electron { 12 | constructor($) { 13 | this.log = new Log('electron'); 14 | this.$ = $; 15 | } 16 | 17 | async init() { 18 | this.electron = await this.$.getDependency('electron', defaultDependencies.electron); 19 | } 20 | 21 | run() { 22 | // Until: https://github.com/electron-userland/electron-prebuilt/pull/118 23 | const { env } = process; 24 | env.ELECTRON_ENV = 'development'; 25 | 26 | const cmd = []; 27 | 28 | if (this.$.env.options.debug) { 29 | cmd.push('--debug=5858'); 30 | } 31 | 32 | cmd.push('.'); 33 | 34 | const child = spawn(this.electron.dependency, cmd, { 35 | cwd: this.$.env.paths.electronApp.root, 36 | env 37 | }); 38 | 39 | // TODO: check if we can configure piping in spawn options 40 | child.stdout.on('data', (chunk) => { 41 | process.stdout.write(chunk); 42 | }); 43 | child.stderr.on('data', (chunk) => { 44 | process.stderr.write(chunk); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/electronAppScaffold.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-unused-vars 2 | import regeneratorRuntime from 'regenerator-runtime/runtime'; 3 | import fs from 'fs'; 4 | import del from 'del'; 5 | import shell from 'shelljs'; 6 | import path from 'path'; 7 | 8 | import Log from './log'; 9 | import dependencies from './skeletonDependencies'; 10 | 11 | const { join } = path; 12 | shell.config.fatal = true; 13 | 14 | /** 15 | * Represents the .desktop dir scaffold. 16 | */ 17 | export default class ElectronAppScaffold { 18 | /** 19 | * @param {MeteorDesktop} $ - context 20 | * @constructor 21 | */ 22 | constructor($) { 23 | this.log = new Log('electronAppScaffold'); 24 | this.$ = $; 25 | 26 | this.packageJson = { 27 | name: 'MyMeteorApp', 28 | main: (this.$.env.isProductionBuild()) ? 29 | 'app.asar/index.js' : 'app/index.js', 30 | dependencies: Object.assign({}, dependencies) 31 | }; 32 | 33 | if (!this.$.env.isProductionBuild() || this.$.env.options.prodDebug) { 34 | this.packageJson.dependencies.devtron = '1.4.0'; 35 | this.packageJson.dependencies['electron-debug'] = '1.5.0'; 36 | } 37 | } 38 | 39 | /** 40 | * Just a public getter from the default package.json object. 41 | * @returns {Object} 42 | */ 43 | getDefaultPackageJson() { 44 | return Object.assign({}, this.packageJson); 45 | } 46 | 47 | /** 48 | * Clear the electron app. Removes everything except the node_modules which would be a waste 49 | * to delete. Later `npm prune` will keep it clear. 50 | */ 51 | clear() { 52 | if (!this.$.utils.exists(this.$.env.paths.electronApp.root)) { 53 | this.log.verbose(`creating ${this.$.env.paths.electronApp.rootName}`); 54 | shell.mkdir(this.$.env.paths.electronApp.root); 55 | } 56 | 57 | return del([ 58 | `${this.$.env.paths.electronApp.root}${path.sep}*`, 59 | `!${this.$.env.paths.electronApp.nodeModules}` 60 | ], { force: true }); 61 | } 62 | 63 | /** 64 | * Just copies the Skeleton App into the electron app. 65 | */ 66 | copySkeletonApp() { 67 | this.log.verbose('copying skeleton app'); 68 | try { 69 | shell.cp( 70 | '-rf', 71 | join(this.$.env.paths.meteorDesktop.skeleton, '*'), 72 | this.$.env.paths.electronApp.appRoot + path.sep 73 | ); 74 | } catch (e) { 75 | this.log.error('error while copying skeleton app:', e); 76 | process.exit(1); 77 | } 78 | } 79 | 80 | /** 81 | * After clearing the electron app path, copies a fresh skeleton. 82 | */ 83 | async make() { 84 | try { 85 | this.log.verbose(`clearing ${this.$.env.paths.electronApp.rootName}`); 86 | await this.clear(); 87 | } catch (e) { 88 | this.log.error( 89 | `error while removing ${this.$.env.paths.electronApp.root}: `, e 90 | ); 91 | process.exit(1); 92 | } 93 | 94 | this.createAppRoot(); 95 | 96 | this.copySkeletonApp(); 97 | 98 | // TODO: hey, wait, .gitignore is not needed - right? 99 | /* 100 | this.log.debug('creating .gitignore'); 101 | fs.writeFileSync(this.$.env.paths.electronApp.gitIgnore, [ 102 | 'node_modules' 103 | ].join('\n')); 104 | */ 105 | this.log.verbose('writing package.json'); 106 | fs.writeFileSync( 107 | this.$.env.paths.electronApp.packageJson, JSON.stringify(this.packageJson, null, 2) 108 | ); 109 | } 110 | 111 | /** 112 | * Creates the app directory in the electron app. 113 | */ 114 | createAppRoot() { 115 | try { 116 | this.log.verbose(`creating ${this.$.env.paths.electronApp.appRoot}`); 117 | fs.mkdirSync(this.$.env.paths.electronApp.appRoot); 118 | } catch (e) { 119 | if (e.code !== 'EEXIST') { 120 | this.log.error( 121 | `error while creating dir: ${this.$.env.paths.electronApp.appRoot}: `, e 122 | ); 123 | process.exit(1); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /lib/log.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | /* 3 | 0.OFF 4 | 1.INFO 5 | 2.WARN 6 | 3.ERROR 7 | 4.TRACE 8 | 5.DEBUG 9 | 6.ALL 10 | */ 11 | 12 | export default class Log { 13 | constructor(prefix) { 14 | this.prefix = prefix; 15 | } 16 | 17 | static level() { 18 | return process.env.MD_LOG_LEVEL || 'ALL'; 19 | } 20 | 21 | static slice(args) { 22 | return Array.prototype.slice.call(args, 0); 23 | } 24 | 25 | log(type, args) { 26 | console.log.apply(null, [`${type} ${this.prefix}: `].concat(Log.slice(args))); 27 | } 28 | 29 | info(...args) { 30 | if (/INFO|ALL/i.test(Log.level())) { 31 | this.log('INFO', args); 32 | } 33 | } 34 | 35 | warn(...args) { 36 | if (/WARN|ALL/i.test(Log.level())) { 37 | this.log('WARN', args); 38 | } 39 | } 40 | 41 | error(...args) { 42 | if (/ERROR|ALL/i.test(Log.level())) { 43 | this.log('ERROR', args); 44 | } 45 | } 46 | 47 | debug(...args) { 48 | if (/DEBUG|ALL/i.test(Log.level())) { 49 | this.log('DEBUG', args); 50 | } 51 | } 52 | 53 | verbose(...args) { 54 | if (/VERBOSE|ALL/i.test(Log.level())) { 55 | this.log('VERBOSE', args); 56 | } 57 | } 58 | 59 | trace(...args) { 60 | if (/TRACE|ALL/i.test(Log.level())) { 61 | this.log('TRACE', args); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/packager.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-unused-vars 2 | import regeneratorRuntime from 'regenerator-runtime/runtime'; 3 | import assignIn from 'lodash/assignIn'; 4 | import path from 'path'; 5 | import fs from 'fs'; 6 | import shell from 'shelljs'; 7 | 8 | import Log from './log'; 9 | import defaultDependencies from './defaultDependencies'; 10 | 11 | const { join } = path; 12 | 13 | /** 14 | * Wrapper around electron-packager. 15 | * @class 16 | */ 17 | export default class ElectronPackager { 18 | constructor($) { 19 | this.log = new Log('electron-packager'); 20 | this.$ = $; 21 | } 22 | 23 | async init() { 24 | this.packager = (await this.$.getDependency('electron-packager', defaultDependencies['electron-packager'])).dependency; 25 | } 26 | 27 | /** 28 | * Runs the packager with provided arguments. 29 | * 30 | * @param {Object} args 31 | * @returns {Promise} 32 | */ 33 | runPackager(args) { 34 | return new Promise((resolve, reject) => { 35 | this.packager(args, (err) => { 36 | if (err) { 37 | reject(err); 38 | } else { 39 | this.log.info(`wrote packaged app to ${this.$.env.paths.packageDir}`); 40 | resolve(); 41 | } 42 | }); 43 | }); 44 | } 45 | 46 | async packageApp() { 47 | const { version } = JSON.parse(fs.readFileSync( 48 | join( 49 | this.$.env.paths.meteorApp.root, 50 | 'node_modules', 51 | 'electron', 52 | 'package.json' 53 | ), 'UTF-8' 54 | )); 55 | 56 | const settings = this.$.desktop.getSettings(); 57 | const { name } = settings; 58 | if (!name) { 59 | this.log.error('`name` field in settings.json not set'); 60 | process.exit(1); 61 | } 62 | 63 | const arch = this.$.env.options.ia32 ? 'ia32' : 'x64'; 64 | 65 | this.log.info( 66 | `packaging '${name}' for platform '${this.$.env.sys.platform}-${arch}'` + 67 | ` using electron v${version}` 68 | ); 69 | 70 | try { 71 | await this.$.utils.rmWithRetries( 72 | '-rf', path.join(this.$.env.options.output, this.$.env.paths.packageDir) 73 | ); 74 | } catch (e) { 75 | throw new Error(e); 76 | } 77 | 78 | const args = { 79 | name, 80 | arch, 81 | prune: false, 82 | electronVersion: version, 83 | platform: this.$.env.sys.platform, 84 | dir: this.$.env.paths.electronApp.root, 85 | out: path.join(this.$.env.options.output, this.$.env.paths.packageDir) 86 | }; 87 | 88 | if ('packagerOptions' in settings) { 89 | const { packagerOptions } = settings; 90 | 91 | ['windows', 'linux', 'osx'].forEach((system) => { 92 | if ( 93 | this.$.env.os[`is${system[0].toUpperCase()}${system.substring(1)}`] && 94 | (`_${system}`) in packagerOptions 95 | ) { 96 | assignIn(packagerOptions, packagerOptions[`_${system}`]); 97 | } 98 | }); 99 | 100 | Object.keys(packagerOptions).forEach((field) => { 101 | if (packagerOptions[field] === '@version') { 102 | packagerOptions[field] = settings.version; 103 | } 104 | }); 105 | 106 | assignIn(args, packagerOptions); 107 | } 108 | 109 | // Move node_modules away. We do not want to delete it, just temporarily remove it from 110 | // our way. 111 | fs.renameSync( 112 | this.$.env.paths.electronApp.nodeModules, 113 | this.$.env.paths.electronApp.tmpNodeModules 114 | ); 115 | 116 | let extracted = false; 117 | 118 | if (this.$.utils.exists(this.$.env.paths.electronApp.extractedNodeModules)) { 119 | fs.renameSync( 120 | this.$.env.paths.electronApp.extractedNodeModules, 121 | this.$.env.paths.electronApp.nodeModules 122 | ); 123 | extracted = true; 124 | } 125 | 126 | try { 127 | await this.runPackager(args); 128 | } finally { 129 | if (extracted) { 130 | shell.rm('-rf', this.$.env.paths.electronApp.extractedNodeModules); 131 | shell.rm('-rf', this.$.env.paths.electronApp.nodeModules); 132 | } 133 | // Move node_modules back. 134 | fs.renameSync( 135 | this.$.env.paths.electronApp.tmpNodeModules, 136 | this.$.env.paths.electronApp.nodeModules 137 | ); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /lib/scripts/addToScripts.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import path from 'path'; 3 | 4 | import addScript from './utils/addScript'; 5 | /** 6 | * This script adds a 'desktop' entry to 'scripts' in package.json. If the entry already exists 7 | * it leaves it untouched. 8 | */ 9 | function fail() { 10 | console.error('[meteor-desktop] failed to add meteor-desktop to your package.json scripts, ' + 11 | 'please add it manually as \'desktop\': \'meteor-desktop\''); 12 | process.exit(0); 13 | } 14 | 15 | const packageJsonPath = path.resolve( 16 | path.join(__dirname, '..', '..', '..', '..', 'package.json') 17 | ); 18 | 19 | addScript('desktop', 'meteor-desktop', packageJsonPath, fail); 20 | 21 | console.log('[meteor-desktop] successfully added a \'desktop\' entry to your package.json' + 22 | ' scripts section.'); 23 | -------------------------------------------------------------------------------- /lib/scripts/propagateVersion.js: -------------------------------------------------------------------------------- 1 | // This propagates the version from package.json to Meteor plugins. 2 | 3 | const { version } = require('../../package.json'); 4 | const fs = require('fs'); 5 | 6 | const paths = ['./plugins/bundler/package.js', './plugins/watcher/package.js']; 7 | paths.forEach((path) => { 8 | let packageJs = fs.readFileSync(path, 'UTF-8'); 9 | packageJs = packageJs.replace(/(version: ')([^']+)'/, `$1${version}'`); 10 | if (~path.indexOf('watcher')) { 11 | packageJs = packageJs.replace(/(omega:meteor-desktop-bundler@)([^']+)'/, `$1${version}'`); 12 | } 13 | fs.writeFileSync(path, packageJs); 14 | }); 15 | -------------------------------------------------------------------------------- /lib/scripts/utils/addScript.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | function readJsonFile(jsonFilePath) { 4 | try { 5 | return JSON.parse(fs.readFileSync(jsonFilePath, 'UTF-8')); 6 | } catch (e) { 7 | return false; 8 | } 9 | } 10 | 11 | function writeJsonFile(jsonFilePath, jsonContents) { 12 | try { 13 | fs.writeFileSync(jsonFilePath, JSON.stringify(jsonContents, null, 2)); 14 | } catch (e) { 15 | return false; 16 | } 17 | return true; 18 | } 19 | 20 | export default function addScript(name, script, packageJsonPath, fail) { 21 | const packageJson = readJsonFile(packageJsonPath); 22 | if (!(packageJson && packageJson.name)) { 23 | fail(); 24 | return; 25 | } 26 | 27 | if (!('scripts' in packageJson)) { 28 | packageJson.scripts = {}; 29 | } 30 | 31 | if (!(name in packageJson.scripts)) { 32 | packageJson.scripts[name] = script; 33 | } 34 | 35 | if (!writeJsonFile(packageJsonPath, packageJson)) { 36 | fail(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/skeletonDependencies.js: -------------------------------------------------------------------------------- 1 | export default { 2 | connect: '3.6.6', 3 | 'server-destroy': '1.0.1', 4 | winston: '2.3.0', 5 | 'find-port': '2.0.1', 6 | rimraf: '2.6.2', 7 | shelljs: '0.7.5', 8 | lodash: '4.17.15', 9 | request: '2.88.0', 10 | queue: '4.0.1', 11 | reify: '0.17.3', 12 | send: '0.16.2', 13 | mime: '2.0.3', 14 | 'fs-extra': '3.0.1', 15 | 'fs-plus': '2.9.3' 16 | }; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meteor-desktop", 3 | "version": "2.2.5", 4 | "bin": { 5 | "meteor-desktop": "dist/bin/cli.js" 6 | }, 7 | "engines": { 8 | "node": ">=4.0.0" 9 | }, 10 | "description": "Build a Meteor's desktop client with hot code push.", 11 | "main": "dist/index.js", 12 | "scripts": { 13 | "test": "cross-env NODE_ENV=test nyc mocha -t 10000 -r ./tests/helpers/clear.js \"tests/+(unit|functional)/**/*.test.js\"", 14 | "test-integration": "mocha -t 10000 -r reify \"tests/+(integration)/**/*.test.js\"", 15 | "test-watch": "mocha -r ./tests/helpers/clear.js --compilers js:@babel/register \"tests/+(unit|functional)/**/*.test.js\" --watch", 16 | "lint": "eslint lib plugins scaffold skeleton tests", 17 | "prepare-integration-tests": "node tests/integration/prepare.js", 18 | "coverage-html": "nyc report --reporter=lcov", 19 | "coverage": "nyc report --reporter=text-lcov | coveralls", 20 | "report-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov", 21 | "version": "node dist/scripts/propagateVersion.js && git add plugins", 22 | "postversion": "npm run publish-all", 23 | "postinstall": "node dist/scripts/addToScripts || echo", 24 | "publish-plugins": "(cls || reset) && cd plugins/bundler && (meteor publish --release=METEOR@1.8.1) && cd ../watcher && (meteor publish --release=METEOR@1.8.1)", 25 | "prepublish": "npm run build || echo", 26 | "publish-all": "npm run publish-plugins && npm publish", 27 | "build": "babel lib --out-dir dist --source-maps inline --copy-files", 28 | "build-watch": "babel lib --watch --out-dir dist --source-maps inline --copy-files", 29 | "develop": "npm-run-all --parallel build-watch test-watch", 30 | "generate-docs": "jsdoc2md skeleton/preload.js > docs/api/desktop.md && jsdoc2md skeleton/modules/module.js > docs/api/module.md", 31 | "update-locks": "(rmdir /S /Q node_modules || rm -rf node_modules || echo) && yarn && (rmdir /S /Q node_modules || rm -rf node_modules) && npm i" 32 | }, 33 | "author": "Bartosz Wojtkowiak ", 34 | "license": "MIT", 35 | "devDependencies": { 36 | "@babel/cli": "7.5.5", 37 | "@babel/register": "7.5.5", 38 | "babel-plugin-istanbul": "^5.2.0", 39 | "chai": "3.5.0", 40 | "chai-as-promised": "6.0.0", 41 | "codecov": "1.0.1", 42 | "connect": "3.6.6", 43 | "connect-modrewrite": "0.9.0", 44 | "coveralls": "3.0.5", 45 | "cross-env": "3.1.4", 46 | "dirty-chai": "1.2.2", 47 | "eslint": "4.19.1", 48 | "eslint-config-airbnb-base": "12.1.0", 49 | "eslint-plugin-import": "2.12.0", 50 | "find-port": "2.0.1", 51 | "fs-extra": "4.0.1", 52 | "fs-plus": "2.9.3", 53 | "import-fresh": "2.0.0", 54 | "jsdoc-to-markdown": "5.0.0", 55 | "mime": "2.0.3", 56 | "mocha": "2.5.3", 57 | "mockery": "2.1.0", 58 | "npm-run-all": "4.0.1", 59 | "nyc": "14.1.1", 60 | "proxyquire": "1.7.11", 61 | "queue": "4.0.1", 62 | "reify": "0.17.3", 63 | "request": "2.88.0", 64 | "rewire": "3.0.2", 65 | "run-sequence": "1.2.2", 66 | "send": "0.16.2", 67 | "serve-static": "1.13.2", 68 | "server-destroy": "1.0.1", 69 | "sha1-file": "1.0.1", 70 | "sinon": "2.3.1", 71 | "sinon-chai": "2.10.0", 72 | "spectron": "8.0.0", 73 | "temp-dir": "2.0.0", 74 | "watch": "1.0.2" 75 | }, 76 | "dependencies": { 77 | "@babel/core": "7.5.5", 78 | "@babel/preset-env": "7.5.5", 79 | "@babel/runtime": "7.5.5", 80 | "asar": "0.14.3", 81 | "cacache": "10.0.4", 82 | "commander": "2.17.1", 83 | "cross-spawn": "5.0.1", 84 | "del": "2.2.2", 85 | "install-local": "0.6.0", 86 | "isbinaryfile": "3.0.3", 87 | "lodash": "4.17.15", 88 | "md5": "2.2.1", 89 | "mksnapshot": "0.3.5", 90 | "node-fetch": "2.2.0", 91 | "regenerator-runtime": "0.12.1", 92 | "rimraf": "2.6.2", 93 | "semver": "5.5.1", 94 | "shelljs": "0.8.2", 95 | "single-line-log": "1.1.2", 96 | "terser": "3.8.2" 97 | }, 98 | "peerDependencies": { 99 | "app-builder-lib": "*", 100 | "electron-builder": "*", 101 | "electron-packager": "*" 102 | }, 103 | "repository": { 104 | "type": "git", 105 | "url": "https://github.com/wojtkowiak/meteor-desktop" 106 | }, 107 | "keywords": [ 108 | "electron", 109 | "meteor", 110 | "packager", 111 | "desktop" 112 | ], 113 | "nyc": { 114 | "exclude": [ 115 | ".reify-cache", 116 | "dist", 117 | "node_modules", 118 | "plugins", 119 | "tests", 120 | "scaffold", 121 | "lib", 122 | "devEnvSetup.js" 123 | ], 124 | "require": [ 125 | "@babel/register" 126 | ], 127 | "sourceMap": false, 128 | "instrument": false, 129 | "all": true 130 | }, 131 | "bugs": { 132 | "url": "https://github.com/wojtkowiak/meteor-desktop/issues" 133 | }, 134 | "homepage": "https://github.com/wojtkowiak/meteor-desktop" 135 | } 136 | -------------------------------------------------------------------------------- /plugins/bundler/README.md: -------------------------------------------------------------------------------- 1 | ## Meteor Desktop bundler 2 | 3 | Essential part of the `.desktop` hot code push mechanism. Bundles the contents of `.desktop` dir 4 | to a `desktop.asar` archive which is then added as asset and served through the normal Meteor hot 5 | code push mechanism. 6 | 7 | -------------------------------------------------------------------------------- /plugins/bundler/package.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-arrow-callback */ 2 | Package.describe({ 3 | name: 'omega:meteor-desktop-bundler', 4 | version: '2.2.5', 5 | summary: 'Bundles .desktop dir into desktop.asar.', 6 | git: 'https://github.com/wojtkowiak/meteor-desktop', 7 | documentation: 'README.md' 8 | }); 9 | 10 | Package.registerBuildPlugin({ 11 | name: 'meteor-desktop-bundler', 12 | use: ['ecmascript@0.4.4'], 13 | sources: ['bundler.js'], 14 | npmDependencies: { chokidar: '2.0.3' } 15 | }); 16 | 17 | Package.onUse(function onUse(api) { 18 | api.versionsFrom('1.3.3'); 19 | api.use('isobuild:compiler-plugin@1.0.0'); 20 | api.addFiles([ 21 | 'version._desktop_.js' 22 | ]); 23 | api.export('METEOR_DESKTOP_VERSION', 'server'); 24 | }); 25 | -------------------------------------------------------------------------------- /plugins/bundler/version._desktop_.js: -------------------------------------------------------------------------------- 1 | METEOR_DESKTOP_VERSION = null; 2 | -------------------------------------------------------------------------------- /plugins/bundler/version.desktop: -------------------------------------------------------------------------------- 1 | { 2 | "version": "initial" 3 | } -------------------------------------------------------------------------------- /plugins/watcher/README.md: -------------------------------------------------------------------------------- 1 | ## Meteor Desktop watcher 2 | 3 | Triggers Meteor client rebuild on any change in the `.desktop` dir. 4 | -------------------------------------------------------------------------------- /plugins/watcher/package.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-arrow-callback */ 2 | Package.describe({ 3 | name: 'omega:meteor-desktop-watcher', 4 | version: '2.2.5', 5 | summary: 'Watches .desktop dir and triggers rebuilds on file change.', 6 | git: 'https://github.com/wojtkowiak/meteor-desktop', 7 | documentation: 'README.md', 8 | debugOnly: true 9 | }); 10 | 11 | Npm.depends({ 12 | chokidar: '2.0.2' 13 | }); 14 | 15 | Package.onUse(function onUse(api) { 16 | api.versionsFrom('METEOR@1.3.3'); 17 | api.use('ecmascript'); 18 | api.use([ 19 | 'omega:meteor-desktop-bundler@2.2.5', 20 | ], ['server'], { 21 | weak: true 22 | }); 23 | api.addFiles([ 24 | 'watcher.js' 25 | ], 'server'); 26 | }); 27 | -------------------------------------------------------------------------------- /scaffold/assets/dmgBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/dmgBackground.png -------------------------------------------------------------------------------- /scaffold/assets/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/loading.gif -------------------------------------------------------------------------------- /scaffold/assets/meteor.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/meteor.icns -------------------------------------------------------------------------------- /scaffold/assets/meteor.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/meteor.ico -------------------------------------------------------------------------------- /scaffold/assets/meteor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/meteor.png -------------------------------------------------------------------------------- /scaffold/assets/splashScreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/splashScreen.png -------------------------------------------------------------------------------- /scaffold/assets/updating.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/scaffold/assets/updating.gif -------------------------------------------------------------------------------- /scaffold/desktop.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import process from 'process'; 3 | import { app, dialog } from 'electron'; 4 | 5 | /** 6 | * Entry point to your native desktop code. 7 | * 8 | * @class 9 | */ 10 | export default class Desktop { 11 | /** 12 | * @param {Object} log - Winston logger instance 13 | * @param {Object} skeletonApp - reference to the skeleton app instance 14 | * @param {Object} appSettings - settings.json contents 15 | * @param {Object} eventsBus - event emitter for listening or emitting events 16 | * shared across skeleton app and every module/plugin 17 | * @param {Object} modules - references to all loaded modules 18 | * @param {Object} Module - reference to the Module class 19 | * @constructor 20 | */ 21 | constructor({ 22 | log, skeletonApp, appSettings, eventsBus, modules, Module 23 | }) { 24 | /** 25 | * You can delete unused var from the param destructuring. 26 | * Left them here just to emphasize what is passed. Delete the eslint rule at the top 27 | * when done. 28 | * You can also just have a one `config` param and do `Object.assign(this, config);` 29 | */ 30 | const desktop = new Module('desktop'); 31 | // Get the automatically predefined logger instance. 32 | this.log = log; 33 | 34 | // From Meteor use this by invoking Desktop.send('desktop', 'closeApp'); 35 | desktop.on('closeApp', () => app.quit()); 36 | 37 | // We need to handle gracefully potential problems. 38 | // Lets remove the default handler and replace it with ours. 39 | skeletonApp.removeUncaughtExceptionListener(); 40 | 41 | process.on('uncaughtException', Desktop.uncaughtExceptionHandler); 42 | 43 | // Chrome problems should also be handled. The `windowCreated` event has a `window` 44 | // reference. This is the reference to the current Electron renderer process (Chrome) 45 | // displaying your Meteor app. 46 | eventsBus.on('windowCreated', (window) => { 47 | window.webContents.on('crashed', Desktop.windowCrashedHandler); 48 | window.on('unresponsive', Desktop.windowUnresponsiveHandler); 49 | }); 50 | 51 | // Consider setting a crash reporter -> 52 | // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md 53 | } 54 | 55 | /** 56 | * Window crash handler. 57 | */ 58 | static windowCrashedHandler() { 59 | Desktop.displayRestartDialog( 60 | 'Application has crashed', 61 | 'Do you want to restart it?' 62 | ); 63 | } 64 | 65 | /** 66 | * Window's unresponsiveness handler. 67 | */ 68 | static windowUnresponsiveHandler() { 69 | Desktop.displayRestartDialog( 70 | 'Application is not responding', 71 | 'Do you want to restart it?' 72 | ); 73 | } 74 | 75 | /** 76 | * JS's uncaught exception handler. 77 | * @param {string} error - error message 78 | */ 79 | static uncaughtExceptionHandler(error) { 80 | // Consider sending a log somewhere, it is good be aware your users are having problems, 81 | // right? 82 | Desktop.displayRestartDialog( 83 | 'Application encountered an error', 84 | 'Do you want to restart it?', 85 | error.message 86 | ); 87 | } 88 | 89 | /** 90 | * Displays an error dialog with simple 'restart' or 'shutdown' choice. 91 | * @param {string} title - title of the dialog 92 | * @param {string} message - message shown in the dialog 93 | * @param {string} details - additional details to be displayed 94 | */ 95 | static displayRestartDialog(title, message, details = '') { 96 | dialog.showMessageBox( 97 | { 98 | type: 'error', buttons: ['Restart', 'Shutdown'], title, message, detail: details 99 | }, 100 | (response) => { 101 | if (response === 0) { 102 | app.relaunch(); 103 | } 104 | app.exit(0); 105 | } 106 | ); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /scaffold/desktop.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-param-reassign */ 2 | import test from 'ava'; 3 | import electron from 'electron'; 4 | import path from 'path'; 5 | import { Application } from 'spectron'; 6 | 7 | /** 8 | * For this to work, init testing with `npm run desktop -- init-tests-support`. 9 | * This will add necessary packages to your `devDependencies` and add `desktop-test` to scripts. 10 | * 11 | * This is an example of functional test for your desktop app. 12 | * Remember that you need to rebuild your desktop app if you made changes in .desktop. You can 13 | * do that with `npm run desktop -- build`. 14 | * There is a plan for using desktop.asar built from omega:meteor-desktop-bundler so that you could 15 | * avoid manual rebuild. 16 | */ 17 | 18 | test.beforeEach(async (t) => { 19 | // Before each test we will spawn a new desktop app instance. 20 | t.context.app = new Application({ 21 | path: electron, 22 | requireName: 'electronRequire', 23 | args: [path.join(__dirname, '..', '.meteor', 'desktop-build')], 24 | env: { NODE_ENV: 'test', ELECTRON_ENV: 'test', METEOR_DESKTOP_NO_SPLASH_SCREEN: 1 } 25 | }); 26 | await t.context.app.start(); 27 | }); 28 | 29 | test.afterEach.always(async (t) => { 30 | // Kill the app after the test. 31 | if (t.context.app && t.context.app.isRunning()) { 32 | await t.context.app.stop(); 33 | } 34 | }); 35 | 36 | /** 37 | * Sends an IPC event to your module. 38 | * 39 | * @param {Object} app - app ref from Spectron 40 | * @param {string} module - module name 41 | * @param {string} event - event from your module 42 | * @param {...*} args - arguments to pass to ipc.send 43 | */ 44 | function sendModuleEvent(app, module, event, ...args) { 45 | args.unshift(`${module}__${event}`); 46 | return app.electron.ipcRenderer.send(...args); 47 | } 48 | 49 | /** 50 | * Waits until a promise from a function finally returns true. 51 | * @param {Function} functionReturningPromise - function to test 52 | * @param {number} ms - expiration timeout in milliseconds 53 | * @returns {Promise} 54 | */ 55 | function waitFor(functionReturningPromise, ms = 10000) { 56 | return new Promise((resolve, reject) => { 57 | let invokerTimeout; 58 | let timeout; 59 | const invokeFunction = () => 60 | functionReturningPromise() 61 | .then((result) => { 62 | if (result) { 63 | clearTimeout(invokerTimeout); 64 | clearTimeout(timeout); 65 | resolve(); 66 | } else { 67 | invokerTimeout = setTimeout(invokeFunction, 500); 68 | } 69 | }) 70 | .catch(() => { 71 | invokerTimeout = setTimeout(invokeFunction, 500); 72 | }); 73 | invokeFunction(); 74 | timeout = setTimeout(() => { 75 | clearTimeout(invokerTimeout); 76 | reject('timeout expired on waitFor'); 77 | }, ms); 78 | }); 79 | } 80 | 81 | /** 82 | * Waits for the app to load and appear. 83 | * @param {Object} t - test context 84 | * @returns {{app: (Application|*), window: *}} 85 | */ 86 | async function waitForApp(t) { 87 | const { app } = t.context; 88 | await app.client.waitUntilWindowLoaded(); 89 | const window = app.browserWindow; 90 | // Wait for the main window for max 30seconds. Adjust to your app. 91 | await waitFor(window.isVisible, 30000); 92 | t.is(await app.client.getWindowCount(), 1); 93 | await app.client.waitUntil( 94 | () => app.client.execute( 95 | () => document.readyState === 'complete' 96 | ) 97 | ); 98 | return { app, window }; 99 | } 100 | 101 | test.serial('if app can be closed', async (t) => { 102 | const { app, window } = await waitForApp(t); // eslint-disable-line no-unused-vars 103 | await sendModuleEvent(app, 'desktop', 'closeApp'); 104 | t.true(await app.client.getWindowCount() === 0); 105 | 106 | // Spectron does not seem to notice app has quit so we need to do it manually. 107 | t.context.app.running = false; 108 | }); 109 | 110 | // Empty test. 111 | test.serial('if window title is set properly', async (t) => { 112 | const { app, window } = await waitForApp(t); // eslint-disable-line no-unused-vars 113 | 114 | // Your assertions... 115 | 116 | /* 117 | const title = await window.getTitle(); 118 | t.is(title, 'my app '); 119 | 120 | // NOTE: 121 | // avoid using await in assertions like 122 | // t.is(await window.getTitle(), 'my app <title>'); 123 | // it makes Power Assert not producing it's useful graphs 124 | */ 125 | }); 126 | -------------------------------------------------------------------------------- /scaffold/modules/example/example.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import test from 'ava'; 3 | import { Application } from 'spectron'; 4 | import path from 'path'; 5 | import fs from 'fs'; 6 | import shell from 'shelljs'; 7 | import electron from 'electron'; 8 | import { 9 | constructModule, createTestAppWithModule, fetch, 10 | fireEventsBusEventAndWaitForAnother 11 | } from 12 | 'meteor-desktop-test-suite'; 13 | 14 | /** 15 | * For this to work, init testing with `npm run desktop -- init-tests-support`. 16 | * This will add necessary packages to your `devDependencies` and add `desktop-test` to scripts. 17 | * 18 | * This is an example of functional test for your module. 19 | * 20 | * You could test your module from the built app, like in desktop.test.js. 21 | * 22 | * Here instead we will treat this module like a separate plugin and test it in a test app instance. 23 | * This has a significant advantage as you do not have to rebuild the desktop app if you made 24 | * changes in the module - you just need to rerun the tests which is usually faster. 25 | * 26 | * However if your module is importing files from the outside of its dir this will fail - support 27 | * for that is planned - vote on features on meteor-desktop issues list on github. 28 | * 29 | * Be aware that you can specify npm dependencies in the dependencies section of module.json - 30 | * those will be installed in the test app. 31 | */ 32 | 33 | let userData; 34 | let appDir; 35 | 36 | async function getApp(t) { 37 | // Waits for the test app to start. 38 | const { app } = t.context; 39 | await app.client.waitUntilWindowLoaded(); 40 | t.is(await app.client.getWindowCount(), 1); 41 | return app; 42 | } 43 | 44 | test.before( 45 | async () => { 46 | // Create a new test app with this module included. 47 | appDir = await createTestAppWithModule( 48 | null, __dirname 49 | ); 50 | } 51 | ); 52 | 53 | test.after( 54 | () => { 55 | // Remove the test app and its data. 56 | shell.rm('-rf', userData); 57 | shell.rm('-rf', appDir); 58 | } 59 | ); 60 | 61 | test.beforeEach(async (t) => { 62 | // Every test start a new instance of the test app. 63 | t.context.app = new Application({ // eslint-disable-line no-param-reassign 64 | path: electron, 65 | args: [appDir], 66 | env: { ELECTRON_ENV: 'test' } 67 | }); 68 | await t.context.app.start(); 69 | userData = await t.context.app.electron.remote.app.getPath('userData'); 70 | }); 71 | 72 | test.afterEach.always(async (t) => { 73 | try { 74 | // Test app saves an error.txt file if it encounters an uncaught exception. 75 | // It is good to see it's contents if it is present. 76 | const errorFile = path.join(appDir, 'error.txt'); 77 | console.log( 78 | 'error caught in the test app:', 79 | fs.readFileSync(errorFile, 'utf8') 80 | ); 81 | fs.unlinkSync(errorFile); 82 | } catch (e) { 83 | // No error.txt present. That's good! 84 | } 85 | 86 | if (t.context.app && t.context.app.isRunning()) { 87 | await t.context.app.stop(); 88 | } 89 | }); 90 | 91 | test('the test app', async t => getApp(t)); 92 | 93 | test.serial('if testEvent returns true for 1', async (t) => { 94 | const app = await getApp(t); 95 | await constructModule(app); 96 | await fireEventsBusEventAndWaitForAnother(app, 'desktopLoaded', 'example.loaded'); 97 | const response = await fetch(app, 'example', 'testEvent', 1); 98 | // Fetch returns an array with the response event arguments. 99 | t.true(response[0]); 100 | }); 101 | 102 | test.serial('if testEvent returns false for 5', async (t) => { 103 | const app = await getApp(t); 104 | await constructModule(app); 105 | await fireEventsBusEventAndWaitForAnother(app, 'desktopLoaded', 'example.loaded'); 106 | const response = await fetch(app, 'example', 'testEvent', 5); 107 | // Fetch returns an array with the response event arguments. 108 | t.false(response[0]); 109 | }); 110 | -------------------------------------------------------------------------------- /scaffold/modules/example/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import moduleJson from './module.json'; 3 | 4 | /** 5 | * Example module. 6 | * 7 | * @param {Object} log - Winston logger instance 8 | * @param {Object} skeletonApp - reference to the skeleton app instance 9 | * @param {Object} appSettings - settings.json contents 10 | * @param {Object} eventsBus - event emitter for listening or emitting events 11 | * shared across skeleton app and every module/plugin 12 | * @param {Object} modules - references to all loaded modules 13 | * @param {Object} settings - module settings 14 | * @param {Object} Module - reference to the Module class 15 | * @constructor 16 | */ 17 | export default class Example { 18 | constructor({ 19 | log, skeletonApp, appSettings, eventsBus, modules, settings, Module 20 | }) { 21 | /** 22 | * You can delete unused vars from the param destructuring. 23 | * Left them here just to emphasize what is passed. Delete the eslint rule at the top 24 | * when done. 25 | * You can also just have a one `config` param and do `Object.assign(this, config);` 26 | */ 27 | this.module = new Module(moduleJson.name); 28 | 29 | // Get the automatically predefined logger instance. 30 | this.log = log; 31 | this.eventsBus = eventsBus; 32 | 33 | // Never do time consuming or blocking things directly in the constructor. 34 | // Instead hook to 'beforeDesktopJsLoad`, `desktopLoaded` or `afterInitialization` events. 35 | // This will also ensure plugins providing things like splash screens will be able 36 | // to start as quickly as possible. 37 | this.eventsBus.on('desktopLoaded', () => { 38 | this.init(); 39 | }); 40 | } 41 | 42 | init() { 43 | // Do some initialization if necessary. 44 | 45 | this.registerApi(); 46 | 47 | // Lets inform that the module has finished loading. 48 | this.eventsBus.emit(`${moduleJson.name}.loaded`); 49 | } 50 | 51 | registerApi() { 52 | // Lets create a test event. 53 | this.module.on('testEvent', (event, fetchId, testArg) => { 54 | // Nothing fancy here, we will just respond with the result of testArg === 1. 55 | // fetchId is necessary for the system to know to which request the response is for. 56 | // It will be present if you will emit this event in Meteor app with `Desktop.fetch`. 57 | this.module.respond('testEvent', fetchId, testArg === 1); 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /scaffold/modules/example/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "dependencies": { 4 | }, 5 | "extract": [] 6 | } 7 | -------------------------------------------------------------------------------- /scaffold/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "My Meteor App", 3 | "version": "0.0.1", 4 | "projectName": "MyMeteorApp", 5 | "devTools": true, 6 | "devtron": true, 7 | "desktopHCP": true, 8 | "desktopHCPIgnoreCompatibilityVersion": false, 9 | "squirrel": { 10 | "autoUpdateFeedUrl": "http://127.0.0.1/update/:platform/:version", 11 | "autoUpdateFeedHeaders": {}, 12 | "autoUpdateCheckOnStart": false 13 | }, 14 | "webAppStartupTimeout": 60000, 15 | "exposeLocalFilesystem": false, 16 | "allowOriginLocalServer": false, 17 | "window": { 18 | "icon": "@assets/meteor.png", 19 | "_windows": { 20 | "icon": "@assets/meteor.ico" 21 | } 22 | }, 23 | "windowDev": { 24 | }, 25 | "uglify": true, 26 | "plugins": { 27 | "meteor-desktop-splash-screen": { 28 | "version": "0.5.0", 29 | "windowSettings": { 30 | "width": 800, 31 | "height": 600 32 | }, 33 | "updateScreen": true, 34 | "updateScreenSettings": { 35 | "imagePath": "updating.gif", 36 | "windowSettings": { 37 | "width": 400, 38 | "height": 300 39 | }, 40 | "clickThrough": false, 41 | "style": { 42 | "background-size": "auto" 43 | } 44 | } 45 | } 46 | }, 47 | "dependencies": {}, 48 | "packageJsonFields": { 49 | "description": "My Meteor App", 50 | "author": "Me, Myself And I", 51 | "private": true 52 | }, 53 | "builderOptions": { 54 | "icon": ".desktop/assets/meteor.ico", 55 | "appId": "meteor.app", 56 | "productName": "My Meteor App", 57 | "compression": "maximum", 58 | "win": { 59 | "target": "nsis" 60 | }, 61 | "squirrelWindows": { 62 | "iconUrl": "https://github.com/wojtkowiak/meteor-desktop/blob/beta/scaffold/assets/meteor.ico?raw=true", 63 | "loadingGif": ".desktop/assets/loading.gif" 64 | }, 65 | "publish": [ 66 | { 67 | "provider": "generic", 68 | "url": "http://127.0.0.1:8080/" 69 | } 70 | ], 71 | "mac": { 72 | "icon": ".desktop/assets/meteor.icns" 73 | }, 74 | "dmg": { 75 | "icon": ".desktop/assets/meteor.icns", 76 | "background": ".desktop/assets/dmgBackground.png", 77 | "iconSize": 54, 78 | "contents": [ 79 | { "x": 377, "y": 190, "type": "link", "path": "/Applications" }, 80 | { "x": 63, "y": 190, "type": "file" } 81 | ], 82 | "window": { 83 | "width": 480, 84 | "height": 300 85 | } 86 | } 87 | }, 88 | "packagerOptions": { 89 | "icon": ".desktop/assets/meteor.ico", 90 | "_osx": { 91 | "icon": ".desktop/assets/meteor.icns" 92 | }, 93 | "appVersion": "@version", 94 | "buildVersion": "@version", 95 | "appCopyright": "Copyright 2018 My Company - All rights reserved.", 96 | "win32metadata": { 97 | "CompanyName": "My Company", 98 | "FileDescription": "MyMeteorApp", 99 | "OriginalFilename": "MyMeteorApp.exe", 100 | "ProductName": "MyMeteorApp", 101 | "InternalName": "MyMeteorApp.exe" 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /skeleton/cordova.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | /** 3 | * This is based on: 4 | * https://github.com/meteor/cordova-plugin-meteor-webapp/blob/master/www/webapp_local_server.js 5 | */ 6 | 7 | WebAppLocalServer = { 8 | onNewVersionReadyCallback: null, 9 | onErrorCallback: null, 10 | onVersionsCleanedUpCallback: null, 11 | 12 | startupDidComplete(callback) { 13 | this.onVersionsCleanedUpCallback = callback; 14 | Desktop.send('autoupdate', 'startupDidComplete'); 15 | }, 16 | 17 | checkForUpdates() { 18 | Desktop.send('autoupdate', 'checkForUpdates'); 19 | }, 20 | 21 | onNewVersionReady(callback) { 22 | this.onNewVersionReadyCallback = callback; 23 | }, 24 | 25 | onError(callback) { 26 | this.onErrorCallback = callback; 27 | } 28 | }; 29 | 30 | Desktop.on('autoupdate', 'error', (event, args) => { 31 | WebAppLocalServer.onErrorCallback(args); 32 | }); 33 | 34 | Desktop.on('autoupdate', 'warn', (event, args) => { 35 | console.warn(args); 36 | }); 37 | 38 | Desktop.on('autoupdate', 'onVersionsCleanedUp', () => { 39 | if (WebAppLocalServer.onVersionsCleanedUpCallback) { 40 | WebAppLocalServer.onVersionsCleanedUpCallback(); 41 | } 42 | }); 43 | 44 | Desktop.on('autoupdate', 'onNewVersionReady', (event, args) => { 45 | console.log('new version ready', args); 46 | if (WebAppLocalServer.onNewVersionReadyCallback) { 47 | WebAppLocalServer.onNewVersionReadyCallback(args); 48 | } 49 | }); 50 | 51 | // Set the reference, so that the desktop side will be able to communicate with us asap. 52 | Desktop.send('dummyModule', 'setRendererReference'); 53 | -------------------------------------------------------------------------------- /skeleton/index.js: -------------------------------------------------------------------------------- 1 | // Init reify. 2 | require('reify'); 3 | // Load the app. 4 | require('./app.js'); 5 | -------------------------------------------------------------------------------- /skeleton/loggerManager.js: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import winston from 'winston'; 3 | 4 | export default class LoggerManager { 5 | /** 6 | * @param {App} $ - context. 7 | */ 8 | constructor($) { 9 | this.$ = $; 10 | 11 | /* TODO: fix `Possible EventEmitter memory leak detected.` warning - will probably have to 12 | drop winston in favor of bunyan (winston does not seem to be actively supported) 13 | */ 14 | 15 | // Default Winston transports. 16 | this.fileLogConfiguration = { 17 | level: 'debug', 18 | filename: join($.userDataDir, 'run.log'), 19 | handleExceptions: false, 20 | json: false, 21 | maxsize: 5242880, // 5MB 22 | maxFiles: 5, 23 | colorize: false 24 | }; 25 | this.consoleLogConfiguration = { 26 | level: 'debug', 27 | handleExceptions: false, 28 | json: false, 29 | colorize: true 30 | }; 31 | 32 | this.loggerTransports = [ 33 | new (winston.transports.Console)(this.consoleLogConfiguration), 34 | new (winston.transports.File)(this.fileLogConfiguration) 35 | ]; 36 | 37 | winston.loggers.options.transports = this.loggerTransports; 38 | this.mainLogger = this.configureLogger(); 39 | } 40 | 41 | /** 42 | * @returns {Log} 43 | */ 44 | getMainLogger() { 45 | return this.mainLogger; 46 | } 47 | 48 | /** 49 | * Returns a new logger instance. 50 | * @param {string} entityName 51 | * @returns {Log} 52 | */ 53 | configureLogger(entityName = 'main') { 54 | winston.loggers.add(entityName, {}); 55 | 56 | const logger = winston.loggers.get(entityName); 57 | if (entityName !== 'main') { 58 | logger.add(winston.transports.File, { 59 | level: 'debug', 60 | name: entityName, 61 | handleExceptions: false, 62 | filename: join(this.$.userDataDir, `${entityName}.log`) 63 | }); 64 | } 65 | 66 | logger.filters.push((level, msg) => `[${entityName}] ${msg}`); 67 | logger.entityName = entityName; 68 | 69 | logger.getLoggerFor = (subEntityName) => { 70 | if (!winston.loggers.loggers[`${logger.entityName}__${subEntityName}`]) { 71 | winston.loggers.add(`${logger.entityName}__${subEntityName}`, {}); 72 | const newLogger = winston.loggers.get(`${logger.entityName}__${subEntityName}`); 73 | newLogger.filters.push((level, msg) => `[${logger.entityName}] [${subEntityName}] ${msg}`); 74 | newLogger.getLoggerFor = logger.getLoggerFor; 75 | return newLogger; 76 | } 77 | return winston.loggers.get(`${logger.entityName}__${subEntityName}`); 78 | }; 79 | 80 | return logger; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /skeleton/modules/autoupdate/assetManifest.js: -------------------------------------------------------------------------------- 1 | /** 2 | This is a slightly modified JS port of hot code push android client from here: 3 | https://github.com/meteor/cordova-plugin-meteor-webapp 4 | 5 | The MIT License (MIT) 6 | 7 | Copyright (c) 2015 Meteor Development Group 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | This file is based on: 28 | /cordova-plugin-meteor-webapp/blob/master/src/android/AssetManifest.java 29 | 30 | */ 31 | 32 | import assignIn from 'lodash/assignIn'; 33 | 34 | /** 35 | * Represents single file in the manifest. 36 | * 37 | * @param {object} manifestEntry 38 | * @param {string} manifestEntry.path 39 | * @param {string} manifestEntry.url 40 | * @param {string} manifestEntry.type 41 | * @param {number} manifestEntry.size 42 | * @param {bool} manifestEntry.cacheable 43 | * @param {string} manifestEntry.hash 44 | * @param {string} manifestEntry.sourceMap 45 | * @param {string} manifestEntry.sourceMapUrl 46 | * 47 | * @property {string} filePath 48 | * @property {string} urlPath 49 | * @property {string} fileType 50 | * @property {number} size 51 | * @property {bool} cacheable 52 | * @property {string} hash 53 | * @property {string} sourceMapFilePath 54 | * @property {string} sourceMapUrlPath 55 | * @constructor 56 | */ 57 | function ManifestEntry(manifestEntry) { 58 | assignIn(this, { 59 | filePath: manifestEntry.path, 60 | urlPath: manifestEntry.url, 61 | fileType: manifestEntry.type, 62 | size: manifestEntry.size, 63 | cacheable: manifestEntry.cacheable, 64 | hash: manifestEntry.hash || null, 65 | sourceMapFilePath: manifestEntry.sourceMap || null, 66 | sourceMapUrlPath: manifestEntry.sourceMapUrl || null 67 | }); 68 | } 69 | 70 | /** 71 | * Represents a program.json app manifest. 72 | * 73 | * @param {Object} logger - Logger instance. 74 | * @param {string} manifestSource - Manifest source. 75 | * 76 | * @property {string} version 77 | * @property {string} cordovaCompatibilityVersion 78 | * 79 | * @constructor 80 | */ 81 | export default function AssetManifest(logger, manifestSource) { 82 | const log = logger.getLoggerFor('AssetManifest'); 83 | let json; 84 | let format; 85 | 86 | function error(msg) { 87 | log.error(msg); 88 | throw new Error(msg); 89 | } 90 | 91 | try { 92 | /** 93 | * @type object 94 | * @property {string} format 95 | * @property {string|null} version 96 | * @property {object} cordovaCompatibilityVersions 97 | * @property {string} cordovaCompatibilityVersions.android 98 | * @property {string} cordovaCompatibilityVersions.ios 99 | * @property {Array} manifest 100 | */ 101 | json = JSON.parse(manifestSource); 102 | format = json.format || null; 103 | 104 | if (format !== null && format !== 'web-program-pre1') { 105 | error(`The asset manifest format is incompatible: ${format}`); 106 | } 107 | if (!('version' in json) || json.version === null) { 108 | error('Asset manifest does not have a version.'); 109 | } 110 | 111 | this.version = json.version; 112 | 113 | // We are not using compatibility versions, but for sanity check this is ok. 114 | if (!('cordovaCompatibilityVersions' in json) || 115 | !('android' in json.cordovaCompatibilityVersions)) { 116 | error('Asset manifest does not have a cordovaCompatibilityVersion.'); 117 | } 118 | 119 | this.cordovaCompatibilityVersion = json.cordovaCompatibilityVersions.android; 120 | 121 | this.entries = json.manifest 122 | .filter(manifestEntry => manifestEntry.where === 'client') 123 | .map(manifestEntry => new ManifestEntry(manifestEntry)); 124 | 125 | log.debug(`${this.entries.length} entries. (Version: ${this.version})`); 126 | } catch (e) { 127 | error(`error parsing asset manifest: ${e.message}`); 128 | } 129 | } 130 | 131 | module.exports = AssetManifest; 132 | 133 | /** 134 | * @typedef {Object} AssetManifest 135 | * @property {string} version 136 | * @property {string} cordovaCompatibilityVersion 137 | */ 138 | -------------------------------------------------------------------------------- /skeleton/modules/autoupdate/isDesktopInjector.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * Until we would have a `web.desktop` arch in Meteor we need to provide a way to distinguish 5 | * the desktop specific code. The easiest approach is to have a Meteor.isDesktop. Since we do not 6 | * want the `Meteor.isCordova` to be true we just replace it with `isDesktop`. 7 | * Also we need to change the faulty version check procedure to fire on desktop architecture. 8 | */ 9 | 10 | class IsDesktopInjector { 11 | constructor() { 12 | this.startupDidCompleteRegEx = 13 | new RegExp('\\.isCordova\\)[\\S\\s]*?startupDidComplete\\(', 'gm'); 14 | 15 | this.startupDidCompleteRegExReplace = 16 | new RegExp('(\\(\\w+\\.)(?:isCordova)(\\)[\\S\\s]*?startupDidComplete\\()', 'gm'); 17 | 18 | this.startupDidCompleteProductionRegEx = 19 | new RegExp('\\.isCordova&&\\w*\\.startupDidComplete', 'gm'); 20 | 21 | this.startupDidCompleteProductionRegExReplace = 22 | new RegExp('(\\w+\\.)(?:isCordova)(&&\\w*\\.startupDidComplete\\()', 'gm'); 23 | } 24 | /** 25 | * Searches for and replaces two places in Meteor app: 26 | * - where `isCordova` is set to true 27 | * - where `startupDidComplete` is fired 28 | * 29 | * @param {string} contents 30 | * @returns {{fileContents: *, injectedStartupDidComplete: boolean, injected: boolean}} 31 | */ 32 | processFileContents(contents) { 33 | // This searches for the place where `startupDidComplete` is fired. We need that now to be 34 | // fired when `isDesktop` is set. 35 | 36 | let injectedStartupDidComplete = false; 37 | let injected = false; 38 | let fileContents = contents; 39 | 40 | // This changes the place where `isCordova` is set to true. 41 | fileContents = fileContents.replace('.isCordova=!0', '.isDesktop=!0'); 42 | fileContents = fileContents.replace('.isCordova = true', '.isDesktop = true'); 43 | 44 | if (this.startupDidCompleteRegEx.test(fileContents)) { 45 | fileContents = fileContents.replace( 46 | this.startupDidCompleteRegExReplace, 47 | '$1isDesktop$2' 48 | ); 49 | injectedStartupDidComplete = true; 50 | } 51 | if (this.startupDidCompleteProductionRegEx.test(fileContents)) { 52 | fileContents = fileContents.replace( 53 | this.startupDidCompleteProductionRegExReplace, 54 | '$1isDesktop$2' 55 | ); 56 | injectedStartupDidComplete = true; 57 | } 58 | 59 | if (~fileContents.indexOf('.isDesktop=!0') || 60 | ~fileContents.indexOf('.isDesktop = true')) { 61 | injected = true; 62 | } 63 | 64 | this.startupDidCompleteProductionRegEx.lastIndex = 0; 65 | this.startupDidCompleteRegEx.lastIndex = 0; 66 | this.startupDidCompleteProductionRegExReplace.lastIndex = 0; 67 | this.startupDidCompleteRegExReplace.lastIndex = 0; 68 | 69 | return { 70 | fileContents, 71 | injectedStartupDidComplete, 72 | injected 73 | }; 74 | } 75 | } 76 | 77 | module.exports = IsDesktopInjector; 78 | -------------------------------------------------------------------------------- /skeleton/modules/autoupdate/utils.js: -------------------------------------------------------------------------------- 1 | import rimraf from 'rimraf'; 2 | 3 | /** 4 | * Simple wrapper for rimraf with additional retries in case of failure. 5 | * It is useful when something is concurrently reading the dir you want to remove. 6 | */ 7 | function rimrafWithRetries(...args) { 8 | let retries = 0; 9 | return new Promise((resolve, reject) => { 10 | function rm(...rmArgs) { 11 | try { 12 | rimraf.sync(...rmArgs); 13 | resolve(); 14 | } catch (e) { 15 | retries += 1; 16 | if (retries < 5) { 17 | setTimeout(() => { 18 | rm(...rmArgs); 19 | }, 100); 20 | } else { 21 | reject(e); 22 | } 23 | } 24 | } 25 | rm(...args); 26 | }); 27 | } 28 | 29 | export default { 30 | rimrafWithRetries 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /skeleton/modules/dummy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dummy module which is called on the renderer process startup, so that the Module can save a 3 | * reference to the renderer. 4 | * 5 | * @type {Module} 6 | */ 7 | 8 | import Module from './module'; 9 | 10 | const dummy = new Module('dummyModule'); 11 | 12 | // Nothing to do here since Module is already setting this reference for us. 13 | dummy.on('setRendererReference', Function.prototype); 14 | 15 | export default function Dummy() {} 16 | -------------------------------------------------------------------------------- /skeleton/modules/storageMigration/ioHelper.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs-plus'; 2 | import shelljs from 'shelljs'; 3 | import rimraf from 'rimraf'; 4 | import fsExtra from 'fs-extra'; 5 | 6 | /** 7 | * Traverses the local storage directory looking for the last modified local storage file. 8 | * 9 | * @returns {{latestPort: number, files: Array}} 10 | */ 11 | export function findNewestFileOrDirectory(path, condition = () => true) { 12 | let maxMTime = 0; 13 | const returnValue = { entries: [], newest: null }; 14 | 15 | if (fs.existsSync(path)) { 16 | const files = shelljs.ls('-l', path); 17 | returnValue.entries = files; 18 | files.forEach((file) => { 19 | if (condition(file) && file.mtime.getTime() > maxMTime) { 20 | maxMTime = file.mtime.getTime(); 21 | returnValue.newest = file.name; 22 | } 23 | }); 24 | } 25 | return returnValue; 26 | } 27 | 28 | export function rimrafPromisfied(path) { 29 | return new Promise((resolve, reject) => { 30 | rimraf(path, {}, (error) => { 31 | if (error) { 32 | reject(error); 33 | } else { 34 | resolve(); 35 | } 36 | }); 37 | }); 38 | } 39 | 40 | export function removePaths(paths = [], deleteFunction) { 41 | const rimrafPromises = []; 42 | paths.forEach((filePath) => { 43 | if (fs.existsSync(filePath)) { 44 | rimrafPromises.push(deleteFunction(filePath)); 45 | } else { 46 | rimrafPromises.push(Promise.resolve()); 47 | } 48 | }); 49 | return Promise.all(rimrafPromises); 50 | } 51 | 52 | /** 53 | * Simple wrapper for copy/move with additional retries in case of failure. 54 | * It is useful when something is concurrently accessing the files you want to modify. 55 | */ 56 | export function ioOperationWithRetries(operation, maxRetries = 5, delayMs = 100, ...args) { 57 | let retries = 0; 58 | return new Promise((resolve, reject) => { 59 | function io() { 60 | fsExtra[operation](...args) 61 | .then(() => { 62 | resolve(true); 63 | }) 64 | .catch((err) => { 65 | retries += 1; 66 | if (retries <= maxRetries) { 67 | setTimeout(() => { 68 | io(operation, ...args); 69 | }, delayMs); 70 | } else { 71 | reject(err); 72 | } 73 | }); 74 | } 75 | io(operation, ...args); 76 | }); 77 | } 78 | 79 | export function batchIoOperationWithRetries( 80 | operation, maxRetries, delayMs, operationFunction, operationArgs = [] 81 | ) { 82 | const ioPromises = []; 83 | operationArgs.forEach((args) => { 84 | ioPromises.push(operationFunction(operation, maxRetries, delayMs, ...args)); 85 | }); 86 | return Promise.all(ioPromises); 87 | } 88 | -------------------------------------------------------------------------------- /skeleton/windowSettings.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-param-reassign */ 2 | 3 | import { join } from 'path'; 4 | import assignIn from 'lodash/assignIn'; 5 | 6 | export default class WindowSettings { 7 | /** 8 | * Merges window dev settings. 9 | */ 10 | static mergeWindowDevSettings(settings) { 11 | if ('windowDev' in settings) { 12 | assignIn(settings.window, settings.windowDev); 13 | } 14 | } 15 | 16 | /** 17 | * Merges window settings specific to current os. 18 | */ 19 | static mergeOsSpecificWindowSettings(settings, os) { 20 | ['windows', 'linux', 'osx'].forEach((system) => { 21 | if ( 22 | os[`is${system[0].toUpperCase()}${system.substring(1)}`] && 23 | (`_${system}`) in settings.window 24 | ) { 25 | assignIn(settings.window, settings.window[`_${system}`]); 26 | } 27 | }); 28 | } 29 | 30 | /** 31 | * Applies variables to window settings. Supported: 32 | * `@assets` - prefixes paths with current assets path 33 | * 34 | * @param {Object} windowSettings - Window settings from settings.json 35 | */ 36 | static applyVars(windowSettings, desktopPath) { 37 | Object.keys(windowSettings).forEach((key) => { 38 | if (key[0] !== '_') { 39 | if (typeof windowSettings[key] === 'object') { 40 | this.applyVars(windowSettings[key]); 41 | } else if (typeof windowSettings[key] === 'string') { 42 | if (~windowSettings[key].indexOf('@assets')) { 43 | windowSettings[key] = join( 44 | desktopPath, 45 | 'assets', 46 | windowSettings[key].replace(/@assets\//gmi, '') 47 | ); 48 | } 49 | } 50 | } 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/fixtures/.desktop/assets/dmgBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/assets/dmgBackground.png -------------------------------------------------------------------------------- /tests/fixtures/.desktop/assets/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/assets/loading.gif -------------------------------------------------------------------------------- /tests/fixtures/.desktop/assets/meteor.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/assets/meteor.icns -------------------------------------------------------------------------------- /tests/fixtures/.desktop/assets/meteor.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/assets/meteor.ico -------------------------------------------------------------------------------- /tests/fixtures/.desktop/assets/meteor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/assets/meteor.png -------------------------------------------------------------------------------- /tests/fixtures/.desktop/assets/splashScreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/assets/splashScreen.png -------------------------------------------------------------------------------- /tests/fixtures/.desktop/desktop.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import process from 'process'; 3 | import { app, dialog } from 'electron'; 4 | 5 | /** 6 | * Entry point to your native desktop code. 7 | * 8 | * @class 9 | */ 10 | export default class Desktop { 11 | /** 12 | * @param {Object} log - Winston logger instance 13 | * @param {Object} skeletonApp - reference to the skeleton app instance 14 | * @param {Object} appSettings - settings.json contents 15 | * @param {Object} eventsBus - event emitter for listening or emitting events 16 | * shared across skeleton app and every module/plugin 17 | * @param {Object} modules - references to all loaded modules 18 | * @param {Object} Module - reference to the Module class 19 | * @constructor 20 | */ 21 | constructor({ log, skeletonApp, appSettings, eventsBus, modules, Module }) { 22 | /** 23 | * You can delete unused var from the param destructuring. 24 | * Left them here just to emphasize what is passed. Delete the eslint rule at the top 25 | * when done. 26 | * You can also just have a one `config` param and do `Object.assign(this, config);` 27 | */ 28 | const desktop = new Module('desktop'); 29 | // Get the automatically predefined logger instance. 30 | this.log = log; 31 | 32 | // From Meteor use this by invoking Desktop.send('desktop', 'closeApp'); 33 | desktop.on('closeApp', () => app.quit()); 34 | 35 | // We need to handle gracefully potential problems. 36 | // Lets remove the default handler and replace it with ours. 37 | skeletonApp.removeUncaughtExceptionListener(); 38 | 39 | process.on('uncaughtException', Desktop.uncaughtExceptionHandler); 40 | 41 | // Chrome problems should also be handled. The `windowCreated` event has a `window` 42 | // reference. This is the reference to the current Electron renderer process (Chrome) 43 | // displaying your Meteor app. 44 | eventsBus.on('windowCreated', (window) => { 45 | window.webContents.on('crashed', Desktop.windowCrashedHandler); 46 | window.on('unresponsive', Desktop.windowUnresponsiveHandler); 47 | }); 48 | 49 | // Consider setting a crash reporter -> 50 | // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md 51 | } 52 | 53 | /** 54 | * Window crash handler. 55 | */ 56 | static windowCrashedHandler() { 57 | Desktop.displayRestartDialog( 58 | 'Application has crashed', 59 | 'Do you want to restart it?' 60 | ); 61 | } 62 | 63 | /** 64 | * Window's unresponsiveness handler. 65 | */ 66 | static windowUnresponsiveHandler() { 67 | Desktop.displayRestartDialog( 68 | 'Application is not responding', 69 | 'Do you want to restart it?' 70 | ); 71 | } 72 | 73 | /** 74 | * JS's uncaught exception handler. 75 | * @param {string} error - error message 76 | */ 77 | static uncaughtExceptionHandler(error) { 78 | // Consider sending a log somewhere, it is good be aware your users are having problems, 79 | // right? 80 | Desktop.displayRestartDialog( 81 | 'Application encountered an error', 82 | 'Do you want to restart it?', 83 | error 84 | ); 85 | } 86 | 87 | /** 88 | * Displays an error dialog with simple 'restart' or 'shutdown' choice. 89 | * @param {string} title - title of the dialog 90 | * @param {string} message - message shown in the dialog 91 | * @param {string} details - additional details to be displayed 92 | */ 93 | static displayRestartDialog(title, message, details = '') { 94 | dialog.showMessageBox( 95 | { type: 'error', buttons: ['Restart', 'Shutdown'], title, message, detail: details }, 96 | (response) => { 97 | if (response === 0) { 98 | app.relaunch(); 99 | } 100 | app.exit(0); 101 | } 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/fixtures/.desktop/modules/someModule/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "someModule", 3 | "dependencies": { 4 | "dependency": "1.0.1" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/fixtures/.desktop/modules/someModule/someModule.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/modules/someModule/someModule.js -------------------------------------------------------------------------------- /tests/fixtures/.desktop/modules/someModule2/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "someModule2", 3 | "dependencies": { 4 | "dependency2": "0.0.5" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/fixtures/.desktop/modules/someModule2/someModule.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/.desktop/modules/someModule2/someModule.js -------------------------------------------------------------------------------- /tests/fixtures/.desktop/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "My Meteor App", 3 | "version": "0.0.1", 4 | "projectName": "MyMeteorApp", 5 | "devTools": true, 6 | "devtron": true, 7 | "desktopHCP": true, 8 | "desktopHCPIgnoreCompatibilityVersion": false, 9 | "autoUpdateFeedUrl": "http://127.0.0.1/update/:platform/:version", 10 | "autoUpdateFeedHeaders": {}, 11 | "autoUpdateCheckOnStart": true, 12 | "rebuildNativeNodeModules": false, 13 | "webAppStartupTimeout": 60000, 14 | "window": { 15 | "icon": "@assets/meteor.png", 16 | "_windows": { 17 | "icon": "@assets/meteor.ico" 18 | } 19 | }, 20 | "windowDev": { 21 | }, 22 | "uglify": true, 23 | "plugins": { 24 | "meteor-desktop-splash-screen": { 25 | "version": "0.3.0", 26 | "windowSettings": { 27 | "width": 800, 28 | "height": 600 29 | } 30 | }, 31 | "meteor-desktop-localstorage": "0.0.11" 32 | }, 33 | "dependencies": { 34 | "some-package": "1.2.3" 35 | }, 36 | "packageJsonFields": { 37 | "description": "My Meteor App", 38 | "author": "Me, Myself And I", 39 | "private": true 40 | }, 41 | "builderOptions": { 42 | "win": { 43 | "title": "My Meteor App", 44 | "authors": "Me, Myself And I", 45 | "target": "squirrel" 46 | }, 47 | "squirrelWindows": { 48 | "iconUrl": "https://github.com/wojtkowiak/meteor-desktop/blob/beta/scaffold/assets/meteor.ico?raw=true", 49 | "loadingGif": ".desktop/assets/loading.gif" 50 | }, 51 | "icon": ".desktop/assets/meteor.ico", 52 | "appId": "meteor.app", 53 | "productName": "My Meteor App", 54 | "compression": "maximum", 55 | "mac": { 56 | "icon": ".desktop/assets/meteor.icns" 57 | }, 58 | "dmg": { 59 | "icon": ".desktop/assets/meteor.icns", 60 | "background": ".desktop/assets/dmgBackground.png", 61 | "iconSize": 54, 62 | "contents": [ 63 | { "x": 377, "y": 190, "type": "link", "path": "/Applications" }, 64 | { "x": 63, "y": 190, "type": "file" } 65 | ], 66 | "window": { 67 | "width": 480, 68 | "height": 300 69 | } 70 | } }, 71 | "packagerOptions": { 72 | "icon": ".desktop/assets/meteor.ico", 73 | "_osx": { 74 | "icon": ".desktop/assets/meteor.icns" 75 | }, 76 | "version-string": { 77 | "CompanyName": "My Company", 78 | "LegalCopyright": "Copyright 2016 My Company - All rights reserved.", 79 | "FileDescription": "MyMeteorApp", 80 | "OriginalFilename": "MyMeteorApp.exe", 81 | "FileVersion": "@version", 82 | "ProductVersion": "@version", 83 | "ProductName": "MyMeteorApp", 84 | "InternalName": "MyMeteorApp.exe" 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/.gitattributes: -------------------------------------------------------------------------------- 1 | * eol=lf 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/127.0.0.1_root_url/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "127.0.0.1_root_url", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [] 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/different_cordova_compatibility_version/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "different_cordova_compatibility_version", 4 | "cordovaCompatibilityVersions": { 5 | "android": "f9d1e65c341c1b68740d41d35250e6a8e9503236", 6 | "ios": "9a02a7998ece3cf17379eec42582b3618825dc91" 7 | }, 8 | "manifest": [ 9 | { 10 | "path": "packages/meteor.js", 11 | "where": "client", 12 | "type": "js", 13 | "cacheable": true, 14 | "url": "/packages/meteor.js?57d11a30155349aa5106f8150cee35eac5f4764c", 15 | "sourceMap": "packages/meteor.js.map", 16 | "sourceMapUrl": "/packages/57d11a30155349aa5106f8150cee35eac5f4764c.map", 17 | "size": 113991, 18 | "hash": "57d11a30155349aa5106f8150cee35eac5f4764c" 19 | }, 20 | { 21 | "path": "app/template.mobileapp.js", 22 | "where": "client", 23 | "type": "js", 24 | "cacheable": true, 25 | "url": "/app/template.mobileapp.js?979b20f66caf126704c250fbd29ce253c6cb490e", 26 | "sourceMap": "app/template.mobileapp.js.map", 27 | "sourceMapUrl": "/app/979b20f66caf126704c250fbd29ce253c6cb490e.map", 28 | "size": 578, 29 | "hash": "979b20f66caf126704c250fbd29ce253c6cb490e" 30 | }, 31 | { 32 | "path": "app/mobileapp.js", 33 | "where": "client", 34 | "type": "js", 35 | "cacheable": true, 36 | "url": "/app/mobileapp.js?6db9763f3e0f4e4cbf78111f73823043ab08e3e7", 37 | "sourceMap": "app/mobileapp.js.map", 38 | "sourceMapUrl": "/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map", 39 | "size": 2275, 40 | "hash": "6db9763f3e0f4e4cbf78111f73823043ab08e3e7" 41 | }, 42 | { 43 | "path": "merged-stylesheets.css", 44 | "where": "client", 45 | "type": "css", 46 | "cacheable": true, 47 | "url": "/merged-stylesheets.css?20ae2c8d51b2507244e598844414ecdec2615ce3", 48 | "sourceMap": "merged-stylesheets.css.map", 49 | "sourceMapUrl": "/20ae2c8d51b2507244e598844414ecdec2615ce3.map", 50 | "size": 30, 51 | "hash": "20ae2c8d51b2507244e598844414ecdec2615ce3" 52 | }, 53 | { 54 | "path": "app/some-data.json", 55 | "where": "client", 56 | "type": "asset", 57 | "cacheable": false, 58 | "url": "/some-data.json", 59 | "size": 15, 60 | "hash": "3edc8875bc0dd76d9f5fce5e823dca6f17a26da7" 61 | }, 62 | { 63 | "path": "app/some-file", 64 | "where": "client", 65 | "type": "asset", 66 | "cacheable": false, 67 | "url": "/some-file", 68 | "size": 10, 69 | "hash": "23300652a57f3e819038d9a268ba36af0e25d33b" 70 | }, 71 | { 72 | "path": "app/some-font.woff", 73 | "where": "client", 74 | "type": "asset", 75 | "cacheable": false, 76 | "url": "/some-font.woff", 77 | "size": 15, 78 | "hash": "6ec7e1e1c0199bfb5bcd6877de9fe7abefd26df8" 79 | }, 80 | { 81 | "path": "app/some-image.jpg", 82 | "where": "client", 83 | "type": "asset", 84 | "cacheable": false, 85 | "url": "/some-image.jpg", 86 | "size": 15, 87 | "hash": "13f1d459365d5604dbf2b64b203fa583c1c7fc3f" 88 | }, 89 | { 90 | "path": "app/some-image.png", 91 | "where": "client", 92 | "type": "asset", 93 | "cacheable": false, 94 | "url": "/some-image.png", 95 | "size": 15, 96 | "hash": "06b05b4c2720cd9ff733d21c594eac4e865a6e73" 97 | }, 98 | { 99 | "path": "app/some-javascript.js", 100 | "where": "client", 101 | "type": "asset", 102 | "cacheable": false, 103 | "url": "/some-javascript.js", 104 | "size": 19, 105 | "hash": "51a3422f25ddf466a35e00e327d5f4ca90eee8f4" 106 | }, 107 | { 108 | "path": "app/some-page.html", 109 | "where": "client", 110 | "type": "asset", 111 | "cacheable": false, 112 | "url": "/some-page.html", 113 | "size": 15, 114 | "hash": "5dc6878863a1fd4f7f69713b4c072280932255af" 115 | }, 116 | { 117 | "path": "app/some-stylesheet.css", 118 | "where": "client", 119 | "type": "asset", 120 | "cacheable": false, 121 | "url": "/some-stylesheet.css", 122 | "size": 20, 123 | "hash": "b33cc1bdaa963ae1cec9afd4c833d80caf7641a2" 124 | }, 125 | { 126 | "path": "app/some-text.txt", 127 | "where": "client", 128 | "type": "asset", 129 | "cacheable": false, 130 | "url": "/some-text.txt", 131 | "size": 14, 132 | "hash": "bb874a02400d28518a3d0f7a4c7fd8970735bea1" 133 | }, 134 | { 135 | "path": "app/some-video.mp4", 136 | "where": "client", 137 | "type": "asset", 138 | "cacheable": false, 139 | "url": "/some-video.mp4", 140 | "size": 15, 141 | "hash": "45e892d4c7ce693f5cd551fcd671cf227ff1ae3a" 142 | }, 143 | { 144 | "path": "head.html", 145 | "where": "internal", 146 | "type": "head", 147 | "hash": "2ce23f770b76d2f1cb0d71f4a43fbbb61afb25be" 148 | } 149 | ] 150 | } 151 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/missing_app_id/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "missing_app_id", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [] 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/missing_cordova_compatibility_version/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "missing_cordova_compatibility_version", 4 | "manifest": [ 5 | { 6 | "path": "packages/meteor.js", 7 | "where": "client", 8 | "type": "js", 9 | "cacheable": true, 10 | "url": "/packages/meteor.js?57d11a30155349aa5106f8150cee35eac5f4764c", 11 | "sourceMap": "packages/meteor.js.map", 12 | "sourceMapUrl": "/packages/57d11a30155349aa5106f8150cee35eac5f4764c.map", 13 | "size": 113991, 14 | "hash": "57d11a30155349aa5106f8150cee35eac5f4764c" 15 | }, 16 | { 17 | "path": "app/template.mobileapp.js", 18 | "where": "client", 19 | "type": "js", 20 | "cacheable": true, 21 | "url": "/app/template.mobileapp.js?979b20f66caf126704c250fbd29ce253c6cb490e", 22 | "sourceMap": "app/template.mobileapp.js.map", 23 | "sourceMapUrl": "/app/979b20f66caf126704c250fbd29ce253c6cb490e.map", 24 | "size": 578, 25 | "hash": "979b20f66caf126704c250fbd29ce253c6cb490e" 26 | }, 27 | { 28 | "path": "app/mobileapp.js", 29 | "where": "client", 30 | "type": "js", 31 | "cacheable": true, 32 | "url": "/app/mobileapp.js?6db9763f3e0f4e4cbf78111f73823043ab08e3e7", 33 | "sourceMap": "app/mobileapp.js.map", 34 | "sourceMapUrl": "/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map", 35 | "size": 2275, 36 | "hash": "6db9763f3e0f4e4cbf78111f73823043ab08e3e7" 37 | }, 38 | { 39 | "path": "merged-stylesheets.css", 40 | "where": "client", 41 | "type": "css", 42 | "cacheable": true, 43 | "url": "/merged-stylesheets.css?20ae2c8d51b2507244e598844414ecdec2615ce3", 44 | "sourceMap": "merged-stylesheets.css.map", 45 | "sourceMapUrl": "/20ae2c8d51b2507244e598844414ecdec2615ce3.map", 46 | "size": 30, 47 | "hash": "20ae2c8d51b2507244e598844414ecdec2615ce3" 48 | }, 49 | { 50 | "path": "app/some-data.json", 51 | "where": "client", 52 | "type": "asset", 53 | "cacheable": false, 54 | "url": "/some-data.json", 55 | "size": 15, 56 | "hash": "3edc8875bc0dd76d9f5fce5e823dca6f17a26da7" 57 | }, 58 | { 59 | "path": "app/some-file", 60 | "where": "client", 61 | "type": "asset", 62 | "cacheable": false, 63 | "url": "/some-file", 64 | "size": 10, 65 | "hash": "23300652a57f3e819038d9a268ba36af0e25d33b" 66 | }, 67 | { 68 | "path": "app/some-font.woff", 69 | "where": "client", 70 | "type": "asset", 71 | "cacheable": false, 72 | "url": "/some-font.woff", 73 | "size": 15, 74 | "hash": "6ec7e1e1c0199bfb5bcd6877de9fe7abefd26df8" 75 | }, 76 | { 77 | "path": "app/some-image.jpg", 78 | "where": "client", 79 | "type": "asset", 80 | "cacheable": false, 81 | "url": "/some-image.jpg", 82 | "size": 15, 83 | "hash": "13f1d459365d5604dbf2b64b203fa583c1c7fc3f" 84 | }, 85 | { 86 | "path": "app/some-image.png", 87 | "where": "client", 88 | "type": "asset", 89 | "cacheable": false, 90 | "url": "/some-image.png", 91 | "size": 15, 92 | "hash": "06b05b4c2720cd9ff733d21c594eac4e865a6e73" 93 | }, 94 | { 95 | "path": "app/some-javascript.js", 96 | "where": "client", 97 | "type": "asset", 98 | "cacheable": false, 99 | "url": "/some-javascript.js", 100 | "size": 19, 101 | "hash": "51a3422f25ddf466a35e00e327d5f4ca90eee8f4" 102 | }, 103 | { 104 | "path": "app/some-page.html", 105 | "where": "client", 106 | "type": "asset", 107 | "cacheable": false, 108 | "url": "/some-page.html", 109 | "size": 15, 110 | "hash": "5dc6878863a1fd4f7f69713b4c072280932255af" 111 | }, 112 | { 113 | "path": "app/some-stylesheet.css", 114 | "where": "client", 115 | "type": "asset", 116 | "cacheable": false, 117 | "url": "/some-stylesheet.css", 118 | "size": 20, 119 | "hash": "b33cc1bdaa963ae1cec9afd4c833d80caf7641a2" 120 | }, 121 | { 122 | "path": "app/some-text.txt", 123 | "where": "client", 124 | "type": "asset", 125 | "cacheable": false, 126 | "url": "/some-text.txt", 127 | "size": 14, 128 | "hash": "bb874a02400d28518a3d0f7a4c7fd8970735bea1" 129 | }, 130 | { 131 | "path": "app/some-video.mp4", 132 | "where": "client", 133 | "type": "asset", 134 | "cacheable": false, 135 | "url": "/some-video.mp4", 136 | "size": 15, 137 | "hash": "45e892d4c7ce693f5cd551fcd671cf227ff1ae3a" 138 | }, 139 | { 140 | "path": "head.html", 141 | "where": "internal", 142 | "type": "head", 143 | "hash": "2ce23f770b76d2f1cb0d71f4a43fbbb61afb25be" 144 | } 145 | ] 146 | } 147 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/missing_root_url/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "missing_root_url", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [] 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/979b20f66caf126704c250fbd29ce253c6cb490e.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"<h1>Welcome to Meteor!</h1>\\n\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"<button>Click Me</button>\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/not-in-manifest: -------------------------------------------------------------------------------- 1 | not-in-manifest 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-file: -------------------------------------------------------------------------------- 1 | some-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/app/template.mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | Template.body.addContent((function() { 3 | var view = this; 4 | return [ HTML.Raw("<h1>Welcome to Meteor!</h1>\n\n "), Spacebars.include(view.lookupTemplate("hello")) ]; 5 | })); 6 | Meteor.startup(Template.body.renderToDocument); 7 | 8 | Template.__checkName("hello"); 9 | Template["hello"] = new Template("Template.hello", (function() { 10 | var view = this; 11 | return [ HTML.Raw("<button>Click Me</button>\n "), HTML.P("You've pressed the button ", Blaze.View("lookup:counter", function() { 12 | return Spacebars.mustache(view.lookup("counter")); 13 | }), " times.") ]; 14 | })); 15 | 16 | }).call(this); 17 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/head.html: -------------------------------------------------------------------------------- 1 | <title>mobileapp -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "version1", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [ 9 | { 10 | "path": "packages/meteor.js", 11 | "where": "client", 12 | "type": "js", 13 | "cacheable": true, 14 | "url": "/packages/meteor.js?57d11a30155349aa5106f8150cee35eac5f4764c", 15 | "sourceMap": "packages/meteor.js.map", 16 | "sourceMapUrl": "/packages/57d11a30155349aa5106f8150cee35eac5f4764c.map", 17 | "size": 113991, 18 | "hash": "57d11a30155349aa5106f8150cee35eac5f4764c" 19 | }, 20 | { 21 | "path": "app/template.mobileapp.js", 22 | "where": "client", 23 | "type": "js", 24 | "cacheable": true, 25 | "url": "/app/template.mobileapp.js?979b20f66caf126704c250fbd29ce253c6cb490e", 26 | "sourceMap": "app/template.mobileapp.js.map", 27 | "sourceMapUrl": "/app/979b20f66caf126704c250fbd29ce253c6cb490e.map", 28 | "size": 578, 29 | "hash": "979b20f66caf126704c250fbd29ce253c6cb490e" 30 | }, 31 | { 32 | "path": "app/mobileapp.js", 33 | "where": "client", 34 | "type": "js", 35 | "cacheable": true, 36 | "url": "/app/mobileapp.js?6db9763f3e0f4e4cbf78111f73823043ab08e3e7", 37 | "sourceMap": "app/mobileapp.js.map", 38 | "sourceMapUrl": "/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map", 39 | "size": 2275, 40 | "hash": "6db9763f3e0f4e4cbf78111f73823043ab08e3e7" 41 | }, 42 | { 43 | "path": "merged-stylesheets.css", 44 | "where": "client", 45 | "type": "css", 46 | "cacheable": true, 47 | "url": "/merged-stylesheets.css?20ae2c8d51b2507244e598844414ecdec2615ce3", 48 | "sourceMap": "merged-stylesheets.css.map", 49 | "sourceMapUrl": "/20ae2c8d51b2507244e598844414ecdec2615ce3.map", 50 | "size": 30, 51 | "hash": "20ae2c8d51b2507244e598844414ecdec2615ce3" 52 | }, 53 | { 54 | "path": "app/some-data.json", 55 | "where": "client", 56 | "type": "asset", 57 | "cacheable": false, 58 | "url": "/some-data.json", 59 | "size": 15, 60 | "hash": "3edc8875bc0dd76d9f5fce5e823dca6f17a26da7" 61 | }, 62 | { 63 | "path": "app/some-file", 64 | "where": "client", 65 | "type": "asset", 66 | "cacheable": false, 67 | "url": "/some-file", 68 | "size": 10, 69 | "hash": "23300652a57f3e819038d9a268ba36af0e25d33b" 70 | }, 71 | { 72 | "path": "app/some-font.woff", 73 | "where": "client", 74 | "type": "asset", 75 | "cacheable": false, 76 | "url": "/some-font.woff", 77 | "size": 15, 78 | "hash": "6ec7e1e1c0199bfb5bcd6877de9fe7abefd26df8" 79 | }, 80 | { 81 | "path": "app/some-image.jpg", 82 | "where": "client", 83 | "type": "asset", 84 | "cacheable": false, 85 | "url": "/some-image.jpg", 86 | "size": 15, 87 | "hash": "13f1d459365d5604dbf2b64b203fa583c1c7fc3f" 88 | }, 89 | { 90 | "path": "app/some-image.png", 91 | "where": "client", 92 | "type": "asset", 93 | "cacheable": false, 94 | "url": "/some-image.png", 95 | "size": 15, 96 | "hash": "06b05b4c2720cd9ff733d21c594eac4e865a6e73" 97 | }, 98 | { 99 | "path": "app/some-javascript.js", 100 | "where": "client", 101 | "type": "asset", 102 | "cacheable": false, 103 | "url": "/some-javascript.js", 104 | "size": 19, 105 | "hash": "51a3422f25ddf466a35e00e327d5f4ca90eee8f4" 106 | }, 107 | { 108 | "path": "app/some-page.html", 109 | "where": "client", 110 | "type": "asset", 111 | "cacheable": false, 112 | "url": "/some-page.html", 113 | "size": 15, 114 | "hash": "5dc6878863a1fd4f7f69713b4c072280932255af" 115 | }, 116 | { 117 | "path": "app/some-stylesheet.css", 118 | "where": "client", 119 | "type": "asset", 120 | "cacheable": false, 121 | "url": "/some-stylesheet.css", 122 | "size": 20, 123 | "hash": "b33cc1bdaa963ae1cec9afd4c833d80caf7641a2" 124 | }, 125 | { 126 | "path": "app/some-text.txt", 127 | "where": "client", 128 | "type": "asset", 129 | "cacheable": false, 130 | "url": "/some-text.txt", 131 | "size": 14, 132 | "hash": "bb874a02400d28518a3d0f7a4c7fd8970735bea1" 133 | }, 134 | { 135 | "path": "app/some-video.mp4", 136 | "where": "client", 137 | "type": "asset", 138 | "cacheable": false, 139 | "url": "/some-video.mp4", 140 | "size": 15, 141 | "hash": "45e892d4c7ce693f5cd551fcd671cf227ff1ae3a" 142 | }, 143 | { 144 | "path": "head.html", 145 | "where": "internal", 146 | "type": "head", 147 | "hash": "2ce23f770b76d2f1cb0d71f4a43fbbb61afb25be" 148 | } 149 | ] 150 | } 151 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version1/merged-stylesheets.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/20ae2c8d51b2507244e598844414ecdec2615ce3.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/3f6275657e6db3a21acb37d0f6c207cf83871e90.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"

Welcome to Meteor (again)!

\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-file: -------------------------------------------------------------------------------- 1 | some-file (changed) 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-other-file: -------------------------------------------------------------------------------- 1 | some-other-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/app/template.mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | Template.body.addContent((function() { 3 | var view = this; 4 | return [ HTML.Raw("

Welcome to Meteor (again)!

\n "), Spacebars.include(view.lookupTemplate("hello")) ]; 5 | })); 6 | Meteor.startup(Template.body.renderToDocument); 7 | 8 | Template.__checkName("hello"); 9 | Template["hello"] = new Template("Template.hello", (function() { 10 | var view = this; 11 | return [ HTML.Raw("\n "), HTML.P("You've pressed the button ", Blaze.View("lookup:counter", function() { 12 | return Spacebars.mustache(view.lookup("counter")); 13 | }), " times.") ]; 14 | })); 15 | 16 | }).call(this); 17 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/head.html: -------------------------------------------------------------------------------- 1 | mobileapp -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "version2", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [ 9 | { 10 | "path": "packages/meteor.js", 11 | "where": "client", 12 | "type": "js", 13 | "cacheable": true, 14 | "url": "/packages/meteor.js?57d11a30155349aa5106f8150cee35eac5f4764c", 15 | "sourceMap": "packages/meteor.js.map", 16 | "sourceMapUrl": "/packages/57d11a30155349aa5106f8150cee35eac5f4764c.map", 17 | "size": 113991, 18 | "hash": "57d11a30155349aa5106f8150cee35eac5f4764c" 19 | }, 20 | { 21 | "path": "app/template.mobileapp.js", 22 | "where": "client", 23 | "type": "js", 24 | "cacheable": true, 25 | "url": "/app/template.mobileapp.js?3f6275657e6db3a21acb37d0f6c207cf83871e90", 26 | "sourceMap": "app/template.mobileapp.js.map", 27 | "sourceMapUrl": "/app/3f6275657e6db3a21acb37d0f6c207cf83871e90.map", 28 | "size": 584, 29 | "hash": "3f6275657e6db3a21acb37d0f6c207cf83871e90" 30 | }, 31 | { 32 | "path": "app/mobileapp.js", 33 | "where": "client", 34 | "type": "js", 35 | "cacheable": true, 36 | "url": "/app/mobileapp.js?6db9763f3e0f4e4cbf78111f73823043ab08e3e7", 37 | "sourceMap": "app/mobileapp.js.map", 38 | "sourceMapUrl": "/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map", 39 | "size": 2275, 40 | "hash": "6db9763f3e0f4e4cbf78111f73823043ab08e3e7" 41 | }, 42 | { 43 | "path": "merged-stylesheets.css", 44 | "where": "client", 45 | "type": "css", 46 | "cacheable": true, 47 | "url": "/merged-stylesheets.css?20ae2c8d51b2507244e598844414ecdec2615ce3", 48 | "sourceMap": "merged-stylesheets.css.map", 49 | "sourceMapUrl": "/20ae2c8d51b2507244e598844414ecdec2615ce3.map", 50 | "size": 30, 51 | "hash": "20ae2c8d51b2507244e598844414ecdec2615ce3" 52 | }, 53 | { 54 | "path": "app/some-data.json", 55 | "where": "client", 56 | "type": "asset", 57 | "cacheable": false, 58 | "url": "/some-data.json", 59 | "size": 15, 60 | "hash": "3edc8875bc0dd76d9f5fce5e823dca6f17a26da7" 61 | }, 62 | { 63 | "path": "app/some-file", 64 | "where": "client", 65 | "type": "asset", 66 | "cacheable": false, 67 | "url": "/some-file", 68 | "size": 20, 69 | "hash": "20242aa2ac9c728ca21c7cbbee841fd87e8277aa" 70 | }, 71 | { 72 | "path": "app/some-other-file", 73 | "where": "client", 74 | "type": "asset", 75 | "cacheable": false, 76 | "url": "/some-other-file", 77 | "size": 16, 78 | "hash": "aa4405bb6a2eb7d79af8488b44d91e5c66c123a5" 79 | }, 80 | { 81 | "path": "app/some-font.woff", 82 | "where": "client", 83 | "type": "asset", 84 | "cacheable": false, 85 | "url": "/some-font.woff", 86 | "size": 15, 87 | "hash": "6ec7e1e1c0199bfb5bcd6877de9fe7abefd26df8" 88 | }, 89 | { 90 | "path": "app/some-image.jpg", 91 | "where": "client", 92 | "type": "asset", 93 | "cacheable": false, 94 | "url": "/some-image.jpg", 95 | "size": 15, 96 | "hash": "13f1d459365d5604dbf2b64b203fa583c1c7fc3f" 97 | }, 98 | { 99 | "path": "app/some-image.png", 100 | "where": "client", 101 | "type": "asset", 102 | "cacheable": false, 103 | "url": "/some-image.png", 104 | "size": 15, 105 | "hash": "06b05b4c2720cd9ff733d21c594eac4e865a6e73" 106 | }, 107 | { 108 | "path": "app/some-javascript.js", 109 | "where": "client", 110 | "type": "asset", 111 | "cacheable": false, 112 | "url": "/some-javascript.js", 113 | "size": 19, 114 | "hash": "51a3422f25ddf466a35e00e327d5f4ca90eee8f4" 115 | }, 116 | { 117 | "path": "app/some-page.html", 118 | "where": "client", 119 | "type": "asset", 120 | "cacheable": false, 121 | "url": "/some-page.html", 122 | "size": 15, 123 | "hash": "5dc6878863a1fd4f7f69713b4c072280932255af" 124 | }, 125 | { 126 | "path": "app/some-stylesheet.css", 127 | "where": "client", 128 | "type": "asset", 129 | "cacheable": false, 130 | "url": "/some-stylesheet.css", 131 | "size": 20, 132 | "hash": "b33cc1bdaa963ae1cec9afd4c833d80caf7641a2" 133 | }, 134 | { 135 | "path": "app/some-text.txt", 136 | "where": "client", 137 | "type": "asset", 138 | "cacheable": false, 139 | "url": "/some-text.txt", 140 | "size": 14, 141 | "hash": "bb874a02400d28518a3d0f7a4c7fd8970735bea1" 142 | }, 143 | { 144 | "path": "app/some-video.mp4", 145 | "where": "client", 146 | "type": "asset", 147 | "cacheable": false, 148 | "url": "/some-video.mp4", 149 | "size": 15, 150 | "hash": "45e892d4c7ce693f5cd551fcd671cf227ff1ae3a" 151 | }, 152 | { 153 | "path": "head.html", 154 | "where": "internal", 155 | "type": "head", 156 | "hash": "2ce23f770b76d2f1cb0d71f4a43fbbb61afb25be" 157 | } 158 | ] 159 | } 160 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/20ae2c8d51b2507244e598844414ecdec2615ce3.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/3f6275657e6db3a21acb37d0f6c207cf83871e90.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"

Welcome to Meteor (again)!

\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-file: -------------------------------------------------------------------------------- 1 | some-file (changed) 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-other-file: -------------------------------------------------------------------------------- 1 | some-other-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/app/template.mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | Template.body.addContent((function() { 3 | var view = this; 4 | return [ HTML.Raw("

Welcome to Meteor (one more time)!

\n "), Spacebars.include(view.lookupTemplate("hello")) ]; 5 | })); 6 | Meteor.startup(Template.body.renderToDocument); 7 | 8 | Template.__checkName("hello"); 9 | Template["hello"] = new Template("Template.hello", (function() { 10 | var view = this; 11 | return [ HTML.Raw("\n "), HTML.P("You've pressed the button ", Blaze.View("lookup:counter", function() { 12 | return Spacebars.mustache(view.lookup("counter")); 13 | }), " times.") ]; 14 | })); 15 | 16 | }).call(this); 17 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/head.html: -------------------------------------------------------------------------------- 1 | mobileapp -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_invalid_asset/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/20ae2c8d51b2507244e598844414ecdec2615ce3.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/3f6275657e6db3a21acb37d0f6c207cf83871e90.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"

Welcome to Meteor (again)!

\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-file: -------------------------------------------------------------------------------- 1 | some-file (changed) 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-other-file: -------------------------------------------------------------------------------- 1 | some-other-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/head.html: -------------------------------------------------------------------------------- 1 | mobileapp -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_missing_asset/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/20ae2c8d51b2507244e598844414ecdec2615ce3.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/3f6275657e6db3a21acb37d0f6c207cf83871e90.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"

Welcome to Meteor (again)!

\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-file: -------------------------------------------------------------------------------- 1 | some-file (changed) 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-other-file: -------------------------------------------------------------------------------- 1 | some-other-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/app/template.mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | Template.body.addContent((function() { 3 | var view = this; 4 | return [ HTML.Raw("

Welcome to Meteor (again)!

\n "), Spacebars.include(view.lookupTemplate("hello")) ]; 5 | })); 6 | Meteor.startup(Template.body.renderToDocument); 7 | 8 | Template.__checkName("hello"); 9 | Template["hello"] = new Template("Template.hello", (function() { 10 | var view = this; 11 | return [ HTML.Raw("\n "), HTML.P("You've pressed the button ", Blaze.View("lookup:counter", function() { 12 | return Spacebars.mustache(view.lookup("counter")); 13 | }), " times.") ]; 14 | })); 15 | 16 | }).call(this); 17 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/head.html: -------------------------------------------------------------------------------- 1 | mobileapp -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version2_with_version_mismatch/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/20ae2c8d51b2507244e598844414ecdec2615ce3.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/36e96c1d40459ae12164569599c9c0a203b36db7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"

Welcome to Meteor (one more time)!

\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-file: -------------------------------------------------------------------------------- 1 | some-file (changed again) 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-other-file: -------------------------------------------------------------------------------- 1 | some-other-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/app/template.mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | Template.body.addContent((function() { 3 | var view = this; 4 | return [ HTML.Raw("

Welcome to Meteor (one more time)!

\n "), Spacebars.include(view.lookupTemplate("hello")) ]; 5 | })); 6 | Meteor.startup(Template.body.renderToDocument); 7 | 8 | Template.__checkName("hello"); 9 | Template["hello"] = new Template("Template.hello", (function() { 10 | var view = this; 11 | return [ HTML.Raw("\n "), HTML.P("You've pressed the button ", Blaze.View("lookup:counter", function() { 12 | return Spacebars.mustache(view.lookup("counter")); 13 | }), " times.") ]; 14 | })); 15 | 16 | }).call(this); 17 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/head.html: -------------------------------------------------------------------------------- 1 | mobileapp -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "version3", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [ 9 | { 10 | "path": "packages/meteor.js", 11 | "where": "client", 12 | "type": "js", 13 | "cacheable": true, 14 | "url": "/packages/meteor.js?57d11a30155349aa5106f8150cee35eac5f4764c", 15 | "sourceMap": "packages/meteor.js.map", 16 | "sourceMapUrl": "/packages/57d11a30155349aa5106f8150cee35eac5f4764c.map", 17 | "size": 113991, 18 | "hash": "57d11a30155349aa5106f8150cee35eac5f4764c" 19 | }, 20 | { 21 | "path": "app/template.mobileapp.js", 22 | "where": "client", 23 | "type": "js", 24 | "cacheable": true, 25 | "url": "/app/template.mobileapp.js?36e96c1d40459ae12164569599c9c0a203b36db7", 26 | "sourceMap": "app/template.mobileapp.js.map", 27 | "sourceMapUrl": "/app/36e96c1d40459ae12164569599c9c0a203b36db7.map", 28 | "size": 592, 29 | "hash": "36e96c1d40459ae12164569599c9c0a203b36db7" 30 | }, 31 | { 32 | "path": "app/mobileapp.js", 33 | "where": "client", 34 | "type": "js", 35 | "cacheable": true, 36 | "url": "/app/mobileapp.js?6db9763f3e0f4e4cbf78111f73823043ab08e3e7", 37 | "sourceMap": "app/mobileapp.js.map", 38 | "sourceMapUrl": "/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map", 39 | "size": 2275, 40 | "hash": "6db9763f3e0f4e4cbf78111f73823043ab08e3e7" 41 | }, 42 | { 43 | "path": "merged-stylesheets.css", 44 | "where": "client", 45 | "type": "css", 46 | "cacheable": true, 47 | "url": "/merged-stylesheets.css?20ae2c8d51b2507244e598844414ecdec2615ce3", 48 | "sourceMap": "merged-stylesheets.css.map", 49 | "sourceMapUrl": "/20ae2c8d51b2507244e598844414ecdec2615ce3.map", 50 | "size": 30, 51 | "hash": "20ae2c8d51b2507244e598844414ecdec2615ce3" 52 | }, 53 | { 54 | "path": "app/some-data.json", 55 | "where": "client", 56 | "type": "asset", 57 | "cacheable": false, 58 | "url": "/some-data.json", 59 | "size": 15, 60 | "hash": "3edc8875bc0dd76d9f5fce5e823dca6f17a26da7" 61 | }, 62 | { 63 | "path": "app/some-file", 64 | "where": "client", 65 | "type": "asset", 66 | "cacheable": false, 67 | "url": "/some-file", 68 | "size": 26, 69 | "hash": "eb436b5a9ae39f7b8faef931024a86b73729da9e" 70 | }, 71 | { 72 | "path": "app/some-other-file", 73 | "where": "client", 74 | "type": "asset", 75 | "cacheable": false, 76 | "url": "/some-other-file", 77 | "size": 16, 78 | "hash": "aa4405bb6a2eb7d79af8488b44d91e5c66c123a5" 79 | }, 80 | { 81 | "path": "app/some-font.woff", 82 | "where": "client", 83 | "type": "asset", 84 | "cacheable": false, 85 | "url": "/some-font.woff", 86 | "size": 15, 87 | "hash": "6ec7e1e1c0199bfb5bcd6877de9fe7abefd26df8" 88 | }, 89 | { 90 | "path": "app/some-image.jpg", 91 | "where": "client", 92 | "type": "asset", 93 | "cacheable": false, 94 | "url": "/some-image.jpg", 95 | "size": 15, 96 | "hash": "13f1d459365d5604dbf2b64b203fa583c1c7fc3f" 97 | }, 98 | { 99 | "path": "app/some-image.png", 100 | "where": "client", 101 | "type": "asset", 102 | "cacheable": false, 103 | "url": "/some-image.png", 104 | "size": 15, 105 | "hash": "06b05b4c2720cd9ff733d21c594eac4e865a6e73" 106 | }, 107 | { 108 | "path": "app/some-javascript.js", 109 | "where": "client", 110 | "type": "asset", 111 | "cacheable": false, 112 | "url": "/some-javascript.js", 113 | "size": 19, 114 | "hash": "51a3422f25ddf466a35e00e327d5f4ca90eee8f4" 115 | }, 116 | { 117 | "path": "app/some-page.html", 118 | "where": "client", 119 | "type": "asset", 120 | "cacheable": false, 121 | "url": "/some-page.html", 122 | "size": 15, 123 | "hash": "5dc6878863a1fd4f7f69713b4c072280932255af" 124 | }, 125 | { 126 | "path": "app/some-stylesheet.css", 127 | "where": "client", 128 | "type": "asset", 129 | "cacheable": false, 130 | "url": "/some-stylesheet.css", 131 | "size": 20, 132 | "hash": "b33cc1bdaa963ae1cec9afd4c833d80caf7641a2" 133 | }, 134 | { 135 | "path": "app/some-text.txt", 136 | "where": "client", 137 | "type": "asset", 138 | "cacheable": false, 139 | "url": "/some-text.txt", 140 | "size": 14, 141 | "hash": "bb874a02400d28518a3d0f7a4c7fd8970735bea1" 142 | }, 143 | { 144 | "path": "app/some-video.mp4", 145 | "where": "client", 146 | "type": "asset", 147 | "cacheable": false, 148 | "url": "/some-video.mp4", 149 | "size": 15, 150 | "hash": "45e892d4c7ce693f5cd551fcd671cf227ff1ae3a" 151 | }, 152 | { 153 | "path": "head.html", 154 | "where": "internal", 155 | "type": "head", 156 | "hash": "2ce23f770b76d2f1cb0d71f4a43fbbb61afb25be" 157 | } 158 | ] 159 | } 160 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/version3/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/wrong_app_id/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "wrong_app_id", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [] 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/downloadableVersions/wrong_root_url/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "wrong_root_url", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [] 9 | } 10 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/partiallyDownloadedVersions/version2/app/some-file: -------------------------------------------------------------------------------- 1 | some-file (changed) 2 | -------------------------------------------------------------------------------- /tests/fixtures/autoUpdate/partiallyDownloadedVersions/version2/app/some-other-file: -------------------------------------------------------------------------------- 1 | some-other-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | ///////////////////////////////////////////////////////////////////////// 4 | // // 5 | // mobileapp.js // 6 | // // 7 | ///////////////////////////////////////////////////////////////////////// 8 | // 9 | if (Meteor.isClient) { // 1 10 | // counter starts at 0 // 11 | Session.setDefault('counter', 0); // 3 12 | // 13 | Template.hello.helpers({ // 5 14 | counter: function () { // 6 15 | return Session.get('counter'); // 7 16 | } // 17 | }); // 18 | // 19 | Template.hello.events({ // 11 20 | 'click button': function () { // 12 21 | // increment the counter when button is clicked // 22 | Session.set('counter', Session.get('counter') + 1); // 14 23 | } // 24 | }); // 25 | } // 26 | // 27 | if (Meteor.isServer) { // 19 28 | Meteor.startup(function () { // 20 29 | // code to run on server at startup // 30 | }); // 31 | } // 32 | ///////////////////////////////////////////////////////////////////////// 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/mobileapp.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/mobileapp.js"],"names":[],"mappings":";;;;;;;;AAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;;AAEnB,SAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;;AAEjC,UAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;AACrB,WAAO,EAAE,YAAY;AACnB,aAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;KAC/B;GACF,CAAC,CAAC;;AAEH,UAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpB,kBAAc,EAAE,YAAY;;AAE1B,aAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;KACpD;GACF,CAAC,CAAC;CACJ;;AAED,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAM,CAAC,OAAO,CAAC,YAAY;;GAE1B,CAAC,CAAC;CACJ,wE","file":"/mobileapp.js","sourcesContent":["if (Meteor.isClient) {\n // counter starts at 0\n Session.setDefault('counter', 0);\n\n Template.hello.helpers({\n counter: function () {\n return Session.get('counter');\n }\n });\n\n Template.hello.events({\n 'click button': function () {\n // increment the counter when button is clicked\n Session.set('counter', Session.get('counter') + 1);\n }\n });\n}\n\nif (Meteor.isServer) {\n Meteor.startup(function () {\n // code to run on server at startup\n });\n}\n"]} -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-data.json: -------------------------------------------------------------------------------- 1 | some-data.json 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-file: -------------------------------------------------------------------------------- 1 | some-file 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-font.woff: -------------------------------------------------------------------------------- 1 | some-font.woff 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-image.jpg: -------------------------------------------------------------------------------- 1 | some-image.jpg 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-image.png: -------------------------------------------------------------------------------- 1 | some-image.png 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-javascript.js: -------------------------------------------------------------------------------- 1 | some-javascript.js 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-page.html: -------------------------------------------------------------------------------- 1 | some-page.html 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-stylesheet.css: -------------------------------------------------------------------------------- 1 | some-stylesheet.css 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-text.txt: -------------------------------------------------------------------------------- 1 | some-text.txt 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/some-video.mp4: -------------------------------------------------------------------------------- 1 | some-video.mp4 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/template.mobileapp.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | Template.body.addContent((function() { 3 | var view = this; 4 | return [ HTML.Raw("

Welcome to Meteor!

\n\n "), Spacebars.include(view.lookupTemplate("hello")) ]; 5 | })); 6 | Meteor.startup(Template.body.renderToDocument); 7 | 8 | Template.__checkName("hello"); 9 | Template["hello"] = new Template("Template.hello", (function() { 10 | var view = this; 11 | return [ HTML.Raw("\n "), HTML.P("You've pressed the button ", Blaze.View("lookup:counter", function() { 12 | return Spacebars.mustache(view.lookup("counter")); 13 | }), " times.") ]; 14 | })); 15 | 16 | }).call(this); 17 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/app/template.mobileapp.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/template.mobileapp.js"],"names":[],"mappings":"YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/template.mobileapp.js","sourcesContent":["\nTemplate.body.addContent((function() {\n var view = this;\n return [ HTML.Raw(\"

Welcome to Meteor!

\\n\\n \"), Spacebars.include(view.lookupTemplate(\"hello\")) ];\n}));\nMeteor.startup(Template.body.renderToDocument);\n\nTemplate.__checkName(\"hello\");\nTemplate[\"hello\"] = new Template(\"Template.hello\", (function() {\n var view = this;\n return [ HTML.Raw(\"\\n \"), HTML.P(\"You've pressed the button \", Blaze.View(\"lookup:counter\", function() {\n return Spacebars.mustache(view.lookup(\"counter\"));\n }), \" times.\") ];\n}));\n"]} -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/head.html: -------------------------------------------------------------------------------- 1 | mobileapp -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/merged-stylesheets.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/merged-stylesheets.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["meteor://💻app/app/mobileapp.css"],"names":[],"mappings":"AAAA","sourcesContent":["/* CSS declarations go here */\n"]} -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/not-in-manifest: -------------------------------------------------------------------------------- 1 | not-in-manifest 2 | -------------------------------------------------------------------------------- /tests/fixtures/localServer/bundledWww/program.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "web-program-pre1", 3 | "version": "version1", 4 | "cordovaCompatibilityVersions": { 5 | "android": "4017747ca6b4f460f33b121e439b7a11a070205a", 6 | "ios": "0abe549f2adbcf6cd295428aefea628ebe69666a" 7 | }, 8 | "manifest": [ 9 | { 10 | "path": "packages/meteor.js", 11 | "where": "client", 12 | "type": "js", 13 | "cacheable": true, 14 | "url": "/packages/meteor.js?57d11a30155349aa5106f8150cee35eac5f4764c", 15 | "sourceMap": "packages/meteor.js.map", 16 | "sourceMapUrl": "/packages/57d11a30155349aa5106f8150cee35eac5f4764c.map", 17 | "size": 113991, 18 | "hash": "57d11a30155349aa5106f8150cee35eac5f4764c" 19 | }, 20 | { 21 | "path": "app/template.mobileapp.js", 22 | "where": "client", 23 | "type": "js", 24 | "cacheable": true, 25 | "url": "/app/template.mobileapp.js?979b20f66caf126704c250fbd29ce253c6cb490e", 26 | "sourceMap": "app/template.mobileapp.js.map", 27 | "sourceMapUrl": "/app/979b20f66caf126704c250fbd29ce253c6cb490e.map", 28 | "size": 578, 29 | "hash": "979b20f66caf126704c250fbd29ce253c6cb490e" 30 | }, 31 | { 32 | "path": "app/mobileapp.js", 33 | "where": "client", 34 | "type": "js", 35 | "cacheable": true, 36 | "url": "/app/mobileapp.js?6db9763f3e0f4e4cbf78111f73823043ab08e3e7", 37 | "sourceMap": "app/mobileapp.js.map", 38 | "sourceMapUrl": "/app/6db9763f3e0f4e4cbf78111f73823043ab08e3e7.map", 39 | "size": 2275, 40 | "hash": "6db9763f3e0f4e4cbf78111f73823043ab08e3e7" 41 | }, 42 | { 43 | "path": "merged-stylesheets.css", 44 | "where": "client", 45 | "type": "css", 46 | "cacheable": true, 47 | "url": "/merged-stylesheets.css?20ae2c8d51b2507244e598844414ecdec2615ce3", 48 | "sourceMap": "merged-stylesheets.css.map", 49 | "sourceMapUrl": "/20ae2c8d51b2507244e598844414ecdec2615ce3.map", 50 | "size": 30, 51 | "hash": "20ae2c8d51b2507244e598844414ecdec2615ce3" 52 | }, 53 | { 54 | "path": "app/some-data.json", 55 | "where": "client", 56 | "type": "asset", 57 | "cacheable": false, 58 | "url": "/some-data.json", 59 | "size": 15, 60 | "hash": "3edc8875bc0dd76d9f5fce5e823dca6f17a26da7" 61 | }, 62 | { 63 | "path": "app/some-file", 64 | "where": "client", 65 | "type": "asset", 66 | "cacheable": false, 67 | "url": "/some-file", 68 | "size": 10, 69 | "hash": "23300652a57f3e819038d9a268ba36af0e25d33b" 70 | }, 71 | { 72 | "path": "app/some-font.woff", 73 | "where": "client", 74 | "type": "asset", 75 | "cacheable": false, 76 | "url": "/some-font.woff", 77 | "size": 15, 78 | "hash": "6ec7e1e1c0199bfb5bcd6877de9fe7abefd26df8" 79 | }, 80 | { 81 | "path": "app/some-image.jpg", 82 | "where": "client", 83 | "type": "asset", 84 | "cacheable": false, 85 | "url": "/some-image.jpg", 86 | "size": 15, 87 | "hash": "13f1d459365d5604dbf2b64b203fa583c1c7fc3f" 88 | }, 89 | { 90 | "path": "app/some-image.png", 91 | "where": "client", 92 | "type": "asset", 93 | "cacheable": false, 94 | "url": "/some-image.png", 95 | "size": 15, 96 | "hash": "06b05b4c2720cd9ff733d21c594eac4e865a6e73" 97 | }, 98 | { 99 | "path": "app/some-javascript.js", 100 | "where": "client", 101 | "type": "asset", 102 | "cacheable": false, 103 | "url": "/some-javascript.js", 104 | "size": 19, 105 | "hash": "51a3422f25ddf466a35e00e327d5f4ca90eee8f4" 106 | }, 107 | { 108 | "path": "app/some-page.html", 109 | "where": "client", 110 | "type": "asset", 111 | "cacheable": false, 112 | "url": "/some-page.html", 113 | "size": 15, 114 | "hash": "5dc6878863a1fd4f7f69713b4c072280932255af" 115 | }, 116 | { 117 | "path": "app/some-stylesheet.css", 118 | "where": "client", 119 | "type": "asset", 120 | "cacheable": false, 121 | "url": "/some-stylesheet.css", 122 | "size": 20, 123 | "hash": "b33cc1bdaa963ae1cec9afd4c833d80caf7641a2" 124 | }, 125 | { 126 | "path": "app/some-text.txt", 127 | "where": "client", 128 | "type": "asset", 129 | "cacheable": false, 130 | "url": "/some-text.txt", 131 | "size": 14, 132 | "hash": "bb874a02400d28518a3d0f7a4c7fd8970735bea1" 133 | }, 134 | { 135 | "path": "app/some-video.mp4", 136 | "where": "client", 137 | "type": "asset", 138 | "cacheable": false, 139 | "url": "/some-video.mp4", 140 | "size": 15, 141 | "hash": "45e892d4c7ce693f5cd551fcd671cf227ff1ae3a" 142 | }, 143 | { 144 | "path": "head.html", 145 | "where": "internal", 146 | "type": "head", 147 | "hash": "2ce23f770b76d2f1cb0d71f4a43fbbb61afb25be" 148 | } 149 | ] 150 | } 151 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | hze4wnxharjw9d067u 8 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base # Packages every Meteor app needs to have 8 | mobile-experience # Packages for a great mobile UX 9 | mongo # The database Meteor supports right now 10 | blaze-html-templates # Compile .html files into Meteor Blaze views 11 | reactive-var # Reactive variable for tracker 12 | jquery # Helpful client-side library 13 | tracker # Meteor's client-side reactive programming library 14 | 15 | standard-minifier-css # CSS minifier run for production mode 16 | standard-minifier-js # JS minifier run for production mode 17 | es5-shim # ECMAScript 5 compatibility for older browsers. 18 | ecmascript # Enable ECMAScript2015+ syntax in app code 19 | 20 | autopublish # Publish all data to the clients (for prototyping) 21 | insecure # Allow all DB writes from clients (for prototyping) 22 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/platforms: -------------------------------------------------------------------------------- 1 | android 2 | browser 3 | server 4 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.3.2.4 2 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/.meteor/versions: -------------------------------------------------------------------------------- 1 | allow-deny@1.0.4 2 | autopublish@1.0.7 3 | autoupdate@1.2.9 4 | babel-compiler@6.6.4 5 | babel-runtime@0.1.8 6 | base64@1.0.8 7 | binary-heap@1.0.8 8 | blaze@2.1.7 9 | blaze-html-templates@1.0.4 10 | blaze-tools@1.0.8 11 | boilerplate-generator@1.0.8 12 | caching-compiler@1.0.4 13 | caching-html-compiler@1.0.6 14 | callback-hook@1.0.8 15 | check@1.2.1 16 | ddp@1.2.5 17 | ddp-client@1.2.7 18 | ddp-common@1.2.5 19 | ddp-server@1.2.6 20 | deps@1.0.12 21 | diff-sequence@1.0.5 22 | ecmascript@0.4.3 23 | ecmascript-runtime@0.2.10 24 | ejson@1.0.11 25 | es5-shim@4.5.10 26 | fastclick@1.0.11 27 | geojson-utils@1.0.8 28 | hot-code-push@1.0.4 29 | html-tools@1.0.9 30 | htmljs@1.0.9 31 | http@1.1.5 32 | id-map@1.0.7 33 | insecure@1.0.7 34 | jquery@1.11.8 35 | launch-screen@1.0.11 36 | livedata@1.0.18 37 | logging@1.0.12 38 | meteor@1.1.14 39 | meteor-base@1.0.4 40 | minifier-css@1.1.11 41 | minifier-js@1.1.11 42 | minimongo@1.0.16 43 | mobile-experience@1.0.4 44 | mobile-status-bar@1.0.12 45 | modules@0.6.1 46 | modules-runtime@0.6.3 47 | mongo@1.1.7 48 | mongo-id@1.0.4 49 | npm-mongo@1.4.43 50 | observe-sequence@1.0.11 51 | ordered-dict@1.0.7 52 | promise@0.6.7 53 | random@1.0.9 54 | reactive-var@1.0.9 55 | reload@1.1.8 56 | retry@1.0.7 57 | routepolicy@1.0.10 58 | spacebars@1.0.11 59 | spacebars-compiler@1.0.11 60 | standard-minifier-css@1.0.6 61 | standard-minifier-js@1.0.6 62 | templating@1.1.9 63 | templating-tools@1.0.4 64 | tracker@1.0.13 65 | ui@1.0.11 66 | underscore@1.0.8 67 | url@1.0.9 68 | webapp@1.2.8 69 | webapp-hashing@1.0.9 70 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/client/main.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ 2 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/client/main.html: -------------------------------------------------------------------------------- 1 | 2 | simple 3 | 4 | 5 | 6 |

Welcome to Meteor!

7 | 8 | {{> hello}} 9 | {{> info}} 10 | 11 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/client/main.js: -------------------------------------------------------------------------------- 1 | import { Template } from 'meteor/templating'; 2 | import { ReactiveVar } from 'meteor/reactive-var'; 3 | 4 | import './main.html'; 5 | 6 | Template.hello.onCreated(function helloOnCreated() { 7 | // counter starts at 0 8 | this.counter = new ReactiveVar(0); 9 | }); 10 | 11 | Template.hello.helpers({ 12 | counter() { 13 | return Template.instance().counter.get(); 14 | }, 15 | }); 16 | 17 | Template.hello.events({ 18 | 'click button'(event, instance) { 19 | // increment the counter when button is clicked 20 | instance.counter.set(instance.counter.get() + 1); 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-desktop", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run", 6 | "e": "node ../meteor-desktop-client/bin/cli.js" 7 | }, 8 | "dependencies": { 9 | "meteor-node-stubs": "~0.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/fixtures/meteorProject/server/main.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | Meteor.startup(() => { 4 | // code to run on server at startup 5 | }); 6 | -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/chrome-devtools_devtools_0.localstorage: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/chrome-devtools_devtools_0.localstorage-journal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/storages/Local Storage/chrome-devtools_devtools_0.localstorage-journal -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/http_127.0.0.1_57206.localstorage: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/http_127.0.0.1_57206.localstorage-journal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/storages/Local Storage/http_127.0.0.1_57206.localstorage-journal -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/http_127.0.0.1_57207.localstorage: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/http_127.0.0.1_57207.localstorage-journal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/storages/Local Storage/http_127.0.0.1_57207.localstorage-journal -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/http_127.0.0.1_57214.localstorage: -------------------------------------------------------------------------------- 1 | 4 2 | -------------------------------------------------------------------------------- /tests/fixtures/storages/Local Storage/http_127.0.0.1_57214.localstorage-journal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wojtkowiak/meteor-desktop/01fb583d25b7b0f82308677389bce77cb5c8ce79/tests/fixtures/storages/Local Storage/http_127.0.0.1_57214.localstorage-journal -------------------------------------------------------------------------------- /tests/functional/electronApp.test.js: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import dirty from 'dirty-chai'; 3 | import sinonChai from 'sinon-chai'; 4 | import path from 'path'; 5 | import fs from 'fs'; 6 | import shell from 'shelljs'; 7 | import asar from 'asar'; 8 | 9 | import { createTestInstance, StubLog, getModuleJson, saveModuleJson } from '../helpers/meteorDesktop'; 10 | import paths from '../helpers/paths'; 11 | 12 | chai.use(sinonChai); 13 | chai.use(dirty); 14 | const { describe, it } = global; 15 | const { expect } = chai; 16 | 17 | describe('electronApp', () => { 18 | let MeteorDesktop; 19 | let logStub; 20 | 21 | beforeEach(() => { 22 | MeteorDesktop = createTestInstance(); 23 | shell.cp('-rf', paths.fixtures.desktop, paths.testProjectInstallPath); 24 | shell.mkdir(MeteorDesktop.env.paths.electronApp.root); 25 | logStub = new StubLog(MeteorDesktop.electronApp, 'info'); 26 | }); 27 | 28 | afterEach(() => { 29 | logStub.restore(); 30 | shell.rm('-rf', paths.testProjectInstallPath); 31 | }); 32 | 33 | describe('#packDesktopToAsar', () => { 34 | it('should make desktop.asar from .desktop', (done) => { 35 | MeteorDesktop.electronApp.copyDesktopToDesktopTemp(); 36 | MeteorDesktop.electronApp.packDesktopToAsar().then(() => { 37 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.desktopAsar)).to.be.true(); 38 | const files = asar.listPackage(MeteorDesktop.env.paths.electronApp.desktopAsar); 39 | const expected = ['desktop.js', 'settings.json', 'modules', 'assets']; 40 | expect(files).to.include.members( 41 | expected.map(expectedPath => path.sep + expectedPath) 42 | ); 43 | done(); 44 | }).catch((e) => { done(e); }); 45 | }); 46 | }); 47 | 48 | describe('#updatePackageJsonFields', () => { 49 | it('should update fields according to settings.packageJsonFields', () => { 50 | MeteorDesktop.electronApp.updatePackageJsonFields(); 51 | const packageJson = JSON.parse( 52 | fs.readFileSync(MeteorDesktop.env.paths.electronApp.packageJson, 'UTF-8') 53 | ); 54 | expect(packageJson.description).to.be.equal('My Meteor App'); 55 | expect(packageJson.private).to.be.true(); 56 | expect(packageJson.author).to.be.equal('Me, Myself And I'); 57 | expect(packageJson.name).to.be.equal('MyMeteorApp'); 58 | logStub.restore(); 59 | }); 60 | }); 61 | 62 | describe('#updateDependencies', () => { 63 | it('should update dependencies list', () => { 64 | MeteorDesktop.electronApp.packageJson = {}; 65 | MeteorDesktop.electronApp.updateDependenciesList(); 66 | const packageJson = JSON.parse( 67 | fs.readFileSync(MeteorDesktop.env.paths.electronApp.packageJson, 'UTF-8') 68 | ); 69 | expect(packageJson.dependencies).to.have.a.property('some-package', '1.2.3'); 70 | expect(packageJson.dependencies).to.have.a.property( 71 | 'meteor-desktop-splash-screen', '0.3.0' 72 | ); 73 | expect(packageJson.dependencies).to.have.a.property('dependency', '1.0.1'); 74 | expect(packageJson.dependencies).to.have.a.property('dependency2', '0.0.5'); 75 | }); 76 | 77 | 78 | function testUpdateDependenciesError(module, dependency, version, match) { 79 | logStub.restore(); 80 | logStub = new StubLog(MeteorDesktop.electronApp, ['info'], true); 81 | const moduleJson = getModuleJson(module); 82 | moduleJson.dependencies[dependency] = version; 83 | saveModuleJson(module, moduleJson); 84 | MeteorDesktop.electronApp.packageJson = {}; 85 | MeteorDesktop.electronApp.updatePackageJsonFields(); 86 | let err = null; 87 | try { 88 | MeteorDesktop.electronApp.updateDependenciesList(); 89 | } catch (e) { 90 | err = e; 91 | } 92 | expect(err.message).to.match(match); 93 | } 94 | 95 | it('should report error on dependency version range', () => { 96 | testUpdateDependenciesError('someModule', 'someDep', '^1.2.0', /semver ranges/); 97 | }); 98 | it('should report error on dependency conflict', () => { 99 | testUpdateDependenciesError( 100 | 'someModule2', 'dependency', '0.2.0', /found to be conflicting/ 101 | ); 102 | }); 103 | it('should report error dependency conflict with core', () => { 104 | testUpdateDependenciesError( 105 | 'someModule', 'shelljs', '0.2.0', /found to be conflicting/ 106 | ); 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /tests/functional/electronAppScaffold.test.js: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import dirty from 'dirty-chai'; 3 | import fs from 'fs'; 4 | import shell from 'shelljs'; 5 | 6 | import { createTestInstance, StubLog } from '../helpers/meteorDesktop'; 7 | 8 | chai.use(dirty); 9 | const { describe, it } = global; 10 | const { expect } = chai; 11 | 12 | describe('electronAppScaffold', () => { 13 | let MeteorDesktop; 14 | 15 | beforeEach(() => { 16 | MeteorDesktop = createTestInstance(); 17 | }); 18 | 19 | describe('#make', () => { 20 | it('should create .meteor-desktop scaffold', (done) => { 21 | const logStub = new StubLog(MeteorDesktop.electronApp.scaffold, 'info'); 22 | MeteorDesktop.electronApp.scaffold.make().then(() => { 23 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.root)).to.be.true(); 24 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.cordova)).to.be.true(); 25 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.index)).to.be.true(); 26 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.app)).to.be.true(); 27 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.preload)).to.be.true(); 28 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.modules)).to.be.true(); 29 | expect(fs.existsSync(MeteorDesktop.env.paths.electronApp.packageJson)).to.be.true(); 30 | shell.rm('-rf', MeteorDesktop.env.paths.electronApp); 31 | logStub.restore(); 32 | 33 | done(); 34 | }).catch((e) => { done(e); logStub.restore(); }); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/helpers/clear.js: -------------------------------------------------------------------------------- 1 | import shell from 'shelljs'; 2 | import paths from './paths'; 3 | 4 | shell.rm('-rf', paths.testsTmpPath); 5 | 6 | -------------------------------------------------------------------------------- /tests/helpers/meteorDesktop.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import sinon from 'sinon'; 4 | import path from 'path'; 5 | import fs from 'fs'; 6 | import shell from 'shelljs'; 7 | 8 | import meteorDesktop from '../../dist/index'; 9 | import paths from './paths'; 10 | 11 | export function StubLog(object, methods, stubProcessExit) { 12 | const stubs = {}; 13 | 14 | const methodsArray = Array.isArray(methods) ? methods : [methods]; 15 | 16 | if (stubProcessExit) { 17 | sinon.stub(process, 'exit'); 18 | } 19 | 20 | methodsArray.forEach((method) => { 21 | stubs[method] = sinon.stub(object.log, method); 22 | }); 23 | 24 | this.restore = () => { 25 | Object.keys(stubs).forEach(method => stubs[method].restore()); 26 | if (stubProcessExit) { 27 | process.exit.restore(); 28 | } 29 | }; 30 | 31 | this.stubs = stubs; 32 | 33 | return this; 34 | } 35 | 36 | export function createTestInstance() { 37 | shell.rm('-rf', paths.testsTmpPath); 38 | 39 | // Copy test meteor app. 40 | shell.mkdir('-p', paths.testsTmpPath); 41 | shell.mkdir(paths.testProjectInstallPath); 42 | shell.cp('-r', paths.fixtures.testProject, paths.testsTmpPath); 43 | 44 | return meteorDesktop( 45 | paths.testProjectInstallPath, 46 | paths.testProjectInstallPath, 47 | { ddpUrl: 'http://127.0.0.1:3788', output: paths.testProjectInstallPath }, 48 | { 49 | log: class { 50 | constructor() { 51 | this.info = sinon.stub(); 52 | this.error = (...args) => console.error(args); 53 | } 54 | } 55 | } 56 | ); 57 | } 58 | 59 | class Logger { 60 | constructor(show, showErrors) { 61 | this.show = show; 62 | this.showErrors = showErrors; 63 | this.loggers = { 64 | get: () => new Logger(show, showErrors) 65 | }; 66 | } 67 | 68 | info(...args) { 69 | if (this.show) { 70 | console.log(...args); 71 | } 72 | } 73 | 74 | verbose(...args) { 75 | if (this.show) { 76 | console.log(...args); 77 | } 78 | } 79 | 80 | debug(...args) { 81 | if (this.show) { 82 | console.log(...args); 83 | } 84 | } 85 | 86 | warn(...args) { 87 | if (this.show) { 88 | console.warn(...args); 89 | } 90 | } 91 | 92 | error(...args) { 93 | if (this.show || this.showErrors) { 94 | console.error(...args); 95 | } 96 | } 97 | 98 | getLoggerFor() { 99 | return new Logger(this.show, this.showErrors); 100 | } 101 | } 102 | 103 | export function getFakeLogger(show, showErrors) { 104 | return new Logger(show, showErrors); 105 | } 106 | 107 | export function getModuleJson(module) { 108 | const moduleJsonPath = path.join( 109 | paths.testProjectInstallPath, '.desktop', 'modules', module, 'module.json' 110 | ); 111 | return JSON.parse(fs.readFileSync(moduleJsonPath, 'UTF-8')); 112 | } 113 | 114 | export function saveModuleJson(module, moduleJson) { 115 | const moduleJsonPath = path.join( 116 | paths.testProjectInstallPath, '.desktop', 'modules', module, 'module.json' 117 | ); 118 | fs.writeFileSync( 119 | moduleJsonPath, JSON.stringify(moduleJson, null, 2) 120 | ); 121 | } 122 | 123 | export default function (input, output, options) { 124 | return meteorDesktop(input, output, options); 125 | } 126 | -------------------------------------------------------------------------------- /tests/helpers/mockerySettings.js: -------------------------------------------------------------------------------- 1 | const settings = { 2 | warnOnReplace: false, 3 | warnOnUnregistered: false 4 | }; 5 | 6 | export default settings; 7 | -------------------------------------------------------------------------------- /tests/helpers/paths.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import tempDir from 'temp-dir'; 3 | 4 | const { join, resolve } = path; 5 | 6 | const testsPath = resolve(path.join(__dirname, '..', '..', 'tests')); 7 | 8 | const testsTmpPath = resolve(path.join(tempDir, '.__tmp')); 9 | const testsIntegrationTmpPath = resolve(path.join(tempDir, '.__tmp_int')); 10 | 11 | const fixturesPath = 'fixtures'; 12 | const projectDir = 'meteorProject'; 13 | 14 | const testProjectInstallPath = join(testsTmpPath, projectDir); 15 | const autoUpdateVersionsPath = join(testsTmpPath, 'autoupdate'); 16 | const storagesPath = join(testsTmpPath, 'storages'); 17 | 18 | const fixtures = { 19 | testProject: join(testsPath, fixturesPath, projectDir), 20 | desktop: join(testsPath, fixturesPath, '.desktop'), 21 | storages: join(testsPath, fixturesPath, 'storages'), 22 | electronApp: join(testsPath, fixturesPath, '.meteor-desktop'), 23 | bundledWww: join(testsPath, fixturesPath, 'localServer', 'bundledWww'), 24 | downloadableVersions: join(testsPath, fixturesPath, 'autoUpdate', 'downloadableVersions'), 25 | autoUpdate: join(testsPath, fixturesPath, 'autoUpdate'), 26 | partiallyDownloadableVersions: join( 27 | testsPath, fixturesPath, 'autoUpdate', 'partiallyDownloadedVersions' 28 | ) 29 | }; 30 | 31 | const cli = resolve(join(__dirname, '..', 'bin', 'cli.js')); 32 | export default { 33 | testsPath, 34 | testsTmpPath, 35 | testsIntegrationTmpPath, 36 | testProjectInstallPath, 37 | autoUpdateVersionsPath, 38 | fixtures, 39 | fixturesPath, 40 | storagesPath, 41 | cli 42 | }; 43 | -------------------------------------------------------------------------------- /tests/integration/prepare.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | require('reify'); 3 | // CI cache version: 1 4 | 5 | const tempDir = require('temp-dir'); 6 | const shell = require('shelljs'); 7 | const path = require('path'); 8 | const fs = require('fs'); 9 | 10 | const testsTmpPath = path.resolve(path.join(tempDir, '.__tmp_int')); 11 | 12 | const meteorVersion = '1.8.1'; 13 | 14 | shell.config.fatal = true; 15 | const appDir = path.join(testsTmpPath, 'test-desktop'); 16 | 17 | shell.rm('-rf', testsTmpPath); 18 | 19 | if (!fs.existsSync(testsTmpPath) || !fs.existsSync(path.join(appDir, 'package.json'))) { 20 | console.log('creating test dir'); 21 | shell.mkdir('-p', testsTmpPath); 22 | console.log('creating test meteor app'); 23 | shell.exec(`meteor create test-desktop --release=METEOR@${meteorVersion}`, { cwd: testsTmpPath }); 24 | const packageJson = JSON.parse(fs.readFileSync(path.join(appDir, 'package.json'), 'utf8')); 25 | packageJson.dependencies['meteor-desktop'] = path.resolve(path.join(__dirname, '..', '..' )); 26 | if (process.env.APPVEYOR) { 27 | const versions = require('../../lib/defaultDependencies'); 28 | packageJson.dependencies.electron = versions.electron; 29 | packageJson.dependencies['electron-builder'] = versions['electron-builder']; 30 | } 31 | fs.writeFileSync(path.join(appDir, 'package.json'), JSON.stringify(packageJson, null, 2)); 32 | } else { 33 | const currentVersion = fs.readFileSync(path.join(appDir, '.meteor', 'release'), 'utf-8').split('@')[1].replace(/[\r\n]/gm, ''); 34 | if (currentVersion !== meteorVersion) { 35 | console.log('updating meteor version'); 36 | shell.exec(`meteor update --release=METEOR@${meteorVersion} --all-packages`, { cwd: appDir }); 37 | } 38 | console.log('meteor npm prune'); 39 | shell.exec('meteor npm prune', { cwd: appDir }); 40 | } 41 | console.log('meteor npm install'); 42 | shell.exec('meteor npm install', { cwd: appDir }); 43 | 44 | 45 | if (process.env.TRAVIS) { 46 | shell.config.fatal = false; 47 | shell.exec('meteor add-platform android', { cwd: appDir }); 48 | console.log(shell.exec('meteor build ../build --server=127.0.0.1:3000', { cwd: appDir })); 49 | } else { 50 | // This should bootstrap cordova. 51 | console.log('adding platform ios'); 52 | shell.exec('meteor add-platform ios', { cwd: appDir }); 53 | console.log('removing platform ios'); 54 | shell.exec('meteor remove-platform ios', { cwd: appDir }); 55 | } 56 | -------------------------------------------------------------------------------- /tests/unit/meteorApp.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require, import/extensions */ 2 | import chai from 'chai'; 3 | import dirty from 'dirty-chai'; 4 | import sinonChai from 'sinon-chai'; 5 | import sinon from 'sinon'; 6 | import mockery from 'mockery'; 7 | 8 | // need for running test 9 | import asar from 'asar'; // eslint-disable-line no-unused-vars 10 | 11 | chai.use(sinonChai); 12 | chai.use(dirty); 13 | 14 | const { 15 | describe, it, before, after 16 | } = global; 17 | const { expect } = chai; 18 | 19 | const fs = {}; 20 | const METEOR_APP_CONTEXT = { env: { paths: { meteorApp: { release: 'release.file' } } } }; 21 | const METEOR_RELEASES = [ 22 | { release: 'METEOR@1.3.4', version: '1.3.4', semver: '1.3.4' }, 23 | { release: 'METEOR@1.4.2.7', version: '1.4.2.7', semver: '1.4.2' }, 24 | { release: 'METEOR@1.5-alpha', version: '1.5', semver: '1.5.0' }, 25 | { release: 'METEOR@2-rc.0', version: '2', semver: '2.0.0' }, 26 | { release: 'METEOR@1.6.0.1\r\n\r\n', version: '1.6.0.1', semver: '1.6.0' } 27 | ]; 28 | 29 | let MeteorApp; 30 | 31 | describe('meteorApp', () => { 32 | before(() => { 33 | mockery.registerMock('fs', fs); 34 | mockery.enable({ 35 | warnOnReplace: false, 36 | warnOnUnregistered: false 37 | }); 38 | MeteorApp = require('../../lib/meteorApp.js').default; 39 | }); 40 | 41 | after(() => { 42 | mockery.deregisterMock('fs'); 43 | mockery.disable(); 44 | }); 45 | 46 | function prepareFsStubs(release) { 47 | const readFileSyncStub = sinon.stub(); 48 | readFileSyncStub 49 | .withArgs(sinon.match('release.file'), 'UTF-8') 50 | .returns(release); 51 | fs.readFileSync = readFileSyncStub; 52 | } 53 | 54 | describe('#castMeteorReleaseToSemver', () => { 55 | it('should cast release to semver', () => { 56 | const instance = new MeteorApp(METEOR_APP_CONTEXT); 57 | METEOR_RELEASES.forEach((version) => { 58 | prepareFsStubs(version.release); 59 | expect(instance.castMeteorReleaseToSemver()).be.equal(version.semver); 60 | }); 61 | }); 62 | }); 63 | 64 | describe('#getMeteorRelease', () => { 65 | it('should parse Meteor version', () => { 66 | const instance = new MeteorApp(METEOR_APP_CONTEXT); 67 | METEOR_RELEASES.forEach((version) => { 68 | prepareFsStubs(version.release); 69 | expect(instance.getMeteorRelease()).be.equal(version.version); 70 | }); 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /tests/unit/meteorManager.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/extensions, import/no-extraneous-dependencies, global-require */ 2 | import chai from 'chai'; 3 | import dirty from 'dirty-chai'; 4 | import sinonChai from 'sinon-chai'; 5 | import sinon from 'sinon'; 6 | import mockery from 'mockery'; 7 | import importFresh from 'import-fresh'; 8 | 9 | chai.use(sinonChai); 10 | chai.use(dirty); 11 | const { 12 | describe, it, after, before 13 | } = global; 14 | const { expect } = chai; 15 | 16 | const fs = {}; 17 | const METEOR_APP_CONTEXT = { env: { paths: { meteorApp: { root: 'root.path', packages: 'package.file', versions: 'version.file' } } } }; 18 | 19 | let MeteorManager; 20 | 21 | describe('meteorManager', () => { 22 | before(() => { 23 | mockery.registerMock('fs', fs); 24 | mockery.enable({ 25 | warnOnReplace: false, 26 | warnOnUnregistered: false 27 | }); 28 | 29 | MeteorManager = importFresh('../../lib/meteorManager.js').default; 30 | }); 31 | 32 | after(() => { 33 | mockery.deregisterMock('fs'); 34 | mockery.disable(); 35 | }); 36 | 37 | function prepareFsStubs() { 38 | const readFileSyncStub = sinon.stub(); 39 | readFileSyncStub 40 | .withArgs(sinon.match(METEOR_APP_CONTEXT.env.paths.meteorApp.packages, 'UTF-8')) 41 | .returns([ 42 | '# Comment in file', 43 | 'meteor-base@1.1.0', 44 | 'mongo@1.1.18 # Package name with comment', 45 | '# es5-shim@4.6.15 # Commented package', 46 | 'omega:meteor-desktop-localstorage@=0.0.11' 47 | ].join('\n')); 48 | readFileSyncStub 49 | .withArgs(sinon.match(METEOR_APP_CONTEXT.env.paths.meteorApp.versions, 'UTF-8')) 50 | .returns([ 51 | 'meteor-base@1.1.0', 52 | 'mongo@1.1.18', 53 | 'omega:meteor-desktop-localstorage@0.0.11' 54 | ].join('\n')); 55 | fs.readFileSync = readFileSyncStub; 56 | } 57 | 58 | describe('#checkPackages', () => { 59 | let instance; 60 | 61 | before(() => { 62 | instance = new MeteorManager(METEOR_APP_CONTEXT); 63 | prepareFsStubs(); 64 | }); 65 | 66 | it('should find package in project', () => { 67 | expect( 68 | instance.checkPackages(['omega:meteor-desktop-localstorage@=0.0.11']) 69 | ).to.be.true(); 70 | }); 71 | 72 | it('should find package in project without specific versions', () => { 73 | expect( 74 | instance.checkPackages(['omega:meteor-desktop-localstorage']) 75 | ).to.be.true(); 76 | }); 77 | 78 | it('should not find commented package in project', () => { 79 | expect( 80 | instance.checkPackages(['es5-shim']) 81 | ).to.be.false(); 82 | }); 83 | }); 84 | 85 | describe('#checkPackagesVersion', () => { 86 | let instance; 87 | 88 | before(() => { 89 | instance = new MeteorManager(METEOR_APP_CONTEXT); 90 | prepareFsStubs(); 91 | }); 92 | 93 | it('should find package in project with specific versions', () => { 94 | expect( 95 | instance.checkPackagesVersion(['omega:meteor-desktop-localstorage@0.0.11']) 96 | ).to.be.true(); 97 | }); 98 | 99 | it('should not find package in project without specific versions', () => { 100 | expect( 101 | instance.checkPackagesVersion(['omega:meteor-desktop-localstorage']) 102 | ).to.be.false(); 103 | }); 104 | 105 | it('should not find one package from list in project', () => { 106 | expect( 107 | instance.checkPackagesVersion([ 108 | 'omega:meteor-desktop-localstorage@0.0.11', 109 | 'omega:meteor-desktop-watcher@0.0.11' 110 | ]) 111 | ).to.be.false(); 112 | }); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /tests/unit/modules/module.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | import chai from 'chai'; 3 | import dirty from 'dirty-chai'; 4 | import sinonChai from 'sinon-chai'; 5 | import sinon from 'sinon'; 6 | import mockery from 'mockery'; 7 | import rewire from 'rewire'; 8 | 9 | import mockerySettings from '../../helpers/mockerySettings'; 10 | 11 | chai.use(sinonChai); 12 | chai.use(dirty); 13 | const { 14 | describe, it, before, after 15 | } = global; 16 | const { expect } = chai; 17 | 18 | const Electron = { 19 | }; 20 | 21 | let Module; 22 | 23 | describe('Module', () => { 24 | before(() => { 25 | mockery.registerMock('electron', Electron); 26 | mockery.enable(mockerySettings); 27 | Module = rewire('../../../skeleton/modules/module.js'); 28 | }); 29 | 30 | after(() => { 31 | mockery.deregisterMock('electron'); 32 | mockery.disable(); 33 | }); 34 | 35 | describe('#sendInternal', () => { 36 | it('should throw when no reference to renderer set yet', () => { 37 | expect(Module.sendInternal.bind(module, 'test')).to.throw( 38 | /No reference to renderer process/ 39 | ); 40 | }); 41 | it('should send ipc when renderer is set', () => { 42 | const rendererMock = { send: sinon.stub(), isDestroyed: () => false }; 43 | const revert = Module.__set__('renderer', rendererMock); 44 | const arg1 = { some: 'data' }; 45 | const arg2 = 'test'; 46 | Module.sendInternal('event', arg1, arg2); 47 | expect(rendererMock.send).to.be.calledWith('event', arg1, arg2); 48 | revert(); 49 | }); 50 | it('should not send ipc when renderer is destroyed', () => { 51 | const rendererMock = { send: sinon.stub(), isDestroyed: () => true }; 52 | const revert = Module.__set__('renderer', rendererMock); 53 | Module.sendInternal('event'); 54 | expect(rendererMock.send).to.have.callCount(0); 55 | revert(); 56 | }); 57 | }); 58 | describe('#getEventName', () => { 59 | it('should return namespaced event name', () => { 60 | const module = new Module('test'); 61 | expect(module.getEventName('event')).to.equal('test__event'); 62 | }); 63 | }); 64 | describe('#getResponseEventName', () => { 65 | it('should return namespaced response event name', () => { 66 | const module = new Module('test'); 67 | expect(module.getResponseEventName('event')).to.equal('test__event___response'); 68 | }); 69 | }); 70 | 71 | describe('#setDefaultFetchTimeout', () => { 72 | it('should call fetch with correct timeout', () => { 73 | const module = new Module('test'); 74 | const arg1 = { some: 'data' }; 75 | const arg2 = 'test'; 76 | const event = 'yyy'; 77 | module.setDefaultFetchTimeout(999); 78 | module.fetch = sinon.stub(); 79 | module.call(event, arg1, arg2); 80 | expect(module.fetch).to.be.calledWith(event, 999, arg1, arg2); 81 | }); 82 | }); 83 | }); 84 | --------------------------------------------------------------------------------