diff --git a/gulpfile.js b/gulpfile.js index 1dc9445125..ab23375bd5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -55,6 +55,7 @@ var paths = { curatedTypings: [ 'src/*.d.ts', '!src/instance-id.d.ts', + '!src/security-rules.d.ts', '!src/project-management.d.ts' ], }; @@ -70,7 +71,6 @@ const TEMPORARY_TYPING_EXCLUDES = [ '!lib/machine-learning/*.d.ts', '!lib/messaging/*.d.ts', '!lib/remote-config/*.d.ts', - '!lib/security-rules/*.d.ts', '!lib/storage/*.d.ts', '!lib/utils/*.d.ts' ]; diff --git a/src/security-rules/index.ts b/src/security-rules/index.ts new file mode 100644 index 0000000000..ecdae9d8f5 --- /dev/null +++ b/src/security-rules/index.ts @@ -0,0 +1,47 @@ +/*! + * Copyright 2020 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FirebaseApp } from '../firebase-app'; +import * as securityRulesApi from './security-rules'; +import * as firebaseAdmin from '../index'; + +export function securityRules(app?: FirebaseApp): securityRulesApi.SecurityRules { + if (typeof(app) === 'undefined') { + app = firebaseAdmin.app(); + } + return app.securityRules(); +} + +/** + * We must define a namespace to make the typings work correctly. Otherwise + * `admin.securityRules()` cannot be called like a function. Temporarily, + * admin.securityRules is used as the namespace name because we cannot barrel + * re-export the contents from security-rules, and we want it to + * match the namespacing in the re-export inside src/index.d.ts + */ +/* eslint-disable @typescript-eslint/no-namespace */ +export namespace admin.securityRules { + // See https://github.com/microsoft/TypeScript/issues/4336 + /* eslint-disable @typescript-eslint/no-unused-vars */ + // See https://github.com/typescript-eslint/typescript-eslint/issues/363 + export import RulesFile = securityRulesApi.RulesFile; + export import RulesetMetadata = securityRulesApi.RulesetMetadata; + export import RulesetMetadataList = securityRulesApi.RulesetMetadataList; + + /* eslint-disable @typescript-eslint/no-empty-interface */ + export interface Ruleset extends securityRulesApi.Ruleset {} + export interface SecurityRules extends securityRulesApi.SecurityRules {} +} diff --git a/src/security-rules/security-rules-api-client.ts b/src/security-rules/security-rules-api-client-internal.ts similarity index 99% rename from src/security-rules/security-rules-api-client.ts rename to src/security-rules/security-rules-api-client-internal.ts index 5048113825..50fdbc9cb8 100644 --- a/src/security-rules/security-rules-api-client.ts +++ b/src/security-rules/security-rules-api-client-internal.ts @@ -16,7 +16,7 @@ import { HttpRequestConfig, HttpClient, HttpError, AuthorizedHttpClient } from '../utils/api-request'; import { PrefixedFirebaseError } from '../utils/error'; -import { FirebaseSecurityRulesError, SecurityRulesErrorCode } from './security-rules-utils'; +import { FirebaseSecurityRulesError, SecurityRulesErrorCode } from './security-rules-internal'; import * as utils from '../utils/index'; import * as validator from '../utils/validator'; import { FirebaseApp } from '../firebase-app'; diff --git a/src/security-rules/security-rules-utils.ts b/src/security-rules/security-rules-internal.ts similarity index 100% rename from src/security-rules/security-rules-utils.ts rename to src/security-rules/security-rules-internal.ts diff --git a/src/security-rules/security-rules.ts b/src/security-rules/security-rules.ts index 21da0eabab..89eda3825f 100644 --- a/src/security-rules/security-rules.ts +++ b/src/security-rules/security-rules.ts @@ -19,11 +19,14 @@ import { FirebaseApp } from '../firebase-app'; import * as validator from '../utils/validator'; import { SecurityRulesApiClient, RulesetResponse, RulesetContent, ListRulesetsResponse, -} from './security-rules-api-client'; -import { FirebaseSecurityRulesError } from './security-rules-utils'; +} from './security-rules-api-client-internal'; +import { FirebaseSecurityRulesError } from './security-rules-internal'; /** - * A source file containing some Firebase security rules. + * A source file containing some Firebase security rules. The content includes raw + * source code including text formatting, indentation and comments. Use the + * [`securityRules.createRulesFileFromSource()`](admin.securityRules.SecurityRules#createRulesFileFromSource) + * method to create new instances of this type. */ export interface RulesFile { readonly name: string; @@ -31,10 +34,18 @@ export interface RulesFile { } /** - * Additional metadata associated with a Ruleset. + * Required metadata associated with a ruleset. */ export interface RulesetMetadata { + /** + * Name of the `Ruleset` as a short string. This can be directly passed into APIs + * like [`securityRules.getRuleset()`](admin.securityRules.SecurityRules#getRuleset) + * and [`securityRules.deleteRuleset()`](admin.securityRules.SecurityRules#deleteRuleset). + */ readonly name: string; + /** + * Creation time of the `Ruleset` as a UTC timestamp string. + */ readonly createTime: string; } @@ -42,7 +53,13 @@ export interface RulesetMetadata { * A page of ruleset metadata. */ export interface RulesetMetadataList { + /** + * A batch of ruleset metadata. + */ readonly rulesets: RulesetMetadata[]; + /** + * The next page token if available. This is needed to retrieve the next batch. + */ readonly nextPageToken?: string; } @@ -97,7 +114,10 @@ export class Ruleset implements RulesetMetadata { } /** - * SecurityRules service bound to the provided app. + * The Firebase `SecurityRules` service interface. + * + * Do not call this constructor directly. Instead, use + * [`admin.securityRules()`](admin.securityRules#securityRules). */ export class SecurityRules implements FirebaseServiceInterface { @@ -235,12 +255,21 @@ export class SecurityRules implements FirebaseServiceInterface { } /** - * Creates a `RulesFile` with the given name and source. Throws if any of the arguments are invalid. This is a - * local operation, and does not involve any network API calls. + * Creates a {@link admin.securityRules.RulesFile `RuleFile`} with the given name + * and source. Throws an error if any of the arguments are invalid. This is a local + * operation, and does not involve any network API calls. * - * @param {string} name Name to assign to the rules file. - * @param {string|Buffer} source Contents of the rules file. - * @returns {RulesFile} A new rules file instance. + * @example + * ```javascript + * const source = '// Some rules source'; + * const rulesFile = admin.securityRules().createRulesFileFromSource( + * 'firestore.rules', source); + * ``` + * + * @param name Name to assign to the rules file. This is usually a short file name that + * helps identify the file in a ruleset. + * @param source Contents of the rules file. + * @return A new rules file instance. */ public createRulesFileFromSource(name: string, source: string | Buffer): RulesFile { if (!validator.isNonEmptyString(name)) { @@ -265,10 +294,11 @@ export class SecurityRules implements FirebaseServiceInterface { } /** - * Creates a new `Ruleset` from the given `RulesFile`. + * Creates a new {@link admin.securityRules.Ruleset `Ruleset`} from the given + * {@link admin.securityRules.RulesFile `RuleFile`}. * - * @param {RulesFile} file Rules file to include in the new Ruleset. - * @returns {Promise} A promise that fulfills with the newly created Ruleset. + * @param file Rules file to include in the new `Ruleset`. + * @returns A promise that fulfills with the newly created `Ruleset`. */ public createRuleset(file: RulesFile): Promise { const ruleset: RulesetContent = { @@ -284,24 +314,27 @@ export class SecurityRules implements FirebaseServiceInterface { } /** - * Deletes the Ruleset identified by the given name. The input name should be the short name string without - * the project ID prefix. For example, to delete the `projects/project-id/rulesets/my-ruleset`, pass the - * short name "my-ruleset". Rejects with a `not-found` error if the specified Ruleset cannot be found. + * Deletes the {@link admin.securityRules.Ruleset `Ruleset`} identified by the given + * name. The input name should be the short name string without the project ID + * prefix. For example, to delete the `projects/project-id/rulesets/my-ruleset`, + * pass the short name "my-ruleset". Rejects with a `not-found` error if the + * specified `Ruleset` cannot be found. * - * @param {string} name Name of the Ruleset to delete. - * @returns {Promise} A promise that fulfills when the Ruleset is deleted. + * @param name Name of the `Ruleset` to delete. + * @return A promise that fulfills when the `Ruleset` is deleted. */ public deleteRuleset(name: string): Promise { return this.client.deleteRuleset(name); } /** - * Retrieves a page of rulesets. + * Retrieves a page of ruleset metadata. * - * @param {number=} pageSize The page size, 100 if undefined. This is also the maximum allowed limit. - * @param {string=} nextPageToken The next page token. If not specified, returns rulesets starting - * without any offset. - * @returns {Promise} A promise that fulfills a page of rulesets. + * @param pageSize The page size, 100 if undefined. This is also the maximum allowed + * limit. + * @param nextPageToken The next page token. If not specified, returns rulesets + * starting without any offset. + * @return A promise that fulfills with a page of rulesets. */ public listRulesetMetadata(pageSize = 100, nextPageToken?: string): Promise { return this.client.listRulesets(pageSize, nextPageToken) diff --git a/test/unit/security-rules/security-rules-api-client.spec.ts b/test/unit/security-rules/security-rules-api-client.spec.ts index 81b4472dc2..3a3c37a892 100644 --- a/test/unit/security-rules/security-rules-api-client.spec.ts +++ b/test/unit/security-rules/security-rules-api-client.spec.ts @@ -19,8 +19,8 @@ import * as _ from 'lodash'; import * as chai from 'chai'; import * as sinon from 'sinon'; -import { SecurityRulesApiClient, RulesetContent } from '../../../src/security-rules/security-rules-api-client'; -import { FirebaseSecurityRulesError } from '../../../src/security-rules/security-rules-utils'; +import { SecurityRulesApiClient, RulesetContent } from '../../../src/security-rules/security-rules-api-client-internal'; +import { FirebaseSecurityRulesError } from '../../../src/security-rules/security-rules-internal'; import { HttpClient } from '../../../src/utils/api-request'; import * as utils from '../utils'; import * as mocks from '../../resources/mocks'; diff --git a/test/unit/security-rules/security-rules.spec.ts b/test/unit/security-rules/security-rules.spec.ts index 8946d1d685..fd81fa7fd2 100644 --- a/test/unit/security-rules/security-rules.spec.ts +++ b/test/unit/security-rules/security-rules.spec.ts @@ -22,8 +22,8 @@ import * as sinon from 'sinon'; import { SecurityRules } from '../../../src/security-rules/security-rules'; import { FirebaseApp } from '../../../src/firebase-app'; import * as mocks from '../../resources/mocks'; -import { SecurityRulesApiClient, RulesetContent } from '../../../src/security-rules/security-rules-api-client'; -import { FirebaseSecurityRulesError } from '../../../src/security-rules/security-rules-utils'; +import { SecurityRulesApiClient, RulesetContent } from '../../../src/security-rules/security-rules-api-client-internal'; +import { FirebaseSecurityRulesError } from '../../../src/security-rules/security-rules-internal'; import { deepCopy } from '../../../src/utils/deep-copy'; const expect = chai.expect;