mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
Use closure-net as a dependency of Firestore (#8190)
* Add closure library blobs as Firestore dependency. * Remove our compilation of Closure. * Add closure-net as a git submodule. * remove temporary .only in test. * prettier. * add yarn.lock differences. * create a types.d.ts for the webchannel-wrapper package. * Bring back the aggregated types and implementations for size report. * Undo CI changes for git submodules. * Remove the git submodule. * Use git+https in package.json devDependencies. * prettier. * Set up rollup for webchannel-wrapper (#8203) * convert webchannel-wrapper package to use rollup * clean up rollup config * formatting * Create thick-spoons-check.md * Better changeset. * Address feedback on versioning. --------- Co-authored-by: Christina Holland <[email protected]>
This commit is contained in:
committed by
GitHub
co-authored by
Christina Holland
parent
b7110d221d
commit
5f79012857
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@firebase/firestore": patch
|
||||
"@firebase/webchannel-wrapper": major
|
||||
---
|
||||
|
||||
Use closure-net as a dependency of webchannel-wrapper and Firestore.
|
||||
@@ -24,7 +24,8 @@
|
||||
"packages/component/dist/src/provider.d.ts",
|
||||
"packages/component/dist/src/component_container.d.ts",
|
||||
"packages/logger/dist/src/logger.d.ts",
|
||||
"packages/webchannel-wrapper/src/index.d.ts",
|
||||
"packages/webchannel-wrapper/dist/bloom-blob/bloom_blob_types.d.ts",
|
||||
"packages/webchannel-wrapper/dist/webchannel-blob/webchannel_blob_types.d.ts",
|
||||
"packages/util/dist/src/crypt.d.ts",
|
||||
"packages/util/dist/src/defaults.d.ts",
|
||||
"packages/util/dist/src/emulator.d.ts",
|
||||
|
||||
@@ -27,9 +27,9 @@ import {
|
||||
EventTarget,
|
||||
StatEvent,
|
||||
Event,
|
||||
Stat,
|
||||
FetchXmlHttpFactory
|
||||
} from '@firebase/webchannel-wrapper';
|
||||
FetchXmlHttpFactory,
|
||||
Stat
|
||||
} from '@firebase/webchannel-wrapper/webchannel-blob';
|
||||
|
||||
import { Token } from '../../api/credentials';
|
||||
import { ExperimentalLongPollingOptions } from '../../api/long_polling_options';
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Md5, Integer } from '@firebase/webchannel-wrapper';
|
||||
|
||||
import { Md5, Integer } from '@firebase/webchannel-wrapper/bloom-blob';
|
||||
|
||||
import { newTextEncoder } from '../platform/text_serializer';
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// These tests are mostly to ensure that the exported classes correctly map to
|
||||
// underlying functionality from google-closure-library.
|
||||
|
||||
import { Md5, Integer } from '@firebase/webchannel-wrapper';
|
||||
import { Md5, Integer } from '@firebase/webchannel-wrapper/bloom-blob';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { newTextEncoder } from '../../../src/platform/text_serializer';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@firebase/webchannel-wrapper/bloom-blob",
|
||||
"description": "Bloom filter related code from the Closure library.",
|
||||
"main": "../dist/bloom-blob/bloom_blob_es2018.js",
|
||||
"browser": "../dist/bloom-blob/esm/bloom_blob_es2018.js",
|
||||
"module": "../dist/bloom-blob/esm/bloom_blob_es2018.js",
|
||||
"esm5": "../dist/bloom-blob/bloom_blob_es5.js",
|
||||
"typings": "../dist/bloom-blob/bloom_blob_types.d.ts"
|
||||
}
|
||||
+8
-3
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,5 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** @type {!Object} */
|
||||
const module = {};
|
||||
/**
|
||||
* This package has no main entry point and only allows imports from its
|
||||
* two subpaths. This file is provided for the top-level package.json
|
||||
* "main" field to point to.
|
||||
*/
|
||||
|
||||
export default {};
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2017 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Overrides for the goog.net.WebChannel.Options object provided
|
||||
* by closure-library. This prevents the mangling of these properties
|
||||
* so downstream clients can properly leverage the API
|
||||
*/
|
||||
|
||||
/** @record @suppress {duplicate} */
|
||||
goog.net.WebChannel.Options = {};
|
||||
|
||||
/** @type {Object<string, string>|undefined} */
|
||||
goog.net.WebChannel.Options.messageHeaders;
|
||||
|
||||
/** @type {Object<string, string>|undefined} */
|
||||
goog.net.WebChannel.Options.initMessageHeaders;
|
||||
|
||||
/** @type {string|boolean|undefined} */
|
||||
goog.net.WebChannel.Options.messageContentType;
|
||||
|
||||
/** @type {Object<string, string>|undefined|undefined} */
|
||||
goog.net.WebChannel.Options.messageUrlParams;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.clientProtocolHeaderRequired;
|
||||
|
||||
/** @type {number|undefined} */
|
||||
goog.net.WebChannel.Options.concurrentRequestLimit;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.supportsCrossDomainXhr;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.sendRawJson;
|
||||
|
||||
/** @type {string|undefined} */
|
||||
goog.net.WebChannel.Options.httpSessionIdParam;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.encodeInitMessageHeaders;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.fastHandshake;
|
||||
|
||||
/** @type {!Object<string, boolean|number>|undefined} */
|
||||
goog.net.WebChannel.Options.internalChannelParams;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.forceLongPolling;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.detectBufferingProxy;
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
goog.net.WebChannel.Options.useFetchStreams;
|
||||
|
||||
/** @type {unknown} */
|
||||
goog.net.WebChannel.Options.xmlHttpFactory;
|
||||
|
||||
/** @type {number|undefined} */
|
||||
goog.net.WebChannel.Options.longPollingTimeout;
|
||||
|
||||
goog.labs.net.webChannel.requestStats.Event = {};
|
||||
goog.labs.net.webChannel.requestStats.Event.STAT_EVENT;
|
||||
|
||||
goog.labs.net.webChannel.requestStats.StatEvent = {};
|
||||
goog.labs.net.webChannel.requestStats.StatEvent.stat;
|
||||
|
||||
goog.labs.net.webChannel.requestStats.Stat = {};
|
||||
goog.labs.net.webChannel.requestStats.Stat.PROXY;
|
||||
goog.labs.net.webChannel.requestStats.Stat.NOPROXY;
|
||||
@@ -1,218 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const gulp = require('gulp');
|
||||
const rollup = require('rollup');
|
||||
const closureCompiler = require('google-closure-compiler').gulp();
|
||||
const del = require('del');
|
||||
const path = require('path');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
const { resolve } = require('path');
|
||||
const commonjs = require('@rollup/plugin-commonjs');
|
||||
const rollupSourcemaps = require('rollup-plugin-sourcemaps');
|
||||
const typescriptPlugin = require('rollup-plugin-typescript2');
|
||||
const typescript = require('typescript');
|
||||
const pkg = require('./package.json');
|
||||
|
||||
// Copied from "../../scripts/build/rollup_emit_module_package_file" which is ESM
|
||||
// and would require converting this file to MJS to use
|
||||
function emitModulePackageFile() {
|
||||
return {
|
||||
generateBundle() {
|
||||
this.emitFile({
|
||||
fileName: 'package.json',
|
||||
source: `{"type":"module"}`,
|
||||
type: 'asset'
|
||||
});
|
||||
},
|
||||
name: 'emit-module-package-file'
|
||||
};
|
||||
}
|
||||
|
||||
// The optimization level for the JS compiler.
|
||||
// Valid levels: WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS.
|
||||
const OPTIMIZATION_LEVEL = 'ADVANCED_OPTIMIZATIONS';
|
||||
|
||||
// For minified builds, wrap the output so we avoid leaking global variables.
|
||||
const CJS_WRAPPER_PREFIX = `(function() {`;
|
||||
const CJS_WRAPPER_SUFFIX =
|
||||
`}).apply(typeof global !== 'undefined' ? ` +
|
||||
`global : typeof self !== 'undefined' ? ` +
|
||||
`self : typeof window !== 'undefined' ? window : {});`;
|
||||
|
||||
const closureLibRoot = path.dirname(
|
||||
require.resolve('google-closure-library/package.json')
|
||||
);
|
||||
|
||||
const closureDefines = [
|
||||
// Avoid unsafe eval() calls (https://github.com/firebase/firebase-js-sdk/issues/798)
|
||||
'goog.json.USE_NATIVE_JSON=true',
|
||||
// Disable debug logging (saves 8780 bytes).
|
||||
'goog.DEBUG=false',
|
||||
// Disable fallbacks for running async code (saves 1472 bytes).
|
||||
'goog.ASSUME_NATIVE_PROMISE=true',
|
||||
// Disables IE8-specific event fallback code (saves 523 bytes).
|
||||
'goog.events.CAPTURE_SIMULATION_MODE=0',
|
||||
// Disable IE-Specific ActiveX fallback for XHRs (saves 524 bytes).
|
||||
'goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR=true',
|
||||
// Disable Origin Trials code for WebChannel (saves 1786 bytes).
|
||||
'goog.net.webChannel.ALLOW_ORIGIN_TRIAL_FEATURES=false'
|
||||
];
|
||||
|
||||
/**
|
||||
* Generates a closure compiler build of webchannel-wrapper.
|
||||
* @param {string} filename name of the generated file
|
||||
* @param {string} prefix prefix to the compiled code
|
||||
* @param {string} suffix suffix to the compiled code
|
||||
*/
|
||||
function createBuildTask(filename, prefix, suffix, languageout) {
|
||||
return function closureBuild() {
|
||||
return gulp
|
||||
.src(
|
||||
[
|
||||
`${closureLibRoot}/closure/goog/**/*.js`,
|
||||
`${closureLibRoot}/third_party/closure/goog/**/*.js`,
|
||||
'src/**/*.js'
|
||||
],
|
||||
{ base: '.' }
|
||||
)
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(
|
||||
closureCompiler({
|
||||
js_output_file: filename,
|
||||
output_wrapper: `${prefix}%output%${suffix}`,
|
||||
entry_point: 'firebase.webchannel.wrapper',
|
||||
compilation_level: OPTIMIZATION_LEVEL,
|
||||
externs: [
|
||||
resolve(__dirname, './externs/overrides.js'),
|
||||
resolve(__dirname, './externs/module.js')
|
||||
],
|
||||
language_out: languageout,
|
||||
dependency_mode: 'PRUNE',
|
||||
define: closureDefines
|
||||
})
|
||||
)
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest('dist'));
|
||||
};
|
||||
}
|
||||
|
||||
function createRollupTask({
|
||||
inputPath,
|
||||
outputExtension,
|
||||
compileToES5 = false,
|
||||
format = 'es'
|
||||
}) {
|
||||
return async function rollupBuild() {
|
||||
const plugins = [rollupSourcemaps(), commonjs()];
|
||||
if (compileToES5) {
|
||||
plugins.push(
|
||||
typescriptPlugin({
|
||||
typescript,
|
||||
// Uncomment for development only. Prevents caching between builds.
|
||||
// clean: true,
|
||||
compilerOptions: { allowJs: true },
|
||||
include: ['dist/**/*.js']
|
||||
})
|
||||
);
|
||||
}
|
||||
if (format === 'es') {
|
||||
plugins.push(emitModulePackageFile());
|
||||
}
|
||||
const inputOptions = {
|
||||
input: inputPath,
|
||||
plugins
|
||||
};
|
||||
|
||||
let outputFilename;
|
||||
if (format === 'es') {
|
||||
if (compileToES5) {
|
||||
// ESM5
|
||||
outputFilename = pkg.esm5;
|
||||
} else {
|
||||
// ESM2017
|
||||
outputFilename = pkg.module;
|
||||
}
|
||||
} else {
|
||||
// CJS
|
||||
outputFilename = pkg.main;
|
||||
}
|
||||
const outputOptions = {
|
||||
file: outputFilename,
|
||||
format,
|
||||
sourcemap: true,
|
||||
// Prevents warning when compiling CJS that there are named and default exports together.
|
||||
exports: 'named'
|
||||
};
|
||||
|
||||
const bundle = await rollup.rollup(inputOptions);
|
||||
return bundle.write(outputOptions);
|
||||
};
|
||||
}
|
||||
|
||||
async function deleteIntermediateFiles() {
|
||||
await del('dist/temp');
|
||||
}
|
||||
|
||||
// Closure-generated ES2017 intermediate file (no wrapper text)
|
||||
const intermediateEsmFile = 'temp/esm.js';
|
||||
const intermediateEsmPath = resolve(__dirname, 'dist/', intermediateEsmFile);
|
||||
const esmBuild = createBuildTask(
|
||||
intermediateEsmFile,
|
||||
'',
|
||||
'',
|
||||
'ECMASCRIPT_2017'
|
||||
);
|
||||
|
||||
// cjs output
|
||||
// Closure-generated ES5 CJS build
|
||||
const cjsBuildOutput = 'index.js';
|
||||
const cjsBuild = createBuildTask(
|
||||
cjsBuildOutput,
|
||||
CJS_WRAPPER_PREFIX,
|
||||
CJS_WRAPPER_SUFFIX,
|
||||
'ECMASCRIPT5'
|
||||
);
|
||||
|
||||
gulp.task('cjs', cjsBuild);
|
||||
|
||||
// esm intermediateEsmPath
|
||||
const rollupEsmTask = createRollupTask({
|
||||
inputPath: intermediateEsmPath,
|
||||
outputExtension: 'esm',
|
||||
compileToES5: true,
|
||||
format: 'es'
|
||||
});
|
||||
gulp.task('esm', gulp.series(esmBuild, rollupEsmTask));
|
||||
|
||||
// esm2017 output
|
||||
const rollup2017Task = createRollupTask({
|
||||
inputPath: intermediateEsmPath,
|
||||
outputExtension: 'esm2017',
|
||||
compileToES5: false,
|
||||
format: 'es'
|
||||
});
|
||||
gulp.task('esm2017', gulp.series(esmBuild, rollup2017Task));
|
||||
|
||||
gulp.task(
|
||||
'allEsm',
|
||||
gulp.series(esmBuild, gulp.parallel(rollupEsmTask, rollup2017Task))
|
||||
);
|
||||
|
||||
gulp.task('buildAll', gulp.parallel('cjs', 'allEsm'));
|
||||
|
||||
gulp.task('default', gulp.series('buildAll', deleteIntermediateFiles));
|
||||
@@ -3,35 +3,39 @@
|
||||
"version": "0.10.6",
|
||||
"description": "A wrapper of the webchannel packages from closure-library for use outside of a closure compiled application",
|
||||
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/esm/index.esm2017.js",
|
||||
"esm5": "dist/esm/index.esm.js",
|
||||
"main": "empty.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"esm5": "./dist/esm/index.esm.js",
|
||||
"default": "./dist/esm/index.esm2017.js"
|
||||
"./webchannel-blob": {
|
||||
"types": "./dist/webchannel-blob/webchannel_blob_types.d.ts",
|
||||
"require": "./dist/webchannel-blob/webchannel_blob_es2018.js",
|
||||
"esm5": "./dist/webchannel-blob/webchannel_blob_es5.js",
|
||||
"default": "./dist/webchannel-blob/esm/webchannel_blob_es2018.js"
|
||||
},
|
||||
"./bloom-blob": {
|
||||
"types": "./dist/bloom-blob/bloom_blob_types.d.ts",
|
||||
"require": "./dist/bloom-blob/bloom_blob_es2018.js",
|
||||
"es5": "./dist/bloom-blob/bloom_blob_es5.js",
|
||||
"default": "./dist/bloom-blob/esm/bloom_blob_es2018.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"bloom-blob/package.json",
|
||||
"webchannel-blob/package.json"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "watch 'yarn build' src",
|
||||
"build": "gulp",
|
||||
"build": "rollup -c",
|
||||
"test": "echo 'No test suite for webchannel-wrapper'",
|
||||
"test:ci": "echo 'No test suite for webchannel-wrapper'"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"closure-net": "git+https://github.com/google/closure-net.git#9844d60",
|
||||
"@rollup/plugin-commonjs": "21.1.0",
|
||||
"google-closure-compiler": "20230228.0.0",
|
||||
"google-closure-library": "git+https://github.com/google/closure-library.git#7818ff7",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-sourcemaps": "3.0.0",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-copy": "3.5.0",
|
||||
"rollup-plugin-sourcemaps": "0.6.3",
|
||||
"rollup-plugin-typescript2": "0.31.2",
|
||||
"typescript": "4.7.4"
|
||||
@@ -41,7 +45,7 @@
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/firebase/firebase-js-sdk.git"
|
||||
},
|
||||
"typings": "src/index.d.ts",
|
||||
"typings": "./dist/webchannel-blob/webchannel_blob_types.d.ts",
|
||||
"bugs": {
|
||||
"url": "https://github.com/firebase/firebase-js-sdk/issues"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { join } from 'path';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import typescriptPlugin from 'rollup-plugin-typescript2';
|
||||
import typescript from 'typescript';
|
||||
import { emitModulePackageFile } from '../../scripts/build/rollup_emit_module_package_file';
|
||||
import pkg from './package.json';
|
||||
|
||||
const closureBlobsDir = '../../node_modules/closure-net/firebase/';
|
||||
|
||||
const es2017BuildPlugins = [
|
||||
copy({
|
||||
targets: [
|
||||
{
|
||||
src: join(closureBlobsDir, 'webchannel_blob_*.*'),
|
||||
dest: 'dist/webchannel-blob'
|
||||
},
|
||||
{ src: join(closureBlobsDir, 'bloom_blob_*.*'), dest: 'dist/bloom-blob' }
|
||||
]
|
||||
}),
|
||||
typescriptPlugin({
|
||||
typescript,
|
||||
tsconfigOverride: {
|
||||
compilerOptions: {
|
||||
target: 'es2017'
|
||||
}
|
||||
}
|
||||
}),
|
||||
commonjs()
|
||||
];
|
||||
|
||||
/**
|
||||
* ESM builds
|
||||
*/
|
||||
const esm2017Builds = [
|
||||
{
|
||||
input: join(closureBlobsDir, 'webchannel_blob_es2018.js'),
|
||||
output: {
|
||||
file: pkg.exports['./webchannel-blob'].default,
|
||||
format: 'es',
|
||||
sourcemap: true
|
||||
},
|
||||
plugins: [...es2017BuildPlugins, emitModulePackageFile()]
|
||||
},
|
||||
{
|
||||
input: join(closureBlobsDir, 'bloom_blob_es2018.js'),
|
||||
output: {
|
||||
file: pkg.exports['./bloom-blob'].default,
|
||||
format: 'es',
|
||||
sourcemap: true
|
||||
},
|
||||
plugins: [...es2017BuildPlugins, emitModulePackageFile()]
|
||||
}
|
||||
];
|
||||
|
||||
export default esm2017Builds;
|
||||
-165
@@ -1,165 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// WARNING: This is not a complete set of types exported by WebChannelWrapper.
|
||||
// It is merely meant to support the usage patterns of the Firestore SDK.
|
||||
|
||||
export var EventType: {
|
||||
COMPLETE: string;
|
||||
};
|
||||
|
||||
export namespace WebChannel {
|
||||
export var EventType: {
|
||||
OPEN: string;
|
||||
CLOSE: string;
|
||||
ERROR: string;
|
||||
MESSAGE: string;
|
||||
};
|
||||
}
|
||||
|
||||
export var Event: {
|
||||
STAT_EVENT: string;
|
||||
};
|
||||
|
||||
export var Stat: {
|
||||
PROXY: number;
|
||||
NOPROXY: number;
|
||||
};
|
||||
|
||||
export var ErrorCode: {
|
||||
NO_ERROR: number;
|
||||
HTTP_ERROR: number;
|
||||
TIMEOUT: number;
|
||||
};
|
||||
|
||||
export interface Headers {
|
||||
[name: string]: string | number;
|
||||
}
|
||||
|
||||
export interface WebChannelError {
|
||||
error?: { status: string; message: string };
|
||||
}
|
||||
|
||||
export class XhrIo {
|
||||
send(
|
||||
url: string,
|
||||
method?: string,
|
||||
body?: string,
|
||||
headers?: Headers,
|
||||
timeoutInterval?: number
|
||||
): void;
|
||||
|
||||
getLastErrorCode(): number;
|
||||
|
||||
getLastError(): string;
|
||||
|
||||
getStatus(): number;
|
||||
|
||||
getResponseText(): string;
|
||||
|
||||
getResponseJson(): WebChannelError | object;
|
||||
|
||||
listenOnce(type: string, cb: (param: unknown) => void): void;
|
||||
|
||||
setWithCredentials(withCredentials: boolean): void;
|
||||
}
|
||||
|
||||
export interface WebChannelOptions {
|
||||
messageHeaders?: {
|
||||
// To ensure compatibility with property minifcation tools, keys need to
|
||||
// be listed explicity.
|
||||
[k: string]: never;
|
||||
};
|
||||
initMessageHeaders?: {
|
||||
// To ensure compatibility with property minifcation tools, keys need to
|
||||
// be listed explicity.
|
||||
[k: string]: never;
|
||||
};
|
||||
messageContentType?: string;
|
||||
messageUrlParams?: {
|
||||
database?: string;
|
||||
};
|
||||
clientProtocolHeaderRequired?: boolean;
|
||||
concurrentRequestLimit?: number;
|
||||
supportsCrossDomainXhr?: boolean;
|
||||
sendRawJson?: boolean;
|
||||
httpSessionIdParam?: string;
|
||||
encodeInitMessageHeaders?: boolean;
|
||||
forceLongPolling?: boolean;
|
||||
detectBufferingProxy?: boolean;
|
||||
longPollingTimeout?: number;
|
||||
fastHandshake?: boolean;
|
||||
disableRedac?: boolean;
|
||||
clientProfile?: string;
|
||||
internalChannelParams?: {
|
||||
forwardChannelRequestTimeoutMs?: number;
|
||||
};
|
||||
useFetchStreams?: boolean;
|
||||
xmlHttpFactory?: unknown;
|
||||
requestRefreshThresholds?: { [key: string]: number };
|
||||
}
|
||||
|
||||
export interface EventTarget {
|
||||
listen(type: string | number, cb: (param: unknown) => void): void;
|
||||
}
|
||||
|
||||
export interface WebChannel extends EventTarget {
|
||||
open(): void;
|
||||
close(): void;
|
||||
send(msg: unknown): void;
|
||||
}
|
||||
|
||||
export interface StatEvent {
|
||||
stat: number;
|
||||
}
|
||||
|
||||
export interface WebChannelTransport {
|
||||
createWebChannel(url: string, options: WebChannelOptions): WebChannel;
|
||||
}
|
||||
|
||||
export function createWebChannelTransport(): WebChannelTransport;
|
||||
|
||||
export function getStatEventTarget(): EventTarget;
|
||||
|
||||
export class FetchXmlHttpFactory {
|
||||
constructor(options: {});
|
||||
}
|
||||
|
||||
// See https://google.github.io/closure-library/api/goog.crypt.Md5.html
|
||||
// Unit test are written in
|
||||
// packages/firestore/test/unit/core/webchannel_wrapper.test.ts
|
||||
export class Md5 {
|
||||
reset(): void;
|
||||
digest(): Array<number>;
|
||||
update(bytes: Array<number> | Uint8Array | string, opt_length?: number): void;
|
||||
}
|
||||
|
||||
// See https://google.github.io/closure-library/api/goog.math.Integer.html
|
||||
// Unit test are written in
|
||||
// packages/firestore/test/unit/core/webchannel_wrapper.test.ts
|
||||
export class Integer {
|
||||
constructor(bits: Array<number>, sign: number);
|
||||
add(other: Integer): Integer;
|
||||
multiply(other: Integer): Integer;
|
||||
modulo(other: Integer): Integer;
|
||||
compare(other: Integer): number;
|
||||
toNumber(): number;
|
||||
toString(opt_radix?: number): string;
|
||||
getBits(index: number): number;
|
||||
static fromNumber(value: number): Integer;
|
||||
static fromString(str: string, opt_radix?: number): Integer;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2017 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bring in closure-library dependencies
|
||||
*/
|
||||
|
||||
goog.provide('firebase.webchannel.wrapper');
|
||||
|
||||
// goog.net.WebChannelTransport
|
||||
goog.require('goog.net.createWebChannelTransport');
|
||||
goog.require('goog.net.FetchXmlHttpFactory');
|
||||
goog.require('goog.labs.net.webChannel.requestStats');
|
||||
goog.require('goog.labs.net.webChannel.WebChannelBaseTransport');
|
||||
|
||||
/**
|
||||
* NOTE: The `createWebChannel` function takes an options object as a second param
|
||||
* whose properties are typically mangled. We override these in externs/overrides.js
|
||||
* Without those externs, this does not function properly.
|
||||
*/
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.prototype['createWebChannel'] =
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.prototype.createWebChannel;
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.Channel.prototype['send'] =
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.Channel.prototype.send;
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.Channel.prototype['open'] =
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.Channel.prototype.open;
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.Channel.prototype['close'] =
|
||||
goog.labs.net.webChannel.WebChannelBaseTransport.Channel.prototype.close;
|
||||
|
||||
// goog.net.ErrorCode
|
||||
goog.require('goog.net.ErrorCode');
|
||||
goog.net.ErrorCode['NO_ERROR'] = goog.net.ErrorCode.NO_ERROR;
|
||||
goog.net.ErrorCode['TIMEOUT'] = goog.net.ErrorCode.TIMEOUT;
|
||||
goog.net.ErrorCode['HTTP_ERROR'] = goog.net.ErrorCode.HTTP_ERROR;
|
||||
|
||||
// goog.net.ErrorType
|
||||
goog.require('goog.net.EventType');
|
||||
goog.net.EventType['COMPLETE'] = goog.net.EventType.COMPLETE;
|
||||
|
||||
// goog.net.WebChannel
|
||||
goog.require('goog.net.WebChannel');
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.net.WebChannel['EventType'] = goog.net.WebChannel.EventType;
|
||||
goog.net.WebChannel.EventType['OPEN'] = goog.net.WebChannel.EventType.OPEN;
|
||||
goog.net.WebChannel.EventType['CLOSE'] = goog.net.WebChannel.EventType.CLOSE;
|
||||
goog.net.WebChannel.EventType['ERROR'] = goog.net.WebChannel.EventType.ERROR;
|
||||
goog.net.WebChannel.EventType['MESSAGE'] =
|
||||
goog.net.WebChannel.EventType.MESSAGE;
|
||||
goog.events.EventTarget.prototype['listen'] =
|
||||
goog.events.EventTarget.prototype.listen;
|
||||
|
||||
goog.require('goog.net.XhrIo');
|
||||
goog.net.XhrIo.prototype['listenOnce'] = goog.net.XhrIo.prototype.listenOnce;
|
||||
goog.net.XhrIo.prototype['getLastError'] =
|
||||
goog.net.XhrIo.prototype.getLastError;
|
||||
goog.net.XhrIo.prototype['getLastErrorCode'] =
|
||||
goog.net.XhrIo.prototype.getLastErrorCode;
|
||||
goog.net.XhrIo.prototype['getStatus'] = goog.net.XhrIo.prototype.getStatus;
|
||||
goog.net.XhrIo.prototype['getResponseJson'] =
|
||||
goog.net.XhrIo.prototype.getResponseJson;
|
||||
goog.net.XhrIo.prototype['getResponseText'] =
|
||||
goog.net.XhrIo.prototype.getResponseText;
|
||||
goog.net.XhrIo.prototype['send'] = goog.net.XhrIo.prototype.send;
|
||||
goog.net.XhrIo.prototype['setWithCredentials'] =
|
||||
goog.net.XhrIo.prototype.setWithCredentials;
|
||||
|
||||
goog.require('goog.crypt.Md5');
|
||||
goog.crypt.Md5.prototype['digest'] = goog.crypt.Md5.prototype.digest;
|
||||
goog.crypt.Md5.prototype['reset'] = goog.crypt.Md5.prototype.reset;
|
||||
goog.crypt.Md5.prototype['update'] = goog.crypt.Md5.prototype.update;
|
||||
|
||||
goog.require('goog.math.Integer');
|
||||
goog.math.Integer.prototype['add'] = goog.math.Integer.prototype.add;
|
||||
goog.math.Integer.prototype['multiply'] = goog.math.Integer.prototype.multiply;
|
||||
goog.math.Integer.prototype['modulo'] = goog.math.Integer.prototype.modulo;
|
||||
goog.math.Integer.prototype['compare'] = goog.math.Integer.prototype.compare;
|
||||
goog.math.Integer.prototype['toNumber'] = goog.math.Integer.prototype.toNumber;
|
||||
goog.math.Integer.prototype['toString'] = goog.math.Integer.prototype.toString;
|
||||
goog.math.Integer.prototype['getBits'] = goog.math.Integer.prototype.getBits;
|
||||
goog.math.Integer['fromNumber'] = goog.math.Integer.fromNumber;
|
||||
goog.math.Integer['fromString'] = goog.math.Integer.fromString;
|
||||
|
||||
module['exports']['createWebChannelTransport'] =
|
||||
goog.net.createWebChannelTransport;
|
||||
module['exports']['getStatEventTarget'] =
|
||||
goog.labs.net.webChannel.requestStats.getStatEventTarget;
|
||||
module['exports']['ErrorCode'] = goog.net.ErrorCode;
|
||||
module['exports']['EventType'] = goog.net.EventType;
|
||||
module['exports']['Event'] = goog.labs.net.webChannel.requestStats.Event;
|
||||
module['exports']['Stat'] = goog.labs.net.webChannel.requestStats.Stat;
|
||||
module['exports']['FetchXmlHttpFactory'] = goog.net.FetchXmlHttpFactory;
|
||||
module['exports']['WebChannel'] = goog.net.WebChannel;
|
||||
module['exports']['XhrIo'] = goog.net.XhrIo;
|
||||
module['exports']['Md5'] = goog.crypt.Md5;
|
||||
module['exports']['Integer'] = goog.math.Integer;
|
||||
@@ -4,5 +4,6 @@
|
||||
"declaration": false,
|
||||
"outDir": "dist",
|
||||
"downlevelIteration": true,
|
||||
}
|
||||
},
|
||||
"include": ["../../node_modules/closure-net/firebase"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@firebase/webchannel-wrapper/webchannel-blob",
|
||||
"description": "Webchannel related code from the Closure library.",
|
||||
"main": "../dist/webchannel-blob/webchannel_blob_es2018.js",
|
||||
"browser": "../dist/webchannel-blob/esm/webchannel_blob_es2018.js",
|
||||
"module": "../dist/webchannel-blob/esm/webchannel_blob_es2018.js",
|
||||
"esm5": "../dist/webchannel-blob/webchannel_blob_es5.js",
|
||||
"typings": "../dist/webchannel-blob/webchannel_blob_types.d.ts"
|
||||
}
|
||||
@@ -498,7 +498,7 @@ export async function generateReportForModule(
|
||||
*
|
||||
* @param pkgJson package.json of the module.
|
||||
*
|
||||
* This function implements a fallback of locating module's budle file.
|
||||
* This function implements a fallback of locating module's bundle file.
|
||||
* It first looks at esm2017 field of package.json, then module field. Main
|
||||
* field at the last.
|
||||
*
|
||||
|
||||
@@ -5518,20 +5518,10 @@ camelcase@^6.0.0, camelcase@^6.2.0:
|
||||
resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz"
|
||||
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
|
||||
|
||||
caniuse-lite@^1.0.30001259:
|
||||
version "1.0.30001429"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz"
|
||||
integrity sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==
|
||||
|
||||
caniuse-lite@^1.0.30001517:
|
||||
version "1.0.30001524"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz"
|
||||
integrity sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==
|
||||
|
||||
caniuse-lite@^1.0.30001587:
|
||||
version "1.0.30001600"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz#93a3ee17a35aa6a9f0c6ef1b2ab49507d1ab9079"
|
||||
integrity sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==
|
||||
caniuse-lite@^1.0.30001259, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001587:
|
||||
version "1.0.30001611"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz"
|
||||
integrity sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==
|
||||
|
||||
cardinal@^2.1.1:
|
||||
version "2.1.1"
|
||||
@@ -5573,7 +5563,7 @@ [email protected]:
|
||||
pathval "^1.1.1"
|
||||
type-detect "^4.0.8"
|
||||
|
||||
[email protected], [email protected], chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
||||
[email protected], chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
@@ -5893,6 +5883,10 @@ cloneable-readable@^1.0.0:
|
||||
process-nextick-args "^2.0.0"
|
||||
readable-stream "^2.3.5"
|
||||
|
||||
"closure-net@git+https://github.com/google/closure-net.git#9844d60":
|
||||
version "0.0.0"
|
||||
resolved "git+https://github.com/google/closure-net.git#9844d605191623eaba4b184775610fe875e78ac4"
|
||||
|
||||
cmd-shim@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz"
|
||||
@@ -9195,45 +9189,6 @@ google-auth-library@^8.0.2:
|
||||
jws "^4.0.0"
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
google-closure-compiler-java@^20230228.0.0:
|
||||
version "20230228.0.0"
|
||||
resolved "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20230228.0.0.tgz"
|
||||
integrity sha512-t0sXYJbhfkuNTF6zniwrTv4gLap620D32v6GwBJQzlYUg0lb7yQHN9KswwqBsuuO917cPNwW4okI0O40G7GrMQ==
|
||||
|
||||
google-closure-compiler-linux@^20230228.0.0:
|
||||
version "20230228.0.0"
|
||||
resolved "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20230228.0.0.tgz#17cb6187015e0e2ae8c2dd5b560228fdf5625818"
|
||||
integrity sha512-5YLxfWS8lvHkD/a0+pitTuDV1X9QPBToGQ5mnLFg7HcbBR1w6I5ZKHjl7FAsAOHEXYwIrStwwaLzrNzbolrZLg==
|
||||
|
||||
google-closure-compiler-osx@^20230228.0.0:
|
||||
version "20230228.0.0"
|
||||
resolved "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20230228.0.0.tgz"
|
||||
integrity sha512-ORveHpHuNhJEJIGir35+xP4UuBOldSO8XeOwJV5yunUhZAPzR4aixdTdtm6i0GsqW4/Eu2cjcHrkIR3eFCcwSg==
|
||||
|
||||
google-closure-compiler-windows@^20230228.0.0:
|
||||
version "20230228.0.0"
|
||||
resolved "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20230228.0.0.tgz#dff4afcd6d21a831b38a9bdb873eed0daca79807"
|
||||
integrity sha512-xKMjUq6JwEOFqS97S86TWkn+BMiDHjP85mMgAmR8vRmKxgfHIyxMcr+RlMz0msgY9jedgj119KXyOe32lIQTjA==
|
||||
|
||||
[email protected]:
|
||||
version "20230228.0.0"
|
||||
resolved "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20230228.0.0.tgz"
|
||||
integrity sha512-jFI4QNZgM4WhNIoaRNwA5kHq6n6NKSWZj3N9HgRsJE9bN4LUrkIURI+svChbEp/WmGh3Bt3o3/5kUlOOWyCo3Q==
|
||||
dependencies:
|
||||
chalk "4.x"
|
||||
google-closure-compiler-java "^20230228.0.0"
|
||||
minimist "1.x"
|
||||
vinyl "2.x"
|
||||
vinyl-sourcemaps-apply "^0.2.0"
|
||||
optionalDependencies:
|
||||
google-closure-compiler-linux "^20230228.0.0"
|
||||
google-closure-compiler-osx "^20230228.0.0"
|
||||
google-closure-compiler-windows "^20230228.0.0"
|
||||
|
||||
"google-closure-library@git+https://github.com/google/closure-library.git#7818ff7":
|
||||
version "20230802.0.0"
|
||||
resolved "git+https://[email protected]/google/closure-library.git#7818ff7dc0b53555a7fb3c3427e6761e88bde3a2"
|
||||
|
||||
google-gax@^3.0.1:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.npmjs.org/google-gax/-/google-gax-3.1.3.tgz"
|
||||
@@ -12517,7 +12472,7 @@ [email protected], minimist-options@^4.0.2:
|
||||
is-plain-obj "^1.1.0"
|
||||
kind-of "^6.0.3"
|
||||
|
||||
[email protected], minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
|
||||
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
@@ -16058,7 +16013,7 @@ source-map-url@^0.4.0:
|
||||
resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz"
|
||||
integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
|
||||
|
||||
source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3:
|
||||
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||
@@ -17809,14 +17764,7 @@ vinyl-sourcemap@^1.1.0:
|
||||
remove-bom-buffer "^3.0.0"
|
||||
vinyl "^2.0.0"
|
||||
|
||||
vinyl-sourcemaps-apply@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz"
|
||||
integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=
|
||||
dependencies:
|
||||
source-map "^0.5.1"
|
||||
|
||||
[email protected], vinyl@^2.0.0, vinyl@^2.1.0, vinyl@^2.2.1:
|
||||
vinyl@^2.0.0, vinyl@^2.1.0, vinyl@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz"
|
||||
integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
|
||||
|
||||
Reference in New Issue
Block a user