@horizonmedia/blu-sdk 0.0.0-stage → 1.8.4

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.
@@ -0,0 +1,139 @@
1
+ import { ComponentType } from 'react';
2
+
3
+ interface BluUser {
4
+ id: string;
5
+ email: string;
6
+ displayName: string;
7
+ provider: string;
8
+ }
9
+ interface BluClient {
10
+ id: string;
11
+ name: string;
12
+ }
13
+ interface BluEnvironment {
14
+ /** The deployment stage of whatever is hosting the module (local | dev | staging | prod). */
15
+ stage: string;
16
+ /**
17
+ * This module's OWN backend for that stage — resolved by the host from the
18
+ * registry (or by the standalone harness from its deployment config). Modules
19
+ * call this; they never build URLs from `stage` themselves.
20
+ */
21
+ apiBaseUrl: string;
22
+ moduleId: string;
23
+ }
24
+ /** Who is hosting the module right now. Added in 1.1 (optional: additive, no major bump). */
25
+ interface BluShellInfo {
26
+ kind: "blu-shell" | "standalone";
27
+ /** e.g. "Blu shell (embedded in IFrame Host)" or "Team A standalone app". */
28
+ label: string;
29
+ /** Who chose the active client: the embedder (IFrame Host), the Blu shell, or the standalone app. */
30
+ clientChosenBy: "iframe-host" | "blu-shell" | "standalone";
31
+ /**
32
+ * How this module is mounted (1.2, optional): "inline" in the Blu page (Module
33
+ * Federation), "isolated" in its own sandboxed frame, or "standalone".
34
+ */
35
+ mount?: "inline" | "isolated" | "standalone";
36
+ }
37
+ /**
38
+ * Where the user is INSIDE this module (1.3, optional). Paths are
39
+ * module-relative ("/campaigns/acme-2"); the host maps them under the module's
40
+ * nav path, keeps the address bar and back button in sync, and opens them from
41
+ * links (e.g. in the Concierge's answers). Declare linkable ones in
42
+ * blu.module.json `routes`.
43
+ */
44
+ interface BluRoute {
45
+ path: string;
46
+ /** The query string, with its "?" ("" when none). Since 1.5. */
47
+ search?: string;
48
+ /**
49
+ * Go to a module-relative path, optionally with a query ("/campaigns?status=Live"),
50
+ * or change only the query ("?status=Live"). `replace` rewrites the current
51
+ * history entry instead of adding one (e.g. a filter kept in the URL). Since 1.5.
52
+ */
53
+ navigate(path: string, opts?: {
54
+ replace?: boolean;
55
+ }): void;
56
+ }
57
+ interface BluTheme {
58
+ primary: string;
59
+ surface: string;
60
+ surfaceAlt: string;
61
+ text: string;
62
+ textMuted: string;
63
+ border: string;
64
+ danger: string;
65
+ success: string;
66
+ radius: string;
67
+ font: string;
68
+ }
69
+ interface BluEvent {
70
+ type: string;
71
+ source: string;
72
+ payload: unknown;
73
+ at: string;
74
+ }
75
+ interface EventBus {
76
+ emit(type: string, payload?: unknown): void;
77
+ on(type: string | "*", handler: (event: BluEvent) => void): () => void;
78
+ }
79
+ interface HostContextValue {
80
+ contractVersion: string;
81
+ user: BluUser;
82
+ client: BluClient;
83
+ roles: string[];
84
+ environment: BluEnvironment;
85
+ theme: BluTheme;
86
+ embedded: {
87
+ inIframe: boolean;
88
+ parentOrigin: string | null;
89
+ };
90
+ shell?: BluShellInfo;
91
+ route?: BluRoute;
92
+ /**
93
+ * Always returns a non-expired Blu token for THIS module's API only (audience
94
+ * `blu-module:<moduleId>`): useless at Blu or at any other module's API.
95
+ * The host refreshes behind this.
96
+ */
97
+ getToken(): Promise<string>;
98
+ navigate(path: string): void;
99
+ events: EventBus;
100
+ }
101
+
102
+ declare function mountIsolated({ Page, rootId }: {
103
+ Page: ComponentType;
104
+ rootId?: string;
105
+ }): Promise<void>;
106
+ /**
107
+ * The bridge on its own, for apps that render their own root and router (e.g. a
108
+ * Next.js app mounted isolated with `frame.routing: "url"`): you get the same
109
+ * HostContextValue the hooks provide, and `reportRoute()` to keep Blu's
110
+ * address bar in step with your router. mountIsolated() uses it too.
111
+ */
112
+ declare function connectToBluShell(hostOrigins: Set<string> | string[]): {
113
+ /**
114
+ * The app moved (its own router): Blu updates its URL. Pass `replace: true`
115
+ * when your router already added a browser-history entry (it did, if it uses
116
+ * pushState) — then Blu replaces its URL instead of adding a second entry, and
117
+ * the back button steps once.
118
+ */
119
+ reportRoute(path: string, opts?: {
120
+ replace?: boolean;
121
+ }): void;
122
+ onContext(l: (c: HostContextValue) => void): () => any;
123
+ };
124
+ type BluShellConnection = ReturnType<typeof createBridge>;
125
+ declare function createBridge(hostOrigins: Set<string>): {
126
+ /**
127
+ * The app moved (its own router): Blu updates its URL. Pass `replace: true`
128
+ * when your router already added a browser-history entry (it did, if it uses
129
+ * pushState) — then Blu replaces its URL instead of adding a second entry, and
130
+ * the back button steps once.
131
+ */
132
+ reportRoute(path: string, opts?: {
133
+ replace?: boolean;
134
+ }): void;
135
+ onContext(l: (c: HostContextValue) => void): () => any;
136
+ };
137
+
138
+ export { connectToBluShell, mountIsolated };
139
+ export type { BluShellConnection };
@@ -0,0 +1,176 @@
1
+ /**
2
+ * "Sign in with Blu" for a browser app — OAuth 2.1 authorization code + PKCE.
3
+ *
4
+ * Used by the Blu shell (client "blu-host") and by every module's standalone
5
+ * app (client = the module id). The person signs in on Blu's own page, never
6
+ * inside the calling app, and Blu only sends them back to a redirect address
7
+ * that client registered. What comes back is a token for THAT client only.
8
+ *
9
+ * The one-time PKCE verifier and state live in sessionStorage between the
10
+ * redirect out and the redirect back (same tab, same origin); tokens never do.
11
+ */
12
+ interface BluTokenResponse {
13
+ access_token: string;
14
+ token_type: "Bearer";
15
+ expires_in: number;
16
+ refresh_token?: string;
17
+ /** Clients this token may switch between, with display names (module tokens only). */
18
+ blu_clients?: {
19
+ id: string;
20
+ name: string;
21
+ }[];
22
+ authz_version?: number;
23
+ }
24
+ type BluSignInResult = {
25
+ kind: "none";
26
+ } | {
27
+ kind: "error";
28
+ error: string;
29
+ description: string;
30
+ } | {
31
+ kind: "signed-in";
32
+ tokens: BluTokenResponse;
33
+ hostApi: string;
34
+ };
35
+ /** Leave for Blu's sign-in page. `redirectUri` must exactly match one the client registered. */
36
+ declare function beginBluSignIn({ hostApi, clientId, redirectUri }: {
37
+ hostApi: string;
38
+ clientId: string;
39
+ redirectUri: string;
40
+ }): Promise<void>;
41
+ /**
42
+ * Finish a sign-in if this page load is Blu's redirect back. Safe to call more
43
+ * than once per page load (React StrictMode): the work happens once.
44
+ */
45
+ declare function completeBluSignIn(): Promise<BluSignInResult>;
46
+
47
+ interface BluUser {
48
+ id: string;
49
+ email: string;
50
+ displayName: string;
51
+ provider: string;
52
+ }
53
+ interface BluClient {
54
+ id: string;
55
+ name: string;
56
+ }
57
+ interface BluEnvironment {
58
+ /** The deployment stage of whatever is hosting the module (local | dev | staging | prod). */
59
+ stage: string;
60
+ /**
61
+ * This module's OWN backend for that stage — resolved by the host from the
62
+ * registry (or by the standalone harness from its deployment config). Modules
63
+ * call this; they never build URLs from `stage` themselves.
64
+ */
65
+ apiBaseUrl: string;
66
+ moduleId: string;
67
+ }
68
+ /** Who is hosting the module right now. Added in 1.1 (optional: additive, no major bump). */
69
+ interface BluShellInfo {
70
+ kind: "blu-shell" | "standalone";
71
+ /** e.g. "Blu shell (embedded in IFrame Host)" or "Team A standalone app". */
72
+ label: string;
73
+ /** Who chose the active client: the embedder (IFrame Host), the Blu shell, or the standalone app. */
74
+ clientChosenBy: "iframe-host" | "blu-shell" | "standalone";
75
+ /**
76
+ * How this module is mounted (1.2, optional): "inline" in the Blu page (Module
77
+ * Federation), "isolated" in its own sandboxed frame, or "standalone".
78
+ */
79
+ mount?: "inline" | "isolated" | "standalone";
80
+ }
81
+ /**
82
+ * Where the user is INSIDE this module (1.3, optional). Paths are
83
+ * module-relative ("/campaigns/acme-2"); the host maps them under the module's
84
+ * nav path, keeps the address bar and back button in sync, and opens them from
85
+ * links (e.g. in the Concierge's answers). Declare linkable ones in
86
+ * blu.module.json `routes`.
87
+ */
88
+ interface BluRoute {
89
+ path: string;
90
+ /** The query string, with its "?" ("" when none). Since 1.5. */
91
+ search?: string;
92
+ /**
93
+ * Go to a module-relative path, optionally with a query ("/campaigns?status=Live"),
94
+ * or change only the query ("?status=Live"). `replace` rewrites the current
95
+ * history entry instead of adding one (e.g. a filter kept in the URL). Since 1.5.
96
+ */
97
+ navigate(path: string, opts?: {
98
+ replace?: boolean;
99
+ }): void;
100
+ }
101
+ interface BluTheme {
102
+ primary: string;
103
+ surface: string;
104
+ surfaceAlt: string;
105
+ text: string;
106
+ textMuted: string;
107
+ border: string;
108
+ danger: string;
109
+ success: string;
110
+ radius: string;
111
+ font: string;
112
+ }
113
+ interface BluEvent {
114
+ type: string;
115
+ source: string;
116
+ payload: unknown;
117
+ at: string;
118
+ }
119
+ interface EventBus {
120
+ emit(type: string, payload?: unknown): void;
121
+ on(type: string | "*", handler: (event: BluEvent) => void): () => void;
122
+ }
123
+ interface HostContextValue {
124
+ contractVersion: string;
125
+ user: BluUser;
126
+ client: BluClient;
127
+ roles: string[];
128
+ environment: BluEnvironment;
129
+ theme: BluTheme;
130
+ embedded: {
131
+ inIframe: boolean;
132
+ parentOrigin: string | null;
133
+ };
134
+ shell?: BluShellInfo;
135
+ route?: BluRoute;
136
+ /**
137
+ * Always returns a non-expired Blu token for THIS module's API only (audience
138
+ * `blu-module:<moduleId>`): useless at Blu or at any other module's API.
139
+ * The host refreshes behind this.
140
+ */
141
+ getToken(): Promise<string>;
142
+ navigate(path: string): void;
143
+ events: EventBus;
144
+ }
145
+ declare function useHost(): HostContextValue;
146
+ /**
147
+ * The host context if this code is running inside a Blu host, otherwise null —
148
+ * for components shared with an app that also runs on its own (e.g. a team's
149
+ * client switcher: render nothing inside Blu, because Blu chose the client).
150
+ */
151
+ declare function useOptionalHost(): HostContextValue | null;
152
+ declare const useUser: () => BluUser;
153
+ declare const useClient: () => BluClient;
154
+ declare const useRoles: () => string[];
155
+ declare const useEnvironment: () => BluEnvironment;
156
+ declare const useTheme: () => BluTheme;
157
+ declare const useEventBus: () => EventBus;
158
+ declare const useShell: () => BluShellInfo;
159
+ declare const useAuthToken: () => () => Promise<string>;
160
+ /** The module-relative route; a host older than 1.3 gives "/" and ignores navigation. */
161
+ declare const useRoute: () => BluRoute;
162
+ declare class ApiError extends Error {
163
+ status: number;
164
+ body: unknown;
165
+ url: string;
166
+ constructor(status: number, body: unknown, url: string);
167
+ }
168
+ interface ApiClient {
169
+ baseUrl: string;
170
+ get<T = unknown>(path: string, init?: RequestInit): Promise<T>;
171
+ post<T = unknown>(path: string, body?: unknown, init?: RequestInit): Promise<T>;
172
+ }
173
+ declare function useApiClient(): ApiClient;
174
+
175
+ export { ApiError, beginBluSignIn, completeBluSignIn, useApiClient, useAuthToken, useClient, useEnvironment, useEventBus, useHost, useOptionalHost, useRoles, useRoute, useShell, useTheme, useUser };
176
+ export type { ApiClient, BluClient, BluEnvironment, BluEvent, BluRoute, BluShellInfo, BluSignInResult, BluTheme, BluTokenResponse, BluUser, EventBus };