@capitalos/angular 0.1.0-rc.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.
@@ -0,0 +1,360 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, EventEmitter, Component, Input, Output, ViewChild, NgModule } from '@angular/core';
3
+ import { exchangeOneTimeToken, TokenType, TokenParamKey, TokenParamLocation, createLogger, IframeManager, CapitalOSError } from '@capitalos/core';
4
+ export { CapitalOSError, ErrorCode } from '@capitalos/core';
5
+ import { BehaviorSubject, combineLatest, map } from 'rxjs';
6
+
7
+ /**
8
+ * Injection token for CapitalOS configuration
9
+ */
10
+ const CAPITALOS_CONFIG = new InjectionToken('CAPITALOS_CONFIG');
11
+ /**
12
+ * Provides the CapitalOS SDK with the specified configuration.
13
+ *
14
+ * Usage in app.config.ts (standalone):
15
+ * ```typescript
16
+ * bootstrapApplication(AppComponent, {
17
+ * providers: [
18
+ * provideCapitalOs({
19
+ * getToken: async () => {
20
+ * const response = await fetch('/api/capitalos/token');
21
+ * const data = await response.json();
22
+ * return data.token;
23
+ * },
24
+ * enableLogging: true,
25
+ * }),
26
+ * ],
27
+ * });
28
+ * ```
29
+ *
30
+ * For NgModule-based apps, use CapitalOsModule.forRoot() instead.
31
+ */
32
+ function provideCapitalOs(config) {
33
+ return [
34
+ {
35
+ provide: CAPITALOS_CONFIG,
36
+ useValue: config,
37
+ },
38
+ TokenExchangeService,
39
+ CapitalOsAuthService,
40
+ ];
41
+ }
42
+
43
+ const TOKEN_EXCHANGE_TIMEOUT_MS = 10000;
44
+ /**
45
+ * Service responsible for exchanging one-time tokens for long-lived JWTs.
46
+ * Creates a hidden iframe to perform the token exchange securely.
47
+ */
48
+ class TokenExchangeService {
49
+ constructor() {
50
+ this.config = inject(CAPITALOS_CONFIG);
51
+ this.isDestroyed = false;
52
+ this.activeAbortController = null;
53
+ }
54
+ ngOnDestroy() {
55
+ this.isDestroyed = true;
56
+ this.activeAbortController?.abort();
57
+ this.activeAbortController = null;
58
+ }
59
+ /**
60
+ * Exchanges a one-time token for a long-lived JWT.
61
+ * Delegates to @capitalos/core (browser-only) which handles iframe + Penpal lifecycle.
62
+ */
63
+ async exchange(oneTimeToken, options = {}) {
64
+ if (this.isDestroyed) {
65
+ throw new Error('TokenExchangeService was destroyed');
66
+ }
67
+ // Abort any in-flight exchange when a new one begins.
68
+ this.activeAbortController?.abort();
69
+ const abortController = new AbortController();
70
+ this.activeAbortController = abortController;
71
+ try {
72
+ return await exchangeOneTimeToken({
73
+ oneTimeToken,
74
+ enableLogging: options.enableLogging,
75
+ logger: this.config.logger,
76
+ timeoutMs: TOKEN_EXCHANGE_TIMEOUT_MS,
77
+ signal: abortController.signal,
78
+ });
79
+ }
80
+ finally {
81
+ if (this.activeAbortController === abortController) {
82
+ this.activeAbortController = null;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ TokenExchangeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TokenExchangeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
88
+ TokenExchangeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TokenExchangeService });
89
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TokenExchangeService, decorators: [{
90
+ type: Injectable
91
+ }] });
92
+
93
+ /**
94
+ * Converts an unknown error to an Error object
95
+ */
96
+ function toError(error) {
97
+ if (error instanceof Error) {
98
+ return error;
99
+ }
100
+ return new Error(String(error));
101
+ }
102
+ /**
103
+ * Service that manages CapitalOS authentication state.
104
+ * This is the Angular equivalent of React's CapitalOsAuthenticationProvider.
105
+ *
106
+ * It handles:
107
+ * - Fetching one-time tokens via the provided getToken callback
108
+ * - Exchanging one-time tokens for long-lived JWTs
109
+ * - Managing token state via observables
110
+ * - Auto-refreshing tokens when they expire
111
+ */
112
+ class CapitalOsAuthService {
113
+ constructor() {
114
+ this.config = inject(CAPITALOS_CONFIG);
115
+ this.tokenExchangeService = inject(TokenExchangeService);
116
+ // Private BehaviorSubjects for internal state
117
+ this._longLivedToken$ = new BehaviorSubject(undefined);
118
+ this._baseUrl$ = new BehaviorSubject(undefined);
119
+ this._isLoading$ = new BehaviorSubject(false);
120
+ this._error$ = new BehaviorSubject(undefined);
121
+ // Public observable for token data
122
+ this.tokenData$ = combineLatest([this._longLivedToken$, this._baseUrl$]).pipe(map(([token, baseUrl]) => {
123
+ if (!token || !baseUrl) {
124
+ return undefined;
125
+ }
126
+ return {
127
+ token,
128
+ tokenType: TokenType.longLived,
129
+ baseUrl,
130
+ paramKey: TokenParamKey.accessToken,
131
+ paramLocation: TokenParamLocation.hash,
132
+ };
133
+ }));
134
+ // Public observables for UI state
135
+ this.isLoading$ = this._isLoading$.asObservable();
136
+ this.error$ = this._error$.asObservable();
137
+ this.authState$ = combineLatest([this._isLoading$, this._error$, this.tokenData$]).pipe(map(([isLoading, error, tokenData]) => {
138
+ if (isLoading)
139
+ return 'loading';
140
+ if (error)
141
+ return 'error';
142
+ if (tokenData)
143
+ return 'authenticated';
144
+ return 'idle';
145
+ }));
146
+ this.isDestroyed = false;
147
+ this.logger = createLogger(this.config.enableLogging, this.config.logger);
148
+ // Start authentication flow eagerly on construction.
149
+ // This is intentional: auth begins as soon as the app boots so the token
150
+ // is ready when CardsAppComponent renders, reducing perceived load time.
151
+ this.refreshToken();
152
+ }
153
+ ngOnDestroy() {
154
+ this.isDestroyed = true;
155
+ }
156
+ /**
157
+ * Invalidates the current token, triggering a refresh.
158
+ * Called when the iframe signals that the token has expired.
159
+ */
160
+ invalidateToken() {
161
+ this.logger.log('CapitalOsAuthService: Invalidating token');
162
+ this._longLivedToken$.next(undefined);
163
+ this._baseUrl$.next(undefined);
164
+ this._error$.next(undefined);
165
+ this.refreshToken();
166
+ }
167
+ /**
168
+ * Refreshes the token by fetching a new one-time token and exchanging it.
169
+ */
170
+ async refreshToken() {
171
+ if (this.isDestroyed) {
172
+ return;
173
+ }
174
+ // Prevent concurrent refresh calls - if already loading, skip
175
+ if (this._isLoading$.value) {
176
+ this.logger.log('CapitalOsAuthService: Token refresh already in progress, skipping');
177
+ return;
178
+ }
179
+ this.logger.log('CapitalOsAuthService: Starting token refresh');
180
+ this._isLoading$.next(true);
181
+ this._error$.next(undefined);
182
+ try {
183
+ // Get one-time token from platform
184
+ const oneTimeToken = await this.config.getToken();
185
+ this.logger.log('CapitalOsAuthService: Received one-time token');
186
+ if (this.isDestroyed) {
187
+ return;
188
+ }
189
+ // Exchange for long-lived token
190
+ const result = await this.tokenExchangeService.exchange(oneTimeToken, {
191
+ enableLogging: this.config.enableLogging,
192
+ });
193
+ if (this.isDestroyed) {
194
+ return;
195
+ }
196
+ this._longLivedToken$.next(result.longLivedToken);
197
+ this._baseUrl$.next(result.baseUrl);
198
+ this._error$.next(undefined);
199
+ this.logger.log('CapitalOsAuthService: Token exchange complete');
200
+ }
201
+ catch (rawError) {
202
+ if (!this.isDestroyed) {
203
+ const error = toError(rawError);
204
+ this.logger.error(`CapitalOsAuthService: Token refresh failed: ${error.message}`);
205
+ this._error$.next(error);
206
+ }
207
+ }
208
+ finally {
209
+ if (!this.isDestroyed) {
210
+ this._isLoading$.next(false);
211
+ }
212
+ }
213
+ }
214
+ }
215
+ CapitalOsAuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsAuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
216
+ CapitalOsAuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsAuthService });
217
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsAuthService, decorators: [{
218
+ type: Injectable
219
+ }], ctorParameters: function () { return []; } });
220
+
221
+ // TODO: Automate version injection at build time
222
+ const SDK_VERSION = '0.1.0-rc.1';
223
+ /**
224
+ * CardsApp component that renders the CapitalOS cards interface in an iframe.
225
+ *
226
+ * The component emits events for loading state - consumers should handle their own loading UI:
227
+ *
228
+ * ```html
229
+ * <div *ngIf="!cardsLoaded">
230
+ * <my-loading-spinner></my-loading-spinner>
231
+ * </div>
232
+ * <capitalos-cards-app
233
+ * (loaded)="cardsLoaded = true"
234
+ * (error)="onCardsError($event)"
235
+ * ></capitalos-cards-app>
236
+ * ```
237
+ */
238
+ class CardsAppComponent {
239
+ constructor() {
240
+ // Injected services
241
+ this.authService = inject(CapitalOsAuthService);
242
+ this.config = inject(CAPITALOS_CONFIG);
243
+ this.heightOffsetPx = 12;
244
+ // Outputs
245
+ this.loaded = new EventEmitter();
246
+ this.error = new EventEmitter();
247
+ }
248
+ ngAfterViewInit() {
249
+ // Subscribe to tokenData$ and initialize iframe when ready
250
+ this.tokenDataSubscription = this.authService.tokenData$.subscribe((tokenData) => {
251
+ if (tokenData && this.iframeContainer) {
252
+ this.initializeIframe(tokenData, this.iframeContainer.nativeElement);
253
+ }
254
+ });
255
+ }
256
+ ngOnDestroy() {
257
+ this.tokenDataSubscription?.unsubscribe();
258
+ this.iframeManager?.destroy();
259
+ }
260
+ initializeIframe(tokenData, container) {
261
+ // Destroy previous iframe if exists
262
+ this.iframeManager?.destroy();
263
+ const resolvedEnableLogging = this.enableLogging ?? this.config.enableLogging ?? false;
264
+ const resolvedTheme = this.theme ?? this.config.theme;
265
+ this.iframeManager = new IframeManager({
266
+ container,
267
+ tokenData,
268
+ renderingContext: { entryPoint: 'cardsApp' },
269
+ theme: resolvedTheme,
270
+ enableLogging: resolvedEnableLogging,
271
+ logger: this.config.logger,
272
+ sdkVersion: SDK_VERSION,
273
+ heightOffsetPx: this.heightOffsetPx,
274
+ callbacks: {
275
+ onLoad: () => {
276
+ this.loaded.emit();
277
+ },
278
+ onError: (rawError) => {
279
+ const capitalOsError = new CapitalOSError(rawError);
280
+ this.error.emit(capitalOsError);
281
+ },
282
+ onTokenExpired: () => {
283
+ this.authService.invalidateToken();
284
+ },
285
+ },
286
+ });
287
+ }
288
+ }
289
+ CardsAppComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CardsAppComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
290
+ CardsAppComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CardsAppComponent, isStandalone: true, selector: "capitalos-cards-app", inputs: { theme: "theme", heightOffsetPx: "heightOffsetPx", enableLogging: "enableLogging" }, outputs: { loaded: "loaded", error: "error" }, viewQueries: [{ propertyName: "iframeContainer", first: true, predicate: ["iframeContainer"], descendants: true }], ngImport: i0, template: `<div #iframeContainer class="capitalos-iframe-container"></div>`, isInline: true, styles: [":host{display:block;width:100%}.capitalos-iframe-container{width:100%}\n"] });
291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CardsAppComponent, decorators: [{
292
+ type: Component,
293
+ args: [{ selector: 'capitalos-cards-app', standalone: true, template: `<div #iframeContainer class="capitalos-iframe-container"></div>`, styles: [":host{display:block;width:100%}.capitalos-iframe-container{width:100%}\n"] }]
294
+ }], propDecorators: { theme: [{
295
+ type: Input
296
+ }], heightOffsetPx: [{
297
+ type: Input
298
+ }], enableLogging: [{
299
+ type: Input
300
+ }], loaded: [{
301
+ type: Output
302
+ }], error: [{
303
+ type: Output
304
+ }], iframeContainer: [{
305
+ type: ViewChild,
306
+ args: ['iframeContainer']
307
+ }] } });
308
+
309
+ /**
310
+ * NgModule for CapitalOS SDK.
311
+ *
312
+ * Use this module for NgModule-based Angular applications.
313
+ * For standalone applications, use provideCapitalOs() instead.
314
+ *
315
+ * Usage:
316
+ * ```typescript
317
+ * @NgModule({
318
+ * imports: [
319
+ * CapitalOsModule.forRoot({
320
+ * getToken: async () => {
321
+ * const response = await fetch('/api/capitalos/token');
322
+ * const data = await response.json();
323
+ * return data.token;
324
+ * },
325
+ * enableLogging: true,
326
+ * }),
327
+ * ],
328
+ * })
329
+ * export class AppModule {}
330
+ * ```
331
+ */
332
+ class CapitalOsModule {
333
+ static forRoot(config) {
334
+ return {
335
+ ngModule: CapitalOsModule,
336
+ providers: [{ provide: CAPITALOS_CONFIG, useValue: config }, TokenExchangeService, CapitalOsAuthService],
337
+ };
338
+ }
339
+ }
340
+ CapitalOsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
341
+ CapitalOsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsModule, imports: [CardsAppComponent], exports: [CardsAppComponent] });
342
+ CapitalOsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsModule, imports: [CardsAppComponent] });
343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CapitalOsModule, decorators: [{
344
+ type: NgModule,
345
+ args: [{
346
+ imports: [CardsAppComponent],
347
+ exports: [CardsAppComponent],
348
+ }]
349
+ }] });
350
+
351
+ /*
352
+ * Public API Surface of @capitalos/angular
353
+ */
354
+
355
+ /**
356
+ * Generated bundle index. Do not edit.
357
+ */
358
+
359
+ export { CAPITALOS_CONFIG, CapitalOsAuthService, CapitalOsModule, CardsAppComponent, provideCapitalOs };
360
+ //# sourceMappingURL=capitalos-angular.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capitalos-angular.mjs","sources":["../../../projects/capitalos-angular/src/lib/provide-capitalos.ts","../../../projects/capitalos-angular/src/lib/token-exchange.service.ts","../../../projects/capitalos-angular/src/lib/capitalos-auth.service.ts","../../../projects/capitalos-angular/src/lib/cards-app.component.ts","../../../projects/capitalos-angular/src/lib/capitalos.module.ts","../../../projects/capitalos-angular/src/public-api.ts","../../../projects/capitalos-angular/src/capitalos-angular.ts"],"sourcesContent":["import { InjectionToken, Provider } from '@angular/core'\nimport { Logger, ThemeColorScheme } from '@capitalos/core'\nimport { CapitalOsAuthService } from './capitalos-auth.service'\nimport { TokenExchangeService } from './token-exchange.service'\n\n/**\n * Configuration for CapitalOS SDK\n */\nexport interface CapitalOsConfig {\n /**\n * Function that returns a promise resolving to a one-time token.\n * This is typically a call to your backend that initiates a CapitalOS login.\n */\n getToken: () => Promise<string>\n\n /**\n * Whether to enable logging for debugging purposes.\n */\n enableLogging?: boolean\n\n /**\n * Optional custom logger for capturing SDK logs.\n */\n logger?: Logger\n\n /**\n * Theme color scheme for the SDK components.\n */\n theme?: ThemeColorScheme\n}\n\n/**\n * Injection token for CapitalOS configuration\n */\nexport const CAPITALOS_CONFIG = new InjectionToken<CapitalOsConfig>('CAPITALOS_CONFIG')\n\n/**\n * Provides the CapitalOS SDK with the specified configuration.\n *\n * Usage in app.config.ts (standalone):\n * ```typescript\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideCapitalOs({\n * getToken: async () => {\n * const response = await fetch('/api/capitalos/token');\n * const data = await response.json();\n * return data.token;\n * },\n * enableLogging: true,\n * }),\n * ],\n * });\n * ```\n *\n * For NgModule-based apps, use CapitalOsModule.forRoot() instead.\n */\nexport function provideCapitalOs(config: CapitalOsConfig): Provider[] {\n return [\n {\n provide: CAPITALOS_CONFIG,\n useValue: config,\n },\n TokenExchangeService,\n CapitalOsAuthService,\n ]\n}\n","import { Injectable, inject, OnDestroy } from '@angular/core'\nimport { exchangeOneTimeToken } from '@capitalos/core'\nimport { CAPITALOS_CONFIG } from './provide-capitalos'\n\nconst TOKEN_EXCHANGE_TIMEOUT_MS = 10_000\n\nexport interface TokenExchangeResult {\n longLivedToken: string\n baseUrl: string\n}\n\n/**\n * Service responsible for exchanging one-time tokens for long-lived JWTs.\n * Creates a hidden iframe to perform the token exchange securely.\n */\n@Injectable()\nexport class TokenExchangeService implements OnDestroy {\n private readonly config = inject(CAPITALOS_CONFIG)\n private isDestroyed = false\n private activeAbortController: AbortController | null = null\n\n ngOnDestroy(): void {\n this.isDestroyed = true\n this.activeAbortController?.abort()\n this.activeAbortController = null\n }\n\n /**\n * Exchanges a one-time token for a long-lived JWT.\n * Delegates to @capitalos/core (browser-only) which handles iframe + Penpal lifecycle.\n */\n async exchange(oneTimeToken: string, options: { enableLogging?: boolean } = {}): Promise<TokenExchangeResult> {\n if (this.isDestroyed) {\n throw new Error('TokenExchangeService was destroyed')\n }\n\n // Abort any in-flight exchange when a new one begins.\n this.activeAbortController?.abort()\n\n const abortController = new AbortController()\n this.activeAbortController = abortController\n\n try {\n return await exchangeOneTimeToken({\n oneTimeToken,\n enableLogging: options.enableLogging,\n logger: this.config.logger,\n timeoutMs: TOKEN_EXCHANGE_TIMEOUT_MS,\n signal: abortController.signal,\n })\n } finally {\n if (this.activeAbortController === abortController) {\n this.activeAbortController = null\n }\n }\n }\n}\n","import { Injectable, inject, OnDestroy } from '@angular/core'\nimport { BehaviorSubject, Observable, combineLatest, map } from 'rxjs'\nimport { TokenData, TokenType, TokenParamKey, TokenParamLocation, createLogger } from '@capitalos/core'\nimport { TokenExchangeService } from './token-exchange.service'\nimport { CAPITALOS_CONFIG } from './provide-capitalos'\n\n/**\n * Converts an unknown error to an Error object\n */\nfunction toError(error: unknown): Error {\n if (error instanceof Error) {\n return error\n }\n return new Error(String(error))\n}\n\n/**\n * Authentication state enum\n */\nexport type AuthState = 'idle' | 'loading' | 'authenticated' | 'error'\n\n/**\n * Service that manages CapitalOS authentication state.\n * This is the Angular equivalent of React's CapitalOsAuthenticationProvider.\n *\n * It handles:\n * - Fetching one-time tokens via the provided getToken callback\n * - Exchanging one-time tokens for long-lived JWTs\n * - Managing token state via observables\n * - Auto-refreshing tokens when they expire\n */\n@Injectable()\nexport class CapitalOsAuthService implements OnDestroy {\n private readonly config = inject(CAPITALOS_CONFIG)\n private readonly tokenExchangeService = inject(TokenExchangeService)\n\n // Private BehaviorSubjects for internal state\n private readonly _longLivedToken$ = new BehaviorSubject<string | undefined>(undefined)\n private readonly _baseUrl$ = new BehaviorSubject<string | undefined>(undefined)\n private readonly _isLoading$ = new BehaviorSubject(false)\n private readonly _error$ = new BehaviorSubject<Error | undefined>(undefined)\n\n // Public observable for token data\n readonly tokenData$: Observable<TokenData | undefined> = combineLatest([this._longLivedToken$, this._baseUrl$]).pipe(\n map(([token, baseUrl]) => {\n if (!token || !baseUrl) {\n return undefined\n }\n\n return {\n token,\n tokenType: TokenType.longLived,\n baseUrl,\n paramKey: TokenParamKey.accessToken,\n paramLocation: TokenParamLocation.hash,\n }\n })\n )\n\n // Public observables for UI state\n readonly isLoading$: Observable<boolean> = this._isLoading$.asObservable()\n readonly error$: Observable<Error | undefined> = this._error$.asObservable()\n readonly authState$: Observable<AuthState> = combineLatest([this._isLoading$, this._error$, this.tokenData$]).pipe(\n map(([isLoading, error, tokenData]) => {\n if (isLoading) return 'loading'\n if (error) return 'error'\n if (tokenData) return 'authenticated'\n return 'idle'\n })\n )\n\n private isDestroyed = false\n private logger: ReturnType<typeof createLogger>\n\n constructor() {\n this.logger = createLogger(this.config.enableLogging, this.config.logger)\n\n // Start authentication flow eagerly on construction.\n // This is intentional: auth begins as soon as the app boots so the token\n // is ready when CardsAppComponent renders, reducing perceived load time.\n this.refreshToken()\n }\n\n ngOnDestroy(): void {\n this.isDestroyed = true\n }\n\n /**\n * Invalidates the current token, triggering a refresh.\n * Called when the iframe signals that the token has expired.\n */\n invalidateToken(): void {\n this.logger.log('CapitalOsAuthService: Invalidating token')\n this._longLivedToken$.next(undefined)\n this._baseUrl$.next(undefined)\n this._error$.next(undefined)\n this.refreshToken()\n }\n\n /**\n * Refreshes the token by fetching a new one-time token and exchanging it.\n */\n async refreshToken(): Promise<void> {\n if (this.isDestroyed) {\n return\n }\n\n // Prevent concurrent refresh calls - if already loading, skip\n if (this._isLoading$.value) {\n this.logger.log('CapitalOsAuthService: Token refresh already in progress, skipping')\n return\n }\n\n this.logger.log('CapitalOsAuthService: Starting token refresh')\n this._isLoading$.next(true)\n this._error$.next(undefined)\n\n try {\n // Get one-time token from platform\n const oneTimeToken = await this.config.getToken()\n this.logger.log('CapitalOsAuthService: Received one-time token')\n\n if (this.isDestroyed) {\n return\n }\n\n // Exchange for long-lived token\n const result = await this.tokenExchangeService.exchange(oneTimeToken, {\n enableLogging: this.config.enableLogging,\n })\n\n if (this.isDestroyed) {\n return\n }\n\n this._longLivedToken$.next(result.longLivedToken)\n this._baseUrl$.next(result.baseUrl)\n this._error$.next(undefined)\n this.logger.log('CapitalOsAuthService: Token exchange complete')\n } catch (rawError) {\n if (!this.isDestroyed) {\n const error = toError(rawError)\n this.logger.error(`CapitalOsAuthService: Token refresh failed: ${error.message}`)\n this._error$.next(error)\n }\n } finally {\n if (!this.isDestroyed) {\n this._isLoading$.next(false)\n }\n }\n }\n}\n","import {\n Component,\n inject,\n Input,\n Output,\n EventEmitter,\n ViewChild,\n ElementRef,\n AfterViewInit,\n OnDestroy,\n} from '@angular/core'\nimport { Subscription } from 'rxjs'\nimport { IframeManager, CapitalOSError, TokenData, RawErrorDetails, ThemeColorScheme } from '@capitalos/core'\nimport { CapitalOsAuthService } from './capitalos-auth.service'\nimport { CAPITALOS_CONFIG } from './provide-capitalos'\n\n// TODO: Automate version injection at build time\nconst SDK_VERSION = '0.1.0-rc.1'\n\n/**\n * CardsApp component that renders the CapitalOS cards interface in an iframe.\n *\n * The component emits events for loading state - consumers should handle their own loading UI:\n *\n * ```html\n * <div *ngIf=\"!cardsLoaded\">\n * <my-loading-spinner></my-loading-spinner>\n * </div>\n * <capitalos-cards-app\n * (loaded)=\"cardsLoaded = true\"\n * (error)=\"onCardsError($event)\"\n * ></capitalos-cards-app>\n * ```\n */\n@Component({\n selector: 'capitalos-cards-app',\n standalone: true,\n template: `<div #iframeContainer class=\"capitalos-iframe-container\"></div>`,\n styles: [\n `\n :host {\n display: block;\n width: 100%;\n }\n\n .capitalos-iframe-container {\n width: 100%;\n }\n `,\n ],\n})\nexport class CardsAppComponent implements AfterViewInit, OnDestroy {\n // Injected services\n private readonly authService = inject(CapitalOsAuthService)\n private readonly config = inject(CAPITALOS_CONFIG)\n\n // Inputs\n @Input() theme?: ThemeColorScheme\n @Input() heightOffsetPx = 12\n @Input() enableLogging?: boolean\n\n // Outputs\n @Output() loaded = new EventEmitter<void>()\n @Output() error = new EventEmitter<CapitalOSError>()\n\n // View children\n @ViewChild('iframeContainer') iframeContainer?: ElementRef<HTMLDivElement>\n\n // Internal state\n private iframeManager?: IframeManager\n private tokenDataSubscription?: Subscription\n\n ngAfterViewInit(): void {\n // Subscribe to tokenData$ and initialize iframe when ready\n this.tokenDataSubscription = this.authService.tokenData$.subscribe((tokenData) => {\n if (tokenData && this.iframeContainer) {\n this.initializeIframe(tokenData, this.iframeContainer.nativeElement)\n }\n })\n }\n\n ngOnDestroy(): void {\n this.tokenDataSubscription?.unsubscribe()\n this.iframeManager?.destroy()\n }\n\n private initializeIframe(tokenData: TokenData, container: HTMLElement): void {\n // Destroy previous iframe if exists\n this.iframeManager?.destroy()\n\n const resolvedEnableLogging = this.enableLogging ?? this.config.enableLogging ?? false\n const resolvedTheme = this.theme ?? this.config.theme\n\n this.iframeManager = new IframeManager({\n container,\n tokenData,\n renderingContext: { entryPoint: 'cardsApp' },\n theme: resolvedTheme,\n enableLogging: resolvedEnableLogging,\n logger: this.config.logger,\n sdkVersion: SDK_VERSION,\n heightOffsetPx: this.heightOffsetPx,\n callbacks: {\n onLoad: () => {\n this.loaded.emit()\n },\n onError: (rawError: RawErrorDetails) => {\n const capitalOsError = new CapitalOSError(rawError)\n this.error.emit(capitalOsError)\n },\n onTokenExpired: () => {\n this.authService.invalidateToken()\n },\n },\n })\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core'\nimport { CardsAppComponent } from './cards-app.component'\nimport { CapitalOsConfig, CAPITALOS_CONFIG } from './provide-capitalos'\nimport { CapitalOsAuthService } from './capitalos-auth.service'\nimport { TokenExchangeService } from './token-exchange.service'\n\n/**\n * NgModule for CapitalOS SDK.\n *\n * Use this module for NgModule-based Angular applications.\n * For standalone applications, use provideCapitalOs() instead.\n *\n * Usage:\n * ```typescript\n * @NgModule({\n * imports: [\n * CapitalOsModule.forRoot({\n * getToken: async () => {\n * const response = await fetch('/api/capitalos/token');\n * const data = await response.json();\n * return data.token;\n * },\n * enableLogging: true,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@NgModule({\n imports: [CardsAppComponent],\n exports: [CardsAppComponent],\n})\nexport class CapitalOsModule {\n static forRoot(config: CapitalOsConfig): ModuleWithProviders<CapitalOsModule> {\n return {\n ngModule: CapitalOsModule,\n providers: [{ provide: CAPITALOS_CONFIG, useValue: config }, TokenExchangeService, CapitalOsAuthService],\n }\n }\n}\n","/*\n * Public API Surface of @capitalos/angular\n */\n\n// Components\nexport { CardsAppComponent } from './lib/cards-app.component'\n\n// Services\nexport { CapitalOsAuthService } from './lib/capitalos-auth.service'\nexport type { AuthState } from './lib/capitalos-auth.service'\n\n// Provider (standalone)\nexport { provideCapitalOs, CAPITALOS_CONFIG } from './lib/provide-capitalos'\nexport type { CapitalOsConfig } from './lib/provide-capitalos'\n\n// Module (NgModule-based apps)\nexport { CapitalOsModule } from './lib/capitalos.module'\n\n// Re-export commonly used types from core\nexport type { ThemeColorScheme, Logger, TokenData, RawErrorDetails } from '@capitalos/core'\n\nexport { CapitalOSError, ErrorCode } from '@capitalos/core'\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AA+BA;;AAEG;MACU,gBAAgB,GAAG,IAAI,cAAc,CAAkB,kBAAkB,EAAC;AAEvF;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,gBAAgB,CAAC,MAAuB,EAAA;IACtD,OAAO;AACL,QAAA;AACE,YAAA,OAAO,EAAE,gBAAgB;AACzB,YAAA,QAAQ,EAAE,MAAM;AACjB,SAAA;QACD,oBAAoB;QACpB,oBAAoB;KACrB,CAAA;AACH;;AC9DA,MAAM,yBAAyB,GAAG,KAAM,CAAA;AAOxC;;;AAGG;MAEU,oBAAoB,CAAA;AADjC,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAC1C,IAAW,CAAA,WAAA,GAAG,KAAK,CAAA;QACnB,IAAqB,CAAA,qBAAA,GAA2B,IAAI,CAAA;AAqC7D,KAAA;IAnCC,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;AACvB,QAAA,IAAI,CAAC,qBAAqB,EAAE,KAAK,EAAE,CAAA;AACnC,QAAA,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAA;KAClC;AAED;;;AAGG;AACH,IAAA,MAAM,QAAQ,CAAC,YAAoB,EAAE,UAAuC,EAAE,EAAA;QAC5E,IAAI,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;AACtD,SAAA;;AAGD,QAAA,IAAI,CAAC,qBAAqB,EAAE,KAAK,EAAE,CAAA;AAEnC,QAAA,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;AAC7C,QAAA,IAAI,CAAC,qBAAqB,GAAG,eAAe,CAAA;QAE5C,IAAI;YACF,OAAO,MAAM,oBAAoB,CAAC;gBAChC,YAAY;gBACZ,aAAa,EAAE,OAAO,CAAC,aAAa;AACpC,gBAAA,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;AAC1B,gBAAA,SAAS,EAAE,yBAAyB;gBACpC,MAAM,EAAE,eAAe,CAAC,MAAM;AAC/B,aAAA,CAAC,CAAA;AACH,SAAA;AAAS,gBAAA;AACR,YAAA,IAAI,IAAI,CAAC,qBAAqB,KAAK,eAAe,EAAE;AAClD,gBAAA,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAA;AAClC,aAAA;AACF,SAAA;KACF;;iHAvCU,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;qHAApB,oBAAoB,EAAA,CAAA,CAAA;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBADhC,UAAU;;;ACTX;;AAEG;AACH,SAAS,OAAO,CAAC,KAAc,EAAA;IAC7B,IAAI,KAAK,YAAY,KAAK,EAAE;AAC1B,QAAA,OAAO,KAAK,CAAA;AACb,KAAA;IACD,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;AACjC,CAAC;AAOD;;;;;;;;;AASG;MAEU,oBAAoB,CAAA;AA0C/B,IAAA,WAAA,GAAA;AAzCiB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAA;AACjC,QAAA,IAAA,CAAA,oBAAoB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAA;;AAGnD,QAAA,IAAA,CAAA,gBAAgB,GAAG,IAAI,eAAe,CAAqB,SAAS,CAAC,CAAA;AACrE,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,eAAe,CAAqB,SAAS,CAAC,CAAA;AAC9D,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAAA;AACxC,QAAA,IAAA,CAAA,OAAO,GAAG,IAAI,eAAe,CAAoB,SAAS,CAAC,CAAA;;QAGnE,IAAU,CAAA,UAAA,GAAsC,aAAa,CAAC,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAClH,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,KAAI;AACvB,YAAA,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE;AACtB,gBAAA,OAAO,SAAS,CAAA;AACjB,aAAA;YAED,OAAO;gBACL,KAAK;gBACL,SAAS,EAAE,SAAS,CAAC,SAAS;gBAC9B,OAAO;gBACP,QAAQ,EAAE,aAAa,CAAC,WAAW;gBACnC,aAAa,EAAE,kBAAkB,CAAC,IAAI;aACvC,CAAA;SACF,CAAC,CACH,CAAA;;AAGQ,QAAA,IAAA,CAAA,UAAU,GAAwB,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAA;AACjE,QAAA,IAAA,CAAA,MAAM,GAAkC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAA;AACnE,QAAA,IAAA,CAAA,UAAU,GAA0B,aAAa,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAChH,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,KAAI;AACpC,YAAA,IAAI,SAAS;AAAE,gBAAA,OAAO,SAAS,CAAA;AAC/B,YAAA,IAAI,KAAK;AAAE,gBAAA,OAAO,OAAO,CAAA;AACzB,YAAA,IAAI,SAAS;AAAE,gBAAA,OAAO,eAAe,CAAA;AACrC,YAAA,OAAO,MAAM,CAAA;SACd,CAAC,CACH,CAAA;QAEO,IAAW,CAAA,WAAA,GAAG,KAAK,CAAA;AAIzB,QAAA,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;;;;QAKzE,IAAI,CAAC,YAAY,EAAE,CAAA;KACpB;IAED,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;KACxB;AAED;;;AAGG;IACH,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAA;AAC3D,QAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;AACrC,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;AAC9B,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC5B,IAAI,CAAC,YAAY,EAAE,CAAA;KACpB;AAED;;AAEG;AACH,IAAA,MAAM,YAAY,GAAA;QAChB,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,OAAM;AACP,SAAA;;AAGD,QAAA,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;AAC1B,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAA;YACpF,OAAM;AACP,SAAA;AAED,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAA;AAC/D,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAE5B,IAAI;;YAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;AACjD,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;YAEhE,IAAI,IAAI,CAAC,WAAW,EAAE;gBACpB,OAAM;AACP,aAAA;;YAGD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,YAAY,EAAE;AACpE,gBAAA,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;AACzC,aAAA,CAAC,CAAA;YAEF,IAAI,IAAI,CAAC,WAAW,EAAE;gBACpB,OAAM;AACP,aAAA;YAED,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;YACjD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AACnC,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;AAC5B,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;AACjE,SAAA;AAAC,QAAA,OAAO,QAAQ,EAAE;AACjB,YAAA,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AACrB,gBAAA,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;gBAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAA+C,4CAAA,EAAA,KAAK,CAAC,OAAO,CAAE,CAAA,CAAC,CAAA;AACjF,gBAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACzB,aAAA;AACF,SAAA;AAAS,gBAAA;AACR,YAAA,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AACrB,gBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC7B,aAAA;AACF,SAAA;KACF;;iHAtHU,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;qHAApB,oBAAoB,EAAA,CAAA,CAAA;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBADhC,UAAU;;;ACfX;AACA,MAAM,WAAW,GAAG,YAAY,CAAA;AAEhC;;;;;;;;;;;;;;AAcG;MAkBU,iBAAiB,CAAA;AAjB9B,IAAA,WAAA,GAAA;;AAmBmB,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAA;AAC1C,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAIzC,IAAc,CAAA,cAAA,GAAG,EAAE,CAAA;;AAIlB,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,YAAY,EAAQ,CAAA;AACjC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,YAAY,EAAkB,CAAA;AAqDrD,KAAA;IA5CC,eAAe,GAAA;;AAEb,QAAA,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,SAAS,KAAI;AAC/E,YAAA,IAAI,SAAS,IAAI,IAAI,CAAC,eAAe,EAAE;gBACrC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,CAAA;AACrE,aAAA;AACH,SAAC,CAAC,CAAA;KACH;IAED,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,qBAAqB,EAAE,WAAW,EAAE,CAAA;AACzC,QAAA,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,CAAA;KAC9B;IAEO,gBAAgB,CAAC,SAAoB,EAAE,SAAsB,EAAA;;AAEnE,QAAA,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,CAAA;AAE7B,QAAA,MAAM,qBAAqB,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,KAAK,CAAA;QACtF,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAA;AAErD,QAAA,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC;YACrC,SAAS;YACT,SAAS;AACT,YAAA,gBAAgB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE;AAC5C,YAAA,KAAK,EAAE,aAAa;AACpB,YAAA,aAAa,EAAE,qBAAqB;AACpC,YAAA,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;AAC1B,YAAA,UAAU,EAAE,WAAW;YACvB,cAAc,EAAE,IAAI,CAAC,cAAc;AACnC,YAAA,SAAS,EAAE;gBACT,MAAM,EAAE,MAAK;AACX,oBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;iBACnB;AACD,gBAAA,OAAO,EAAE,CAAC,QAAyB,KAAI;AACrC,oBAAA,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAA;AACnD,oBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;iBAChC;gBACD,cAAc,EAAE,MAAK;AACnB,oBAAA,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,CAAA;iBACnC;AACF,aAAA;AACF,SAAA,CAAC,CAAA;KACH;;8GAhEU,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAjB,iBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,iBAAiB,gVAdlB,CAAiE,+DAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,0EAAA,CAAA,EAAA,CAAA,CAAA;2FAchE,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAjB7B,SAAS;+BACE,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,QAAA,EACN,CAAiE,+DAAA,CAAA,EAAA,MAAA,EAAA,CAAA,0EAAA,CAAA,EAAA,CAAA;8BAoBlE,KAAK,EAAA,CAAA;sBAAb,KAAK;gBACG,cAAc,EAAA,CAAA;sBAAtB,KAAK;gBACG,aAAa,EAAA,CAAA;sBAArB,KAAK;gBAGI,MAAM,EAAA,CAAA;sBAAf,MAAM;gBACG,KAAK,EAAA,CAAA;sBAAd,MAAM;gBAGuB,eAAe,EAAA,CAAA;sBAA5C,SAAS;uBAAC,iBAAiB,CAAA;;;AC5D9B;;;;;;;;;;;;;;;;;;;;;;AAsBG;MAKU,eAAe,CAAA;IAC1B,OAAO,OAAO,CAAC,MAAuB,EAAA;QACpC,OAAO;AACL,YAAA,QAAQ,EAAE,eAAe;AACzB,YAAA,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,oBAAoB,EAAE,oBAAoB,CAAC;SACzG,CAAA;KACF;;4GANU,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;6GAAf,eAAe,EAAA,OAAA,EAAA,CAHhB,iBAAiB,CAAA,EAAA,OAAA,EAAA,CACjB,iBAAiB,CAAA,EAAA,CAAA,CAAA;AAEhB,eAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,YAHhB,iBAAiB,CAAA,EAAA,CAAA,CAAA;2FAGhB,eAAe,EAAA,UAAA,EAAA,CAAA;kBAJ3B,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,OAAO,EAAE,CAAC,iBAAiB,CAAC;oBAC5B,OAAO,EAAE,CAAC,iBAAiB,CAAC;AAC7B,iBAAA,CAAA;;;AChCD;;AAEG;;ACFH;;AAEG;;;;"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@capitalos/angular" />
5
+ export * from './public-api';
@@ -0,0 +1,45 @@
1
+ import { OnDestroy } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import { TokenData } from '@capitalos/core';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Authentication state enum
7
+ */
8
+ export declare type AuthState = 'idle' | 'loading' | 'authenticated' | 'error';
9
+ /**
10
+ * Service that manages CapitalOS authentication state.
11
+ * This is the Angular equivalent of React's CapitalOsAuthenticationProvider.
12
+ *
13
+ * It handles:
14
+ * - Fetching one-time tokens via the provided getToken callback
15
+ * - Exchanging one-time tokens for long-lived JWTs
16
+ * - Managing token state via observables
17
+ * - Auto-refreshing tokens when they expire
18
+ */
19
+ export declare class CapitalOsAuthService implements OnDestroy {
20
+ private readonly config;
21
+ private readonly tokenExchangeService;
22
+ private readonly _longLivedToken$;
23
+ private readonly _baseUrl$;
24
+ private readonly _isLoading$;
25
+ private readonly _error$;
26
+ readonly tokenData$: Observable<TokenData | undefined>;
27
+ readonly isLoading$: Observable<boolean>;
28
+ readonly error$: Observable<Error | undefined>;
29
+ readonly authState$: Observable<AuthState>;
30
+ private isDestroyed;
31
+ private logger;
32
+ constructor();
33
+ ngOnDestroy(): void;
34
+ /**
35
+ * Invalidates the current token, triggering a refresh.
36
+ * Called when the iframe signals that the token has expired.
37
+ */
38
+ invalidateToken(): void;
39
+ /**
40
+ * Refreshes the token by fetching a new one-time token and exchanging it.
41
+ */
42
+ refreshToken(): Promise<void>;
43
+ static ɵfac: i0.ɵɵFactoryDeclaration<CapitalOsAuthService, never>;
44
+ static ɵprov: i0.ɵɵInjectableDeclaration<CapitalOsAuthService>;
45
+ }
@@ -0,0 +1,33 @@
1
+ import { ModuleWithProviders } from '@angular/core';
2
+ import { CapitalOsConfig } from './provide-capitalos';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "./cards-app.component";
5
+ /**
6
+ * NgModule for CapitalOS SDK.
7
+ *
8
+ * Use this module for NgModule-based Angular applications.
9
+ * For standalone applications, use provideCapitalOs() instead.
10
+ *
11
+ * Usage:
12
+ * ```typescript
13
+ * @NgModule({
14
+ * imports: [
15
+ * CapitalOsModule.forRoot({
16
+ * getToken: async () => {
17
+ * const response = await fetch('/api/capitalos/token');
18
+ * const data = await response.json();
19
+ * return data.token;
20
+ * },
21
+ * enableLogging: true,
22
+ * }),
23
+ * ],
24
+ * })
25
+ * export class AppModule {}
26
+ * ```
27
+ */
28
+ export declare class CapitalOsModule {
29
+ static forRoot(config: CapitalOsConfig): ModuleWithProviders<CapitalOsModule>;
30
+ static ɵfac: i0.ɵɵFactoryDeclaration<CapitalOsModule, never>;
31
+ static ɵmod: i0.ɵɵNgModuleDeclaration<CapitalOsModule, never, [typeof i1.CardsAppComponent], [typeof i1.CardsAppComponent]>;
32
+ static ɵinj: i0.ɵɵInjectorDeclaration<CapitalOsModule>;
33
+ }
@@ -0,0 +1,35 @@
1
+ import { EventEmitter, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
2
+ import { CapitalOSError, ThemeColorScheme } from '@capitalos/core';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * CardsApp component that renders the CapitalOS cards interface in an iframe.
6
+ *
7
+ * The component emits events for loading state - consumers should handle their own loading UI:
8
+ *
9
+ * ```html
10
+ * <div *ngIf="!cardsLoaded">
11
+ * <my-loading-spinner></my-loading-spinner>
12
+ * </div>
13
+ * <capitalos-cards-app
14
+ * (loaded)="cardsLoaded = true"
15
+ * (error)="onCardsError($event)"
16
+ * ></capitalos-cards-app>
17
+ * ```
18
+ */
19
+ export declare class CardsAppComponent implements AfterViewInit, OnDestroy {
20
+ private readonly authService;
21
+ private readonly config;
22
+ theme?: ThemeColorScheme;
23
+ heightOffsetPx: number;
24
+ enableLogging?: boolean;
25
+ loaded: EventEmitter<void>;
26
+ error: EventEmitter<CapitalOSError>;
27
+ iframeContainer?: ElementRef<HTMLDivElement>;
28
+ private iframeManager?;
29
+ private tokenDataSubscription?;
30
+ ngAfterViewInit(): void;
31
+ ngOnDestroy(): void;
32
+ private initializeIframe;
33
+ static ɵfac: i0.ɵɵFactoryDeclaration<CardsAppComponent, never>;
34
+ static ɵcmp: i0.ɵɵComponentDeclaration<CardsAppComponent, "capitalos-cards-app", never, { "theme": "theme"; "heightOffsetPx": "heightOffsetPx"; "enableLogging": "enableLogging"; }, { "loaded": "loaded"; "error": "error"; }, never, never, true>;
35
+ }
@@ -0,0 +1,50 @@
1
+ import { InjectionToken, Provider } from '@angular/core';
2
+ import { Logger, ThemeColorScheme } from '@capitalos/core';
3
+ /**
4
+ * Configuration for CapitalOS SDK
5
+ */
6
+ export interface CapitalOsConfig {
7
+ /**
8
+ * Function that returns a promise resolving to a one-time token.
9
+ * This is typically a call to your backend that initiates a CapitalOS login.
10
+ */
11
+ getToken: () => Promise<string>;
12
+ /**
13
+ * Whether to enable logging for debugging purposes.
14
+ */
15
+ enableLogging?: boolean;
16
+ /**
17
+ * Optional custom logger for capturing SDK logs.
18
+ */
19
+ logger?: Logger;
20
+ /**
21
+ * Theme color scheme for the SDK components.
22
+ */
23
+ theme?: ThemeColorScheme;
24
+ }
25
+ /**
26
+ * Injection token for CapitalOS configuration
27
+ */
28
+ export declare const CAPITALOS_CONFIG: InjectionToken<CapitalOsConfig>;
29
+ /**
30
+ * Provides the CapitalOS SDK with the specified configuration.
31
+ *
32
+ * Usage in app.config.ts (standalone):
33
+ * ```typescript
34
+ * bootstrapApplication(AppComponent, {
35
+ * providers: [
36
+ * provideCapitalOs({
37
+ * getToken: async () => {
38
+ * const response = await fetch('/api/capitalos/token');
39
+ * const data = await response.json();
40
+ * return data.token;
41
+ * },
42
+ * enableLogging: true,
43
+ * }),
44
+ * ],
45
+ * });
46
+ * ```
47
+ *
48
+ * For NgModule-based apps, use CapitalOsModule.forRoot() instead.
49
+ */
50
+ export declare function provideCapitalOs(config: CapitalOsConfig): Provider[];
@@ -0,0 +1,25 @@
1
+ import { OnDestroy } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ export interface TokenExchangeResult {
4
+ longLivedToken: string;
5
+ baseUrl: string;
6
+ }
7
+ /**
8
+ * Service responsible for exchanging one-time tokens for long-lived JWTs.
9
+ * Creates a hidden iframe to perform the token exchange securely.
10
+ */
11
+ export declare class TokenExchangeService implements OnDestroy {
12
+ private readonly config;
13
+ private isDestroyed;
14
+ private activeAbortController;
15
+ ngOnDestroy(): void;
16
+ /**
17
+ * Exchanges a one-time token for a long-lived JWT.
18
+ * Delegates to @capitalos/core (browser-only) which handles iframe + Penpal lifecycle.
19
+ */
20
+ exchange(oneTimeToken: string, options?: {
21
+ enableLogging?: boolean;
22
+ }): Promise<TokenExchangeResult>;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<TokenExchangeService, never>;
24
+ static ɵprov: i0.ɵɵInjectableDeclaration<TokenExchangeService>;
25
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@capitalos/angular",
3
+ "version": "0.1.0-rc.1",
4
+ "description": "Angular SDK for CapitalOS",
5
+ "peerDependencies": {
6
+ "@angular/common": ">=14.0.0",
7
+ "@angular/core": ">=14.0.0"
8
+ },
9
+ "dependencies": {
10
+ "@capitalos/core": "^0.1.0-rc.1",
11
+ "tslib": "^2.3.0"
12
+ },
13
+ "sideEffects": false,
14
+ "keywords": [
15
+ "capitalos",
16
+ "angular",
17
+ "sdk"
18
+ ],
19
+ "author": "CapitalOS",
20
+ "license": "MIT",
21
+ "module": "fesm2015/capitalos-angular.mjs",
22
+ "es2020": "fesm2020/capitalos-angular.mjs",
23
+ "esm2020": "esm2020/capitalos-angular.mjs",
24
+ "fesm2020": "fesm2020/capitalos-angular.mjs",
25
+ "fesm2015": "fesm2015/capitalos-angular.mjs",
26
+ "typings": "index.d.ts",
27
+ "exports": {
28
+ "./package.json": {
29
+ "default": "./package.json"
30
+ },
31
+ ".": {
32
+ "types": "./index.d.ts",
33
+ "esm2020": "./esm2020/capitalos-angular.mjs",
34
+ "es2020": "./fesm2020/capitalos-angular.mjs",
35
+ "es2015": "./fesm2015/capitalos-angular.mjs",
36
+ "node": "./fesm2015/capitalos-angular.mjs",
37
+ "default": "./fesm2020/capitalos-angular.mjs"
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,8 @@
1
+ export { CardsAppComponent } from './lib/cards-app.component';
2
+ export { CapitalOsAuthService } from './lib/capitalos-auth.service';
3
+ export type { AuthState } from './lib/capitalos-auth.service';
4
+ export { provideCapitalOs, CAPITALOS_CONFIG } from './lib/provide-capitalos';
5
+ export type { CapitalOsConfig } from './lib/provide-capitalos';
6
+ export { CapitalOsModule } from './lib/capitalos.module';
7
+ export type { ThemeColorScheme, Logger, TokenData, RawErrorDetails } from '@capitalos/core';
8
+ export { CapitalOSError, ErrorCode } from '@capitalos/core';