Skip to content

Commit ae034f6

Browse files
Merge master into release
2 parents 1ff9a1f + 5edd81f commit ae034f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+702
-151
lines changed

.changeset/late-ducks-invite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'firebase': patch
3+
---
4+
5+
Add installations CDN build and entry point.

.changeset/metal-spies-shave.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@firebase/database": patch
3+
"@firebase/util": patch
4+
---
5+
6+
Forced `get()` to wait until db is online to resolve.

.changeset/shiny-bats-reflect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/analytics': minor
3+
---
4+
5+
Add function `setConsent()` to set the applicable end user "consent" state.

.changeset/silly-panthers-mix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/analytics': minor
3+
---
4+
5+
Add function `setDefaultEventParameters()` to set data that will be logged on every Analytics SDK event

.changeset/tiny-donuts-draw.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/functions': patch
3+
---
4+
5+
Update public `FunctionsErrorCode` type to include "functions/" prefix.

.changeset/witty-windows-unite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@firebase/auth": patch
3+
---
4+
5+
Update user agent detection to better detect iPad; fixes bug for some iPad devices running Cordova apps

.github/CODEOWNERS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# - @lahirumaramba
1717
# - @hsubox76
1818
# - @allspain
19+
# - @dwyfrequency
1920

2021

2122
# ===========================================================
@@ -32,7 +33,7 @@
3233

3334

3435
# These owners will be the default owners for everything in the repo.
35-
* @allspain @hsubox76 @firebase/jssdk-global-approvers
36+
* @dwyfrequency @hsubox76 @firebase/jssdk-global-approvers
3637

3738
# Database Code
3839
packages/database @maneesht @jsdt @firebase/jssdk-global-approvers

.github/workflows/health-metrics-pull-request.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
name: Health Metrics
22

3-
on: [push, pull_request]
3+
on:
4+
push:
5+
branches: ['**']
6+
pull_request:
47

58
env:
69
GITHUB_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}

.github/workflows/release-pr.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
release:
1111
name: Create Release PR
1212
runs-on: ubuntu-latest
13+
if: ${{ !startsWith(github.event.head_commit.message, 'Version Packages (#') }}
1314
steps:
1415
- name: Checkout Repo
1516
uses: actions/checkout@master

.github/workflows/release-prod.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
# Release script requires git history and tags.
2222
fetch-depth: 0
2323
ref: release
24+
token: ${{ secrets.OSS_BOT_GITHUB_TOKEN }}
2425
- name: Yarn install
2526
run: yarn
2627
- name: Publish to NPM
@@ -31,7 +32,6 @@ jobs:
3132
# TODO: Make these flags defaults in the release script.
3233
run: yarn release --releaseType Production --ci --skipTests --skipReinstall --ignoreUnstaged
3334
env:
34-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3535
NPM_TOKEN_ANALYTICS: ${{secrets.NPM_TOKEN_ANALYTICS}}
3636
NPM_TOKEN_ANALYTICS_INTEROP_TYPES: ${{secrets.NPM_TOKEN_ANALYTICS_INTEROP_TYPES}}
3737
NPM_TOKEN_ANALYTICS_TYPES: ${{secrets.NPM_TOKEN_ANALYTICS_TYPES}}

.github/workflows/test-all.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
name: Test All Packages
22

3-
on: push
3+
on:
4+
push:
5+
branches: ['**']
6+
47
env:
58
# make chromedriver detect installed Chrome version and download the corresponding driver
69
DETECT_CHROMEDRIVER_VERSION: true

common/api-review/analytics.api.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ export interface AnalyticsSettings {
2121
config?: GtagConfigParams | EventParams;
2222
}
2323

24+
// @public
25+
export interface ConsentSettings {
26+
// (undocumented)
27+
[key: string]: unknown;
28+
ad_storage?: ConsentStatusString;
29+
analytics_storage?: ConsentStatusString;
30+
functionality_storage?: ConsentStatusString;
31+
personalization_storage?: ConsentStatusString;
32+
security_storage?: ConsentStatusString;
33+
}
34+
35+
// @public
36+
export type ConsentStatusString = 'granted' | 'denied';
37+
2438
// @public
2539
export interface ControlParams {
2640
// (undocumented)
@@ -388,9 +402,15 @@ export interface Promotion {
388402
// @public
389403
export function setAnalyticsCollectionEnabled(analyticsInstance: Analytics, enabled: boolean): void;
390404

405+
// @public
406+
export function setConsent(consentSettings: ConsentSettings): void;
407+
391408
// @public @deprecated
392409
export function setCurrentScreen(analyticsInstance: Analytics, screenName: string, options?: AnalyticsCallOptions): void;
393410

411+
// @public
412+
export function setDefaultEventParameters(customParams: CustomParams): void;
413+
394414
// @public
395415
export function settings(options: SettingsOptions): void;
396416

common/api-review/functions.api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ export interface FunctionsError extends FirebaseError {
2424
}
2525

2626
// @public
27-
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';
27+
export type FunctionsErrorCode = `functions/${FunctionsErrorCodeCore}`;
28+
29+
// @public
30+
export type FunctionsErrorCodeCore = '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';
2831

2932
// @public
3033
export function getFunctions(app?: FirebaseApp, regionOrCustomDomain?: string): Functions;

common/api-review/util.api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,11 @@ export function ordinal(i: number): string;
346346
// @public (undocumented)
347347
export type PartialObserver<T> = Partial<Observer<T>>;
348348

349+
// Warning: (ae-internal-missing-underscore) The name "promiseWithTimeout" should be prefixed with an underscore because the declaration is marked as @internal
350+
//
351+
// @internal
352+
export function promiseWithTimeout<T>(promise: Promise<T>, timeInMS?: number): Promise<T>;
353+
349354
// Warning: (ae-missing-release-tag) "querystring" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
350355
//
351356
// @public

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@
136136
"mocha": "9.2.2",
137137
"mz": "2.7.0",
138138
"npm-run-all": "4.1.5",
139-
"npm-run-path": "4.0.1",
140139
"nyc": "15.1.0",
141140
"ora": "5.4.1",
142141
"prettier": "2.6.2",

packages/analytics/src/api.test.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,27 @@ import { expect } from 'chai';
1919
import { SinonStub, stub } from 'sinon';
2020
import '../testing/setup';
2121
import { getFullApp } from '../testing/get-fake-firebase-services';
22-
import { getAnalytics, initializeAnalytics } from './api';
22+
import {
23+
getAnalytics,
24+
initializeAnalytics,
25+
setConsent,
26+
setDefaultEventParameters
27+
} from './api';
2328
import { FirebaseApp, deleteApp } from '@firebase/app';
2429
import { AnalyticsError } from './errors';
2530
import * as init from './initialize-analytics';
2631
const fakeAppParams = { appId: 'abcdefgh12345:23405', apiKey: 'AAbbCCdd12345' };
32+
import * as factory from './factory';
33+
import {
34+
defaultConsentSettingsForInit,
35+
defaultEventParametersForInit
36+
} from './functions';
37+
import { ConsentSettings } from './public-types';
2738

2839
describe('FirebaseAnalytics API tests', () => {
2940
let initStub: SinonStub = stub();
3041
let app: FirebaseApp;
42+
const wrappedGtag: SinonStub = stub();
3143

3244
beforeEach(() => {
3345
initStub = stub(init, '_initializeAnalytics').resolves(
@@ -94,4 +106,52 @@ describe('FirebaseAnalytics API tests', () => {
94106
const analyticsInstance = initializeAnalytics(app);
95107
expect(getAnalytics(app)).to.equal(analyticsInstance);
96108
});
109+
it('setDefaultEventParameters() updates defaultEventParametersForInit if gtag does not exist ', () => {
110+
const eventParametersForInit = {
111+
'github_user': 'dwyfrequency',
112+
'company': 'google'
113+
};
114+
app = getFullApp(fakeAppParams);
115+
setDefaultEventParameters(eventParametersForInit);
116+
expect(defaultEventParametersForInit).to.deep.equal(eventParametersForInit);
117+
});
118+
it('setDefaultEventParameters() calls gtag set if wrappedGtagFunction exists', () => {
119+
const eventParametersForInit = {
120+
'github_user': 'dwyfrequency',
121+
'company': 'google'
122+
};
123+
stub(factory, 'wrappedGtagFunction').get(() => wrappedGtag);
124+
app = getFullApp(fakeAppParams);
125+
setDefaultEventParameters(eventParametersForInit);
126+
expect(wrappedGtag).to.have.been.calledWithExactly(
127+
'set',
128+
eventParametersForInit
129+
);
130+
});
131+
it('setConsent() updates defaultConsentSettingsForInit if gtag does not exist ', () => {
132+
const consentParametersForInit: ConsentSettings = {
133+
'analytics_storage': 'granted',
134+
'functionality_storage': 'denied'
135+
};
136+
stub(factory, 'wrappedGtagFunction').get(() => undefined);
137+
app = getFullApp(fakeAppParams);
138+
setConsent(consentParametersForInit);
139+
expect(defaultConsentSettingsForInit).to.deep.equal(
140+
consentParametersForInit
141+
);
142+
});
143+
it('setConsent() calls gtag consent "update" if wrappedGtagFunction exists', () => {
144+
const consentParametersForInit: ConsentSettings = {
145+
'analytics_storage': 'granted',
146+
'functionality_storage': 'denied'
147+
};
148+
stub(factory, 'wrappedGtagFunction').get(() => wrappedGtag);
149+
app = getFullApp(fakeAppParams);
150+
setConsent(consentParametersForInit);
151+
expect(wrappedGtag).to.have.been.calledWithExactly(
152+
'consent',
153+
'update',
154+
consentParametersForInit
155+
);
156+
});
97157
});

packages/analytics/src/api.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
Analytics,
2323
AnalyticsCallOptions,
2424
AnalyticsSettings,
25+
ConsentSettings,
2526
CustomParams,
2627
EventNameString,
2728
EventParams
@@ -35,7 +36,7 @@ import {
3536
getModularInstance,
3637
deepEqual
3738
} from '@firebase/util';
38-
import { ANALYTICS_TYPE } from './constants';
39+
import { ANALYTICS_TYPE, GtagCommand } from './constants';
3940
import {
4041
AnalyticsService,
4142
initializationPromisesMap,
@@ -47,7 +48,9 @@ import {
4748
setCurrentScreen as internalSetCurrentScreen,
4849
setUserId as internalSetUserId,
4950
setUserProperties as internalSetUserProperties,
50-
setAnalyticsCollectionEnabled as internalSetAnalyticsCollectionEnabled
51+
setAnalyticsCollectionEnabled as internalSetAnalyticsCollectionEnabled,
52+
_setConsentDefaultForInit,
53+
_setDefaultEventParametersForInit
5154
} from './functions';
5255
import { ERROR_FACTORY, AnalyticsError } from './errors';
5356

@@ -224,6 +227,23 @@ export function setAnalyticsCollectionEnabled(
224227
enabled
225228
).catch(e => logger.error(e));
226229
}
230+
231+
/**
232+
* Adds data that will be set on every event logged from the SDK, including automatic ones.
233+
* With gtag's "set" command, the values passed persist on the current page and are passed with
234+
* all subsequent events.
235+
* @public
236+
* @param customParams - Any custom params the user may pass to gtag.js.
237+
*/
238+
export function setDefaultEventParameters(customParams: CustomParams): void {
239+
// Check if reference to existing gtag function on window object exists
240+
if (wrappedGtagFunction) {
241+
wrappedGtagFunction(GtagCommand.SET, customParams);
242+
} else {
243+
_setDefaultEventParametersForInit(customParams);
244+
}
245+
}
246+
227247
/**
228248
* Sends a Google Analytics event with given `eventParams`. This method
229249
* automatically associates this logged event with this Firebase web
@@ -716,3 +736,21 @@ export function logEvent(
716736
* @public
717737
*/
718738
export type CustomEventName<T> = T extends EventNameString ? never : T;
739+
740+
/**
741+
* Sets the applicable end user consent state for this web app across all gtag references once
742+
* Firebase Analytics is initialized.
743+
*
744+
* Use the {@link ConsentSettings} to specify individual consent type values. By default consent
745+
* types are set to "granted".
746+
* @public
747+
* @param consentSettings - Maps the applicable end user consent state for gtag.js.
748+
*/
749+
export function setConsent(consentSettings: ConsentSettings): void {
750+
// Check if reference to existing gtag function on window object exists
751+
if (wrappedGtagFunction) {
752+
wrappedGtagFunction(GtagCommand.CONSENT, 'update', consentSettings);
753+
} else {
754+
_setConsentDefaultForInit(consentSettings);
755+
}
756+
}

packages/analytics/src/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ export const GTAG_URL = 'https://www.googletagmanager.com/gtag/js';
3434
export const enum GtagCommand {
3535
EVENT = 'event',
3636
SET = 'set',
37-
CONFIG = 'config'
37+
CONFIG = 'config',
38+
CONSENT = 'consent'
3839
}

packages/analytics/src/functions.test.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ import {
2323
logEvent,
2424
setUserId,
2525
setUserProperties,
26-
setAnalyticsCollectionEnabled
26+
setAnalyticsCollectionEnabled,
27+
defaultEventParametersForInit,
28+
_setDefaultEventParametersForInit,
29+
_setConsentDefaultForInit,
30+
defaultConsentSettingsForInit
2731
} from './functions';
2832
import { GtagCommand } from './constants';
33+
import { ConsentSettings } from './public-types';
2934

3035
const fakeMeasurementId = 'abcd-efgh-ijkl';
3136
const fakeInitializationPromise = Promise.resolve(fakeMeasurementId);
@@ -170,4 +175,46 @@ describe('FirebaseAnalytics methods', () => {
170175
expect(window[`ga-disable-${fakeMeasurementId}`]).to.be.true;
171176
delete window[`ga-disable-${fakeMeasurementId}`];
172177
});
178+
it('_setDefaultEventParametersForInit() stores individual params correctly', async () => {
179+
const eventParametersForInit = {
180+
'github_user': 'dwyfrequency',
181+
'company': 'google'
182+
};
183+
_setDefaultEventParametersForInit(eventParametersForInit);
184+
expect(defaultEventParametersForInit).to.deep.equal(eventParametersForInit);
185+
});
186+
it('_setDefaultEventParametersForInit() replaces previous params with new params', async () => {
187+
const eventParametersForInit = {
188+
'github_user': 'dwyfrequency',
189+
'company': 'google'
190+
};
191+
const additionalParams = { 'food': 'sushi' };
192+
_setDefaultEventParametersForInit(eventParametersForInit);
193+
_setDefaultEventParametersForInit(additionalParams);
194+
expect(defaultEventParametersForInit).to.deep.equal({
195+
...additionalParams
196+
});
197+
});
198+
it('_setConsentDefaultForInit() stores individual params correctly', async () => {
199+
const consentParametersForInit: ConsentSettings = {
200+
'analytics_storage': 'granted',
201+
'functionality_storage': 'denied'
202+
};
203+
_setConsentDefaultForInit(consentParametersForInit);
204+
expect(defaultConsentSettingsForInit).to.deep.equal(
205+
consentParametersForInit
206+
);
207+
});
208+
it('_setConsentDefaultForInit() replaces previous params with new params', async () => {
209+
const consentParametersForInit: ConsentSettings = {
210+
'analytics_storage': 'granted',
211+
'functionality_storage': 'denied'
212+
};
213+
const additionalParams = { 'wait_for_update': 500 };
214+
_setConsentDefaultForInit(consentParametersForInit);
215+
_setConsentDefaultForInit(additionalParams);
216+
expect(defaultConsentSettingsForInit).to.deep.equal({
217+
...additionalParams
218+
});
219+
});
173220
});

0 commit comments

Comments
 (0)