Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/setScriptSrc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

// @jest-environment node
describe("setScriptSrc(): SSR safety", () => {
it("should be importable when window is not available", async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case our infra changes over time, can you assert that window is not available for this test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, added a check for this

await expect(import("./setScriptSrc.js")).resolves.toBeDefined();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's also get some coverage of what the expected output is, both for supported Trusted Types envs and unsupported envs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also added tests for the different new and old behaviors of setScriptSrc

});
39 changes: 26 additions & 13 deletions src/setScriptSrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,34 @@ import type { TrustedTypePolicyFactory } from "trusted-types";
import { logDevWarning, MSG_TRUSTED_TYPES_POLICY_FAILED } from "./messages.js";

const TRUSTED_TYPES_POLICY_NAME = "@googlemaps/js-api-loader";
type TrustedTypesWindow = Window & {
interface TrustedTypesGlobals {
trustedTypes?: TrustedTypePolicyFactory;
};

// Try to create a Trusted Types policy when supported. Falls back to a string
// passthrough when Trusted Types is unsupported, blocked by CSP, or already
// registered.
}

let policy: {
type Policy = {
createScriptURL: (url: string) => string | TrustedScriptURL;
};

const trustedTypes = (window as TrustedTypesWindow).trustedTypes;
const fallbackPolicy: Policy = { createScriptURL: (url: string) => url };

let policy: Policy | undefined;

/*
* Tries to create a Trusted Types policy when supported. Falls back to a string passthrough
* when Trusted Types is unsupported, blocked by CSP, or already registered.
*/
function getPolicy(): Policy {
if (policy) {
return policy;
}

const trustedTypes = (globalThis as TrustedTypesGlobals).trustedTypes;

if (!trustedTypes) {
policy = fallbackPolicy;
return policy;
}

if (!trustedTypes) {
policy = { createScriptURL: (url: string) => url };
} else {
try {
policy = trustedTypes.createPolicy(TRUSTED_TYPES_POLICY_NAME, {
createScriptURL: (url: string) => url,
Expand All @@ -33,10 +44,12 @@ if (!trustedTypes) {
logDevWarning(
MSG_TRUSTED_TYPES_POLICY_FAILED(TRUSTED_TYPES_POLICY_NAME, e)
);
policy = { createScriptURL: (url: string) => url };
policy = fallbackPolicy;
}

return policy;
}

export function setScriptSrc(script: HTMLScriptElement, src: string): void {
script.src = policy.createScriptURL(src) as string;
script.src = getPolicy().createScriptURL(src) as string;
}
Loading