link
This commit is contained in:
14
node_modules/firebase-functions/lib/common/app.d.ts
generated
vendored
Normal file
14
node_modules/firebase-functions/lib/common/app.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { App } from "firebase-admin/app";
|
||||
export declare function getApp(): App;
|
||||
/**
|
||||
* This function allows the Firebase Emulator Suite to override the FirebaseApp instance
|
||||
* used by the Firebase Functions SDK. Developers should never call this function for
|
||||
* other purposes.
|
||||
* N.B. For clarity for use in testing this name has no mention of emulation, but
|
||||
* it must be exported from index as app.setEmulatedAdminApp or we break the emulator.
|
||||
* We can remove this export when:
|
||||
* A) We complete the new emulator and no longer depend on monkeypatching
|
||||
* B) We tweak the CLI to look for different APIs to monkeypatch depending on versions.
|
||||
* @alpha
|
||||
*/
|
||||
export declare function setApp(app?: App): void;
|
||||
62
node_modules/firebase-functions/lib/common/app.js
generated
vendored
Normal file
62
node_modules/firebase-functions/lib/common/app.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2017 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.setApp = exports.getApp = void 0;
|
||||
const app_1 = require("firebase-admin/app");
|
||||
const config_1 = require("./config");
|
||||
const APP_NAME = "__FIREBASE_FUNCTIONS_SDK__";
|
||||
let cache;
|
||||
function getApp() {
|
||||
if (typeof cache === "undefined") {
|
||||
try {
|
||||
cache = (0, app_1.getApp)( /* default */);
|
||||
}
|
||||
catch {
|
||||
// Default app does not exist. Initialize app.
|
||||
cache = (0, app_1.initializeApp)({
|
||||
...(0, config_1.firebaseConfig)(),
|
||||
credential: (0, app_1.applicationDefault)(),
|
||||
}, APP_NAME);
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
exports.getApp = getApp;
|
||||
/**
|
||||
* This function allows the Firebase Emulator Suite to override the FirebaseApp instance
|
||||
* used by the Firebase Functions SDK. Developers should never call this function for
|
||||
* other purposes.
|
||||
* N.B. For clarity for use in testing this name has no mention of emulation, but
|
||||
* it must be exported from index as app.setEmulatedAdminApp or we break the emulator.
|
||||
* We can remove this export when:
|
||||
* A) We complete the new emulator and no longer depend on monkeypatching
|
||||
* B) We tweak the CLI to look for different APIs to monkeypatch depending on versions.
|
||||
* @alpha
|
||||
*/
|
||||
function setApp(app) {
|
||||
if ((cache === null || cache === void 0 ? void 0 : cache.name) === APP_NAME) {
|
||||
void (0, app_1.deleteApp)(cache);
|
||||
}
|
||||
cache = app;
|
||||
}
|
||||
exports.setApp = setApp;
|
||||
41
node_modules/firebase-functions/lib/common/change.d.ts
generated
vendored
Normal file
41
node_modules/firebase-functions/lib/common/change.d.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* `ChangeJson` is the JSON format used to construct a `Change` object.
|
||||
*/
|
||||
export interface ChangeJson {
|
||||
/**
|
||||
* Key-value pairs representing state of data after the change.
|
||||
*/
|
||||
after?: any;
|
||||
/**
|
||||
* Key-value pairs representing state of data before the change. If
|
||||
* `fieldMask` is set, then only fields that changed are present in `before`.
|
||||
*/
|
||||
before?: any;
|
||||
/**
|
||||
* Comma-separated string that represents names of fields that changed.
|
||||
*/
|
||||
fieldMask?: string;
|
||||
}
|
||||
/**
|
||||
* The Cloud Functions interface for events that change state, such as
|
||||
* Realtime Database or Cloud Firestore `onWrite` and `onUpdate` events.
|
||||
*
|
||||
* For more information about the format used to construct `Change` objects, see
|
||||
* {@link ChangeJson} below.
|
||||
*
|
||||
*/
|
||||
export declare class Change<T> {
|
||||
before: T;
|
||||
after: T;
|
||||
/**
|
||||
* Factory method for creating a `Change` from a `before` object and an `after`
|
||||
* object.
|
||||
*/
|
||||
static fromObjects<T>(before: T, after: T): Change<T>;
|
||||
/**
|
||||
* Factory method for creating a `Change` from JSON and an optional customizer
|
||||
* function to be applied to both the `before` and the `after` fields.
|
||||
*/
|
||||
static fromJSON<T>(json: ChangeJson, customizer?: (x: any) => T): Change<T>;
|
||||
constructor(before: T, after: T);
|
||||
}
|
||||
80
node_modules/firebase-functions/lib/common/change.js
generated
vendored
Normal file
80
node_modules/firebase-functions/lib/common/change.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Change = exports.applyFieldMask = void 0;
|
||||
/** @internal */
|
||||
function applyFieldMask(sparseBefore, after, fieldMask) {
|
||||
const before = { ...after };
|
||||
const masks = fieldMask.split(",");
|
||||
for (const mask of masks) {
|
||||
const parts = mask.split(".");
|
||||
const head = parts[0];
|
||||
const tail = parts.slice(1).join(".");
|
||||
if (parts.length > 1) {
|
||||
before[head] = applyFieldMask(sparseBefore === null || sparseBefore === void 0 ? void 0 : sparseBefore[head], after[head], tail);
|
||||
continue;
|
||||
}
|
||||
const val = sparseBefore === null || sparseBefore === void 0 ? void 0 : sparseBefore[head];
|
||||
if (typeof val === "undefined") {
|
||||
delete before[mask];
|
||||
}
|
||||
else {
|
||||
before[mask] = val;
|
||||
}
|
||||
}
|
||||
return before;
|
||||
}
|
||||
exports.applyFieldMask = applyFieldMask;
|
||||
/**
|
||||
* The Cloud Functions interface for events that change state, such as
|
||||
* Realtime Database or Cloud Firestore `onWrite` and `onUpdate` events.
|
||||
*
|
||||
* For more information about the format used to construct `Change` objects, see
|
||||
* {@link ChangeJson} below.
|
||||
*
|
||||
*/
|
||||
class Change {
|
||||
/**
|
||||
* Factory method for creating a `Change` from a `before` object and an `after`
|
||||
* object.
|
||||
*/
|
||||
static fromObjects(before, after) {
|
||||
return new Change(before, after);
|
||||
}
|
||||
/**
|
||||
* Factory method for creating a `Change` from JSON and an optional customizer
|
||||
* function to be applied to both the `before` and the `after` fields.
|
||||
*/
|
||||
static fromJSON(json, customizer = (x) => x) {
|
||||
let before = { ...json.before };
|
||||
if (json.fieldMask) {
|
||||
before = applyFieldMask(before, json.after, json.fieldMask);
|
||||
}
|
||||
return Change.fromObjects(customizer(before || {}), customizer(json.after || {}));
|
||||
}
|
||||
constructor(before, after) {
|
||||
this.before = before;
|
||||
this.after = after;
|
||||
}
|
||||
}
|
||||
exports.Change = Change;
|
||||
6
node_modules/firebase-functions/lib/common/config.d.ts
generated
vendored
Normal file
6
node_modules/firebase-functions/lib/common/config.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { AppOptions } from "firebase-admin/app";
|
||||
/**
|
||||
* Get the fields you need to initialize a Firebase app
|
||||
* @alpha
|
||||
*/
|
||||
export declare function firebaseConfig(): AppOptions | null;
|
||||
49
node_modules/firebase-functions/lib/common/config.js
generated
vendored
Normal file
49
node_modules/firebase-functions/lib/common/config.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.firebaseConfig = exports.resetCache = void 0;
|
||||
const fs_1 = require("fs");
|
||||
const path = require("path");
|
||||
const logger = require("../logger");
|
||||
let cache = null;
|
||||
/**
|
||||
* @internal
|
||||
* @alpha
|
||||
*/
|
||||
function resetCache(newCache = null) {
|
||||
cache = newCache;
|
||||
}
|
||||
exports.resetCache = resetCache;
|
||||
/**
|
||||
* Get the fields you need to initialize a Firebase app
|
||||
* @alpha
|
||||
*/
|
||||
function firebaseConfig() {
|
||||
if (cache) {
|
||||
return cache;
|
||||
}
|
||||
let env = process.env.FIREBASE_CONFIG;
|
||||
if (env) {
|
||||
// Firebase Tools will always use a JSON blob in prod, but docs
|
||||
// explicitly state that the user can set the env to a file:
|
||||
// https://firebase.google.com/docs/admin/setup#initialize-without-parameters
|
||||
if (!env.startsWith("{")) {
|
||||
env = (0, fs_1.readFileSync)(path.join(process.env.PWD, env)).toString("utf8");
|
||||
}
|
||||
cache = JSON.parse(env);
|
||||
return cache;
|
||||
}
|
||||
if (process.env.GCLOUD_PROJECT) {
|
||||
logger.warn("Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail");
|
||||
cache = {
|
||||
databaseURL: process.env.DATABASE_URL || `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`,
|
||||
storageBucket: process.env.STORAGE_BUCKET_URL || `${process.env.GCLOUD_PROJECT}.appspot.com`,
|
||||
projectId: process.env.GCLOUD_PROJECT,
|
||||
};
|
||||
return cache;
|
||||
}
|
||||
else {
|
||||
logger.warn("Warning, FIREBASE_CONFIG and GCLOUD_PROJECT environment variables are missing. Initializing firebase-admin will fail");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.firebaseConfig = firebaseConfig;
|
||||
1
node_modules/firebase-functions/lib/common/debug.d.ts
generated
vendored
Normal file
1
node_modules/firebase-functions/lib/common/debug.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
54
node_modules/firebase-functions/lib/common/debug.js
generated
vendored
Normal file
54
node_modules/firebase-functions/lib/common/debug.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2021 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isDebugFeatureEnabled = exports.debugFeatureValue = void 0;
|
||||
// Do NOT turn on a debug feature in production.
|
||||
const debugMode = process.env.FIREBASE_DEBUG_MODE === "true";
|
||||
function loadDebugFeatures() {
|
||||
if (!debugMode) {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
const obj = JSON.parse(process.env.FIREBASE_DEBUG_FEATURES);
|
||||
if (typeof obj !== "object") {
|
||||
return {};
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
/* @internal */
|
||||
function debugFeatureValue(feat) {
|
||||
if (!debugMode) {
|
||||
return;
|
||||
}
|
||||
return loadDebugFeatures()[feat];
|
||||
}
|
||||
exports.debugFeatureValue = debugFeatureValue;
|
||||
/* @internal */
|
||||
function isDebugFeatureEnabled(feat) {
|
||||
return debugMode && !!debugFeatureValue(feat);
|
||||
}
|
||||
exports.isDebugFeatureEnabled = isDebugFeatureEnabled;
|
||||
17
node_modules/firebase-functions/lib/common/encoding.d.ts
generated
vendored
Normal file
17
node_modules/firebase-functions/lib/common/encoding.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Expression } from "../params";
|
||||
/**
|
||||
* A type alias used to annotate interfaces as using a google.protobuf.Duration.
|
||||
* This type is parsed/encoded as a string of seconds + the "s" prefix.
|
||||
*/
|
||||
export type Duration = string;
|
||||
/** Get a google.protobuf.Duration for a number of seconds. */
|
||||
export declare function durationFromSeconds(s: number): Duration;
|
||||
/**
|
||||
* Utility function to help copy fields from type A to B.
|
||||
* As a safety net, catches typos or fields that aren't named the same
|
||||
* in A and B, but cannot verify that both Src and Dest have the same type for the same field.
|
||||
*/
|
||||
export declare function copyIfPresent<Src, Dest>(dest: Dest, src: Src, ...fields: Array<keyof Src & keyof Dest>): void;
|
||||
export declare function convertIfPresent<Src, Dest>(dest: Dest, src: Src, destField: keyof Dest, srcField: keyof Src, converter?: (from: any) => any): void;
|
||||
export declare function serviceAccountFromShorthand(serviceAccount: string | Expression<string>): string | Expression<string> | null;
|
||||
export declare function convertInvoker(invoker: string | string[]): string[];
|
||||
96
node_modules/firebase-functions/lib/common/encoding.js
generated
vendored
Normal file
96
node_modules/firebase-functions/lib/common/encoding.js
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2021 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.convertInvoker = exports.serviceAccountFromShorthand = exports.convertIfPresent = exports.copyIfPresent = exports.durationFromSeconds = void 0;
|
||||
const params_1 = require("../params");
|
||||
/** Get a google.protobuf.Duration for a number of seconds. */
|
||||
function durationFromSeconds(s) {
|
||||
return `${s}s`;
|
||||
}
|
||||
exports.durationFromSeconds = durationFromSeconds;
|
||||
/**
|
||||
* Utility function to help copy fields from type A to B.
|
||||
* As a safety net, catches typos or fields that aren't named the same
|
||||
* in A and B, but cannot verify that both Src and Dest have the same type for the same field.
|
||||
*/
|
||||
function copyIfPresent(dest, src, ...fields) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
for (const field of fields) {
|
||||
if (!Object.prototype.hasOwnProperty.call(src, field)) {
|
||||
continue;
|
||||
}
|
||||
dest[field] = src[field];
|
||||
}
|
||||
}
|
||||
exports.copyIfPresent = copyIfPresent;
|
||||
function convertIfPresent(dest, src, destField, srcField, converter = (from) => {
|
||||
return from;
|
||||
}) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
if (!Object.prototype.hasOwnProperty.call(src, srcField)) {
|
||||
return;
|
||||
}
|
||||
dest[destField] = converter(src[srcField]);
|
||||
}
|
||||
exports.convertIfPresent = convertIfPresent;
|
||||
function serviceAccountFromShorthand(serviceAccount) {
|
||||
if (serviceAccount === "default") {
|
||||
return null;
|
||||
}
|
||||
else if (serviceAccount instanceof params_1.Expression) {
|
||||
return serviceAccount;
|
||||
}
|
||||
else if (serviceAccount.endsWith("@")) {
|
||||
if (!process.env.GCLOUD_PROJECT) {
|
||||
throw new Error(`Unable to determine email for service account '${serviceAccount}' because process.env.GCLOUD_PROJECT is not set.`);
|
||||
}
|
||||
return `${serviceAccount}${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`;
|
||||
}
|
||||
else if (serviceAccount.includes("@")) {
|
||||
return serviceAccount;
|
||||
}
|
||||
else {
|
||||
throw new Error(`Invalid option for serviceAccount: '${serviceAccount}'. Valid options are 'default', a service account email, or '{serviceAccountName}@'`);
|
||||
}
|
||||
}
|
||||
exports.serviceAccountFromShorthand = serviceAccountFromShorthand;
|
||||
function convertInvoker(invoker) {
|
||||
if (typeof invoker === "string") {
|
||||
invoker = [invoker];
|
||||
}
|
||||
if (invoker.length === 0) {
|
||||
throw new Error("Invalid option for invoker: Must be a non-empty array.");
|
||||
}
|
||||
if (invoker.find((inv) => inv.length === 0)) {
|
||||
throw new Error("Invalid option for invoker: Must be a non-empty string.");
|
||||
}
|
||||
if (invoker.length > 1 && invoker.find((inv) => inv === "public" || inv === "private")) {
|
||||
throw new Error("Invalid option for invoker: Cannot have 'public' or 'private' in an array of service accounts.");
|
||||
}
|
||||
return invoker;
|
||||
}
|
||||
exports.convertInvoker = convertInvoker;
|
||||
7
node_modules/firebase-functions/lib/common/onInit.d.ts
generated
vendored
Normal file
7
node_modules/firebase-functions/lib/common/onInit.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Registers a callback that should be run when in a production environment
|
||||
* before executing any functions code.
|
||||
* Calling this function more than once leads to undefined behavior.
|
||||
* @param callback initialization callback to be run before any function executes.
|
||||
*/
|
||||
export declare function onInit(callback: () => unknown): void;
|
||||
36
node_modules/firebase-functions/lib/common/onInit.js
generated
vendored
Normal file
36
node_modules/firebase-functions/lib/common/onInit.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.withInit = exports.onInit = void 0;
|
||||
const logger = require("../logger");
|
||||
let initCallback = null;
|
||||
let didInit = false;
|
||||
/**
|
||||
* Registers a callback that should be run when in a production environment
|
||||
* before executing any functions code.
|
||||
* Calling this function more than once leads to undefined behavior.
|
||||
* @param callback initialization callback to be run before any function executes.
|
||||
*/
|
||||
function onInit(callback) {
|
||||
if (initCallback) {
|
||||
logger.warn("Setting onInit callback more than once. Only the most recent callback will be called");
|
||||
}
|
||||
initCallback = callback;
|
||||
didInit = false;
|
||||
}
|
||||
exports.onInit = onInit;
|
||||
/** @internal */
|
||||
function withInit(func) {
|
||||
return async (...args) => {
|
||||
if (!didInit) {
|
||||
if (initCallback) {
|
||||
await initCallback();
|
||||
}
|
||||
didInit = true;
|
||||
}
|
||||
// Note: This cast is actually inaccurate because it may be a promise, but
|
||||
// it doesn't actually matter because the async function will promisify
|
||||
// non-promises and forward promises.
|
||||
return func(...args);
|
||||
};
|
||||
}
|
||||
exports.withInit = withInit;
|
||||
14
node_modules/firebase-functions/lib/common/options.d.ts
generated
vendored
Normal file
14
node_modules/firebase-functions/lib/common/options.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Special configuration type to reset configuration to platform default.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export declare class ResetValue {
|
||||
toJSON(): null;
|
||||
private constructor();
|
||||
static getInstance(): ResetValue;
|
||||
}
|
||||
/**
|
||||
* Special configuration value to reset configuration to platform default.
|
||||
*/
|
||||
export declare const RESET_VALUE: ResetValue;
|
||||
44
node_modules/firebase-functions/lib/common/options.js
generated
vendored
Normal file
44
node_modules/firebase-functions/lib/common/options.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.RESET_VALUE = exports.ResetValue = void 0;
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
/**
|
||||
* Special configuration type to reset configuration to platform default.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
class ResetValue {
|
||||
toJSON() {
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
constructor() { }
|
||||
static getInstance() {
|
||||
return new ResetValue();
|
||||
}
|
||||
}
|
||||
exports.ResetValue = ResetValue;
|
||||
/**
|
||||
* Special configuration value to reset configuration to platform default.
|
||||
*/
|
||||
exports.RESET_VALUE = ResetValue.getInstance();
|
||||
33
node_modules/firebase-functions/lib/common/params.d.ts
generated
vendored
Normal file
33
node_modules/firebase-functions/lib/common/params.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Expression } from "../params";
|
||||
/**
|
||||
* A type that splits literal string S with delimiter D.
|
||||
*
|
||||
* For example Split<"a/b/c", "/"> is ['a' | "b" | "c"]
|
||||
*/
|
||||
export type Split<S extends string, D extends string> = string extends S ? string[] : S extends "" ? [] : S extends `${D}${infer Tail}` ? [...Split<Tail, D>] : S extends `${infer Head}${D}${infer Tail}` ? string extends Head ? [...Split<Tail, D>] : [Head, ...Split<Tail, D>] : [
|
||||
S
|
||||
];
|
||||
/**
|
||||
* A type that ensure that type S is not null or undefined.
|
||||
*/
|
||||
export type NullSafe<S extends null | undefined | string> = S extends null ? never : S extends undefined ? never : S extends string ? S : never;
|
||||
/**
|
||||
* A type that extracts parameter name enclosed in bracket as string.
|
||||
* Ignore wildcard matches
|
||||
*
|
||||
* For example, Extract<"{uid}"> is "uid".
|
||||
* For example, Extract<"{uid=*}"> is "uid".
|
||||
* For example, Extract<"{uid=**}"> is "uid".
|
||||
*/
|
||||
export type Extract<Part extends string> = Part extends `{${infer Param}=**}` ? Param : Part extends `{${infer Param}=*}` ? Param : Part extends `{${infer Param}}` ? Param : never;
|
||||
/**
|
||||
* A type that maps all parameter capture gropus into keys of a record.
|
||||
* For example, ParamsOf<"users/{uid}"> is { uid: string }
|
||||
* ParamsOf<"users/{uid}/logs/{log}"> is { uid: string; log: string }
|
||||
* ParamsOf<"some/static/data"> is {}
|
||||
*
|
||||
* For flexibility reasons, ParamsOf<string> is Record<string, string>
|
||||
*/
|
||||
export type ParamsOf<PathPattern extends string | Expression<string>> = PathPattern extends Expression<string> ? Record<string, string> : string extends PathPattern ? Record<string, string> : {
|
||||
[Key in Extract<Split<NullSafe<Exclude<PathPattern, Expression<string>>>, "/">[number]>]: string;
|
||||
};
|
||||
23
node_modules/firebase-functions/lib/common/params.js
generated
vendored
Normal file
23
node_modules/firebase-functions/lib/common/params.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2021 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
151
node_modules/firebase-functions/lib/common/providers/database.d.ts
generated
vendored
Normal file
151
node_modules/firebase-functions/lib/common/providers/database.d.ts
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
import { App } from "firebase-admin/app";
|
||||
import * as database from "firebase-admin/database";
|
||||
/**
|
||||
* Pulled from @firebase/database-types, make sure the interface is updated on dependencies upgrades.
|
||||
* Represents a child snapshot of a `Reference` that is being iterated over. The key will never be undefined.
|
||||
*/
|
||||
interface IteratedDataSnapshot extends DataSnapshot {
|
||||
key: string;
|
||||
}
|
||||
/**
|
||||
* Interface representing a Firebase Realtime database data snapshot.
|
||||
*/
|
||||
export declare class DataSnapshot implements database.DataSnapshot {
|
||||
private app?;
|
||||
instance: string;
|
||||
/** @hidden */
|
||||
private _ref;
|
||||
/** @hidden */
|
||||
private _path;
|
||||
/** @hidden */
|
||||
private _data;
|
||||
/** @hidden */
|
||||
private _childPath;
|
||||
constructor(data: any, path?: string, // path is undefined for the database root
|
||||
app?: App, instance?: string);
|
||||
/**
|
||||
* Returns a [`Reference`](/docs/reference/admin/node/admin.database.Reference)
|
||||
* to the database location where the triggering write occurred. Has
|
||||
* full read and write access.
|
||||
*/
|
||||
get ref(): database.Reference;
|
||||
/**
|
||||
* The key (last part of the path) of the location of this `DataSnapshot`.
|
||||
*
|
||||
* The last token in a database location is considered its key. For example,
|
||||
* "ada" is the key for the `/users/ada/` node. Accessing the key on any
|
||||
* `DataSnapshot` returns the key for the location that generated it.
|
||||
* However, accessing the key on the root URL of a database returns `null`.
|
||||
*/
|
||||
get key(): string | null;
|
||||
/**
|
||||
* Extracts a JavaScript value from a `DataSnapshot`.
|
||||
*
|
||||
* Depending on the data in a `DataSnapshot`, the `val()` method may return a
|
||||
* scalar type (string, number, or boolean), an array, or an object. It may also
|
||||
* return `null`, indicating that the `DataSnapshot` is empty (contains no
|
||||
* data).
|
||||
*
|
||||
* @return The snapshot's contents as a JavaScript value (Object,
|
||||
* Array, string, number, boolean, or `null`).
|
||||
*/
|
||||
val(): any;
|
||||
/**
|
||||
* Exports the entire contents of the `DataSnapshot` as a JavaScript object.
|
||||
*
|
||||
* @return The contents of the `DataSnapshot` as a JavaScript value
|
||||
* (Object, Array, string, number, boolean, or `null`).
|
||||
*/
|
||||
exportVal(): any;
|
||||
/**
|
||||
* Gets the priority value of the data in this `DataSnapshot`.
|
||||
*
|
||||
* As an alternative to using priority, applications can order collections by
|
||||
* ordinary properties. See [Sorting and filtering
|
||||
* data](/docs/database/web/lists-of-data#sorting_and_filtering_data).
|
||||
*
|
||||
* @return The priority value of the data.
|
||||
*/
|
||||
getPriority(): string | number | null;
|
||||
/**
|
||||
* Returns `true` if this `DataSnapshot` contains any data. It is slightly more
|
||||
* efficient than using `snapshot.val() !== null`.
|
||||
*
|
||||
* @return `true` if this `DataSnapshot` contains any data; otherwise, `false`.
|
||||
*/
|
||||
exists(): boolean;
|
||||
/**
|
||||
* Gets a `DataSnapshot` for the location at the specified relative path.
|
||||
*
|
||||
* The relative path can either be a simple child name (for example, "ada") or
|
||||
* a deeper slash-separated path (for example, "ada/name/first").
|
||||
*
|
||||
* @param path A relative path from this location to the desired child
|
||||
* location.
|
||||
* @return The specified child location.
|
||||
*/
|
||||
child(childPath: string): DataSnapshot;
|
||||
/**
|
||||
* Enumerates the `DataSnapshot`s of the children items.
|
||||
*
|
||||
* Because of the way JavaScript objects work, the ordering of data in the
|
||||
* JavaScript object returned by `val()` is not guaranteed to match the ordering
|
||||
* on the server nor the ordering of `child_added` events. That is where
|
||||
* `forEach()` comes in handy. It guarantees the children of a `DataSnapshot`
|
||||
* can be iterated in their query order.
|
||||
*
|
||||
* If no explicit `orderBy*()` method is used, results are returned
|
||||
* ordered by key (unless priorities are used, in which case, results are
|
||||
* returned by priority).
|
||||
*
|
||||
* @param action A function that is called for each child `DataSnapshot`.
|
||||
* The callback can return `true` to cancel further enumeration.
|
||||
*
|
||||
* @return `true` if enumeration was canceled due to your callback
|
||||
* returning `true`.
|
||||
*/
|
||||
forEach(action: (a: IteratedDataSnapshot) => boolean | void): boolean;
|
||||
/**
|
||||
* Returns `true` if the specified child path has (non-`null`) data.
|
||||
*
|
||||
* @param path A relative path to the location of a potential child.
|
||||
* @return `true` if data exists at the specified child path; otherwise,
|
||||
* `false`.
|
||||
*/
|
||||
hasChild(childPath: string): boolean;
|
||||
/**
|
||||
* Returns whether or not the `DataSnapshot` has any non-`null` child
|
||||
* properties.
|
||||
*
|
||||
* You can use `hasChildren()` to determine if a `DataSnapshot` has any
|
||||
* children. If it does, you can enumerate them using `forEach()`. If it
|
||||
* doesn't, then either this snapshot contains a primitive value (which can be
|
||||
* retrieved with `val()`) or it is empty (in which case, `val()` returns
|
||||
* `null`).
|
||||
*
|
||||
* @return `true` if this snapshot has any children; else `false`.
|
||||
*/
|
||||
hasChildren(): boolean;
|
||||
/**
|
||||
* Returns the number of child properties of this `DataSnapshot`.
|
||||
*
|
||||
* @return Number of child properties of this `DataSnapshot`.
|
||||
*/
|
||||
numChildren(): number;
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this object.
|
||||
*
|
||||
* @return A JSON-serializable representation of this object.
|
||||
*/
|
||||
toJSON(): Record<string, unknown>;
|
||||
/** Recursive function to check if keys are numeric & convert node object to array if they are
|
||||
*
|
||||
* @hidden
|
||||
*/
|
||||
private _checkAndConvertToArray;
|
||||
/** @hidden */
|
||||
private _dup;
|
||||
/** @hidden */
|
||||
private _fullPath;
|
||||
}
|
||||
export {};
|
||||
298
node_modules/firebase-functions/lib/common/providers/database.js
generated
vendored
Normal file
298
node_modules/firebase-functions/lib/common/providers/database.js
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.DataSnapshot = void 0;
|
||||
const database = require("firebase-admin/database");
|
||||
const config_1 = require("../../common/config");
|
||||
const path_1 = require("../../common/utilities/path");
|
||||
/**
|
||||
* Interface representing a Firebase Realtime database data snapshot.
|
||||
*/
|
||||
class DataSnapshot {
|
||||
constructor(data, path, // path is undefined for the database root
|
||||
app, instance) {
|
||||
this.app = app;
|
||||
const config = (0, config_1.firebaseConfig)();
|
||||
if (instance) {
|
||||
// SDK always supplies instance, but user's unit tests may not
|
||||
this.instance = instance;
|
||||
}
|
||||
else if (app) {
|
||||
this.instance = app.options.databaseURL;
|
||||
}
|
||||
else if (config.databaseURL) {
|
||||
this.instance = config.databaseURL;
|
||||
}
|
||||
else if (process.env.GCLOUD_PROJECT) {
|
||||
this.instance = "https://" + process.env.GCLOUD_PROJECT + "-default-rtdb.firebaseio.com";
|
||||
}
|
||||
this._path = path;
|
||||
this._data = data;
|
||||
}
|
||||
/**
|
||||
* Returns a [`Reference`](/docs/reference/admin/node/admin.database.Reference)
|
||||
* to the database location where the triggering write occurred. Has
|
||||
* full read and write access.
|
||||
*/
|
||||
get ref() {
|
||||
if (!this.app) {
|
||||
// may be unpopulated in user's unit tests
|
||||
throw new Error("Please supply a Firebase app in the constructor for DataSnapshot" +
|
||||
" in order to use the .ref method.");
|
||||
}
|
||||
if (!this._ref) {
|
||||
let db;
|
||||
if (this.instance) {
|
||||
db = database.getDatabaseWithUrl(this.instance, this.app);
|
||||
}
|
||||
else {
|
||||
db = database.getDatabase(this.app);
|
||||
}
|
||||
this._ref = db.ref(this._fullPath());
|
||||
}
|
||||
return this._ref;
|
||||
}
|
||||
/**
|
||||
* The key (last part of the path) of the location of this `DataSnapshot`.
|
||||
*
|
||||
* The last token in a database location is considered its key. For example,
|
||||
* "ada" is the key for the `/users/ada/` node. Accessing the key on any
|
||||
* `DataSnapshot` returns the key for the location that generated it.
|
||||
* However, accessing the key on the root URL of a database returns `null`.
|
||||
*/
|
||||
get key() {
|
||||
const segments = (0, path_1.pathParts)(this._fullPath());
|
||||
const last = segments[segments.length - 1];
|
||||
return !last || last === "" ? null : last;
|
||||
}
|
||||
/**
|
||||
* Extracts a JavaScript value from a `DataSnapshot`.
|
||||
*
|
||||
* Depending on the data in a `DataSnapshot`, the `val()` method may return a
|
||||
* scalar type (string, number, or boolean), an array, or an object. It may also
|
||||
* return `null`, indicating that the `DataSnapshot` is empty (contains no
|
||||
* data).
|
||||
*
|
||||
* @return The snapshot's contents as a JavaScript value (Object,
|
||||
* Array, string, number, boolean, or `null`).
|
||||
*/
|
||||
val() {
|
||||
const parts = (0, path_1.pathParts)(this._childPath);
|
||||
let source = this._data;
|
||||
if (parts.length) {
|
||||
for (const part of parts) {
|
||||
if (source[part] === undefined) {
|
||||
return null;
|
||||
}
|
||||
source = source[part];
|
||||
}
|
||||
}
|
||||
const node = source !== null && source !== void 0 ? source : null;
|
||||
return this._checkAndConvertToArray(node);
|
||||
}
|
||||
/**
|
||||
* Exports the entire contents of the `DataSnapshot` as a JavaScript object.
|
||||
*
|
||||
* @return The contents of the `DataSnapshot` as a JavaScript value
|
||||
* (Object, Array, string, number, boolean, or `null`).
|
||||
*/
|
||||
exportVal() {
|
||||
return this.val();
|
||||
}
|
||||
/**
|
||||
* Gets the priority value of the data in this `DataSnapshot`.
|
||||
*
|
||||
* As an alternative to using priority, applications can order collections by
|
||||
* ordinary properties. See [Sorting and filtering
|
||||
* data](/docs/database/web/lists-of-data#sorting_and_filtering_data).
|
||||
*
|
||||
* @return The priority value of the data.
|
||||
*/
|
||||
getPriority() {
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Returns `true` if this `DataSnapshot` contains any data. It is slightly more
|
||||
* efficient than using `snapshot.val() !== null`.
|
||||
*
|
||||
* @return `true` if this `DataSnapshot` contains any data; otherwise, `false`.
|
||||
*/
|
||||
exists() {
|
||||
const val = this.val();
|
||||
if (typeof val === "undefined" || val === null) {
|
||||
return false;
|
||||
}
|
||||
if (typeof val === "object" && Object.keys(val).length === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Gets a `DataSnapshot` for the location at the specified relative path.
|
||||
*
|
||||
* The relative path can either be a simple child name (for example, "ada") or
|
||||
* a deeper slash-separated path (for example, "ada/name/first").
|
||||
*
|
||||
* @param path A relative path from this location to the desired child
|
||||
* location.
|
||||
* @return The specified child location.
|
||||
*/
|
||||
child(childPath) {
|
||||
if (!childPath) {
|
||||
return this;
|
||||
}
|
||||
return this._dup(childPath);
|
||||
}
|
||||
/**
|
||||
* Enumerates the `DataSnapshot`s of the children items.
|
||||
*
|
||||
* Because of the way JavaScript objects work, the ordering of data in the
|
||||
* JavaScript object returned by `val()` is not guaranteed to match the ordering
|
||||
* on the server nor the ordering of `child_added` events. That is where
|
||||
* `forEach()` comes in handy. It guarantees the children of a `DataSnapshot`
|
||||
* can be iterated in their query order.
|
||||
*
|
||||
* If no explicit `orderBy*()` method is used, results are returned
|
||||
* ordered by key (unless priorities are used, in which case, results are
|
||||
* returned by priority).
|
||||
*
|
||||
* @param action A function that is called for each child `DataSnapshot`.
|
||||
* The callback can return `true` to cancel further enumeration.
|
||||
*
|
||||
* @return `true` if enumeration was canceled due to your callback
|
||||
* returning `true`.
|
||||
*/
|
||||
forEach(action) {
|
||||
const val = this.val() || {};
|
||||
if (typeof val === "object") {
|
||||
return Object.keys(val).some((key) => action(this.child(key)) === true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns `true` if the specified child path has (non-`null`) data.
|
||||
*
|
||||
* @param path A relative path to the location of a potential child.
|
||||
* @return `true` if data exists at the specified child path; otherwise,
|
||||
* `false`.
|
||||
*/
|
||||
hasChild(childPath) {
|
||||
return this.child(childPath).exists();
|
||||
}
|
||||
/**
|
||||
* Returns whether or not the `DataSnapshot` has any non-`null` child
|
||||
* properties.
|
||||
*
|
||||
* You can use `hasChildren()` to determine if a `DataSnapshot` has any
|
||||
* children. If it does, you can enumerate them using `forEach()`. If it
|
||||
* doesn't, then either this snapshot contains a primitive value (which can be
|
||||
* retrieved with `val()`) or it is empty (in which case, `val()` returns
|
||||
* `null`).
|
||||
*
|
||||
* @return `true` if this snapshot has any children; else `false`.
|
||||
*/
|
||||
hasChildren() {
|
||||
const val = this.val();
|
||||
return val !== null && typeof val === "object" && Object.keys(val).length > 0;
|
||||
}
|
||||
/**
|
||||
* Returns the number of child properties of this `DataSnapshot`.
|
||||
*
|
||||
* @return Number of child properties of this `DataSnapshot`.
|
||||
*/
|
||||
numChildren() {
|
||||
const val = this.val();
|
||||
return val !== null && typeof val === "object" ? Object.keys(val).length : 0;
|
||||
}
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this object.
|
||||
*
|
||||
* @return A JSON-serializable representation of this object.
|
||||
*/
|
||||
toJSON() {
|
||||
return this.val();
|
||||
}
|
||||
/** Recursive function to check if keys are numeric & convert node object to array if they are
|
||||
*
|
||||
* @hidden
|
||||
*/
|
||||
_checkAndConvertToArray(node) {
|
||||
if (node === null || typeof node === "undefined") {
|
||||
return null;
|
||||
}
|
||||
if (typeof node !== "object") {
|
||||
return node;
|
||||
}
|
||||
const obj = {};
|
||||
let numKeys = 0;
|
||||
let maxKey = 0;
|
||||
let allIntegerKeys = true;
|
||||
for (const key in node) {
|
||||
if (!node.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
const childNode = node[key];
|
||||
const v = this._checkAndConvertToArray(childNode);
|
||||
if (v === null) {
|
||||
// Empty child node
|
||||
continue;
|
||||
}
|
||||
obj[key] = v;
|
||||
numKeys++;
|
||||
const integerRegExp = /^(0|[1-9]\d*)$/;
|
||||
if (allIntegerKeys && integerRegExp.test(key)) {
|
||||
maxKey = Math.max(maxKey, Number(key));
|
||||
}
|
||||
else {
|
||||
allIntegerKeys = false;
|
||||
}
|
||||
}
|
||||
if (numKeys === 0) {
|
||||
// Empty node
|
||||
return null;
|
||||
}
|
||||
if (allIntegerKeys && maxKey < 2 * numKeys) {
|
||||
// convert to array.
|
||||
const array = [];
|
||||
for (const key of Object.keys(obj)) {
|
||||
array[key] = obj[key];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
/** @hidden */
|
||||
_dup(childPath) {
|
||||
const dup = new DataSnapshot(this._data, undefined, this.app, this.instance);
|
||||
[dup._path, dup._childPath] = [this._path, this._childPath];
|
||||
if (childPath) {
|
||||
dup._childPath = (0, path_1.joinPath)(dup._childPath, childPath);
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
/** @hidden */
|
||||
_fullPath() {
|
||||
return (this._path || "") + "/" + (this._childPath || "");
|
||||
}
|
||||
}
|
||||
exports.DataSnapshot = DataSnapshot;
|
||||
1
node_modules/firebase-functions/lib/common/providers/firestore.d.ts
generated
vendored
Normal file
1
node_modules/firebase-functions/lib/common/providers/firestore.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
110
node_modules/firebase-functions/lib/common/providers/firestore.js
generated
vendored
Normal file
110
node_modules/firebase-functions/lib/common/providers/firestore.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2023 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createBeforeSnapshotFromJson = exports.createSnapshotFromJson = exports.createBeforeSnapshotFromProtobuf = exports.createSnapshotFromProtobuf = void 0;
|
||||
const firestore = require("firebase-admin/firestore");
|
||||
const logger = require("../../logger");
|
||||
const app_1 = require("../../common/app");
|
||||
const compiledFirestore_1 = require("../../../protos/compiledFirestore");
|
||||
const encoder_1 = require("../../common/utilities/encoder");
|
||||
/** static-complied protobufs */
|
||||
const DocumentEventData = compiledFirestore_1.google.events.cloud.firestore.v1.DocumentEventData;
|
||||
let firestoreInstance;
|
||||
/** @hidden */
|
||||
function _getValueProto(data, resource, valueFieldName) {
|
||||
const value = data === null || data === void 0 ? void 0 : data[valueFieldName];
|
||||
if (typeof value === "undefined" ||
|
||||
value === null ||
|
||||
(typeof value === "object" && !Object.keys(value).length)) {
|
||||
// Firestore#snapshot_ takes resource string instead of proto for a non-existent snapshot
|
||||
return resource;
|
||||
}
|
||||
const proto = {
|
||||
fields: (value === null || value === void 0 ? void 0 : value.fields) || {},
|
||||
createTime: (0, encoder_1.dateToTimestampProto)(value === null || value === void 0 ? void 0 : value.createTime),
|
||||
updateTime: (0, encoder_1.dateToTimestampProto)(value === null || value === void 0 ? void 0 : value.updateTime),
|
||||
name: (value === null || value === void 0 ? void 0 : value.name) || resource,
|
||||
};
|
||||
return proto;
|
||||
}
|
||||
/** @internal */
|
||||
function createSnapshotFromProtobuf(data, path, databaseId) {
|
||||
if (!firestoreInstance) {
|
||||
firestoreInstance = firestore.getFirestore((0, app_1.getApp)(), databaseId);
|
||||
}
|
||||
try {
|
||||
const dataBuffer = Buffer.from(data);
|
||||
const firestoreDecoded = DocumentEventData.decode(dataBuffer);
|
||||
return firestoreInstance.snapshot_(firestoreDecoded.value || path, null, "protobufJS");
|
||||
}
|
||||
catch (err) {
|
||||
logger.error("Failed to decode protobuf and create a snapshot.");
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
exports.createSnapshotFromProtobuf = createSnapshotFromProtobuf;
|
||||
/** @internal */
|
||||
function createBeforeSnapshotFromProtobuf(data, path, databaseId) {
|
||||
if (!firestoreInstance) {
|
||||
firestoreInstance = firestore.getFirestore((0, app_1.getApp)(), databaseId);
|
||||
}
|
||||
try {
|
||||
const dataBuffer = Buffer.from(data);
|
||||
const firestoreDecoded = DocumentEventData.decode(dataBuffer);
|
||||
return firestoreInstance.snapshot_(firestoreDecoded.oldValue || path, null, "protobufJS");
|
||||
}
|
||||
catch (err) {
|
||||
logger.error("Failed to decode protobuf and create a before snapshot.");
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
exports.createBeforeSnapshotFromProtobuf = createBeforeSnapshotFromProtobuf;
|
||||
/** @internal */
|
||||
function createSnapshotFromJson(data, source, createTime, updateTime, databaseId) {
|
||||
if (!firestoreInstance) {
|
||||
firestoreInstance = databaseId
|
||||
? firestore.getFirestore((0, app_1.getApp)(), databaseId)
|
||||
: firestore.getFirestore((0, app_1.getApp)());
|
||||
}
|
||||
const valueProto = _getValueProto(data, source, "value");
|
||||
let timeString = createTime || updateTime;
|
||||
if (!timeString) {
|
||||
logger.warn("Snapshot has no readTime. Using now()");
|
||||
timeString = new Date().toISOString();
|
||||
}
|
||||
const readTime = (0, encoder_1.dateToTimestampProto)(timeString);
|
||||
return firestoreInstance.snapshot_(valueProto, readTime, "json");
|
||||
}
|
||||
exports.createSnapshotFromJson = createSnapshotFromJson;
|
||||
/** @internal */
|
||||
function createBeforeSnapshotFromJson(data, source, createTime, updateTime, databaseId) {
|
||||
if (!firestoreInstance) {
|
||||
firestoreInstance = databaseId
|
||||
? firestore.getFirestore((0, app_1.getApp)(), databaseId)
|
||||
: firestore.getFirestore((0, app_1.getApp)());
|
||||
}
|
||||
const oldValueProto = _getValueProto(data, source, "oldValue");
|
||||
const oldReadTime = (0, encoder_1.dateToTimestampProto)(createTime || updateTime);
|
||||
return firestoreInstance.snapshot_(oldValueProto, oldReadTime, "json");
|
||||
}
|
||||
exports.createBeforeSnapshotFromJson = createBeforeSnapshotFromJson;
|
||||
240
node_modules/firebase-functions/lib/common/providers/https.d.ts
generated
vendored
Normal file
240
node_modules/firebase-functions/lib/common/providers/https.d.ts
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
/// <reference types="node" />
|
||||
import * as express from "express";
|
||||
import { DecodedAppCheckToken } from "firebase-admin/app-check";
|
||||
import { DecodedIdToken } from "firebase-admin/auth";
|
||||
import { TaskContext } from "./tasks";
|
||||
/** An express request with the wire format representation of the request body. */
|
||||
export interface Request extends express.Request {
|
||||
/** The wire format representation of the request body. */
|
||||
rawBody: Buffer;
|
||||
}
|
||||
/**
|
||||
* The interface for AppCheck tokens verified in Callable functions
|
||||
*/
|
||||
export interface AppCheckData {
|
||||
/**
|
||||
* The app ID of a Firebase App attested by the App Check token.
|
||||
*/
|
||||
appId: string;
|
||||
/**
|
||||
* Decoded App Check token.
|
||||
*/
|
||||
token: DecodedAppCheckToken;
|
||||
/**
|
||||
* Indicates if the token has been consumed.
|
||||
*
|
||||
* @remarks
|
||||
* `false` value indicates that this is the first time the App Check service has seen this token and marked the
|
||||
* token as consumed for future use of the token.
|
||||
*
|
||||
* `true` value indicates the token has previously been marked as consumed by the App Check service. In this case,
|
||||
* consider taking extra precautions, such as rejecting the request or requiring additional security checks.
|
||||
*/
|
||||
alreadyConsumed?: boolean;
|
||||
}
|
||||
/**
|
||||
* The interface for Auth tokens verified in Callable functions
|
||||
*/
|
||||
export interface AuthData {
|
||||
uid: string;
|
||||
token: DecodedIdToken;
|
||||
}
|
||||
/**
|
||||
* The interface for metadata for the API as passed to the handler.
|
||||
*/
|
||||
export interface CallableContext {
|
||||
/**
|
||||
* The result of decoding and verifying a Firebase AppCheck token.
|
||||
*/
|
||||
app?: AppCheckData;
|
||||
/**
|
||||
* The result of decoding and verifying a Firebase Auth ID token.
|
||||
*/
|
||||
auth?: AuthData;
|
||||
/**
|
||||
* An unverified token for a Firebase Instance ID.
|
||||
*/
|
||||
instanceIdToken?: string;
|
||||
/**
|
||||
* The raw request handled by the callable.
|
||||
*/
|
||||
rawRequest: Request;
|
||||
}
|
||||
/**
|
||||
* The request used to call a callable function.
|
||||
*/
|
||||
export interface CallableRequest<T = any> {
|
||||
/**
|
||||
* The parameters used by a client when calling this function.
|
||||
*/
|
||||
data: T;
|
||||
/**
|
||||
* The result of decoding and verifying a Firebase App Check token.
|
||||
*/
|
||||
app?: AppCheckData;
|
||||
/**
|
||||
* The result of decoding and verifying a Firebase Auth ID token.
|
||||
*/
|
||||
auth?: AuthData;
|
||||
/**
|
||||
* An unverified token for a Firebase Instance ID.
|
||||
*/
|
||||
instanceIdToken?: string;
|
||||
/**
|
||||
* The raw request handled by the callable.
|
||||
*/
|
||||
rawRequest: Request;
|
||||
/**
|
||||
* Whether this is a streaming request.
|
||||
* Code can be optimized by not trying to generate a stream of chunks to
|
||||
* call `response.sendChunk` if `request.acceptsStreaming` is false.
|
||||
* It is always safe, however, to call `response.sendChunk` as this will
|
||||
* noop if `acceptsStreaming` is false.
|
||||
*/
|
||||
acceptsStreaming: boolean;
|
||||
}
|
||||
/**
|
||||
* `CallableProxyResponse` allows streaming response chunks and listening to signals
|
||||
* triggered in events such as a disconnect.
|
||||
*/
|
||||
export interface CallableResponse<T = unknown> {
|
||||
/**
|
||||
* Writes a chunk of the response body to the client. This method can be called
|
||||
* multiple times to stream data progressively.
|
||||
* Returns a promise of whether the data was written. This can be false, for example,
|
||||
* if the request was not a streaming request. Rejects if there is a network error.
|
||||
*/
|
||||
sendChunk: (chunk: T) => Promise<boolean>;
|
||||
/**
|
||||
* An `AbortSignal` that is triggered when the client disconnects or the
|
||||
* request is terminated prematurely.
|
||||
*/
|
||||
signal: AbortSignal;
|
||||
}
|
||||
/**
|
||||
* The set of Firebase Functions status codes. The codes are the same at the
|
||||
* ones exposed by {@link https://github.com/grpc/grpc/blob/master/doc/statuscodes.md | gRPC}.
|
||||
*
|
||||
* @remarks
|
||||
* Possible values:
|
||||
*
|
||||
* - `cancelled`: The operation was cancelled (typically by the caller).
|
||||
*
|
||||
* - `unknown`: Unknown error or an error from a different error domain.
|
||||
*
|
||||
* - `invalid-argument`: Client specified an invalid argument. Note that this
|
||||
* differs from `failed-precondition`. `invalid-argument` indicates
|
||||
* arguments that are problematic regardless of the state of the system
|
||||
* (e.g. an invalid field name).
|
||||
*
|
||||
* - `deadline-exceeded`: Deadline expired before operation could complete.
|
||||
* For operations that change the state of the system, this error may be
|
||||
* returned even if the operation has completed successfully. For example,
|
||||
* a successful response from a server could have been delayed long enough
|
||||
* for the deadline to expire.
|
||||
*
|
||||
* - `not-found`: Some requested document was not found.
|
||||
*
|
||||
* - `already-exists`: Some document that we attempted to create already
|
||||
* exists.
|
||||
*
|
||||
* - `permission-denied`: The caller does not have permission to execute the
|
||||
* specified operation.
|
||||
*
|
||||
* - `resource-exhausted`: Some resource has been exhausted, perhaps a
|
||||
* per-user quota, or perhaps the entire file system is out of space.
|
||||
*
|
||||
* - `failed-precondition`: Operation was rejected because the system is not
|
||||
* in a state required for the operation's execution.
|
||||
*
|
||||
* - `aborted`: The operation was aborted, typically due to a concurrency
|
||||
* issue like transaction aborts, etc.
|
||||
*
|
||||
* - `out-of-range`: Operation was attempted past the valid range.
|
||||
*
|
||||
* - `unimplemented`: Operation is not implemented or not supported/enabled.
|
||||
*
|
||||
* - `internal`: Internal errors. Means some invariants expected by
|
||||
* underlying system has been broken. If you see one of these errors,
|
||||
* something is very broken.
|
||||
*
|
||||
* - `unavailable`: The service is currently unavailable. This is most likely
|
||||
* a transient condition and may be corrected by retrying with a backoff.
|
||||
*
|
||||
* - `data-loss`: Unrecoverable data loss or corruption.
|
||||
*
|
||||
* - `unauthenticated`: The request does not have valid authentication
|
||||
* credentials for the operation.
|
||||
*/
|
||||
export type FunctionsErrorCode = "ok" | "cancelled" | "unknown" | "invalid-argument" | "deadline-exceeded" | "not-found" | "already-exists" | "permission-denied" | "resource-exhausted" | "failed-precondition" | "aborted" | "out-of-range" | "unimplemented" | "internal" | "unavailable" | "data-loss" | "unauthenticated";
|
||||
/** @hidden */
|
||||
export type CanonicalErrorCodeName = "OK" | "CANCELLED" | "UNKNOWN" | "INVALID_ARGUMENT" | "DEADLINE_EXCEEDED" | "NOT_FOUND" | "ALREADY_EXISTS" | "PERMISSION_DENIED" | "UNAUTHENTICATED" | "RESOURCE_EXHAUSTED" | "FAILED_PRECONDITION" | "ABORTED" | "OUT_OF_RANGE" | "UNIMPLEMENTED" | "INTERNAL" | "UNAVAILABLE" | "DATA_LOSS";
|
||||
/** @hidden */
|
||||
interface HttpErrorCode {
|
||||
canonicalName: CanonicalErrorCodeName;
|
||||
status: number;
|
||||
}
|
||||
/** @hidden */
|
||||
interface HttpErrorWireFormat {
|
||||
details?: unknown;
|
||||
message: string;
|
||||
status: CanonicalErrorCodeName;
|
||||
}
|
||||
/**
|
||||
* An explicit error that can be thrown from a handler to send an error to the
|
||||
* client that called the function.
|
||||
*/
|
||||
export declare class HttpsError extends Error {
|
||||
/**
|
||||
* A standard error code that will be returned to the client. This also
|
||||
* determines the HTTP status code of the response, as defined in code.proto.
|
||||
*/
|
||||
readonly code: FunctionsErrorCode;
|
||||
/**
|
||||
* Extra data to be converted to JSON and included in the error response.
|
||||
*/
|
||||
readonly details: unknown;
|
||||
/**
|
||||
* A wire format representation of a provided error code.
|
||||
*
|
||||
* @hidden
|
||||
*/
|
||||
readonly httpErrorCode: HttpErrorCode;
|
||||
constructor(code: FunctionsErrorCode, message: string, details?: unknown);
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this object.
|
||||
*/
|
||||
toJSON(): HttpErrorWireFormat;
|
||||
}
|
||||
/** @hidden */
|
||||
interface HttpRequest extends Request {
|
||||
body: {
|
||||
data: any;
|
||||
};
|
||||
}
|
||||
/** @hidden */
|
||||
export declare function isValidRequest(req: Request): req is HttpRequest;
|
||||
/**
|
||||
* Encodes arbitrary data in our special format for JSON.
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
/** @hidden */
|
||||
export declare function encode(data: any): any;
|
||||
/**
|
||||
* Decodes our special format for JSON into native types.
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
/** @hidden */
|
||||
export declare function decode(data: any): any;
|
||||
/**
|
||||
* Be careful when changing token status values.
|
||||
*
|
||||
* Users are encouraged to setup log-based metric based on these values, and
|
||||
* changing their values may cause their metrics to break.
|
||||
*
|
||||
*/
|
||||
/** @hidden */
|
||||
type TokenStatus = "MISSING" | "VALID" | "INVALID";
|
||||
/** @interanl */
|
||||
export declare function checkAuthToken(req: Request, ctx: CallableContext | TaskContext): Promise<TokenStatus>;
|
||||
export {};
|
||||
590
node_modules/firebase-functions/lib/common/providers/https.js
generated
vendored
Normal file
590
node_modules/firebase-functions/lib/common/providers/https.js
generated
vendored
Normal file
@@ -0,0 +1,590 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2021 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.onCallHandler = exports.checkAuthToken = exports.unsafeDecodeAppCheckToken = exports.unsafeDecodeIdToken = exports.unsafeDecodeToken = exports.decode = exports.encode = exports.isValidRequest = exports.HttpsError = exports.DEFAULT_HEARTBEAT_SECONDS = exports.ORIGINAL_AUTH_HEADER = exports.CALLABLE_AUTH_HEADER = void 0;
|
||||
const cors = require("cors");
|
||||
const logger = require("../../logger");
|
||||
// TODO(inlined): Decide whether we want to un-version apps or whether we want a
|
||||
// different strategy
|
||||
const app_check_1 = require("firebase-admin/app-check");
|
||||
const auth_1 = require("firebase-admin/auth");
|
||||
const app_1 = require("../app");
|
||||
const debug_1 = require("../debug");
|
||||
const JWT_REGEX = /^[a-zA-Z0-9\-_=]+?\.[a-zA-Z0-9\-_=]+?\.([a-zA-Z0-9\-_=]+)?$/;
|
||||
/** @internal */
|
||||
exports.CALLABLE_AUTH_HEADER = "x-callable-context-auth";
|
||||
/** @internal */
|
||||
exports.ORIGINAL_AUTH_HEADER = "x-original-auth";
|
||||
/** @internal */
|
||||
exports.DEFAULT_HEARTBEAT_SECONDS = 30;
|
||||
/**
|
||||
* Standard error codes and HTTP statuses for different ways a request can fail,
|
||||
* as defined by:
|
||||
* https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
|
||||
*
|
||||
* This map is used primarily to convert from a client error code string to
|
||||
* to the HTTP format error code string and status, and make sure it's in the
|
||||
* supported set.
|
||||
*/
|
||||
const errorCodeMap = {
|
||||
ok: { canonicalName: "OK", status: 200 },
|
||||
cancelled: { canonicalName: "CANCELLED", status: 499 },
|
||||
unknown: { canonicalName: "UNKNOWN", status: 500 },
|
||||
"invalid-argument": { canonicalName: "INVALID_ARGUMENT", status: 400 },
|
||||
"deadline-exceeded": { canonicalName: "DEADLINE_EXCEEDED", status: 504 },
|
||||
"not-found": { canonicalName: "NOT_FOUND", status: 404 },
|
||||
"already-exists": { canonicalName: "ALREADY_EXISTS", status: 409 },
|
||||
"permission-denied": { canonicalName: "PERMISSION_DENIED", status: 403 },
|
||||
unauthenticated: { canonicalName: "UNAUTHENTICATED", status: 401 },
|
||||
"resource-exhausted": { canonicalName: "RESOURCE_EXHAUSTED", status: 429 },
|
||||
"failed-precondition": { canonicalName: "FAILED_PRECONDITION", status: 400 },
|
||||
aborted: { canonicalName: "ABORTED", status: 409 },
|
||||
"out-of-range": { canonicalName: "OUT_OF_RANGE", status: 400 },
|
||||
unimplemented: { canonicalName: "UNIMPLEMENTED", status: 501 },
|
||||
internal: { canonicalName: "INTERNAL", status: 500 },
|
||||
unavailable: { canonicalName: "UNAVAILABLE", status: 503 },
|
||||
"data-loss": { canonicalName: "DATA_LOSS", status: 500 },
|
||||
};
|
||||
/**
|
||||
* An explicit error that can be thrown from a handler to send an error to the
|
||||
* client that called the function.
|
||||
*/
|
||||
class HttpsError extends Error {
|
||||
constructor(code, message, details) {
|
||||
super(message);
|
||||
// A sanity check for non-TypeScript consumers.
|
||||
if (code in errorCodeMap === false) {
|
||||
throw new Error(`Unknown error code: ${code}.`);
|
||||
}
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
this.httpErrorCode = errorCodeMap[code];
|
||||
}
|
||||
/**
|
||||
* Returns a JSON-serializable representation of this object.
|
||||
*/
|
||||
toJSON() {
|
||||
const { details, httpErrorCode: { canonicalName: status }, message, } = this;
|
||||
return {
|
||||
...(details === undefined ? {} : { details }),
|
||||
message,
|
||||
status,
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.HttpsError = HttpsError;
|
||||
/** @hidden */
|
||||
// Returns true if req is a properly formatted callable request.
|
||||
function isValidRequest(req) {
|
||||
// The body must not be empty.
|
||||
if (!req.body) {
|
||||
logger.warn("Request is missing body.");
|
||||
return false;
|
||||
}
|
||||
// Make sure it's a POST.
|
||||
if (req.method !== "POST") {
|
||||
logger.warn("Request has invalid method.", req.method);
|
||||
return false;
|
||||
}
|
||||
// Check that the Content-Type is JSON.
|
||||
let contentType = (req.header("Content-Type") || "").toLowerCase();
|
||||
// If it has a charset, just ignore it for now.
|
||||
const semiColon = contentType.indexOf(";");
|
||||
if (semiColon >= 0) {
|
||||
contentType = contentType.slice(0, semiColon).trim();
|
||||
}
|
||||
if (contentType !== "application/json") {
|
||||
logger.warn("Request has incorrect Content-Type.", contentType);
|
||||
return false;
|
||||
}
|
||||
// The body must have data.
|
||||
if (typeof req.body.data === "undefined") {
|
||||
logger.warn("Request body is missing data.", req.body);
|
||||
return false;
|
||||
}
|
||||
// TODO(klimt): Allow only specific http headers.
|
||||
// Verify that the body does not have any extra fields.
|
||||
const extraKeys = Object.keys(req.body).filter((field) => field !== "data");
|
||||
if (extraKeys.length !== 0) {
|
||||
logger.warn("Request body has extra fields: ", extraKeys.join(", "));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.isValidRequest = isValidRequest;
|
||||
/** @hidden */
|
||||
const LONG_TYPE = "type.googleapis.com/google.protobuf.Int64Value";
|
||||
/** @hidden */
|
||||
const UNSIGNED_LONG_TYPE = "type.googleapis.com/google.protobuf.UInt64Value";
|
||||
/**
|
||||
* Encodes arbitrary data in our special format for JSON.
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
/** @hidden */
|
||||
function encode(data) {
|
||||
if (data === null || typeof data === "undefined") {
|
||||
return null;
|
||||
}
|
||||
if (data instanceof Number) {
|
||||
data = data.valueOf();
|
||||
}
|
||||
if (Number.isFinite(data)) {
|
||||
// Any number in JS is safe to put directly in JSON and parse as a double
|
||||
// without any loss of precision.
|
||||
return data;
|
||||
}
|
||||
if (typeof data === "boolean") {
|
||||
return data;
|
||||
}
|
||||
if (typeof data === "string") {
|
||||
return data;
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(encode);
|
||||
}
|
||||
if (typeof data === "object" || typeof data === "function") {
|
||||
// Sadly we don't have Object.fromEntries in Node 10, so we can't use a single
|
||||
// list comprehension
|
||||
const obj = {};
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
obj[k] = encode(v);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
// If we got this far, the data is not encodable.
|
||||
logger.error("Data cannot be encoded in JSON.", data);
|
||||
throw new Error(`Data cannot be encoded in JSON: ${data}`);
|
||||
}
|
||||
exports.encode = encode;
|
||||
/**
|
||||
* Decodes our special format for JSON into native types.
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
/** @hidden */
|
||||
function decode(data) {
|
||||
if (data === null) {
|
||||
return data;
|
||||
}
|
||||
if (data["@type"]) {
|
||||
switch (data["@type"]) {
|
||||
case LONG_TYPE:
|
||||
// Fall through and handle this the same as unsigned.
|
||||
case UNSIGNED_LONG_TYPE: {
|
||||
// Technically, this could work return a valid number for malformed
|
||||
// data if there was a number followed by garbage. But it's just not
|
||||
// worth all the extra code to detect that case.
|
||||
const value = parseFloat(data.value);
|
||||
if (isNaN(value)) {
|
||||
logger.error("Data cannot be decoded from JSON.", data);
|
||||
throw new Error(`Data cannot be decoded from JSON: ${data}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
logger.error("Data cannot be decoded from JSON.", data);
|
||||
throw new Error(`Data cannot be decoded from JSON: ${data}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(decode);
|
||||
}
|
||||
if (typeof data === "object") {
|
||||
const obj = {};
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
obj[k] = decode(v);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
// Anything else is safe to return.
|
||||
return data;
|
||||
}
|
||||
exports.decode = decode;
|
||||
/** @internal */
|
||||
function unsafeDecodeToken(token) {
|
||||
if (!JWT_REGEX.test(token)) {
|
||||
return {};
|
||||
}
|
||||
const components = token.split(".").map((s) => Buffer.from(s, "base64").toString());
|
||||
let payload = components[1];
|
||||
if (typeof payload === "string") {
|
||||
try {
|
||||
const obj = JSON.parse(payload);
|
||||
if (typeof obj === "object") {
|
||||
payload = obj;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
exports.unsafeDecodeToken = unsafeDecodeToken;
|
||||
/**
|
||||
* Decode, but not verify, a Auth ID token.
|
||||
*
|
||||
* Do not use in production. Token should always be verified using the Admin SDK.
|
||||
*
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
/** @internal */
|
||||
function unsafeDecodeIdToken(token) {
|
||||
const decoded = unsafeDecodeToken(token);
|
||||
decoded.uid = decoded.sub;
|
||||
return decoded;
|
||||
}
|
||||
exports.unsafeDecodeIdToken = unsafeDecodeIdToken;
|
||||
/**
|
||||
* Decode, but not verify, an App Check token.
|
||||
*
|
||||
* Do not use in production. Token should always be verified using the Admin SDK.
|
||||
*
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
/** @internal */
|
||||
function unsafeDecodeAppCheckToken(token) {
|
||||
const decoded = unsafeDecodeToken(token);
|
||||
decoded.app_id = decoded.sub;
|
||||
return decoded;
|
||||
}
|
||||
exports.unsafeDecodeAppCheckToken = unsafeDecodeAppCheckToken;
|
||||
/**
|
||||
* Check and verify tokens included in the requests. Once verified, tokens
|
||||
* are injected into the callable context.
|
||||
*
|
||||
* @param {Request} req - Request sent to the Callable function.
|
||||
* @param {CallableContext} ctx - Context to be sent to callable function handler.
|
||||
* @returns {CallableTokenStatus} Status of the token verifications.
|
||||
*/
|
||||
/** @internal */
|
||||
async function checkTokens(req, ctx, options) {
|
||||
const verifications = {
|
||||
app: "INVALID",
|
||||
auth: "INVALID",
|
||||
};
|
||||
[verifications.auth, verifications.app] = await Promise.all([
|
||||
checkAuthToken(req, ctx),
|
||||
checkAppCheckToken(req, ctx, options),
|
||||
]);
|
||||
const logPayload = {
|
||||
verifications,
|
||||
"logging.googleapis.com/labels": {
|
||||
"firebase-log-type": "callable-request-verification",
|
||||
},
|
||||
};
|
||||
const errs = [];
|
||||
if (verifications.app === "INVALID") {
|
||||
errs.push("AppCheck token was rejected.");
|
||||
}
|
||||
if (verifications.auth === "INVALID") {
|
||||
errs.push("Auth token was rejected.");
|
||||
}
|
||||
if (errs.length === 0) {
|
||||
logger.debug("Callable request verification passed", logPayload);
|
||||
}
|
||||
else {
|
||||
logger.warn(`Callable request verification failed: ${errs.join(" ")}`, logPayload);
|
||||
}
|
||||
return verifications;
|
||||
}
|
||||
/** @interanl */
|
||||
async function checkAuthToken(req, ctx) {
|
||||
const authorization = req.header("Authorization");
|
||||
if (!authorization) {
|
||||
return "MISSING";
|
||||
}
|
||||
const match = authorization.match(/^Bearer (.*)$/i);
|
||||
if (!match) {
|
||||
return "INVALID";
|
||||
}
|
||||
const idToken = match[1];
|
||||
try {
|
||||
let authToken;
|
||||
if ((0, debug_1.isDebugFeatureEnabled)("skipTokenVerification")) {
|
||||
authToken = unsafeDecodeIdToken(idToken);
|
||||
}
|
||||
else {
|
||||
authToken = await (0, auth_1.getAuth)((0, app_1.getApp)()).verifyIdToken(idToken);
|
||||
}
|
||||
ctx.auth = {
|
||||
uid: authToken.uid,
|
||||
token: authToken,
|
||||
};
|
||||
return "VALID";
|
||||
}
|
||||
catch (err) {
|
||||
logger.warn("Failed to validate auth token.", err);
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
exports.checkAuthToken = checkAuthToken;
|
||||
/** @internal */
|
||||
async function checkAppCheckToken(req, ctx, options) {
|
||||
var _a;
|
||||
const appCheckToken = req.header("X-Firebase-AppCheck");
|
||||
if (!appCheckToken) {
|
||||
return "MISSING";
|
||||
}
|
||||
try {
|
||||
let appCheckData;
|
||||
if ((0, debug_1.isDebugFeatureEnabled)("skipTokenVerification")) {
|
||||
const decodedToken = unsafeDecodeAppCheckToken(appCheckToken);
|
||||
appCheckData = { appId: decodedToken.app_id, token: decodedToken };
|
||||
if (options.consumeAppCheckToken) {
|
||||
appCheckData.alreadyConsumed = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const appCheck = (0, app_check_1.getAppCheck)((0, app_1.getApp)());
|
||||
if (options.consumeAppCheckToken) {
|
||||
if (((_a = appCheck.verifyToken) === null || _a === void 0 ? void 0 : _a.length) === 1) {
|
||||
const errorMsg = "Unsupported version of the Admin SDK." +
|
||||
" App Check token will not be consumed." +
|
||||
" Please upgrade the firebase-admin to the latest version.";
|
||||
logger.error(errorMsg);
|
||||
throw new HttpsError("internal", "Internal Error");
|
||||
}
|
||||
appCheckData = await (0, app_check_1.getAppCheck)((0, app_1.getApp)()).verifyToken(appCheckToken, { consume: true });
|
||||
}
|
||||
else {
|
||||
appCheckData = await (0, app_check_1.getAppCheck)((0, app_1.getApp)()).verifyToken(appCheckToken);
|
||||
}
|
||||
}
|
||||
ctx.app = appCheckData;
|
||||
return "VALID";
|
||||
}
|
||||
catch (err) {
|
||||
logger.warn("Failed to validate AppCheck token.", err);
|
||||
if (err instanceof HttpsError) {
|
||||
throw err;
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
function onCallHandler(options, handler, version) {
|
||||
const wrapped = wrapOnCallHandler(options, handler, version);
|
||||
return (req, res) => {
|
||||
return new Promise((resolve) => {
|
||||
res.on("finish", resolve);
|
||||
cors(options.cors)(req, res, () => {
|
||||
resolve(wrapped(req, res));
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.onCallHandler = onCallHandler;
|
||||
function encodeSSE(data) {
|
||||
return `data: ${JSON.stringify(data)}\n\n`;
|
||||
}
|
||||
/** @internal */
|
||||
function wrapOnCallHandler(options, handler, version) {
|
||||
return async (req, res) => {
|
||||
var _a;
|
||||
const abortController = new AbortController();
|
||||
let heartbeatInterval = null;
|
||||
const heartbeatSeconds = options.heartbeatSeconds === undefined ? exports.DEFAULT_HEARTBEAT_SECONDS : options.heartbeatSeconds;
|
||||
const clearScheduledHeartbeat = () => {
|
||||
if (heartbeatInterval) {
|
||||
clearTimeout(heartbeatInterval);
|
||||
heartbeatInterval = null;
|
||||
}
|
||||
};
|
||||
const scheduleHeartbeat = () => {
|
||||
clearScheduledHeartbeat();
|
||||
if (!abortController.signal.aborted) {
|
||||
heartbeatInterval = setTimeout(() => {
|
||||
if (!abortController.signal.aborted) {
|
||||
res.write(": ping\n\n");
|
||||
scheduleHeartbeat();
|
||||
}
|
||||
}, heartbeatSeconds * 1000);
|
||||
}
|
||||
};
|
||||
res.on("close", () => {
|
||||
clearScheduledHeartbeat();
|
||||
abortController.abort();
|
||||
});
|
||||
try {
|
||||
if (!isValidRequest(req)) {
|
||||
logger.error("Invalid request, unable to process.");
|
||||
throw new HttpsError("invalid-argument", "Bad Request");
|
||||
}
|
||||
const context = { rawRequest: req };
|
||||
// TODO(colerogers): yank this when we release a breaking change of the CLI that removes
|
||||
// our monkey-patching code referenced below and increases the minimum supported SDK version.
|
||||
//
|
||||
// Note: This code is needed to fix v1 callable functions in the emulator with a monorepo setup.
|
||||
// The original monkey-patched code lived in the functionsEmulatorRuntime
|
||||
// (link: https://github.com/firebase/firebase-tools/blob/accea7abda3cc9fa6bb91368e4895faf95281c60/src/emulator/functionsEmulatorRuntime.ts#L480)
|
||||
// and was not compatible with how monorepos separate out packages (see https://github.com/firebase/firebase-tools/issues/5210).
|
||||
if ((0, debug_1.isDebugFeatureEnabled)("skipTokenVerification") && version === "gcfv1") {
|
||||
const authContext = context.rawRequest.header(exports.CALLABLE_AUTH_HEADER);
|
||||
if (authContext) {
|
||||
logger.debug("Callable functions auth override", {
|
||||
key: exports.CALLABLE_AUTH_HEADER,
|
||||
value: authContext,
|
||||
});
|
||||
context.auth = JSON.parse(decodeURIComponent(authContext));
|
||||
delete context.rawRequest.headers[exports.CALLABLE_AUTH_HEADER];
|
||||
}
|
||||
const originalAuth = context.rawRequest.header(exports.ORIGINAL_AUTH_HEADER);
|
||||
if (originalAuth) {
|
||||
context.rawRequest.headers["authorization"] = originalAuth;
|
||||
delete context.rawRequest.headers[exports.ORIGINAL_AUTH_HEADER];
|
||||
}
|
||||
}
|
||||
const tokenStatus = await checkTokens(req, context, options);
|
||||
if (tokenStatus.auth === "INVALID") {
|
||||
throw new HttpsError("unauthenticated", "Unauthenticated");
|
||||
}
|
||||
if (tokenStatus.app === "INVALID") {
|
||||
if (options.enforceAppCheck) {
|
||||
throw new HttpsError("unauthenticated", "Unauthenticated");
|
||||
}
|
||||
else {
|
||||
logger.warn("Allowing request with invalid AppCheck token because enforcement is disabled");
|
||||
}
|
||||
}
|
||||
if (tokenStatus.app === "MISSING" && options.enforceAppCheck) {
|
||||
throw new HttpsError("unauthenticated", "Unauthenticated");
|
||||
}
|
||||
const instanceId = req.header("Firebase-Instance-ID-Token");
|
||||
if (instanceId) {
|
||||
// Validating the token requires an http request, so we don't do it.
|
||||
// If the user wants to use it for something, it will be validated then.
|
||||
// Currently, the only real use case for this token is for sending
|
||||
// pushes with FCM. In that case, the FCM APIs will validate the token.
|
||||
context.instanceIdToken = req.header("Firebase-Instance-ID-Token");
|
||||
}
|
||||
const acceptsStreaming = req.header("accept") === "text/event-stream";
|
||||
if (acceptsStreaming && version === "gcfv1") {
|
||||
// streaming responses are not supported in v1 callable
|
||||
throw new HttpsError("invalid-argument", "Unsupported Accept header 'text/event-stream'");
|
||||
}
|
||||
const data = decode(req.body.data);
|
||||
if (options.authPolicy) {
|
||||
const authorized = await options.authPolicy((_a = context.auth) !== null && _a !== void 0 ? _a : null, data);
|
||||
if (!authorized) {
|
||||
throw new HttpsError("permission-denied", "Permission Denied");
|
||||
}
|
||||
}
|
||||
let result;
|
||||
if (version === "gcfv1") {
|
||||
result = await handler(data, context);
|
||||
}
|
||||
else {
|
||||
const arg = {
|
||||
...context,
|
||||
data,
|
||||
acceptsStreaming,
|
||||
};
|
||||
const responseProxy = {
|
||||
sendChunk(chunk) {
|
||||
// if client doesn't accept sse-protocol, response.write() is no-op.
|
||||
if (!acceptsStreaming) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
// if connection is already closed, response.write() is no-op.
|
||||
if (abortController.signal.aborted) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
const formattedData = encodeSSE({ message: chunk });
|
||||
let resolve;
|
||||
let reject;
|
||||
const p = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
const wrote = res.write(formattedData, (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(wrote);
|
||||
});
|
||||
// Reset heartbeat timer after successful write
|
||||
if (wrote && heartbeatInterval !== null && heartbeatSeconds > 0) {
|
||||
scheduleHeartbeat();
|
||||
}
|
||||
return p;
|
||||
},
|
||||
signal: abortController.signal,
|
||||
};
|
||||
if (acceptsStreaming) {
|
||||
// SSE always responds with 200
|
||||
res.status(200);
|
||||
if (heartbeatSeconds !== null && heartbeatSeconds > 0) {
|
||||
scheduleHeartbeat();
|
||||
}
|
||||
}
|
||||
// For some reason the type system isn't picking up that the handler
|
||||
// is a one argument function.
|
||||
result = await handler(arg, responseProxy);
|
||||
clearScheduledHeartbeat();
|
||||
}
|
||||
if (!abortController.signal.aborted) {
|
||||
// Encode the result as JSON to preserve types like Dates.
|
||||
result = encode(result);
|
||||
// If there was some result, encode it in the body.
|
||||
const responseBody = { result };
|
||||
if (acceptsStreaming) {
|
||||
res.write(encodeSSE(responseBody));
|
||||
res.end();
|
||||
}
|
||||
else {
|
||||
res.status(200).send(responseBody);
|
||||
}
|
||||
}
|
||||
else {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
if (!abortController.signal.aborted) {
|
||||
let httpErr = err;
|
||||
if (!(err instanceof HttpsError)) {
|
||||
// This doesn't count as an 'explicit' error.
|
||||
logger.error("Unhandled error", err);
|
||||
httpErr = new HttpsError("internal", "INTERNAL");
|
||||
}
|
||||
const { status } = httpErr.httpErrorCode;
|
||||
const body = { error: httpErr.toJSON() };
|
||||
if (version === "gcfv2" && req.header("accept") === "text/event-stream") {
|
||||
res.write(encodeSSE(body));
|
||||
res.end();
|
||||
}
|
||||
else {
|
||||
res.status(status).send(body);
|
||||
}
|
||||
}
|
||||
else {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
clearScheduledHeartbeat();
|
||||
}
|
||||
};
|
||||
}
|
||||
258
node_modules/firebase-functions/lib/common/providers/identity.d.ts
generated
vendored
Normal file
258
node_modules/firebase-functions/lib/common/providers/identity.d.ts
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
import * as auth from "firebase-admin/auth";
|
||||
import { EventContext } from "../../v1/cloud-functions";
|
||||
import { HttpsError } from "./https";
|
||||
export { HttpsError };
|
||||
/**
|
||||
* Shorthand auth blocking events from GCIP.
|
||||
* @hidden
|
||||
* @alpha
|
||||
*/
|
||||
export type AuthBlockingEventType = "beforeCreate" | "beforeSignIn" | "beforeSendEmail" | "beforeSendSms";
|
||||
/**
|
||||
* The `UserRecord` passed to Cloud Functions is the same
|
||||
* {@link https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth.userrecord | UserRecord}
|
||||
* that is returned by the Firebase Admin SDK.
|
||||
*/
|
||||
export type UserRecord = auth.UserRecord;
|
||||
/**
|
||||
* `UserInfo` that is part of the `UserRecord`.
|
||||
*/
|
||||
export type UserInfo = auth.UserInfo;
|
||||
/**
|
||||
* Helper class to create the user metadata in a `UserRecord` object.
|
||||
*/
|
||||
export declare class UserRecordMetadata implements auth.UserMetadata {
|
||||
creationTime: string;
|
||||
lastSignInTime: string;
|
||||
constructor(creationTime: string, lastSignInTime: string);
|
||||
/** Returns a plain JavaScript object with the properties of UserRecordMetadata. */
|
||||
toJSON(): AuthUserMetadata;
|
||||
}
|
||||
/**
|
||||
* Helper function that creates a `UserRecord` class from data sent over the wire.
|
||||
* @param wireData data sent over the wire
|
||||
* @returns an instance of `UserRecord` with correct toJSON functions
|
||||
*/
|
||||
export declare function userRecordConstructor(wireData: Record<string, unknown>): UserRecord;
|
||||
/**
|
||||
* User info that is part of the `AuthUserRecord`.
|
||||
*/
|
||||
export interface AuthUserInfo {
|
||||
/**
|
||||
* The user identifier for the linked provider.
|
||||
*/
|
||||
uid: string;
|
||||
/**
|
||||
* The display name for the linked provider.
|
||||
*/
|
||||
displayName: string;
|
||||
/**
|
||||
* The email for the linked provider.
|
||||
*/
|
||||
email: string;
|
||||
/**
|
||||
* The photo URL for the linked provider.
|
||||
*/
|
||||
photoURL: string;
|
||||
/**
|
||||
* The linked provider ID (for example, "google.com" for the Google provider).
|
||||
*/
|
||||
providerId: string;
|
||||
/**
|
||||
* The phone number for the linked provider.
|
||||
*/
|
||||
phoneNumber: string;
|
||||
}
|
||||
/**
|
||||
* Additional metadata about the user.
|
||||
*/
|
||||
export interface AuthUserMetadata {
|
||||
/**
|
||||
* The date the user was created, formatted as a UTC string.
|
||||
*/
|
||||
creationTime: string;
|
||||
/**
|
||||
* The date the user last signed in, formatted as a UTC string.
|
||||
*/
|
||||
lastSignInTime: string;
|
||||
}
|
||||
/**
|
||||
* Interface representing the common properties of a user-enrolled second factor.
|
||||
*/
|
||||
export interface AuthMultiFactorInfo {
|
||||
/**
|
||||
* The ID of the enrolled second factor. This ID is unique to the user.
|
||||
*/
|
||||
uid: string;
|
||||
/**
|
||||
* The optional display name of the enrolled second factor.
|
||||
*/
|
||||
displayName?: string;
|
||||
/**
|
||||
* The type identifier of the second factor. For SMS second factors, this is `phone`.
|
||||
*/
|
||||
factorId: string;
|
||||
/**
|
||||
* The optional date the second factor was enrolled, formatted as a UTC string.
|
||||
*/
|
||||
enrollmentTime?: string;
|
||||
/**
|
||||
* The phone number associated with a phone second factor.
|
||||
*/
|
||||
phoneNumber?: string;
|
||||
}
|
||||
/**
|
||||
* The multi-factor related properties for the current user, if available.
|
||||
*/
|
||||
export interface AuthMultiFactorSettings {
|
||||
/**
|
||||
* List of second factors enrolled with the current user.
|
||||
*/
|
||||
enrolledFactors: AuthMultiFactorInfo[];
|
||||
}
|
||||
/**
|
||||
* The `UserRecord` passed to auth blocking functions from the identity platform.
|
||||
*/
|
||||
export interface AuthUserRecord {
|
||||
/**
|
||||
* The user's `uid`.
|
||||
*/
|
||||
uid: string;
|
||||
/**
|
||||
* The user's primary email, if set.
|
||||
*/
|
||||
email?: string;
|
||||
/**
|
||||
* Whether or not the user's primary email is verified.
|
||||
*/
|
||||
emailVerified: boolean;
|
||||
/**
|
||||
* The user's display name.
|
||||
*/
|
||||
displayName?: string;
|
||||
/**
|
||||
* The user's photo URL.
|
||||
*/
|
||||
photoURL?: string;
|
||||
/**
|
||||
* The user's primary phone number, if set.
|
||||
*/
|
||||
phoneNumber?: string;
|
||||
/**
|
||||
* Whether or not the user is disabled: `true` for disabled; `false` for
|
||||
* enabled.
|
||||
*/
|
||||
disabled: boolean;
|
||||
/**
|
||||
* Additional metadata about the user.
|
||||
*/
|
||||
metadata: AuthUserMetadata;
|
||||
/**
|
||||
* An array of providers (for example, Google, Facebook) linked to the user.
|
||||
*/
|
||||
providerData: AuthUserInfo[];
|
||||
/**
|
||||
* The user's hashed password (base64-encoded).
|
||||
*/
|
||||
passwordHash?: string;
|
||||
/**
|
||||
* The user's password salt (base64-encoded).
|
||||
*/
|
||||
passwordSalt?: string;
|
||||
/**
|
||||
* The user's custom claims object if available, typically used to define
|
||||
* user roles and propagated to an authenticated user's ID token.
|
||||
*/
|
||||
customClaims?: Record<string, any>;
|
||||
/**
|
||||
* The ID of the tenant the user belongs to, if available.
|
||||
*/
|
||||
tenantId?: string | null;
|
||||
/**
|
||||
* The date the user's tokens are valid after, formatted as a UTC string.
|
||||
*/
|
||||
tokensValidAfterTime?: string;
|
||||
/**
|
||||
* The multi-factor related properties for the current user, if available.
|
||||
*/
|
||||
multiFactor?: AuthMultiFactorSettings;
|
||||
}
|
||||
/** The additional user info component of the auth event context */
|
||||
export interface AdditionalUserInfo {
|
||||
providerId?: string;
|
||||
profile?: any;
|
||||
username?: string;
|
||||
isNewUser: boolean;
|
||||
recaptchaScore?: number;
|
||||
email?: string;
|
||||
phoneNumber?: string;
|
||||
}
|
||||
/** The credential component of the auth event context */
|
||||
export interface Credential {
|
||||
claims?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
idToken?: string;
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
expirationTime?: string;
|
||||
secret?: string;
|
||||
providerId: string;
|
||||
signInMethod: string;
|
||||
}
|
||||
/**
|
||||
* Possible types of emails as described by the GCIP backend, which can be:
|
||||
* - A sign-in email
|
||||
* - A password reset email
|
||||
*/
|
||||
export type EmailType = "EMAIL_SIGN_IN" | "PASSWORD_RESET";
|
||||
/**
|
||||
* The type of SMS message, which can be:
|
||||
* - A sign-in or sign up SMS message
|
||||
* - A multi-factor sign-in SMS message
|
||||
* - A multi-factor enrollment SMS message
|
||||
*/
|
||||
export type SmsType = "SIGN_IN_OR_SIGN_UP" | "MULTI_FACTOR_SIGN_IN" | "MULTI_FACTOR_ENROLLMENT";
|
||||
/** Defines the auth event context for blocking events */
|
||||
export interface AuthEventContext extends EventContext {
|
||||
locale?: string;
|
||||
ipAddress: string;
|
||||
userAgent: string;
|
||||
additionalUserInfo?: AdditionalUserInfo;
|
||||
credential?: Credential;
|
||||
emailType?: EmailType;
|
||||
smsType?: SmsType;
|
||||
}
|
||||
/** Defines the auth event for 2nd gen blocking events */
|
||||
export interface AuthBlockingEvent extends AuthEventContext {
|
||||
data?: AuthUserRecord;
|
||||
}
|
||||
/** The reCAPTCHA action options. */
|
||||
export type RecaptchaActionOptions = "ALLOW" | "BLOCK";
|
||||
/** The handler response type for `beforeEmailSent` blocking events */
|
||||
export interface BeforeEmailResponse {
|
||||
recaptchaActionOverride?: RecaptchaActionOptions;
|
||||
}
|
||||
/** The handler response type for `beforeSmsSent` blocking events */
|
||||
export interface BeforeSmsResponse {
|
||||
recaptchaActionOverride?: RecaptchaActionOptions;
|
||||
}
|
||||
/** The handler response type for `beforeCreate` blocking events */
|
||||
export interface BeforeCreateResponse {
|
||||
displayName?: string;
|
||||
disabled?: boolean;
|
||||
emailVerified?: boolean;
|
||||
photoURL?: string;
|
||||
customClaims?: object;
|
||||
recaptchaActionOverride?: RecaptchaActionOptions;
|
||||
}
|
||||
/** The handler response type for `beforeSignIn` blocking events */
|
||||
export interface BeforeSignInResponse extends BeforeCreateResponse {
|
||||
sessionClaims?: object;
|
||||
}
|
||||
export type MaybeAsync<T> = T | Promise<T>;
|
||||
export type HandlerV1 = (userOrContext: AuthUserRecord | AuthEventContext, context?: AuthEventContext) => MaybeAsync<BeforeCreateResponse | BeforeSignInResponse | BeforeEmailResponse | BeforeSmsResponse | void>;
|
||||
export type HandlerV2 = (event: AuthBlockingEvent) => MaybeAsync<BeforeCreateResponse | BeforeSignInResponse | BeforeEmailResponse | BeforeSmsResponse | void>;
|
||||
export type AuthBlockingEventHandler = (HandlerV1 | HandlerV2) & {
|
||||
platform: "gcfv1" | "gcfv2";
|
||||
};
|
||||
494
node_modules/firebase-functions/lib/common/providers/identity.js
generated
vendored
Normal file
494
node_modules/firebase-functions/lib/common/providers/identity.js
generated
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.wrapHandler = exports.getUpdateMask = exports.validateAuthResponse = exports.parseAuthEventContext = exports.generateResponsePayload = exports.parseAuthUserRecord = exports.parseMultiFactor = exports.parseDate = exports.parseProviderData = exports.parseMetadata = exports.isValidRequest = exports.userRecordConstructor = exports.UserRecordMetadata = exports.HttpsError = void 0;
|
||||
const auth = require("firebase-admin/auth");
|
||||
const logger = require("../../logger");
|
||||
const app_1 = require("../app");
|
||||
const debug_1 = require("../debug");
|
||||
const https_1 = require("./https");
|
||||
Object.defineProperty(exports, "HttpsError", { enumerable: true, get: function () { return https_1.HttpsError; } });
|
||||
const DISALLOWED_CUSTOM_CLAIMS = [
|
||||
"acr",
|
||||
"amr",
|
||||
"at_hash",
|
||||
"aud",
|
||||
"auth_time",
|
||||
"azp",
|
||||
"cnf",
|
||||
"c_hash",
|
||||
"exp",
|
||||
"iat",
|
||||
"iss",
|
||||
"jti",
|
||||
"nbf",
|
||||
"nonce",
|
||||
"firebase",
|
||||
];
|
||||
const CLAIMS_MAX_PAYLOAD_SIZE = 1000;
|
||||
const EVENT_MAPPING = {
|
||||
beforeCreate: "providers/cloud.auth/eventTypes/user.beforeCreate",
|
||||
beforeSignIn: "providers/cloud.auth/eventTypes/user.beforeSignIn",
|
||||
beforeSendEmail: "providers/cloud.auth/eventTypes/user.beforeSendEmail",
|
||||
beforeSendSms: "providers/cloud.auth/eventTypes/user.beforeSendSms",
|
||||
};
|
||||
/**
|
||||
* Helper class to create the user metadata in a `UserRecord` object.
|
||||
*/
|
||||
class UserRecordMetadata {
|
||||
constructor(creationTime, lastSignInTime) {
|
||||
this.creationTime = creationTime;
|
||||
this.lastSignInTime = lastSignInTime;
|
||||
}
|
||||
/** Returns a plain JavaScript object with the properties of UserRecordMetadata. */
|
||||
toJSON() {
|
||||
return {
|
||||
creationTime: this.creationTime,
|
||||
lastSignInTime: this.lastSignInTime,
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.UserRecordMetadata = UserRecordMetadata;
|
||||
/**
|
||||
* Helper function that creates a `UserRecord` class from data sent over the wire.
|
||||
* @param wireData data sent over the wire
|
||||
* @returns an instance of `UserRecord` with correct toJSON functions
|
||||
*/
|
||||
function userRecordConstructor(wireData) {
|
||||
// Falsey values from the wire format proto get lost when converted to JSON, this adds them back.
|
||||
const falseyValues = {
|
||||
email: null,
|
||||
emailVerified: false,
|
||||
displayName: null,
|
||||
photoURL: null,
|
||||
phoneNumber: null,
|
||||
disabled: false,
|
||||
providerData: [],
|
||||
customClaims: {},
|
||||
passwordSalt: null,
|
||||
passwordHash: null,
|
||||
tokensValidAfterTime: null,
|
||||
};
|
||||
const record = { ...falseyValues, ...wireData };
|
||||
const meta = record.metadata;
|
||||
if (meta) {
|
||||
record.metadata = new UserRecordMetadata(meta.createdAt || meta.creationTime, meta.lastSignedInAt || meta.lastSignInTime);
|
||||
}
|
||||
else {
|
||||
record.metadata = new UserRecordMetadata(null, null);
|
||||
}
|
||||
record.toJSON = () => {
|
||||
const { uid, email, emailVerified, displayName, photoURL, phoneNumber, disabled, passwordHash, passwordSalt, tokensValidAfterTime, } = record;
|
||||
const json = {
|
||||
uid,
|
||||
email,
|
||||
emailVerified,
|
||||
displayName,
|
||||
photoURL,
|
||||
phoneNumber,
|
||||
disabled,
|
||||
passwordHash,
|
||||
passwordSalt,
|
||||
tokensValidAfterTime,
|
||||
};
|
||||
json.metadata = record.metadata.toJSON();
|
||||
json.customClaims = JSON.parse(JSON.stringify(record.customClaims));
|
||||
json.providerData = record.providerData.map((entry) => {
|
||||
const newEntry = { ...entry };
|
||||
newEntry.toJSON = () => entry;
|
||||
return newEntry;
|
||||
});
|
||||
return json;
|
||||
};
|
||||
return record;
|
||||
}
|
||||
exports.userRecordConstructor = userRecordConstructor;
|
||||
/**
|
||||
* Checks for a valid identity platform web request, otherwise throws an HttpsError.
|
||||
* @internal
|
||||
*/
|
||||
function isValidRequest(req) {
|
||||
var _a, _b;
|
||||
if (req.method !== "POST") {
|
||||
logger.warn(`Request has invalid method "${req.method}".`);
|
||||
return false;
|
||||
}
|
||||
const contentType = (req.header("Content-Type") || "").toLowerCase();
|
||||
if (!contentType.includes("application/json")) {
|
||||
logger.warn("Request has invalid header Content-Type.");
|
||||
return false;
|
||||
}
|
||||
if (!((_b = (_a = req.body) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.jwt)) {
|
||||
logger.warn("Request has an invalid body.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.isValidRequest = isValidRequest;
|
||||
/**
|
||||
* Decode, but not verify, an Auth Blocking token.
|
||||
*
|
||||
* Do not use in production. Token should always be verified using the Admin SDK.
|
||||
*
|
||||
* This is exposed only for testing.
|
||||
*/
|
||||
function unsafeDecodeAuthBlockingToken(token) {
|
||||
const decoded = (0, https_1.unsafeDecodeToken)(token);
|
||||
decoded.uid = decoded.sub;
|
||||
return decoded;
|
||||
}
|
||||
/**
|
||||
* Helper function to parse the decoded metadata object into a `UserMetaData` object
|
||||
* @internal
|
||||
*/
|
||||
function parseMetadata(metadata) {
|
||||
const creationTime = (metadata === null || metadata === void 0 ? void 0 : metadata.creation_time)
|
||||
? new Date(metadata.creation_time).toUTCString()
|
||||
: null;
|
||||
const lastSignInTime = (metadata === null || metadata === void 0 ? void 0 : metadata.last_sign_in_time)
|
||||
? new Date(metadata.last_sign_in_time).toUTCString()
|
||||
: null;
|
||||
return {
|
||||
creationTime,
|
||||
lastSignInTime,
|
||||
};
|
||||
}
|
||||
exports.parseMetadata = parseMetadata;
|
||||
/**
|
||||
* Helper function to parse the decoded user info array into an `AuthUserInfo` array.
|
||||
* @internal
|
||||
*/
|
||||
function parseProviderData(providerData) {
|
||||
const providers = [];
|
||||
for (const provider of providerData) {
|
||||
providers.push({
|
||||
uid: provider.uid,
|
||||
displayName: provider.display_name,
|
||||
email: provider.email,
|
||||
photoURL: provider.photo_url,
|
||||
providerId: provider.provider_id,
|
||||
phoneNumber: provider.phone_number,
|
||||
});
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
exports.parseProviderData = parseProviderData;
|
||||
/**
|
||||
* Helper function to parse the date into a UTC string.
|
||||
* @internal
|
||||
*/
|
||||
function parseDate(tokensValidAfterTime) {
|
||||
if (!tokensValidAfterTime) {
|
||||
return null;
|
||||
}
|
||||
tokensValidAfterTime = tokensValidAfterTime * 1000;
|
||||
try {
|
||||
const date = new Date(tokensValidAfterTime);
|
||||
if (!isNaN(date.getTime())) {
|
||||
return date.toUTCString();
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// ignore error
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.parseDate = parseDate;
|
||||
/**
|
||||
* Helper function to parse the decoded enrolled factors into a valid MultiFactorSettings
|
||||
* @internal
|
||||
*/
|
||||
function parseMultiFactor(multiFactor) {
|
||||
if (!multiFactor) {
|
||||
return null;
|
||||
}
|
||||
const parsedEnrolledFactors = [];
|
||||
for (const factor of multiFactor.enrolled_factors || []) {
|
||||
if (!factor.uid) {
|
||||
throw new https_1.HttpsError("internal", "INTERNAL ASSERT FAILED: Invalid multi-factor info response");
|
||||
}
|
||||
const enrollmentTime = factor.enrollment_time
|
||||
? new Date(factor.enrollment_time).toUTCString()
|
||||
: null;
|
||||
parsedEnrolledFactors.push({
|
||||
uid: factor.uid,
|
||||
factorId: factor.phone_number ? factor.factor_id || "phone" : factor.factor_id,
|
||||
displayName: factor.display_name,
|
||||
enrollmentTime,
|
||||
phoneNumber: factor.phone_number,
|
||||
});
|
||||
}
|
||||
if (parsedEnrolledFactors.length > 0) {
|
||||
return {
|
||||
enrolledFactors: parsedEnrolledFactors,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.parseMultiFactor = parseMultiFactor;
|
||||
/**
|
||||
* Parses the decoded user record into a valid UserRecord for use in the handler
|
||||
* @internal
|
||||
*/
|
||||
function parseAuthUserRecord(decodedJWTUserRecord) {
|
||||
if (!decodedJWTUserRecord.uid) {
|
||||
throw new https_1.HttpsError("internal", "INTERNAL ASSERT FAILED: Invalid user response");
|
||||
}
|
||||
const disabled = decodedJWTUserRecord.disabled || false;
|
||||
const metadata = parseMetadata(decodedJWTUserRecord.metadata);
|
||||
const providerData = parseProviderData(decodedJWTUserRecord.provider_data);
|
||||
const tokensValidAfterTime = parseDate(decodedJWTUserRecord.tokens_valid_after_time);
|
||||
const multiFactor = parseMultiFactor(decodedJWTUserRecord.multi_factor);
|
||||
return {
|
||||
uid: decodedJWTUserRecord.uid,
|
||||
email: decodedJWTUserRecord.email,
|
||||
emailVerified: decodedJWTUserRecord.email_verified,
|
||||
displayName: decodedJWTUserRecord.display_name,
|
||||
photoURL: decodedJWTUserRecord.photo_url,
|
||||
phoneNumber: decodedJWTUserRecord.phone_number,
|
||||
disabled,
|
||||
metadata,
|
||||
providerData,
|
||||
passwordHash: decodedJWTUserRecord.password_hash,
|
||||
passwordSalt: decodedJWTUserRecord.password_salt,
|
||||
customClaims: decodedJWTUserRecord.custom_claims,
|
||||
tenantId: decodedJWTUserRecord.tenant_id,
|
||||
tokensValidAfterTime,
|
||||
multiFactor,
|
||||
};
|
||||
}
|
||||
exports.parseAuthUserRecord = parseAuthUserRecord;
|
||||
/** Helper to get the `AdditionalUserInfo` from the decoded JWT */
|
||||
function parseAdditionalUserInfo(decodedJWT) {
|
||||
let profile;
|
||||
let username;
|
||||
if (decodedJWT.raw_user_info) {
|
||||
try {
|
||||
profile = JSON.parse(decodedJWT.raw_user_info);
|
||||
}
|
||||
catch (err) {
|
||||
logger.debug(`Parse Error: ${err.message}`);
|
||||
}
|
||||
}
|
||||
if (profile) {
|
||||
if (decodedJWT.sign_in_method === "github.com") {
|
||||
username = profile.login;
|
||||
}
|
||||
if (decodedJWT.sign_in_method === "twitter.com") {
|
||||
username = profile.screen_name;
|
||||
}
|
||||
}
|
||||
return {
|
||||
providerId: decodedJWT.sign_in_method === "emailLink" ? "password" : decodedJWT.sign_in_method,
|
||||
profile,
|
||||
username,
|
||||
isNewUser: decodedJWT.event_type === "beforeCreate" ? true : false,
|
||||
recaptchaScore: decodedJWT.recaptcha_score,
|
||||
email: decodedJWT.email,
|
||||
phoneNumber: decodedJWT.phone_number,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Helper to generate a response from the blocking function to the Firebase Auth backend.
|
||||
* @internal
|
||||
*/
|
||||
function generateResponsePayload(authResponse) {
|
||||
if (!authResponse) {
|
||||
return {};
|
||||
}
|
||||
const { recaptchaActionOverride, ...formattedAuthResponse } = authResponse;
|
||||
const result = {};
|
||||
const updateMask = getUpdateMask(formattedAuthResponse);
|
||||
if (updateMask.length !== 0) {
|
||||
result.userRecord = {
|
||||
...formattedAuthResponse,
|
||||
updateMask,
|
||||
};
|
||||
}
|
||||
if (recaptchaActionOverride !== undefined) {
|
||||
result.recaptchaActionOverride = recaptchaActionOverride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.generateResponsePayload = generateResponsePayload;
|
||||
/** Helper to get the Credential from the decoded JWT */
|
||||
function parseAuthCredential(decodedJWT, time) {
|
||||
if (!decodedJWT.sign_in_attributes &&
|
||||
!decodedJWT.oauth_id_token &&
|
||||
!decodedJWT.oauth_access_token &&
|
||||
!decodedJWT.oauth_refresh_token) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
claims: decodedJWT.sign_in_attributes,
|
||||
idToken: decodedJWT.oauth_id_token,
|
||||
accessToken: decodedJWT.oauth_access_token,
|
||||
refreshToken: decodedJWT.oauth_refresh_token,
|
||||
expirationTime: decodedJWT.oauth_expires_in
|
||||
? new Date(time + decodedJWT.oauth_expires_in * 1000).toUTCString()
|
||||
: undefined,
|
||||
secret: decodedJWT.oauth_token_secret,
|
||||
providerId: decodedJWT.sign_in_method === "emailLink" ? "password" : decodedJWT.sign_in_method,
|
||||
signInMethod: decodedJWT.sign_in_method,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Parses the decoded jwt into a valid AuthEventContext for use in the handler
|
||||
* @internal
|
||||
*/
|
||||
function parseAuthEventContext(decodedJWT, projectId, time = new Date().getTime()) {
|
||||
const eventType = (EVENT_MAPPING[decodedJWT.event_type] || decodedJWT.event_type) +
|
||||
(decodedJWT.sign_in_method ? `:${decodedJWT.sign_in_method}` : "");
|
||||
return {
|
||||
locale: decodedJWT.locale,
|
||||
ipAddress: decodedJWT.ip_address,
|
||||
userAgent: decodedJWT.user_agent,
|
||||
eventId: decodedJWT.event_id,
|
||||
eventType,
|
||||
authType: decodedJWT.user_record ? "USER" : "UNAUTHENTICATED",
|
||||
resource: {
|
||||
// TODO(colerogers): figure out the correct service
|
||||
service: "identitytoolkit.googleapis.com",
|
||||
name: decodedJWT.tenant_id
|
||||
? `projects/${projectId}/tenants/${decodedJWT.tenant_id}`
|
||||
: `projects/${projectId}`,
|
||||
},
|
||||
timestamp: new Date(decodedJWT.iat * 1000).toUTCString(),
|
||||
additionalUserInfo: parseAdditionalUserInfo(decodedJWT),
|
||||
credential: parseAuthCredential(decodedJWT, time),
|
||||
emailType: decodedJWT.email_type,
|
||||
smsType: decodedJWT.sms_type,
|
||||
params: {},
|
||||
};
|
||||
}
|
||||
exports.parseAuthEventContext = parseAuthEventContext;
|
||||
/**
|
||||
* Checks the handler response for invalid customClaims & sessionClaims objects
|
||||
* @internal
|
||||
*/
|
||||
function validateAuthResponse(eventType, authRequest) {
|
||||
if (!authRequest) {
|
||||
authRequest = {};
|
||||
}
|
||||
if (authRequest.customClaims) {
|
||||
const invalidClaims = DISALLOWED_CUSTOM_CLAIMS.filter((claim) => authRequest.customClaims.hasOwnProperty(claim));
|
||||
if (invalidClaims.length > 0) {
|
||||
throw new https_1.HttpsError("invalid-argument", `The customClaims claims "${invalidClaims.join(",")}" are reserved and cannot be specified.`);
|
||||
}
|
||||
if (JSON.stringify(authRequest.customClaims).length > CLAIMS_MAX_PAYLOAD_SIZE) {
|
||||
throw new https_1.HttpsError("invalid-argument", `The customClaims payload should not exceed ${CLAIMS_MAX_PAYLOAD_SIZE} characters.`);
|
||||
}
|
||||
}
|
||||
if (eventType === "beforeSignIn" && authRequest.sessionClaims) {
|
||||
const invalidClaims = DISALLOWED_CUSTOM_CLAIMS.filter((claim) => authRequest.sessionClaims.hasOwnProperty(claim));
|
||||
if (invalidClaims.length > 0) {
|
||||
throw new https_1.HttpsError("invalid-argument", `The sessionClaims claims "${invalidClaims.join(",")}" are reserved and cannot be specified.`);
|
||||
}
|
||||
if (JSON.stringify(authRequest.sessionClaims).length >
|
||||
CLAIMS_MAX_PAYLOAD_SIZE) {
|
||||
throw new https_1.HttpsError("invalid-argument", `The sessionClaims payload should not exceed ${CLAIMS_MAX_PAYLOAD_SIZE} characters.`);
|
||||
}
|
||||
const combinedClaims = {
|
||||
...authRequest.customClaims,
|
||||
...authRequest.sessionClaims,
|
||||
};
|
||||
if (JSON.stringify(combinedClaims).length > CLAIMS_MAX_PAYLOAD_SIZE) {
|
||||
throw new https_1.HttpsError("invalid-argument", `The customClaims and sessionClaims payloads should not exceed ${CLAIMS_MAX_PAYLOAD_SIZE} characters combined.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.validateAuthResponse = validateAuthResponse;
|
||||
/**
|
||||
* Helper function to generate the update mask for the identity platform changed values
|
||||
* @internal
|
||||
*/
|
||||
function getUpdateMask(authResponse) {
|
||||
if (!authResponse) {
|
||||
return "";
|
||||
}
|
||||
const updateMask = [];
|
||||
for (const key in authResponse) {
|
||||
if (authResponse.hasOwnProperty(key) && typeof authResponse[key] !== "undefined") {
|
||||
updateMask.push(key);
|
||||
}
|
||||
}
|
||||
return updateMask.join(",");
|
||||
}
|
||||
exports.getUpdateMask = getUpdateMask;
|
||||
/** @internal */
|
||||
function wrapHandler(eventType, handler) {
|
||||
return async (req, res) => {
|
||||
try {
|
||||
const projectId = process.env.GCLOUD_PROJECT;
|
||||
if (!isValidRequest(req)) {
|
||||
logger.error("Invalid request, unable to process");
|
||||
throw new https_1.HttpsError("invalid-argument", "Bad Request");
|
||||
}
|
||||
if (!auth.getAuth((0, app_1.getApp)())._verifyAuthBlockingToken) {
|
||||
throw new Error("Cannot validate Auth Blocking token. Please update Firebase Admin SDK to >= v10.1.0");
|
||||
}
|
||||
const decodedPayload = (0, debug_1.isDebugFeatureEnabled)("skipTokenVerification")
|
||||
? unsafeDecodeAuthBlockingToken(req.body.data.jwt)
|
||||
: handler.platform === "gcfv1"
|
||||
? await auth.getAuth((0, app_1.getApp)())._verifyAuthBlockingToken(req.body.data.jwt)
|
||||
: await auth.getAuth((0, app_1.getApp)())._verifyAuthBlockingToken(req.body.data.jwt, "run.app");
|
||||
let authUserRecord;
|
||||
if (decodedPayload.event_type === "beforeCreate" ||
|
||||
decodedPayload.event_type === "beforeSignIn") {
|
||||
authUserRecord = parseAuthUserRecord(decodedPayload.user_record);
|
||||
}
|
||||
const authEventContext = parseAuthEventContext(decodedPayload, projectId);
|
||||
let authResponse;
|
||||
if (handler.platform === "gcfv1") {
|
||||
authResponse = authUserRecord
|
||||
? (await handler(authUserRecord, authEventContext)) || undefined
|
||||
: (await handler(authEventContext)) || undefined;
|
||||
}
|
||||
else {
|
||||
authResponse =
|
||||
(await handler({
|
||||
...authEventContext,
|
||||
data: authUserRecord,
|
||||
})) || undefined;
|
||||
}
|
||||
validateAuthResponse(eventType, authResponse);
|
||||
const result = generateResponsePayload(authResponse);
|
||||
res.status(200);
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.send(JSON.stringify(result));
|
||||
}
|
||||
catch (err) {
|
||||
let httpErr = err;
|
||||
if (!(httpErr instanceof https_1.HttpsError)) {
|
||||
// This doesn't count as an 'explicit' error.
|
||||
logger.error("Unhandled error", err);
|
||||
httpErr = new https_1.HttpsError("internal", "An unexpected error occurred.");
|
||||
}
|
||||
const { status } = httpErr.httpErrorCode;
|
||||
const body = { error: httpErr.toJSON() };
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.status(status).send(body);
|
||||
}
|
||||
};
|
||||
}
|
||||
exports.wrapHandler = wrapHandler;
|
||||
112
node_modules/firebase-functions/lib/common/providers/tasks.d.ts
generated
vendored
Normal file
112
node_modules/firebase-functions/lib/common/providers/tasks.d.ts
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
import { DecodedIdToken } from "firebase-admin/auth";
|
||||
import { Expression } from "../../params";
|
||||
import { ResetValue } from "../options";
|
||||
/** How a task should be retried in the event of a non-2xx return. */
|
||||
export interface RetryConfig {
|
||||
/**
|
||||
* Maximum number of times a request should be attempted.
|
||||
* If left unspecified, will default to 3.
|
||||
*/
|
||||
maxAttempts?: number | Expression<number> | ResetValue;
|
||||
/**
|
||||
* Maximum amount of time for retrying failed task.
|
||||
* If left unspecified will retry indefinitely.
|
||||
*/
|
||||
maxRetrySeconds?: number | Expression<number> | ResetValue;
|
||||
/**
|
||||
* The maximum amount of time to wait between attempts.
|
||||
* If left unspecified will default to 1hr.
|
||||
*/
|
||||
maxBackoffSeconds?: number | Expression<number> | ResetValue;
|
||||
/**
|
||||
* The maximum number of times to double the backoff between
|
||||
* retries. If left unspecified will default to 16.
|
||||
*/
|
||||
maxDoublings?: number | Expression<number> | ResetValue;
|
||||
/**
|
||||
* The minimum time to wait between attempts. If left unspecified
|
||||
* will default to 100ms.
|
||||
*/
|
||||
minBackoffSeconds?: number | Expression<number> | ResetValue;
|
||||
}
|
||||
/** How congestion control should be applied to the function. */
|
||||
export interface RateLimits {
|
||||
/**
|
||||
* The maximum number of requests that can be processed at a time.
|
||||
* If left unspecified, will default to 1000.
|
||||
*/
|
||||
maxConcurrentDispatches?: number | Expression<number> | ResetValue;
|
||||
/**
|
||||
* The maximum number of requests that can be invoked per second.
|
||||
* If left unspecified, will default to 500.
|
||||
*/
|
||||
maxDispatchesPerSecond?: number | Expression<number> | ResetValue;
|
||||
}
|
||||
/** Metadata about the authorization used to invoke a function. */
|
||||
export interface AuthData {
|
||||
uid: string;
|
||||
token: DecodedIdToken;
|
||||
}
|
||||
/** Metadata about a call to a Task Queue function. */
|
||||
export interface TaskContext {
|
||||
/**
|
||||
* The result of decoding and verifying an ODIC token.
|
||||
*/
|
||||
auth?: AuthData;
|
||||
/**
|
||||
* The name of the queue.
|
||||
* Populated via the `X-CloudTasks-QueueName` header.
|
||||
*/
|
||||
queueName: string;
|
||||
/**
|
||||
* The "short" name of the task, or, if no name was specified at creation, a unique
|
||||
* system-generated id.
|
||||
* This is the "my-task-id" value in the complete task name, such as "task_name =
|
||||
* projects/my-project-id/locations/my-location/queues/my-queue-id/tasks/my-task-id."
|
||||
* Populated via the `X-CloudTasks-TaskName` header.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The number of times this task has been retried.
|
||||
* For the first attempt, this value is 0. This number includes attempts where the task failed
|
||||
* due to 5XX error codes and never reached the execution phase.
|
||||
* Populated via the `X-CloudTasks-TaskRetryCount` header.
|
||||
*/
|
||||
retryCount: number;
|
||||
/**
|
||||
* The total number of times that the task has received a response from the handler.
|
||||
* Since Cloud Tasks deletes the task once a successful response has been received, all
|
||||
* previous handler responses were failures. This number does not include failures due to 5XX
|
||||
* error codes.
|
||||
* Populated via the `X-CloudTasks-TaskExecutionCount` header.
|
||||
*/
|
||||
executionCount: number;
|
||||
/**
|
||||
* The schedule time of the task, as an RFC 3339 string in UTC time zone.
|
||||
* Populated via the `X-CloudTasks-TaskETA` header, which uses seconds since January 1 1970.
|
||||
*/
|
||||
scheduledTime: string;
|
||||
/**
|
||||
* The HTTP response code from the previous retry.
|
||||
* Populated via the `X-CloudTasks-TaskPreviousResponse` header
|
||||
*/
|
||||
previousResponse?: number;
|
||||
/**
|
||||
* The reason for retrying the task.
|
||||
* Populated via the `X-CloudTasks-TaskRetryReason` header.
|
||||
*/
|
||||
retryReason?: string;
|
||||
/**
|
||||
* Raw request headers.
|
||||
*/
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
/**
|
||||
* The request used to call a task queue function.
|
||||
*/
|
||||
export type Request<T = any> = TaskContext & {
|
||||
/**
|
||||
* The parameters used by a client when calling this function.
|
||||
*/
|
||||
data: T;
|
||||
};
|
||||
100
node_modules/firebase-functions/lib/common/providers/tasks.js
generated
vendored
Normal file
100
node_modules/firebase-functions/lib/common/providers/tasks.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.onDispatchHandler = void 0;
|
||||
const logger = require("../../logger");
|
||||
const https = require("./https");
|
||||
/** @internal */
|
||||
function onDispatchHandler(handler) {
|
||||
return async (req, res) => {
|
||||
var _a;
|
||||
try {
|
||||
if (!https.isValidRequest(req)) {
|
||||
logger.error("Invalid request, unable to process.");
|
||||
throw new https.HttpsError("invalid-argument", "Bad Request");
|
||||
}
|
||||
const headers = {};
|
||||
for (const [key, value] of Object.entries(req.headers)) {
|
||||
if (!Array.isArray(value)) {
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
const context = {
|
||||
queueName: req.header("X-CloudTasks-QueueName"),
|
||||
id: req.header("X-CloudTasks-TaskName"),
|
||||
retryCount: req.header("X-CloudTasks-TaskRetryCount")
|
||||
? Number(req.header("X-CloudTasks-TaskRetryCount"))
|
||||
: undefined,
|
||||
executionCount: req.header("X-CloudTasks-TaskExecutionCount")
|
||||
? Number(req.header("X-CloudTasks-TaskExecutionCount"))
|
||||
: undefined,
|
||||
scheduledTime: req.header("X-CloudTasks-TaskETA"),
|
||||
previousResponse: req.header("X-CloudTasks-TaskPreviousResponse")
|
||||
? Number(req.header("X-CloudTasks-TaskPreviousResponse"))
|
||||
: undefined,
|
||||
retryReason: req.header("X-CloudTasks-TaskRetryReason"),
|
||||
headers,
|
||||
};
|
||||
if (!process.env.FUNCTIONS_EMULATOR) {
|
||||
const authHeader = req.header("Authorization") || "";
|
||||
const token = (_a = authHeader.match(/^Bearer (.*)$/)) === null || _a === void 0 ? void 0 : _a[1];
|
||||
// Note: this should never happen since task queue functions are guarded by IAM.
|
||||
if (!token) {
|
||||
throw new https.HttpsError("unauthenticated", "Unauthenticated");
|
||||
}
|
||||
// We skip authenticating the token since tq functions are guarded by IAM.
|
||||
const authToken = https.unsafeDecodeIdToken(token);
|
||||
context.auth = {
|
||||
uid: authToken.uid,
|
||||
token: authToken,
|
||||
};
|
||||
}
|
||||
const data = https.decode(req.body.data);
|
||||
if (handler.length === 2) {
|
||||
await handler(data, context);
|
||||
}
|
||||
else {
|
||||
const arg = {
|
||||
...context,
|
||||
data,
|
||||
};
|
||||
// For some reason the type system isn't picking up that the handler
|
||||
// is a one argument function.
|
||||
await handler(arg);
|
||||
}
|
||||
res.status(204).end();
|
||||
}
|
||||
catch (err) {
|
||||
let httpErr = err;
|
||||
if (!(err instanceof https.HttpsError)) {
|
||||
// This doesn't count as an 'explicit' error.
|
||||
logger.error("Unhandled error", err);
|
||||
httpErr = new https.HttpsError("internal", "INTERNAL");
|
||||
}
|
||||
const { status } = httpErr.httpErrorCode;
|
||||
const body = { error: httpErr.toJSON() };
|
||||
res.status(status).send(body);
|
||||
}
|
||||
};
|
||||
}
|
||||
exports.onDispatchHandler = onDispatchHandler;
|
||||
2
node_modules/firebase-functions/lib/common/timezone.d.ts
generated
vendored
Normal file
2
node_modules/firebase-functions/lib/common/timezone.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const tzDatabase: Record<string, string>;
|
||||
export type timezone = keyof typeof tzDatabase;
|
||||
543
node_modules/firebase-functions/lib/common/timezone.js
generated
vendored
Normal file
543
node_modules/firebase-functions/lib/common/timezone.js
generated
vendored
Normal file
@@ -0,0 +1,543 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.tzDatabase = void 0;
|
||||
exports.tzDatabase = {
|
||||
"Africa/Abidjan": "+00:00",
|
||||
"Africa/Accra": "+00:00",
|
||||
"Africa/Addis_Ababa": "+03:00",
|
||||
"Africa/Algiers": "+01:00",
|
||||
"Africa/Asmara": "+03:00",
|
||||
"Africa/Asmera": "+03:00",
|
||||
"Africa/Bamako": "+00:00",
|
||||
"Africa/Bangui": "+01:00",
|
||||
"Africa/Banjul": "+00:00",
|
||||
"Africa/Blantyre": "+02:00",
|
||||
"Africa/Brazzaville": "+01:00",
|
||||
"Africa/Bujumbura": "+02:00",
|
||||
"Africa/Cairo": "+02:00",
|
||||
"Africa/Casablanca": "+00:00",
|
||||
"Africa/Ceuta": "+01:00",
|
||||
"Africa/Conakry": "+00:00",
|
||||
"Africa/Dakar": "+00:00",
|
||||
"Africa/Dar_es_Salaam": "+03:00",
|
||||
"Africa/Djibouti": "+03:00",
|
||||
"Africa/Douala": "+01:00",
|
||||
"Africa/El_Aaiun": "+00:00",
|
||||
"Africa/Freetown": "+00:00",
|
||||
"Africa/Gaborone": "+02:00",
|
||||
"Africa/Harare": "+02:00",
|
||||
"Africa/Johannesburg": "+02:00",
|
||||
"Africa/Juba": "+03:00",
|
||||
"Africa/Kampala": "+03:00",
|
||||
"Africa/Khartoum": "+03:00",
|
||||
"Africa/Kigali": "+02:00",
|
||||
"Africa/Kinshasa": "+01:00",
|
||||
"Africa/Lagos": "+01:00",
|
||||
"Africa/Libreville": "+01:00",
|
||||
"Africa/Lome": "+00:00",
|
||||
"Africa/Luanda": "+01:00",
|
||||
"Africa/Lubumbashi": "+02:00",
|
||||
"Africa/Lusaka": "+02:00",
|
||||
"Africa/Malabo": "+01:00",
|
||||
"Africa/Maputo": "+02:00",
|
||||
"Africa/Maseru": "+02:00",
|
||||
"Africa/Mbabane": "+02:00",
|
||||
"Africa/Mogadishu": "+03:00",
|
||||
"Africa/Monrovia": "+00:00",
|
||||
"Africa/Nairobi": "+03:00",
|
||||
"Africa/Ndjamena": "+01:00",
|
||||
"Africa/Niamey": "+01:00",
|
||||
"Africa/Nouakchott": "+00:00",
|
||||
"Africa/Ouagadougou": "+00:00",
|
||||
"Africa/Porto-Novo": "+01:00",
|
||||
"Africa/Sao_Tome": "+00:00",
|
||||
"Africa/Timbuktu": "+00:00",
|
||||
"Africa/Tripoli": "+02:00",
|
||||
"Africa/Tunis": "+01:00",
|
||||
"Africa/Windhoek": "+01:00",
|
||||
"America/Adak": "-10:00",
|
||||
"America/Anchorage": "-09:00",
|
||||
"America/Anguilla": "-04:00",
|
||||
"America/Antigua": "-04:00",
|
||||
"America/Araguaina": "-03:00",
|
||||
"America/Argentina/Buenos_Aires": "-03:00",
|
||||
"America/Argentina/Catamarca": "-03:00",
|
||||
"America/Argentina/ComodRivadavia": "-03:00",
|
||||
"America/Argentina/Cordoba": "-03:00",
|
||||
"America/Argentina/Jujuy": "-03:00",
|
||||
"America/Argentina/La_Rioja": "-03:00",
|
||||
"America/Argentina/Mendoza": "-03:00",
|
||||
"America/Argentina/Rio_Gallegos": "-03:00",
|
||||
"America/Argentina/Salta": "-03:00",
|
||||
"America/Argentina/San_Juan": "-03:00",
|
||||
"America/Argentina/San_Luis": "-03:00",
|
||||
"America/Argentina/Tucuman": "-03:00",
|
||||
"America/Argentina/Ushuaia": "-03:00",
|
||||
"America/Aruba": "-04:00",
|
||||
"America/Asuncion": "-04:00",
|
||||
"America/Atikokan": "-05:00",
|
||||
"America/Atka": "-10:00",
|
||||
"America/Bahia": "-03:00",
|
||||
"America/Bahia_Banderas": "-06:00",
|
||||
"America/Barbados": "-04:00",
|
||||
"America/Belem": "-03:00",
|
||||
"America/Belize": "-06:00",
|
||||
"America/Blanc-Sablon": "-04:00",
|
||||
"America/Boa_Vista": "-04:00",
|
||||
"America/Bogota": "-05:00",
|
||||
"America/Boise": "-07:00",
|
||||
"America/Buenos_Aires": "-03:00",
|
||||
"America/Cambridge_Bay": "-07:00",
|
||||
"America/Campo_Grande": "-04:00",
|
||||
"America/Cancun": "-06:00",
|
||||
"America/Caracas": "-04:30",
|
||||
"America/Catamarca": "-03:00",
|
||||
"America/Cayenne": "-03:00",
|
||||
"America/Cayman": "-05:00",
|
||||
"America/Chicago": "-06:00",
|
||||
"America/Chihuahua": "-07:00",
|
||||
"America/Coral_Harbour": "-05:00",
|
||||
"America/Cordoba": "-03:00",
|
||||
"America/Costa_Rica": "-06:00",
|
||||
"America/Creston": "-07:00",
|
||||
"America/Cuiaba": "-04:00",
|
||||
"America/Curacao": "-04:00",
|
||||
"America/Danmarkshavn": "+00:00",
|
||||
"America/Dawson": "-08:00",
|
||||
"America/Dawson_Creek": "-07:00",
|
||||
"America/Denver": "-07:00",
|
||||
"America/Detroit": "-05:00",
|
||||
"America/Dominica": "-04:00",
|
||||
"America/Edmonton": "-07:00",
|
||||
"America/Eirunepe": "-05:00",
|
||||
"America/El_Salvador": "-06:00",
|
||||
"America/Ensenada": "-08:00",
|
||||
"America/Fort_Wayne": "-05:00",
|
||||
"America/Fortaleza": "-03:00",
|
||||
"America/Glace_Bay": "-04:00",
|
||||
"America/Godthab": "-03:00",
|
||||
"America/Goose_Bay": "-04:00",
|
||||
"America/Grand_Turk": "-05:00",
|
||||
"America/Grenada": "-04:00",
|
||||
"America/Guadeloupe": "-04:00",
|
||||
"America/Guatemala": "-06:00",
|
||||
"America/Guayaquil": "-05:00",
|
||||
"America/Guyana": "-04:00",
|
||||
"America/Halifax": "-04:00",
|
||||
"America/Havana": "-05:00",
|
||||
"America/Hermosillo": "-07:00",
|
||||
"America/Indiana/Indianapolis": "-05:00",
|
||||
"America/Indiana/Knox": "-06:00",
|
||||
"America/Indiana/Marengo": "-05:00",
|
||||
"America/Indiana/Petersburg": "-05:00",
|
||||
"America/Indiana/Tell_City": "-06:00",
|
||||
"America/Indiana/Valparaiso": "-06:00",
|
||||
"America/Indiana/Vevay": "-05:00",
|
||||
"America/Indiana/Vincennes": "-05:00",
|
||||
"America/Indiana/Winamac": "-05:00",
|
||||
"America/Indianapolis": "-05:00",
|
||||
"America/Inuvik": "-07:00",
|
||||
"America/Iqaluit": "-05:00",
|
||||
"America/Jamaica": "-05:00",
|
||||
"America/Jujuy": "-03:00",
|
||||
"America/Juneau": "-09:00",
|
||||
"America/Kentucky/Louisville": "-05:00",
|
||||
"America/Kentucky/Monticello": "-05:00",
|
||||
"America/Knox_IN": "-06:00",
|
||||
"America/Kralendijk": "-04:00",
|
||||
"America/La_Paz": "-04:00",
|
||||
"America/Lima": "-05:00",
|
||||
"America/Los_Angeles": "-08:00",
|
||||
"America/Louisville": "-05:00",
|
||||
"America/Lower_Princes": "-04:00",
|
||||
"America/Maceio": "-03:00",
|
||||
"America/Managua": "-06:00",
|
||||
"America/Manaus": "-04:00",
|
||||
"America/Marigot": "-04:00",
|
||||
"America/Martinique": "-04:00",
|
||||
"America/Matamoros": "-06:00",
|
||||
"America/Mazatlan": "-07:00",
|
||||
"America/Mendoza": "-03:00",
|
||||
"America/Menominee": "-06:00",
|
||||
"America/Merida": "-06:00",
|
||||
"America/Metlakatla": "-08:00",
|
||||
"America/Mexico_City": "-06:00",
|
||||
"America/Miquelon": "-03:00",
|
||||
"America/Moncton": "-04:00",
|
||||
"America/Monterrey": "-06:00",
|
||||
"America/Montevideo": "-03:00",
|
||||
"America/Montreal": "-05:00",
|
||||
"America/Montserrat": "-04:00",
|
||||
"America/Nassau": "-05:00",
|
||||
"America/New_York": "-05:00",
|
||||
"America/Nipigon": "-05:00",
|
||||
"America/Nome": "-09:00",
|
||||
"America/Noronha": "-02:00",
|
||||
"America/North_Dakota/Beulah": "-06:00",
|
||||
"America/North_Dakota/Center": "-06:00",
|
||||
"America/North_Dakota/New_Salem": "-06:00",
|
||||
"America/Ojinaga": "-07:00",
|
||||
"America/Panama": "-05:00",
|
||||
"America/Pangnirtung": "-05:00",
|
||||
"America/Paramaribo": "-03:00",
|
||||
"America/Phoenix": "-07:00",
|
||||
"America/Port_of_Spain": "-04:00",
|
||||
"America/Port-au-Prince": "-05:00",
|
||||
"America/Porto_Acre": "-05:00",
|
||||
"America/Porto_Velho": "-04:00",
|
||||
"America/Puerto_Rico": "-04:00",
|
||||
"America/Rainy_River": "-06:00",
|
||||
"America/Rankin_Inlet": "-06:00",
|
||||
"America/Recife": "-03:00",
|
||||
"America/Regina": "-06:00",
|
||||
"America/Resolute": "-06:00",
|
||||
"America/Rio_Branco": "-05:00",
|
||||
"America/Rosario": "-03:00",
|
||||
"America/Santa_Isabel": "-08:00",
|
||||
"America/Santarem": "-03:00",
|
||||
"America/Santiago": "-03:00",
|
||||
"America/Santo_Domingo": "-04:00",
|
||||
"America/Sao_Paulo": "-03:00",
|
||||
"America/Scoresbysund": "-01:00",
|
||||
"America/Shiprock": "-07:00",
|
||||
"America/Sitka": "-09:00",
|
||||
"America/St_Barthelemy": "-04:00",
|
||||
"America/St_Johns": "-03:30",
|
||||
"America/St_Kitts": "-04:00",
|
||||
"America/St_Lucia": "-04:00",
|
||||
"America/St_Thomas": "-04:00",
|
||||
"America/St_Vincent": "-04:00",
|
||||
"America/Swift_Current": "-06:00",
|
||||
"America/Tegucigalpa": "-06:00",
|
||||
"America/Thule": "-04:00",
|
||||
"America/Thunder_Bay": "-05:00",
|
||||
"America/Tijuana": "-08:00",
|
||||
"America/Toronto": "-05:00",
|
||||
"America/Tortola": "-04:00",
|
||||
"America/Vancouver": "-08:00",
|
||||
"America/Virgin": "-04:00",
|
||||
"America/Whitehorse": "-08:00",
|
||||
"America/Winnipeg": "-06:00",
|
||||
"America/Yakutat": "-09:00",
|
||||
"America/Yellowknife": "-07:00",
|
||||
"Antarctica/Casey": "+11:00",
|
||||
"Antarctica/Davis": "+05:00",
|
||||
"Antarctica/DumontDUrville": "+10:00",
|
||||
"Antarctica/Macquarie": "+11:00",
|
||||
"Antarctica/Mawson": "+05:00",
|
||||
"Antarctica/McMurdo": "+12:00",
|
||||
"Antarctica/Palmer": "-04:00",
|
||||
"Antarctica/Rothera": "-03:00",
|
||||
"Antarctica/South_Pole": "+12:00",
|
||||
"Antarctica/Syowa": "+03:00",
|
||||
"Antarctica/Troll": "+00:00",
|
||||
"Antarctica/Vostok": "+06:00",
|
||||
"Arctic/Longyearbyen": "+01:00",
|
||||
"Asia/Aden": "+03:00",
|
||||
"Asia/Almaty": "+06:00",
|
||||
"Asia/Amman": "+02:00",
|
||||
"Asia/Anadyr": "+12:00",
|
||||
"Asia/Aqtau": "+05:00",
|
||||
"Asia/Aqtobe": "+05:00",
|
||||
"Asia/Ashgabat": "+05:00",
|
||||
"Asia/Ashkhabad": "+05:00",
|
||||
"Asia/Baghdad": "+03:00",
|
||||
"Asia/Bahrain": "+03:00",
|
||||
"Asia/Baku": "+04:00",
|
||||
"Asia/Bangkok": "+07:00",
|
||||
"Asia/Beirut": "+02:00",
|
||||
"Asia/Bishkek": "+06:00",
|
||||
"Asia/Brunei": "+08:00",
|
||||
"Asia/Calcutta": "+05:30",
|
||||
"Asia/Choibalsan": "+08:00",
|
||||
"Asia/Chongqing": "+08:00",
|
||||
"Asia/Chungking": "+08:00",
|
||||
"Asia/Colombo": "+05:30",
|
||||
"Asia/Dacca": "+06:00",
|
||||
"Asia/Damascus": "+02:00",
|
||||
"Asia/Dhaka": "+06:00",
|
||||
"Asia/Dili": "+09:00",
|
||||
"Asia/Dubai": "+04:00",
|
||||
"Asia/Dushanbe": "+05:00",
|
||||
"Asia/Gaza": "+02:00",
|
||||
"Asia/Harbin": "+08:00",
|
||||
"Asia/Hebron": "+02:00",
|
||||
"Asia/Ho_Chi_Minh": "+07:00",
|
||||
"Asia/Hong_Kong": "+08:00",
|
||||
"Asia/Hovd": "+07:00",
|
||||
"Asia/Irkutsk": "+08:00",
|
||||
"Asia/Istanbul": "+02:00",
|
||||
"Asia/Jakarta": "+07:00",
|
||||
"Asia/Jayapura": "+09:00",
|
||||
"Asia/Jerusalem": "+02:00",
|
||||
"Asia/Kabul": "+04:30",
|
||||
"Asia/Kamchatka": "+12:00",
|
||||
"Asia/Karachi": "+05:00",
|
||||
"Asia/Kashgar": "+08:00",
|
||||
"Asia/Kathmandu": "+05:45",
|
||||
"Asia/Katmandu": "+05:45",
|
||||
"Asia/Khandyga": "+09:00",
|
||||
"Asia/Kolkata": "+05:30",
|
||||
"Asia/Krasnoyarsk": "+07:00",
|
||||
"Asia/Kuala_Lumpur": "+08:00",
|
||||
"Asia/Kuching": "+08:00",
|
||||
"Asia/Kuwait": "+03:00",
|
||||
"Asia/Macao": "+08:00",
|
||||
"Asia/Macau": "+08:00",
|
||||
"Asia/Magadan": "+10:00",
|
||||
"Asia/Makassar": "+08:00",
|
||||
"Asia/Manila": "+08:00",
|
||||
"Asia/Muscat": "+04:00",
|
||||
"Asia/Nicosia": "+02:00",
|
||||
"Asia/Novokuznetsk": "+07:00",
|
||||
"Asia/Novosibirsk": "+06:00",
|
||||
"Asia/Omsk": "+06:00",
|
||||
"Asia/Oral": "+05:00",
|
||||
"Asia/Phnom_Penh": "+07:00",
|
||||
"Asia/Pontianak": "+07:00",
|
||||
"Asia/Pyongyang": "+09:00",
|
||||
"Asia/Qatar": "+03:00",
|
||||
"Asia/Qyzylorda": "+06:00",
|
||||
"Asia/Rangoon": "+06:30",
|
||||
"Asia/Riyadh": "+03:00",
|
||||
"Asia/Saigon": "+07:00",
|
||||
"Asia/Sakhalin": "+11:00",
|
||||
"Asia/Samarkand": "+05:00",
|
||||
"Asia/Seoul": "+09:00",
|
||||
"Asia/Shanghai": "+08:00",
|
||||
"Asia/Singapore": "+08:00",
|
||||
"Asia/Taipei": "+08:00",
|
||||
"Asia/Tashkent": "+05:00",
|
||||
"Asia/Tbilisi": "+04:00",
|
||||
"Asia/Tehran": "+03:30",
|
||||
"Asia/Tel_Aviv": "+02:00",
|
||||
"Asia/Thimbu": "+06:00",
|
||||
"Asia/Thimphu": "+06:00",
|
||||
"Asia/Tokyo": "+09:00",
|
||||
"Asia/Ujung_Pandang": "+08:00",
|
||||
"Asia/Ulaanbaatar": "+08:00",
|
||||
"Asia/Ulan_Bator": "+08:00",
|
||||
"Asia/Urumqi": "+08:00",
|
||||
"Asia/Ust-Nera": "+10:00",
|
||||
"Asia/Vientiane": "+07:00",
|
||||
"Asia/Vladivostok": "+10:00",
|
||||
"Asia/Yakutsk": "+09:00",
|
||||
"Asia/Yekaterinburg": "+05:00",
|
||||
"Asia/Yerevan": "+04:00",
|
||||
"Atlantic/Azores": "-01:00",
|
||||
"Atlantic/Bermuda": "-04:00",
|
||||
"Atlantic/Canary": "+00:00",
|
||||
"Atlantic/Cape_Verde": "-01:00",
|
||||
"Atlantic/Faeroe": "+00:00",
|
||||
"Atlantic/Faroe": "+00:00",
|
||||
"Atlantic/Jan_Mayen": "+01:00",
|
||||
"Atlantic/Madeira": "+00:00",
|
||||
"Atlantic/Reykjavik": "+00:00",
|
||||
"Atlantic/South_Georgia": "-02:00",
|
||||
"Atlantic/St_Helena": "+00:00",
|
||||
"Atlantic/Stanley": "-03:00",
|
||||
"Australia/ACT": "+10:00",
|
||||
"Australia/Adelaide": "+09:30",
|
||||
"Australia/Brisbane": "+10:00",
|
||||
"Australia/Broken_Hill": "+09:30",
|
||||
"Australia/Canberra": "+10:00",
|
||||
"Australia/Currie": "+10:00",
|
||||
"Australia/Darwin": "+09:30",
|
||||
"Australia/Eucla": "+08:45",
|
||||
"Australia/Hobart": "+10:00",
|
||||
"Australia/LHI": "+10:30",
|
||||
"Australia/Lindeman": "+10:00",
|
||||
"Australia/Lord_Howe": "+10:30",
|
||||
"Australia/Melbourne": "+10:00",
|
||||
"Australia/North": "+09:30",
|
||||
"Australia/NSW": "+10:00",
|
||||
"Australia/Perth": "+08:00",
|
||||
"Australia/Queensland": "+10:00",
|
||||
"Australia/South": "+09:30",
|
||||
"Australia/Sydney": "+10:00",
|
||||
"Australia/Tasmania": "+10:00",
|
||||
"Australia/Victoria": "+10:00",
|
||||
"Australia/West": "+08:00",
|
||||
"Australia/Yancowinna": "+09:30",
|
||||
"Brazil/Acre": "-05:00",
|
||||
"Brazil/DeNoronha": "-02:00",
|
||||
"Brazil/East": "-03:00",
|
||||
"Brazil/West": "-04:00",
|
||||
"Canada/Atlantic": "-04:00",
|
||||
"Canada/Central": "-06:00",
|
||||
"Canada/Eastern": "-05:00",
|
||||
"Canada/East-Saskatchewan": "-06:00",
|
||||
"Canada/Mountain": "-07:00",
|
||||
"Canada/Newfoundland": "-03:30",
|
||||
"Canada/Pacific": "-08:00",
|
||||
"Canada/Saskatchewan": "-06:00",
|
||||
"Canada/Yukon": "-08:00",
|
||||
"Chile/Continental": "-03:00",
|
||||
"Chile/EasterIsland": "-05:00",
|
||||
Cuba: "-05:00",
|
||||
Egypt: "+02:00",
|
||||
Eire: "+00:00",
|
||||
"Etc/GMT": "+00:00",
|
||||
"Etc/GMT+0": "+00:00",
|
||||
"Etc/UCT": "+00:00",
|
||||
"Etc/Universal": "+00:00",
|
||||
"Etc/UTC": "+00:00",
|
||||
"Etc/Zulu": "+00:00",
|
||||
"Europe/Amsterdam": "+01:00",
|
||||
"Europe/Andorra": "+01:00",
|
||||
"Europe/Athens": "+02:00",
|
||||
"Europe/Belfast": "+00:00",
|
||||
"Europe/Belgrade": "+01:00",
|
||||
"Europe/Berlin": "+01:00",
|
||||
"Europe/Bratislava": "+01:00",
|
||||
"Europe/Brussels": "+01:00",
|
||||
"Europe/Bucharest": "+02:00",
|
||||
"Europe/Budapest": "+01:00",
|
||||
"Europe/Busingen": "+01:00",
|
||||
"Europe/Chisinau": "+02:00",
|
||||
"Europe/Copenhagen": "+01:00",
|
||||
"Europe/Dublin": "+00:00",
|
||||
"Europe/Gibraltar": "+01:00",
|
||||
"Europe/Guernsey": "+00:00",
|
||||
"Europe/Helsinki": "+02:00",
|
||||
"Europe/Isle_of_Man": "+00:00",
|
||||
"Europe/Istanbul": "+02:00",
|
||||
"Europe/Jersey": "+00:00",
|
||||
"Europe/Kaliningrad": "+02:00",
|
||||
"Europe/Kiev": "+02:00",
|
||||
"Europe/Lisbon": "+00:00",
|
||||
"Europe/Ljubljana": "+01:00",
|
||||
"Europe/London": "+00:00",
|
||||
"Europe/Luxembourg": "+01:00",
|
||||
"Europe/Madrid": "+01:00",
|
||||
"Europe/Malta": "+01:00",
|
||||
"Europe/Mariehamn": "+02:00",
|
||||
"Europe/Minsk": "+03:00",
|
||||
"Europe/Monaco": "+01:00",
|
||||
"Europe/Moscow": "+03:00",
|
||||
"Europe/Nicosia": "+02:00",
|
||||
"Europe/Oslo": "+01:00",
|
||||
"Europe/Paris": "+01:00",
|
||||
"Europe/Podgorica": "+01:00",
|
||||
"Europe/Prague": "+01:00",
|
||||
"Europe/Riga": "+02:00",
|
||||
"Europe/Rome": "+01:00",
|
||||
"Europe/Samara": "+04:00",
|
||||
"Europe/San_Marino": "+01:00",
|
||||
"Europe/Sarajevo": "+01:00",
|
||||
"Europe/Simferopol": "+03:00",
|
||||
"Europe/Skopje": "+01:00",
|
||||
"Europe/Sofia": "+02:00",
|
||||
"Europe/Stockholm": "+01:00",
|
||||
"Europe/Tallinn": "+02:00",
|
||||
"Europe/Tirane": "+01:00",
|
||||
"Europe/Tiraspol": "+02:00",
|
||||
"Europe/Uzhgorod": "+02:00",
|
||||
"Europe/Vaduz": "+01:00",
|
||||
"Europe/Vatican": "+01:00",
|
||||
"Europe/Vienna": "+01:00",
|
||||
"Europe/Vilnius": "+02:00",
|
||||
"Europe/Volgograd": "+03:00",
|
||||
"Europe/Warsaw": "+01:00",
|
||||
"Europe/Zagreb": "+01:00",
|
||||
"Europe/Zaporozhye": "+02:00",
|
||||
"Europe/Zurich": "+01:00",
|
||||
GB: "+00:00",
|
||||
"GB-Eire": "+00:00",
|
||||
GMT: "+00:00",
|
||||
"GMT+0": "+00:00",
|
||||
GMT0: "+00:00",
|
||||
"GMT-0": "+00:00",
|
||||
Greenwich: "+00:00",
|
||||
Hongkong: "+08:00",
|
||||
Iceland: "+00:00",
|
||||
"Indian/Antananarivo": "+03:00",
|
||||
"Indian/Chagos": "+06:00",
|
||||
"Indian/Christmas": "+07:00",
|
||||
"Indian/Cocos": "+06:30",
|
||||
"Indian/Comoro": "+03:00",
|
||||
"Indian/Kerguelen": "+05:00",
|
||||
"Indian/Mahe": "+04:00",
|
||||
"Indian/Maldives": "+05:00",
|
||||
"Indian/Mauritius": "+04:00",
|
||||
"Indian/Mayotte": "+03:00",
|
||||
"Indian/Reunion": "+04:00",
|
||||
Iran: "+03:30",
|
||||
Israel: "+02:00",
|
||||
Jamaica: "-05:00",
|
||||
Japan: "+09:00",
|
||||
Kwajalein: "+12:00",
|
||||
Libya: "+02:00",
|
||||
"Mexico/BajaNorte": "-08:00",
|
||||
"Mexico/BajaSur": "-07:00",
|
||||
"Mexico/General": "-06:00",
|
||||
Navajo: "-07:00",
|
||||
NZ: "+12:00",
|
||||
"NZ-CHAT": "+12:45",
|
||||
"Pacific/Apia": "+13:00",
|
||||
"Pacific/Auckland": "+12:00",
|
||||
"Pacific/Chatham": "+12:45",
|
||||
"Pacific/Chuuk": "+10:00",
|
||||
"Pacific/Easter": "-06:00",
|
||||
"Pacific/Efate": "+11:00",
|
||||
"Pacific/Enderbury": "+13:00",
|
||||
"Pacific/Fakaofo": "+13:00",
|
||||
"Pacific/Fiji": "+12:00",
|
||||
"Pacific/Funafuti": "+12:00",
|
||||
"Pacific/Galapagos": "-06:00",
|
||||
"Pacific/Gambier": "-09:00",
|
||||
"Pacific/Guadalcanal": "+11:00",
|
||||
"Pacific/Guam": "+10:00",
|
||||
"Pacific/Honolulu": "-10:00",
|
||||
"Pacific/Johnston": "-10:00",
|
||||
"Pacific/Kiritimati": "+14:00",
|
||||
"Pacific/Kosrae": "+11:00",
|
||||
"Pacific/Kwajalein": "+12:00",
|
||||
"Pacific/Majuro": "+12:00",
|
||||
"Pacific/Marquesas": "-09:30",
|
||||
"Pacific/Midway": "-11:00",
|
||||
"Pacific/Nauru": "+12:00",
|
||||
"Pacific/Niue": "-11:00",
|
||||
"Pacific/Norfolk": "+11:30",
|
||||
"Pacific/Noumea": "+11:00",
|
||||
"Pacific/Pago_Pago": "-11:00",
|
||||
"Pacific/Palau": "+09:00",
|
||||
"Pacific/Pitcairn": "-08:00",
|
||||
"Pacific/Pohnpei": "+11:00",
|
||||
"Pacific/Ponape": "+11:00",
|
||||
"Pacific/Port_Moresby": "+10:00",
|
||||
"Pacific/Rarotonga": "-10:00",
|
||||
"Pacific/Saipan": "+10:00",
|
||||
"Pacific/Samoa": "-11:00",
|
||||
"Pacific/Tahiti": "-10:00",
|
||||
"Pacific/Tarawa": "+12:00",
|
||||
"Pacific/Tongatapu": "+13:00",
|
||||
"Pacific/Truk": "+10:00",
|
||||
"Pacific/Wake": "+12:00",
|
||||
"Pacific/Wallis": "+12:00",
|
||||
"Pacific/Yap": "+10:00",
|
||||
Poland: "+01:00",
|
||||
Portugal: "+00:00",
|
||||
PRC: "+08:00",
|
||||
ROC: "+08:00",
|
||||
ROK: "+09:00",
|
||||
Singapore: "+08:00",
|
||||
Turkey: "+02:00",
|
||||
UCT: "+00:00",
|
||||
Universal: "+00:00",
|
||||
"US/Alaska": "-09:00",
|
||||
"US/Aleutian": "-10:00",
|
||||
"US/Arizona": "-07:00",
|
||||
"US/Central": "-06:00",
|
||||
"US/Eastern": "-05:00",
|
||||
"US/East-Indiana": "-05:00",
|
||||
"US/Hawaii": "-10:00",
|
||||
"US/Indiana-Starke": "-06:00",
|
||||
"US/Michigan": "-05:00",
|
||||
"US/Mountain": "-07:00",
|
||||
"US/Pacific": "-08:00",
|
||||
"US/Samoa": "-11:00",
|
||||
UTC: "+00:00",
|
||||
"W-SU": "+03:00",
|
||||
Zulu: "+00:00",
|
||||
};
|
||||
14
node_modules/firebase-functions/lib/common/trace.d.ts
generated
vendored
Normal file
14
node_modules/firebase-functions/lib/common/trace.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
export interface TraceContext {
|
||||
version: string;
|
||||
traceId: string;
|
||||
parentId: string;
|
||||
sample: boolean;
|
||||
}
|
||||
/**
|
||||
* Extracts trace context from given carrier object, if any.
|
||||
*
|
||||
* Supports Cloud Trace and traceparent format.
|
||||
*
|
||||
* @param carrier
|
||||
*/
|
||||
export declare function extractTraceContext(carrier: unknown): TraceContext | undefined;
|
||||
69
node_modules/firebase-functions/lib/common/trace.js
generated
vendored
Normal file
69
node_modules/firebase-functions/lib/common/trace.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.extractTraceContext = exports.traceContext = void 0;
|
||||
const async_hooks_1 = require("async_hooks");
|
||||
/* @internal */
|
||||
exports.traceContext = new async_hooks_1.AsyncLocalStorage();
|
||||
/**
|
||||
* A regex to match the Cloud Trace header.
|
||||
* - ([A-Fa-f0-9]{32}): The trace id, a 32 character hex value. (e.g. 4bf92f3577b34da6a3ce929d0e0e4736)
|
||||
* - ([0-9]+): The parent span id, a 64 bit integer. (e.g. 00f067aa0ba902b7)
|
||||
* - (?:;o=([0-3])): The trace mask, 1-3 denote it should be traced.
|
||||
*/
|
||||
const CLOUD_TRACE_REGEX = new RegExp("^(?<traceId>[A-Fa-f0-9]{32})/" + "(?<parentIdInt>[0-9]+)" + "(?:;o=(?<traceMask>[0-3]))?$");
|
||||
const CLOUD_TRACE_HEADER = "X-Cloud-Trace-Context";
|
||||
function matchCloudTraceHeader(carrier) {
|
||||
let header = carrier === null || carrier === void 0 ? void 0 : carrier[CLOUD_TRACE_HEADER];
|
||||
if (!header) {
|
||||
// try lowercase header
|
||||
header = carrier === null || carrier === void 0 ? void 0 : carrier[CLOUD_TRACE_HEADER.toLowerCase()];
|
||||
}
|
||||
if (header && typeof header === "string") {
|
||||
const matches = CLOUD_TRACE_REGEX.exec(header);
|
||||
if (matches && matches.groups) {
|
||||
const { traceId, parentIdInt, traceMask } = matches.groups;
|
||||
// Convert parentId from unsigned int to hex
|
||||
const parentId = parseInt(parentIdInt);
|
||||
if (isNaN(parentId)) {
|
||||
// Ignore traces with invalid parentIds
|
||||
return;
|
||||
}
|
||||
const sample = !!traceMask && traceMask !== "0";
|
||||
return { traceId, parentId: parentId.toString(16), sample, version: "00" };
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A regex to match the traceparent header.
|
||||
* - ^([a-f0-9]{2}): The specification version (e.g. 00)
|
||||
* - ([a-f0-9]{32}): The trace id, a 16-byte array. (e.g. 4bf92f3577b34da6a3ce929d0e0e4736)
|
||||
* - ([a-f0-9]{16}): The parent span id, an 8-byte array. (e.g. 00f067aa0ba902b7)
|
||||
* - ([a-f0-9]{2}: The sampled flag. (e.g. 00)
|
||||
*/
|
||||
const TRACEPARENT_REGEX = new RegExp("^(?<version>[a-f0-9]{2})-" +
|
||||
"(?<traceId>[a-f0-9]{32})-" +
|
||||
"(?<parentId>[a-f0-9]{16})-" +
|
||||
"(?<flag>[a-f0-9]{2})$");
|
||||
const TRACEPARENT_HEADER = "traceparent";
|
||||
function matchTraceparentHeader(carrier) {
|
||||
const header = carrier === null || carrier === void 0 ? void 0 : carrier[TRACEPARENT_HEADER];
|
||||
if (header && typeof header === "string") {
|
||||
const matches = TRACEPARENT_REGEX.exec(header);
|
||||
if (matches && matches.groups) {
|
||||
const { version, traceId, parentId, flag } = matches.groups;
|
||||
const sample = flag === "01";
|
||||
return { traceId, parentId, sample, version };
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Extracts trace context from given carrier object, if any.
|
||||
*
|
||||
* Supports Cloud Trace and traceparent format.
|
||||
*
|
||||
* @param carrier
|
||||
*/
|
||||
function extractTraceContext(carrier) {
|
||||
return matchCloudTraceHeader(carrier) || matchTraceparentHeader(carrier);
|
||||
}
|
||||
exports.extractTraceContext = extractTraceContext;
|
||||
4
node_modules/firebase-functions/lib/common/utilities/encoder.d.ts
generated
vendored
Normal file
4
node_modules/firebase-functions/lib/common/utilities/encoder.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export declare function dateToTimestampProto(timeString?: string): {
|
||||
seconds: number;
|
||||
nanos: number;
|
||||
};
|
||||
39
node_modules/firebase-functions/lib/common/utilities/encoder.js
generated
vendored
Normal file
39
node_modules/firebase-functions/lib/common/utilities/encoder.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2017 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.dateToTimestampProto = void 0;
|
||||
function dateToTimestampProto(timeString) {
|
||||
if (typeof timeString === "undefined") {
|
||||
return;
|
||||
}
|
||||
const date = new Date(timeString);
|
||||
const seconds = Math.floor(date.getTime() / 1000);
|
||||
let nanos = 0;
|
||||
if (timeString.length > 20) {
|
||||
const nanoString = timeString.substring(20, timeString.length - 1);
|
||||
const trailingZeroes = 9 - nanoString.length;
|
||||
nanos = parseInt(nanoString, 10) * Math.pow(10, trailingZeroes);
|
||||
}
|
||||
return { seconds, nanos };
|
||||
}
|
||||
exports.dateToTimestampProto = dateToTimestampProto;
|
||||
1
node_modules/firebase-functions/lib/common/utilities/path-pattern.d.ts
generated
vendored
Normal file
1
node_modules/firebase-functions/lib/common/utilities/path-pattern.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
143
node_modules/firebase-functions/lib/common/utilities/path-pattern.js
generated
vendored
Normal file
143
node_modules/firebase-functions/lib/common/utilities/path-pattern.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PathPattern = exports.trimParam = void 0;
|
||||
const path_1 = require("./path");
|
||||
/** https://cloud.google.com/eventarc/docs/path-patterns */
|
||||
/** @hidden */
|
||||
const WILDCARD_CAPTURE_REGEX = new RegExp("{[^/{}]+}", "g");
|
||||
/** @internal */
|
||||
function trimParam(param) {
|
||||
const paramNoBraces = param.slice(1, -1);
|
||||
if (paramNoBraces.includes("=")) {
|
||||
return paramNoBraces.slice(0, paramNoBraces.indexOf("="));
|
||||
}
|
||||
return paramNoBraces;
|
||||
}
|
||||
exports.trimParam = trimParam;
|
||||
/** @hidden */
|
||||
class Segment {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
this.name = "segment";
|
||||
this.trimmed = value;
|
||||
}
|
||||
isSingleSegmentWildcard() {
|
||||
return this.value.includes("*") && !this.isMultiSegmentWildcard();
|
||||
}
|
||||
isMultiSegmentWildcard() {
|
||||
return this.value.includes("**");
|
||||
}
|
||||
}
|
||||
/** @hidden */
|
||||
class SingleCaptureSegment {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
this.name = "single-capture";
|
||||
this.trimmed = trimParam(value);
|
||||
}
|
||||
isSingleSegmentWildcard() {
|
||||
return true;
|
||||
}
|
||||
isMultiSegmentWildcard() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/** @hidden */
|
||||
class MultiCaptureSegment {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
this.name = "multi-capture";
|
||||
this.trimmed = trimParam(value);
|
||||
}
|
||||
isSingleSegmentWildcard() {
|
||||
return false;
|
||||
}
|
||||
isMultiSegmentWildcard() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Implements Eventarc's path pattern from the spec https://cloud.google.com/eventarc/docs/path-patterns
|
||||
* @internal
|
||||
*/
|
||||
class PathPattern {
|
||||
/** @throws on validation error */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
static compile(rawPath) {
|
||||
return undefined;
|
||||
}
|
||||
constructor(raw) {
|
||||
this.raw = raw;
|
||||
this.segments = [];
|
||||
this.initPathSegments(raw);
|
||||
}
|
||||
getValue() {
|
||||
return this.raw;
|
||||
}
|
||||
// If false, we don't need to use pathPattern as our eventarc match type.
|
||||
hasWildcards() {
|
||||
return this.segments.some((segment) => segment.isSingleSegmentWildcard() || segment.isMultiSegmentWildcard());
|
||||
}
|
||||
hasCaptures() {
|
||||
return this.segments.some((segment) => segment.name === "single-capture" || segment.name === "multi-capture");
|
||||
}
|
||||
extractMatches(path) {
|
||||
const matches = {};
|
||||
if (!this.hasCaptures()) {
|
||||
return matches;
|
||||
}
|
||||
const pathSegments = (0, path_1.pathParts)(path);
|
||||
let pathNdx = 0;
|
||||
for (let segmentNdx = 0; segmentNdx < this.segments.length && pathNdx < pathSegments.length; segmentNdx++) {
|
||||
const segment = this.segments[segmentNdx];
|
||||
const remainingSegments = this.segments.length - 1 - segmentNdx;
|
||||
const nextPathNdx = pathSegments.length - remainingSegments;
|
||||
if (segment.name === "single-capture") {
|
||||
matches[segment.trimmed] = pathSegments[pathNdx];
|
||||
}
|
||||
else if (segment.name === "multi-capture") {
|
||||
matches[segment.trimmed] = pathSegments.slice(pathNdx, nextPathNdx).join("/");
|
||||
}
|
||||
pathNdx = segment.isMultiSegmentWildcard() ? nextPathNdx : pathNdx + 1;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
initPathSegments(raw) {
|
||||
const parts = (0, path_1.pathParts)(raw);
|
||||
for (const part of parts) {
|
||||
let segment;
|
||||
const capture = part.match(WILDCARD_CAPTURE_REGEX);
|
||||
if (capture && capture.length === 1) {
|
||||
segment = part.includes("**")
|
||||
? new MultiCaptureSegment(part)
|
||||
: new SingleCaptureSegment(part);
|
||||
}
|
||||
else {
|
||||
segment = new Segment(part);
|
||||
}
|
||||
this.segments.push(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.PathPattern = PathPattern;
|
||||
19
node_modules/firebase-functions/lib/common/utilities/path.d.ts
generated
vendored
Normal file
19
node_modules/firebase-functions/lib/common/utilities/path.d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/** @hidden
|
||||
* Removes leading and trailing slashes from a path.
|
||||
*
|
||||
* @param path A path to normalize, in POSIX format.
|
||||
*/
|
||||
export declare function normalizePath(path: string): string;
|
||||
/**
|
||||
* Normalizes a given path and splits it into an array of segments.
|
||||
*
|
||||
* @param path A path to split, in POSIX format.
|
||||
*/
|
||||
export declare function pathParts(path: string): string[];
|
||||
/**
|
||||
* Normalizes given paths and joins these together using a POSIX separator.
|
||||
*
|
||||
* @param base A first path segment, in POSIX format.
|
||||
* @param child A second path segment, in POSIX format.
|
||||
*/
|
||||
export declare function joinPath(base: string, child: string): string;
|
||||
37
node_modules/firebase-functions/lib/common/utilities/path.js
generated
vendored
Normal file
37
node_modules/firebase-functions/lib/common/utilities/path.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.joinPath = exports.pathParts = exports.normalizePath = void 0;
|
||||
/** @hidden
|
||||
* Removes leading and trailing slashes from a path.
|
||||
*
|
||||
* @param path A path to normalize, in POSIX format.
|
||||
*/
|
||||
function normalizePath(path) {
|
||||
if (!path) {
|
||||
return "";
|
||||
}
|
||||
return path.replace(/^\//, "").replace(/\/$/, "");
|
||||
}
|
||||
exports.normalizePath = normalizePath;
|
||||
/**
|
||||
* Normalizes a given path and splits it into an array of segments.
|
||||
*
|
||||
* @param path A path to split, in POSIX format.
|
||||
*/
|
||||
function pathParts(path) {
|
||||
if (!path || path === "" || path === "/") {
|
||||
return [];
|
||||
}
|
||||
return normalizePath(path).split("/");
|
||||
}
|
||||
exports.pathParts = pathParts;
|
||||
/**
|
||||
* Normalizes given paths and joins these together using a POSIX separator.
|
||||
*
|
||||
* @param base A first path segment, in POSIX format.
|
||||
* @param child A second path segment, in POSIX format.
|
||||
*/
|
||||
function joinPath(base, child) {
|
||||
return pathParts(base).concat(pathParts(child)).join("/");
|
||||
}
|
||||
exports.joinPath = joinPath;
|
||||
2
node_modules/firebase-functions/lib/common/utilities/utils.d.ts
generated
vendored
Normal file
2
node_modules/firebase-functions/lib/common/utilities/utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @hidden */
|
||||
export declare function applyChange(src: any, dest: any): any;
|
||||
52
node_modules/firebase-functions/lib/common/utilities/utils.js
generated
vendored
Normal file
52
node_modules/firebase-functions/lib/common/utilities/utils.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2017 Firebase
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.applyChange = void 0;
|
||||
function isObject(obj) {
|
||||
return typeof obj === "object" && !!obj;
|
||||
}
|
||||
/** @hidden */
|
||||
function applyChange(src, dest) {
|
||||
// if not mergeable, don't merge
|
||||
if (!isObject(dest) || !isObject(src)) {
|
||||
return dest;
|
||||
}
|
||||
return merge(src, dest);
|
||||
}
|
||||
exports.applyChange = applyChange;
|
||||
function merge(src, dest) {
|
||||
const res = {};
|
||||
const keys = new Set([...Object.keys(src), ...Object.keys(dest)]);
|
||||
for (const key of keys.values()) {
|
||||
if (key in dest) {
|
||||
if (dest[key] === null) {
|
||||
continue;
|
||||
}
|
||||
res[key] = applyChange(src[key], dest[key]);
|
||||
}
|
||||
else if (src[key] !== null) {
|
||||
res[key] = src[key];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
Reference in New Issue
Block a user