@pillar-ai/angular 0.1.11

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/dist/README.md ADDED
@@ -0,0 +1,357 @@
1
+ # @pillar-ai/angular
2
+
3
+ Angular SDK for the [Pillar](https://trypillar.com) open-source AI copilot — embed a product assistant in your Angular app that executes tasks, not just answers questions. [GitHub](https://github.com/pillarhq/pillar) · [Docs](https://trypillar.com/docs)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@pillar-ai/angular)](https://www.npmjs.com/package/@pillar-ai/angular)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@pillar-ai/angular)](https://www.npmjs.com/package/@pillar-ai/angular)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)](https://www.typescriptlang.org/)
9
+
10
+ ## What is Pillar?
11
+
12
+ Pillar is a product copilot for SaaS and web applications. Users say what they want, and Pillar uses your UI to make it happen — navigating pages, pre-filling forms, and calling your APIs.
13
+
14
+ For example, a user could ask:
15
+
16
+ > "Close the Walmart deal as won in Salesforce and notify implementation"
17
+
18
+ > "Create a P1 bug in Linear for the checkout crash and add it to this sprint"
19
+
20
+ > "How do I set up a webhook in Stripe?"
21
+
22
+ Pillar understands the intent, builds a multi-step plan, and executes it client-side with the user's session.
23
+
24
+ ## Requirements
25
+
26
+ - Angular 17.0.0 or higher
27
+ - `@pillar-ai/sdk` (installed automatically as a dependency)
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @pillar-ai/angular
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ### 1. Initialize Pillar in your app config
38
+
39
+ ```typescript
40
+ // app.config.ts
41
+ import { ApplicationConfig, APP_INITIALIZER, inject } from '@angular/core';
42
+ import { PillarService } from '@pillar-ai/angular';
43
+
44
+ function initPillar() {
45
+ const pillar = inject(PillarService);
46
+ return () => pillar.init({ productKey: 'your-product-key' });
47
+ }
48
+
49
+ export const appConfig: ApplicationConfig = {
50
+ providers: [
51
+ { provide: APP_INITIALIZER, useFactory: initPillar, multi: true },
52
+ ],
53
+ };
54
+ ```
55
+
56
+ ### 2. Use Pillar in your components
57
+
58
+ ```typescript
59
+ // help-button.component.ts
60
+ import { Component } from '@angular/core';
61
+ import { injectPillar } from '@pillar-ai/angular';
62
+
63
+ @Component({
64
+ selector: 'app-help-button',
65
+ standalone: true,
66
+ template: `
67
+ <button (click)="toggle()">
68
+ {{ isPanelOpen() ? 'Close Help' : 'Get Help' }}
69
+ </button>
70
+ `,
71
+ })
72
+ export class HelpButtonComponent {
73
+ private pillar = injectPillar();
74
+ isPanelOpen = this.pillar.isPanelOpen;
75
+ toggle = this.pillar.toggle;
76
+ }
77
+ ```
78
+
79
+ ## API Reference
80
+
81
+ ### PillarService
82
+
83
+ Injectable service that manages the Pillar SDK lifecycle.
84
+
85
+ ```typescript
86
+ import { PillarService } from '@pillar-ai/angular';
87
+
88
+ @Component({...})
89
+ export class MyComponent {
90
+ constructor(private pillarService: PillarService) {}
91
+ }
92
+ ```
93
+
94
+ #### Methods
95
+
96
+ | Method | Description |
97
+ |--------|-------------|
98
+ | `init(config)` | Initialize the SDK with your product key |
99
+ | `open(options?)` | Open the help panel |
100
+ | `close()` | Close the help panel |
101
+ | `toggle()` | Toggle the help panel |
102
+ | `openArticle(slug)` | Open a specific article |
103
+ | `openCategory(slug)` | Navigate to a category |
104
+ | `search(query)` | Open search with a query |
105
+ | `navigate(view, params?)` | Navigate to a specific view |
106
+ | `setTheme(theme)` | Update the panel theme |
107
+ | `setTextSelectionEnabled(enabled)` | Toggle text selection popover |
108
+ | `on(event, callback)` | Subscribe to SDK events |
109
+ | `onTask(taskName, handler)` | Register a task handler |
110
+
111
+ #### Signals
112
+
113
+ | Signal | Type | Description |
114
+ |--------|------|-------------|
115
+ | `state` | `WritableSignal<PillarState>` | Current SDK state |
116
+ | `isReady` | `Signal<boolean>` | Whether SDK is ready |
117
+ | `isPanelOpen` | `WritableSignal<boolean>` | Whether panel is open |
118
+
119
+ ### injectPillar()
120
+
121
+ Angular injection function for accessing the Pillar SDK with full functionality.
122
+
123
+ ```typescript
124
+ import { injectPillar } from '@pillar-ai/angular';
125
+
126
+ @Component({...})
127
+ export class MyComponent {
128
+ private pillar = injectPillar();
129
+
130
+ handleHelp() {
131
+ this.pillar.open({ view: 'chat' });
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### injectHelpPanel()
137
+
138
+ Simplified injection function focused on panel controls.
139
+
140
+ ```typescript
141
+ import { injectHelpPanel } from '@pillar-ai/angular';
142
+
143
+ @Component({...})
144
+ export class HelpMenuComponent {
145
+ private panel = injectHelpPanel();
146
+
147
+ isOpen = this.panel.isOpen;
148
+ toggle = this.panel.toggle;
149
+ openChat = this.panel.openChat;
150
+ }
151
+ ```
152
+
153
+ ### PillarPanelComponent
154
+
155
+ Standalone component for custom panel placement.
156
+
157
+ ```typescript
158
+ import { PillarPanelComponent } from '@pillar-ai/angular';
159
+
160
+ @Component({
161
+ selector: 'app-layout',
162
+ standalone: true,
163
+ imports: [PillarPanelComponent],
164
+ template: `
165
+ <div class="layout">
166
+ <pillar-panel class="help-panel" />
167
+ <main>
168
+ <router-outlet />
169
+ </main>
170
+ </div>
171
+ `,
172
+ })
173
+ export class LayoutComponent {}
174
+ ```
175
+
176
+ **Important**: When using `PillarPanelComponent`, set `panel.container: 'manual'` in your config:
177
+
178
+ ```typescript
179
+ pillar.init({
180
+ productKey: 'your-product-key',
181
+ config: { panel: { container: 'manual' } }
182
+ });
183
+ ```
184
+
185
+ ## Advanced Usage
186
+
187
+ ### Type-Safe Task Handlers
188
+
189
+ Define your actions and get full TypeScript support:
190
+
191
+ ```typescript
192
+ // lib/pillar/actions.ts
193
+ import { defineActions } from '@pillar-ai/sdk';
194
+
195
+ export const actions = defineActions({
196
+ invite_member: {
197
+ description: 'Invite a team member',
198
+ data: {
199
+ email: { type: 'string', description: 'Email address' },
200
+ role: { type: 'string', description: 'Member role' },
201
+ },
202
+ },
203
+ });
204
+ ```
205
+
206
+ ```typescript
207
+ // my.component.ts
208
+ import { Component, OnInit, OnDestroy } from '@angular/core';
209
+ import { injectPillar } from '@pillar-ai/angular';
210
+ import { actions } from './lib/pillar/actions';
211
+
212
+ @Component({...})
213
+ export class MyComponent implements OnInit, OnDestroy {
214
+ private pillar = injectPillar<typeof actions>();
215
+ private unsubscribe?: () => void;
216
+
217
+ ngOnInit() {
218
+ // TypeScript knows the exact shape of data
219
+ this.unsubscribe = this.pillar.onTask('invite_member', (data) => {
220
+ console.log(data.email); // ✓ Typed as string
221
+ console.log(data.role); // ✓ Typed as string
222
+ });
223
+ }
224
+
225
+ ngOnDestroy() {
226
+ this.unsubscribe?.();
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### Custom Card Components
232
+
233
+ Render custom Angular components for inline UI actions:
234
+
235
+ ```typescript
236
+ // invite-card.component.ts
237
+ import { Component, input } from '@angular/core';
238
+ import type { CardComponentProps } from '@pillar-ai/angular';
239
+
240
+ @Component({
241
+ selector: 'app-invite-card',
242
+ standalone: true,
243
+ template: `
244
+ <div class="invite-card">
245
+ <h3>Invite Team Members</h3>
246
+ <input [(ngModel)]="email" placeholder="Email address" />
247
+ <button (click)="confirm()">Send Invite</button>
248
+ <button (click)="cancel()">Cancel</button>
249
+ </div>
250
+ `,
251
+ })
252
+ export class InviteCardComponent implements CardComponentProps {
253
+ data = input.required<Record<string, unknown>>();
254
+ onConfirm = input.required<(data?: Record<string, unknown>) => void>();
255
+ onCancel = input.required<() => void>();
256
+ onStateChange = input<(state: 'loading' | 'success' | 'error', message?: string) => void>();
257
+
258
+ email = '';
259
+
260
+ confirm() {
261
+ this.onConfirm()({ email: this.email });
262
+ }
263
+
264
+ cancel() {
265
+ this.onCancel()();
266
+ }
267
+ }
268
+ ```
269
+
270
+ ```typescript
271
+ // app.config.ts
272
+ pillar.init({
273
+ productKey: 'your-product-key',
274
+ cards: {
275
+ invite_member: InviteCardComponent,
276
+ },
277
+ });
278
+ ```
279
+
280
+ ### Theme Synchronization
281
+
282
+ Sync Pillar's theme with your app's dark mode:
283
+
284
+ ```typescript
285
+ @Component({...})
286
+ export class ThemeToggleComponent {
287
+ private pillar = injectPillar();
288
+
289
+ toggleDarkMode(isDark: boolean) {
290
+ this.pillar.setTheme({ mode: isDark ? 'dark' : 'light' });
291
+ }
292
+ }
293
+ ```
294
+
295
+ ### Subscribe to Events
296
+
297
+ ```typescript
298
+ @Component({...})
299
+ export class AnalyticsComponent implements OnInit, OnDestroy {
300
+ private pillar = injectPillar();
301
+ private unsubscribes: (() => void)[] = [];
302
+
303
+ ngOnInit() {
304
+ this.unsubscribes.push(
305
+ this.pillar.on('panel:open', () => {
306
+ analytics.track('help_panel_opened');
307
+ }),
308
+ this.pillar.on('task:execute', (task) => {
309
+ analytics.track('task_executed', { name: task.name });
310
+ })
311
+ );
312
+ }
313
+
314
+ ngOnDestroy() {
315
+ this.unsubscribes.forEach(unsub => unsub());
316
+ }
317
+ }
318
+ ```
319
+
320
+ ## Configuration Options
321
+
322
+ ```typescript
323
+ interface PillarInitConfig {
324
+ /** Your product key from app.trypillar.com */
325
+ productKey: string;
326
+
327
+ /** Additional SDK configuration */
328
+ config?: {
329
+ panel?: {
330
+ /** Panel placement: 'auto' | 'manual' */
331
+ container?: string;
332
+ /** Use Shadow DOM for style isolation */
333
+ useShadowDOM?: boolean;
334
+ };
335
+ theme?: {
336
+ /** Theme mode: 'light' | 'dark' | 'auto' */
337
+ mode?: string;
338
+ /** Custom colors */
339
+ colors?: {
340
+ primary?: string;
341
+ // ... other color options
342
+ };
343
+ };
344
+ // ... other options
345
+ };
346
+
347
+ /** Global task handler */
348
+ onTask?: (task: TaskExecutePayload) => void;
349
+
350
+ /** Custom card components */
351
+ cards?: Record<string, Type<any>>;
352
+ }
353
+ ```
354
+
355
+ ## License
356
+
357
+ MIT
@@ -0,0 +1,59 @@
1
+ /**
2
+ * injectHelpPanel Function
3
+ * Angular injection helper for panel-specific controls
4
+ */
5
+ import { inject, computed } from '@angular/core';
6
+ import { PillarService } from './pillar.service';
7
+ /**
8
+ * Angular injection function for panel-specific controls.
9
+ * Provides a simplified API focused on panel operations.
10
+ *
11
+ * Must be called within an injection context (constructor, field initializer, or inject()).
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * @Component({
16
+ * selector: 'app-help-menu',
17
+ * standalone: true,
18
+ * template: `
19
+ * <div>
20
+ * <button (click)="toggle()">
21
+ * {{ isOpen() ? 'Close' : 'Help' }}
22
+ * </button>
23
+ * <button (click)="openChat()">Ask AI</button>
24
+ * </div>
25
+ * `,
26
+ * })
27
+ * export class HelpMenuComponent {
28
+ * private panel = injectHelpPanel();
29
+ * isOpen = this.panel.isOpen;
30
+ * toggle = this.panel.toggle;
31
+ * openChat = this.panel.openChat;
32
+ * }
33
+ * ```
34
+ */
35
+ export function injectHelpPanel() {
36
+ const service = inject(PillarService);
37
+ const openSearch = (query) => {
38
+ if (query) {
39
+ service.search(query);
40
+ }
41
+ else {
42
+ service.open({ view: 'search' });
43
+ }
44
+ };
45
+ const openChat = () => {
46
+ service.navigate('chat');
47
+ };
48
+ return {
49
+ isOpen: computed(() => service.isPanelOpen()),
50
+ open: service.open.bind(service),
51
+ close: service.close.bind(service),
52
+ toggle: service.toggle.bind(service),
53
+ openArticle: service.openArticle.bind(service),
54
+ openCategory: service.openCategory.bind(service),
55
+ openSearch,
56
+ openChat,
57
+ };
58
+ }
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0LWhlbHAtcGFuZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2luamVjdC1oZWxwLXBhbmVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUdqRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBQ0gsTUFBTSxVQUFVLGVBQWU7SUFDN0IsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBRXRDLE1BQU0sVUFBVSxHQUFHLENBQUMsS0FBYyxFQUFRLEVBQUU7UUFDMUMsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEIsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUMsQ0FBQztJQUVGLE1BQU0sUUFBUSxHQUFHLEdBQVMsRUFBRTtRQUMxQixPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzNCLENBQUMsQ0FBQztJQUVGLE9BQU87UUFDTCxNQUFNLEVBQUUsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUM3QyxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQ2hDLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDbEMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUNwQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQzlDLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDaEQsVUFBVTtRQUNWLFFBQVE7S0FDVCxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogaW5qZWN0SGVscFBhbmVsIEZ1bmN0aW9uXG4gKiBBbmd1bGFyIGluamVjdGlvbiBoZWxwZXIgZm9yIHBhbmVsLXNwZWNpZmljIGNvbnRyb2xzXG4gKi9cblxuaW1wb3J0IHsgaW5qZWN0LCBjb21wdXRlZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUGlsbGFyU2VydmljZSB9IGZyb20gJy4vcGlsbGFyLnNlcnZpY2UnO1xuaW1wb3J0IHR5cGUgeyBJbmplY3RIZWxwUGFuZWxSZXN1bHQgfSBmcm9tICcuL3R5cGVzJztcblxuLyoqXG4gKiBBbmd1bGFyIGluamVjdGlvbiBmdW5jdGlvbiBmb3IgcGFuZWwtc3BlY2lmaWMgY29udHJvbHMuXG4gKiBQcm92aWRlcyBhIHNpbXBsaWZpZWQgQVBJIGZvY3VzZWQgb24gcGFuZWwgb3BlcmF0aW9ucy5cbiAqXG4gKiBNdXN0IGJlIGNhbGxlZCB3aXRoaW4gYW4gaW5qZWN0aW9uIGNvbnRleHQgKGNvbnN0cnVjdG9yLCBmaWVsZCBpbml0aWFsaXplciwgb3IgaW5qZWN0KCkpLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBAQ29tcG9uZW50KHtcbiAqICAgc2VsZWN0b3I6ICdhcHAtaGVscC1tZW51JyxcbiAqICAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAqICAgdGVtcGxhdGU6IGBcbiAqICAgICA8ZGl2PlxuICogICAgICAgPGJ1dHRvbiAoY2xpY2spPVwidG9nZ2xlKClcIj5cbiAqICAgICAgICAge3sgaXNPcGVuKCkgPyAnQ2xvc2UnIDogJ0hlbHAnIH19XG4gKiAgICAgICA8L2J1dHRvbj5cbiAqICAgICAgIDxidXR0b24gKGNsaWNrKT1cIm9wZW5DaGF0KClcIj5Bc2sgQUk8L2J1dHRvbj5cbiAqICAgICA8L2Rpdj5cbiAqICAgYCxcbiAqIH0pXG4gKiBleHBvcnQgY2xhc3MgSGVscE1lbnVDb21wb25lbnQge1xuICogICBwcml2YXRlIHBhbmVsID0gaW5qZWN0SGVscFBhbmVsKCk7XG4gKiAgIGlzT3BlbiA9IHRoaXMucGFuZWwuaXNPcGVuO1xuICogICB0b2dnbGUgPSB0aGlzLnBhbmVsLnRvZ2dsZTtcbiAqICAgb3BlbkNoYXQgPSB0aGlzLnBhbmVsLm9wZW5DaGF0O1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbmplY3RIZWxwUGFuZWwoKTogSW5qZWN0SGVscFBhbmVsUmVzdWx0IHtcbiAgY29uc3Qgc2VydmljZSA9IGluamVjdChQaWxsYXJTZXJ2aWNlKTtcblxuICBjb25zdCBvcGVuU2VhcmNoID0gKHF1ZXJ5Pzogc3RyaW5nKTogdm9pZCA9PiB7XG4gICAgaWYgKHF1ZXJ5KSB7XG4gICAgICBzZXJ2aWNlLnNlYXJjaChxdWVyeSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNlcnZpY2Uub3Blbih7IHZpZXc6ICdzZWFyY2gnIH0pO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBvcGVuQ2hhdCA9ICgpOiB2b2lkID0+IHtcbiAgICBzZXJ2aWNlLm5hdmlnYXRlKCdjaGF0Jyk7XG4gIH07XG5cbiAgcmV0dXJuIHtcbiAgICBpc09wZW46IGNvbXB1dGVkKCgpID0+IHNlcnZpY2UuaXNQYW5lbE9wZW4oKSksXG4gICAgb3Blbjogc2VydmljZS5vcGVuLmJpbmQoc2VydmljZSksXG4gICAgY2xvc2U6IHNlcnZpY2UuY2xvc2UuYmluZChzZXJ2aWNlKSxcbiAgICB0b2dnbGU6IHNlcnZpY2UudG9nZ2xlLmJpbmQoc2VydmljZSksXG4gICAgb3BlbkFydGljbGU6IHNlcnZpY2Uub3BlbkFydGljbGUuYmluZChzZXJ2aWNlKSxcbiAgICBvcGVuQ2F0ZWdvcnk6IHNlcnZpY2Uub3BlbkNhdGVnb3J5LmJpbmQoc2VydmljZSksXG4gICAgb3BlblNlYXJjaCxcbiAgICBvcGVuQ2hhdCxcbiAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,111 @@
1
+ /**
2
+ * injectPillarTool Function
3
+ * Angular-idiomatic injection helper for registering Pillar tools
4
+ *
5
+ * Register one or more tools with co-located metadata and handlers.
6
+ * Tools are registered when called and automatically unregistered
7
+ * when the component is destroyed.
8
+ *
9
+ * @example Single tool
10
+ * ```typescript
11
+ * import { Component } from '@angular/core';
12
+ * import { injectPillarTool } from '@pillar-ai/angular';
13
+ *
14
+ * @Component({
15
+ * selector: 'app-cart-button',
16
+ * standalone: true,
17
+ * template: `<button>Cart</button>`,
18
+ * })
19
+ * export class CartButtonComponent {
20
+ * constructor() {
21
+ * injectPillarTool({
22
+ * name: 'add_to_cart',
23
+ * description: 'Add a product to the shopping cart',
24
+ * inputSchema: {
25
+ * type: 'object',
26
+ * properties: {
27
+ * productId: { type: 'string', description: 'Product ID' },
28
+ * quantity: { type: 'number', description: 'Quantity to add' },
29
+ * },
30
+ * required: ['productId', 'quantity'],
31
+ * },
32
+ * execute: async ({ productId, quantity }) => {
33
+ * await cartApi.add(productId, quantity);
34
+ * return { content: [{ type: 'text', text: 'Added to cart' }] };
35
+ * },
36
+ * });
37
+ * }
38
+ * }
39
+ * ```
40
+ *
41
+ * @example Multiple tools
42
+ * ```typescript
43
+ * import { Component } from '@angular/core';
44
+ * import { injectPillarTool } from '@pillar-ai/angular';
45
+ *
46
+ * @Component({
47
+ * selector: 'app-billing-page',
48
+ * standalone: true,
49
+ * template: `<div>Billing Content</div>`,
50
+ * })
51
+ * export class BillingPageComponent {
52
+ * constructor() {
53
+ * injectPillarTool([
54
+ * {
55
+ * name: 'get_current_plan',
56
+ * description: 'Get the current billing plan',
57
+ * execute: async () => ({ plan: 'pro', price: 29 }),
58
+ * },
59
+ * {
60
+ * name: 'upgrade_plan',
61
+ * description: 'Upgrade to a higher plan',
62
+ * inputSchema: {
63
+ * type: 'object',
64
+ * properties: { planId: { type: 'string' } },
65
+ * required: ['planId'],
66
+ * },
67
+ * execute: async ({ planId }) => {
68
+ * await billingApi.upgrade(planId);
69
+ * return { content: [{ type: 'text', text: 'Upgraded!' }] };
70
+ * },
71
+ * },
72
+ * ]);
73
+ * }
74
+ * }
75
+ * ```
76
+ */
77
+ import { inject, DestroyRef } from '@angular/core';
78
+ import { PillarService } from './pillar.service';
79
+ /**
80
+ * Register one or more Pillar tools with co-located metadata and handlers.
81
+ *
82
+ * The tools are registered when this function is called and automatically
83
+ * unregistered when the component is destroyed. Must be called within
84
+ * an injection context (constructor, field initializer, or inject()).
85
+ *
86
+ * @param schemaOrSchemas - Single tool schema or array of tool schemas
87
+ */
88
+ export function injectPillarTool(
89
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
+ schemaOrSchemas) {
91
+ const service = inject(PillarService);
92
+ const destroyRef = inject(DestroyRef);
93
+ // Normalize to array for consistent handling
94
+ const schemas = Array.isArray(schemaOrSchemas)
95
+ ? schemaOrSchemas
96
+ : [schemaOrSchemas];
97
+ // Track unsubscribe functions
98
+ const unsubscribes = [];
99
+ // Register all tools
100
+ schemas.forEach((schema) => {
101
+ const unsub = service.defineTool(schema);
102
+ unsubscribes.push(unsub);
103
+ });
104
+ // Cleanup on destroy
105
+ destroyRef.onDestroy(() => {
106
+ unsubscribes.forEach((unsub) => unsub());
107
+ });
108
+ }
109
+ /** @deprecated Use injectPillarTool instead */
110
+ export const injectPillarAction = injectPillarTool;
111
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0LXBpbGxhci10b29sLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9pbmplY3QtcGlsbGFyLXRvb2wudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJFRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRW5ELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVqRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxnQkFBZ0I7QUFDOUIsOERBQThEO0FBQzlELGVBQW9EO0lBRXBELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN0QyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7SUFFdEMsNkNBQTZDO0lBQzdDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDO1FBQzVDLENBQUMsQ0FBQyxlQUFlO1FBQ2pCLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBRXRCLDhCQUE4QjtJQUM5QixNQUFNLFlBQVksR0FBc0IsRUFBRSxDQUFDO0lBRTNDLHFCQUFxQjtJQUNyQixPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7UUFDekIsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN6QyxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNCLENBQUMsQ0FBQyxDQUFDO0lBRUgscUJBQXFCO0lBQ3JCLFVBQVUsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1FBQ3hCLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDM0MsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsK0NBQStDO0FBQy9DLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLGdCQUFnQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBpbmplY3RQaWxsYXJUb29sIEZ1bmN0aW9uXG4gKiBBbmd1bGFyLWlkaW9tYXRpYyBpbmplY3Rpb24gaGVscGVyIGZvciByZWdpc3RlcmluZyBQaWxsYXIgdG9vbHNcbiAqXG4gKiBSZWdpc3RlciBvbmUgb3IgbW9yZSB0b29scyB3aXRoIGNvLWxvY2F0ZWQgbWV0YWRhdGEgYW5kIGhhbmRsZXJzLlxuICogVG9vbHMgYXJlIHJlZ2lzdGVyZWQgd2hlbiBjYWxsZWQgYW5kIGF1dG9tYXRpY2FsbHkgdW5yZWdpc3RlcmVkXG4gKiB3aGVuIHRoZSBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICpcbiAqIEBleGFtcGxlIFNpbmdsZSB0b29sXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbiAqIGltcG9ydCB7IGluamVjdFBpbGxhclRvb2wgfSBmcm9tICdAcGlsbGFyLWFpL2FuZ3VsYXInO1xuICpcbiAqIEBDb21wb25lbnQoe1xuICogICBzZWxlY3RvcjogJ2FwcC1jYXJ0LWJ1dHRvbicsXG4gKiAgIHN0YW5kYWxvbmU6IHRydWUsXG4gKiAgIHRlbXBsYXRlOiBgPGJ1dHRvbj5DYXJ0PC9idXR0b24+YCxcbiAqIH0pXG4gKiBleHBvcnQgY2xhc3MgQ2FydEJ1dHRvbkNvbXBvbmVudCB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIGluamVjdFBpbGxhclRvb2woe1xuICogICAgICAgbmFtZTogJ2FkZF90b19jYXJ0JyxcbiAqICAgICAgIGRlc2NyaXB0aW9uOiAnQWRkIGEgcHJvZHVjdCB0byB0aGUgc2hvcHBpbmcgY2FydCcsXG4gKiAgICAgICBpbnB1dFNjaGVtYToge1xuICogICAgICAgICB0eXBlOiAnb2JqZWN0JyxcbiAqICAgICAgICAgcHJvcGVydGllczoge1xuICogICAgICAgICAgIHByb2R1Y3RJZDogeyB0eXBlOiAnc3RyaW5nJywgZGVzY3JpcHRpb246ICdQcm9kdWN0IElEJyB9LFxuICogICAgICAgICAgIHF1YW50aXR5OiB7IHR5cGU6ICdudW1iZXInLCBkZXNjcmlwdGlvbjogJ1F1YW50aXR5IHRvIGFkZCcgfSxcbiAqICAgICAgICAgfSxcbiAqICAgICAgICAgcmVxdWlyZWQ6IFsncHJvZHVjdElkJywgJ3F1YW50aXR5J10sXG4gKiAgICAgICB9LFxuICogICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgcHJvZHVjdElkLCBxdWFudGl0eSB9KSA9PiB7XG4gKiAgICAgICAgIGF3YWl0IGNhcnRBcGkuYWRkKHByb2R1Y3RJZCwgcXVhbnRpdHkpO1xuICogICAgICAgICByZXR1cm4geyBjb250ZW50OiBbeyB0eXBlOiAndGV4dCcsIHRleHQ6ICdBZGRlZCB0byBjYXJ0JyB9XSB9O1xuICogICAgICAgfSxcbiAqICAgICB9KTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKlxuICogQGV4YW1wbGUgTXVsdGlwbGUgdG9vbHNcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuICogaW1wb3J0IHsgaW5qZWN0UGlsbGFyVG9vbCB9IGZyb20gJ0BwaWxsYXItYWkvYW5ndWxhcic7XG4gKlxuICogQENvbXBvbmVudCh7XG4gKiAgIHNlbGVjdG9yOiAnYXBwLWJpbGxpbmctcGFnZScsXG4gKiAgIHN0YW5kYWxvbmU6IHRydWUsXG4gKiAgIHRlbXBsYXRlOiBgPGRpdj5CaWxsaW5nIENvbnRlbnQ8L2Rpdj5gLFxuICogfSlcbiAqIGV4cG9ydCBjbGFzcyBCaWxsaW5nUGFnZUNvbXBvbmVudCB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIGluamVjdFBpbGxhclRvb2woW1xuICogICAgICAge1xuICogICAgICAgICBuYW1lOiAnZ2V0X2N1cnJlbnRfcGxhbicsXG4gKiAgICAgICAgIGRlc2NyaXB0aW9uOiAnR2V0IHRoZSBjdXJyZW50IGJpbGxpbmcgcGxhbicsXG4gKiAgICAgICAgIGV4ZWN1dGU6IGFzeW5jICgpID0+ICh7IHBsYW46ICdwcm8nLCBwcmljZTogMjkgfSksXG4gKiAgICAgICB9LFxuICogICAgICAge1xuICogICAgICAgICBuYW1lOiAndXBncmFkZV9wbGFuJyxcbiAqICAgICAgICAgZGVzY3JpcHRpb246ICdVcGdyYWRlIHRvIGEgaGlnaGVyIHBsYW4nLFxuICogICAgICAgICBpbnB1dFNjaGVtYToge1xuICogICAgICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICogICAgICAgICAgIHByb3BlcnRpZXM6IHsgcGxhbklkOiB7IHR5cGU6ICdzdHJpbmcnIH0gfSxcbiAqICAgICAgICAgICByZXF1aXJlZDogWydwbGFuSWQnXSxcbiAqICAgICAgICAgfSxcbiAqICAgICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgcGxhbklkIH0pID0+IHtcbiAqICAgICAgICAgICBhd2FpdCBiaWxsaW5nQXBpLnVwZ3JhZGUocGxhbklkKTtcbiAqICAgICAgICAgICByZXR1cm4geyBjb250ZW50OiBbeyB0eXBlOiAndGV4dCcsIHRleHQ6ICdVcGdyYWRlZCEnIH1dIH07XG4gKiAgICAgICAgIH0sXG4gKiAgICAgICB9LFxuICogICAgIF0pO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgeyBpbmplY3QsIERlc3Ryb3lSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHsgVG9vbFNjaGVtYSB9IGZyb20gJ0BwaWxsYXItYWkvc2RrJztcbmltcG9ydCB7IFBpbGxhclNlcnZpY2UgfSBmcm9tICcuL3BpbGxhci5zZXJ2aWNlJztcblxuLyoqXG4gKiBSZWdpc3RlciBvbmUgb3IgbW9yZSBQaWxsYXIgdG9vbHMgd2l0aCBjby1sb2NhdGVkIG1ldGFkYXRhIGFuZCBoYW5kbGVycy5cbiAqXG4gKiBUaGUgdG9vbHMgYXJlIHJlZ2lzdGVyZWQgd2hlbiB0aGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBhbmQgYXV0b21hdGljYWxseVxuICogdW5yZWdpc3RlcmVkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuIE11c3QgYmUgY2FsbGVkIHdpdGhpblxuICogYW4gaW5qZWN0aW9uIGNvbnRleHQgKGNvbnN0cnVjdG9yLCBmaWVsZCBpbml0aWFsaXplciwgb3IgaW5qZWN0KCkpLlxuICpcbiAqIEBwYXJhbSBzY2hlbWFPclNjaGVtYXMgLSBTaW5nbGUgdG9vbCBzY2hlbWEgb3IgYXJyYXkgb2YgdG9vbCBzY2hlbWFzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbmplY3RQaWxsYXJUb29sKFxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxuICBzY2hlbWFPclNjaGVtYXM6IFRvb2xTY2hlbWE8YW55PiB8IFRvb2xTY2hlbWE8YW55PltdXG4pOiB2b2lkIHtcbiAgY29uc3Qgc2VydmljZSA9IGluamVjdChQaWxsYXJTZXJ2aWNlKTtcbiAgY29uc3QgZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICAvLyBOb3JtYWxpemUgdG8gYXJyYXkgZm9yIGNvbnNpc3RlbnQgaGFuZGxpbmdcbiAgY29uc3Qgc2NoZW1hcyA9IEFycmF5LmlzQXJyYXkoc2NoZW1hT3JTY2hlbWFzKVxuICAgID8gc2NoZW1hT3JTY2hlbWFzXG4gICAgOiBbc2NoZW1hT3JTY2hlbWFzXTtcblxuICAvLyBUcmFjayB1bnN1YnNjcmliZSBmdW5jdGlvbnNcbiAgY29uc3QgdW5zdWJzY3JpYmVzOiBBcnJheTwoKSA9PiB2b2lkPiA9IFtdO1xuXG4gIC8vIFJlZ2lzdGVyIGFsbCB0b29sc1xuICBzY2hlbWFzLmZvckVhY2goKHNjaGVtYSkgPT4ge1xuICAgIGNvbnN0IHVuc3ViID0gc2VydmljZS5kZWZpbmVUb29sKHNjaGVtYSk7XG4gICAgdW5zdWJzY3JpYmVzLnB1c2godW5zdWIpO1xuICB9KTtcblxuICAvLyBDbGVhbnVwIG9uIGRlc3Ryb3lcbiAgZGVzdHJveVJlZi5vbkRlc3Ryb3koKCkgPT4ge1xuICAgIHVuc3Vic2NyaWJlcy5mb3JFYWNoKCh1bnN1YikgPT4gdW5zdWIoKSk7XG4gIH0pO1xufVxuXG4vKiogQGRlcHJlY2F0ZWQgVXNlIGluamVjdFBpbGxhclRvb2wgaW5zdGVhZCAqL1xuZXhwb3J0IGNvbnN0IGluamVjdFBpbGxhckFjdGlvbiA9IGluamVjdFBpbGxhclRvb2w7XG4iXX0=
@@ -0,0 +1,79 @@
1
+ /**
2
+ * injectPillar Function
3
+ * Angular-idiomatic injection helper for accessing Pillar SDK
4
+ */
5
+ import { inject } from '@angular/core';
6
+ import { PillarService } from './pillar.service';
7
+ /**
8
+ * Angular injection function to access the Pillar SDK.
9
+ * Use this in components, directives, or services to interact with Pillar.
10
+ *
11
+ * Must be called within an injection context (constructor, field initializer, or inject()).
12
+ *
13
+ * @example Basic usage (untyped)
14
+ * ```typescript
15
+ * @Component({
16
+ * selector: 'app-help-button',
17
+ * standalone: true,
18
+ * template: `
19
+ * <button (click)="toggle()">
20
+ * {{ isPanelOpen() ? 'Close Help' : 'Get Help' }}
21
+ * </button>
22
+ * `,
23
+ * })
24
+ * export class HelpButtonComponent {
25
+ * private pillar = injectPillar();
26
+ * isPanelOpen = this.pillar.isPanelOpen;
27
+ * toggle = this.pillar.toggle;
28
+ * }
29
+ * ```
30
+ *
31
+ * @example Type-safe onTask with action definitions
32
+ * ```typescript
33
+ * import { actions } from '@/lib/pillar/actions';
34
+ *
35
+ * @Component({...})
36
+ * export class MyComponent implements OnInit, OnDestroy {
37
+ * private pillar = injectPillar<typeof actions>();
38
+ * private unsubscribe?: () => void;
39
+ *
40
+ * ngOnInit() {
41
+ * // TypeScript knows data has the correct shape
42
+ * this.unsubscribe = this.pillar.onTask('add_new_source', (data) => {
43
+ * console.log(data.url); // ✓ Typed!
44
+ * });
45
+ * }
46
+ *
47
+ * ngOnDestroy() {
48
+ * this.unsubscribe?.();
49
+ * }
50
+ * }
51
+ * ```
52
+ */
53
+ export function injectPillar() {
54
+ const service = inject(PillarService);
55
+ // Create a type-safe wrapper around pillar.onTask
56
+ const onTask = (taskName, handler) => {
57
+ // Cast handler to match the SDK's expected type
58
+ // The runtime behavior is the same, this is just for type narrowing
59
+ return service.onTask(taskName, handler);
60
+ };
61
+ return {
62
+ pillar: () => service.getInstance(),
63
+ state: service.state,
64
+ isReady: service.isReady,
65
+ isPanelOpen: service.isPanelOpen,
66
+ open: service.open.bind(service),
67
+ close: service.close.bind(service),
68
+ toggle: service.toggle.bind(service),
69
+ openArticle: service.openArticle.bind(service),
70
+ openCategory: service.openCategory.bind(service),
71
+ search: service.search.bind(service),
72
+ navigate: service.navigate.bind(service),
73
+ setTheme: service.setTheme.bind(service),
74
+ setTextSelectionEnabled: service.setTextSelectionEnabled.bind(service),
75
+ on: service.on.bind(service),
76
+ onTask,
77
+ };
78
+ }
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0LXBpbGxhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvaW5qZWN0LXBpbGxhci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBT3ZDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQWlFakQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTZDRztBQUNILE1BQU0sVUFBVSxZQUFZO0lBRzFCLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUV0QyxrREFBa0Q7SUFDbEQsTUFBTSxNQUFNLEdBQUcsQ0FDYixRQUFlLEVBQ2YsT0FBd0QsRUFDMUMsRUFBRTtRQUNoQixnREFBZ0Q7UUFDaEQsb0VBQW9FO1FBQ3BFLE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FDbkIsUUFBa0IsRUFDbEIsT0FBa0QsQ0FDbkQsQ0FBQztJQUNKLENBQUMsQ0FBQztJQUVGLE9BQU87UUFDTCxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRTtRQUNuQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7UUFDcEIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQ3hCLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztRQUNoQyxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQ2hDLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDbEMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUNwQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQzlDLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDaEQsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUNwQyxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQ3hDLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDeEMsdUJBQXVCLEVBQUUsT0FBTyxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDdEUsRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUM1QixNQUFNO0tBQ1AsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGluamVjdFBpbGxhciBGdW5jdGlvblxuICogQW5ndWxhci1pZGlvbWF0aWMgaW5qZWN0aW9uIGhlbHBlciBmb3IgYWNjZXNzaW5nIFBpbGxhciBTREtcbiAqL1xuXG5pbXBvcnQgeyBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHtcbiAgU3luY0FjdGlvbkRlZmluaXRpb25zLFxuICBBY3Rpb25EZWZpbml0aW9ucyxcbiAgQWN0aW9uRGF0YVR5cGUsXG4gIEFjdGlvbk5hbWVzLFxufSBmcm9tICdAcGlsbGFyLWFpL3Nkayc7XG5pbXBvcnQgeyBQaWxsYXJTZXJ2aWNlIH0gZnJvbSAnLi9waWxsYXIuc2VydmljZSc7XG5cbi8qKlxuICogUmVzdWx0IHR5cGUgZm9yIGluamVjdFBpbGxhciB3aXRoIHR5cGUtc2FmZSBvblRhc2suXG4gKlxuICogQHRlbXBsYXRlIFRBY3Rpb25zIC0gVGhlIGFjdGlvbiBkZWZpbml0aW9ucyBmb3IgdHlwZSBpbmZlcmVuY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbmplY3RQaWxsYXJSZXN1bHQ8XG4gIFRBY3Rpb25zIGV4dGVuZHMgU3luY0FjdGlvbkRlZmluaXRpb25zIHwgQWN0aW9uRGVmaW5pdGlvbnMgPSBTeW5jQWN0aW9uRGVmaW5pdGlvbnMsXG4+IHtcbiAgLyoqIEdldCB0aGUgUGlsbGFyIFNESyBpbnN0YW5jZSAqL1xuICBwaWxsYXI6ICgpID0+IFJldHVyblR5cGU8UGlsbGFyU2VydmljZVsnZ2V0SW5zdGFuY2UnXT47XG5cbiAgLyoqIEN1cnJlbnQgU0RLIHN0YXRlICovXG4gIHN0YXRlOiBQaWxsYXJTZXJ2aWNlWydzdGF0ZSddO1xuXG4gIC8qKiBXaGV0aGVyIHRoZSBTREsgaXMgcmVhZHkgKi9cbiAgaXNSZWFkeTogUGlsbGFyU2VydmljZVsnaXNSZWFkeSddO1xuXG4gIC8qKiBXaGV0aGVyIHRoZSBwYW5lbCBpcyBjdXJyZW50bHkgb3BlbiAqL1xuICBpc1BhbmVsT3BlbjogUGlsbGFyU2VydmljZVsnaXNQYW5lbE9wZW4nXTtcblxuICAvKiogT3BlbiB0aGUgaGVscCBwYW5lbCAqL1xuICBvcGVuOiBQaWxsYXJTZXJ2aWNlWydvcGVuJ107XG5cbiAgLyoqIENsb3NlIHRoZSBoZWxwIHBhbmVsICovXG4gIGNsb3NlOiBQaWxsYXJTZXJ2aWNlWydjbG9zZSddO1xuXG4gIC8qKiBUb2dnbGUgdGhlIGhlbHAgcGFuZWwgKi9cbiAgdG9nZ2xlOiBQaWxsYXJTZXJ2aWNlWyd0b2dnbGUnXTtcblxuICAvKiogT3BlbiBhIHNwZWNpZmljIGFydGljbGUgKi9cbiAgb3BlbkFydGljbGU6IFBpbGxhclNlcnZpY2VbJ29wZW5BcnRpY2xlJ107XG5cbiAgLyoqIE9wZW4gYSBzcGVjaWZpYyBjYXRlZ29yeSAqL1xuICBvcGVuQ2F0ZWdvcnk6IFBpbGxhclNlcnZpY2VbJ29wZW5DYXRlZ29yeSddO1xuXG4gIC8qKiBQZXJmb3JtIGEgc2VhcmNoICovXG4gIHNlYXJjaDogUGlsbGFyU2VydmljZVsnc2VhcmNoJ107XG5cbiAgLyoqIE5hdmlnYXRlIHRvIGEgc3BlY2lmaWMgdmlldyAqL1xuICBuYXZpZ2F0ZTogUGlsbGFyU2VydmljZVsnbmF2aWdhdGUnXTtcblxuICAvKiogVXBkYXRlIHRoZSBwYW5lbCB0aGVtZSBhdCBydW50aW1lICovXG4gIHNldFRoZW1lOiBQaWxsYXJTZXJ2aWNlWydzZXRUaGVtZSddO1xuXG4gIC8qKiBFbmFibGUgb3IgZGlzYWJsZSB0aGUgdGV4dCBzZWxlY3Rpb24gXCJBc2sgQUlcIiBwb3BvdmVyICovXG4gIHNldFRleHRTZWxlY3Rpb25FbmFibGVkOiBQaWxsYXJTZXJ2aWNlWydzZXRUZXh0U2VsZWN0aW9uRW5hYmxlZCddO1xuXG4gIC8qKiBTdWJzY3JpYmUgdG8gU0RLIGV2ZW50cyAqL1xuICBvbjogUGlsbGFyU2VydmljZVsnb24nXTtcblxuICAvKipcbiAgICogVHlwZS1zYWZlIHRhc2sgaGFuZGxlciByZWdpc3RyYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB0YXNrTmFtZSAtIFRoZSBhY3Rpb24gbmFtZSAoYXV0b2NvbXBsZXRlZCBmcm9tIHlvdXIgYWN0aW9ucylcbiAgICogQHBhcmFtIGhhbmRsZXIgLSBIYW5kbGVyIGZ1bmN0aW9uIHdpdGggdHlwZWQgZGF0YSBwYXJhbWV0ZXJcbiAgICogQHJldHVybnMgVW5zdWJzY3JpYmUgZnVuY3Rpb25cbiAgICovXG4gIG9uVGFzazogPFROYW1lIGV4dGVuZHMgQWN0aW9uTmFtZXM8VEFjdGlvbnM+PihcbiAgICB0YXNrTmFtZTogVE5hbWUsXG4gICAgaGFuZGxlcjogKGRhdGE6IEFjdGlvbkRhdGFUeXBlPFRBY3Rpb25zLCBUTmFtZT4pID0+IHZvaWRcbiAgKSA9PiAoKSA9PiB2b2lkO1xufVxuXG4vKipcbiAqIEFuZ3VsYXIgaW5qZWN0aW9uIGZ1bmN0aW9uIHRvIGFjY2VzcyB0aGUgUGlsbGFyIFNESy5cbiAqIFVzZSB0aGlzIGluIGNvbXBvbmVudHMsIGRpcmVjdGl2ZXMsIG9yIHNlcnZpY2VzIHRvIGludGVyYWN0IHdpdGggUGlsbGFyLlxuICpcbiAqIE11c3QgYmUgY2FsbGVkIHdpdGhpbiBhbiBpbmplY3Rpb24gY29udGV4dCAoY29uc3RydWN0b3IsIGZpZWxkIGluaXRpYWxpemVyLCBvciBpbmplY3QoKSkuXG4gKlxuICogQGV4YW1wbGUgQmFzaWMgdXNhZ2UgKHVudHlwZWQpXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBAQ29tcG9uZW50KHtcbiAqICAgc2VsZWN0b3I6ICdhcHAtaGVscC1idXR0b24nLFxuICogICBzdGFuZGFsb25lOiB0cnVlLFxuICogICB0ZW1wbGF0ZTogYFxuICogICAgIDxidXR0b24gKGNsaWNrKT1cInRvZ2dsZSgpXCI+XG4gKiAgICAgICB7eyBpc1BhbmVsT3BlbigpID8gJ0Nsb3NlIEhlbHAnIDogJ0dldCBIZWxwJyB9fVxuICogICAgIDwvYnV0dG9uPlxuICogICBgLFxuICogfSlcbiAqIGV4cG9ydCBjbGFzcyBIZWxwQnV0dG9uQ29tcG9uZW50IHtcbiAqICAgcHJpdmF0ZSBwaWxsYXIgPSBpbmplY3RQaWxsYXIoKTtcbiAqICAgaXNQYW5lbE9wZW4gPSB0aGlzLnBpbGxhci5pc1BhbmVsT3BlbjtcbiAqICAgdG9nZ2xlID0gdGhpcy5waWxsYXIudG9nZ2xlO1xuICogfVxuICogYGBgXG4gKlxuICogQGV4YW1wbGUgVHlwZS1zYWZlIG9uVGFzayB3aXRoIGFjdGlvbiBkZWZpbml0aW9uc1xuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgYWN0aW9ucyB9IGZyb20gJ0AvbGliL3BpbGxhci9hY3Rpb25zJztcbiAqXG4gKiBAQ29tcG9uZW50KHsuLi59KVxuICogZXhwb3J0IGNsYXNzIE15Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICogICBwcml2YXRlIHBpbGxhciA9IGluamVjdFBpbGxhcjx0eXBlb2YgYWN0aW9ucz4oKTtcbiAqICAgcHJpdmF0ZSB1bnN1YnNjcmliZT86ICgpID0+IHZvaWQ7XG4gKlxuICogICBuZ09uSW5pdCgpIHtcbiAqICAgICAvLyBUeXBlU2NyaXB0IGtub3dzIGRhdGEgaGFzIHRoZSBjb3JyZWN0IHNoYXBlXG4gKiAgICAgdGhpcy51bnN1YnNjcmliZSA9IHRoaXMucGlsbGFyLm9uVGFzaygnYWRkX25ld19zb3VyY2UnLCAoZGF0YSkgPT4ge1xuICogICAgICAgY29uc29sZS5sb2coZGF0YS51cmwpOyAvLyDinJMgVHlwZWQhXG4gKiAgICAgfSk7XG4gKiAgIH1cbiAqXG4gKiAgIG5nT25EZXN0cm95KCkge1xuICogICAgIHRoaXMudW5zdWJzY3JpYmU/LigpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluamVjdFBpbGxhcjxcbiAgVEFjdGlvbnMgZXh0ZW5kcyBTeW5jQWN0aW9uRGVmaW5pdGlvbnMgfCBBY3Rpb25EZWZpbml0aW9ucyA9IFN5bmNBY3Rpb25EZWZpbml0aW9ucyxcbj4oKTogSW5qZWN0UGlsbGFyUmVzdWx0PFRBY3Rpb25zPiB7XG4gIGNvbnN0IHNlcnZpY2UgPSBpbmplY3QoUGlsbGFyU2VydmljZSk7XG5cbiAgLy8gQ3JlYXRlIGEgdHlwZS1zYWZlIHdyYXBwZXIgYXJvdW5kIHBpbGxhci5vblRhc2tcbiAgY29uc3Qgb25UYXNrID0gPFROYW1lIGV4dGVuZHMgQWN0aW9uTmFtZXM8VEFjdGlvbnM+PihcbiAgICB0YXNrTmFtZTogVE5hbWUsXG4gICAgaGFuZGxlcjogKGRhdGE6IEFjdGlvbkRhdGFUeXBlPFRBY3Rpb25zLCBUTmFtZT4pID0+IHZvaWRcbiAgKTogKCgpID0+IHZvaWQpID0+IHtcbiAgICAvLyBDYXN0IGhhbmRsZXIgdG8gbWF0Y2ggdGhlIFNESydzIGV4cGVjdGVkIHR5cGVcbiAgICAvLyBUaGUgcnVudGltZSBiZWhhdmlvciBpcyB0aGUgc2FtZSwgdGhpcyBpcyBqdXN0IGZvciB0eXBlIG5hcnJvd2luZ1xuICAgIHJldHVybiBzZXJ2aWNlLm9uVGFzayhcbiAgICAgIHRhc2tOYW1lIGFzIHN0cmluZyxcbiAgICAgIGhhbmRsZXIgYXMgKGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB2b2lkXG4gICAgKTtcbiAgfTtcblxuICByZXR1cm4ge1xuICAgIHBpbGxhcjogKCkgPT4gc2VydmljZS5nZXRJbnN0YW5jZSgpLFxuICAgIHN0YXRlOiBzZXJ2aWNlLnN0YXRlLFxuICAgIGlzUmVhZHk6IHNlcnZpY2UuaXNSZWFkeSxcbiAgICBpc1BhbmVsT3Blbjogc2VydmljZS5pc1BhbmVsT3BlbixcbiAgICBvcGVuOiBzZXJ2aWNlLm9wZW4uYmluZChzZXJ2aWNlKSxcbiAgICBjbG9zZTogc2VydmljZS5jbG9zZS5iaW5kKHNlcnZpY2UpLFxuICAgIHRvZ2dsZTogc2VydmljZS50b2dnbGUuYmluZChzZXJ2aWNlKSxcbiAgICBvcGVuQXJ0aWNsZTogc2VydmljZS5vcGVuQXJ0aWNsZS5iaW5kKHNlcnZpY2UpLFxuICAgIG9wZW5DYXRlZ29yeTogc2VydmljZS5vcGVuQ2F0ZWdvcnkuYmluZChzZXJ2aWNlKSxcbiAgICBzZWFyY2g6IHNlcnZpY2Uuc2VhcmNoLmJpbmQoc2VydmljZSksXG4gICAgbmF2aWdhdGU6IHNlcnZpY2UubmF2aWdhdGUuYmluZChzZXJ2aWNlKSxcbiAgICBzZXRUaGVtZTogc2VydmljZS5zZXRUaGVtZS5iaW5kKHNlcnZpY2UpLFxuICAgIHNldFRleHRTZWxlY3Rpb25FbmFibGVkOiBzZXJ2aWNlLnNldFRleHRTZWxlY3Rpb25FbmFibGVkLmJpbmQoc2VydmljZSksXG4gICAgb246IHNlcnZpY2Uub24uYmluZChzZXJ2aWNlKSxcbiAgICBvblRhc2ssXG4gIH07XG59XG4iXX0=