@iloveagents/foundry-web-shell 0.2.2 → 0.3.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/AGENTS.md CHANGED
@@ -2,7 +2,7 @@ Browser bootstrap for the LastSpace agent UI starter. Published as `@iloveagents
2
2
 
3
3
  # Architecture
4
4
 
5
- Source-shipping (no build step) — same convention as the other `@lastspace/*` packages.
5
+ Source-shipping (no build step) — same convention as the other `@iloveagents/foundry-*` packages.
6
6
 
7
7
  ```
8
8
  src/
@@ -79,4 +79,4 @@ pnpm --filter @iloveagents/foundry-web-shell typecheck # tsc --noEmit
79
79
 
80
80
  # Authoring a module
81
81
 
82
- See [`docs/AUTHORING_A_MODULE.md`](../../docs/AUTHORING_A_MODULE.md).
82
+ The `ChatModule` protocol is documented in **Public API** above; the canonical type definitions live in [`src/types.ts`](src/types.ts) (`ChatModule`, `defineChatModule`). For the nav-mutation-from-`useInit` pattern, have your module's `useInit` write the sidebar nav `config` into `useNavStore` (the same store [`src/shell-layout.tsx`](src/shell-layout.tsx) reads via `useNavStore((s) => s.config)`).
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @iloveagents/foundry-web-shell
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [9ec870e]
8
+ - @iloveagents/foundry-web-ui@0.3.1
9
+ - @iloveagents/foundry-agent@0.3.1
10
+ - @iloveagents/foundry-web-primitives@0.3.1
11
+
12
+ ## 0.3.0
13
+
14
+ ### Minor Changes
15
+
16
+ - df383c9: Add runtime configuration support so the web app can ship as a single prebuilt
17
+ container image that boots for any environment without a rebuild. New
18
+ `runtimeConfig(key)` helper resolves `window.__APP_CONFIG__[key]` (injected by
19
+ the container at startup) before `import.meta.env[key]` (build-time Vite env,
20
+ the local-dev fallback). The default MSAL auth adapter and agent fetch client
21
+ now read `VITE_MSAL_*` / `VITE_API_BASE_URL` through it. Local `pnpm dev` is
22
+ unchanged (no `/config.js` → falls back to `import.meta.env`).
23
+
24
+ ### Patch Changes
25
+
26
+ - @iloveagents/foundry-agent@0.3.0
27
+ - @iloveagents/foundry-web-primitives@0.3.0
28
+ - @iloveagents/foundry-web-ui@0.3.0
29
+
3
30
  ## 0.2.2
4
31
 
5
32
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-web-shell",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "type": "module",
6
6
  "types": "./src/index.ts",
@@ -19,9 +19,9 @@
19
19
  "zustand": "^5.0.0"
20
20
  },
21
21
  "dependencies": {
22
- "@iloveagents/foundry-agent": "0.2.2",
23
- "@iloveagents/foundry-web-primitives": "0.2.2",
24
- "@iloveagents/foundry-web-ui": "0.2.2"
22
+ "@iloveagents/foundry-agent": "0.3.1",
23
+ "@iloveagents/foundry-web-primitives": "0.3.1",
24
+ "@iloveagents/foundry-web-ui": "0.3.1"
25
25
  },
26
26
  "devDependencies": {
27
27
  "typescript": "~5.9.3",
@@ -2,6 +2,7 @@ import type { FC, ReactNode } from "react";
2
2
  import { AuthProvider } from "@iloveagents/foundry-web-ui";
3
3
  import type { MsalAuthConfig } from "@iloveagents/foundry-agent/msal";
4
4
  import type { AuthAdapter } from "./types.ts";
5
+ import { runtimeConfig } from "./runtime-config.ts";
5
6
 
6
7
 
7
8
 
@@ -23,15 +24,16 @@ function AuthConfigError({ missingKeys }: AuthConfigErrorProps) {
23
24
  }
24
25
 
25
26
  /**
26
- * Read MSAL configuration from Vite env. Returns the resolved config or the
27
- * list of missing keys. The shell renders <AuthConfigError /> when any key
28
- * is missing.
27
+ * Read MSAL configuration. Prefers runtime config (`window.__APP_CONFIG__`,
28
+ * injected by the container at startup) and falls back to build-time Vite env
29
+ * (`import.meta.env`) for local dev — see {@link runtimeConfig}. Returns the
30
+ * resolved config or the list of missing keys; the shell renders
31
+ * <AuthConfigError /> when any key is missing.
29
32
  */
30
- function readMsalConfigFromEnv(): MsalAuthConfig | { missing: string[] } {
31
- const env = import.meta.env;
32
- const clientId = env.VITE_MSAL_CLIENT_ID;
33
- const authority = env.VITE_MSAL_AUTHORITY;
34
- const apiScope = env.VITE_MSAL_API_SCOPE;
33
+ function readMsalConfig(): MsalAuthConfig | { missing: string[] } {
34
+ const clientId = runtimeConfig("VITE_MSAL_CLIENT_ID");
35
+ const authority = runtimeConfig("VITE_MSAL_AUTHORITY");
36
+ const apiScope = runtimeConfig("VITE_MSAL_API_SCOPE");
35
37
  const missing = [
36
38
  !clientId ? "VITE_MSAL_CLIENT_ID" : null,
37
39
  !authority ? "VITE_MSAL_AUTHORITY" : null,
@@ -39,21 +41,22 @@ function readMsalConfigFromEnv(): MsalAuthConfig | { missing: string[] } {
39
41
  ].filter((v): v is string => v !== null);
40
42
  if (missing.length > 0) return { missing };
41
43
  return {
42
- clientId: clientId!,
43
- authority: authority!,
44
- apiScope: apiScope!,
44
+ clientId,
45
+ authority,
46
+ apiScope,
45
47
  redirectUri: window.location.origin,
46
48
  };
47
49
  }
48
50
 
49
51
  /**
50
- * Default MSAL-backed auth adapter. Reads VITE_MSAL_* from import.meta.env.
52
+ * Default MSAL-backed auth adapter. Reads VITE_MSAL_* from runtime config
53
+ * (`window.__APP_CONFIG__`) with `import.meta.env` fallback for local dev.
51
54
  * Customers override via `bootstrapShell({ authProvider: { Provider: ... } })`
52
55
  * for tests or non-MSAL deployments.
53
56
  */
54
57
  export const defaultAuthAdapter: AuthAdapter = {
55
58
  Provider: ({ children }: { children: ReactNode }) => {
56
- const result = readMsalConfigFromEnv();
59
+ const result = readMsalConfig();
57
60
  if ("missing" in result) {
58
61
  return <AuthConfigError missingKeys={result.missing} />;
59
62
  }
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export { ShellApp } from "./shell-app.tsx";
3
3
  export { ShellLayout } from "./shell-layout.tsx";
4
4
  export { defaultAuthAdapter, ShellAuth } from "./auth-default.tsx";
5
5
  export { defaultAgentFetch } from "./service-fetch-default.ts";
6
+ export { runtimeConfig } from "./runtime-config.ts";
6
7
  export { defineChatModule } from "./types.ts";
7
8
  export type {
8
9
  ChatModule,
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Runtime configuration reader.
3
+ *
4
+ * The web app ships as a SINGLE prebuilt container image that must boot
5
+ * correctly for any customer / environment without a rebuild. Per-env values
6
+ * (API base URL, MSAL client/authority/scopes) therefore arrive at RUNTIME —
7
+ * the container entrypoint writes a small `/config.js` from env vars that sets
8
+ * `window.__APP_CONFIG__`, loaded before the app bundle.
9
+ *
10
+ * `runtimeConfig(key)` resolves, in order:
11
+ * 1. `window.__APP_CONFIG__[key]` — runtime config injected by the container
12
+ * 2. `import.meta.env[key]` — build-time Vite env (local `pnpm dev`)
13
+ * 3. `""` — absent
14
+ *
15
+ * Keeping `import.meta.env` as the fallback means local dev is unchanged: there
16
+ * is no `/config.js` in dev, so `window.__APP_CONFIG__` is undefined and the
17
+ * existing `VITE_*` values from `.env` are used exactly as before.
18
+ *
19
+ * The window cast is inline (no `declare global`) so this can be duplicated in
20
+ * sibling packages without conflicting global augmentations.
21
+ */
22
+ export function runtimeConfig(key: string): string {
23
+ const fromWindow =
24
+ typeof window !== "undefined"
25
+ ? (window as { __APP_CONFIG__?: Record<string, string | undefined> })
26
+ .__APP_CONFIG__?.[key]
27
+ : undefined;
28
+ const fromEnv = (import.meta.env as Record<string, string | undefined>)[key];
29
+ return fromWindow ?? fromEnv ?? "";
30
+ }
@@ -1,5 +1,6 @@
1
1
  import { createServiceFetch } from "@iloveagents/foundry-agent";
2
2
  import { authStore } from "@iloveagents/foundry-agent/msal";
3
+ import { runtimeConfig } from "./runtime-config.ts";
3
4
 
4
5
  /**
5
6
  * Default agent fetch client wired to the MSAL token store and the host's
@@ -21,5 +22,5 @@ export const defaultAgentFetch: typeof fetch = createServiceFetch({
21
22
  acquireToken: (options) => authStore.getState().getAccessToken("api", options),
22
23
  recoverFromHardAuthFailure: (reason) =>
23
24
  authStore.getState().recoverFromHardAuthFailure(reason),
24
- baseUrl: import.meta.env.VITE_API_BASE_URL,
25
+ baseUrl: runtimeConfig("VITE_API_BASE_URL"),
25
26
  });