@mfe-orchestrator-hub/client 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # @mfe-orchestrator-hub/client
2
2
 
3
- Framework agnostic client for [MFE Orchestrator](https://github.com/mfe-orchestrator). It asks the
4
- console which microfrontends the current environment serves and hands back their ready to use,
5
- version pinned URLs.
3
+ **Part of [MFE Orchestrator](https://mfe-orchestrator.dev)** — the control plane for your
4
+ microfrontends. The site is the short version; the
5
+ [documentation](https://mfe-orchestrator.dev/documentation/docs/integration/client-sdk) is where this
6
+ package sits in context: environments, deployments, canary releases.
7
+
8
+ Framework agnostic client for the platform. It asks the console which microfrontends the current
9
+ environment serves and hands back their ready to use, version pinned URLs.
6
10
 
7
11
  Zero runtime dependencies, ESM + CJS, ships its own types.
8
12
 
@@ -60,6 +64,18 @@ configure({
60
64
  provider may call it on every render. A second call with different options is ignored, with a
61
65
  warning, because the manifest of this page load may already be in flight.
62
66
 
67
+ ### Who is the logged in user?
68
+
69
+ `userId` is what the backend decides a *user based canary* on: it enrols the ids you list in the
70
+ console, and a page that sends none of them gets the stable version. Pass it here when the host
71
+ already knows its user at boot, as a value or as a getter resolved right before the request:
72
+
73
+ ```ts
74
+ configure({ backendUrl: "…", projectId: "…", userId: () => authStore.getState().user?.id })
75
+ ```
76
+
77
+ When the user only appears later, or changes without a reload, use [`setUserId()`](#setuseriduserid).
78
+
63
79
  ## Bundler configuration
64
80
 
65
81
  The string below is injected into the host bundle, so the bare specifier is resolved by the host's
@@ -134,6 +150,9 @@ export interface OrchestratorConfig {
134
150
  /** Call once, synchronously, before any remote is imported. Idempotent. */
135
151
  export function configure(config: OrchestratorConfig): void
136
152
 
153
+ /** Replaces the user mid session and drops the memoized manifest. `undefined` on logout. */
154
+ export function setUserId(userId: OrchestratorConfig["userId"]): void
155
+
137
156
  /** Resolves the ready to use, version pinned URL of a remote. Awaits the manifest internally. */
138
157
  export function remoteUrl(slug: string): Promise<string>
139
158
 
@@ -173,6 +192,33 @@ const variables = await globalVariables()
173
192
  // { API_URL: "https://…", FEATURE_FLAG: "on" }
174
193
  ```
175
194
 
195
+ ### `setUserId(userId)`
196
+
197
+ The one option that legitimately changes while the page is alive — a login, a logout, an account
198
+ switch — so it has its own setter. Unlike a second `configure()`, this one takes effect: it drops the
199
+ memoized manifest, so the next `manifest()`, `remoteUrl()` or `globalVariables()` asks the backend
200
+ again and is answered for the new user.
201
+
202
+ ```ts
203
+ import { setUserId } from "@mfe-orchestrator-hub/client"
204
+
205
+ auth.onLogin(user => setUserId(user.id))
206
+ auth.onLogout(() => setUserId(undefined)) // no mfeUserId at all: back to the stable version
207
+ ```
208
+
209
+ It does **not** reload the remotes already imported. The federation runtime keeps the container it
210
+ loaded, so a microfrontend already on the page stays on the version drawn for the previous user, and
211
+ only the remotes resolved after the call see the new one. Two ways out, pick one:
212
+
213
+ - mount the remotes behind your own auth guard, and set the user before the guard opens — nothing was
214
+ resolved yet, so the whole page is decided on the right identity;
215
+ - or reload the page after the switch, when it has to be consistent end to end.
216
+
217
+ Setting the same plain value again is a no op, so an auth store may call it on every emission without
218
+ costing a request. A getter is always taken as a change: what it returns is exactly what this side
219
+ cannot know. A request already in flight is not cancelled — whoever is awaiting it still gets the
220
+ manifest of the previous identity — and calling it before `configure()` throws.
221
+
176
222
  ### `identities()`
177
223
 
178
224
  ```ts
@@ -215,7 +261,8 @@ backend uses.
215
261
 
216
262
  `userId` may be a value, a getter, or an async getter. It is resolved as late as possible, right
217
263
  before the request is issued, so a host that only knows its user after an auth round trip can pass a
218
- function.
264
+ function — or hand the user over later with `setUserId()`, which is also how it changes without a
265
+ reload.
219
266
 
220
267
  Both ids are generated with `crypto.randomUUID()` on first use and persisted. Storage can throw —
221
268
  Safari in private mode, disabled storage, hardened browsers that throw on the property access
package/dist/index.cjs CHANGED
@@ -233,7 +233,9 @@ var resolveUserId = async (userId) => {
233
233
  const value = typeof userId === "function" ? await userId() : userId;
234
234
  return value === void 0 || value === null || value === "" ? void 0 : String(value);
235
235
  };
236
- var sameConfig = (left, right) => left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment && left.userId === right.userId;
236
+ var sameTarget = (left, right) => left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment;
237
+ var sameConfig = (left, right) => sameTarget(left, right) && left.userId === right.userId;
238
+ var sameUserId = (left, right) => typeof left !== "function" && typeof right !== "function" && left === right;
237
239
  var requireConfig = (config, integration) => {
238
240
  if (typeof config !== "object" || config === null) {
239
241
  throw new Error(noConfigMessage(config, integration));
@@ -301,7 +303,7 @@ var configure = (config) => {
301
303
  if (current) {
302
304
  if (!sameConfig(current, config)) {
303
305
  console.warn(
304
- `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`
306
+ sameTarget(current, config) ? `${PREFIX} configure() was called again with a different userId. The configuration is fixed for this page load, so this one is ignored: call setUserId() instead, which is the supported way to change the user mid session and also drops the memoized manifest, so the next read is decided on the new identity.` : `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`
305
307
  );
306
308
  }
307
309
  return;
@@ -309,6 +311,18 @@ var configure = (config) => {
309
311
  state.config = { ...config };
310
312
  warnAboutConfig(config);
311
313
  };
314
+ var setUserId = (userId) => {
315
+ const state = getState();
316
+ const current = state.config;
317
+ if (!current) {
318
+ throw new Error(notConfiguredMessage("setUserId()", state.integration));
319
+ }
320
+ if (sameUserId(current.userId, userId)) {
321
+ return;
322
+ }
323
+ state.config = { ...current, userId };
324
+ state.manifestPromise = null;
325
+ };
312
326
  var registerIntegration = (integration) => {
313
327
  getState().integration = integration;
314
328
  };
@@ -368,5 +382,6 @@ exports.identities = identities;
368
382
  exports.manifest = manifest;
369
383
  exports.registerIntegration = registerIntegration;
370
384
  exports.remoteUrl = remoteUrl;
385
+ exports.setUserId = setUserId;
371
386
  //# sourceMappingURL=index.cjs.map
372
387
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/state.ts","../src/storage.ts","../src/index.ts"],"names":["created"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Everything the client says when its configuration is wrong or absent.\n *\n * The two required options almost always arrive from build time environment variables, so the\n * failure the host sees is not \"a value is invalid\" but \"nothing reached the bundle\". Messages here\n * are written for that moment: they name the option, show what actually arrived, say where the real\n * value comes from, and print the exact call to write, in the flavour of the package the host uses.\n */\n\nexport const PREFIX = \"[@mfe-orchestrator-hub/client]\"\n\n/** Which package the host went through. Only decides which snippet an error prints. */\nexport type Integration = \"core\" | \"react\" | \"vue\" | \"angular\"\n\n/** The two options without which nothing can be requested. */\nexport type RequiredOption = \"backendUrl\" | \"projectId\"\n\nconst EXAMPLE_BACKEND_URL = \"https://console.mfe-orchestrator.dev/api\"\nconst EXAMPLE_PROJECT_ID = \"6f1b2c3d4e5f6a7b8c9d0e1f\"\n\nconst SNIPPETS: Record<Integration, string> = {\n core: `import { configure } from \"@mfe-orchestrator-hub/client\"\n\nconfigure({\n backendUrl: \"${EXAMPLE_BACKEND_URL}\",\n projectId: \"${EXAMPLE_PROJECT_ID}\"\n})`,\n react: `import { OrchestratorProvider } from \"@mfe-orchestrator-hub/client-react\"\n\n<OrchestratorProvider config={{ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }}>\n <App />\n</OrchestratorProvider>`,\n vue: `import { createOrchestrator } from \"@mfe-orchestrator-hub/client-vue\"\n\napp.use(createOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }))`,\n angular: `import { provideOrchestrator } from \"@mfe-orchestrator-hub/client-angular\"\n\nbootstrapApplication(AppComponent, {\n providers: [provideOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" })]\n})`\n}\n\nconst WHERE: Record<Integration, string> = {\n core: \"Call it once, at the very top of the host entry point, before anything imports a remote.\",\n react: \"Render it above every component that resolves a remote. Better still, call configure() at the very top of the entry point: a bundler may import a remote before React mounts.\",\n vue: \"Install the plugin before mounting the app. Better still, call configure() at the very top of the entry point: a bundler may import a remote before the app is created.\",\n angular: \"Pass it to bootstrapApplication(). Better still, call configure() at the very top of main.ts: a lazily loaded remote must find the client already configured.\"\n}\n\nconst WHAT_IT_IS: Record<RequiredOption, string> = {\n backendUrl: `It is the base URL of the console API, protocol included, ex. \"${EXAMPLE_BACKEND_URL}\". A path on the same origin as the host, ex. \"/api\", works too.`,\n projectId: `It is the id of the project in the console: open the project and copy it from its page, ex. \"${EXAMPLE_PROJECT_ID}\".`\n}\n\n/** The name the value travels under from the bundler config into the bundle, per toolchain. */\nconst BUILD_VARIABLE: Record<RequiredOption, { vite: string; webpack: string }> = {\n backendUrl: { vite: \"VITE_MFE_BACKEND_URL\", webpack: \"MFE_BACKEND_URL\" },\n projectId: { vite: \"VITE_MFE_PROJECT_ID\", webpack: \"MFE_PROJECT_ID\" }\n}\n\n/**\n * What an option that was never substituted into the bundle looks like.\n *\n * The bundler config is named before the .env file on purpose: it is where the console writes both\n * values when it generates the config, so it is where they are missing from when they are missing.\n */\nconst missingEnvHint = (option: RequiredOption): string =>\n `Nothing arrived here at all, which is what a value that never reached the bundle looks like: check ${BUILD_VARIABLE[option].vite} (Vite) or ${BUILD_VARIABLE[option].webpack} (webpack) in the build that produced this bundle. The generated configs carry it in the \"define\" block of vite.config, or in the DefinePlugin of webpack.config, so look there first; declared only in a .env file the build never reads, it looks exactly like this.`\n\n/** Values that mean \"the template was never filled in\". */\nconst PLACEHOLDER = /^(…|\\.{3}|undefined|null|nan|<[^>]*>|\\{\\{[^}]*\\}\\}|\\$\\{[^}]*\\}|your[-_ ]?[a-z]*|x{3,}|change[-_ ]?me|todo|tbd)$/i\n\n/** Long values are cut: an error message is not the place to print a whole JWT. */\nconst quoted = (value: string): string => JSON.stringify(value.length > 120 ? `${value.slice(0, 120)}…` : value)\n\nconst described = (value: unknown): string => {\n if (value === null) {\n return \"null\"\n }\n if (Array.isArray(value)) {\n return \"an array\"\n }\n const type = typeof value\n return type === \"object\" || type === \"function\" ? `a ${type}` : `a ${type} (${String(value)})`\n}\n\n/** Same key modulo case and separators: projectID, project_id, PROJECT-ID all collapse onto projectid. */\nconst normalized = (key: string): string => key.toLowerCase().replace(/[^a-z0-9]/g, \"\")\n\nconst ALIASES: Record<RequiredOption, string[]> = {\n backendUrl: [\"backendurl\", \"backendbaseurl\", \"apiurl\", \"baseurl\", \"consoleurl\", \"url\", \"backend\"],\n projectId: [\"projectid\", \"project\", \"idproject\", \"projectuuid\", \"projectkey\"]\n}\n\n/**\n * The key the host actually wrote, when it looks like a misspelling of the one that is missing.\n * `projectID` is by far the most common: it is silently ignored, so without this the message would\n * claim the option is absent while the developer stares at a line that clearly sets it.\n */\nconst confusableKey = (option: RequiredOption, config: unknown): string | undefined => {\n if (typeof config !== \"object\" || config === null) {\n return undefined\n }\n const candidates = ALIASES[option]\n return Object.keys(config).find(key => key !== option && candidates.includes(normalized(key)))\n}\n\n/** One thing that is wrong with one option, already spelled out. */\nexport interface ConfigProblem {\n option: RequiredOption\n /** Predicate completing \"<option> …\", ex. `is missing`. */\n what: string\n /** Extra lines, printed under the option, that say how to fix this particular case. */\n hints: string[]\n}\n\nconst problem = (option: RequiredOption, what: string, ...hints: (string | undefined)[]): ConfigProblem => ({\n option,\n what,\n hints: [WHAT_IT_IS[option], ...hints].filter((hint): hint is string => Boolean(hint))\n})\n\n/**\n * A backendUrl the client can actually build a request on: an absolute http(s) URL, or a path on the\n * host's own origin, which `fetch` resolves against the page.\n */\nconst diagnoseBackendUrl = (value: string): ConfigProblem | null => {\n const trimmed = value.trim()\n if (trimmed.startsWith(\"/\")) {\n return null\n }\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, which is not a URL`,\n trimmed.includes(\".\") || trimmed.includes(\":\")\n ? `It looks like a host without a protocol: write \"https://${trimmed}\" instead, or \"/${trimmed.replace(/^\\/+/, \"\")}\" if the console API answers on the same origin as this page.`\n : undefined\n )\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, whose \"${parsed.protocol.replace(\":\", \"\")}\" scheme is neither http nor https`,\n 'A bare \"host:port\" is read as a scheme: write \"http://localhost:3000/api\", not \"localhost:3000/api\".'\n )\n }\n return null\n}\n\n/** Everything wrong with one required option, or null when it is usable. */\nconst diagnose = (option: RequiredOption, config: unknown): ConfigProblem | null => {\n const value = (config as Record<string, unknown> | null | undefined)?.[option]\n const typo = confusableKey(option, config)\n const typoHint = typo ? `The configuration carries \"${typo}\", which the client ignores. The option is spelled \"${option}\".` : undefined\n\n if (value === undefined || value === null) {\n return problem(option, value === null ? \"is null\" : \"is missing\", typoHint, typo ? undefined : missingEnvHint(option))\n }\n if (typeof value !== \"string\") {\n return problem(option, `is ${described(value)}, not a string`, typoHint)\n }\n if (value.trim() === \"\") {\n return problem(option, value === \"\" ? \"is an empty string\" : \"holds nothing but whitespace\", typoHint, missingEnvHint(option))\n }\n if (PLACEHOLDER.test(value.trim())) {\n const looksLikeAnUnsetVariable = /^(undefined|null|nan)$/i.test(value.trim())\n return problem(option, `is still the placeholder ${quoted(value)}`, typoHint, looksLikeAnUnsetVariable ? missingEnvHint(option) : undefined)\n }\n if (option === \"projectId\" && value.trim() !== value) {\n // Percent encoded into the path, so the padding would travel to the backend as %20.\n return problem(\n \"projectId\",\n `is ${quoted(value)}, padded with whitespace`,\n \"Trim the value: it is percent encoded into the manifest URL, so the spaces would reach the backend as part of the id.\"\n )\n }\n return option === \"backendUrl\" ? diagnoseBackendUrl(value) : null\n}\n\n/** Every problem of a configuration, in the order the options are declared. Empty means usable. */\nexport const diagnoseConfig = (config: unknown): ConfigProblem[] =>\n ([\"backendUrl\", \"projectId\"] as const).map(option => diagnose(option, config)).filter((found): found is ConfigProblem => found !== null)\n\nconst bulleted = (problems: ConfigProblem[]): string => problems.map(({ option, what, hints }) => [` • ${option} ${what}.`, ...hints.map(hint => ` → ${hint}`)].join(\"\\n\")).join(\"\\n\")\n\nconst indented = (block: string): string =>\n block\n .split(\"\\n\")\n .map(line => (line ? ` ${line}` : line))\n .join(\"\\n\")\n\nconst howToConfigure = (integration: Integration): string => `Configure the client like this:\\n\\n${indented(SNIPPETS[integration])}\\n\\n${WHERE[integration]}`\n\nconst listed = (options: RequiredOption[]): string => (options.length > 1 ? `${options.slice(0, -1).join(\", \")} and ${options.at(-1)}` : String(options[0]))\n\n/** The message thrown by `configure()` when what it received cannot be used. */\nexport const invalidConfigMessage = (problems: ConfigProblem[], integration: Integration): string => {\n const options = problems.map(({ option }) => option)\n const headline = `${PREFIX} configure() cannot start the client: ${listed(options)} ${options.length > 1 ? \"are\" : \"is\"} not usable.`\n return `${headline}\\n\\n${bulleted(problems)}\\n\\n${howToConfigure(integration)}`\n}\n\n/** The message thrown by `configure()` when it did not even receive an object. */\nexport const noConfigMessage = (config: unknown, integration: Integration): string =>\n `${PREFIX} configure() was called with ${config === undefined ? \"no argument\" : described(config)} instead of a configuration object. It needs at least backendUrl and projectId.\\n\\n${howToConfigure(integration)}`\n\n/** The message every read rejects with while the client has no configuration at all. */\nexport const notConfiguredMessage = (caller: string, integration: Integration): string =>\n `${PREFIX} the client is not configured: ${caller} was called before configure() ever ran, so neither backendUrl nor projectId is known and no manifest can be requested.\\n\\n${howToConfigure(integration)}`\n","import type { Integration } from \"./errors\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport interface OrchestratorState {\n config: OrchestratorConfig | null\n manifestPromise: Promise<Manifest> | null\n identities: Identities | null\n /** Set by the framework adapters as they load, so an error prints the snippet of their own API. */\n integration: Integration\n}\n\n/**\n * The state lives on `globalThis` under this key, not in a module scope variable.\n *\n * A host can end up with two copies of this package loaded at once: the app imports the ESM build\n * while something else pulls the CJS one, or the bundler config and the app resolve to different\n * chunks. Two module scopes would mean two configurations and two manifest requests, which is\n * exactly what the contract forbids. One well known global slot makes the singleton real.\n */\nexport const STATE_KEY = \"__mfe_orchestrator_client__\"\n\nconst globalSlot = globalThis as typeof globalThis & Record<typeof STATE_KEY, OrchestratorState | undefined>\n\nexport const getState = (): OrchestratorState => {\n let state = globalSlot[STATE_KEY]\n if (!state) {\n state = { config: null, manifestPromise: null, identities: null, integration: \"core\" }\n globalSlot[STATE_KEY] = state\n }\n return state\n}\n","import type { Identities } from \"./types\"\n\nexport const SESSION_ID_KEY = \"mfe-orchestrator.sessionId\"\nexport const DEVICE_ID_KEY = \"mfe-orchestrator.deviceId\"\n\nconst PROBE_KEY = \"mfe-orchestrator.probe\"\n\ntype StorageKind = \"local\" | \"session\"\n\n/**\n * Ids minted while storage was unusable. They live for the lifetime of the page so that, even\n * without storage, every request of this page load carries one stable pair of ids.\n */\nconst inMemoryIds = new Map<string, string>()\n\nconst uuidFromRandomBytes = (bytes: Uint8Array): string => {\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex: string[] = []\n for (const byte of bytes) {\n hex.push(byte.toString(16).padStart(2, \"0\"))\n }\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`\n}\n\n/**\n * A v4 UUID. `crypto.randomUUID` is the intended path; the two fallbacks only exist so that a page\n * served over plain http, or an exotic runtime, still gets an id instead of an exception.\n */\nexport const newId = (): string => {\n const cryptoApi = globalThis.crypto\n try {\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID()\n }\n if (typeof cryptoApi?.getRandomValues === \"function\") {\n return uuidFromRandomBytes(cryptoApi.getRandomValues(new Uint8Array(16)))\n }\n } catch {\n // fall through to the non cryptographic fallback\n }\n const bytes = new Uint8Array(16)\n for (let index = 0; index < bytes.length; index++) {\n bytes[index] = Math.floor(Math.random() * 256)\n }\n return uuidFromRandomBytes(bytes)\n}\n\n/**\n * The requested storage, or `null` when it is missing or unusable.\n *\n * Both the property access and the write can throw: Safari in private mode exposes the object and\n * then refuses `setItem`, some hardened browsers throw a SecurityError on the access itself. The\n * write probe is the only reliable way to tell a usable storage from a decorative one.\n */\nconst openStorage = (kind: StorageKind): Storage | null => {\n try {\n const storage = kind === \"local\" ? globalThis.localStorage : globalThis.sessionStorage\n if (!storage) {\n return null\n }\n storage.setItem(PROBE_KEY, \"1\")\n storage.removeItem(PROBE_KEY)\n return storage\n } catch {\n return null\n }\n}\n\n/**\n * The id under `key`, read from storage and created on first use. Falls back to an id kept in\n * memory when storage cannot be used, so this never throws out of the SDK.\n */\nconst persistentId = (kind: StorageKind, key: string): string => {\n const storage = openStorage(kind)\n if (storage) {\n try {\n const stored = storage.getItem(key)\n if (stored) {\n return stored\n }\n const created = newId()\n storage.setItem(key, created)\n return created\n } catch {\n // storage passed the probe and failed anyway: keep going with an in memory id\n }\n }\n const remembered = inMemoryIds.get(key)\n if (remembered) {\n return remembered\n }\n const created = newId()\n inMemoryIds.set(key, created)\n return created\n}\n\n/** Reads, and creates when needed, the session and device ids. */\nexport const readIdentities = (): Identities => ({\n sessionId: persistentId(\"session\", SESSION_ID_KEY),\n deviceId: persistentId(\"local\", DEVICE_ID_KEY)\n})\n","import { diagnoseConfig, type Integration, invalidConfigMessage, noConfigMessage, notConfiguredMessage, PREFIX } from \"./errors\"\nimport { getState } from \"./state\"\nimport { readIdentities } from \"./storage\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport type { ConfigProblem, Integration } from \"./errors\"\nexport type { GlobalVariable, Identities, Manifest, Microfrontend, OrchestratorConfig } from \"./types\"\n\nconst withoutTrailingSlash = (value: string): string => value.replace(/\\/+$/, \"\")\n\nconst resolveUserId = async (userId: OrchestratorConfig[\"userId\"]): Promise<string | undefined> => {\n const value = typeof userId === \"function\" ? await userId() : userId\n return value === undefined || value === null || value === \"\" ? undefined : String(value)\n}\n\nconst sameConfig = (left: OrchestratorConfig, right: OrchestratorConfig): boolean =>\n left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment && left.userId === right.userId\n\n/**\n * Rejects a configuration the client could not use, with a message that names the option, shows what\n * actually arrived and prints the call to write. environment is deliberately not required: without\n * it the backend resolves it from the domain. It is still checked for type, because a non string\n * there would silently end up percent encoded into the path.\n */\nconst requireConfig = (config: OrchestratorConfig, integration: Integration): void => {\n if (typeof config !== \"object\" || config === null) {\n throw new Error(noConfigMessage(config, integration))\n }\n const problems = diagnoseConfig(config)\n if (problems.length > 0) {\n throw new Error(invalidConfigMessage(problems, integration))\n }\n if (config.environment !== undefined && config.environment !== null && typeof config.environment !== \"string\") {\n throw new Error(\n `${PREFIX} configure() received environment as a ${typeof config.environment}, not a string. Pass the environment slug as it appears in the console, ex. \"DEV\", or leave it out to let the backend resolve it from the domain of this page.`\n )\n }\n}\n\n/** Notices about a stored configuration that works but probably does not do what the host meant. */\nconst warnAboutConfig = (config: OrchestratorConfig): void => {\n if (typeof config.environment === \"string\" && config.environment.trim() === \"\") {\n console.warn(\n `${PREFIX} configure() received an empty environment, so the client falls back to the auto routes and the backend resolves the environment from the domain of this page. Remove the option if that is what you want, or check the variable that feeds it.`\n )\n }\n}\n\n/**\n * Two shapes, one per route family. With an explicit environment the slug is the last segment; with\n * no environment the \"auto\" segment takes its place before the project id and the backend resolves\n * the environment from the domain the request comes from.\n */\nconst manifestPath = (config: OrchestratorConfig): string => {\n const projectId = encodeURIComponent(config.projectId)\n return config.environment ? `/serve/all/${projectId}/${encodeURIComponent(config.environment)}` : `/serve/all/auto/${projectId}`\n}\n\nconst manifestUrl = async (config: OrchestratorConfig): Promise<string> => {\n const { sessionId, deviceId } = identities()\n const query = new URLSearchParams({ mfeSessionId: sessionId, mfeDeviceId: deviceId })\n // Resolved as late as possible: the host may only know the user after its own auth round trip.\n const userId = await resolveUserId(config.userId)\n if (userId) {\n query.set(\"mfeUserId\", userId)\n }\n return `${withoutTrailingSlash(config.backendUrl)}${manifestPath(config)}?${query.toString()}`\n}\n\n/**\n * What a status usually means on this route. The backend answers the same 404 for an unknown project\n * and for an unknown environment, and the two are indistinguishable from here, so both are named.\n */\nconst statusHint = (status: number, config: OrchestratorConfig): string => {\n if (status === 404) {\n const environment = config.environment\n ? `the environment \"${config.environment}\" does not exist in it`\n : \"no environment of that project declares the domain this page is served on, which is what the auto route resolves on\"\n return `\\n\\nA 404 on this route means the backend did not find what the URL names: either the project id \"${config.projectId}\" is not a project of this console, or ${environment}. Check both in the console, and check that backendUrl points at the console API of the same instance.`\n }\n if (status === 401 || status === 403) {\n return `\\n\\nThe console refused the request. Check that the project id \"${config.projectId}\" belongs to the instance backendUrl points at, and that this domain is allowed to read its manifest.`\n }\n return \"\"\n}\n\nconst fetchManifest = async (config: OrchestratorConfig): Promise<Manifest> => {\n const url = await manifestUrl(config)\n // No retry in v1: whatever fetch throws travels straight to the caller.\n const response = await fetch(url, { headers: { accept: \"application/json\" } })\n if (!response.ok) {\n throw new Error(`${PREFIX} the manifest request failed with ${response.status} ${response.statusText}. GET ${url}${statusHint(response.status, config)}`)\n }\n const payload = (await response.json()) as Partial<Manifest> | null\n return {\n globalVariables: payload?.globalVariables ?? [],\n microfrontends: payload?.microfrontends ?? []\n }\n}\n\n/**\n * Hands the client its configuration. Call it once, synchronously, before any remote is imported.\n *\n * `backendUrl` and `projectId` are required. `environment` is not: omitting it makes the client use\n * the \"auto\" routes, where the backend resolves the environment from the domain of the host page.\n *\n * Idempotent: calling it again with the same options is a no op, so a framework provider may safely\n * call it on every render. A second call with different options is ignored, with a warning, because\n * the manifest of this page load may already be in flight or resolved.\n */\nexport const configure = (config: OrchestratorConfig): void => {\n const state = getState()\n requireConfig(config, state.integration)\n const current = state.config\n if (current) {\n if (!sameConfig(current, config)) {\n console.warn(\n `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`\n )\n }\n return\n }\n state.config = { ...config }\n warnAboutConfig(config)\n}\n\n/**\n * @internal Lets a framework adapter say which package the host is really using, so a configuration\n * error prints the snippet of that API instead of the bare `configure()` one. Idempotent, and never\n * needed by an application: the adapters call it as they load.\n */\nexport const registerIntegration = (integration: Integration): void => {\n getState().integration = integration\n}\n\n/**\n * The whole manifest of the environment, fetched once per page load and memoized as a promise, so\n * that concurrent callers share the single request in flight.\n *\n * A successful result is memoized for good. A failed attempt is not: the memo is dropped when the\n * shared attempt settles as rejected, so the next caller starts a fresh request. That is not a retry\n * — nothing here loops or backs off — it only means one flaky lookup at boot does not condemn the\n * page to reject every `remoteUrl()` until a full reload.\n */\nconst loadManifest = (caller: string): Promise<Manifest> => {\n const state = getState()\n const config = state.config\n if (!config) {\n // Not memoized: the host may still configure the client and try again.\n return Promise.reject(new Error(notConfiguredMessage(caller, state.integration)))\n }\n if (!state.manifestPromise) {\n // Assigned before the first await inside fetchManifest, which is what makes N concurrent\n // callers collapse onto one request.\n const attempt = fetchManifest(config)\n state.manifestPromise = attempt\n // Cleared once, when the shared attempt settles, not in each caller's own catch: every\n // caller already waiting on this attempt still gets its rejection. The identity check keeps\n // a late failure from evicting a newer attempt.\n attempt.catch(() => {\n if (state.manifestPromise === attempt) {\n state.manifestPromise = null\n }\n })\n }\n return state.manifestPromise\n}\n\n/** The whole manifest of the environment. See `loadManifest` for the memoization contract. */\nexport const manifest = (): Promise<Manifest> => loadManifest(\"manifest()\")\n\n/**\n * The ready to use, version pinned URL of a remote. Awaits the manifest internally.\n *\n * The returned URL is used verbatim: the host never parses the version out of it and never strips\n * the `_v/<version>/` segment, or a classic script would load its chunks off another version.\n */\nexport const remoteUrl = async (slug: string): Promise<string> => {\n const { microfrontends } = await loadManifest(`remoteUrl(\"${slug}\")`)\n const found = microfrontends.find(microfrontend => microfrontend.slug === slug)\n if (!found) {\n const available = microfrontends.map(microfrontend => `\"${microfrontend.slug}\"`).join(\", \")\n const environment = getState().config?.environment\n // With no configured environment the host cannot name the one it was served: only the backend knows.\n const where = environment ? `environment \"${environment}\"` : \"the environment resolved from this domain\"\n throw new Error(`${PREFIX} unknown microfrontend slug \"${slug}\". Available in ${where}: ${available || \"none, this environment serves no microfrontend\"}.`)\n }\n if (!found.url) {\n throw new Error(`${PREFIX} the microfrontend \"${slug}\" is in the manifest but carries no url. Check its deployment in the console.`)\n }\n return found.url\n}\n\n/** The global variables of the environment, as a plain object. */\nexport const globalVariables = async (): Promise<Record<string, string>> => {\n const { globalVariables: variables } = await loadManifest(\"globalVariables()\")\n const result: Record<string, string> = {}\n for (const variable of variables) {\n if (variable && typeof variable.key === \"string\") {\n result[variable.key] = variable.value\n }\n }\n return result\n}\n\n/**\n * The session and device ids of this page, exposed for telemetry and debugging. Created on first\n * use and stable for the lifetime of the page, whether or not storage is available.\n */\nexport const identities = (): Identities => {\n const state = getState()\n if (!state.identities) {\n state.identities = readIdentities()\n }\n return state.identities\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/state.ts","../src/storage.ts","../src/index.ts"],"names":["created"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Everything the client says when its configuration is wrong or absent.\n *\n * The two required options almost always arrive from build time environment variables, so the\n * failure the host sees is not \"a value is invalid\" but \"nothing reached the bundle\". Messages here\n * are written for that moment: they name the option, show what actually arrived, say where the real\n * value comes from, and print the exact call to write, in the flavour of the package the host uses.\n */\n\nexport const PREFIX = \"[@mfe-orchestrator-hub/client]\"\n\n/** Which package the host went through. Only decides which snippet an error prints. */\nexport type Integration = \"core\" | \"react\" | \"vue\" | \"angular\"\n\n/** The two options without which nothing can be requested. */\nexport type RequiredOption = \"backendUrl\" | \"projectId\"\n\nconst EXAMPLE_BACKEND_URL = \"https://console.mfe-orchestrator.dev/api\"\nconst EXAMPLE_PROJECT_ID = \"6f1b2c3d4e5f6a7b8c9d0e1f\"\n\nconst SNIPPETS: Record<Integration, string> = {\n core: `import { configure } from \"@mfe-orchestrator-hub/client\"\n\nconfigure({\n backendUrl: \"${EXAMPLE_BACKEND_URL}\",\n projectId: \"${EXAMPLE_PROJECT_ID}\"\n})`,\n react: `import { OrchestratorProvider } from \"@mfe-orchestrator-hub/client-react\"\n\n<OrchestratorProvider config={{ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }}>\n <App />\n</OrchestratorProvider>`,\n vue: `import { createOrchestrator } from \"@mfe-orchestrator-hub/client-vue\"\n\napp.use(createOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }))`,\n angular: `import { provideOrchestrator } from \"@mfe-orchestrator-hub/client-angular\"\n\nbootstrapApplication(AppComponent, {\n providers: [provideOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" })]\n})`\n}\n\nconst WHERE: Record<Integration, string> = {\n core: \"Call it once, at the very top of the host entry point, before anything imports a remote.\",\n react: \"Render it above every component that resolves a remote. Better still, call configure() at the very top of the entry point: a bundler may import a remote before React mounts.\",\n vue: \"Install the plugin before mounting the app. Better still, call configure() at the very top of the entry point: a bundler may import a remote before the app is created.\",\n angular: \"Pass it to bootstrapApplication(). Better still, call configure() at the very top of main.ts: a lazily loaded remote must find the client already configured.\"\n}\n\nconst WHAT_IT_IS: Record<RequiredOption, string> = {\n backendUrl: `It is the base URL of the console API, protocol included, ex. \"${EXAMPLE_BACKEND_URL}\". A path on the same origin as the host, ex. \"/api\", works too.`,\n projectId: `It is the id of the project in the console: open the project and copy it from its page, ex. \"${EXAMPLE_PROJECT_ID}\".`\n}\n\n/** The name the value travels under from the bundler config into the bundle, per toolchain. */\nconst BUILD_VARIABLE: Record<RequiredOption, { vite: string; webpack: string }> = {\n backendUrl: { vite: \"VITE_MFE_BACKEND_URL\", webpack: \"MFE_BACKEND_URL\" },\n projectId: { vite: \"VITE_MFE_PROJECT_ID\", webpack: \"MFE_PROJECT_ID\" }\n}\n\n/**\n * What an option that was never substituted into the bundle looks like.\n *\n * The bundler config is named before the .env file on purpose: it is where the console writes both\n * values when it generates the config, so it is where they are missing from when they are missing.\n */\nconst missingEnvHint = (option: RequiredOption): string =>\n `Nothing arrived here at all, which is what a value that never reached the bundle looks like: check ${BUILD_VARIABLE[option].vite} (Vite) or ${BUILD_VARIABLE[option].webpack} (webpack) in the build that produced this bundle. The generated configs carry it in the \"define\" block of vite.config, or in the DefinePlugin of webpack.config, so look there first; declared only in a .env file the build never reads, it looks exactly like this.`\n\n/** Values that mean \"the template was never filled in\". */\nconst PLACEHOLDER = /^(…|\\.{3}|undefined|null|nan|<[^>]*>|\\{\\{[^}]*\\}\\}|\\$\\{[^}]*\\}|your[-_ ]?[a-z]*|x{3,}|change[-_ ]?me|todo|tbd)$/i\n\n/** Long values are cut: an error message is not the place to print a whole JWT. */\nconst quoted = (value: string): string => JSON.stringify(value.length > 120 ? `${value.slice(0, 120)}…` : value)\n\nconst described = (value: unknown): string => {\n if (value === null) {\n return \"null\"\n }\n if (Array.isArray(value)) {\n return \"an array\"\n }\n const type = typeof value\n return type === \"object\" || type === \"function\" ? `a ${type}` : `a ${type} (${String(value)})`\n}\n\n/** Same key modulo case and separators: projectID, project_id, PROJECT-ID all collapse onto projectid. */\nconst normalized = (key: string): string => key.toLowerCase().replace(/[^a-z0-9]/g, \"\")\n\nconst ALIASES: Record<RequiredOption, string[]> = {\n backendUrl: [\"backendurl\", \"backendbaseurl\", \"apiurl\", \"baseurl\", \"consoleurl\", \"url\", \"backend\"],\n projectId: [\"projectid\", \"project\", \"idproject\", \"projectuuid\", \"projectkey\"]\n}\n\n/**\n * The key the host actually wrote, when it looks like a misspelling of the one that is missing.\n * `projectID` is by far the most common: it is silently ignored, so without this the message would\n * claim the option is absent while the developer stares at a line that clearly sets it.\n */\nconst confusableKey = (option: RequiredOption, config: unknown): string | undefined => {\n if (typeof config !== \"object\" || config === null) {\n return undefined\n }\n const candidates = ALIASES[option]\n return Object.keys(config).find(key => key !== option && candidates.includes(normalized(key)))\n}\n\n/** One thing that is wrong with one option, already spelled out. */\nexport interface ConfigProblem {\n option: RequiredOption\n /** Predicate completing \"<option> …\", ex. `is missing`. */\n what: string\n /** Extra lines, printed under the option, that say how to fix this particular case. */\n hints: string[]\n}\n\nconst problem = (option: RequiredOption, what: string, ...hints: (string | undefined)[]): ConfigProblem => ({\n option,\n what,\n hints: [WHAT_IT_IS[option], ...hints].filter((hint): hint is string => Boolean(hint))\n})\n\n/**\n * A backendUrl the client can actually build a request on: an absolute http(s) URL, or a path on the\n * host's own origin, which `fetch` resolves against the page.\n */\nconst diagnoseBackendUrl = (value: string): ConfigProblem | null => {\n const trimmed = value.trim()\n if (trimmed.startsWith(\"/\")) {\n return null\n }\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, which is not a URL`,\n trimmed.includes(\".\") || trimmed.includes(\":\")\n ? `It looks like a host without a protocol: write \"https://${trimmed}\" instead, or \"/${trimmed.replace(/^\\/+/, \"\")}\" if the console API answers on the same origin as this page.`\n : undefined\n )\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, whose \"${parsed.protocol.replace(\":\", \"\")}\" scheme is neither http nor https`,\n 'A bare \"host:port\" is read as a scheme: write \"http://localhost:3000/api\", not \"localhost:3000/api\".'\n )\n }\n return null\n}\n\n/** Everything wrong with one required option, or null when it is usable. */\nconst diagnose = (option: RequiredOption, config: unknown): ConfigProblem | null => {\n const value = (config as Record<string, unknown> | null | undefined)?.[option]\n const typo = confusableKey(option, config)\n const typoHint = typo ? `The configuration carries \"${typo}\", which the client ignores. The option is spelled \"${option}\".` : undefined\n\n if (value === undefined || value === null) {\n return problem(option, value === null ? \"is null\" : \"is missing\", typoHint, typo ? undefined : missingEnvHint(option))\n }\n if (typeof value !== \"string\") {\n return problem(option, `is ${described(value)}, not a string`, typoHint)\n }\n if (value.trim() === \"\") {\n return problem(option, value === \"\" ? \"is an empty string\" : \"holds nothing but whitespace\", typoHint, missingEnvHint(option))\n }\n if (PLACEHOLDER.test(value.trim())) {\n const looksLikeAnUnsetVariable = /^(undefined|null|nan)$/i.test(value.trim())\n return problem(option, `is still the placeholder ${quoted(value)}`, typoHint, looksLikeAnUnsetVariable ? missingEnvHint(option) : undefined)\n }\n if (option === \"projectId\" && value.trim() !== value) {\n // Percent encoded into the path, so the padding would travel to the backend as %20.\n return problem(\n \"projectId\",\n `is ${quoted(value)}, padded with whitespace`,\n \"Trim the value: it is percent encoded into the manifest URL, so the spaces would reach the backend as part of the id.\"\n )\n }\n return option === \"backendUrl\" ? diagnoseBackendUrl(value) : null\n}\n\n/** Every problem of a configuration, in the order the options are declared. Empty means usable. */\nexport const diagnoseConfig = (config: unknown): ConfigProblem[] =>\n ([\"backendUrl\", \"projectId\"] as const).map(option => diagnose(option, config)).filter((found): found is ConfigProblem => found !== null)\n\nconst bulleted = (problems: ConfigProblem[]): string => problems.map(({ option, what, hints }) => [` • ${option} ${what}.`, ...hints.map(hint => ` → ${hint}`)].join(\"\\n\")).join(\"\\n\")\n\nconst indented = (block: string): string =>\n block\n .split(\"\\n\")\n .map(line => (line ? ` ${line}` : line))\n .join(\"\\n\")\n\nconst howToConfigure = (integration: Integration): string => `Configure the client like this:\\n\\n${indented(SNIPPETS[integration])}\\n\\n${WHERE[integration]}`\n\nconst listed = (options: RequiredOption[]): string => (options.length > 1 ? `${options.slice(0, -1).join(\", \")} and ${options.at(-1)}` : String(options[0]))\n\n/** The message thrown by `configure()` when what it received cannot be used. */\nexport const invalidConfigMessage = (problems: ConfigProblem[], integration: Integration): string => {\n const options = problems.map(({ option }) => option)\n const headline = `${PREFIX} configure() cannot start the client: ${listed(options)} ${options.length > 1 ? \"are\" : \"is\"} not usable.`\n return `${headline}\\n\\n${bulleted(problems)}\\n\\n${howToConfigure(integration)}`\n}\n\n/** The message thrown by `configure()` when it did not even receive an object. */\nexport const noConfigMessage = (config: unknown, integration: Integration): string =>\n `${PREFIX} configure() was called with ${config === undefined ? \"no argument\" : described(config)} instead of a configuration object. It needs at least backendUrl and projectId.\\n\\n${howToConfigure(integration)}`\n\n/** The message every read rejects with while the client has no configuration at all. */\nexport const notConfiguredMessage = (caller: string, integration: Integration): string =>\n `${PREFIX} the client is not configured: ${caller} was called before configure() ever ran, so neither backendUrl nor projectId is known and no manifest can be requested.\\n\\n${howToConfigure(integration)}`\n","import type { Integration } from \"./errors\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport interface OrchestratorState {\n config: OrchestratorConfig | null\n manifestPromise: Promise<Manifest> | null\n identities: Identities | null\n /** Set by the framework adapters as they load, so an error prints the snippet of their own API. */\n integration: Integration\n}\n\n/**\n * The state lives on `globalThis` under this key, not in a module scope variable.\n *\n * A host can end up with two copies of this package loaded at once: the app imports the ESM build\n * while something else pulls the CJS one, or the bundler config and the app resolve to different\n * chunks. Two module scopes would mean two configurations and two manifest requests, which is\n * exactly what the contract forbids. One well known global slot makes the singleton real.\n */\nexport const STATE_KEY = \"__mfe_orchestrator_client__\"\n\nconst globalSlot = globalThis as typeof globalThis & Record<typeof STATE_KEY, OrchestratorState | undefined>\n\nexport const getState = (): OrchestratorState => {\n let state = globalSlot[STATE_KEY]\n if (!state) {\n state = { config: null, manifestPromise: null, identities: null, integration: \"core\" }\n globalSlot[STATE_KEY] = state\n }\n return state\n}\n","import type { Identities } from \"./types\"\n\nexport const SESSION_ID_KEY = \"mfe-orchestrator.sessionId\"\nexport const DEVICE_ID_KEY = \"mfe-orchestrator.deviceId\"\n\nconst PROBE_KEY = \"mfe-orchestrator.probe\"\n\ntype StorageKind = \"local\" | \"session\"\n\n/**\n * Ids minted while storage was unusable. They live for the lifetime of the page so that, even\n * without storage, every request of this page load carries one stable pair of ids.\n */\nconst inMemoryIds = new Map<string, string>()\n\nconst uuidFromRandomBytes = (bytes: Uint8Array): string => {\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex: string[] = []\n for (const byte of bytes) {\n hex.push(byte.toString(16).padStart(2, \"0\"))\n }\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`\n}\n\n/**\n * A v4 UUID. `crypto.randomUUID` is the intended path; the two fallbacks only exist so that a page\n * served over plain http, or an exotic runtime, still gets an id instead of an exception.\n */\nexport const newId = (): string => {\n const cryptoApi = globalThis.crypto\n try {\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID()\n }\n if (typeof cryptoApi?.getRandomValues === \"function\") {\n return uuidFromRandomBytes(cryptoApi.getRandomValues(new Uint8Array(16)))\n }\n } catch {\n // fall through to the non cryptographic fallback\n }\n const bytes = new Uint8Array(16)\n for (let index = 0; index < bytes.length; index++) {\n bytes[index] = Math.floor(Math.random() * 256)\n }\n return uuidFromRandomBytes(bytes)\n}\n\n/**\n * The requested storage, or `null` when it is missing or unusable.\n *\n * Both the property access and the write can throw: Safari in private mode exposes the object and\n * then refuses `setItem`, some hardened browsers throw a SecurityError on the access itself. The\n * write probe is the only reliable way to tell a usable storage from a decorative one.\n */\nconst openStorage = (kind: StorageKind): Storage | null => {\n try {\n const storage = kind === \"local\" ? globalThis.localStorage : globalThis.sessionStorage\n if (!storage) {\n return null\n }\n storage.setItem(PROBE_KEY, \"1\")\n storage.removeItem(PROBE_KEY)\n return storage\n } catch {\n return null\n }\n}\n\n/**\n * The id under `key`, read from storage and created on first use. Falls back to an id kept in\n * memory when storage cannot be used, so this never throws out of the SDK.\n */\nconst persistentId = (kind: StorageKind, key: string): string => {\n const storage = openStorage(kind)\n if (storage) {\n try {\n const stored = storage.getItem(key)\n if (stored) {\n return stored\n }\n const created = newId()\n storage.setItem(key, created)\n return created\n } catch {\n // storage passed the probe and failed anyway: keep going with an in memory id\n }\n }\n const remembered = inMemoryIds.get(key)\n if (remembered) {\n return remembered\n }\n const created = newId()\n inMemoryIds.set(key, created)\n return created\n}\n\n/** Reads, and creates when needed, the session and device ids. */\nexport const readIdentities = (): Identities => ({\n sessionId: persistentId(\"session\", SESSION_ID_KEY),\n deviceId: persistentId(\"local\", DEVICE_ID_KEY)\n})\n","import { diagnoseConfig, type Integration, invalidConfigMessage, noConfigMessage, notConfiguredMessage, PREFIX } from \"./errors\"\nimport { getState } from \"./state\"\nimport { readIdentities } from \"./storage\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport type { ConfigProblem, Integration } from \"./errors\"\nexport type { GlobalVariable, Identities, Manifest, Microfrontend, OrchestratorConfig } from \"./types\"\n\nconst withoutTrailingSlash = (value: string): string => value.replace(/\\/+$/, \"\")\n\nconst resolveUserId = async (userId: OrchestratorConfig[\"userId\"]): Promise<string | undefined> => {\n const value = typeof userId === \"function\" ? await userId() : userId\n return value === undefined || value === null || value === \"\" ? undefined : String(value)\n}\n\n/** Everything but the identity: the part of the configuration that is fixed for a page load. */\nconst sameTarget = (left: OrchestratorConfig, right: OrchestratorConfig): boolean =>\n left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment\n\nconst sameConfig = (left: OrchestratorConfig, right: OrchestratorConfig): boolean => sameTarget(left, right) && left.userId === right.userId\n\n/**\n * Whether replacing the identity would change nothing. Two getters are never considered equal, even the\n * same one twice: what a function returns is exactly what this side cannot know, so a host handing one\n * over is taken at its word and the manifest is re-fetched.\n */\nconst sameUserId = (left: OrchestratorConfig[\"userId\"], right: OrchestratorConfig[\"userId\"]): boolean => typeof left !== \"function\" && typeof right !== \"function\" && left === right\n\n/**\n * Rejects a configuration the client could not use, with a message that names the option, shows what\n * actually arrived and prints the call to write. environment is deliberately not required: without\n * it the backend resolves it from the domain. It is still checked for type, because a non string\n * there would silently end up percent encoded into the path.\n */\nconst requireConfig = (config: OrchestratorConfig, integration: Integration): void => {\n if (typeof config !== \"object\" || config === null) {\n throw new Error(noConfigMessage(config, integration))\n }\n const problems = diagnoseConfig(config)\n if (problems.length > 0) {\n throw new Error(invalidConfigMessage(problems, integration))\n }\n if (config.environment !== undefined && config.environment !== null && typeof config.environment !== \"string\") {\n throw new Error(\n `${PREFIX} configure() received environment as a ${typeof config.environment}, not a string. Pass the environment slug as it appears in the console, ex. \"DEV\", or leave it out to let the backend resolve it from the domain of this page.`\n )\n }\n}\n\n/** Notices about a stored configuration that works but probably does not do what the host meant. */\nconst warnAboutConfig = (config: OrchestratorConfig): void => {\n if (typeof config.environment === \"string\" && config.environment.trim() === \"\") {\n console.warn(\n `${PREFIX} configure() received an empty environment, so the client falls back to the auto routes and the backend resolves the environment from the domain of this page. Remove the option if that is what you want, or check the variable that feeds it.`\n )\n }\n}\n\n/**\n * Two shapes, one per route family. With an explicit environment the slug is the last segment; with\n * no environment the \"auto\" segment takes its place before the project id and the backend resolves\n * the environment from the domain the request comes from.\n */\nconst manifestPath = (config: OrchestratorConfig): string => {\n const projectId = encodeURIComponent(config.projectId)\n return config.environment ? `/serve/all/${projectId}/${encodeURIComponent(config.environment)}` : `/serve/all/auto/${projectId}`\n}\n\nconst manifestUrl = async (config: OrchestratorConfig): Promise<string> => {\n const { sessionId, deviceId } = identities()\n const query = new URLSearchParams({ mfeSessionId: sessionId, mfeDeviceId: deviceId })\n // Resolved as late as possible: the host may only know the user after its own auth round trip.\n const userId = await resolveUserId(config.userId)\n if (userId) {\n query.set(\"mfeUserId\", userId)\n }\n return `${withoutTrailingSlash(config.backendUrl)}${manifestPath(config)}?${query.toString()}`\n}\n\n/**\n * What a status usually means on this route. The backend answers the same 404 for an unknown project\n * and for an unknown environment, and the two are indistinguishable from here, so both are named.\n */\nconst statusHint = (status: number, config: OrchestratorConfig): string => {\n if (status === 404) {\n const environment = config.environment\n ? `the environment \"${config.environment}\" does not exist in it`\n : \"no environment of that project declares the domain this page is served on, which is what the auto route resolves on\"\n return `\\n\\nA 404 on this route means the backend did not find what the URL names: either the project id \"${config.projectId}\" is not a project of this console, or ${environment}. Check both in the console, and check that backendUrl points at the console API of the same instance.`\n }\n if (status === 401 || status === 403) {\n return `\\n\\nThe console refused the request. Check that the project id \"${config.projectId}\" belongs to the instance backendUrl points at, and that this domain is allowed to read its manifest.`\n }\n return \"\"\n}\n\nconst fetchManifest = async (config: OrchestratorConfig): Promise<Manifest> => {\n const url = await manifestUrl(config)\n // No retry in v1: whatever fetch throws travels straight to the caller.\n const response = await fetch(url, { headers: { accept: \"application/json\" } })\n if (!response.ok) {\n throw new Error(`${PREFIX} the manifest request failed with ${response.status} ${response.statusText}. GET ${url}${statusHint(response.status, config)}`)\n }\n const payload = (await response.json()) as Partial<Manifest> | null\n return {\n globalVariables: payload?.globalVariables ?? [],\n microfrontends: payload?.microfrontends ?? []\n }\n}\n\n/**\n * Hands the client its configuration. Call it once, synchronously, before any remote is imported.\n *\n * `backendUrl` and `projectId` are required. `environment` is not: omitting it makes the client use\n * the \"auto\" routes, where the backend resolves the environment from the domain of the host page.\n *\n * Idempotent: calling it again with the same options is a no op, so a framework provider may safely\n * call it on every render. A second call with different options is ignored, with a warning, because\n * the manifest of this page load may already be in flight or resolved. The user is the exception, and\n * it changes through `setUserId()`, not through a second call here.\n */\nexport const configure = (config: OrchestratorConfig): void => {\n const state = getState()\n requireConfig(config, state.integration)\n const current = state.config\n if (current) {\n if (!sameConfig(current, config)) {\n console.warn(\n sameTarget(current, config)\n ? `${PREFIX} configure() was called again with a different userId. The configuration is fixed for this page load, so this one is ignored: call setUserId() instead, which is the supported way to change the user mid session and also drops the memoized manifest, so the next read is decided on the new identity.`\n : `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`\n )\n }\n return\n }\n state.config = { ...config }\n warnAboutConfig(config)\n}\n\n/**\n * Replaces the identity the backend decides a user based canary on, after the client was configured.\n *\n * `configure()` is deliberately once only, and this is the one option that legitimately changes while\n * the page is alive: a login, a logout, an account switch. So it gets its own setter, and that setter\n * does what `configure()` must not — it drops the memoized manifest, so the next `manifest()`,\n * `remoteUrl()` or `globalVariables()` asks the backend again and is answered for the new user.\n *\n * Pass `undefined` on logout: the next request then carries no `mfeUserId` at all, which is what makes\n * the backend hand out the stable version again.\n *\n * What this does NOT do is reload the remotes already imported. The federation runtime keeps the\n * container it has, so a microfrontend already on the page stays on the version drawn for the previous\n * user, and only remotes resolved after this call see the new one. When the whole page must be\n * consistent, follow the identity change with a reload; when the host mounts its remotes behind its own\n * auth guard, calling this before the guard opens is enough.\n *\n * Setting the same plain value again is a no op, so an auth store may call it on every emission without\n * costing a request. A getter is always taken as a change, since what it returns is precisely what this\n * side cannot know.\n *\n * A request already in flight is not cancelled: whoever is awaiting it still receives the manifest of\n * the previous identity. Only the memo is dropped.\n */\nexport const setUserId = (userId: OrchestratorConfig[\"userId\"]): void => {\n const state = getState()\n const current = state.config\n if (!current) {\n throw new Error(notConfiguredMessage(\"setUserId()\", state.integration))\n }\n if (sameUserId(current.userId, userId)) {\n return\n }\n state.config = { ...current, userId }\n state.manifestPromise = null\n}\n\n/**\n * @internal Lets a framework adapter say which package the host is really using, so a configuration\n * error prints the snippet of that API instead of the bare `configure()` one. Idempotent, and never\n * needed by an application: the adapters call it as they load.\n */\nexport const registerIntegration = (integration: Integration): void => {\n getState().integration = integration\n}\n\n/**\n * The whole manifest of the environment, fetched once per page load and memoized as a promise, so\n * that concurrent callers share the single request in flight.\n *\n * A successful result is memoized for good. A failed attempt is not: the memo is dropped when the\n * shared attempt settles as rejected, so the next caller starts a fresh request. That is not a retry\n * — nothing here loops or backs off — it only means one flaky lookup at boot does not condemn the\n * page to reject every `remoteUrl()` until a full reload.\n */\nconst loadManifest = (caller: string): Promise<Manifest> => {\n const state = getState()\n const config = state.config\n if (!config) {\n // Not memoized: the host may still configure the client and try again.\n return Promise.reject(new Error(notConfiguredMessage(caller, state.integration)))\n }\n if (!state.manifestPromise) {\n // Assigned before the first await inside fetchManifest, which is what makes N concurrent\n // callers collapse onto one request.\n const attempt = fetchManifest(config)\n state.manifestPromise = attempt\n // Cleared once, when the shared attempt settles, not in each caller's own catch: every\n // caller already waiting on this attempt still gets its rejection. The identity check keeps\n // a late failure from evicting a newer attempt.\n attempt.catch(() => {\n if (state.manifestPromise === attempt) {\n state.manifestPromise = null\n }\n })\n }\n return state.manifestPromise\n}\n\n/** The whole manifest of the environment. See `loadManifest` for the memoization contract. */\nexport const manifest = (): Promise<Manifest> => loadManifest(\"manifest()\")\n\n/**\n * The ready to use, version pinned URL of a remote. Awaits the manifest internally.\n *\n * The returned URL is used verbatim: the host never parses the version out of it and never strips\n * the `_v/<version>/` segment, or a classic script would load its chunks off another version.\n */\nexport const remoteUrl = async (slug: string): Promise<string> => {\n const { microfrontends } = await loadManifest(`remoteUrl(\"${slug}\")`)\n const found = microfrontends.find(microfrontend => microfrontend.slug === slug)\n if (!found) {\n const available = microfrontends.map(microfrontend => `\"${microfrontend.slug}\"`).join(\", \")\n const environment = getState().config?.environment\n // With no configured environment the host cannot name the one it was served: only the backend knows.\n const where = environment ? `environment \"${environment}\"` : \"the environment resolved from this domain\"\n throw new Error(`${PREFIX} unknown microfrontend slug \"${slug}\". Available in ${where}: ${available || \"none, this environment serves no microfrontend\"}.`)\n }\n if (!found.url) {\n throw new Error(`${PREFIX} the microfrontend \"${slug}\" is in the manifest but carries no url. Check its deployment in the console.`)\n }\n return found.url\n}\n\n/** The global variables of the environment, as a plain object. */\nexport const globalVariables = async (): Promise<Record<string, string>> => {\n const { globalVariables: variables } = await loadManifest(\"globalVariables()\")\n const result: Record<string, string> = {}\n for (const variable of variables) {\n if (variable && typeof variable.key === \"string\") {\n result[variable.key] = variable.value\n }\n }\n return result\n}\n\n/**\n * The session and device ids of this page, exposed for telemetry and debugging. Created on first\n * use and stable for the lifetime of the page, whether or not storage is available.\n */\nexport const identities = (): Identities => {\n const state = getState()\n if (!state.identities) {\n state.identities = readIdentities()\n }\n return state.identities\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -29,6 +29,10 @@ interface OrchestratorConfig {
29
29
  /**
30
30
  * Identity of the logged in user, if the host has one. May be a plain value, a getter, or an
31
31
  * async getter resolved right before the manifest request is issued.
32
+ *
33
+ * A host that only learns its user later may leave it out here and call `setUserId()` when the
34
+ * user logs in, logs out or is switched: unlike a second `configure()`, that one takes effect,
35
+ * because it drops the memoized manifest.
32
36
  */
33
37
  userId?: string | (() => string | undefined | Promise<string | undefined>);
34
38
  }
@@ -73,9 +77,35 @@ interface Identities {
73
77
  *
74
78
  * Idempotent: calling it again with the same options is a no op, so a framework provider may safely
75
79
  * call it on every render. A second call with different options is ignored, with a warning, because
76
- * the manifest of this page load may already be in flight or resolved.
80
+ * the manifest of this page load may already be in flight or resolved. The user is the exception, and
81
+ * it changes through `setUserId()`, not through a second call here.
77
82
  */
78
83
  declare const configure: (config: OrchestratorConfig) => void;
84
+ /**
85
+ * Replaces the identity the backend decides a user based canary on, after the client was configured.
86
+ *
87
+ * `configure()` is deliberately once only, and this is the one option that legitimately changes while
88
+ * the page is alive: a login, a logout, an account switch. So it gets its own setter, and that setter
89
+ * does what `configure()` must not — it drops the memoized manifest, so the next `manifest()`,
90
+ * `remoteUrl()` or `globalVariables()` asks the backend again and is answered for the new user.
91
+ *
92
+ * Pass `undefined` on logout: the next request then carries no `mfeUserId` at all, which is what makes
93
+ * the backend hand out the stable version again.
94
+ *
95
+ * What this does NOT do is reload the remotes already imported. The federation runtime keeps the
96
+ * container it has, so a microfrontend already on the page stays on the version drawn for the previous
97
+ * user, and only remotes resolved after this call see the new one. When the whole page must be
98
+ * consistent, follow the identity change with a reload; when the host mounts its remotes behind its own
99
+ * auth guard, calling this before the guard opens is enough.
100
+ *
101
+ * Setting the same plain value again is a no op, so an auth store may call it on every emission without
102
+ * costing a request. A getter is always taken as a change, since what it returns is precisely what this
103
+ * side cannot know.
104
+ *
105
+ * A request already in flight is not cancelled: whoever is awaiting it still receives the manifest of
106
+ * the previous identity. Only the memo is dropped.
107
+ */
108
+ declare const setUserId: (userId: OrchestratorConfig["userId"]) => void;
79
109
  /**
80
110
  * @internal Lets a framework adapter say which package the host is really using, so a configuration
81
111
  * error prints the snippet of that API instead of the bare `configure()` one. Idempotent, and never
@@ -99,4 +129,4 @@ declare const globalVariables: () => Promise<Record<string, string>>;
99
129
  */
100
130
  declare const identities: () => Identities;
101
131
 
102
- export { type ConfigProblem, type GlobalVariable, type Identities, type Integration, type Manifest, type Microfrontend, type OrchestratorConfig, configure, globalVariables, identities, manifest, registerIntegration, remoteUrl };
132
+ export { type ConfigProblem, type GlobalVariable, type Identities, type Integration, type Manifest, type Microfrontend, type OrchestratorConfig, configure, globalVariables, identities, manifest, registerIntegration, remoteUrl, setUserId };
package/dist/index.d.ts CHANGED
@@ -29,6 +29,10 @@ interface OrchestratorConfig {
29
29
  /**
30
30
  * Identity of the logged in user, if the host has one. May be a plain value, a getter, or an
31
31
  * async getter resolved right before the manifest request is issued.
32
+ *
33
+ * A host that only learns its user later may leave it out here and call `setUserId()` when the
34
+ * user logs in, logs out or is switched: unlike a second `configure()`, that one takes effect,
35
+ * because it drops the memoized manifest.
32
36
  */
33
37
  userId?: string | (() => string | undefined | Promise<string | undefined>);
34
38
  }
@@ -73,9 +77,35 @@ interface Identities {
73
77
  *
74
78
  * Idempotent: calling it again with the same options is a no op, so a framework provider may safely
75
79
  * call it on every render. A second call with different options is ignored, with a warning, because
76
- * the manifest of this page load may already be in flight or resolved.
80
+ * the manifest of this page load may already be in flight or resolved. The user is the exception, and
81
+ * it changes through `setUserId()`, not through a second call here.
77
82
  */
78
83
  declare const configure: (config: OrchestratorConfig) => void;
84
+ /**
85
+ * Replaces the identity the backend decides a user based canary on, after the client was configured.
86
+ *
87
+ * `configure()` is deliberately once only, and this is the one option that legitimately changes while
88
+ * the page is alive: a login, a logout, an account switch. So it gets its own setter, and that setter
89
+ * does what `configure()` must not — it drops the memoized manifest, so the next `manifest()`,
90
+ * `remoteUrl()` or `globalVariables()` asks the backend again and is answered for the new user.
91
+ *
92
+ * Pass `undefined` on logout: the next request then carries no `mfeUserId` at all, which is what makes
93
+ * the backend hand out the stable version again.
94
+ *
95
+ * What this does NOT do is reload the remotes already imported. The federation runtime keeps the
96
+ * container it has, so a microfrontend already on the page stays on the version drawn for the previous
97
+ * user, and only remotes resolved after this call see the new one. When the whole page must be
98
+ * consistent, follow the identity change with a reload; when the host mounts its remotes behind its own
99
+ * auth guard, calling this before the guard opens is enough.
100
+ *
101
+ * Setting the same plain value again is a no op, so an auth store may call it on every emission without
102
+ * costing a request. A getter is always taken as a change, since what it returns is precisely what this
103
+ * side cannot know.
104
+ *
105
+ * A request already in flight is not cancelled: whoever is awaiting it still receives the manifest of
106
+ * the previous identity. Only the memo is dropped.
107
+ */
108
+ declare const setUserId: (userId: OrchestratorConfig["userId"]) => void;
79
109
  /**
80
110
  * @internal Lets a framework adapter say which package the host is really using, so a configuration
81
111
  * error prints the snippet of that API instead of the bare `configure()` one. Idempotent, and never
@@ -99,4 +129,4 @@ declare const globalVariables: () => Promise<Record<string, string>>;
99
129
  */
100
130
  declare const identities: () => Identities;
101
131
 
102
- export { type ConfigProblem, type GlobalVariable, type Identities, type Integration, type Manifest, type Microfrontend, type OrchestratorConfig, configure, globalVariables, identities, manifest, registerIntegration, remoteUrl };
132
+ export { type ConfigProblem, type GlobalVariable, type Identities, type Integration, type Manifest, type Microfrontend, type OrchestratorConfig, configure, globalVariables, identities, manifest, registerIntegration, remoteUrl, setUserId };
package/dist/index.js CHANGED
@@ -231,7 +231,9 @@ var resolveUserId = async (userId) => {
231
231
  const value = typeof userId === "function" ? await userId() : userId;
232
232
  return value === void 0 || value === null || value === "" ? void 0 : String(value);
233
233
  };
234
- var sameConfig = (left, right) => left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment && left.userId === right.userId;
234
+ var sameTarget = (left, right) => left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment;
235
+ var sameConfig = (left, right) => sameTarget(left, right) && left.userId === right.userId;
236
+ var sameUserId = (left, right) => typeof left !== "function" && typeof right !== "function" && left === right;
235
237
  var requireConfig = (config, integration) => {
236
238
  if (typeof config !== "object" || config === null) {
237
239
  throw new Error(noConfigMessage(config, integration));
@@ -299,7 +301,7 @@ var configure = (config) => {
299
301
  if (current) {
300
302
  if (!sameConfig(current, config)) {
301
303
  console.warn(
302
- `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`
304
+ sameTarget(current, config) ? `${PREFIX} configure() was called again with a different userId. The configuration is fixed for this page load, so this one is ignored: call setUserId() instead, which is the supported way to change the user mid session and also drops the memoized manifest, so the next read is decided on the new identity.` : `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`
303
305
  );
304
306
  }
305
307
  return;
@@ -307,6 +309,18 @@ var configure = (config) => {
307
309
  state.config = { ...config };
308
310
  warnAboutConfig(config);
309
311
  };
312
+ var setUserId = (userId) => {
313
+ const state = getState();
314
+ const current = state.config;
315
+ if (!current) {
316
+ throw new Error(notConfiguredMessage("setUserId()", state.integration));
317
+ }
318
+ if (sameUserId(current.userId, userId)) {
319
+ return;
320
+ }
321
+ state.config = { ...current, userId };
322
+ state.manifestPromise = null;
323
+ };
310
324
  var registerIntegration = (integration) => {
311
325
  getState().integration = integration;
312
326
  };
@@ -360,6 +374,6 @@ var identities = () => {
360
374
  return state.identities;
361
375
  };
362
376
 
363
- export { configure, globalVariables, identities, manifest, registerIntegration, remoteUrl };
377
+ export { configure, globalVariables, identities, manifest, registerIntegration, remoteUrl, setUserId };
364
378
  //# sourceMappingURL=index.js.map
365
379
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/state.ts","../src/storage.ts","../src/index.ts"],"names":["created"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Everything the client says when its configuration is wrong or absent.\n *\n * The two required options almost always arrive from build time environment variables, so the\n * failure the host sees is not \"a value is invalid\" but \"nothing reached the bundle\". Messages here\n * are written for that moment: they name the option, show what actually arrived, say where the real\n * value comes from, and print the exact call to write, in the flavour of the package the host uses.\n */\n\nexport const PREFIX = \"[@mfe-orchestrator-hub/client]\"\n\n/** Which package the host went through. Only decides which snippet an error prints. */\nexport type Integration = \"core\" | \"react\" | \"vue\" | \"angular\"\n\n/** The two options without which nothing can be requested. */\nexport type RequiredOption = \"backendUrl\" | \"projectId\"\n\nconst EXAMPLE_BACKEND_URL = \"https://console.mfe-orchestrator.dev/api\"\nconst EXAMPLE_PROJECT_ID = \"6f1b2c3d4e5f6a7b8c9d0e1f\"\n\nconst SNIPPETS: Record<Integration, string> = {\n core: `import { configure } from \"@mfe-orchestrator-hub/client\"\n\nconfigure({\n backendUrl: \"${EXAMPLE_BACKEND_URL}\",\n projectId: \"${EXAMPLE_PROJECT_ID}\"\n})`,\n react: `import { OrchestratorProvider } from \"@mfe-orchestrator-hub/client-react\"\n\n<OrchestratorProvider config={{ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }}>\n <App />\n</OrchestratorProvider>`,\n vue: `import { createOrchestrator } from \"@mfe-orchestrator-hub/client-vue\"\n\napp.use(createOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }))`,\n angular: `import { provideOrchestrator } from \"@mfe-orchestrator-hub/client-angular\"\n\nbootstrapApplication(AppComponent, {\n providers: [provideOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" })]\n})`\n}\n\nconst WHERE: Record<Integration, string> = {\n core: \"Call it once, at the very top of the host entry point, before anything imports a remote.\",\n react: \"Render it above every component that resolves a remote. Better still, call configure() at the very top of the entry point: a bundler may import a remote before React mounts.\",\n vue: \"Install the plugin before mounting the app. Better still, call configure() at the very top of the entry point: a bundler may import a remote before the app is created.\",\n angular: \"Pass it to bootstrapApplication(). Better still, call configure() at the very top of main.ts: a lazily loaded remote must find the client already configured.\"\n}\n\nconst WHAT_IT_IS: Record<RequiredOption, string> = {\n backendUrl: `It is the base URL of the console API, protocol included, ex. \"${EXAMPLE_BACKEND_URL}\". A path on the same origin as the host, ex. \"/api\", works too.`,\n projectId: `It is the id of the project in the console: open the project and copy it from its page, ex. \"${EXAMPLE_PROJECT_ID}\".`\n}\n\n/** The name the value travels under from the bundler config into the bundle, per toolchain. */\nconst BUILD_VARIABLE: Record<RequiredOption, { vite: string; webpack: string }> = {\n backendUrl: { vite: \"VITE_MFE_BACKEND_URL\", webpack: \"MFE_BACKEND_URL\" },\n projectId: { vite: \"VITE_MFE_PROJECT_ID\", webpack: \"MFE_PROJECT_ID\" }\n}\n\n/**\n * What an option that was never substituted into the bundle looks like.\n *\n * The bundler config is named before the .env file on purpose: it is where the console writes both\n * values when it generates the config, so it is where they are missing from when they are missing.\n */\nconst missingEnvHint = (option: RequiredOption): string =>\n `Nothing arrived here at all, which is what a value that never reached the bundle looks like: check ${BUILD_VARIABLE[option].vite} (Vite) or ${BUILD_VARIABLE[option].webpack} (webpack) in the build that produced this bundle. The generated configs carry it in the \"define\" block of vite.config, or in the DefinePlugin of webpack.config, so look there first; declared only in a .env file the build never reads, it looks exactly like this.`\n\n/** Values that mean \"the template was never filled in\". */\nconst PLACEHOLDER = /^(…|\\.{3}|undefined|null|nan|<[^>]*>|\\{\\{[^}]*\\}\\}|\\$\\{[^}]*\\}|your[-_ ]?[a-z]*|x{3,}|change[-_ ]?me|todo|tbd)$/i\n\n/** Long values are cut: an error message is not the place to print a whole JWT. */\nconst quoted = (value: string): string => JSON.stringify(value.length > 120 ? `${value.slice(0, 120)}…` : value)\n\nconst described = (value: unknown): string => {\n if (value === null) {\n return \"null\"\n }\n if (Array.isArray(value)) {\n return \"an array\"\n }\n const type = typeof value\n return type === \"object\" || type === \"function\" ? `a ${type}` : `a ${type} (${String(value)})`\n}\n\n/** Same key modulo case and separators: projectID, project_id, PROJECT-ID all collapse onto projectid. */\nconst normalized = (key: string): string => key.toLowerCase().replace(/[^a-z0-9]/g, \"\")\n\nconst ALIASES: Record<RequiredOption, string[]> = {\n backendUrl: [\"backendurl\", \"backendbaseurl\", \"apiurl\", \"baseurl\", \"consoleurl\", \"url\", \"backend\"],\n projectId: [\"projectid\", \"project\", \"idproject\", \"projectuuid\", \"projectkey\"]\n}\n\n/**\n * The key the host actually wrote, when it looks like a misspelling of the one that is missing.\n * `projectID` is by far the most common: it is silently ignored, so without this the message would\n * claim the option is absent while the developer stares at a line that clearly sets it.\n */\nconst confusableKey = (option: RequiredOption, config: unknown): string | undefined => {\n if (typeof config !== \"object\" || config === null) {\n return undefined\n }\n const candidates = ALIASES[option]\n return Object.keys(config).find(key => key !== option && candidates.includes(normalized(key)))\n}\n\n/** One thing that is wrong with one option, already spelled out. */\nexport interface ConfigProblem {\n option: RequiredOption\n /** Predicate completing \"<option> …\", ex. `is missing`. */\n what: string\n /** Extra lines, printed under the option, that say how to fix this particular case. */\n hints: string[]\n}\n\nconst problem = (option: RequiredOption, what: string, ...hints: (string | undefined)[]): ConfigProblem => ({\n option,\n what,\n hints: [WHAT_IT_IS[option], ...hints].filter((hint): hint is string => Boolean(hint))\n})\n\n/**\n * A backendUrl the client can actually build a request on: an absolute http(s) URL, or a path on the\n * host's own origin, which `fetch` resolves against the page.\n */\nconst diagnoseBackendUrl = (value: string): ConfigProblem | null => {\n const trimmed = value.trim()\n if (trimmed.startsWith(\"/\")) {\n return null\n }\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, which is not a URL`,\n trimmed.includes(\".\") || trimmed.includes(\":\")\n ? `It looks like a host without a protocol: write \"https://${trimmed}\" instead, or \"/${trimmed.replace(/^\\/+/, \"\")}\" if the console API answers on the same origin as this page.`\n : undefined\n )\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, whose \"${parsed.protocol.replace(\":\", \"\")}\" scheme is neither http nor https`,\n 'A bare \"host:port\" is read as a scheme: write \"http://localhost:3000/api\", not \"localhost:3000/api\".'\n )\n }\n return null\n}\n\n/** Everything wrong with one required option, or null when it is usable. */\nconst diagnose = (option: RequiredOption, config: unknown): ConfigProblem | null => {\n const value = (config as Record<string, unknown> | null | undefined)?.[option]\n const typo = confusableKey(option, config)\n const typoHint = typo ? `The configuration carries \"${typo}\", which the client ignores. The option is spelled \"${option}\".` : undefined\n\n if (value === undefined || value === null) {\n return problem(option, value === null ? \"is null\" : \"is missing\", typoHint, typo ? undefined : missingEnvHint(option))\n }\n if (typeof value !== \"string\") {\n return problem(option, `is ${described(value)}, not a string`, typoHint)\n }\n if (value.trim() === \"\") {\n return problem(option, value === \"\" ? \"is an empty string\" : \"holds nothing but whitespace\", typoHint, missingEnvHint(option))\n }\n if (PLACEHOLDER.test(value.trim())) {\n const looksLikeAnUnsetVariable = /^(undefined|null|nan)$/i.test(value.trim())\n return problem(option, `is still the placeholder ${quoted(value)}`, typoHint, looksLikeAnUnsetVariable ? missingEnvHint(option) : undefined)\n }\n if (option === \"projectId\" && value.trim() !== value) {\n // Percent encoded into the path, so the padding would travel to the backend as %20.\n return problem(\n \"projectId\",\n `is ${quoted(value)}, padded with whitespace`,\n \"Trim the value: it is percent encoded into the manifest URL, so the spaces would reach the backend as part of the id.\"\n )\n }\n return option === \"backendUrl\" ? diagnoseBackendUrl(value) : null\n}\n\n/** Every problem of a configuration, in the order the options are declared. Empty means usable. */\nexport const diagnoseConfig = (config: unknown): ConfigProblem[] =>\n ([\"backendUrl\", \"projectId\"] as const).map(option => diagnose(option, config)).filter((found): found is ConfigProblem => found !== null)\n\nconst bulleted = (problems: ConfigProblem[]): string => problems.map(({ option, what, hints }) => [` • ${option} ${what}.`, ...hints.map(hint => ` → ${hint}`)].join(\"\\n\")).join(\"\\n\")\n\nconst indented = (block: string): string =>\n block\n .split(\"\\n\")\n .map(line => (line ? ` ${line}` : line))\n .join(\"\\n\")\n\nconst howToConfigure = (integration: Integration): string => `Configure the client like this:\\n\\n${indented(SNIPPETS[integration])}\\n\\n${WHERE[integration]}`\n\nconst listed = (options: RequiredOption[]): string => (options.length > 1 ? `${options.slice(0, -1).join(\", \")} and ${options.at(-1)}` : String(options[0]))\n\n/** The message thrown by `configure()` when what it received cannot be used. */\nexport const invalidConfigMessage = (problems: ConfigProblem[], integration: Integration): string => {\n const options = problems.map(({ option }) => option)\n const headline = `${PREFIX} configure() cannot start the client: ${listed(options)} ${options.length > 1 ? \"are\" : \"is\"} not usable.`\n return `${headline}\\n\\n${bulleted(problems)}\\n\\n${howToConfigure(integration)}`\n}\n\n/** The message thrown by `configure()` when it did not even receive an object. */\nexport const noConfigMessage = (config: unknown, integration: Integration): string =>\n `${PREFIX} configure() was called with ${config === undefined ? \"no argument\" : described(config)} instead of a configuration object. It needs at least backendUrl and projectId.\\n\\n${howToConfigure(integration)}`\n\n/** The message every read rejects with while the client has no configuration at all. */\nexport const notConfiguredMessage = (caller: string, integration: Integration): string =>\n `${PREFIX} the client is not configured: ${caller} was called before configure() ever ran, so neither backendUrl nor projectId is known and no manifest can be requested.\\n\\n${howToConfigure(integration)}`\n","import type { Integration } from \"./errors\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport interface OrchestratorState {\n config: OrchestratorConfig | null\n manifestPromise: Promise<Manifest> | null\n identities: Identities | null\n /** Set by the framework adapters as they load, so an error prints the snippet of their own API. */\n integration: Integration\n}\n\n/**\n * The state lives on `globalThis` under this key, not in a module scope variable.\n *\n * A host can end up with two copies of this package loaded at once: the app imports the ESM build\n * while something else pulls the CJS one, or the bundler config and the app resolve to different\n * chunks. Two module scopes would mean two configurations and two manifest requests, which is\n * exactly what the contract forbids. One well known global slot makes the singleton real.\n */\nexport const STATE_KEY = \"__mfe_orchestrator_client__\"\n\nconst globalSlot = globalThis as typeof globalThis & Record<typeof STATE_KEY, OrchestratorState | undefined>\n\nexport const getState = (): OrchestratorState => {\n let state = globalSlot[STATE_KEY]\n if (!state) {\n state = { config: null, manifestPromise: null, identities: null, integration: \"core\" }\n globalSlot[STATE_KEY] = state\n }\n return state\n}\n","import type { Identities } from \"./types\"\n\nexport const SESSION_ID_KEY = \"mfe-orchestrator.sessionId\"\nexport const DEVICE_ID_KEY = \"mfe-orchestrator.deviceId\"\n\nconst PROBE_KEY = \"mfe-orchestrator.probe\"\n\ntype StorageKind = \"local\" | \"session\"\n\n/**\n * Ids minted while storage was unusable. They live for the lifetime of the page so that, even\n * without storage, every request of this page load carries one stable pair of ids.\n */\nconst inMemoryIds = new Map<string, string>()\n\nconst uuidFromRandomBytes = (bytes: Uint8Array): string => {\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex: string[] = []\n for (const byte of bytes) {\n hex.push(byte.toString(16).padStart(2, \"0\"))\n }\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`\n}\n\n/**\n * A v4 UUID. `crypto.randomUUID` is the intended path; the two fallbacks only exist so that a page\n * served over plain http, or an exotic runtime, still gets an id instead of an exception.\n */\nexport const newId = (): string => {\n const cryptoApi = globalThis.crypto\n try {\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID()\n }\n if (typeof cryptoApi?.getRandomValues === \"function\") {\n return uuidFromRandomBytes(cryptoApi.getRandomValues(new Uint8Array(16)))\n }\n } catch {\n // fall through to the non cryptographic fallback\n }\n const bytes = new Uint8Array(16)\n for (let index = 0; index < bytes.length; index++) {\n bytes[index] = Math.floor(Math.random() * 256)\n }\n return uuidFromRandomBytes(bytes)\n}\n\n/**\n * The requested storage, or `null` when it is missing or unusable.\n *\n * Both the property access and the write can throw: Safari in private mode exposes the object and\n * then refuses `setItem`, some hardened browsers throw a SecurityError on the access itself. The\n * write probe is the only reliable way to tell a usable storage from a decorative one.\n */\nconst openStorage = (kind: StorageKind): Storage | null => {\n try {\n const storage = kind === \"local\" ? globalThis.localStorage : globalThis.sessionStorage\n if (!storage) {\n return null\n }\n storage.setItem(PROBE_KEY, \"1\")\n storage.removeItem(PROBE_KEY)\n return storage\n } catch {\n return null\n }\n}\n\n/**\n * The id under `key`, read from storage and created on first use. Falls back to an id kept in\n * memory when storage cannot be used, so this never throws out of the SDK.\n */\nconst persistentId = (kind: StorageKind, key: string): string => {\n const storage = openStorage(kind)\n if (storage) {\n try {\n const stored = storage.getItem(key)\n if (stored) {\n return stored\n }\n const created = newId()\n storage.setItem(key, created)\n return created\n } catch {\n // storage passed the probe and failed anyway: keep going with an in memory id\n }\n }\n const remembered = inMemoryIds.get(key)\n if (remembered) {\n return remembered\n }\n const created = newId()\n inMemoryIds.set(key, created)\n return created\n}\n\n/** Reads, and creates when needed, the session and device ids. */\nexport const readIdentities = (): Identities => ({\n sessionId: persistentId(\"session\", SESSION_ID_KEY),\n deviceId: persistentId(\"local\", DEVICE_ID_KEY)\n})\n","import { diagnoseConfig, type Integration, invalidConfigMessage, noConfigMessage, notConfiguredMessage, PREFIX } from \"./errors\"\nimport { getState } from \"./state\"\nimport { readIdentities } from \"./storage\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport type { ConfigProblem, Integration } from \"./errors\"\nexport type { GlobalVariable, Identities, Manifest, Microfrontend, OrchestratorConfig } from \"./types\"\n\nconst withoutTrailingSlash = (value: string): string => value.replace(/\\/+$/, \"\")\n\nconst resolveUserId = async (userId: OrchestratorConfig[\"userId\"]): Promise<string | undefined> => {\n const value = typeof userId === \"function\" ? await userId() : userId\n return value === undefined || value === null || value === \"\" ? undefined : String(value)\n}\n\nconst sameConfig = (left: OrchestratorConfig, right: OrchestratorConfig): boolean =>\n left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment && left.userId === right.userId\n\n/**\n * Rejects a configuration the client could not use, with a message that names the option, shows what\n * actually arrived and prints the call to write. environment is deliberately not required: without\n * it the backend resolves it from the domain. It is still checked for type, because a non string\n * there would silently end up percent encoded into the path.\n */\nconst requireConfig = (config: OrchestratorConfig, integration: Integration): void => {\n if (typeof config !== \"object\" || config === null) {\n throw new Error(noConfigMessage(config, integration))\n }\n const problems = diagnoseConfig(config)\n if (problems.length > 0) {\n throw new Error(invalidConfigMessage(problems, integration))\n }\n if (config.environment !== undefined && config.environment !== null && typeof config.environment !== \"string\") {\n throw new Error(\n `${PREFIX} configure() received environment as a ${typeof config.environment}, not a string. Pass the environment slug as it appears in the console, ex. \"DEV\", or leave it out to let the backend resolve it from the domain of this page.`\n )\n }\n}\n\n/** Notices about a stored configuration that works but probably does not do what the host meant. */\nconst warnAboutConfig = (config: OrchestratorConfig): void => {\n if (typeof config.environment === \"string\" && config.environment.trim() === \"\") {\n console.warn(\n `${PREFIX} configure() received an empty environment, so the client falls back to the auto routes and the backend resolves the environment from the domain of this page. Remove the option if that is what you want, or check the variable that feeds it.`\n )\n }\n}\n\n/**\n * Two shapes, one per route family. With an explicit environment the slug is the last segment; with\n * no environment the \"auto\" segment takes its place before the project id and the backend resolves\n * the environment from the domain the request comes from.\n */\nconst manifestPath = (config: OrchestratorConfig): string => {\n const projectId = encodeURIComponent(config.projectId)\n return config.environment ? `/serve/all/${projectId}/${encodeURIComponent(config.environment)}` : `/serve/all/auto/${projectId}`\n}\n\nconst manifestUrl = async (config: OrchestratorConfig): Promise<string> => {\n const { sessionId, deviceId } = identities()\n const query = new URLSearchParams({ mfeSessionId: sessionId, mfeDeviceId: deviceId })\n // Resolved as late as possible: the host may only know the user after its own auth round trip.\n const userId = await resolveUserId(config.userId)\n if (userId) {\n query.set(\"mfeUserId\", userId)\n }\n return `${withoutTrailingSlash(config.backendUrl)}${manifestPath(config)}?${query.toString()}`\n}\n\n/**\n * What a status usually means on this route. The backend answers the same 404 for an unknown project\n * and for an unknown environment, and the two are indistinguishable from here, so both are named.\n */\nconst statusHint = (status: number, config: OrchestratorConfig): string => {\n if (status === 404) {\n const environment = config.environment\n ? `the environment \"${config.environment}\" does not exist in it`\n : \"no environment of that project declares the domain this page is served on, which is what the auto route resolves on\"\n return `\\n\\nA 404 on this route means the backend did not find what the URL names: either the project id \"${config.projectId}\" is not a project of this console, or ${environment}. Check both in the console, and check that backendUrl points at the console API of the same instance.`\n }\n if (status === 401 || status === 403) {\n return `\\n\\nThe console refused the request. Check that the project id \"${config.projectId}\" belongs to the instance backendUrl points at, and that this domain is allowed to read its manifest.`\n }\n return \"\"\n}\n\nconst fetchManifest = async (config: OrchestratorConfig): Promise<Manifest> => {\n const url = await manifestUrl(config)\n // No retry in v1: whatever fetch throws travels straight to the caller.\n const response = await fetch(url, { headers: { accept: \"application/json\" } })\n if (!response.ok) {\n throw new Error(`${PREFIX} the manifest request failed with ${response.status} ${response.statusText}. GET ${url}${statusHint(response.status, config)}`)\n }\n const payload = (await response.json()) as Partial<Manifest> | null\n return {\n globalVariables: payload?.globalVariables ?? [],\n microfrontends: payload?.microfrontends ?? []\n }\n}\n\n/**\n * Hands the client its configuration. Call it once, synchronously, before any remote is imported.\n *\n * `backendUrl` and `projectId` are required. `environment` is not: omitting it makes the client use\n * the \"auto\" routes, where the backend resolves the environment from the domain of the host page.\n *\n * Idempotent: calling it again with the same options is a no op, so a framework provider may safely\n * call it on every render. A second call with different options is ignored, with a warning, because\n * the manifest of this page load may already be in flight or resolved.\n */\nexport const configure = (config: OrchestratorConfig): void => {\n const state = getState()\n requireConfig(config, state.integration)\n const current = state.config\n if (current) {\n if (!sameConfig(current, config)) {\n console.warn(\n `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`\n )\n }\n return\n }\n state.config = { ...config }\n warnAboutConfig(config)\n}\n\n/**\n * @internal Lets a framework adapter say which package the host is really using, so a configuration\n * error prints the snippet of that API instead of the bare `configure()` one. Idempotent, and never\n * needed by an application: the adapters call it as they load.\n */\nexport const registerIntegration = (integration: Integration): void => {\n getState().integration = integration\n}\n\n/**\n * The whole manifest of the environment, fetched once per page load and memoized as a promise, so\n * that concurrent callers share the single request in flight.\n *\n * A successful result is memoized for good. A failed attempt is not: the memo is dropped when the\n * shared attempt settles as rejected, so the next caller starts a fresh request. That is not a retry\n * — nothing here loops or backs off — it only means one flaky lookup at boot does not condemn the\n * page to reject every `remoteUrl()` until a full reload.\n */\nconst loadManifest = (caller: string): Promise<Manifest> => {\n const state = getState()\n const config = state.config\n if (!config) {\n // Not memoized: the host may still configure the client and try again.\n return Promise.reject(new Error(notConfiguredMessage(caller, state.integration)))\n }\n if (!state.manifestPromise) {\n // Assigned before the first await inside fetchManifest, which is what makes N concurrent\n // callers collapse onto one request.\n const attempt = fetchManifest(config)\n state.manifestPromise = attempt\n // Cleared once, when the shared attempt settles, not in each caller's own catch: every\n // caller already waiting on this attempt still gets its rejection. The identity check keeps\n // a late failure from evicting a newer attempt.\n attempt.catch(() => {\n if (state.manifestPromise === attempt) {\n state.manifestPromise = null\n }\n })\n }\n return state.manifestPromise\n}\n\n/** The whole manifest of the environment. See `loadManifest` for the memoization contract. */\nexport const manifest = (): Promise<Manifest> => loadManifest(\"manifest()\")\n\n/**\n * The ready to use, version pinned URL of a remote. Awaits the manifest internally.\n *\n * The returned URL is used verbatim: the host never parses the version out of it and never strips\n * the `_v/<version>/` segment, or a classic script would load its chunks off another version.\n */\nexport const remoteUrl = async (slug: string): Promise<string> => {\n const { microfrontends } = await loadManifest(`remoteUrl(\"${slug}\")`)\n const found = microfrontends.find(microfrontend => microfrontend.slug === slug)\n if (!found) {\n const available = microfrontends.map(microfrontend => `\"${microfrontend.slug}\"`).join(\", \")\n const environment = getState().config?.environment\n // With no configured environment the host cannot name the one it was served: only the backend knows.\n const where = environment ? `environment \"${environment}\"` : \"the environment resolved from this domain\"\n throw new Error(`${PREFIX} unknown microfrontend slug \"${slug}\". Available in ${where}: ${available || \"none, this environment serves no microfrontend\"}.`)\n }\n if (!found.url) {\n throw new Error(`${PREFIX} the microfrontend \"${slug}\" is in the manifest but carries no url. Check its deployment in the console.`)\n }\n return found.url\n}\n\n/** The global variables of the environment, as a plain object. */\nexport const globalVariables = async (): Promise<Record<string, string>> => {\n const { globalVariables: variables } = await loadManifest(\"globalVariables()\")\n const result: Record<string, string> = {}\n for (const variable of variables) {\n if (variable && typeof variable.key === \"string\") {\n result[variable.key] = variable.value\n }\n }\n return result\n}\n\n/**\n * The session and device ids of this page, exposed for telemetry and debugging. Created on first\n * use and stable for the lifetime of the page, whether or not storage is available.\n */\nexport const identities = (): Identities => {\n const state = getState()\n if (!state.identities) {\n state.identities = readIdentities()\n }\n return state.identities\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/state.ts","../src/storage.ts","../src/index.ts"],"names":["created"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Everything the client says when its configuration is wrong or absent.\n *\n * The two required options almost always arrive from build time environment variables, so the\n * failure the host sees is not \"a value is invalid\" but \"nothing reached the bundle\". Messages here\n * are written for that moment: they name the option, show what actually arrived, say where the real\n * value comes from, and print the exact call to write, in the flavour of the package the host uses.\n */\n\nexport const PREFIX = \"[@mfe-orchestrator-hub/client]\"\n\n/** Which package the host went through. Only decides which snippet an error prints. */\nexport type Integration = \"core\" | \"react\" | \"vue\" | \"angular\"\n\n/** The two options without which nothing can be requested. */\nexport type RequiredOption = \"backendUrl\" | \"projectId\"\n\nconst EXAMPLE_BACKEND_URL = \"https://console.mfe-orchestrator.dev/api\"\nconst EXAMPLE_PROJECT_ID = \"6f1b2c3d4e5f6a7b8c9d0e1f\"\n\nconst SNIPPETS: Record<Integration, string> = {\n core: `import { configure } from \"@mfe-orchestrator-hub/client\"\n\nconfigure({\n backendUrl: \"${EXAMPLE_BACKEND_URL}\",\n projectId: \"${EXAMPLE_PROJECT_ID}\"\n})`,\n react: `import { OrchestratorProvider } from \"@mfe-orchestrator-hub/client-react\"\n\n<OrchestratorProvider config={{ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }}>\n <App />\n</OrchestratorProvider>`,\n vue: `import { createOrchestrator } from \"@mfe-orchestrator-hub/client-vue\"\n\napp.use(createOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" }))`,\n angular: `import { provideOrchestrator } from \"@mfe-orchestrator-hub/client-angular\"\n\nbootstrapApplication(AppComponent, {\n providers: [provideOrchestrator({ backendUrl: \"${EXAMPLE_BACKEND_URL}\", projectId: \"${EXAMPLE_PROJECT_ID}\" })]\n})`\n}\n\nconst WHERE: Record<Integration, string> = {\n core: \"Call it once, at the very top of the host entry point, before anything imports a remote.\",\n react: \"Render it above every component that resolves a remote. Better still, call configure() at the very top of the entry point: a bundler may import a remote before React mounts.\",\n vue: \"Install the plugin before mounting the app. Better still, call configure() at the very top of the entry point: a bundler may import a remote before the app is created.\",\n angular: \"Pass it to bootstrapApplication(). Better still, call configure() at the very top of main.ts: a lazily loaded remote must find the client already configured.\"\n}\n\nconst WHAT_IT_IS: Record<RequiredOption, string> = {\n backendUrl: `It is the base URL of the console API, protocol included, ex. \"${EXAMPLE_BACKEND_URL}\". A path on the same origin as the host, ex. \"/api\", works too.`,\n projectId: `It is the id of the project in the console: open the project and copy it from its page, ex. \"${EXAMPLE_PROJECT_ID}\".`\n}\n\n/** The name the value travels under from the bundler config into the bundle, per toolchain. */\nconst BUILD_VARIABLE: Record<RequiredOption, { vite: string; webpack: string }> = {\n backendUrl: { vite: \"VITE_MFE_BACKEND_URL\", webpack: \"MFE_BACKEND_URL\" },\n projectId: { vite: \"VITE_MFE_PROJECT_ID\", webpack: \"MFE_PROJECT_ID\" }\n}\n\n/**\n * What an option that was never substituted into the bundle looks like.\n *\n * The bundler config is named before the .env file on purpose: it is where the console writes both\n * values when it generates the config, so it is where they are missing from when they are missing.\n */\nconst missingEnvHint = (option: RequiredOption): string =>\n `Nothing arrived here at all, which is what a value that never reached the bundle looks like: check ${BUILD_VARIABLE[option].vite} (Vite) or ${BUILD_VARIABLE[option].webpack} (webpack) in the build that produced this bundle. The generated configs carry it in the \"define\" block of vite.config, or in the DefinePlugin of webpack.config, so look there first; declared only in a .env file the build never reads, it looks exactly like this.`\n\n/** Values that mean \"the template was never filled in\". */\nconst PLACEHOLDER = /^(…|\\.{3}|undefined|null|nan|<[^>]*>|\\{\\{[^}]*\\}\\}|\\$\\{[^}]*\\}|your[-_ ]?[a-z]*|x{3,}|change[-_ ]?me|todo|tbd)$/i\n\n/** Long values are cut: an error message is not the place to print a whole JWT. */\nconst quoted = (value: string): string => JSON.stringify(value.length > 120 ? `${value.slice(0, 120)}…` : value)\n\nconst described = (value: unknown): string => {\n if (value === null) {\n return \"null\"\n }\n if (Array.isArray(value)) {\n return \"an array\"\n }\n const type = typeof value\n return type === \"object\" || type === \"function\" ? `a ${type}` : `a ${type} (${String(value)})`\n}\n\n/** Same key modulo case and separators: projectID, project_id, PROJECT-ID all collapse onto projectid. */\nconst normalized = (key: string): string => key.toLowerCase().replace(/[^a-z0-9]/g, \"\")\n\nconst ALIASES: Record<RequiredOption, string[]> = {\n backendUrl: [\"backendurl\", \"backendbaseurl\", \"apiurl\", \"baseurl\", \"consoleurl\", \"url\", \"backend\"],\n projectId: [\"projectid\", \"project\", \"idproject\", \"projectuuid\", \"projectkey\"]\n}\n\n/**\n * The key the host actually wrote, when it looks like a misspelling of the one that is missing.\n * `projectID` is by far the most common: it is silently ignored, so without this the message would\n * claim the option is absent while the developer stares at a line that clearly sets it.\n */\nconst confusableKey = (option: RequiredOption, config: unknown): string | undefined => {\n if (typeof config !== \"object\" || config === null) {\n return undefined\n }\n const candidates = ALIASES[option]\n return Object.keys(config).find(key => key !== option && candidates.includes(normalized(key)))\n}\n\n/** One thing that is wrong with one option, already spelled out. */\nexport interface ConfigProblem {\n option: RequiredOption\n /** Predicate completing \"<option> …\", ex. `is missing`. */\n what: string\n /** Extra lines, printed under the option, that say how to fix this particular case. */\n hints: string[]\n}\n\nconst problem = (option: RequiredOption, what: string, ...hints: (string | undefined)[]): ConfigProblem => ({\n option,\n what,\n hints: [WHAT_IT_IS[option], ...hints].filter((hint): hint is string => Boolean(hint))\n})\n\n/**\n * A backendUrl the client can actually build a request on: an absolute http(s) URL, or a path on the\n * host's own origin, which `fetch` resolves against the page.\n */\nconst diagnoseBackendUrl = (value: string): ConfigProblem | null => {\n const trimmed = value.trim()\n if (trimmed.startsWith(\"/\")) {\n return null\n }\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, which is not a URL`,\n trimmed.includes(\".\") || trimmed.includes(\":\")\n ? `It looks like a host without a protocol: write \"https://${trimmed}\" instead, or \"/${trimmed.replace(/^\\/+/, \"\")}\" if the console API answers on the same origin as this page.`\n : undefined\n )\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return problem(\n \"backendUrl\",\n `is ${quoted(value)}, whose \"${parsed.protocol.replace(\":\", \"\")}\" scheme is neither http nor https`,\n 'A bare \"host:port\" is read as a scheme: write \"http://localhost:3000/api\", not \"localhost:3000/api\".'\n )\n }\n return null\n}\n\n/** Everything wrong with one required option, or null when it is usable. */\nconst diagnose = (option: RequiredOption, config: unknown): ConfigProblem | null => {\n const value = (config as Record<string, unknown> | null | undefined)?.[option]\n const typo = confusableKey(option, config)\n const typoHint = typo ? `The configuration carries \"${typo}\", which the client ignores. The option is spelled \"${option}\".` : undefined\n\n if (value === undefined || value === null) {\n return problem(option, value === null ? \"is null\" : \"is missing\", typoHint, typo ? undefined : missingEnvHint(option))\n }\n if (typeof value !== \"string\") {\n return problem(option, `is ${described(value)}, not a string`, typoHint)\n }\n if (value.trim() === \"\") {\n return problem(option, value === \"\" ? \"is an empty string\" : \"holds nothing but whitespace\", typoHint, missingEnvHint(option))\n }\n if (PLACEHOLDER.test(value.trim())) {\n const looksLikeAnUnsetVariable = /^(undefined|null|nan)$/i.test(value.trim())\n return problem(option, `is still the placeholder ${quoted(value)}`, typoHint, looksLikeAnUnsetVariable ? missingEnvHint(option) : undefined)\n }\n if (option === \"projectId\" && value.trim() !== value) {\n // Percent encoded into the path, so the padding would travel to the backend as %20.\n return problem(\n \"projectId\",\n `is ${quoted(value)}, padded with whitespace`,\n \"Trim the value: it is percent encoded into the manifest URL, so the spaces would reach the backend as part of the id.\"\n )\n }\n return option === \"backendUrl\" ? diagnoseBackendUrl(value) : null\n}\n\n/** Every problem of a configuration, in the order the options are declared. Empty means usable. */\nexport const diagnoseConfig = (config: unknown): ConfigProblem[] =>\n ([\"backendUrl\", \"projectId\"] as const).map(option => diagnose(option, config)).filter((found): found is ConfigProblem => found !== null)\n\nconst bulleted = (problems: ConfigProblem[]): string => problems.map(({ option, what, hints }) => [` • ${option} ${what}.`, ...hints.map(hint => ` → ${hint}`)].join(\"\\n\")).join(\"\\n\")\n\nconst indented = (block: string): string =>\n block\n .split(\"\\n\")\n .map(line => (line ? ` ${line}` : line))\n .join(\"\\n\")\n\nconst howToConfigure = (integration: Integration): string => `Configure the client like this:\\n\\n${indented(SNIPPETS[integration])}\\n\\n${WHERE[integration]}`\n\nconst listed = (options: RequiredOption[]): string => (options.length > 1 ? `${options.slice(0, -1).join(\", \")} and ${options.at(-1)}` : String(options[0]))\n\n/** The message thrown by `configure()` when what it received cannot be used. */\nexport const invalidConfigMessage = (problems: ConfigProblem[], integration: Integration): string => {\n const options = problems.map(({ option }) => option)\n const headline = `${PREFIX} configure() cannot start the client: ${listed(options)} ${options.length > 1 ? \"are\" : \"is\"} not usable.`\n return `${headline}\\n\\n${bulleted(problems)}\\n\\n${howToConfigure(integration)}`\n}\n\n/** The message thrown by `configure()` when it did not even receive an object. */\nexport const noConfigMessage = (config: unknown, integration: Integration): string =>\n `${PREFIX} configure() was called with ${config === undefined ? \"no argument\" : described(config)} instead of a configuration object. It needs at least backendUrl and projectId.\\n\\n${howToConfigure(integration)}`\n\n/** The message every read rejects with while the client has no configuration at all. */\nexport const notConfiguredMessage = (caller: string, integration: Integration): string =>\n `${PREFIX} the client is not configured: ${caller} was called before configure() ever ran, so neither backendUrl nor projectId is known and no manifest can be requested.\\n\\n${howToConfigure(integration)}`\n","import type { Integration } from \"./errors\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport interface OrchestratorState {\n config: OrchestratorConfig | null\n manifestPromise: Promise<Manifest> | null\n identities: Identities | null\n /** Set by the framework adapters as they load, so an error prints the snippet of their own API. */\n integration: Integration\n}\n\n/**\n * The state lives on `globalThis` under this key, not in a module scope variable.\n *\n * A host can end up with two copies of this package loaded at once: the app imports the ESM build\n * while something else pulls the CJS one, or the bundler config and the app resolve to different\n * chunks. Two module scopes would mean two configurations and two manifest requests, which is\n * exactly what the contract forbids. One well known global slot makes the singleton real.\n */\nexport const STATE_KEY = \"__mfe_orchestrator_client__\"\n\nconst globalSlot = globalThis as typeof globalThis & Record<typeof STATE_KEY, OrchestratorState | undefined>\n\nexport const getState = (): OrchestratorState => {\n let state = globalSlot[STATE_KEY]\n if (!state) {\n state = { config: null, manifestPromise: null, identities: null, integration: \"core\" }\n globalSlot[STATE_KEY] = state\n }\n return state\n}\n","import type { Identities } from \"./types\"\n\nexport const SESSION_ID_KEY = \"mfe-orchestrator.sessionId\"\nexport const DEVICE_ID_KEY = \"mfe-orchestrator.deviceId\"\n\nconst PROBE_KEY = \"mfe-orchestrator.probe\"\n\ntype StorageKind = \"local\" | \"session\"\n\n/**\n * Ids minted while storage was unusable. They live for the lifetime of the page so that, even\n * without storage, every request of this page load carries one stable pair of ids.\n */\nconst inMemoryIds = new Map<string, string>()\n\nconst uuidFromRandomBytes = (bytes: Uint8Array): string => {\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex: string[] = []\n for (const byte of bytes) {\n hex.push(byte.toString(16).padStart(2, \"0\"))\n }\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`\n}\n\n/**\n * A v4 UUID. `crypto.randomUUID` is the intended path; the two fallbacks only exist so that a page\n * served over plain http, or an exotic runtime, still gets an id instead of an exception.\n */\nexport const newId = (): string => {\n const cryptoApi = globalThis.crypto\n try {\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID()\n }\n if (typeof cryptoApi?.getRandomValues === \"function\") {\n return uuidFromRandomBytes(cryptoApi.getRandomValues(new Uint8Array(16)))\n }\n } catch {\n // fall through to the non cryptographic fallback\n }\n const bytes = new Uint8Array(16)\n for (let index = 0; index < bytes.length; index++) {\n bytes[index] = Math.floor(Math.random() * 256)\n }\n return uuidFromRandomBytes(bytes)\n}\n\n/**\n * The requested storage, or `null` when it is missing or unusable.\n *\n * Both the property access and the write can throw: Safari in private mode exposes the object and\n * then refuses `setItem`, some hardened browsers throw a SecurityError on the access itself. The\n * write probe is the only reliable way to tell a usable storage from a decorative one.\n */\nconst openStorage = (kind: StorageKind): Storage | null => {\n try {\n const storage = kind === \"local\" ? globalThis.localStorage : globalThis.sessionStorage\n if (!storage) {\n return null\n }\n storage.setItem(PROBE_KEY, \"1\")\n storage.removeItem(PROBE_KEY)\n return storage\n } catch {\n return null\n }\n}\n\n/**\n * The id under `key`, read from storage and created on first use. Falls back to an id kept in\n * memory when storage cannot be used, so this never throws out of the SDK.\n */\nconst persistentId = (kind: StorageKind, key: string): string => {\n const storage = openStorage(kind)\n if (storage) {\n try {\n const stored = storage.getItem(key)\n if (stored) {\n return stored\n }\n const created = newId()\n storage.setItem(key, created)\n return created\n } catch {\n // storage passed the probe and failed anyway: keep going with an in memory id\n }\n }\n const remembered = inMemoryIds.get(key)\n if (remembered) {\n return remembered\n }\n const created = newId()\n inMemoryIds.set(key, created)\n return created\n}\n\n/** Reads, and creates when needed, the session and device ids. */\nexport const readIdentities = (): Identities => ({\n sessionId: persistentId(\"session\", SESSION_ID_KEY),\n deviceId: persistentId(\"local\", DEVICE_ID_KEY)\n})\n","import { diagnoseConfig, type Integration, invalidConfigMessage, noConfigMessage, notConfiguredMessage, PREFIX } from \"./errors\"\nimport { getState } from \"./state\"\nimport { readIdentities } from \"./storage\"\nimport type { Identities, Manifest, OrchestratorConfig } from \"./types\"\n\nexport type { ConfigProblem, Integration } from \"./errors\"\nexport type { GlobalVariable, Identities, Manifest, Microfrontend, OrchestratorConfig } from \"./types\"\n\nconst withoutTrailingSlash = (value: string): string => value.replace(/\\/+$/, \"\")\n\nconst resolveUserId = async (userId: OrchestratorConfig[\"userId\"]): Promise<string | undefined> => {\n const value = typeof userId === \"function\" ? await userId() : userId\n return value === undefined || value === null || value === \"\" ? undefined : String(value)\n}\n\n/** Everything but the identity: the part of the configuration that is fixed for a page load. */\nconst sameTarget = (left: OrchestratorConfig, right: OrchestratorConfig): boolean =>\n left.backendUrl === right.backendUrl && left.projectId === right.projectId && left.environment === right.environment\n\nconst sameConfig = (left: OrchestratorConfig, right: OrchestratorConfig): boolean => sameTarget(left, right) && left.userId === right.userId\n\n/**\n * Whether replacing the identity would change nothing. Two getters are never considered equal, even the\n * same one twice: what a function returns is exactly what this side cannot know, so a host handing one\n * over is taken at its word and the manifest is re-fetched.\n */\nconst sameUserId = (left: OrchestratorConfig[\"userId\"], right: OrchestratorConfig[\"userId\"]): boolean => typeof left !== \"function\" && typeof right !== \"function\" && left === right\n\n/**\n * Rejects a configuration the client could not use, with a message that names the option, shows what\n * actually arrived and prints the call to write. environment is deliberately not required: without\n * it the backend resolves it from the domain. It is still checked for type, because a non string\n * there would silently end up percent encoded into the path.\n */\nconst requireConfig = (config: OrchestratorConfig, integration: Integration): void => {\n if (typeof config !== \"object\" || config === null) {\n throw new Error(noConfigMessage(config, integration))\n }\n const problems = diagnoseConfig(config)\n if (problems.length > 0) {\n throw new Error(invalidConfigMessage(problems, integration))\n }\n if (config.environment !== undefined && config.environment !== null && typeof config.environment !== \"string\") {\n throw new Error(\n `${PREFIX} configure() received environment as a ${typeof config.environment}, not a string. Pass the environment slug as it appears in the console, ex. \"DEV\", or leave it out to let the backend resolve it from the domain of this page.`\n )\n }\n}\n\n/** Notices about a stored configuration that works but probably does not do what the host meant. */\nconst warnAboutConfig = (config: OrchestratorConfig): void => {\n if (typeof config.environment === \"string\" && config.environment.trim() === \"\") {\n console.warn(\n `${PREFIX} configure() received an empty environment, so the client falls back to the auto routes and the backend resolves the environment from the domain of this page. Remove the option if that is what you want, or check the variable that feeds it.`\n )\n }\n}\n\n/**\n * Two shapes, one per route family. With an explicit environment the slug is the last segment; with\n * no environment the \"auto\" segment takes its place before the project id and the backend resolves\n * the environment from the domain the request comes from.\n */\nconst manifestPath = (config: OrchestratorConfig): string => {\n const projectId = encodeURIComponent(config.projectId)\n return config.environment ? `/serve/all/${projectId}/${encodeURIComponent(config.environment)}` : `/serve/all/auto/${projectId}`\n}\n\nconst manifestUrl = async (config: OrchestratorConfig): Promise<string> => {\n const { sessionId, deviceId } = identities()\n const query = new URLSearchParams({ mfeSessionId: sessionId, mfeDeviceId: deviceId })\n // Resolved as late as possible: the host may only know the user after its own auth round trip.\n const userId = await resolveUserId(config.userId)\n if (userId) {\n query.set(\"mfeUserId\", userId)\n }\n return `${withoutTrailingSlash(config.backendUrl)}${manifestPath(config)}?${query.toString()}`\n}\n\n/**\n * What a status usually means on this route. The backend answers the same 404 for an unknown project\n * and for an unknown environment, and the two are indistinguishable from here, so both are named.\n */\nconst statusHint = (status: number, config: OrchestratorConfig): string => {\n if (status === 404) {\n const environment = config.environment\n ? `the environment \"${config.environment}\" does not exist in it`\n : \"no environment of that project declares the domain this page is served on, which is what the auto route resolves on\"\n return `\\n\\nA 404 on this route means the backend did not find what the URL names: either the project id \"${config.projectId}\" is not a project of this console, or ${environment}. Check both in the console, and check that backendUrl points at the console API of the same instance.`\n }\n if (status === 401 || status === 403) {\n return `\\n\\nThe console refused the request. Check that the project id \"${config.projectId}\" belongs to the instance backendUrl points at, and that this domain is allowed to read its manifest.`\n }\n return \"\"\n}\n\nconst fetchManifest = async (config: OrchestratorConfig): Promise<Manifest> => {\n const url = await manifestUrl(config)\n // No retry in v1: whatever fetch throws travels straight to the caller.\n const response = await fetch(url, { headers: { accept: \"application/json\" } })\n if (!response.ok) {\n throw new Error(`${PREFIX} the manifest request failed with ${response.status} ${response.statusText}. GET ${url}${statusHint(response.status, config)}`)\n }\n const payload = (await response.json()) as Partial<Manifest> | null\n return {\n globalVariables: payload?.globalVariables ?? [],\n microfrontends: payload?.microfrontends ?? []\n }\n}\n\n/**\n * Hands the client its configuration. Call it once, synchronously, before any remote is imported.\n *\n * `backendUrl` and `projectId` are required. `environment` is not: omitting it makes the client use\n * the \"auto\" routes, where the backend resolves the environment from the domain of the host page.\n *\n * Idempotent: calling it again with the same options is a no op, so a framework provider may safely\n * call it on every render. A second call with different options is ignored, with a warning, because\n * the manifest of this page load may already be in flight or resolved. The user is the exception, and\n * it changes through `setUserId()`, not through a second call here.\n */\nexport const configure = (config: OrchestratorConfig): void => {\n const state = getState()\n requireConfig(config, state.integration)\n const current = state.config\n if (current) {\n if (!sameConfig(current, config)) {\n console.warn(\n sameTarget(current, config)\n ? `${PREFIX} configure() was called again with a different userId. The configuration is fixed for this page load, so this one is ignored: call setUserId() instead, which is the supported way to change the user mid session and also drops the memoized manifest, so the next read is decided on the new identity.`\n : `${PREFIX} configure() was called again with a different configuration. The first one is kept: ${JSON.stringify({ backendUrl: current.backendUrl, projectId: current.projectId, environment: current.environment })}.`\n )\n }\n return\n }\n state.config = { ...config }\n warnAboutConfig(config)\n}\n\n/**\n * Replaces the identity the backend decides a user based canary on, after the client was configured.\n *\n * `configure()` is deliberately once only, and this is the one option that legitimately changes while\n * the page is alive: a login, a logout, an account switch. So it gets its own setter, and that setter\n * does what `configure()` must not — it drops the memoized manifest, so the next `manifest()`,\n * `remoteUrl()` or `globalVariables()` asks the backend again and is answered for the new user.\n *\n * Pass `undefined` on logout: the next request then carries no `mfeUserId` at all, which is what makes\n * the backend hand out the stable version again.\n *\n * What this does NOT do is reload the remotes already imported. The federation runtime keeps the\n * container it has, so a microfrontend already on the page stays on the version drawn for the previous\n * user, and only remotes resolved after this call see the new one. When the whole page must be\n * consistent, follow the identity change with a reload; when the host mounts its remotes behind its own\n * auth guard, calling this before the guard opens is enough.\n *\n * Setting the same plain value again is a no op, so an auth store may call it on every emission without\n * costing a request. A getter is always taken as a change, since what it returns is precisely what this\n * side cannot know.\n *\n * A request already in flight is not cancelled: whoever is awaiting it still receives the manifest of\n * the previous identity. Only the memo is dropped.\n */\nexport const setUserId = (userId: OrchestratorConfig[\"userId\"]): void => {\n const state = getState()\n const current = state.config\n if (!current) {\n throw new Error(notConfiguredMessage(\"setUserId()\", state.integration))\n }\n if (sameUserId(current.userId, userId)) {\n return\n }\n state.config = { ...current, userId }\n state.manifestPromise = null\n}\n\n/**\n * @internal Lets a framework adapter say which package the host is really using, so a configuration\n * error prints the snippet of that API instead of the bare `configure()` one. Idempotent, and never\n * needed by an application: the adapters call it as they load.\n */\nexport const registerIntegration = (integration: Integration): void => {\n getState().integration = integration\n}\n\n/**\n * The whole manifest of the environment, fetched once per page load and memoized as a promise, so\n * that concurrent callers share the single request in flight.\n *\n * A successful result is memoized for good. A failed attempt is not: the memo is dropped when the\n * shared attempt settles as rejected, so the next caller starts a fresh request. That is not a retry\n * — nothing here loops or backs off — it only means one flaky lookup at boot does not condemn the\n * page to reject every `remoteUrl()` until a full reload.\n */\nconst loadManifest = (caller: string): Promise<Manifest> => {\n const state = getState()\n const config = state.config\n if (!config) {\n // Not memoized: the host may still configure the client and try again.\n return Promise.reject(new Error(notConfiguredMessage(caller, state.integration)))\n }\n if (!state.manifestPromise) {\n // Assigned before the first await inside fetchManifest, which is what makes N concurrent\n // callers collapse onto one request.\n const attempt = fetchManifest(config)\n state.manifestPromise = attempt\n // Cleared once, when the shared attempt settles, not in each caller's own catch: every\n // caller already waiting on this attempt still gets its rejection. The identity check keeps\n // a late failure from evicting a newer attempt.\n attempt.catch(() => {\n if (state.manifestPromise === attempt) {\n state.manifestPromise = null\n }\n })\n }\n return state.manifestPromise\n}\n\n/** The whole manifest of the environment. See `loadManifest` for the memoization contract. */\nexport const manifest = (): Promise<Manifest> => loadManifest(\"manifest()\")\n\n/**\n * The ready to use, version pinned URL of a remote. Awaits the manifest internally.\n *\n * The returned URL is used verbatim: the host never parses the version out of it and never strips\n * the `_v/<version>/` segment, or a classic script would load its chunks off another version.\n */\nexport const remoteUrl = async (slug: string): Promise<string> => {\n const { microfrontends } = await loadManifest(`remoteUrl(\"${slug}\")`)\n const found = microfrontends.find(microfrontend => microfrontend.slug === slug)\n if (!found) {\n const available = microfrontends.map(microfrontend => `\"${microfrontend.slug}\"`).join(\", \")\n const environment = getState().config?.environment\n // With no configured environment the host cannot name the one it was served: only the backend knows.\n const where = environment ? `environment \"${environment}\"` : \"the environment resolved from this domain\"\n throw new Error(`${PREFIX} unknown microfrontend slug \"${slug}\". Available in ${where}: ${available || \"none, this environment serves no microfrontend\"}.`)\n }\n if (!found.url) {\n throw new Error(`${PREFIX} the microfrontend \"${slug}\" is in the manifest but carries no url. Check its deployment in the console.`)\n }\n return found.url\n}\n\n/** The global variables of the environment, as a plain object. */\nexport const globalVariables = async (): Promise<Record<string, string>> => {\n const { globalVariables: variables } = await loadManifest(\"globalVariables()\")\n const result: Record<string, string> = {}\n for (const variable of variables) {\n if (variable && typeof variable.key === \"string\") {\n result[variable.key] = variable.value\n }\n }\n return result\n}\n\n/**\n * The session and device ids of this page, exposed for telemetry and debugging. Created on first\n * use and stable for the lifetime of the page, whether or not storage is available.\n */\nexport const identities = (): Identities => {\n const state = getState()\n if (!state.identities) {\n state.identities = readIdentities()\n }\n return state.identities\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mfe-orchestrator-hub/client",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Framework agnostic client for MFE Orchestrator: resolves version pinned microfrontend URLs from the console manifest",
5
5
  "license": "MIT",
6
6
  "author": "Lorenzo De Francesco",