Skip to content

Commit 252b640

Browse files
authored
feat(storage): Exposed firebase-admin/storage entry point (#1159)
1 parent e758b15 commit 252b640

9 files changed

+142
-40
lines changed

etc/firebase-admin.api.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -748,15 +748,14 @@ export interface ServiceAccount {
748748
}
749749

750750
// @public
751-
export function storage(app?: app.App): storage.Storage;
751+
export function storage(app?: App): storage.Storage;
752752

753753
// @public (undocumented)
754754
export namespace storage {
755-
export interface Storage {
756-
app: app.App;
757-
// (undocumented)
758-
bucket(name?: string): Bucket;
759-
}
755+
// Warning: (ae-forgotten-export) The symbol "Storage" needs to be exported by the entry point default-namespace.d.ts
756+
//
757+
// (undocumented)
758+
export type Storage = Storage;
760759
}
761760

762761

etc/firebase-admin.storage.api.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## API Report File for "firebase-admin.storage"
2+
3+
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4+
5+
```ts
6+
7+
import { Agent } from 'http';
8+
import { Bucket } from '@google-cloud/storage';
9+
10+
// Warning: (ae-forgotten-export) The symbol "App" needs to be exported by the entry point index.d.ts
11+
//
12+
// @public (undocumented)
13+
export function getStorage(app?: App): Storage;
14+
15+
// @public
16+
export class Storage {
17+
get app(): App;
18+
// (undocumented)
19+
bucket(name?: string): Bucket;
20+
}
21+
22+
// @public
23+
export function storage(app?: App): storage.Storage;
24+
25+
// @public (undocumented)
26+
export namespace storage {
27+
// (undocumented)
28+
export type Storage = Storage;
29+
}
30+
31+
32+
// (No @packageDocumentation comment for this package)
33+
34+
```

generate-reports.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const entryPoints = {
4242
'firebase-admin/messaging': './lib/messaging/index.d.ts',
4343
'firebase-admin/project-management': './lib/project-management/index.d.ts',
4444
'firebase-admin/security-rules': './lib/security-rules/index.d.ts',
45+
'firebase-admin/storage': './lib/storage/index.d.ts',
4546
'firebase-admin/remote-config': './lib/remote-config/index.d.ts',
4647
};
4748

gulpfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ gulp.task('compile', function() {
9595
'lib/messaging/*.d.ts',
9696
'lib/project-management/*.d.ts',
9797
'lib/security-rules/*.d.ts',
98+
'lib/storage/*.d.ts',
9899
'lib/remote-config/*.d.ts',
99100
'!lib/utils/index.d.ts',
100101
];

src/app/firebase-app.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { AppErrorCodes, FirebaseAppError } from '../utils/error';
2626
import { Auth } from '../auth/index';
2727
import { MachineLearning } from '../machine-learning/machine-learning';
2828
import { Messaging } from '../messaging/index';
29-
import { Storage } from '../storage/storage';
29+
import { Storage } from '../storage/index';
3030
import { Database } from '../database/index';
3131
import { Firestore } from '../firestore/index';
3232
import { InstanceId } from '../instance-id/index';
@@ -303,10 +303,8 @@ export class FirebaseApp implements app.App {
303303
* @return The Storage service instance of this app.
304304
*/
305305
public storage(): Storage {
306-
return this.ensureService_('storage', () => {
307-
const storageService: typeof Storage = require('../storage/storage').Storage;
308-
return new storageService(this);
309-
});
306+
const fn = require('../storage/index').getStorage;
307+
return fn(this);
310308
}
311309

312310
public firestore(): Firestore {

src/storage/index.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,22 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Bucket } from '@google-cloud/storage';
18-
import { app } from '../firebase-namespace-api';
17+
import { App, getApp } from '../app';
18+
import { FirebaseApp } from '../app/firebase-app';
19+
import { Storage } from './storage';
20+
21+
export { Storage } from './storage';
22+
23+
export function getStorage(app?: App): Storage {
24+
if (typeof app === 'undefined') {
25+
app = getApp();
26+
}
27+
28+
const firebaseApp: FirebaseApp = app as FirebaseApp;
29+
return firebaseApp.getOrInitService('storage', (app) => new Storage(app));
30+
}
31+
32+
import { Storage as TStorage } from './storage';
1933

2034
/**
2135
* Gets the {@link storage.Storage `Storage`} service for the
@@ -39,25 +53,9 @@ import { app } from '../firebase-namespace-api';
3953
* var otherStorage = admin.storage(otherApp);
4054
* ```
4155
*/
42-
export declare function storage(app?: app.App): storage.Storage;
56+
export declare function storage(app?: App): storage.Storage;
4357

4458
/* eslint-disable @typescript-eslint/no-namespace */
4559
export namespace storage {
46-
/**
47-
* The default `Storage` service if no
48-
* app is provided or the `Storage` service associated with the provided
49-
* app.
50-
*/
51-
export interface Storage {
52-
/**
53-
* Optional app whose `Storage` service to
54-
* return. If not provided, the default `Storage` service will be returned.
55-
*/
56-
app: app.App;
57-
/**
58-
* @returns A [Bucket](https://cloud.google.com/nodejs/docs/reference/storage/latest/Bucket)
59-
* instance as defined in the `@google-cloud/storage` package.
60-
*/
61-
bucket(name?: string): Bucket;
62-
}
60+
export type Storage = TStorage;
6361
}

src/storage/storage.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,29 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { FirebaseApp } from '../app/firebase-app';
18+
import { App } from '../app';
1919
import { FirebaseError } from '../utils/error';
2020
import { ServiceAccountCredential, isApplicationDefault } from '../app/credential-internal';
2121
import { Bucket, Storage as StorageClient } from '@google-cloud/storage';
2222
import * as utils from '../utils/index';
2323
import * as validator from '../utils/validator';
24-
import { storage } from './index';
25-
26-
import StorageInterface = storage.Storage;
2724

2825
/**
2926
* The default `Storage` service if no
3027
* app is provided or the `Storage` service associated with the provided
3128
* app.
3229
*/
33-
export class Storage implements StorageInterface {
30+
export class Storage {
3431

35-
private readonly appInternal: FirebaseApp;
32+
private readonly appInternal: App;
3633
private readonly storageClient: StorageClient;
3734

3835
/**
39-
* @param {FirebaseApp} app The app for this Storage service.
36+
* @param app The app for this Storage service.
4037
* @constructor
4138
* @internal
4239
*/
43-
constructor(app: FirebaseApp) {
40+
constructor(app: App) {
4441
if (!validator.isNonNullObject(app) || !('options' in app)) {
4542
throw new FirebaseError({
4643
code: 'storage/invalid-argument',
@@ -109,7 +106,7 @@ export class Storage implements StorageInterface {
109106
/**
110107
* @return The app associated with this Storage instance.
111108
*/
112-
get app(): FirebaseApp {
109+
get app(): App {
113110
return this.appInternal;
114111
}
115112
}

test/unit/index.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import './machine-learning/machine-learning-api-client.spec';
5656

5757
// Storage
5858
import './storage/storage.spec';
59+
import './storage/index.spec';
5960

6061
// Firestore
6162
import './firestore/firestore.spec';

test/unit/storage/index.spec.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*!
2+
* @license
3+
* Copyright 2021 Google Inc.
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+
'use strict';
19+
20+
import * as chai from 'chai';
21+
import * as sinonChai from 'sinon-chai';
22+
import * as chaiAsPromised from 'chai-as-promised';
23+
24+
import * as mocks from '../../resources/mocks';
25+
import { App } from '../../../src/app/index';
26+
import { getStorage, Storage } from '../../../src/storage/index';
27+
28+
chai.should();
29+
chai.use(sinonChai);
30+
chai.use(chaiAsPromised);
31+
32+
const expect = chai.expect;
33+
34+
describe('Storage', () => {
35+
let mockApp: App;
36+
let mockCredentialApp: App;
37+
38+
const noProjectIdError = 'Failed to initialize Google Cloud Storage client with the '
39+
+ 'available credential. Must initialize the SDK with a certificate credential or '
40+
+ 'application default credentials to use Cloud Storage API.';
41+
42+
beforeEach(() => {
43+
mockApp = mocks.app();
44+
mockCredentialApp = mocks.mockCredentialApp();
45+
});
46+
47+
describe('getStorage()', () => {
48+
it('should throw when default app is not available', () => {
49+
expect(() => {
50+
return getStorage();
51+
}).to.throw('The default Firebase app does not exist.');
52+
});
53+
54+
it('should reject given an invalid credential without project ID', () => {
55+
// Project ID not set in the environment.
56+
delete process.env.GOOGLE_CLOUD_PROJECT;
57+
delete process.env.GCLOUD_PROJECT;
58+
expect(() => getStorage(mockCredentialApp)).to.throw(noProjectIdError);
59+
});
60+
61+
it('should not throw given a valid app', () => {
62+
expect(() => {
63+
return getStorage(mockApp);
64+
}).not.to.throw();
65+
});
66+
67+
it('should return the same instance for a given app instance', () => {
68+
const storage1: Storage = getStorage(mockApp);
69+
const storage2: Storage = getStorage(mockApp);
70+
expect(storage1).to.equal(storage2);
71+
});
72+
});
73+
});

0 commit comments

Comments
 (0)