Skip to content

Commit 8d16795

Browse files
author
James Zhang
committed
Replace browser alias initialization with loader
1 parent 1a255bc commit 8d16795

3 files changed

Lines changed: 63 additions & 43 deletions

File tree

packages/aliases/src/browser.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const DEFAULT_DEPLOYMENT_CONFIG_PATH =
4242
/** The author's declaration file, so it carries the declared defaults. */
4343
export const DEFAULT_DECLARATIONS_PATH = "resources.json";
4444

45-
export interface InitAliasesOptions {
45+
export interface LoadAliasesOptions {
4646
/**
4747
* Escape hatch to force one specific file, relative to `document.baseURI`.
4848
* Setting it disables the fallback, so a missing file throws. Normal
@@ -56,18 +56,36 @@ export interface InitAliasesOptions {
5656
fetch?: typeof globalThis.fetch;
5757
}
5858

59+
/** Aliases loaded for this application. */
60+
export interface LoadedAliases {
61+
/** Returns a resolved custom alias. */
62+
custom(alias: string): Custom;
63+
}
64+
5965
let cachedCustomAliases: Record<string, string> | undefined;
6066
let inFlight: Promise<void> | undefined;
6167

68+
const loadedAliases: LoadedAliases = Object.freeze({ custom });
69+
6270
/**
63-
* Fetches and caches the resolved aliases for this installation. Call once at
64-
* application startup and await it before reading any aliases. Repeated calls
65-
* are deduplicated and become no-ops once the aliases are cached.
71+
* Loads and caches the aliases for this installation, then returns a
72+
* synchronous reader. Repeated and concurrent calls share the same load.
6673
*
6774
* @experimental Exposed only via "@osdk/aliases/experimental". Both custom
6875
* aliases and the shape of this API are provisional and may change.
6976
*/
70-
export async function initAliases(options?: InitAliasesOptions): Promise<void> {
77+
export async function load(
78+
options?: LoadAliasesOptions,
79+
): Promise<LoadedAliases> {
80+
await initAliases(options);
81+
return loadedAliases;
82+
}
83+
84+
/**
85+
* Populates the alias cache. Concurrent calls share a request, and failed
86+
* requests may be retried.
87+
*/
88+
export async function initAliases(options?: LoadAliasesOptions): Promise<void> {
7189
if (cachedCustomAliases !== undefined) {
7290
return;
7391
}
@@ -81,12 +99,12 @@ export async function initAliases(options?: InitAliasesOptions): Promise<void> {
8199
await inFlight;
82100
}
83101

84-
async function loadAliases(options?: InitAliasesOptions): Promise<void> {
102+
async function loadAliases(options?: LoadAliasesOptions): Promise<void> {
85103
const fetchImpl = options?.fetch ?? globalThis.fetch;
86104
if (typeof fetchImpl !== "function") {
87105
throw new TypeError(
88106
"No fetch implementation available to load aliases. Pass one via " +
89-
"initAliases({ fetch }).",
107+
"Aliases.load({ fetch }).",
90108
);
91109
}
92110

packages/aliases/src/experimental.test.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,31 @@
1919
// breaking change for consumers, and that should fail a test rather than pass
2020
// review unnoticed.
2121

22-
import { afterEach, describe, expect, it } from "vitest";
22+
import { afterEach, describe, expect, it, vi } from "vitest";
2323

2424
import * as browser from "./browser.js";
2525
import { resetAliasesCache } from "./browser.js";
2626
import {
2727
Aliases,
28-
custom,
2928
DEFAULT_DECLARATIONS_PATH,
3029
DEFAULT_DEPLOYMENT_CONFIG_PATH,
31-
initAliases,
30+
load,
3231
} from "./public/experimental.js";
3332

3433
const DECLARATIONS = {
3534
aliases: { custom: { apiBaseUrl: { value: "https://api.example.com" } } },
3635
};
3736

3837
function mockFetch(): typeof globalThis.fetch {
39-
return (() =>
38+
return vi.fn(() =>
4039
Promise.resolve({
4140
ok: true,
4241
status: 200,
4342
statusText: "OK",
4443
headers: { get: () => "application/json" },
4544
text: () => Promise.resolve(JSON.stringify(DECLARATIONS)),
46-
})) as unknown as typeof globalThis.fetch;
45+
}),
46+
) as unknown as typeof globalThis.fetch;
4747
}
4848

4949
describe("experimental browser entry point", () => {
@@ -52,16 +52,33 @@ describe("experimental browser entry point", () => {
5252
});
5353

5454
it("exposes the Aliases namespace", async () => {
55-
await Aliases.initAliases({ path: "resources.json", fetch: mockFetch() });
55+
const aliases = await Aliases.load({
56+
path: "resources.json",
57+
fetch: mockFetch(),
58+
});
5659

57-
expect(Aliases.custom("apiBaseUrl")).toBe("https://api.example.com");
60+
expect(aliases.custom("apiBaseUrl")).toBe("https://api.example.com");
61+
});
62+
63+
it("caches concurrent and repeated loads", async () => {
64+
const fetchImpl = mockFetch();
65+
const options = { path: "resources.json", fetch: fetchImpl };
66+
67+
const [first, second] = await Promise.all([
68+
Aliases.load(options),
69+
Aliases.load(options),
70+
]);
71+
const third = await Aliases.load(options);
72+
73+
expect(first).toBe(second);
74+
expect(first).toBe(third);
75+
expect(fetchImpl).toHaveBeenCalledOnce();
5876
});
5977

6078
it("exposes the same members as named exports", () => {
6179
// Same function identities, not merely same names, so the two styles can
6280
// never drift apart.
63-
expect(Aliases.custom).toBe(custom);
64-
expect(Aliases.initAliases).toBe(initAliases);
81+
expect(Aliases.load).toBe(load);
6582
expect(Aliases.DEFAULT_DECLARATIONS_PATH).toBe(DEFAULT_DECLARATIONS_PATH);
6683
expect(Aliases.DEFAULT_DEPLOYMENT_CONFIG_PATH).toBe(
6784
DEFAULT_DEPLOYMENT_CONFIG_PATH,
@@ -73,6 +90,7 @@ describe("experimental browser entry point", () => {
7390
// into a browser bundle.
7491
expect(Aliases).not.toHaveProperty("dataset");
7592
expect(Aliases).not.toHaveProperty("source");
93+
expect(Aliases).not.toHaveProperty("custom");
7694
});
7795

7896
it("keeps the test-only cache reset out of the public surface", () => {

packages/aliases/src/public/experimental.ts

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,47 +14,31 @@
1414
* limitations under the License.
1515
*/
1616

17-
// EXPERIMENTAL browser-safe alias runtime, for applications served to a browser
18-
// such as Developer Console apps.
17+
// Experimental browser-safe aliases for Developer Console apps.
1918
//
2019
// import { Aliases } from "@osdk/aliases/experimental";
21-
// await Aliases.initAliases();
22-
// const apiBaseUrl = Aliases.custom("apiBaseUrl");
20+
// const aliases = await Aliases.load();
21+
// const apiBaseUrl = aliases.custom("apiBaseUrl");
2322
//
24-
// Behind the "experimental" subpath deliberately: both custom aliases and the
25-
// shape of this API are provisional, so the import path says so at every call
26-
// site. Expect it to move to the package root once the design settles, with this
27-
// subpath deprecated rather than removed.
28-
//
29-
// Code running in Node with a filesystem (Functions) wants "@osdk/aliases/node".
23+
// Functions and other Node runtimes use "@osdk/aliases/node".
3024

3125
import {
32-
custom,
3326
DEFAULT_DECLARATIONS_PATH,
3427
DEFAULT_DEPLOYMENT_CONFIG_PATH,
35-
initAliases,
28+
load,
3629
} from "../browser.js";
3730

38-
// Assembled member by member, not `export * as`, to keep the test-only
39-
// resetAliasesCache out of the supported surface.
40-
//
41-
// Explicitly typed: `--isolatedDeclarations` cannot infer this (TS9016).
31+
// Explicitly assembled to exclude test helpers. The type annotation is required
32+
// by `--isolatedDeclarations`.
4233
export const Aliases: {
43-
readonly custom: typeof custom;
44-
readonly initAliases: typeof initAliases;
34+
readonly load: typeof load;
4535
readonly DEFAULT_DECLARATIONS_PATH: typeof DEFAULT_DECLARATIONS_PATH;
4636
readonly DEFAULT_DEPLOYMENT_CONFIG_PATH: typeof DEFAULT_DEPLOYMENT_CONFIG_PATH;
4737
} = {
48-
custom,
49-
initAliases,
38+
load,
5039
DEFAULT_DECLARATIONS_PATH,
5140
DEFAULT_DEPLOYMENT_CONFIG_PATH,
5241
};
5342

54-
export {
55-
custom,
56-
DEFAULT_DECLARATIONS_PATH,
57-
DEFAULT_DEPLOYMENT_CONFIG_PATH,
58-
initAliases,
59-
};
60-
export type { Custom, InitAliasesOptions } from "../browser.js";
43+
export { DEFAULT_DECLARATIONS_PATH, DEFAULT_DEPLOYMENT_CONFIG_PATH, load };
44+
export type { Custom, LoadAliasesOptions, LoadedAliases } from "../browser.js";

0 commit comments

Comments
 (0)