Skip to content

Commit 245c9ae

Browse files
committed
Merge branch 'release-v4.0.0-pre.1' into release
2 parents c138e71 + 9166152 commit 245c9ae

File tree

18 files changed

+263
-71
lines changed

18 files changed

+263
-71
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
# Unreleased changes
22

3-
[Full changelog](https://github.com/mozilla/glean.js/compare/v4.0.0-pre.0...main)
3+
[Full changelog](https://github.com/mozilla/glean.js/compare/v4.0.0-pre.1...main)
4+
5+
# v4.0.0-pre.1 (2023-12-01)
6+
7+
[Full changelog](https://github.com/mozilla/glean.js/compare/v4.0.0-pre.0...v4.0.0-pre.1)
8+
9+
[#1834](https://github.com/mozilla/glean.js/pull/1834): Added support for `navigator.sendBeacon`. This is not turned on by default and needs to be enabled manually.
410

511
# v4.0.0-pre.0 (2023-11-27)
612

713
[Full changelog](https://github.com/mozilla/glean.js/compare/v3.0.0...v4.0.0-pre.0)
814

15+
[#1808](https://github.com/mozilla/glean.js/pull/1808): **BREAKING CHANGE**: Make glean.js fully synchronous.
16+
917
# v3.0.0 (2023-11-16)
1018

1119
[Full changelog](https://github.com/mozilla/glean.js/compare/v3.0.0-pre.1...v3.0.0)

glean/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glean/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mozilla/glean",
3-
"version": "4.0.0-pre.0",
3+
"version": "4.0.0-pre.1",
44
"description": "An implementation of the Glean SDK, a modern cross-platform telemetry client, for JavaScript environments.",
55
"type": "module",
66
"sideEffects": false,

glean/src/core/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const GLEAN_SCHEMA_VERSION = 1;
88
//
99
// PACKAGE_VERSION is defined as a global by webpack,
1010
// we need a default here for testing when the app is not build with webpack.
11-
export const GLEAN_VERSION = "4.0.0-pre.0";
11+
export const GLEAN_VERSION = "4.0.0-pre.1";
1212

1313
// The name of a "ping" that will include Glean ping_info metrics,
1414
// such as ping sequence numbers.

glean/src/core/glean.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ namespace Glean {
268268
Context.applicationId = sanitizeApplicationId(applicationId);
269269

270270
// The configuration constructor will throw in case config has any incorrect prop.
271-
const correctConfig = new Configuration(config);
272-
Context.config = correctConfig;
271+
Context.config = new Configuration(config);
273272

274273
// Pre-set debug options for Glean from browser SessionStorage values.
275274
setDebugOptionsFromSessionStorage();
@@ -283,7 +282,7 @@ namespace Glean {
283282
Context.pingsDatabase = new PingsDatabase();
284283
Context.errorManager = new ErrorManager();
285284

286-
pingUploader = new PingUploadManager(correctConfig, Context.pingsDatabase);
285+
pingUploader = new PingUploadManager(Context.config, Context.pingsDatabase);
287286

288287
Context.initialized = true;
289288

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
// Error to be thrown in case the final ping body is larger than MAX_PING_BODY_SIZE.
6+
export class PingBodyOverflowError extends Error {
7+
constructor(message?: string) {
8+
super(message);
9+
this.name = "PingBodyOverflow";
10+
}
11+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { gzipSync, strToU8 } from "fflate";
6+
import { PingBodyOverflowError } from "./ping_body_overflow_error.js";
7+
8+
/**
9+
* Represents a payload to be transmitted by an uploading mechanism.
10+
*/
11+
export default class PingRequest<BodyType extends string | Uint8Array> {
12+
constructor (
13+
readonly identifier: string,
14+
readonly headers: Record<string, string>,
15+
readonly payload: BodyType,
16+
readonly maxBodySize: number
17+
) {}
18+
19+
asCompressedPayload(): PingRequest<string | Uint8Array> {
20+
// If this is already gzipped, do nothing.
21+
if (this.headers["Content-Encoding"] == "gzip") {
22+
return this;
23+
}
24+
25+
// We prefer using `strToU8` instead of TextEncoder directly,
26+
// because it will polyfill TextEncoder if it's not present in the environment.
27+
// For example, IE doesn't provide TextEncoder.
28+
const encodedBody = strToU8(this.payload as string);
29+
30+
let finalBody: string | Uint8Array;
31+
const headers = this.headers;
32+
try {
33+
finalBody = gzipSync(encodedBody);
34+
headers["Content-Encoding"] = "gzip";
35+
headers["Content-Length"] = finalBody.length.toString();
36+
} catch {
37+
// Fall back to whatever we had.
38+
return this;
39+
}
40+
41+
if (finalBody.length > this.maxBodySize) {
42+
throw new PingBodyOverflowError(
43+
`Body for ping ${this.identifier} exceeds ${this.maxBodySize} bytes. Discarding.`
44+
);
45+
}
46+
47+
return new PingRequest<string | Uint8Array>(this.identifier, headers, finalBody, this.maxBodySize);
48+
}
49+
}
50+

glean/src/core/upload/uploader.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
import type PingRequest from "./ping_request.js";
6+
57
// The timeout, in milliseconds, to use for all operations with the server.
68
export const DEFAULT_UPLOAD_TIMEOUT_MS = 10_000;
79

@@ -51,7 +53,14 @@ export abstract class Uploader {
5153
* @param headers Optional headers to include in the request
5254
* @returns The status code of the response.
5355
*/
54-
abstract post(url: string, body: string | Uint8Array, headers?: Record<string, string>): Promise<UploadResult>;
56+
abstract post(url: string, pingRequest: PingRequest<string | Uint8Array>): Promise<UploadResult>;
57+
58+
/**
59+
* Whether or not this uploader supports submitting custom headers.
60+
*
61+
* @returns whether or not custom headers are supported.
62+
*/
63+
abstract supportsCustomHeaders(): boolean;
5564
}
5665

5766
export default Uploader;

glean/src/core/upload/worker.ts

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
import { gzipSync, strToU8 } from "fflate";
6-
75
import type { QueuedPing } from "./manager.js";
86
import type Uploader from "./uploader.js";
97
import type { UploadTask } from "./task.js";
@@ -14,17 +12,11 @@ import Policy from "./policy.js";
1412
import { UploadResult, UploadResultStatus } from "./uploader.js";
1513
import { UploadTaskTypes } from "./task.js";
1614
import { GLEAN_VERSION } from "../constants.js";
15+
import { PingBodyOverflowError } from "./ping_body_overflow_error.js";
16+
import PingRequest from "./ping_request.js";
1717

1818
const PING_UPLOAD_WORKER_LOG_TAG = "core.Upload.PingUploadWorker";
1919

20-
// Error to be thrown in case the final ping body is larger than MAX_PING_BODY_SIZE.
21-
class PingBodyOverflowError extends Error {
22-
constructor(message?: string) {
23-
super(message);
24-
this.name = "PingBodyOverflow";
25-
}
26-
}
27-
2820
class PingUploadWorker {
2921
// Whether or not someone is blocking on the currentJob.
3022
isBlocking = false;
@@ -47,10 +39,7 @@ class PingUploadWorker {
4739
* @param ping The ping to include the headers in.
4840
* @returns The updated ping.
4941
*/
50-
private buildPingRequest(ping: QueuedPing): {
51-
headers: Record<string, string>;
52-
payload: string | Uint8Array;
53-
} {
42+
private buildPingRequest(ping: QueuedPing): PingRequest<string | Uint8Array> {
5443
let headers = ping.headers || {};
5544
headers = {
5645
...ping.headers,
@@ -60,33 +49,15 @@ class PingUploadWorker {
6049
};
6150

6251
const stringifiedBody = JSON.stringify(ping.payload);
63-
// We prefer using `strToU8` instead of TextEncoder directly,
64-
// because it will polyfill TextEncoder if it's not present in the environment.
65-
// Environments that don't provide TextEncoder are IE and most importantly QML.
66-
const encodedBody = strToU8(stringifiedBody);
67-
68-
let finalBody: string | Uint8Array;
69-
let bodySizeInBytes: number;
70-
try {
71-
finalBody = gzipSync(encodedBody);
72-
bodySizeInBytes = finalBody.length;
73-
headers["Content-Encoding"] = "gzip";
74-
} catch {
75-
finalBody = stringifiedBody;
76-
bodySizeInBytes = encodedBody.length;
77-
}
7852

79-
if (bodySizeInBytes > this.policy.maxPingBodySize) {
53+
if (stringifiedBody.length > this.policy.maxPingBodySize) {
8054
throw new PingBodyOverflowError(
8155
`Body for ping ${ping.identifier} exceeds ${this.policy.maxPingBodySize}bytes. Discarding.`
8256
);
8357
}
8458

85-
headers["Content-Length"] = bodySizeInBytes.toString();
86-
return {
87-
headers,
88-
payload: finalBody
89-
};
59+
headers["Content-Length"] = stringifiedBody.length.toString();
60+
return new PingRequest(ping.identifier, headers, stringifiedBody, this.policy.maxPingBodySize);
9061
}
9162

9263
/**
@@ -99,12 +70,24 @@ class PingUploadWorker {
9970
try {
10071
const finalPing = this.buildPingRequest(ping);
10172

73+
let safeUploader = this.uploader;
74+
if (!this.uploader.supportsCustomHeaders()) {
75+
// Some options require us to submit custom headers. Unfortunately not all the
76+
// uploaders support them (e.g. `sendBeacon`). In case headers are required, switch
77+
// back to the default uploader that, for now, supports headers.
78+
const needsHeaders = !(
79+
(Context.config.sourceTags === undefined) && (Context.config.debugViewTag === undefined)
80+
);
81+
if (needsHeaders) {
82+
safeUploader = Context.platform.uploader;
83+
}
84+
}
85+
10286
// The POST call has to be asynchronous. Once the API call is triggered,
10387
// we rely on the browser's "keepalive" header.
104-
return this.uploader.post(
88+
return safeUploader.post(
10589
`${this.serverEndpoint}${ping.path}`,
106-
finalPing.payload,
107-
finalPing.headers
90+
finalPing
10891
);
10992
} catch (e) {
11093
log(

glean/src/entry/web.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ import platform from "../platform/browser/web/index.js";
66
import { base } from "./base.js";
77

88
export { default as Uploader, UploadResult, UploadResultStatus } from "../core/upload/uploader.js";
9+
export {default as BrowserSendBeaconUploader} from "../platform/browser/sendbeacon_uploader.js";
910
export default base(platform);

0 commit comments

Comments
 (0)