@marsaude/devtools-shell 0.1.0
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,267 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { Type, TemplateRef, EnvironmentProviders, OnDestroy, InjectionToken } from '@angular/core';
|
|
3
|
+
import * as _marsaude_devtools_shell from '@marsaude/devtools-shell';
|
|
4
|
+
import { Observable } from 'rxjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A single pluggable entry surfaced by the shell. `content` is what the shell
|
|
8
|
+
* renders inside its container when this action is selected — a standalone
|
|
9
|
+
* component class or a `TemplateRef`. The shell never knows what the content
|
|
10
|
+
* does; that is entirely the consumer's domain.
|
|
11
|
+
*/
|
|
12
|
+
interface DevtoolsAction {
|
|
13
|
+
/** Stable id, used as the panel key. */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Human-readable label shown in the action switcher. */
|
|
16
|
+
label: string;
|
|
17
|
+
/** Optional Material Symbols glyph name (e.g. `'biotech'`). */
|
|
18
|
+
icon?: string;
|
|
19
|
+
/** Component or template rendered in the container for this action. */
|
|
20
|
+
content?: Type<unknown> | TemplateRef<unknown>;
|
|
21
|
+
/** Lower comes first. Defaults to registration order. */
|
|
22
|
+
order?: number;
|
|
23
|
+
}
|
|
24
|
+
/** Where the FAB sits the first time, before any persisted position exists. */
|
|
25
|
+
type DevtoolsCorner = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
26
|
+
/** Look-and-feel + behaviour knobs for the shell. All optional. */
|
|
27
|
+
interface DevtoolsShellConfig {
|
|
28
|
+
/** Title shown in the container header when no action is active. */
|
|
29
|
+
title?: string;
|
|
30
|
+
/** localStorage key used to persist the FAB position. */
|
|
31
|
+
storageKey?: string;
|
|
32
|
+
/** Initial corner when there is no persisted position. */
|
|
33
|
+
initialCorner?: DevtoolsCorner;
|
|
34
|
+
/** Material Symbols glyph for the FAB itself. Defaults to `developer_mode`. */
|
|
35
|
+
fabIcon?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type ValidationMedia = 'WHATSAPP' | 'SMS';
|
|
39
|
+
/** Everything environment-specific is passed in by the host — the package
|
|
40
|
+
* reads NOTHING from the host app's environment/services. */
|
|
41
|
+
interface DevtoolsConfig {
|
|
42
|
+
/** API base, e.g. https://api.stag.marsaude.net/v1 */
|
|
43
|
+
apiBaseUrl: string;
|
|
44
|
+
/** OTP channel. Default WHATSAPP. */
|
|
45
|
+
media?: ValidationMedia;
|
|
46
|
+
/** X-Mar-Locale header value. Default pt_BR. */
|
|
47
|
+
locale?: string;
|
|
48
|
+
/** Google OAuth client id for the admin login. */
|
|
49
|
+
googleClientId?: string;
|
|
50
|
+
/** Google OAuth redirect_uri (must be whitelisted). */
|
|
51
|
+
googleRedirectUri?: string;
|
|
52
|
+
/** reCAPTCHA v3 site key (optional). */
|
|
53
|
+
recaptchaSiteKey?: string;
|
|
54
|
+
/** Fixed RH organization id used by the generator. Default 200. */
|
|
55
|
+
fixedOrgId?: number;
|
|
56
|
+
/** Fallback admin phone for the SMS-release toggle. */
|
|
57
|
+
adminPhone?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface ProvideDevtoolsOptions extends DevtoolsConfig {
|
|
61
|
+
/** Layer-1 production gate. Pass `!environment.production`. @default true */
|
|
62
|
+
enabled?: boolean;
|
|
63
|
+
/** Extra custom panels, appended to the built-in DevTools panels. */
|
|
64
|
+
actions?: DevtoolsAction[];
|
|
65
|
+
/** Container header title. */
|
|
66
|
+
title?: string;
|
|
67
|
+
/** FAB glyph. @default developer_mode */
|
|
68
|
+
fabIcon?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Mount the self-contained DevTools. Add to `bootstrapApplication` providers or
|
|
72
|
+
* `@NgModule({ providers })`. Everything runs in an ISOLATED environment
|
|
73
|
+
* injector with the package's OWN HttpClient + interceptor — it never touches
|
|
74
|
+
* the host app's services, interceptors or session beyond the deliberate
|
|
75
|
+
* active-session keys used by the Switch panel.
|
|
76
|
+
*/
|
|
77
|
+
declare function provideDevtools(options: ProvideDevtoolsOptions): EnvironmentProviders;
|
|
78
|
+
|
|
79
|
+
interface Point {
|
|
80
|
+
x: number;
|
|
81
|
+
y: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Owns the FAB position + side and persists them. The math is ported verbatim
|
|
85
|
+
* from the `DevTools FAB` prototype (default corner, clamp bounds, edge snap).
|
|
86
|
+
* Only position/side are stored — no domain/session data.
|
|
87
|
+
*/
|
|
88
|
+
declare class DevtoolsPositionService {
|
|
89
|
+
private readonly config;
|
|
90
|
+
private readonly key;
|
|
91
|
+
/** FAB top-left in viewport coords. Null until first measured/loaded. */
|
|
92
|
+
readonly position: _angular_core.WritableSignal<Point>;
|
|
93
|
+
readonly side: _angular_core.WritableSignal<"left" | "right">;
|
|
94
|
+
/** Live update during drag (not persisted). */
|
|
95
|
+
move(p: Point): void;
|
|
96
|
+
/** Commit + persist the final position and side. */
|
|
97
|
+
commit(p: Point, side: 'left' | 'right'): void;
|
|
98
|
+
/** Re-clamp against the current viewport. Call on resize. */
|
|
99
|
+
reclamp(): void;
|
|
100
|
+
/** Prototype clamp: x ∈ [6, W-S-6], y ∈ [70, H-S-6]. */
|
|
101
|
+
clamp(p: Point): Point;
|
|
102
|
+
private persist;
|
|
103
|
+
/** Prototype default corner: { x: W-74, y: H-150 }. */
|
|
104
|
+
private load;
|
|
105
|
+
private loadSide;
|
|
106
|
+
private defaultPos;
|
|
107
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DevtoolsPositionService, never>;
|
|
108
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DevtoolsPositionService>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Tiny toast surface owned by the shell. Panels (or any consumer) can inject it
|
|
113
|
+
* to flash a short message inside the shell's own layer — no Material/snackbar
|
|
114
|
+
* dependency required.
|
|
115
|
+
*/
|
|
116
|
+
declare class DevtoolsToastService {
|
|
117
|
+
/** Current message, or null when nothing is showing. */
|
|
118
|
+
readonly message: _angular_core.WritableSignal<string>;
|
|
119
|
+
private timer;
|
|
120
|
+
show(message: string, durationMs?: number): void;
|
|
121
|
+
clear(): void;
|
|
122
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DevtoolsToastService, never>;
|
|
123
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DevtoolsToastService>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface DialItem {
|
|
127
|
+
action: DevtoolsAction;
|
|
128
|
+
style: Record<string, string | number>;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The invólucro: a draggable FAB that opens an agnostic container.
|
|
132
|
+
*
|
|
133
|
+
* Drag, clamp/snap, the radial speed-dial geometry, the collapse-to-edge grip,
|
|
134
|
+
* the drawer/sheet panel and the toast are ported verbatim from the `DevTools
|
|
135
|
+
* FAB` prototype (Pointer Events, the exact math and the same CSS/keyframes) —
|
|
136
|
+
* kept entirely domain-free. Content arrives via {@link DEVTOOLS_ACTION}
|
|
137
|
+
* (primary) or `<ng-content>` (secondary). Auto-mounted by `provideDevtools()`.
|
|
138
|
+
*/
|
|
139
|
+
declare class DevtoolsShellComponent implements OnDestroy {
|
|
140
|
+
protected readonly pos: DevtoolsPositionService;
|
|
141
|
+
protected readonly config: _marsaude_devtools_shell.DevtoolsShellConfig;
|
|
142
|
+
protected readonly toast: DevtoolsToastService;
|
|
143
|
+
private readonly registered;
|
|
144
|
+
protected readonly actions: _angular_core.WritableSignal<DevtoolsAction[]>;
|
|
145
|
+
protected readonly open: _angular_core.WritableSignal<boolean>;
|
|
146
|
+
protected readonly panelId: _angular_core.WritableSignal<string>;
|
|
147
|
+
protected readonly collapsed: _angular_core.WritableSignal<boolean>;
|
|
148
|
+
protected readonly dragging: _angular_core.WritableSignal<boolean>;
|
|
149
|
+
private readonly winW;
|
|
150
|
+
private readonly winH;
|
|
151
|
+
protected readonly hasDial: _angular_core.Signal<boolean>;
|
|
152
|
+
protected readonly activeAction: _angular_core.Signal<DevtoolsAction>;
|
|
153
|
+
protected readonly isCollapsed: _angular_core.Signal<boolean>;
|
|
154
|
+
/** FAB style — collapsed grip vs expanded button (prototype values). */
|
|
155
|
+
protected readonly fabStyle: _angular_core.Signal<Record<string, string>>;
|
|
156
|
+
/** Radial speed-dial geometry — ported verbatim (R=268, 5°→87°). */
|
|
157
|
+
protected readonly dialItems: _angular_core.Signal<DialItem[]>;
|
|
158
|
+
/** Drawer (desktop) / bottom-sheet (mobile) — prototype values. */
|
|
159
|
+
protected readonly panelStyle: _angular_core.Signal<Record<string, string>>;
|
|
160
|
+
private drag;
|
|
161
|
+
private dragEndAt;
|
|
162
|
+
private collapseTimer;
|
|
163
|
+
private readonly moveHandler;
|
|
164
|
+
private readonly upHandler;
|
|
165
|
+
constructor();
|
|
166
|
+
ngOnDestroy(): void;
|
|
167
|
+
protected onResize(): void;
|
|
168
|
+
protected onFabDown(e: PointerEvent): void;
|
|
169
|
+
private onMove;
|
|
170
|
+
private onUp;
|
|
171
|
+
private detachDragListeners;
|
|
172
|
+
protected onFabClick(): void;
|
|
173
|
+
private toggleDial;
|
|
174
|
+
protected openPanel(id: string): void;
|
|
175
|
+
protected togglePanel(id: string): void;
|
|
176
|
+
protected closePanel(): void;
|
|
177
|
+
protected closeDial(): void;
|
|
178
|
+
protected asTemplate(c: unknown): TemplateRef<unknown> | null;
|
|
179
|
+
protected asComponent(c: unknown): Type<unknown> | null;
|
|
180
|
+
private scheduleCollapse;
|
|
181
|
+
private clearCollapse;
|
|
182
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DevtoolsShellComponent, never>;
|
|
183
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DevtoolsShellComponent, "devtools-shell", never, {}, {}, never, ["*", "*"], true, never>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Multi-provider token. Each `{ provide: DEVTOOLS_ACTION, useValue, multi: true }`
|
|
188
|
+
* adds one pluggable panel to the shell. This is the extension point: the shell
|
|
189
|
+
* collects every registered action and renders it — it has no built-in actions.
|
|
190
|
+
*/
|
|
191
|
+
declare const DEVTOOLS_ACTION: InjectionToken<DevtoolsAction>;
|
|
192
|
+
/** Single-value config token. Falls back to an empty config. */
|
|
193
|
+
declare const DEVTOOLS_SHELL_CONFIG: InjectionToken<DevtoolsShellConfig>;
|
|
194
|
+
|
|
195
|
+
interface DevtoolsSession {
|
|
196
|
+
id: string;
|
|
197
|
+
kind: 'admin' | 'test';
|
|
198
|
+
name: string;
|
|
199
|
+
document?: string;
|
|
200
|
+
accessToken: string;
|
|
201
|
+
refreshToken: string;
|
|
202
|
+
profile?: any;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Manages the *active app session* that the host patient app consumes, letting
|
|
206
|
+
* the QA switch it between the fixed admin (the DevTools identity) and any saved
|
|
207
|
+
* generated user — without re-OTP. The DevTools' own API calls do NOT use this;
|
|
208
|
+
* they always use the admin token via the package interceptor.
|
|
209
|
+
*/
|
|
210
|
+
declare class DevtoolsSessionService {
|
|
211
|
+
private readonly storage;
|
|
212
|
+
private readonly auth;
|
|
213
|
+
private readonly _sessions;
|
|
214
|
+
readonly sessions: _angular_core.Signal<DevtoolsSession[]>;
|
|
215
|
+
readonly activeId: _angular_core.WritableSignal<string>;
|
|
216
|
+
/** Admin session derived from the DevTools identity (auth). */
|
|
217
|
+
readonly admin: _angular_core.Signal<DevtoolsSession>;
|
|
218
|
+
saveTestSession(session: Omit<DevtoolsSession, 'id' | 'kind'> & {
|
|
219
|
+
document: string;
|
|
220
|
+
}): DevtoolsSession;
|
|
221
|
+
/** Write a stored session into the host's active-session keys. */
|
|
222
|
+
switchTo(id: string): DevtoolsSession | null;
|
|
223
|
+
removeSession(id: string): void;
|
|
224
|
+
active(): DevtoolsSession | null;
|
|
225
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DevtoolsSessionService, never>;
|
|
226
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DevtoolsSessionService>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface TokenResponse {
|
|
230
|
+
accessToken: string;
|
|
231
|
+
refreshToken: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The DevTools' OWN identity (admin). Completely separate from the host app's
|
|
236
|
+
* session: its tokens live under `DEVTOOLS_ADMIN_*` and are what the package's
|
|
237
|
+
* interceptor attaches. The package is "logged in" iff an admin token exists.
|
|
238
|
+
*/
|
|
239
|
+
declare class DevtoolsAuthService {
|
|
240
|
+
private readonly storage;
|
|
241
|
+
private readonly config;
|
|
242
|
+
private readonly api;
|
|
243
|
+
private readonly _token;
|
|
244
|
+
readonly logged: _angular_core.Signal<boolean>;
|
|
245
|
+
adminToken(): string | null;
|
|
246
|
+
adminRefreshToken(): string | null;
|
|
247
|
+
adminProfile(): any;
|
|
248
|
+
isLogged(): boolean;
|
|
249
|
+
/** Begin Google OAuth for the admin (full-page redirect). */
|
|
250
|
+
loginGoogleRedirect(): void;
|
|
251
|
+
/**
|
|
252
|
+
* Consume a Google OAuth return that WE initiated (guarded by a flag so we
|
|
253
|
+
* never steal the host app's own OAuth redirect). Exchanges the access token
|
|
254
|
+
* for admin JWTs and loads the admin profile.
|
|
255
|
+
*/
|
|
256
|
+
handleGoogleReturn(): void;
|
|
257
|
+
exchangeGoogle(googleToken: string): Observable<any>;
|
|
258
|
+
/** Used by the interceptor on 401. */
|
|
259
|
+
refresh(): Observable<TokenResponse>;
|
|
260
|
+
setTokens(tokens: TokenResponse): void;
|
|
261
|
+
logout(): void;
|
|
262
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DevtoolsAuthService, never>;
|
|
263
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DevtoolsAuthService>;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export { DEVTOOLS_ACTION, DEVTOOLS_SHELL_CONFIG, DevtoolsAuthService, DevtoolsSessionService, DevtoolsShellComponent, DevtoolsToastService, provideDevtools };
|
|
267
|
+
export type { DevtoolsAction, DevtoolsConfig, DevtoolsCorner, DevtoolsSession, DevtoolsShellConfig, ProvideDevtoolsOptions, ValidationMedia };
|