Skip to content

Commit 7a7b44f

Browse files
Add Node.js support to Storage v9
1 parent 10fb5b8 commit 7a7b44f

27 files changed

+383
-85
lines changed

packages/storage/.run/All_tests.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="All Tests" type="mocha-javascript-test-runner">
3+
<node-interpreter>project</node-interpreter>
4+
<node-options />
5+
<mocha-package>$PROJECT_DIR$/../../node_modules/mocha</mocha-package>
6+
<working-directory>$PROJECT_DIR$</working-directory>
7+
<pass-parent-env>true</pass-parent-env>
8+
<envs>
9+
<env name="TS_NODE_COMPILER_OPTIONS" value="{&quot;module&quot;:&quot;commonjs&quot;}" />
10+
<env name="TS_NODE_FILES" value="true" />
11+
<env name="TS_NODE_CACHE" value="NO" />
12+
</envs>
13+
<ui>bdd</ui>
14+
<extra-mocha-options>--require ts-node/register/type-check --require index.ts</extra-mocha-options>
15+
<test-kind>PATTERN</test-kind>
16+
<test-pattern>test/{,!(browser)/**/}*.test.ts</test-pattern>
17+
<method v="2" />
18+
</configuration>
19+
</component>

packages/storage/exp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@firebase/storage-exp",
33
"description": "A tree-shakeable version of the Storage SDK",
4-
"main": "./dist/index.browser.cjs.js",
4+
"main": "./dist/index.node.cjs.js",
55
"module": "./dist/index.browser.esm2017.js",
66
"browser": "./dist/index.browser.esm2017.js",
77
"esm5": "./dist/index.browser.esm5.js",

packages/storage/package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121
"build:exp:release": "yarn build:exp && yarn build:compat",
2222
"build:deps": "lerna run --scope @firebase/storage --include-dependencies build",
2323
"dev": "rollup -c -w",
24-
"test": "run-p test:browser lint",
25-
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:browser",
24+
"test": "run-p test:browser test:node lint",
25+
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:browser test:node",
2626
"test:browser:compat:unit": "karma start --single-run --compat --unit",
2727
"test:browser:exp:unit": "karma start --single-run --exp --unit",
2828
"test:browser:compat:integration": "karma start --single-run --compat --integration",
2929
"test:browser:exp:integration": "karma start --single-run --exp --integration",
3030
"test:browser:compat": "karma start --single-run --compat",
3131
"test:browser:exp": "karma start --single-run --exp",
3232
"test:browser": "karma start --single-run",
33+
"test:node": "TS_NODE_FILES=true TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/{,!(browser)/**/}*.test.ts' --file index.ts --config ../../config/mocharc.node.js",
3334
"test:debug": "karma start --browser=Chrome",
3435
"prettier": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
3536
"api-report": "api-extractor run --local --verbose && ts-node-script ../../repo-scripts/prune-dts/prune-dts.ts --input exp/dist/storage-public.d.ts --output exp/dist/storage-public.d.ts",
@@ -40,6 +41,7 @@
4041
"@firebase/storage-types": "0.4.1",
4142
"@firebase/util": "1.1.0",
4243
"@firebase/component": "0.5.1",
44+
"node-fetch": "2.6.1",
4345
"tslib": "^2.1.0"
4446
},
4547
"peerDependencies": {
@@ -50,6 +52,7 @@
5052
"@firebase/app": "0.6.23",
5153
"@firebase/auth": "0.16.6",
5254
"rollup": "2.35.1",
55+
"@rollup/plugin-alias": "3.1.1",
5356
"@rollup/plugin-json": "4.1.0",
5457
"rollup-plugin-typescript2": "0.29.0",
5558
"typescript": "4.2.2"
@@ -63,4 +66,4 @@
6366
"url": "https://github.com/firebase/firebase-js-sdk/issues"
6467
},
6568
"typings": "dist/index.d.ts"
66-
}
69+
}

packages/storage/rollup.config.compat.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
import json from '@rollup/plugin-json';
1919
import typescriptPlugin from 'rollup-plugin-typescript2';
2020
import typescript from 'typescript';
21+
import alias from '@rollup/plugin-alias';
2122
import pkg from './package.json';
2223

2324
import { getImportPathTransformer } from '../../scripts/exp/ts-transform-import-path';
2425

26+
const { generateAliasConfig } = require('./rollup.shared');
27+
2528
const deps = [
2629
...Object.keys(Object.assign({}, pkg.peerDependencies, pkg.dependencies)),
2730
'@firebase/storage'
@@ -59,7 +62,7 @@ const es5Builds = [
5962
sourcemap: true
6063
}
6164
],
62-
plugins: es5BuildPlugins,
65+
plugins: [alias(generateAliasConfig('browser')), ...es5BuildPlugins],
6366
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
6467
treeshake: {
6568
moduleSideEffects: false
@@ -98,7 +101,7 @@ const es2017Builds = [
98101
format: 'es',
99102
sourcemap: true
100103
},
101-
plugins: es2017BuildPlugins,
104+
plugins: [alias(generateAliasConfig('browser')), ...es2017BuildPlugins],
102105
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
103106
treeshake: {
104107
moduleSideEffects: false

packages/storage/rollup.config.exp.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ import json from '@rollup/plugin-json';
1919
import typescriptPlugin from 'rollup-plugin-typescript2';
2020
import typescript from 'typescript';
2121
import pkgExp from './exp/package.json';
22+
import alias from '@rollup/plugin-alias';
2223
import pkg from './package.json';
2324
import path from 'path';
2425
import { importPathTransformer } from '../../scripts/exp/ts-transform-import-path';
2526

27+
const { generateAliasConfig } = require('./rollup.shared');
28+
2629
const deps = [
2730
...Object.keys(Object.assign({}, pkg.peerDependencies, pkg.dependencies)),
2831
'@firebase/app'
@@ -38,14 +41,15 @@ const es5Plugins = [
3841
];
3942

4043
const es5Builds = [
44+
// Browser
4145
{
4246
input: './exp/index.ts',
4347
output: {
4448
file: path.resolve('./exp', pkgExp.esm5),
4549
format: 'es',
4650
sourcemap: true
4751
},
48-
plugins: es5Plugins,
52+
plugins: [alias(generateAliasConfig('browser')), ...es5Plugins],
4953
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
5054
treeshake: {
5155
moduleSideEffects: false
@@ -68,21 +72,30 @@ const es2017Plugins = [
6872
];
6973

7074
const es2017Builds = [
75+
// Node
7176
{
7277
input: './exp/index.ts',
73-
output: [
74-
{
75-
file: path.resolve('./exp', pkgExp.main),
76-
format: 'cjs',
77-
sourcemap: true
78-
},
79-
{
80-
file: path.resolve('./exp', pkgExp.browser),
81-
format: 'es',
82-
sourcemap: true
83-
}
84-
],
85-
plugins: es2017Plugins,
78+
output: {
79+
file: path.resolve('./exp', pkgExp.main),
80+
format: 'cjs',
81+
sourcemap: true
82+
},
83+
plugins: [alias(generateAliasConfig('node')), ...es2017Plugins],
84+
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
85+
treeshake: {
86+
moduleSideEffects: false
87+
}
88+
},
89+
90+
// Browser
91+
{
92+
input: './exp/index.ts',
93+
output: {
94+
file: path.resolve('./exp', pkgExp.browser),
95+
format: 'es',
96+
sourcemap: true
97+
},
98+
plugins: [alias(generateAliasConfig('browser')), ...es2017Plugins],
8699
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
87100
treeshake: {
88101
moduleSideEffects: false

packages/storage/rollup.config.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
import json from '@rollup/plugin-json';
1919
import typescriptPlugin from 'rollup-plugin-typescript2';
2020
import typescript from 'typescript';
21+
import alias from '@rollup/plugin-alias';
2122
import pkg from './package.json';
2223

24+
const { generateAliasConfig } = require('./rollup.shared');
25+
2326
const deps = Object.keys(
2427
Object.assign({}, pkg.peerDependencies, pkg.dependencies)
2528
);
@@ -40,7 +43,7 @@ const es5Builds = [
4043
{ file: pkg.main, format: 'cjs', sourcemap: true },
4144
{ file: pkg.module, format: 'es', sourcemap: true }
4245
],
43-
plugins: es5BuildPlugins,
46+
plugins: [alias(generateAliasConfig('browser')), ...es5BuildPlugins],
4447
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
4548
treeshake: {
4649
moduleSideEffects: false
@@ -71,7 +74,7 @@ const es2017Builds = [
7174
format: 'es',
7275
sourcemap: true
7376
},
74-
plugins: es2017BuildPlugins,
77+
plugins: [alias(generateAliasConfig('browser')), ...es2017BuildPlugins],
7578
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`)),
7679
treeshake: {
7780
moduleSideEffects: false

packages/storage/rollup.shared.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* Returns an replacement configuration for `@rollup/plugin-alias` that replaces
20+
* references to platform-specific files with implementations for the provided
21+
* target platform.
22+
*/
23+
function generateAliasConfig(platform) {
24+
return {
25+
entries: [
26+
{
27+
find: /^(.*)\/platform\/([^.\/]*)(\.ts)?$/,
28+
replacement: `$1\/platform/${platform}/$2.ts`
29+
}
30+
]
31+
};
32+
}
33+
34+
exports.generateAliasConfig = generateAliasConfig;

packages/storage/src/implementation/request.ts

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -132,27 +132,24 @@ class NetworkRequest<T> implements Request<T> {
132132
}
133133

134134
// eslint-disable-next-line @typescript-eslint/no-floating-promises
135-
xhr
136-
.send(self.url_, self.method_, self.body_, self.headers_)
137-
.then((xhr: XhrIo) => {
138-
if (self.progressCallback_ !== null) {
139-
xhr.removeUploadProgressListener(progressListener);
140-
}
141-
self.pendingXhr_ = null;
142-
xhr = xhr as XhrIo;
143-
const hitServer = xhr.getErrorCode() === ErrorCode.NO_ERROR;
144-
const status = xhr.getStatus();
145-
if (!hitServer || self.isRetryStatusCode_(status)) {
146-
const wasCanceled = xhr.getErrorCode() === ErrorCode.ABORT;
147-
backoffCallback(
148-
false,
149-
new RequestEndStatus(false, null, wasCanceled)
150-
);
151-
return;
152-
}
153-
const successCode = self.successCodes_.indexOf(status) !== -1;
154-
backoffCallback(true, new RequestEndStatus(successCode, xhr));
155-
});
135+
xhr.send(self.url_, self.method_, self.body_, self.headers_).then(() => {
136+
if (self.progressCallback_ !== null) {
137+
xhr.removeUploadProgressListener(progressListener);
138+
}
139+
self.pendingXhr_ = null;
140+
const hitServer = xhr.getErrorCode() === ErrorCode.NO_ERROR;
141+
const status = xhr.getStatus();
142+
if (!hitServer || self.isRetryStatusCode_(status)) {
143+
const wasCanceled = xhr.getErrorCode() === ErrorCode.ABORT;
144+
backoffCallback(
145+
false,
146+
new RequestEndStatus(false, null, wasCanceled)
147+
);
148+
return;
149+
}
150+
const successCode = self.successCodes_.indexOf(status) !== -1;
151+
backoffCallback(true, new RequestEndStatus(successCode, xhr));
152+
});
156153
}
157154

158155
/**

packages/storage/src/implementation/requests.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ export function createResumableUpload(
399399
const headers = {
400400
'X-Goog-Upload-Protocol': 'resumable',
401401
'X-Goog-Upload-Command': 'start',
402-
'X-Goog-Upload-Header-Content-Length': blob.size(),
402+
'X-Goog-Upload-Header-Content-Length': `${blob.size()}`,
403403
'X-Goog-Upload-Header-Content-Type': metadataForUpload['contentType']!,
404404
'Content-Type': 'application/json; charset=utf-8'
405405
};
@@ -511,7 +511,7 @@ export function continueResumableUpload(
511511
bytesToUpload === bytesLeft ? 'upload, finalize' : 'upload';
512512
const headers = {
513513
'X-Goog-Upload-Command': uploadCommand,
514-
'X-Goog-Upload-Offset': status_.current
514+
'X-Goog-Upload-Offset': `${status_.current}`
515515
};
516516
const body = blob.slice(startByte, endByte);
517517
if (body === null) {

packages/storage/src/implementation/string.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import { unknown, invalidFormat } from './error';
19+
import { decodeBase64 } from '../platform/base64';
1920

2021
/**
2122
* An enumeration of the possible string formats for upload.
@@ -178,7 +179,7 @@ export function base64Bytes_(format: StringFormat, value: string): Uint8Array {
178179
}
179180
let bytes;
180181
try {
181-
bytes = atob(value);
182+
bytes = decodeBase64(value);
182183
} catch (e) {
183184
throw invalidFormat(format, 'Invalid character found');
184185
}

packages/storage/src/implementation/xhrio.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
* XHR headers
2020
*/
2121
export interface Headers {
22-
[name: string]: string | number;
22+
[name: string]: string;
2323
}
2424

2525
/**
@@ -31,8 +31,8 @@ export interface XhrIo {
3131
url: string,
3232
method: string,
3333
body?: ArrayBufferView | Blob | string | null,
34-
headers?: Headers
35-
): Promise<XhrIo>;
34+
headers?: Record<string, string>
35+
): Promise<void>;
3636

3737
getErrorCode(): ErrorCode;
3838

packages/storage/src/implementation/xhriopool.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
* @fileoverview Replacement for goog.net.XhrIoPool that works with fbs.XhrIo.
2020
*/
2121
import { XhrIo } from './xhrio';
22-
import { NetworkXhrIo } from './xhrio_network';
22+
import { newConnection } from '../platform/connection';
2323

2424
/**
2525
* Factory-like class for creating XhrIo instances.
2626
*/
2727
export class XhrIoPool {
2828
createXhrIo(): XhrIo {
29-
return new NetworkXhrIo();
29+
return newConnection();
3030
}
3131
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
// This file is only used under ts-node.
19+
// eslint-disable-next-line @typescript-eslint/no-require-imports
20+
const platform = require(`./${process.env.TEST_PLATFORM ?? 'node'}/base64`);
21+
22+
/** Converts a Base64 encoded string to a binary string. */
23+
export function decodeBase64(encoded: string): string {
24+
return platform.decodeBase64(encoded);
25+
}

0 commit comments

Comments
 (0)