From b0e8a0a812624d8f5de4aa67f5dafa9abfa65790 Mon Sep 17 00:00:00 2001 From: bojeil-google Date: Tue, 31 Jul 2018 21:06:44 -0700 Subject: [PATCH 1/2] Fixes servicerworker/client state syncing Defines the MessageChannel based utility for communicating window <=> window and window <=> worker. Adds receiver in indexedDB when operating from a service worker to listen to keyChanged events. On detection, indexedDB is synced and a response is returned to sender whether the key change was processed. It may be that the key change was already detected. This would return false. Adds a sender when an indexedDB write operation occurs and a service worker is available. The client will send a keyChanged message to the service worker to process the change and blocks on it. On response, the indexedDB write operation will resolve. The operation will resolve on success or failure. This is a best effort approach. If the service worker fails to process, the write operation should still succeed. Updates obsoleted APIs in web worker. --- packages/auth/demo/functions/yarn.lock | 2703 +++++++++++++++++ packages/auth/demo/public/web-worker.js | 16 +- packages/auth/src/messagechannel/defines.js | 65 + .../auth/src/messagechannel/postmessager.js | 114 + packages/auth/src/messagechannel/receiver.js | 206 ++ packages/auth/src/messagechannel/sender.js | 221 ++ packages/auth/src/storage/indexeddb.js | 62 + packages/auth/src/utils.js | 15 + .../test/messagechannel/postmessager_test.js | 72 + .../auth/test/messagechannel/receiver_test.js | 462 +++ .../auth/test/messagechannel/sender_test.js | 525 ++++ packages/auth/test/storage/indexeddb_test.js | 217 ++ 12 files changed, 4670 insertions(+), 8 deletions(-) create mode 100644 packages/auth/demo/functions/yarn.lock create mode 100644 packages/auth/src/messagechannel/defines.js create mode 100644 packages/auth/src/messagechannel/postmessager.js create mode 100644 packages/auth/src/messagechannel/receiver.js create mode 100644 packages/auth/src/messagechannel/sender.js create mode 100644 packages/auth/test/messagechannel/postmessager_test.js create mode 100644 packages/auth/test/messagechannel/receiver_test.js create mode 100644 packages/auth/test/messagechannel/sender_test.js diff --git a/packages/auth/demo/functions/yarn.lock b/packages/auth/demo/functions/yarn.lock new file mode 100644 index 00000000000..46b869e5960 --- /dev/null +++ b/packages/auth/demo/functions/yarn.lock @@ -0,0 +1,2703 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@firebase/app-types@0.1.2": + version "0.1.2" + resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.1.2.tgz#a20cb346e3be374c0bdee6b102de0ea5e8e6fa27" + +"@firebase/app@^0.1.10": + version "0.1.10" + resolved "https://registry.npmjs.org/@firebase/app/-/app-0.1.10.tgz#fc80c62dbe4d601cad1495bc095309adb9074f85" + dependencies: + "@firebase/app-types" "0.1.2" + "@firebase/util" "0.1.10" + tslib "^1.9.0" + +"@firebase/database-types@0.2.1": + version "0.2.1" + resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.2.1.tgz#f83a6d03af5f8c93276ceb89e1f31e4664c9df1b" + +"@firebase/database@^0.2.0": + version "0.2.2" + resolved "https://registry.npmjs.org/@firebase/database/-/database-0.2.2.tgz#a8a0709644d7f281b400e983c71c8c65fba90c70" + dependencies: + "@firebase/database-types" "0.2.1" + "@firebase/logger" "0.1.1" + "@firebase/util" "0.1.11" + faye-websocket "0.11.1" + tslib "1.9.0" + +"@firebase/logger@0.1.1": + version "0.1.1" + resolved "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.1.tgz#af5df54253286993f4b367c3dabe569c848860d3" + +"@firebase/util@0.1.10": + version "0.1.10" + resolved "https://registry.npmjs.org/@firebase/util/-/util-0.1.10.tgz#7898f6e36c8231c287c4024c313000df677b1363" + dependencies: + tslib "^1.9.0" + +"@firebase/util@0.1.11": + version "0.1.11" + resolved "https://registry.npmjs.org/@firebase/util/-/util-0.1.11.tgz#9990dff53930aa9fcae31494ebe8de5c5b8e815c" + dependencies: + tslib "1.9.0" + +"@google-cloud/common-grpc@^0.6.0": + version "0.6.1" + resolved "https://registry.npmjs.org/@google-cloud/common-grpc/-/common-grpc-0.6.1.tgz#629dfb90690f6a38263bbf16eb9740ea4cbcf9df" + dependencies: + "@google-cloud/common" "^0.17.0" + dot-prop "^4.2.0" + duplexify "^3.5.1" + extend "^3.0.1" + grpc "^1.10.0" + is "^3.2.0" + modelo "^4.2.0" + retry-request "^3.3.1" + through2 "^2.0.3" + +"@google-cloud/common@^0.17.0": + version "0.17.0" + resolved "https://registry.npmjs.org/@google-cloud/common/-/common-0.17.0.tgz#8ef558750db481fc10a13757a49479ab9a1c8c07" + dependencies: + array-uniq "^1.0.3" + arrify "^1.0.1" + concat-stream "^1.6.0" + create-error-class "^3.0.2" + duplexify "^3.5.0" + ent "^2.2.0" + extend "^3.0.1" + google-auto-auth "^0.10.0" + is "^3.2.0" + log-driver "1.2.7" + methmeth "^1.1.0" + modelo "^4.2.0" + request "^2.79.0" + retry-request "^3.0.0" + split-array-stream "^1.0.0" + stream-events "^1.0.1" + string-format-obj "^1.1.0" + through2 "^2.0.3" + +"@google-cloud/firestore@^0.13.1": + version "0.13.1" + resolved "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-0.13.1.tgz#40e376852d9aa19aee62deb0334ffc437ebd8d64" + dependencies: + "@google-cloud/common" "^0.17.0" + "@google-cloud/common-grpc" "^0.6.0" + bun "^0.0.12" + deep-equal "^1.0.1" + extend "^3.0.1" + functional-red-black-tree "^1.0.1" + google-gax "^0.16.0" + is "^3.2.1" + safe-buffer "^5.1.1" + through2 "^2.0.3" + +"@google-cloud/storage@^1.6.0": + version "1.7.0" + resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-1.7.0.tgz#07bff573d92d5c294db6a04af246688875a8f74b" + dependencies: + "@google-cloud/common" "^0.17.0" + arrify "^1.0.0" + async "^2.0.1" + compressible "^2.0.12" + concat-stream "^1.5.0" + create-error-class "^3.0.2" + duplexify "^3.5.0" + extend "^3.0.0" + gcs-resumable-upload "^0.10.2" + hash-stream-validation "^0.2.1" + is "^3.0.1" + mime "^2.2.0" + mime-types "^2.0.8" + once "^1.3.1" + pumpify "^1.5.1" + request "^2.85.0" + safe-buffer "^5.1.1" + snakeize "^0.1.0" + stream-events "^1.0.1" + through2 "^2.0.0" + xdg-basedir "^3.0.0" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.0.1": + version "1.1.0" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + +"@types/body-parser@*": + version "1.17.0" + resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/caseless@*": + version "0.12.1" + resolved "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz#9794c69c8385d0192acc471a540d1f8e0d16218a" + +"@types/connect@*": + version "3.4.32" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" + dependencies: + "@types/node" "*" + +"@types/cors@^2.8.1": + version "2.8.4" + resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.4.tgz#50991a759a29c0b89492751008c6af7a7c8267b0" + dependencies: + "@types/express" "*" + +"@types/events@*": + version "1.2.0" + resolved "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" + +"@types/express-serve-static-core@*": + version "4.16.0" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz#fdfe777594ddc1fe8eb8eccce52e261b496e43e7" + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.11.1": + version "4.16.0" + resolved "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz#6d8bc42ccaa6f35cf29a2b7c3333cb47b5a32a19" + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/serve-static" "*" + +"@types/form-data@*": + version "2.2.1" + resolved "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" + dependencies: + "@types/node" "*" + +"@types/google-cloud__storage@^1.1.7": + version "1.7.0" + resolved "https://registry.npmjs.org/@types/google-cloud__storage/-/google-cloud__storage-1.7.0.tgz#60abb5669f78ed07abb625f556d1f396ee84724e" + dependencies: + "@types/node" "*" + "@types/request" "*" + +"@types/jsonwebtoken@^7.1.32": + version "7.2.8" + resolved "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.2.8.tgz#8d199dab4ddb5bba3234f8311b804d2027af2b3a" + dependencies: + "@types/node" "*" + +"@types/lodash@^4.14.34": + version "4.14.115" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.115.tgz#54d171b2ce12c058742443b5f6754760f701b8f9" + +"@types/long@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" + +"@types/mime@*": + version "2.0.0" + resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz#5a7306e367c539b9f6543499de8dd519fac37a8b" + +"@types/node@*", "@types/node@^10.1.0": + version "10.5.5" + resolved "https://registry.npmjs.org/@types/node/-/node-10.5.5.tgz#8e84d24e896cd77b0d4f73df274027e3149ec2ba" + +"@types/node@^8.0.53": + version "8.10.23" + resolved "https://registry.npmjs.org/@types/node/-/node-8.10.23.tgz#e5ccfdafff42af5397c29669b6d7d65f7d629a00" + +"@types/range-parser@*": + version "1.2.2" + resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.2.tgz#fa8e1ad1d474688a757140c91de6dace6f4abc8d" + +"@types/request@*": + version "2.47.1" + resolved "https://registry.npmjs.org/@types/request/-/request-2.47.1.tgz#25410d3afbdac04c91a94ad9efc9824100735824" + dependencies: + "@types/caseless" "*" + "@types/form-data" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + +"@types/serve-static@*": + version "1.13.2" + resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +"@types/tough-cookie@*": + version "2.3.3" + resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.3.tgz#7f226d67d654ec9070e755f46daebf014628e9d9" + +abbrev@1: + version "1.1.1" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-es7-plugin@^1.0.12: + version "1.1.7" + resolved "https://registry.npmjs.org/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b" + +acorn@^5.0.0: + version "5.7.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1, array-uniq@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +ascli@~1: + version "1.0.1" + resolved "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz#bcfa5974a62f18e81cabaeb49732ab4a88f906bc" + dependencies: + colour "~0.7.1" + optjs "~3.2.2" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async@^2.0.1, async@^2.3.0, async@^2.4.0: + version "2.6.1" + resolved "https://registry.npmjs.org/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +axios@^0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + dependencies: + follow-redirects "^1.3.0" + is-buffer "^1.1.5" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +body-parser@1.18.2: + version "1.18.2" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +bun@^0.0.12: + version "0.0.12" + resolved "https://registry.npmjs.org/bun/-/bun-0.0.12.tgz#d54fae69f895557f275423bc14b404030b20a5fc" + dependencies: + readable-stream "~1.0.32" + +bytebuffer@~5: + version "5.0.1" + resolved "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd" + dependencies: + long "~3" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + +call-signature@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/call-signature/-/call-signature-0.0.2.tgz#a84abc825a55ef4cb2b028bd74e205a65b9a4996" + +camelcase@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cliui@^3.0.3: + version "3.2.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +colour@~0.7.1: + version "0.7.1" + resolved "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" + +combined-stream@1.0.6, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +compressible@^2.0.12: + version "2.0.14" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" + dependencies: + mime-db ">= 1.34.0 < 2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0, concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.0.0: + version "2.5.7" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.8.4: + version "2.8.4" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" + dependencies: + object-assign "^4" + vary "^1" + +create-error-class@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +diff-match-patch@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.1.tgz#d5f880213d82fbc124d2b95111fb3c033dbad7fa" + +dir-glob@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + dependencies: + arrify "^1.0.1" + path-type "^3.0.0" + +dot-prop@^4.1.0, dot-prop@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + +duplexify@^3.5.0, duplexify@^3.5.1, duplexify@^3.5.4, duplexify@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecdsa-sig-formatter@1.0.10: + version "1.0.10" + resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3" + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +empower-core@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/empower-core/-/empower-core-1.2.0.tgz#ce3fb2484d5187fa29c23fba8344b0b2fdf5601c" + dependencies: + call-signature "0.0.2" + core-js "^2.0.0" + +empower@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/empower/-/empower-1.3.0.tgz#6b05e77625e77dc44945c4328562c3020b01fa4b" + dependencies: + core-js "^2.0.0" + empower-core "^1.2.0" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +ent@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +espurify@^1.6.0: + version "1.8.1" + resolved "https://registry.npmjs.org/espurify/-/espurify-1.8.1.tgz#5746c6c1ab42d302de10bd1d5bf7f0e8c0515056" + dependencies: + core-js "^2.0.0" + +estraverse@^4.1.0, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express@^4.16.2: + version "4.16.3" + resolved "https://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.3" + qs "6.5.1" + range-parser "~1.2.0" + safe-buffer "5.1.1" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@^3.0.1, extend@~3.0.1: + version "3.0.2" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-glob@^2.0.2: + version "2.2.2" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf" + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.0.1" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.1" + micromatch "^3.1.10" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +faye-websocket@0.11.1: + version "0.11.1" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@0.9.3: + version "0.9.3" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.9.3.tgz#482a505b0df0ae626b969866d3bd740cdb962e83" + dependencies: + websocket-driver ">=0.5.1" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +firebase-admin@5.12.0: + version "5.12.0" + resolved "https://registry.npmjs.org/firebase-admin/-/firebase-admin-5.12.0.tgz#3291b0466b4d161cb4135e83c97f9878e7768cac" + dependencies: + "@firebase/app" "^0.1.10" + "@firebase/database" "^0.2.0" + "@google-cloud/firestore" "^0.13.1" + "@google-cloud/storage" "^1.6.0" + "@types/google-cloud__storage" "^1.1.7" + "@types/node" "^8.0.53" + faye-websocket "0.9.3" + jsonwebtoken "8.1.0" + node-forge "0.7.4" + +firebase-functions@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/firebase-functions/-/firebase-functions-1.0.1.tgz#13160e957d48135fc95c04b40f7fc24f6ebed565" + dependencies: + "@types/cors" "^2.8.1" + "@types/express" "^4.11.1" + "@types/jsonwebtoken" "^7.1.32" + "@types/lodash" "^4.14.34" + cors "^2.8.4" + express "^4.16.2" + jsonwebtoken "^7.1.9" + lodash "^4.6.1" + +follow-redirects@^1.3.0: + version "1.5.1" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" + dependencies: + debug "^3.1.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gcp-metadata@^0.6.1, gcp-metadata@^0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.6.3.tgz#4550c08859c528b370459bd77a7187ea0bdbc4ab" + dependencies: + axios "^0.18.0" + extend "^3.0.1" + retry-axios "0.3.2" + +gcs-resumable-upload@^0.10.2: + version "0.10.2" + resolved "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-0.10.2.tgz#7f29b3ee23dcec4170367c0711418249c660545f" + dependencies: + configstore "^3.1.2" + google-auto-auth "^0.10.0" + pumpify "^1.4.0" + request "^2.85.0" + stream-events "^1.0.3" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + +glob@^7.0.5, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +globby@^8.0.0: + version "8.0.1" + resolved "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50" + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + fast-glob "^2.0.2" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +google-auth-library@^1.3.1: + version "1.6.1" + resolved "https://registry.npmjs.org/google-auth-library/-/google-auth-library-1.6.1.tgz#9c73d831ad720c0c3048ab89d0ffdec714d07dd2" + dependencies: + axios "^0.18.0" + gcp-metadata "^0.6.3" + gtoken "^2.3.0" + jws "^3.1.5" + lodash.isstring "^4.0.1" + lru-cache "^4.1.3" + retry-axios "^0.3.2" + +google-auto-auth@^0.10.0: + version "0.10.1" + resolved "https://registry.npmjs.org/google-auto-auth/-/google-auto-auth-0.10.1.tgz#68834a6f3da59a6cb27fce56f76e3d99ee49d0a2" + dependencies: + async "^2.3.0" + gcp-metadata "^0.6.1" + google-auth-library "^1.3.1" + request "^2.79.0" + +google-gax@^0.16.0: + version "0.16.1" + resolved "https://registry.npmjs.org/google-gax/-/google-gax-0.16.1.tgz#30bf1284a1c384cd31a01163def4d671cec10c0f" + dependencies: + duplexify "^3.5.4" + extend "^3.0.0" + globby "^8.0.0" + google-auto-auth "^0.10.0" + google-proto-files "^0.15.0" + grpc "^1.10.0" + is-stream-ended "^0.1.0" + lodash "^4.17.2" + protobufjs "^6.8.0" + through2 "^2.0.3" + +google-p12-pem@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.2.tgz#c8a3843504012283a0dbffc7430b7c753ecd4b07" + dependencies: + node-forge "^0.7.4" + pify "^3.0.0" + +google-proto-files@^0.15.0: + version "0.15.1" + resolved "https://registry.npmjs.org/google-proto-files/-/google-proto-files-0.15.1.tgz#5c9c485e574e2c100fe829a5ec0bbb3d9bc789a2" + dependencies: + globby "^7.1.1" + power-assert "^1.4.4" + protobufjs "^6.8.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +grpc@^1.10.0: + version "1.13.1" + resolved "https://registry.npmjs.org/grpc/-/grpc-1.13.1.tgz#9b5c49d4e56309b6e3bd631f8948b7b298d88790" + dependencies: + lodash "^4.17.5" + nan "^2.0.0" + node-pre-gyp "^0.10.0" + protobufjs "^5.0.3" + +gtoken@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/gtoken/-/gtoken-2.3.0.tgz#4e0ffc16432d7041a1b3dbc1d97aac17a5dc964a" + dependencies: + axios "^0.18.0" + google-p12-pem "^1.0.0" + jws "^3.1.4" + mime "^2.2.0" + pify "^3.0.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hash-stream-validation@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.1.tgz#ecc9b997b218be5bb31298628bb807869b73dcd1" + dependencies: + through2 "^2.0.0" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.4.0: + version "0.4.13" + resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +iconv-lite@^0.4.4: + version "0.4.23" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-stream-ended@^0.1.0: + version "0.1.4" + resolved "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is@^3.0.1, is@^3.2.0, is@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isemail@1.x.x: + version "1.2.0" + resolved "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +joi@^6.10.1: + version "6.10.1" + resolved "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" + dependencies: + hoek "2.x.x" + isemail "1.x.x" + moment "2.x.x" + topo "1.x.x" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsonwebtoken@8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz#c6397cd2e5fd583d65c007a83dc7bb78e6982b83" + dependencies: + jws "^3.1.4" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.0.0" + xtend "^4.0.1" + +jsonwebtoken@^7.1.9: + version "7.4.3" + resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz#77f5021de058b605a1783fa1283e99812e645638" + dependencies: + joi "^6.10.1" + jws "^3.1.4" + lodash.once "^4.0.0" + ms "^2.0.0" + xtend "^4.0.1" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jwa@^1.1.5: + version "1.1.6" + resolved "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz#87240e76c9808dbde18783cf2264ef4929ee50e6" + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.10" + safe-buffer "^5.0.1" + +jws@^3.1.4, jws@^3.1.5: + version "3.1.5" + resolved "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz#80d12d05b293d1e841e7cb8b4e69e561adcf834f" + dependencies: + jwa "^1.1.5" + safe-buffer "^5.0.1" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.5, lodash@^4.6.1: + version "4.17.10" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +log-driver@1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" + +long@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + +long@~3: + version "3.2.0" + resolved "https://registry.npmjs.org/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" + +lru-cache@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge2@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34" + +methmeth@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/methmeth/-/methmeth-1.1.0.tgz#e80a26618e52f5c4222861bb748510bd10e29089" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +"mime-db@>= 1.34.0 < 2", mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + +mime-types@^2.0.8, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18: + version "2.1.19" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mime@^2.2.0: + version "2.3.1" + resolved "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +modelo@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/modelo/-/modelo-4.2.3.tgz#b278588a4db87fc1e5107ae3a277c0876f38d894" + +moment@2.x.x: + version "2.22.2" + resolved "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +nan@^2.0.0: + version "2.10.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +node-forge@0.7.4: + version "0.7.4" + resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.7.4.tgz#8e6e9f563a1e32213aa7508cded22aa791dbf986" + +node-forge@^0.7.4: + version "0.7.5" + resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.11" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.0, object-keys@^1.0.8: + version "1.0.12" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +optjs@~3.2.2: + version "3.2.2" + resolved "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + dependencies: + pify "^3.0.0" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +power-assert-context-formatter@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-context-formatter/-/power-assert-context-formatter-1.2.0.tgz#8fbe72692288ec5a7203cdf215c8b838a6061d2a" + dependencies: + core-js "^2.0.0" + power-assert-context-traversal "^1.2.0" + +power-assert-context-reducer-ast@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-context-reducer-ast/-/power-assert-context-reducer-ast-1.2.0.tgz#c7ca1c9e39a6fb717f7ac5fe9e76e192bf525df3" + dependencies: + acorn "^5.0.0" + acorn-es7-plugin "^1.0.12" + core-js "^2.0.0" + espurify "^1.6.0" + estraverse "^4.2.0" + +power-assert-context-traversal@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-context-traversal/-/power-assert-context-traversal-1.2.0.tgz#f6e71454baf640de5c1c9c270349f5c9ab0b2e94" + dependencies: + core-js "^2.0.0" + estraverse "^4.1.0" + +power-assert-formatter@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/power-assert-formatter/-/power-assert-formatter-1.4.1.tgz#5dc125ed50a3dfb1dda26c19347f3bf58ec2884a" + dependencies: + core-js "^2.0.0" + power-assert-context-formatter "^1.0.7" + power-assert-context-reducer-ast "^1.0.7" + power-assert-renderer-assertion "^1.0.7" + power-assert-renderer-comparison "^1.0.7" + power-assert-renderer-diagram "^1.0.7" + power-assert-renderer-file "^1.0.7" + +power-assert-renderer-assertion@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-renderer-assertion/-/power-assert-renderer-assertion-1.2.0.tgz#3db6ffcda106b37bc1e06432ad0d748a682b147a" + dependencies: + power-assert-renderer-base "^1.1.1" + power-assert-util-string-width "^1.2.0" + +power-assert-renderer-base@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/power-assert-renderer-base/-/power-assert-renderer-base-1.1.1.tgz#96a650c6fd05ee1bc1f66b54ad61442c8b3f63eb" + +power-assert-renderer-comparison@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-renderer-comparison/-/power-assert-renderer-comparison-1.2.0.tgz#e4f88113225a69be8aa586ead05aef99462c0495" + dependencies: + core-js "^2.0.0" + diff-match-patch "^1.0.0" + power-assert-renderer-base "^1.1.1" + stringifier "^1.3.0" + type-name "^2.0.1" + +power-assert-renderer-diagram@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-renderer-diagram/-/power-assert-renderer-diagram-1.2.0.tgz#37f66e8542e5677c5b58e6d72b01c0d9a30e2219" + dependencies: + core-js "^2.0.0" + power-assert-renderer-base "^1.1.1" + power-assert-util-string-width "^1.2.0" + stringifier "^1.3.0" + +power-assert-renderer-file@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-renderer-file/-/power-assert-renderer-file-1.2.0.tgz#3f4bebd9e1455d75cf2ac541e7bb515a87d4ce4b" + dependencies: + power-assert-renderer-base "^1.1.1" + +power-assert-util-string-width@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/power-assert-util-string-width/-/power-assert-util-string-width-1.2.0.tgz#6e06d5e3581bb876c5d377c53109fffa95bd91a0" + dependencies: + eastasianwidth "^0.2.0" + +power-assert@^1.4.4: + version "1.6.0" + resolved "https://registry.npmjs.org/power-assert/-/power-assert-1.6.0.tgz#3a9d2b943cf0d6fc6a623766869c4460838c05fb" + dependencies: + define-properties "^1.1.2" + empower "^1.3.0" + power-assert-formatter "^1.4.1" + universal-deep-strict-equal "^1.2.1" + xtend "^4.0.0" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +protobufjs@^5.0.3: + version "5.0.3" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17" + dependencies: + ascli "~1" + bytebuffer "~5" + glob "^7.0.5" + yargs "^3.10.0" + +protobufjs@^6.8.0: + version "6.8.8" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + +proxy-addr@~2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.4.0, pumpify@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@6.5.1: + version "6.5.1" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2: + version "2.3.6" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~1.0.32: + version "1.0.34" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +request@^2.79.0, request@^2.81.0, request@^2.85.0: + version "2.87.0" + resolved "https://registry.npmjs.org/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +retry-axios@0.3.2, retry-axios@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz#5757c80f585b4cc4c4986aa2ffd47a60c6d35e13" + +retry-request@^3.0.0, retry-request@^3.3.1: + version "3.3.2" + resolved "https://registry.npmjs.org/retry-request/-/retry-request-3.3.2.tgz#fd8e0079e7b0dfc7056e500b6f089437db0da4df" + dependencies: + request "^2.81.0" + through2 "^2.0.0" + +rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +safe-buffer@5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +semver@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +send@0.16.2: + version "0.16.2" + resolved "https://registry.npmjs.org/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +snakeize@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz#10c088d8b58eb076b3229bb5a04e232ce126422d" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +split-array-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/split-array-stream/-/split-array-stream-1.0.3.tgz#d2b75a8e5e0d824d52fdec8b8225839dc2e35dfa" + dependencies: + async "^2.4.0" + is-stream-ended "^0.1.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sshpk@^1.7.0: + version "1.14.2" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + safer-buffer "^2.0.2" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stream-events@^1.0.1, stream-events@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/stream-events/-/stream-events-1.0.4.tgz#73bfd4007b8f677b46ec699f14e9e2304c2f0a9e" + dependencies: + stubs "^3.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +string-format-obj@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/string-format-obj/-/string-format-obj-1.1.1.tgz#c7612ca4e2ad923812a81db192dc291850aa1f65" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +stringifier@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/stringifier/-/stringifier-1.3.0.tgz#def18342f6933db0f2dbfc9aa02175b448c17959" + dependencies: + core-js "^2.0.0" + traverse "^0.6.6" + type-name "^2.0.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +stubs@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" + +tar@^4: + version "4.4.4" + resolved "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +through2@^2.0.0, through2@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +topo@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" + dependencies: + hoek "2.x.x" + +tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +traverse@^0.6.6: + version "0.6.6" + resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + +tslib@1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-is@~1.6.15, type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +type-name@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/type-name/-/type-name-2.0.2.tgz#efe7d4123d8ac52afff7f40c7e4dec5266008fb4" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + +universal-deep-strict-equal@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/universal-deep-strict-equal/-/universal-deep-strict-equal-1.2.2.tgz#0da4ac2f73cff7924c81fa4de018ca562ca2b0a7" + dependencies: + array-filter "^1.0.0" + indexof "0.0.1" + object-keys "^1.0.0" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@^3.1.0: + version "3.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +window-size@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.0: + version "3.2.1" + resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs@^3.10.0: + version "3.32.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" + dependencies: + camelcase "^2.0.1" + cliui "^3.0.3" + decamelize "^1.1.1" + os-locale "^1.4.0" + string-width "^1.0.1" + window-size "^0.1.4" + y18n "^3.2.0" diff --git a/packages/auth/demo/public/web-worker.js b/packages/auth/demo/public/web-worker.js index 442e3bd774e..37cce8d48ec 100644 --- a/packages/auth/demo/public/web-worker.js +++ b/packages/auth/demo/public/web-worker.js @@ -77,11 +77,11 @@ var runWorkerTests = function(googleIdToken) { firebase.auth().useDeviceLanguage(); return firebase.auth().signInAnonymously(); }) - .then(function(user) { - if (!user.uid) { + .then(function(result) { + if (!result.user.uid) { throw new Error('signInAnonymously unexpectedly failed!'); } - return user.updateProfile({displayName: expectedDisplayName}); + return result.user.updateProfile({displayName: expectedDisplayName}); }) .then(function() { if (firebase.auth().currentUser.displayName != expectedDisplayName) { @@ -95,8 +95,8 @@ var runWorkerTests = function(googleIdToken) { } return firebase.auth().createUserWithEmailAndPassword(email, pass); }) - .then(function(user) { - if (user.email != email) { + .then(function(result) { + if (result.user.email != email) { throw new Error( 'createUserWithEmailAndPassword unexpectedly failed!'); } @@ -107,11 +107,11 @@ var runWorkerTests = function(googleIdToken) { } return firebase.auth().signInWithEmailAndPassword(email, pass); }) - .then(function(user) { - if (user.email != email) { + .then(function(result) { + if (result.user.email != email) { throw new Error('signInWithEmailAndPassword unexpectedly failed!'); } - return user.delete(); + return result.user.delete(); }) .then(function() { return firebase.auth().signInWithPopup(provider) diff --git a/packages/auth/src/messagechannel/defines.js b/packages/auth/src/messagechannel/defines.js new file mode 100644 index 00000000000..29f1706c1ab --- /dev/null +++ b/packages/auth/src/messagechannel/defines.js @@ -0,0 +1,65 @@ +/** + * @fileoverview Defines the MessageChannel common utilities and enums. + */ + +goog.provide('fireauth.messagechannel.Error'); +goog.provide('fireauth.messagechannel.Status'); +goog.provide('fireauth.messagechannel.TimeoutDuration'); +goog.provide('fireauth.messagechannel.utils'); + + +/** + * Enum for the messagechannel error messages. These errors are not meant to be + * user facing. + * @enum {string} + */ +fireauth.messagechannel.Error = { + CONNECTION_UNAVAILABLE: 'connection_unavailable', + INVALID_RESPONSE: 'invalid_response', + TIMEOUT: 'timeout', + UNKNOWN: 'unknown_error', + UNSUPPORTED_EVENT: 'unsupported_event' +}; + + +/** + * Enum for the message channel request status labels. + * @enum {string} + */ +fireauth.messagechannel.Status = { + ACK: 'ack', + DONE: 'done' +}; + + +/** + * Enum for the timeout durations in milliseconds for different contexts. + * @enum {number} + */ +fireauth.messagechannel.TimeoutDuration = { + ACK: 20, + COMPLETION: 500 +}; + + +/** + * @param {?string=} opt_prefix An optional prefix string to prepend to ID. + * @param {?number=} opt_digits An optional number of digits used for event ID. + * @return {string} The generated event ID used to identify a generic event. + */ +fireauth.messagechannel.utils.generateEventId = + function(opt_prefix, opt_digits) { + // 0, null and undefined will default to 20. + var digits = opt_digits || 20; + return opt_prefix ? opt_prefix : '' + + Math.floor(Math.random() * Math.pow(10, digits)).toString(); +}; + + +/** + * @return {?MessageChannel} The initialized MessageChannel instance if + * supported. + */ +fireauth.messagechannel.utils.initializeMessageChannel = function() { + return typeof MessageChannel !== 'undefined' ? new MessageChannel() : null; +}; diff --git a/packages/auth/src/messagechannel/postmessager.js b/packages/auth/src/messagechannel/postmessager.js new file mode 100644 index 00000000000..dca90293784 --- /dev/null +++ b/packages/auth/src/messagechannel/postmessager.js @@ -0,0 +1,114 @@ +/** + * @fileoverview Defines the PostMessager interface needed for the + * `fireauth.messagechannel.Sender`, in addition to 2 types of implementations. + */ + +goog.provide('fireauth.messagechannel.PostMessager'); +goog.provide('fireauth.messagechannel.WindowPostMessager'); +goog.provide('fireauth.messagechannel.WorkerClientPostMessager'); + + +/** + * This is the interface defining the postMessage format of a window which + * takes an additional second parameter for target origin. + * + * @typedef {{ + * postMessage: function(*, string, !Array) + * }} + */ +fireauth.messagechannel.Window; + + +/** + * This is the interface defining the postMessage format of a worker or + * ServiceWorkerClient, etc. which just takes a message and a list of + * Transferables. + * + * @typedef {{ + * postMessage: function(*, !Array) + * }} + */ +fireauth.messagechannel.WorkerClient; + + +/** + * Defines a common interface to postMessage data to a specified PostMessager. + * @interface + */ +fireauth.messagechannel.PostMessager = function() {}; + + +/** + * Sends a message to the specified context. + * @param {*} message The message to send. + * @param {!Array} transfer The list of `Transferable` objects + * that are transferred with the message. The ownsership fo these objects is + * given to the destination side and they are no longer usable on the + * sending side. + */ +fireauth.messagechannel.PostMessager.prototype.postMessage = + function(message, transfer) {}; + + + +/** + * Defines the implementation for postMessaging to a window context. + * @param {!fireauth.messagechannel.Window} win The window PostMessager. + * @param {?string=} opt_targetOrigin The target origin. + * @constructor + * @implements {fireauth.messagechannel.PostMessager} + */ +fireauth.messagechannel.WindowPostMessager = function(win, opt_targetOrigin) { + /** + * @const @private {!fireauth.messagechannel.Window} The window PostMessager. + */ + this.win_ = win; + /** @const @private {string} The postMessage target origin. */ + this.targetOrigin_ = opt_targetOrigin || '*'; +}; + + +/** + * Sends a message to the specified window context. + * @param {*} message The message to send. + * @param {!Array} transfer The list of `Transferable` objects + * that are transferred with the message. The ownsership fo these objects is + * given to the destination side and they are no longer usable on the + * sending side. + * @override + */ +fireauth.messagechannel.WindowPostMessager.prototype.postMessage = + function(message, transfer) { + this.win_.postMessage(message, this.targetOrigin_, transfer); +}; + + +/** + * Defines the implementation for postMessaging to a worker/client context. + * @param {!fireauth.messagechannel.WorkerClient} worker The worker/client + * PostMessager. + * @constructor + * @implements {fireauth.messagechannel.PostMessager} + */ +fireauth.messagechannel.WorkerClientPostMessager = function(worker) { + /** + * @const @private {!fireauth.messagechannel.WorkerClient} The worker/client + * PostMessager. + */ + this.worker_ = worker; +}; + + +/** + * Sends a message to the specified worker/client context. + * @param {*} message The message to send. + * @param {!Array} transfer The list of `Transferable` objects + * that are transferred with the message. The ownsership fo these objects is + * given to the destination side and they are no longer usable on the + * sending side. + * @override + */ +fireauth.messagechannel.WorkerClientPostMessager.prototype.postMessage = + function(message, transfer) { + this.worker_.postMessage(message, transfer); +}; diff --git a/packages/auth/src/messagechannel/receiver.js b/packages/auth/src/messagechannel/receiver.js new file mode 100644 index 00000000000..ca5eee10c10 --- /dev/null +++ b/packages/auth/src/messagechannel/receiver.js @@ -0,0 +1,206 @@ +/** + * @fileoverview Defines the MessageChannel based wrapper for receiving + * messages from other windows or workers. + */ + +goog.provide('fireauth.messagechannel.Receiver'); + +goog.require('fireauth.messagechannel.Status'); +goog.require('goog.Promise'); +goog.require('goog.array'); +goog.require('goog.object'); + + +/** + * Initializes a channel to receive specific messages from a specified event + * target. + * Note receivers should not be manually instantiated. Instead `getInstance()` + * should be used instead to get a receiver instance for a specified event + * target. + * @param {!EventTarget} eventTarget The event target to listen to. + * @constructor + */ +fireauth.messagechannel.Receiver = function(eventTarget) { + /** + * @const @private {!EventTarget} The messageChannel event target. + */ + this.eventTarget_ = eventTarget; + /** + * @const @private {!Object.|void>>} + * This is the event type to handlers hash map. It is used to hold the + * corresponding handlers for specified events. + */ + this.eventHandlers_ = {}; + /** + * @const@private {function(!Event)} The internal 'message' event handler used + * to reroute the request to corresponding subscribed handlers. + */ + this.messageEventHandler_ = goog.bind(this.handleEvent_, this); +}; + + +/** + * @param {!EventTarget} eventTarget The event target to check for. + * @return {boolean} Whether the receiver is listening to the specified event + * target. + */ +fireauth.messagechannel.Receiver.prototype.isListeningTo = + function(eventTarget) { + return this.eventTarget_ == eventTarget; +}; + + +/** + * @const @private {!Array} The list of all + * created `fireauth.messagechannel.Receiver` instances. + */ +fireauth.messagechannel.Receiver.receivers_ = []; + + +/** + * Return a receiver instance for the specified event target. This is needed + * since one instance can be available per event target. Otherwise receivers + * could clobber each other. + * @param {!EventTarget} eventTarget The event target to listen to. + * @return {!fireauth.messagechannel.Receiver} The receiver instance for the + * specified event target. + */ +fireauth.messagechannel.Receiver.getInstance = function(eventTarget) { + // The results are stored in an array since objects can't be keys for other + // objects. In addition, setting a unique property on an event target as a + // hash map key may not be allowed due to CORS restrictions. + var instance; + goog.array.forEach( + fireauth.messagechannel.Receiver.receivers_, + function(receiver) { + if (receiver.isListeningTo(eventTarget)) { + instance = receiver; + } + }); + if (!instance) { + instance = new fireauth.messagechannel.Receiver(eventTarget); + fireauth.messagechannel.Receiver.receivers_.push(instance); + } + return instance; +}; + + +/** + * Handles a PostMessage event based on the following protocol: + * + * + * @param {!Event} event The PostMessage event to handle. + * @private + */ +fireauth.messagechannel.Receiver.prototype.handleEvent_ = function(event) { + // Respond to sender first with ack reply. This will let the client + // know that the service worker can handle this event. + var eventType = event.data['eventType']; + var eventId = event.data['eventId']; + var handlers = this.eventHandlers_[eventType]; + if (handlers && handlers.length > 0) { + // Event can be handled. + event.ports[0].postMessage({ + 'status': fireauth.messagechannel.Status.ACK, + 'eventId': eventId, + 'eventType': eventType, + 'response': null + }); + var promises = []; + goog.array.forEach(handlers, function(handler) { + // Wrap in promise in case the handler doesn't return a promise. + promises.push(goog.Promise.resolve().then(function() { + return handler(event.origin, event.data['data']); + })); + }); + // allSettled is more flexible as it executes all the promises passed and + // returns whether they succeeded or failed. + goog.Promise.allSettled(promises) + .then(function(result) { + // allResponse has the format: + // !Array + // Respond to sender with ack reply. + // De-obfuscate the allSettled result. + var allResponses = []; + goog.array.forEach(result, function(item) { + allResponses.push({ + 'fulfilled': item.fulfilled, + 'value': item.value, + // Error cannot be clone in postMessage. + 'reason': item.reason ? item.reason.message : undefined + }); + }); + // Remove undefined fields. + goog.array.forEach(allResponses, function(item) { + for (var key in item) { + if (typeof item[key] === 'undefined') { + delete item[key]; + } + } + }); + event.ports[0].postMessage({ + 'status': fireauth.messagechannel.Status.DONE, + 'eventId': eventId, + 'eventType': eventType, + 'response': allResponses + }); + }); + } + // Let unsupported events time out, as there could be external receivers + // that can handle them. +}; + + +/** + * Subscribes to events of the specified type. + * @param {string} eventType The event type to listen to. + * @param {function(string, *):!goog.Promise<*>|void} handler The async callback + * function to run when the event is triggered. + */ +fireauth.messagechannel.Receiver.prototype.subscribe = + function(eventType, handler) { + if (goog.object.isEmpty(this.eventHandlers_)) { + this.eventTarget_.addEventListener('message', this.messageEventHandler_); + } + if (typeof this.eventHandlers_[eventType] === 'undefined') { + this.eventHandlers_[eventType] = []; + } + this.eventHandlers_[eventType].push(handler); +}; + + +/** + * Unsubscribes the specified handler from the specified event. If no handler + * is specified, all handlers are unsubscribed. + * @param {string} eventType The event type to unsubscribe from. + * @param {?function(string, *):!goog.Promise<*>|void=} opt_handler The + * callback function to unsubscribe from the specified event type. If none + * is specified, all handlers are unsubscribed. + */ +fireauth.messagechannel.Receiver.prototype.unsubscribe = + function(eventType, opt_handler) { + if (typeof this.eventHandlers_[eventType] !== 'undefined' && opt_handler) { + goog.array.removeAllIf(this.eventHandlers_[eventType], function(ele) { + return ele == opt_handler; + }); + if (this.eventHandlers_[eventType].length == 0) { + delete this.eventHandlers_[eventType]; + } + } else if (!opt_handler) { + // Unsubscribe all handlers for speficied event. + delete this.eventHandlers_[eventType]; + } + if (goog.object.isEmpty(this.eventHandlers_)) { + this.eventTarget_.removeEventListener('message', this.messageEventHandler_); + } +}; diff --git a/packages/auth/src/messagechannel/sender.js b/packages/auth/src/messagechannel/sender.js new file mode 100644 index 00000000000..cf0d9df28e0 --- /dev/null +++ b/packages/auth/src/messagechannel/sender.js @@ -0,0 +1,221 @@ +/** + * @fileoverview Defines the MessageChannel based wrapper for sending messages + * to other windows or workers. + */ + +goog.provide('fireauth.messagechannel.Sender'); + +goog.require('fireauth.messagechannel.Error'); +goog.require('fireauth.messagechannel.PostMessager'); +goog.require('fireauth.messagechannel.Status'); +goog.require('fireauth.messagechannel.TimeoutDuration'); +goog.require('fireauth.messagechannel.utils'); +goog.require('goog.Promise'); +goog.require('goog.array'); + + + +/** + * Helper static function to create messageChannel errors. + * @param {!fireauth.messagechannel.Error} errorId The error identifier. + * @param {?string=} opt_message The optional error message used for generic + * error types. + * @return {!Error} The constructed error to return. + * @private + */ +fireauth.messagechannel.createError_ = function(errorId, opt_message) { + if (errorId != fireauth.messagechannel.Error.UNKNOWN || !opt_message) { + return new Error(errorId); + } else { + return new Error(opt_message); + } +}; + + +/** + * Initializes a channel to send specific messages to a specified PostMessage. + * @param {!fireauth.messagechannel.PostMessager} postMessager The post messager + * to send messages to. + * @constructor + */ +fireauth.messagechannel.Sender = function(postMessager) { + /** + * @const @private {!fireauth.messagechannel.PostMessager} The messageChannel + * PostMessager. + */ + this.postMessager_ = postMessager; + /** + * @private {?MessageChannel} The messageChannel reference if + * supported. + */ + this.messageChannel_ = + fireauth.messagechannel.utils.initializeMessageChannel(); + /** @private {boolean} Whether the connection was started. */ + this.started_ = false; + /** + * @const @private {!Array} The list of subscribed message + * handlers. + */ + this.messageHandlers_ = []; +}; + + +/** + * Sends a message to the receiver. The message is identified by an event + * type and can carry additional payload data. + * The sender protocol works as follows: + *
    + *
  • The request is constructed and postMessaged to the receiver with the port + * used to reply back to sender.
  • + *
  • The operation will block until an ACK response is received. If not, it + * will timeout and reject with an error.
  • + *
  • If an ACK response is received, it will wait longer for the full + * processed response.
  • + *
  • Once the response is received, the operation will resolve with that + * result.
  • + *
+ * + * @param {string} eventType The event type identifying the message. This is + * used to help the receiver handle this message. + * @param {?Object=} opt_data The optional data to send along the message. + * @return {!goog.Promise>} A promise that + * resolves with the receiver responses. + */ +fireauth.messagechannel.Sender.prototype.send = function(eventType, opt_data) { + var self = this; + var eventId; + var data = opt_data || {}; + var onMessage; + var ackTimer; + var completionTimer; + return new goog.Promise(function(resolve, reject) { + // Send message along with port for reply + if (self.messageChannel_) { + eventId = fireauth.messagechannel.utils.generateEventId(); + // Start the connection if not already started. + self.start(); + // Handler for receiving message reply from receiver. + // Blocks promise resolution until service worker detects the change. + ackTimer = setTimeout(function() { + // The receiver may not be able to handle the response for various + // reasons: library not included, or an incompatible version of + // the library is included. + // Timeout after some time. + reject(fireauth.messagechannel.createError_( + fireauth.messagechannel.Error.UNSUPPORTED_EVENT)); + }, fireauth.messagechannel.TimeoutDuration.ACK); + onMessage = function(event) { + // Process only the expected events that match current event ID. + if (event.data['eventId'] !== eventId) { + return; + } + // This avoids adding a long wait when the receiver is unable to handle + // the event. + if (event.data['status'] === fireauth.messagechannel.Status.ACK) { + clearTimeout(ackTimer); + // Set longer timeout to allow receiver to process. + completionTimer = setTimeout(function() { + reject(fireauth.messagechannel.createError_( + fireauth.messagechannel.Error.TIMEOUT)); + }, fireauth.messagechannel.TimeoutDuration.COMPLETION); + return; + } else if (event.data['status'] === + fireauth.messagechannel.Status.DONE) { + clearTimeout(completionTimer); + if (typeof event.data['response'] !== 'undefined') { + resolve(event.data['response']); + } else { + reject(fireauth.messagechannel.createError_( + fireauth.messagechannel.Error.UNKNOWN)); + } + } else { + clearTimeout(ackTimer); + clearTimeout(completionTimer); + reject(fireauth.messagechannel.createError_( + fireauth.messagechannel.Error.INVALID_RESPONSE)); + } + }; + self.messageHandlers_.push(onMessage); + self.messageChannel_.port1.addEventListener('message', onMessage); + var request = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + // It is possible the receiver cannot handle this result. + // For example, the developer may not be including the library in the + // receiver or using an outdated version. + self.postMessager_.postMessage( + request, + [self.messageChannel_.port2]); + } else { + // No connection available. + reject(fireauth.messagechannel.createError_( + fireauth.messagechannel.Error.CONNECTION_UNAVAILABLE)); + } + }).then(function(result) { + // On completion, remove the message handler. A new one is needed for a + // new message. + self.removeMessageHandler_(onMessage); + return result; + }).thenCatch(function(error) { + // On failure, remove the message handler. A new one is needed for a new + // message. + self.removeMessageHandler_(onMessage); + throw error; + }); +}; + + +/** + * @param {function(!Event)} onMessage The message handler to remove. + * @private + */ +fireauth.messagechannel.Sender.prototype.removeMessageHandler_ = + function(onMessage) { + if (this.messageChannel_) { + goog.array.removeAllIf(this.messageHandlers_, function(ele) { + return ele == onMessage; + }); + this.messageChannel_.port1.removeEventListener('message', onMessage); + } +}; + + +/** + * Removing all subscribed message handlers. + * @private + */ +fireauth.messagechannel.Sender.prototype.removeAllMessageHandlers_ = + function() { + while (this.messageHandlers_.length > 0) { + var onMessage = this.messageHandlers_.pop(); + this.messageChannel_.port1.removeEventListener('message', onMessage); + } +}; + + +/** Closes the underlying MessageChannel connection. */ +fireauth.messagechannel.Sender.prototype.close = function() { + if (this.messageChannel_) { + // Any pending event will timeout. + this.removeAllMessageHandlers_(); + // No new messages will be returned. + this.messageChannel_.port1.close(); + this.messageChannel_ = null; + this.started_ = false; + } +}; + + +/** Starts the underlying MessageChannel connection if not already started. */ +fireauth.messagechannel.Sender.prototype.start = function() { + // Note that re-connection is not supported. If a connection is closed, a new + // sender has to be created. + if (this.messageChannel_ && !this.started_) { + this.messageChannel_.port1.start(); + this.started_ = true; + } +}; diff --git a/packages/auth/src/storage/indexeddb.js b/packages/auth/src/storage/indexeddb.js index 6f9d4ac2f33..dcd71ecec1b 100644 --- a/packages/auth/src/storage/indexeddb.js +++ b/packages/auth/src/storage/indexeddb.js @@ -24,6 +24,9 @@ goog.provide('fireauth.storage.IndexedDB'); goog.require('fireauth.AuthError'); goog.require('fireauth.authenum.Error'); +goog.require('fireauth.messagechannel.Receiver'); +goog.require('fireauth.messagechannel.Sender'); +goog.require('fireauth.messagechannel.WorkerClientPostMessager'); goog.require('fireauth.storage.Storage'); goog.require('fireauth.util'); goog.require('goog.Promise'); @@ -96,6 +99,36 @@ fireauth.storage.IndexedDB = function( opt_indexedDB || goog.global.indexedDB); /** @public {string} The storage type identifier. */ this.type = fireauth.storage.Storage.Type.INDEXEDDB; + /** + * @private {?fireauth.messagechannel.Receiver} The messageChannel receiver if + * running from a serviceworker. + */ + this.receiver_ = null; + var scope = this; + if (fireauth.util.getWorkerGlobalScope()) { + this.receiver_ = fireauth.messagechannel.Receiver.getInstance( + /** @type {!WorkerGlobalScope} */ ( + fireauth.util.getWorkerGlobalScope())); + // Listen to indexedDB changes. + this.receiver_.subscribe('keyChanged', function(origin, request) { + // Sync data. + return scope.sync_().then(function(keys) { + // Trigger listeners if unhandled changes are detected. + if (keys.length > 0) { + goog.array.forEach( + scope.storageListeners_, + function(listener) { + listener(keys); + }); + } + // When this is false, it means the change was already + // detected and processed before the notification. + return { + 'keyProcessed': goog.array.contains(keys, request['key']) + }; + }); + }); + } }; @@ -361,6 +394,8 @@ fireauth.storage.IndexedDB.prototype.set = function(key, value) { .then(function() { // Save in local copy to avoid triggering false external event. self.localMap_[key] = value; + // Announce change in key to service worker. + return self.notifySW_(key); }) .thenAlways(function() { if (isLocked) { @@ -370,6 +405,31 @@ fireauth.storage.IndexedDB.prototype.set = function(key, value) { }; +/** + * Notify the service worker of the indexeDB write operation. + * Waits until the operation is processed. + * @param {string} key The key which is changing. + * @return {!goog.Promise} A promise that resolves on delivery. + * @private + */ +fireauth.storage.IndexedDB.prototype.notifySW_ = function(key) { + if (fireauth.util.getServiceWorkerController()) { + var sender = new fireauth.messagechannel.Sender( + new fireauth.messagechannel.WorkerClientPostMessager( + /** @type {!ServiceWorker} */ ( + fireauth.util.getServiceWorkerController()))); + return sender.send('keyChanged', {'key': key}) + .then(function(responses) { + // Return nothing. + }) + .thenCatch(function(error) { + // This is a best effort approach. Ignore errors. + }); + } + return goog.Promise.resolve(); +}; + + /** * Retrieves a stored item identified by the key provided asynchronously. * The value is passed to the callback function provided. @@ -411,6 +471,8 @@ fireauth.storage.IndexedDB.prototype.remove = function(key) { }).then(function() { // Delete from local copy to avoid triggering false external event. delete self.localMap_[key]; + // Announce change in key to service worker. + return self.notifySW_(key); }).thenAlways(function() { if (isLocked) { self.pendingOpsTracker_--; diff --git a/packages/auth/src/utils.js b/packages/auth/src/utils.js index ebd9e26e8d9..f6c731f15fc 100644 --- a/packages/auth/src/utils.js +++ b/packages/auth/src/utils.js @@ -1455,3 +1455,18 @@ fireauth.util.setNoReferrer = function() { } } }; + + +/** @return {?ServiceWorker} The servicerWorker controller if available. */ +fireauth.util.getServiceWorkerController = function() { + return (navigator && + navigator.serviceWorker && + navigator.serviceWorker.controller) || null; +}; + + +/** @return {?WorkerGlobalScope} The worker global scope if available. */ +fireauth.util.getWorkerGlobalScope = function() { + return fireauth.util.isWorker() ? /** @type {!WorkerGlobalScope} */ (self) : + null; +}; diff --git a/packages/auth/test/messagechannel/postmessager_test.js b/packages/auth/test/messagechannel/postmessager_test.js new file mode 100644 index 00000000000..e301a372dc6 --- /dev/null +++ b/packages/auth/test/messagechannel/postmessager_test.js @@ -0,0 +1,72 @@ +/** + * @fileoverview Tests for postmessager.js. + */ + +goog.provide('fireauth.messagechannel.PostMessagerTest'); + +goog.require('fireauth.messagechannel.WindowPostMessager'); +goog.require('fireauth.messagechannel.WorkerClientPostMessager'); +goog.require('goog.testing.MockControl'); +goog.require('goog.testing.jsunit'); + +goog.setTestOnly('fireauth.messagechannel.PostMessagerTest'); + + +var mockControl; + + +function setUp() { + mockControl = new goog.testing.MockControl(); + mockControl.$resetAll(); +} + + +function tearDown() { + try { + mockControl.$verifyAll(); + } finally { + mockControl.$tearDown(); + } +} + + +function testWindowPostMessager_defaultTargetOrigin() { + var message = {'a': 1, 'b': 2}; + var transfer = [{'tranferable1': {}}, {'tranferable2': {}}]; + var targetOrigin = '*'; + var postMessage = mockControl.createFunctionMock('postMessage'); + postMessage(message, targetOrigin, transfer).$once(); + mockControl.$replayAll(); + + var windowPostMessager = new fireauth.messagechannel.WindowPostMessager( + {'postMessage': postMessage}); + windowPostMessager.postMessage(message, transfer); +} + + +function testWindowPostMessager_explicitTargetOrigin() { + var message = {'a': 1, 'b': 2}; + var transfer = [{'tranferable1': {}}, {'tranferable2': {}}]; + var targetOrigin = 'http://www.example.com'; + var postMessage = mockControl.createFunctionMock('postMessage'); + postMessage(message, targetOrigin, transfer).$once(); + mockControl.$replayAll(); + + var windowPostMessager = new fireauth.messagechannel.WindowPostMessager( + {'postMessage': postMessage}, targetOrigin); + windowPostMessager.postMessage(message, transfer); +} + + +function testWorkerClientPostMessager() { + var message = {'a': 1, 'b': 2}; + var transfer = [{'tranferable1': {}}, {'tranferable2': {}}]; + var postMessage = mockControl.createFunctionMock('postMessage'); + postMessage(message, transfer); + mockControl.$replayAll(); + + var workerClientPostMessager = + new fireauth.messagechannel.WorkerClientPostMessager( + {'postMessage': postMessage}); + workerClientPostMessager.postMessage(message, transfer); +} diff --git a/packages/auth/test/messagechannel/receiver_test.js b/packages/auth/test/messagechannel/receiver_test.js new file mode 100644 index 00000000000..c7899396a2e --- /dev/null +++ b/packages/auth/test/messagechannel/receiver_test.js @@ -0,0 +1,462 @@ +/** + * @fileoverview Tests for receiver.js. + */ + +goog.provide('fireauth.messagechannel.ReceiverTest'); + +goog.require('fireauth.messagechannel.Receiver'); +goog.require('goog.Promise'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventTarget'); +goog.require('goog.testing.MockControl'); +goog.require('goog.testing.jsunit'); + +goog.setTestOnly('fireauth.messagechannel.ReceiverTest'); + + +var mockControl; + + +function setUp() { + ignoreArgument = goog.testing.mockmatchers.ignoreArgument; + mockControl = new goog.testing.MockControl(); + mockControl.$resetAll(); +} + + +function tearDown() { + try { + mockControl.$verifyAll(); + } finally { + mockControl.$tearDown(); + } +} + + +function testReceiver_singleHandler_success() { + // Used to prevent the test from finishing prematurely before the underlying + // logic completes. + var sendCompletionSignal; + var eventType = 'eventType1'; + var eventId = '1234'; + var origin = 'https://www.example.com'; + var data = { + 'a': 1, + 'b': 2 + }; + var expectedResponse = { + 'success': true + }; + var eventTarget = new goog.events.EventTarget(); + var postMessage = mockControl.createFunctionMock('postMessage'); + var handler1 = mockControl.createFunctionMock('handler1'); + var handler2 = mockControl.createFunctionMock('handler2'); + var event = new goog.events.Event('message'); + event.origin = origin; + event.ports = [{'postMessage': postMessage}]; + event.data = { + 'eventId': eventId, + 'eventType': eventType, + 'data': data + }; + postMessage({ + 'status': 'ack', + 'eventId': eventId, + 'eventType': eventType, + 'response': null + }).$once(); + handler1(origin, data).$does(function() { + return expectedResponse; + }).$once(); + postMessage({ + 'status': 'done', + 'eventId': eventId, + 'eventType': eventType, + 'response': [{ + 'fulfilled': true, + 'value': expectedResponse + }] + }).$does(function() { + sendCompletionSignal(); + }).$once(); + handler2().$never(); + mockControl.$replayAll(); + + var receiver = new fireauth.messagechannel.Receiver(eventTarget); + assertTrue(receiver.isListeningTo(eventTarget)); + assertFalse(receiver.isListeningTo(new goog.events.EventTarget())); + receiver.subscribe(eventType, handler1); + receiver.subscribe('unsupportedEvent', handler2); + // Simulate incoming sender message event. + eventTarget.dispatchEvent(event); + receiver.unsubscribe(eventType, handler1); + // Second event should not have any effect. + eventTarget.dispatchEvent(event); + + return new goog.Promise(function(resolve, reject) { + sendCompletionSignal = resolve; + }); +} + + +function testReceiver_singleHandler_error() { + var sendCompletionSignal; + var eventType = 'eventType1'; + var eventId = '1234'; + var origin = 'https://www.example.com'; + var data = { + 'a': 1, + 'b': 2 + }; + var expectedError = new Error('some error occurred'); + var eventTarget = new goog.events.EventTarget(); + var postMessage = mockControl.createFunctionMock('postMessage'); + var handler1 = mockControl.createFunctionMock('handler1'); + var handler2 = mockControl.createFunctionMock('handler2'); + var event = new goog.events.Event('message'); + event.origin = origin; + event.ports = [{'postMessage': postMessage}]; + event.data = { + 'eventId': eventId, + 'eventType': eventType, + 'data': data + }; + postMessage({ + 'status': 'ack', + 'eventId': eventId, + 'eventType': eventType, + 'response': null + }).$once(); + handler1(origin, data).$does(function() { + throw expectedError; + }).$once(); + postMessage({ + 'status': 'done', + 'eventId': eventId, + 'eventType': eventType, + 'response': [{ + 'fulfilled': false, + 'reason': expectedError.message + }] + }).$does(function() { + sendCompletionSignal(); + }).$once(); + handler2().$never(); + mockControl.$replayAll(); + + var receiver = new fireauth.messagechannel.Receiver(eventTarget); + receiver.subscribe(eventType, handler1); + receiver.subscribe('unsupportedEvent', handler2); + // Simulate incoming sender message event. + eventTarget.dispatchEvent(event); + receiver.unsubscribe(eventType, handler1); + // Second event should not have any effect. + eventTarget.dispatchEvent(event); + + return new goog.Promise(function(resolve, reject) { + sendCompletionSignal = resolve; + }); +} + + +function testReceiver_multipleHandler_singleEvent_success() { + var sendCompletionSignal; + var eventType = 'eventType1'; + var eventId = '1234'; + var origin = 'https://www.example.com'; + var data = { + 'a': 1, + 'b': 2 + }; + var expectedResponse1 = { + 'c': 3 + }; + var expectedResponse2 = { + 'd': 4 + }; + var eventTarget = new goog.events.EventTarget(); + var postMessage = mockControl.createFunctionMock('postMessage'); + var handler1 = mockControl.createFunctionMock('handler1'); + var handler2 = mockControl.createFunctionMock('handler2'); + var handler3 = mockControl.createFunctionMock('handler3'); + var event = new goog.events.Event('message'); + event.origin = origin; + event.ports = [{'postMessage': postMessage}]; + event.data = { + 'eventId': eventId, + 'eventType': eventType, + 'data': data + }; + // First handler. + postMessage({ + 'status': 'ack', + 'eventId': eventId, + 'eventType': eventType, + 'response': null + }).$once(); + handler1(origin, data).$does(function() { + return expectedResponse1; + }).$once(); + // Second handler. + handler2(origin, data).$does(function() { + return expectedResponse2; + }).$once(); + postMessage({ + 'status': 'done', + 'eventId': eventId, + 'eventType': eventType, + 'response': [{ + 'fulfilled': true, + 'value': expectedResponse1 + }, { + 'fulfilled': true, + 'value': expectedResponse2 + }] + }).$does(function() { + sendCompletionSignal(); + }).$once(); + // Third handler. + handler3().$never(); + mockControl.$replayAll(); + + var receiver = new fireauth.messagechannel.Receiver(eventTarget); + assertTrue(receiver.isListeningTo(eventTarget)); + assertFalse(receiver.isListeningTo(new goog.events.EventTarget())); + receiver.subscribe(eventType, handler1); + receiver.subscribe(eventType, handler2); + receiver.subscribe('unsupportedEvent', handler3); + // Simulate incoming sender message event. handler1 and handler2 should + // trigger. + eventTarget.dispatchEvent(event); + receiver.unsubscribe(eventType, handler1); + receiver.unsubscribe(eventType, handler2); + // Second event should not have any effect. + eventTarget.dispatchEvent(event); + + return new goog.Promise(function(resolve, reject) { + sendCompletionSignal = resolve; + }); +} + + +function testReceiver_multipleHandler_singleEvent_error() { + var sendCompletionSignal; + var eventType = 'eventType1'; + var eventId = '1234'; + var origin = 'https://www.example.com'; + var data = { + 'a': 1, + 'b': 2 + }; + var expectedResponse1 = { + 'c': 3 + }; + var expectedError = new Error('some error occurred'); + var eventTarget = new goog.events.EventTarget(); + var postMessage = mockControl.createFunctionMock('postMessage'); + var handler1 = mockControl.createFunctionMock('handler1'); + var handler2 = mockControl.createFunctionMock('handler2'); + var handler3 = mockControl.createFunctionMock('handler3'); + var event = new goog.events.Event('message'); + event.origin = origin; + event.ports = [{'postMessage': postMessage}]; + event.data = { + 'eventId': eventId, + 'eventType': eventType, + 'data': data + }; + // First handler. + postMessage({ + 'status': 'ack', + 'eventId': eventId, + 'eventType': eventType, + 'response': null + }).$once(); + handler1(origin, data).$does(function() { + return expectedResponse1; + }).$once(); + // Second handler. + handler2(origin, data).$does(function() { + throw expectedError; + }).$once(); + postMessage({ + 'status': 'done', + 'eventId': eventId, + 'eventType': eventType, + 'response': [{ + 'fulfilled': true, + 'value': expectedResponse1 + }, { + 'fulfilled': false, + 'reason': expectedError.message + }] + }).$does(function() { + sendCompletionSignal(); + }).$once(); + // Third handler. + handler3().$never(); + mockControl.$replayAll(); + + var receiver = new fireauth.messagechannel.Receiver(eventTarget); + assertTrue(receiver.isListeningTo(eventTarget)); + assertFalse(receiver.isListeningTo(new goog.events.EventTarget())); + receiver.subscribe(eventType, handler1); + receiver.subscribe(eventType, handler2); + receiver.subscribe('unsupportedEvent', handler3); + // Simulate incoming sender message event. handler1 and handler2 should + // trigger. + eventTarget.dispatchEvent(event); + receiver.unsubscribe(eventType, handler1); + receiver.unsubscribe(eventType, handler2); + // Second event should not have any effect. + eventTarget.dispatchEvent(event); + + return new goog.Promise(function(resolve, reject) { + sendCompletionSignal = resolve; + }); +} + + +function testReceiver_multipleHandler_multipleEvent_success() { + var sendCompletionSignal; + var eventType1 = 'eventType1'; + var eventId1 = '1234'; + var origin1 = 'https://www.example.com'; + var data1 = { + 'a': 1, + 'b': 2 + }; + var expectedResponse1 = { + 'response': 'res1' + }; + var eventType2 = 'eventType2'; + var eventId2 = '5678'; + var origin2 = 'https://www.other.com'; + var data2 = { + 'c': 3, + 'd': 4 + }; + var expectedResponse2 = { + 'response': 'res2' + }; + var eventTarget = new goog.events.EventTarget(); + var postMessage = mockControl.createFunctionMock('postMessage'); + var handler1 = mockControl.createFunctionMock('handler1'); + var handler2 = mockControl.createFunctionMock('handler2'); + var handler3 = mockControl.createFunctionMock('handler3'); + var event1 = new goog.events.Event('message'); + event1.origin = origin1; + event1.ports = [{'postMessage': postMessage}]; + event1.data = { + 'eventId': eventId1, + 'eventType': eventType1, + 'data': data1 + }; + var event2 = new goog.events.Event('message'); + event2.origin = origin2; + event2.ports = [{'postMessage': postMessage}]; + event2.data = { + 'eventId': eventId2, + 'eventType': eventType2, + 'data': data2 + }; + // First handler. + postMessage({ + 'status': 'ack', + 'eventId': eventId1, + 'eventType': eventType1, + 'response': null + }).$once(); + postMessage({ + 'status': 'ack', + 'eventId': eventId2, + 'eventType': eventType2, + 'response': null + }).$once(); + handler1(origin1, data1).$does(function() { + return expectedResponse1; + }).$once(); + // Second handler. + handler2(origin2, data2).$does(function() { + return expectedResponse2; + }).$once(); + postMessage({ + 'status': 'done', + 'eventId': eventId1, + 'eventType': eventType1, + 'response': [{ + 'fulfilled': true, + 'value': expectedResponse1 + }] + }).$once(); + postMessage({ + 'status': 'done', + 'eventId': eventId2, + 'eventType': eventType2, + 'response': [{ + 'fulfilled': true, + 'value': expectedResponse2 + }] + }).$does(function() { + sendCompletionSignal(); + }).$once(); + // Third handler. + handler3().$never(); + mockControl.$replayAll(); + + var receiver = new fireauth.messagechannel.Receiver(eventTarget); + assertTrue(receiver.isListeningTo(eventTarget)); + assertFalse(receiver.isListeningTo(new goog.events.EventTarget())); + // Subscribe, unsubscribe and then re-subscribe handler1. + receiver.subscribe(eventType1, handler1); + receiver.unsubscribe(eventType1, handler1); + receiver.subscribe(eventType1, handler1); + + receiver.subscribe(eventType2, handler2); + receiver.subscribe('unsupportedEvent', handler3); + // Simulate 2 incoming sender message events (eventType 1 and 2). handler1 and + // handler2 should trigger. + eventTarget.dispatchEvent(event1); + eventTarget.dispatchEvent(event2); + + return new goog.Promise(function(resolve, reject) { + sendCompletionSignal = resolve; + }); +} + + +function testReceiver_singleHandler_unsubscribeAll() { + var eventType = 'eventType1'; + var eventId = '1234'; + var origin = 'https://www.example.com'; + var data = { + 'a': 1, + 'b': 2 + }; + var eventTarget = new goog.events.EventTarget(); + var postMessage = mockControl.createFunctionMock('postMessage'); + var handler1 = mockControl.createFunctionMock('handler1'); + var handler2 = mockControl.createFunctionMock('handler2'); + var event = new goog.events.Event('message'); + event.origin = origin; + event.ports = [{'postMessage': postMessage}]; + event.data = { + 'eventId': eventId, + 'eventType': eventType, + 'data': data + }; + postMessage(ignoreArgument).$never(); + handler1().$never(); + handler2().$never(); + mockControl.$replayAll(); + + var receiver = new fireauth.messagechannel.Receiver(eventTarget); + assertTrue(receiver.isListeningTo(eventTarget)); + assertFalse(receiver.isListeningTo(new goog.events.EventTarget())); + receiver.subscribe(eventType, handler1); + receiver.subscribe(eventType, handler2); + // Unsubscribe all handlers. + receiver.unsubscribe(eventType); + // No handler should be triggered. + eventTarget.dispatchEvent(event); +} diff --git a/packages/auth/test/messagechannel/sender_test.js b/packages/auth/test/messagechannel/sender_test.js new file mode 100644 index 00000000000..7e17fdbda30 --- /dev/null +++ b/packages/auth/test/messagechannel/sender_test.js @@ -0,0 +1,525 @@ +/** + * @fileoverview Tests for sender.js. + */ + +goog.provide('fireauth.messagechannel.SenderTest'); + +goog.require('fireauth.messagechannel.Error'); +goog.require('fireauth.messagechannel.Sender'); +goog.require('fireauth.messagechannel.TimeoutDuration'); +goog.require('fireauth.messagechannel.utils'); +goog.require('goog.Promise'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventTarget'); +goog.require('goog.testing.MockClock'); +goog.require('goog.testing.MockControl'); +goog.require('goog.testing.jsunit'); + +goog.setTestOnly('fireauth.messagechannel.SenderTest'); + + +var mockControl; +var clock; +var ignoreArgument; + + +function setUp() { + ignoreArgument = goog.testing.mockmatchers.ignoreArgument; + mockControl = new goog.testing.MockControl(); + mockControl.$resetAll(); + // Install mock clock. + clock = new goog.testing.MockClock(true); +} + + +function tearDown() { + try { + mockControl.$verifyAll(); + } finally { + mockControl.$tearDown(); + } + goog.dispose(clock); +} + + +/** + * @param {!mockControl} mockControl The MockControl reference. + * @return {!MessageChannel} A mock messagechannel for testing. + */ +function createMockMessageChannel(mockControl) { + var messageChannel = { + port1: new goog.events.EventTarget(), + port2: new goog.events.EventTarget() + }; + messageChannel.port1.start = mockControl.createFunctionMock('start'); + messageChannel.port1.close = mockControl.createFunctionMock('close'); + return messageChannel; +} + + +function testSender_messageChannelUnsupported() { + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + initializeMessageChannel().$returns(null); + postMessage(ignoreArgument, ignoreArgument, ignoreArgument).$never(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + return sender.send('myEvent', {'a': 1, 'b': 2}) + .then(fail) + .thenCatch(function(error) { + assertEquals( + error.message, + fireauth.messagechannel.Error.CONNECTION_UNAVAILABLE); + }); +} + + +function testSender_send_ackTimeout() { + var eventId = '12345678'; + var eventType = 'myEvent'; + var data = {'a': 1, 'b': 2}; + var expectedRequest = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + generateEventId().$returns(eventId).$once(); + messageChannel.port1.start().$once(); + postMessage(expectedRequest, [messageChannel.port2]).$does(function() { + // Simulate ACK timeout. + clock.tick(fireauth.messagechannel.TimeoutDuration.ACK); + }).$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + return sender.send(eventType, data) + .then(fail) + .thenCatch(function(error) { + assertEquals( + error.message, + fireauth.messagechannel.Error.UNSUPPORTED_EVENT); + }); +} + + +function testSender_send_invalidResponse() { + var eventId = '12345678'; + var eventType = 'myEvent'; + var data = {'a': 1, 'b': 2}; + var expectedRequest = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + generateEventId().$returns(eventId).$once(); + messageChannel.port1.start().$once(); + postMessage(expectedRequest, [messageChannel.port2]).$does(function() { + var event = new goog.events.Event('message'); + // Simulate an invalid response. + event.data = { + 'eventType': eventType, + 'eventId': eventId, + 'status': 'invalid' + }; + messageChannel.port1.dispatchEvent(event); + }).$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + return sender.send(eventType, data) + .then(fail) + .thenCatch(function(error) { + assertEquals( + error.message, + fireauth.messagechannel.Error.INVALID_RESPONSE); + }); +} + + +function testSender_send_completionTimeout() { + var eventId = '12345678'; + var eventType = 'myEvent'; + var data = {'a': 1, 'b': 2}; + var expectedRequest = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + generateEventId().$returns(eventId).$once(); + messageChannel.port1.start().$once(); + postMessage(expectedRequest, [messageChannel.port2]).$does(function() { + var event = new goog.events.Event('message'); + event.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'ack' + }; + // Simulate ACK response sent successfully. + messageChannel.port1.dispatchEvent(event); + // Simulate completion response timing out. + clock.tick(fireauth.messagechannel.TimeoutDuration.COMPLETION); + }).$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + return sender.send(eventType, data) + .then(fail) + .thenCatch(function(error) { + assertEquals( + error.message, + fireauth.messagechannel.Error.TIMEOUT); + }); +} + + +function testSender_send_completionSuccess() { + var eventId = '12345678'; + var eventType = 'myEvent'; + var data = {'a': 1, 'b': 2}; + var expectedRequest = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + var expectedSuccessResponse = [{ + 'fulfilled': true, + 'value': { + 'c': 3, + 'd': 4 + } + }]; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + generateEventId().$returns(eventId).$once(); + messageChannel.port1.start().$once(); + postMessage(expectedRequest, [messageChannel.port2]).$does(function() { + var event1 = new goog.events.Event('message'); + var event2 = new goog.events.Event('message'); + event1.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'ack' + }; + event2.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'done', + 'response': expectedSuccessResponse + }; + // Simulate successful ACK and DONE responses. + messageChannel.port1.dispatchEvent(event1); + messageChannel.port1.dispatchEvent(event2); + }).$once(); + messageChannel.port1.close().$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + return sender.send(eventType, data) + .then(function(result) { + assertEquals(expectedSuccessResponse, result); + sender.close(); + // Second call should do nothing. + sender.close(); + // Start should not be able to restart the connection. + sender.start(); + // Connection should not be available anymore. + return sender.send(eventType, data).then(fail, function(error) { + assertEquals( + error.message, + fireauth.messagechannel.Error.CONNECTION_UNAVAILABLE); + }); + }); +} + + +function testSender_send_completionError() { + var eventId = '12345678'; + var eventType = 'myEvent'; + var data = {'a': 1, 'b': 2}; + var expectedRequest = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + var expectedErrorResponse = [{ + 'fulfilled': false, + 'reason': 'some error occurred' + }]; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + // start called early. + messageChannel.port1.start().$once(); + generateEventId().$returns(eventId).$once(); + postMessage(expectedRequest, [messageChannel.port2]).$does(function() { + var event1 = new goog.events.Event('message'); + var event2 = new goog.events.Event('message'); + event1.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'ack' + }; + event2.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'done', + 'response': expectedErrorResponse + }; + clock.tick(fireauth.messagechannel.TimeoutDuration.ACK - 1); + messageChannel.port1.dispatchEvent(event1); + clock.tick(fireauth.messagechannel.TimeoutDuration.COMPLETION - 1); + messageChannel.port1.dispatchEvent(event2); + }).$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + sender.start(); + // Second call should be ignored. + sender.start(); + return sender.send(eventType, data) + .then(function(result) { + assertEquals(expectedErrorResponse, result); + }); +} + + +function testSender_send_closedConnection() { + var eventId = '12345678'; + var eventType = 'myEvent'; + var data = {'a': 1, 'b': 2}; + var expectedRequest = { + 'eventType': eventType, + 'eventId': eventId, + 'data': data + }; + var expectedErrorResponse = { + 'fulfilled': true, + 'value': 'success' + }; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + // start called early. + messageChannel.port1.start().$once(); + generateEventId().$returns(eventId).$once(); + postMessage(expectedRequest, [messageChannel.port2]).$does(function() { + var event1 = new goog.events.Event('message'); + var event2 = new goog.events.Event('message'); + event1.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'ack' + }; + event2.data = { + 'eventId': eventId, + 'eventType': eventType, + 'status': 'done', + 'response': expectedErrorResponse + }; + messageChannel.port1.dispatchEvent(event1); + // Simulate the connection gets closed. + sender.close(); + messageChannel.port1.dispatchEvent(event2); + // Second event will be ignored and the resolver will timeout. + clock.tick(fireauth.messagechannel.TimeoutDuration.COMPLETION); + }).$once(); + messageChannel.port1.close().$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + return sender.send(eventType, data) + .then(fail, function(error) { + assertEquals( + error.message, + fireauth.messagechannel.Error.TIMEOUT); + }); +} + + +function testSender_send_multipleMessages() { + var eventId1 = '1234'; + var eventType1 = 'myEvent1'; + var data1 = {'request1': 'req1'}; + var expectedRequest1 = { + 'eventType': eventType1, + 'eventId': eventId1, + 'data': data1 + }; + var expectedSuccessResponse1 = [{ + 'fulfilled': true, + 'value': { + 'response': 'res1' + } + }]; + + var eventId2 = '5678'; + var eventType2 = 'myEvent2'; + var data2 = {'request2': 'req2'}; + var expectedRequest2 = { + 'eventType': eventType2, + 'eventId': eventId2, + 'data': data2 + }; + var expectedSuccessResponse2 = [{ + 'fulfilled': true, + 'value': { + 'response': 'res2' + } + }]; + + var eventId3 = '9012'; + var data3 = {'request3': 'req3'}; + var expectedRequest3 = { + // Test with same event as above. + 'eventType': eventType1, + 'eventId': eventId3, + 'data': data3 + }; + var expectedSuccessResponse3 = [{ + 'fulfilled': true, + 'value': { + 'response': 'res3' + } + }]; + + var messageChannel = createMockMessageChannel(mockControl); + var postMessage = mockControl.createFunctionMock('postMessage'); + var initializeMessageChannel = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'initializeMessageChannel'); + var generateEventId = mockControl.createMethodMock( + fireauth.messagechannel.utils, 'generateEventId'); + initializeMessageChannel().$returns(messageChannel).$once(); + generateEventId().$returns(eventId1).$once(); + generateEventId().$returns(eventId2).$once(); + generateEventId().$returns(eventId3).$once(); + messageChannel.port1.start().$once(); + // First event. + postMessage(expectedRequest1, [messageChannel.port2]).$does(function() { + var event1 = new goog.events.Event('message'); + var event2 = new goog.events.Event('message'); + event1.data = { + 'eventId': eventId1, + 'eventType': eventType1, + 'status': 'ack' + }; + event2.data = { + 'eventId': eventId1, + 'eventType': eventType1, + 'status': 'done', + 'response': expectedSuccessResponse1 + }; + messageChannel.port1.dispatchEvent(event1); + messageChannel.port1.dispatchEvent(event2); + }).$once(); + // Second event. + postMessage(expectedRequest2, [messageChannel.port2]).$does(function() { + var event1 = new goog.events.Event('message'); + var event2 = new goog.events.Event('message'); + event1.data = { + 'eventId': eventId2, + 'eventType': eventType2, + 'status': 'ack' + }; + event2.data = { + 'eventId': eventId2, + 'eventType': eventType2, + 'status': 'done', + 'response': expectedSuccessResponse2 + }; + messageChannel.port1.dispatchEvent(event1); + messageChannel.port1.dispatchEvent(event2); + }).$once(); + // Third event. + postMessage(expectedRequest3, [messageChannel.port2]).$does(function() { + var event1 = new goog.events.Event('message'); + var event2 = new goog.events.Event('message'); + event1.data = { + 'eventId': eventId3, + 'eventType': eventType1, + 'status': 'ack' + }; + event2.data = { + 'eventId': eventId3, + 'eventType': eventType1, + 'status': 'done', + 'response': expectedSuccessResponse3 + }; + messageChannel.port1.dispatchEvent(event1); + messageChannel.port1.dispatchEvent(event2); + }).$once(); + mockControl.$replayAll(); + + var sender = new fireauth.messagechannel.Sender({ + 'postMessage': postMessage + }); + // goog.Promise.all will fail if a single promise fails. + // Test with mixture of events (2 types of events). Each request will have a + // unique event ID. + return goog.Promise.all( + [ + sender.send(eventType1, data1), + sender.send(eventType2, data2), + sender.send(eventType1, data3) + ]).then(function(results) { + assertEquals(3, results.length); + assertEquals(expectedSuccessResponse1, results[0]); + assertEquals(expectedSuccessResponse2, results[1]); + assertEquals(expectedSuccessResponse3, results[2]); + }); +} diff --git a/packages/auth/test/storage/indexeddb_test.js b/packages/auth/test/storage/indexeddb_test.js index fc3346dae9c..2de6afc89f1 100644 --- a/packages/auth/test/storage/indexeddb_test.js +++ b/packages/auth/test/storage/indexeddb_test.js @@ -18,10 +18,13 @@ goog.provide('fireauth.storage.IndexedDBTest'); goog.require('fireauth.AuthError'); goog.require('fireauth.authenum.Error'); +goog.require('fireauth.messagechannel.Receiver'); +goog.require('fireauth.messagechannel.Sender'); goog.require('fireauth.storage.IndexedDB'); goog.require('fireauth.storage.Storage'); goog.require('goog.Promise'); goog.require('goog.testing.MockClock'); +goog.require('goog.testing.MockControl'); goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.require('goog.testing.recordFunction'); @@ -29,6 +32,8 @@ goog.require('goog.testing.recordFunction'); goog.setTestOnly('fireauth.storage.IndexedDBTest'); +var mockControl; +var ignoreArgument; var stubs = new goog.testing.PropertyReplacer(); var db = null; var manager; @@ -39,6 +44,9 @@ var deleted; function setUp() { + mockControl = new goog.testing.MockControl(); + ignoreArgument = goog.testing.mockmatchers.ignoreArgument; + mockControl.$resetAll(); deleted = 0; // IndexedDB not supported in IE9. stubs.replace( @@ -216,6 +224,11 @@ function tearDown() { indexedDBMock = null; stubs.reset(); goog.dispose(clock); + try { + mockControl.$verifyAll(); + } finally { + mockControl.$tearDown(); + } } @@ -395,3 +408,207 @@ function testStopListeners() { assertArrayEquals( ['key1', 'key2'], listener3.getLastCall().getArgument(0)); } + + +function testReceiverSubscribed_noWorkerGlobalScope() { + var getWorkerGlobalScope = mockControl.createMethodMock( + fireauth.util, 'getWorkerGlobalScope'); + var getInstance = mockControl.createMethodMock( + fireauth.messagechannel.Receiver, 'getInstance'); + getWorkerGlobalScope().$returns(null).$atLeastOnce(); + getInstance().$never(); + mockControl.$replayAll(); + + manager = getDefaultFireauthManager(); + return manager.get('abc').then(function(value) { + assertNull(value); + }); +} + + +function testReceiverSubscribed_externalChange_notYetProcessed() { + var listener1 = goog.testing.recordFunction(); + var subscribedCallback; + var workerGlobalScope = {}; + var getWorkerGlobalScope = mockControl.createMethodMock( + fireauth.util, 'getWorkerGlobalScope'); + var receiver = mockControl.createStrictMock(fireauth.messagechannel.Receiver); + var getInstance = mockControl.createMethodMock( + fireauth.messagechannel.Receiver, 'getInstance'); + getWorkerGlobalScope().$returns(workerGlobalScope).$atLeastOnce(); + getInstance(workerGlobalScope).$returns(receiver); + receiver.subscribe('keyChanged', ignoreArgument) + .$does(function(eventType, callback) { + subscribedCallback = callback; + }).$once(); + mockControl.$replayAll(); + + manager = getDefaultFireauthManager(); + manager.addStorageListener(listener1); + return manager.get('abc').then(function(value) { + assertNull(value); + // Simulate external indexedDB change. + db.store['firebaseLocalStorage'] = { + 'abc': {'fbase_key': 'abc', 'value': 'def'} + }; + return subscribedCallback('https://www.example.com', {'key': 'abc'}); + }).then(function(response) { + // Confirm sync completed. Status true returned to confirm the key was + // processed. + assertObjectEquals({'keyProcessed': true}, response); + // Listener should trigger with expected argument. + assertEquals(1, listener1.getCallCount()); + assertArrayEquals(['abc'], listener1.getLastCall().getArgument(0)); + return manager.get('abc'); + }).then(function(value) { + assertEquals('def', value); + }); +} + + +function testReceiverSubscribed_externalChange_alreadyProcessed() { + var listener1 = goog.testing.recordFunction(); + var subscribedCallback; + var workerGlobalScope = {}; + var getWorkerGlobalScope = mockControl.createMethodMock( + fireauth.util, 'getWorkerGlobalScope'); + var receiver = mockControl.createStrictMock(fireauth.messagechannel.Receiver); + var getInstance = mockControl.createMethodMock( + fireauth.messagechannel.Receiver, 'getInstance'); + getWorkerGlobalScope().$returns(workerGlobalScope).$atLeastOnce(); + getInstance(workerGlobalScope).$returns(receiver); + receiver.subscribe('keyChanged', ignoreArgument) + .$does(function(eventType, callback) { + subscribedCallback = callback; + }).$once(); + mockControl.$replayAll(); + + manager = getDefaultFireauthManager(); + manager.addStorageListener(listener1); + return manager.set('abc', 'def').then(function() { + return subscribedCallback('https://www.example.com', {'key': 'abc'}); + }).then(function(response) { + // Confirm sync completed but key not processed since no change is detected. + assertObjectEquals({'keyProcessed': false}, response); + // No listener should trigger. + assertEquals(0, listener1.getCallCount()); + return manager.get('abc'); + }).then(function(value) { + assertEquals('def', value); + }); +} + + +function testSender_writeOperations_serviceWorkerControllerUnavailable() { + var getServiceWorkerController = mockControl.createMethodMock( + fireauth.util, 'getServiceWorkerController'); + var sender = mockControl.createStrictMock(fireauth.messagechannel.Sender); + var senderConstructor = mockControl.createConstructorMock( + fireauth.messagechannel, 'Sender'); + getServiceWorkerController().$returns(null).$atLeastOnce(); + // No sender initialized. + senderConstructor(ignoreArgument).$never(); + sender.send(ignoreArgument).$never(); + mockControl.$replayAll(); + + // Set and remove should not trigger sender. + manager = getDefaultFireauthManager(); + return manager.set('abc', 'def').then(function() { + return manager.get('abc'); + }).then(function(value) { + assertEquals('def', value); + return manager.remove('abc'); + }).then(function() { + return manager.get('abc'); + }).then(function(value) { + assertNull(value); + }); +} + + +function testSender_writeOperations_serviceWorkerControllerAvailable() { + var status = []; + var serviceWorkerController = {}; + var getServiceWorkerController = mockControl.createMethodMock( + fireauth.util, 'getServiceWorkerController'); + + getServiceWorkerController().$returns(serviceWorkerController).$atLeastOnce(); + var sender = mockControl.createStrictMock(fireauth.messagechannel.Sender); + var senderConstructor = mockControl.createConstructorMock( + fireauth.messagechannel, 'Sender'); + // Successful set event. + senderConstructor(ignoreArgument).$returns(sender); + sender.send('keyChanged', {'key': 'abc'}).$does(function(eventType, data) { + status.push(0); + return goog.Promise.resolve([ + { + 'fulfilled': true, + 'value': {'keyProcessed': true} + } + ]); + }).$once(); + // Successful remove event. + senderConstructor(ignoreArgument).$returns(sender); + sender.send('keyChanged', {'key': 'abc'}).$does(function(eventType, data) { + status.push(1); + return goog.Promise.resolve([ + { + 'fulfilled': true, + 'value': {'keyProcessed': true} + } + ]); + }).$once(); + // Failing set event. + senderConstructor(ignoreArgument).$returns(sender); + sender.send('keyChanged', {'key': 'abc'}).$does(function(eventType, data) { + status.push(2); + return goog.Promise.reject(new Error('unsupported_event')); + }).$once(); + // Failing remove event. + senderConstructor(ignoreArgument).$returns(sender); + sender.send('keyChanged', {'key': 'abc'}).$does(function(eventType, data) { + status.push(3); + return goog.Promise.reject(new Error('invalid_response')); + }).$once(); + mockControl.$replayAll(); + + manager = getDefaultFireauthManager(); + return manager.set('abc', 'def').then(function() { + // Set should trigger sender at this point. + assertArrayEquals([0], status); + return manager.get('abc'); + }).then(function(value) { + // Get shouldn't trigger. + assertArrayEquals([0], status); + assertEquals('def', value); + return manager.remove('abc'); + }).then(function() { + // Remove should trigger sender at this point. + assertArrayEquals([0, 1], status); + return manager.get('abc'); + }).then(function(value) { + // Get shouldn't trigger. + assertArrayEquals([0, 1], status); + assertNull(value); + // This should resolve even if sender error occurs. + return manager.set('abc', 'ghi'); + }).then(function() { + // Set should trigger sender at this point. + assertArrayEquals([0, 1, 2], status); + return manager.get('abc'); + }).then(function(value) { + // Get shouldn't trigger. + assertArrayEquals([0, 1, 2], status); + assertEquals('ghi', value); + // This should resolve even if sender error occurs. + return manager.remove('abc'); + }).then(function() { + // Remove should trigger sender at this point. + assertArrayEquals([0, 1, 2, 3], status); + return manager.get('abc'); + }).then(function(value) { + // Get shouldn't trigger. + assertArrayEquals([0, 1, 2, 3], status); + assertNull(value); + }); +} From bf95e11b445c12f386ca1786b640ba8566584685 Mon Sep 17 00:00:00 2001 From: bojeil-google Date: Wed, 1 Aug 2018 10:58:43 -0700 Subject: [PATCH 2/2] Add copyright and license to new files. --- packages/auth/src/messagechannel/defines.js | 16 ++++++++++++++++ packages/auth/src/messagechannel/postmessager.js | 16 ++++++++++++++++ packages/auth/src/messagechannel/receiver.js | 16 ++++++++++++++++ packages/auth/src/messagechannel/sender.js | 16 ++++++++++++++++ .../test/messagechannel/postmessager_test.js | 16 ++++++++++++++++ .../auth/test/messagechannel/receiver_test.js | 16 ++++++++++++++++ packages/auth/test/messagechannel/sender_test.js | 16 ++++++++++++++++ 7 files changed, 112 insertions(+) diff --git a/packages/auth/src/messagechannel/defines.js b/packages/auth/src/messagechannel/defines.js index 29f1706c1ab..f53da4f7f8d 100644 --- a/packages/auth/src/messagechannel/defines.js +++ b/packages/auth/src/messagechannel/defines.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Defines the MessageChannel common utilities and enums. */ diff --git a/packages/auth/src/messagechannel/postmessager.js b/packages/auth/src/messagechannel/postmessager.js index dca90293784..ee21caffe1b 100644 --- a/packages/auth/src/messagechannel/postmessager.js +++ b/packages/auth/src/messagechannel/postmessager.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Defines the PostMessager interface needed for the * `fireauth.messagechannel.Sender`, in addition to 2 types of implementations. diff --git a/packages/auth/src/messagechannel/receiver.js b/packages/auth/src/messagechannel/receiver.js index ca5eee10c10..97a7837002d 100644 --- a/packages/auth/src/messagechannel/receiver.js +++ b/packages/auth/src/messagechannel/receiver.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Defines the MessageChannel based wrapper for receiving * messages from other windows or workers. diff --git a/packages/auth/src/messagechannel/sender.js b/packages/auth/src/messagechannel/sender.js index cf0d9df28e0..34766b1628c 100644 --- a/packages/auth/src/messagechannel/sender.js +++ b/packages/auth/src/messagechannel/sender.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Defines the MessageChannel based wrapper for sending messages * to other windows or workers. diff --git a/packages/auth/test/messagechannel/postmessager_test.js b/packages/auth/test/messagechannel/postmessager_test.js index e301a372dc6..ab0566f17fa 100644 --- a/packages/auth/test/messagechannel/postmessager_test.js +++ b/packages/auth/test/messagechannel/postmessager_test.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Tests for postmessager.js. */ diff --git a/packages/auth/test/messagechannel/receiver_test.js b/packages/auth/test/messagechannel/receiver_test.js index c7899396a2e..59adbaafdc0 100644 --- a/packages/auth/test/messagechannel/receiver_test.js +++ b/packages/auth/test/messagechannel/receiver_test.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Tests for receiver.js. */ diff --git a/packages/auth/test/messagechannel/sender_test.js b/packages/auth/test/messagechannel/sender_test.js index 7e17fdbda30..365565443ff 100644 --- a/packages/auth/test/messagechannel/sender_test.js +++ b/packages/auth/test/messagechannel/sender_test.js @@ -1,3 +1,19 @@ +/** + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * @fileoverview Tests for sender.js. */