@feedlog-ai/webcomponents 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,246 @@
1
+ # @feedlog-ai/webcomponents
2
+
3
+ Stencil-based web components for GitHub issue management. These are framework-agnostic web components that can be used in any JavaScript framework or vanilla HTML.
4
+
5
+ ## Features
6
+
7
+ - **Framework Agnostic**: Built with [Stencil](https://stenciljs.com/) - works with any JavaScript framework or vanilla HTML
8
+ - **Web Components Standard**: Uses Custom Elements, Shadow DOM for true encapsulation
9
+ - **GitHub Issue Management**: Complete solution for displaying and interacting with GitHub issues
10
+ - **Auto-generated Framework Bindings**: React and Vue wrappers generated automatically
11
+ - **Tree-shakeable**: Multiple output formats for optimal bundle sizes
12
+ - **TypeScript Support**: Full type safety with generated TypeScript definitions
13
+ - **Theme Support**: Built-in light/dark theme switching
14
+ - **Event System**: Custom events for upvoting, theme changes, and errors
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @feedlog-ai/webcomponents
20
+ ```
21
+
22
+ ## Components
23
+
24
+ ### FeedlogGithubIssuesClient
25
+
26
+ The main component for displaying GitHub issues with built-in SDK integration.
27
+
28
+ **Props:**
29
+
30
+ - `apiKey` (required): API key for Feedlog authentication
31
+ - `type` (optional): Filter by issue type - `'bug'` or `'enhancement'`
32
+ - `limit` (optional): Maximum issues to fetch (1-100, default: 10)
33
+ - `endpoint` (optional): Custom API endpoint
34
+ - `maxWidth` (optional): Container max width (default: `'42rem'`)
35
+ - `theme` (optional): Theme variant - `'light'` or `'dark'` (default: `'light'`)
36
+ - `showThemeToggle` (optional): Show theme toggle button (default: `true`)
37
+
38
+ **Events:**
39
+
40
+ - `feedlogUpvote`: Emitted when an issue is upvoted
41
+ - `feedlogThemeChange`: Emitted when theme changes
42
+ - `feedlogError`: Emitted on errors
43
+
44
+ ## Usage
45
+
46
+ ### Vanilla HTML
47
+
48
+ ```html
49
+ <!DOCTYPE html>
50
+ <html>
51
+ <head>
52
+ <script
53
+ type="module"
54
+ src="/node_modules/@feedlog-ai/webcomponents/dist/feedlog-toolkit/feedlog-toolkit.esm.js"
55
+ ></script>
56
+ </head>
57
+ <body>
58
+ <feedlog-github-issues-client
59
+ api-key="your-api-key"
60
+ type="bug"
61
+ limit="10"
62
+ theme="light"
63
+ max-width="42rem"
64
+ >
65
+ </feedlog-github-issues-client>
66
+
67
+ <script>
68
+ // Listen for events
69
+ const client = document.querySelector('feedlog-github-issues-client');
70
+
71
+ client.addEventListener('feedlogUpvote', event => {
72
+ console.log('Issue upvoted:', event.detail);
73
+ });
74
+
75
+ client.addEventListener('feedlogError', event => {
76
+ console.error('Error:', event.detail);
77
+ });
78
+ </script>
79
+ </body>
80
+ </html>
81
+ ```
82
+
83
+ ### React (with generated bindings)
84
+
85
+ ```tsx
86
+ import React from 'react';
87
+ import { FeedlogGithubIssuesClient } from '@feedlog-ai/webcomponents/dist/components';
88
+
89
+ function App() {
90
+ return (
91
+ <div>
92
+ <feedlog-github-issues-client
93
+ api-key="your-api-key"
94
+ type="bug"
95
+ limit={10}
96
+ theme="light"
97
+ max-width="42rem"
98
+ onFeedlogUpvote={event => {
99
+ console.log('Issue upvoted:', event.detail);
100
+ }}
101
+ onFeedlogError={event => {
102
+ console.error('Error:', event.detail);
103
+ }}
104
+ />
105
+ </div>
106
+ );
107
+ }
108
+ ```
109
+
110
+ ### Vue (with generated bindings)
111
+
112
+ ```vue
113
+ <template>
114
+ <feedlog-github-issues-client
115
+ api-key="your-api-key"
116
+ type="bug"
117
+ :limit="10"
118
+ theme="light"
119
+ max-width="42rem"
120
+ @feedlog-upvote="handleUpvote"
121
+ @feedlog-error="handleError"
122
+ >
123
+ </feedlog-github-issues-client>
124
+ </template>
125
+
126
+ <script setup lang="ts">
127
+ const handleUpvote = (event: CustomEvent) => {
128
+ console.log('Issue upvoted:', event.detail);
129
+ };
130
+
131
+ const handleError = (event: CustomEvent) => {
132
+ console.error('Error:', event.detail);
133
+ };
134
+ </script>
135
+ ```
136
+
137
+ ### Angular
138
+
139
+ ```typescript
140
+ import { Component } from '@angular/core';
141
+
142
+ @Component({
143
+ selector: 'app-root',
144
+ template: `
145
+ <feedlog-github-issues-client
146
+ api-key="your-api-key"
147
+ type="bug"
148
+ limit="10"
149
+ theme="light"
150
+ max-width="42rem"
151
+ (feedlogUpvote)="onUpvote($event)"
152
+ (feedlogError)="onError($event)"
153
+ >
154
+ </feedlog-github-issues-client>
155
+ `,
156
+ })
157
+ export class AppComponent {
158
+ onUpvote(event: CustomEvent) {
159
+ console.log('Issue upvoted:', event.detail);
160
+ }
161
+
162
+ onError(event: CustomEvent) {
163
+ console.error('Error:', event.detail);
164
+ }
165
+ }
166
+ ```
167
+
168
+ ## Other Components
169
+
170
+ The package also includes additional UI components:
171
+
172
+ - `feedlog-badge`: Label component with variant support
173
+ - `feedlog-button`: Button component with variants and sizes
174
+ - `feedlog-card`: Reusable card container component
175
+ - `feedlog-github-issues`: Issues display component (used internally by client)
176
+ - `feedlog-issues-list`: Issues list component (used internally)
177
+
178
+ ## Build Outputs
179
+
180
+ The package provides multiple build formats:
181
+
182
+ - **ESM**: `dist/feedlog-toolkit/feedlog-toolkit.esm.js` - Modern ES modules
183
+ - **CommonJS**: `dist/index.cjs.js` - Node.js compatible
184
+ - **Loader**: `loader/` - Dynamic loader for different environments
185
+
186
+ ## Events
187
+
188
+ ### feedlogUpvote
189
+
190
+ Emitted when a user upvotes or removes an upvote from an issue.
191
+
192
+ ```typescript
193
+ interface UpvoteEventDetail {
194
+ issueId: string;
195
+ upvoted: boolean; // true if added, false if removed
196
+ upvoteCount: number; // Updated total count
197
+ }
198
+ ```
199
+
200
+ ### feedlogThemeChange
201
+
202
+ Emitted when the theme is changed via the theme toggle.
203
+
204
+ ```typescript
205
+ type ThemeEventDetail = 'light' | 'dark';
206
+ ```
207
+
208
+ ### feedlogError
209
+
210
+ Emitted when an error occurs during API calls or other operations.
211
+
212
+ ```typescript
213
+ interface ErrorEventDetail {
214
+ error: string; // Error message
215
+ code?: number; // HTTP status code (if applicable)
216
+ }
217
+ ```
218
+
219
+ ## Styling
220
+
221
+ Components use Shadow DOM for encapsulation. You can style them using CSS custom properties:
222
+
223
+ ```css
224
+ feedlog-github-issues-client {
225
+ --feedlog-primary-color: #007acc;
226
+ --feedlog-border-radius: 8px;
227
+ --feedlog-font-family: 'Inter', sans-serif;
228
+ }
229
+ ```
230
+
231
+ ## Requirements
232
+
233
+ - Modern browsers with Web Components support
234
+ - ES2017+ for modern builds
235
+ - For older browsers, use the loader build
236
+
237
+ ## Browser Support
238
+
239
+ - Chrome 61+
240
+ - Firefox 63+
241
+ - Safari 11+
242
+ - Edge 79+
243
+
244
+ ## License
245
+
246
+ MIT
@@ -85,6 +85,7 @@ class FeedlogSDK {
85
85
  credentials: 'include',
86
86
  ...config,
87
87
  };
88
+ this.apiKey = this.config.apiKey;
88
89
  this.endpoint = this.config.endpoint || 'https://api.feedlog.app';
89
90
  this.timeout = this.config.timeout || 30000;
90
91
  // Ensure endpoint doesn't have trailing slash
@@ -187,9 +188,13 @@ class FeedlogSDK {
187
188
  * Get request headers
188
189
  */
189
190
  getAuthHeaders() {
190
- return {
191
+ const headers = {
191
192
  'Content-Type': 'application/json',
192
193
  };
194
+ if (this.apiKey) {
195
+ headers['x-api-key'] = this.apiKey;
196
+ }
197
+ return headers;
193
198
  }
194
199
  /**
195
200
  * Fetch with timeout support using AbortController
@@ -383,7 +388,6 @@ const FeedlogGithubIssuesClient = class {
383
388
  };
384
389
  }
385
390
  componentWillLoad() {
386
- this.previousRepos = this.repos;
387
391
  this.previousType = this.type;
388
392
  this.previousLimit = this.limit;
389
393
  this.initializeSDK();
@@ -391,23 +395,24 @@ const FeedlogGithubIssuesClient = class {
391
395
  }
392
396
  componentDidUpdate() {
393
397
  // Re-fetch if any props changed
394
- const reposChanged = JSON.stringify(this.previousRepos) !== JSON.stringify(this.repos);
395
398
  const typeChanged = this.previousType !== this.type;
396
399
  const limitChanged = this.previousLimit !== this.limit;
397
- if (reposChanged || typeChanged || limitChanged) {
400
+ if (typeChanged || limitChanged) {
398
401
  // Reset pagination when filters change
399
402
  this.cursor = null;
400
403
  this.hasMore = false;
401
404
  this.issues = [];
402
405
  this.fetchIssues();
403
- this.previousRepos = this.repos;
404
406
  this.previousType = this.type;
405
407
  this.previousLimit = this.limit;
406
408
  }
407
409
  }
408
410
  initializeSDK() {
409
411
  try {
410
- this.sdk = new FeedlogSDK(Object.assign({}, (this.endpoint && { endpoint: this.endpoint })));
412
+ if (!this.apiKey) {
413
+ throw new Error('API key is required for the Feedlog SDK');
414
+ }
415
+ this.sdk = new FeedlogSDK(Object.assign({ apiKey: this.apiKey }, (this.endpoint && { endpoint: this.endpoint })));
411
416
  this.error = null;
412
417
  }
413
418
  catch (err) {
@@ -416,39 +421,14 @@ const FeedlogGithubIssuesClient = class {
416
421
  this.feedlogError.emit({ error: errorMsg });
417
422
  }
418
423
  }
419
- parseRepos() {
420
- if (!this.repos) {
421
- return [];
422
- }
423
- if (typeof this.repos === 'string') {
424
- try {
425
- const parsed = JSON.parse(this.repos);
426
- return Array.isArray(parsed) ? parsed : [this.repos];
427
- }
428
- catch (_a) {
429
- // If not valid JSON, treat as single repo ID
430
- return [this.repos];
431
- }
432
- }
433
- return Array.isArray(this.repos) ? this.repos : [];
434
- }
435
424
  async fetchIssues() {
436
425
  if (!this.sdk) {
437
426
  return;
438
427
  }
439
- const repos = this.parseRepos();
440
- if (repos.length === 0) {
441
- this.error = 'At least one repository is required';
442
- this.loading = false;
443
- this.feedlogError.emit({ error: 'At least one repository is required' });
444
- return;
445
- }
446
428
  try {
447
429
  this.loading = true;
448
430
  this.error = null;
449
- const params = {
450
- repositoryIds: repos,
451
- };
431
+ const params = {};
452
432
  if (this.type) {
453
433
  params.type = this.type;
454
434
  }
@@ -483,10 +463,7 @@ const FeedlogGithubIssuesClient = class {
483
463
  }
484
464
  this.isLoadingMore = true;
485
465
  try {
486
- const repos = this.parseRepos();
487
- const params = {
488
- repositoryIds: repos,
489
- };
466
+ const params = {};
490
467
  if (this.type) {
491
468
  params.type = this.type;
492
469
  }
@@ -513,7 +490,7 @@ const FeedlogGithubIssuesClient = class {
513
490
  }
514
491
  }
515
492
  render() {
516
- return (index.h("feedlog-github-issues", { key: '38b9e7ec8a5473acbab39df1d0476fcb357866bf', issues: this.issues, maxWidth: this.maxWidth, theme: this.theme, showThemeToggle: this.showThemeToggle, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogThemeChange: this.handleThemeChange, onFeedlogLoadMore: async () => this.loadMore() }));
493
+ return (index.h("feedlog-github-issues", { key: '2c35408db4c6f52927112f8b07c03883238d5e8d', issues: this.issues, maxWidth: this.maxWidth, theme: this.theme, showThemeToggle: this.showThemeToggle, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogThemeChange: this.handleThemeChange, onFeedlogLoadMore: async () => this.loadMore() }));
517
494
  }
518
495
  };
519
496
 
@@ -18,7 +18,7 @@ var patchBrowser = () => {
18
18
 
19
19
  patchBrowser().then(async (options) => {
20
20
  await index.globalScripts();
21
- return index.bootstrapLazy([["feedlog-card.cjs",[[257,"feedlog-card"]]],["feedlog-badge_3.cjs",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues.cjs",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client.cjs",[[1,"feedlog-github-issues-client",{"repos":[1],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
21
+ return index.bootstrapLazy([["feedlog-card.cjs",[[257,"feedlog-card"]]],["feedlog-badge_3.cjs",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues.cjs",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client.cjs",[[1,"feedlog-github-issues-client",{"apiKey":[1,"api-key"],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
22
22
  });
23
23
 
24
24
  exports.setNonce = index.setNonce;
@@ -5,7 +5,7 @@ var index = require('./index-5lluu_3h.js');
5
5
  const defineCustomElements = async (win, options) => {
6
6
  if (typeof window === 'undefined') return undefined;
7
7
  await index.globalScripts();
8
- return index.bootstrapLazy([["feedlog-card.cjs",[[257,"feedlog-card"]]],["feedlog-badge_3.cjs",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues.cjs",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client.cjs",[[1,"feedlog-github-issues-client",{"repos":[1],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
8
+ return index.bootstrapLazy([["feedlog-card.cjs",[[257,"feedlog-card"]]],["feedlog-badge_3.cjs",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues.cjs",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client.cjs",[[1,"feedlog-github-issues-client",{"apiKey":[1,"api-key"],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
9
9
  };
10
10
 
11
11
  exports.setNonce = index.setNonce;
@@ -60,7 +60,6 @@ export class FeedlogGithubIssuesClient {
60
60
  };
61
61
  }
62
62
  componentWillLoad() {
63
- this.previousRepos = this.repos;
64
63
  this.previousType = this.type;
65
64
  this.previousLimit = this.limit;
66
65
  this.initializeSDK();
@@ -68,23 +67,24 @@ export class FeedlogGithubIssuesClient {
68
67
  }
69
68
  componentDidUpdate() {
70
69
  // Re-fetch if any props changed
71
- const reposChanged = JSON.stringify(this.previousRepos) !== JSON.stringify(this.repos);
72
70
  const typeChanged = this.previousType !== this.type;
73
71
  const limitChanged = this.previousLimit !== this.limit;
74
- if (reposChanged || typeChanged || limitChanged) {
72
+ if (typeChanged || limitChanged) {
75
73
  // Reset pagination when filters change
76
74
  this.cursor = null;
77
75
  this.hasMore = false;
78
76
  this.issues = [];
79
77
  this.fetchIssues();
80
- this.previousRepos = this.repos;
81
78
  this.previousType = this.type;
82
79
  this.previousLimit = this.limit;
83
80
  }
84
81
  }
85
82
  initializeSDK() {
86
83
  try {
87
- this.sdk = new FeedlogSDK(Object.assign({}, (this.endpoint && { endpoint: this.endpoint })));
84
+ if (!this.apiKey) {
85
+ throw new Error('API key is required for the Feedlog SDK');
86
+ }
87
+ this.sdk = new FeedlogSDK(Object.assign({ apiKey: this.apiKey }, (this.endpoint && { endpoint: this.endpoint })));
88
88
  this.error = null;
89
89
  }
90
90
  catch (err) {
@@ -93,39 +93,14 @@ export class FeedlogGithubIssuesClient {
93
93
  this.feedlogError.emit({ error: errorMsg });
94
94
  }
95
95
  }
96
- parseRepos() {
97
- if (!this.repos) {
98
- return [];
99
- }
100
- if (typeof this.repos === 'string') {
101
- try {
102
- const parsed = JSON.parse(this.repos);
103
- return Array.isArray(parsed) ? parsed : [this.repos];
104
- }
105
- catch (_a) {
106
- // If not valid JSON, treat as single repo ID
107
- return [this.repos];
108
- }
109
- }
110
- return Array.isArray(this.repos) ? this.repos : [];
111
- }
112
96
  async fetchIssues() {
113
97
  if (!this.sdk) {
114
98
  return;
115
99
  }
116
- const repos = this.parseRepos();
117
- if (repos.length === 0) {
118
- this.error = 'At least one repository is required';
119
- this.loading = false;
120
- this.feedlogError.emit({ error: 'At least one repository is required' });
121
- return;
122
- }
123
100
  try {
124
101
  this.loading = true;
125
102
  this.error = null;
126
- const params = {
127
- repositoryIds: repos,
128
- };
103
+ const params = {};
129
104
  if (this.type) {
130
105
  params.type = this.type;
131
106
  }
@@ -160,10 +135,7 @@ export class FeedlogGithubIssuesClient {
160
135
  }
161
136
  this.isLoadingMore = true;
162
137
  try {
163
- const repos = this.parseRepos();
164
- const params = {
165
- repositoryIds: repos,
166
- };
138
+ const params = {};
167
139
  if (this.type) {
168
140
  params.type = this.type;
169
141
  }
@@ -190,30 +162,30 @@ export class FeedlogGithubIssuesClient {
190
162
  }
191
163
  }
192
164
  render() {
193
- return (h("feedlog-github-issues", { key: '38b9e7ec8a5473acbab39df1d0476fcb357866bf', issues: this.issues, maxWidth: this.maxWidth, theme: this.theme, showThemeToggle: this.showThemeToggle, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogThemeChange: this.handleThemeChange, onFeedlogLoadMore: async () => this.loadMore() }));
165
+ return (h("feedlog-github-issues", { key: '2c35408db4c6f52927112f8b07c03883238d5e8d', issues: this.issues, maxWidth: this.maxWidth, theme: this.theme, showThemeToggle: this.showThemeToggle, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogThemeChange: this.handleThemeChange, onFeedlogLoadMore: async () => this.loadMore() }));
194
166
  }
195
167
  static get is() { return "feedlog-github-issues-client"; }
196
168
  static get encapsulation() { return "shadow"; }
197
169
  static get properties() {
198
170
  return {
199
- "repos": {
171
+ "apiKey": {
200
172
  "type": "string",
201
173
  "mutable": false,
202
174
  "complexType": {
203
- "original": "string[] | string",
204
- "resolved": "string | string[] | undefined",
175
+ "original": "string",
176
+ "resolved": "string",
205
177
  "references": {}
206
178
  },
207
- "required": false,
208
- "optional": true,
179
+ "required": true,
180
+ "optional": false,
209
181
  "docs": {
210
182
  "tags": [],
211
- "text": "Array of repository public IDs or single ID\nFormat: repository public ID (not owner/repo)"
183
+ "text": "API key for Feedlog authentication (required)\nThe API key determines which repositories' issues are fetched"
212
184
  },
213
185
  "getter": false,
214
186
  "setter": false,
215
187
  "reflect": false,
216
- "attribute": "repos"
188
+ "attribute": "api-key"
217
189
  },
218
190
  "type": {
219
191
  "type": "string",
@@ -1 +1 @@
1
- import{t,p as e,H as s,c as i,h as o}from"./index.js";import{d as r}from"./p-CHtSMTyP.js";import{d as n}from"./p-DMdb-G26.js";import{d as h}from"./p-CPOiBAxu.js";import{d as a}from"./p-DMcNh5Ys.js";function u(t){if("string"!=typeof t)return"";let e=t.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");return e=e.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi,""),e=e.replace(/\s*on\w+\s*=\s*[^\s>]*/gi,""),e=e.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,""),e=e.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,""),e=e.replace(/<(embed|object)\b[^<]*>/gi,""),e=e.replace(/javascript:/gi,""),e=e.replace(/data:(?!image\/(?:png|jpg|jpeg|gif|webp);)/gi,""),e}class c extends Error{constructor(t,e,s){super(t),this.statusCode=e,this.originalError=s,this.name="FeedlogError",Object.setPrototypeOf(this,c.prototype)}}class d extends c{constructor(t){super(t),this.name="FeedlogValidationError",Object.setPrototypeOf(this,d.prototype)}}class l extends c{constructor(t,e,s){super(t,e,s),this.name="FeedlogNetworkError",Object.setPrototypeOf(this,l.prototype)}}class p extends c{constructor(t="Request timed out"){super(t),this.name="FeedlogTimeoutError",Object.setPrototypeOf(this,p.prototype)}}class f{constructor(t={}){this.config={credentials:"include",...t},this.endpoint=this.config.endpoint||"https://api.feedlog.app",this.timeout=this.config.timeout||3e4,this.endpoint=this.endpoint.replace(/\/$/,"")}async fetchIssues(t={}){try{const e=this.buildIssuesUrl(t),s=await this.fetchWithTimeout(e,{method:"GET",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(!s.ok)throw new l("Failed to fetch issues: "+s.statusText,s.status);const i=await s.json();return this.validateIssuesResponse(i)}catch(t){if(t instanceof c)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new l("Network error: Unable to reach API",void 0,t);throw new c("Failed to fetch issues: "+(t instanceof Error?t.message:"Unknown error"),void 0,t)}}async toggleUpvote(t){if(!t||"string"!=typeof t)throw new d("Issue ID is required");try{const e=`${this.endpoint}/api/issues/${encodeURIComponent(t)}/upvote`,s=await this.fetchWithTimeout(e,{method:"POST",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(404===s.status)throw new l("Issue not found",404);if(401===s.status)throw new l("Unauthorized",401);if(403===s.status)throw new l("Forbidden: Domain not allowed for this repository",403);if(!s.ok)throw new l("Failed to toggle upvote: "+s.statusText,s.status);const i=await s.json();return this.validateUpvoteResponse(i)}catch(t){if(t instanceof c)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new l("Network error: Unable to reach API",void 0,t);throw new c("Failed to toggle upvote: "+(t instanceof Error?t.message:"Unknown error"),void 0,t)}}buildIssuesUrl(t){const e=new URL(this.endpoint+"/api/issues");if(t.repositoryIds){const s=Array.isArray(t.repositoryIds)?t.repositoryIds:[t.repositoryIds];for(const t of s)e.searchParams.append("repositoryIds",t)}return t.type&&e.searchParams.set("type",t.type),t.cursor&&e.searchParams.set("cursor",t.cursor),void 0!==t.limit&&e.searchParams.set("limit",""+t.limit),""+e}getAuthHeaders(){return{"Content-Type":"application/json"}}async fetchWithTimeout(t,e){const s=new AbortController,i=setTimeout((()=>s.abort()),this.timeout);try{const o=await fetch(t,{...e,signal:s.signal});return clearTimeout(i),o}catch(t){if(clearTimeout(i),t instanceof Error&&"AbortError"===t.name)throw new p(`Request timed out after ${this.timeout}ms`);throw t}}validateIssuesResponse(t){if(!t||"object"!=typeof t)throw new d("Invalid API response: expected object");const e=t;if(!Array.isArray(e.issues))throw new d("Invalid API response: issues must be an array");if(!e.pagination||"object"!=typeof e.pagination)throw new d("Invalid API response: pagination is required");return{issues:e.issues.map((t=>this.validateIssue(t))),pagination:{cursor:e.pagination.cursor,hasMore:!!e.pagination.hasMore}}}validateIssue(t){if(!t||"object"!=typeof t)throw new d("Invalid issue: expected object");const e=t;if("string"!=typeof e.id)throw new d("Invalid issue: id is required and must be a string");if("string"!=typeof e.title)throw new d("Invalid issue: title is required and must be a string");if(!["bug","enhancement"].includes(e.type+""))throw new d('Invalid issue: type must be "bug" or "enhancement"');if(!["open","closed"].includes(e.status+""))throw new d('Invalid issue: status must be "open" or "closed"');if(!e.repository||"object"!=typeof e.repository)throw new d("Invalid issue: repository is required");const s=e.repository;if("string"!=typeof s.id||"string"!=typeof s.name||"string"!=typeof s.owner)throw new d("Invalid issue: repository must have id, name, and owner");const i=u(e.title+""),o=u((e.body||"")+"");return{id:e.id+"",type:e.type||"bug",status:e.status||"open",pinnedAt:e.pinnedAt?e.pinnedAt+"":null,revision:Number(e.revision)||1,title:i,body:o,repository:{id:s.id+"",name:s.name+"",owner:s.owner+""},updatedAt:e.updatedAt+""||(new Date).toISOString(),createdAt:e.createdAt+""||(new Date).toISOString(),upvoteCount:Number(e.upvoteCount)||0,hasUpvoted:!!e.hasUpvoted}}validateUpvoteResponse(t){if(!t||"object"!=typeof t)throw new d("Invalid upvote response: expected object");const e=t;if("boolean"!=typeof e.upvoted)throw new d("Invalid upvote response: upvoted must be a boolean");if("number"!=typeof e.upvoteCount)throw new d("Invalid upvote response: upvoteCount must be a number");if("string"!=typeof e.anonymousUserId)throw new d("Invalid upvote response: anonymousUserId must be a string");return{upvoted:e.upvoted,upvoteCount:e.upvoteCount,anonymousUserId:e.anonymousUserId}}getEndpoint(){return this.endpoint}getTimeout(){return this.timeout}}const g=e(class extends s{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.feedlogUpvote=i(this,"feedlogUpvote"),this.feedlogThemeChange=i(this,"feedlogThemeChange"),this.feedlogError=i(this,"feedlogError"),this.maxWidth="42rem",this.theme="light",this.showThemeToggle=!0,this.issues=[],this.loading=!0,this.error=null,this.cursor=null,this.hasMore=!1,this.isLoadingMore=!1,this.sdk=null,this.handleUpvote=async t=>{if(!this.sdk)return;const{issueId:e,currentUpvoted:s,currentCount:i}=t.detail;this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:!s,upvoteCount:s?i-1:i+1}):t));try{const t=await this.sdk.toggleUpvote(e);this.issues=this.issues.map((s=>s.id===e?Object.assign(Object.assign({},s),{hasUpvoted:t.upvoted,upvoteCount:t.upvoteCount}):s)),this.feedlogUpvote.emit({issueId:e,upvoted:t.upvoted,upvoteCount:t.upvoteCount})}catch(t){this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:s,upvoteCount:i}):t)),this.feedlogError.emit({error:t instanceof Error?t.message:"Failed to toggle upvote"})}},this.handleThemeChange=t=>{this.theme=t.detail,this.feedlogThemeChange.emit(t.detail)}}componentWillLoad(){this.previousRepos=this.repos,this.previousType=this.type,this.previousLimit=this.limit,this.initializeSDK(),this.fetchIssues()}componentDidUpdate(){(JSON.stringify(this.previousRepos)!==JSON.stringify(this.repos)||this.previousType!==this.type||this.previousLimit!==this.limit)&&(this.cursor=null,this.hasMore=!1,this.issues=[],this.fetchIssues(),this.previousRepos=this.repos,this.previousType=this.type,this.previousLimit=this.limit)}initializeSDK(){try{this.sdk=new f(Object.assign({},this.endpoint&&{endpoint:this.endpoint})),this.error=null}catch(t){const e=t instanceof Error?t.message:"Failed to initialize SDK";this.error=e,this.feedlogError.emit({error:e})}}parseRepos(){if(!this.repos)return[];if("string"==typeof this.repos)try{const t=JSON.parse(this.repos);return Array.isArray(t)?t:[this.repos]}catch(t){return[this.repos]}return Array.isArray(this.repos)?this.repos:[]}async fetchIssues(){if(!this.sdk)return;const t=this.parseRepos();if(0===t.length)return this.error="At least one repository is required",this.loading=!1,void this.feedlogError.emit({error:"At least one repository is required"});try{this.loading=!0,this.error=null;const e={repositoryIds:t};this.type&&(e.type=this.type),this.limit&&(e.limit=this.limit),this.cursor&&(e.cursor=this.cursor);const s=await this.sdk.fetchIssues(e);this.issues=s.issues,this.cursor=s.pagination.cursor,this.hasMore=s.pagination.hasMore}catch(t){const e=t instanceof Error?t.message:"Failed to fetch issues";this.error=e,this.issues=[],this.feedlogError.emit({error:e,code:null==t?void 0:t.statusCode})}finally{this.loading=!1,this.isLoadingMore=!1}}async loadMore(){if(this.sdk&&this.hasMore&&!this.isLoadingMore&&!this.loading){this.isLoadingMore=!0;try{const t={repositoryIds:this.parseRepos()};this.type&&(t.type=this.type),this.limit&&(t.limit=this.limit),this.cursor&&(t.cursor=this.cursor);const e=await this.sdk.fetchIssues(t);this.issues=[...this.issues,...e.issues],this.cursor=e.pagination.cursor,this.hasMore=e.pagination.hasMore}catch(t){this.feedlogError.emit({error:t instanceof Error?t.message:"Failed to load more issues",code:null==t?void 0:t.statusCode})}finally{this.isLoadingMore=!1}}}render(){return o("feedlog-github-issues",{key:"38b9e7ec8a5473acbab39df1d0476fcb357866bf",issues:this.issues,maxWidth:this.maxWidth,theme:this.theme,showThemeToggle:this.showThemeToggle,loading:this.loading,error:this.error,hasMore:this.hasMore,isLoadingMore:this.isLoadingMore,onFeedlogUpvote:this.handleUpvote,onFeedlogThemeChange:this.handleThemeChange,onFeedlogLoadMore:async()=>this.loadMore()})}},[1,"feedlog-github-issues-client",{repos:[1],type:[1],limit:[2],endpoint:[1],maxWidth:[1,"max-width"],theme:[1],showThemeToggle:[4,"show-theme-toggle"],issues:[32],loading:[32],error:[32],cursor:[32],hasMore:[32],isLoadingMore:[32]}]);function w(){"undefined"!=typeof customElements&&["feedlog-github-issues-client","feedlog-badge","feedlog-button","feedlog-github-issues","feedlog-issues-list"].forEach((e=>{switch(e){case"feedlog-github-issues-client":customElements.get(t(e))||customElements.define(t(e),g);break;case"feedlog-badge":customElements.get(t(e))||r();break;case"feedlog-button":customElements.get(t(e))||n();break;case"feedlog-github-issues":customElements.get(t(e))||h();break;case"feedlog-issues-list":customElements.get(t(e))||a()}}))}w();const m=g,b=w;export{m as FeedlogGithubIssuesClient,b as defineCustomElement}
1
+ import{t,p as e,H as s,c as i,h as o}from"./index.js";import{d as r}from"./p-CHtSMTyP.js";import{d as n}from"./p-DMdb-G26.js";import{d as h}from"./p-CPOiBAxu.js";import{d as a}from"./p-DMcNh5Ys.js";function u(t){if("string"!=typeof t)return"";let e=t.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");return e=e.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi,""),e=e.replace(/\s*on\w+\s*=\s*[^\s>]*/gi,""),e=e.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,""),e=e.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,""),e=e.replace(/<(embed|object)\b[^<]*>/gi,""),e=e.replace(/javascript:/gi,""),e=e.replace(/data:(?!image\/(?:png|jpg|jpeg|gif|webp);)/gi,""),e}class c extends Error{constructor(t,e,s){super(t),this.statusCode=e,this.originalError=s,this.name="FeedlogError",Object.setPrototypeOf(this,c.prototype)}}class d extends c{constructor(t){super(t),this.name="FeedlogValidationError",Object.setPrototypeOf(this,d.prototype)}}class l extends c{constructor(t,e,s){super(t,e,s),this.name="FeedlogNetworkError",Object.setPrototypeOf(this,l.prototype)}}class p extends c{constructor(t="Request timed out"){super(t),this.name="FeedlogTimeoutError",Object.setPrototypeOf(this,p.prototype)}}class f{constructor(t={}){this.config={credentials:"include",...t},this.apiKey=this.config.apiKey,this.endpoint=this.config.endpoint||"https://api.feedlog.app",this.timeout=this.config.timeout||3e4,this.endpoint=this.endpoint.replace(/\/$/,"")}async fetchIssues(t={}){try{const e=this.buildIssuesUrl(t),s=await this.fetchWithTimeout(e,{method:"GET",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(!s.ok)throw new l("Failed to fetch issues: "+s.statusText,s.status);const i=await s.json();return this.validateIssuesResponse(i)}catch(t){if(t instanceof c)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new l("Network error: Unable to reach API",void 0,t);throw new c("Failed to fetch issues: "+(t instanceof Error?t.message:"Unknown error"),void 0,t)}}async toggleUpvote(t){if(!t||"string"!=typeof t)throw new d("Issue ID is required");try{const e=`${this.endpoint}/api/issues/${encodeURIComponent(t)}/upvote`,s=await this.fetchWithTimeout(e,{method:"POST",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(404===s.status)throw new l("Issue not found",404);if(401===s.status)throw new l("Unauthorized",401);if(403===s.status)throw new l("Forbidden: Domain not allowed for this repository",403);if(!s.ok)throw new l("Failed to toggle upvote: "+s.statusText,s.status);const i=await s.json();return this.validateUpvoteResponse(i)}catch(t){if(t instanceof c)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new l("Network error: Unable to reach API",void 0,t);throw new c("Failed to toggle upvote: "+(t instanceof Error?t.message:"Unknown error"),void 0,t)}}buildIssuesUrl(t){const e=new URL(this.endpoint+"/api/issues");if(t.repositoryIds){const s=Array.isArray(t.repositoryIds)?t.repositoryIds:[t.repositoryIds];for(const t of s)e.searchParams.append("repositoryIds",t)}return t.type&&e.searchParams.set("type",t.type),t.cursor&&e.searchParams.set("cursor",t.cursor),void 0!==t.limit&&e.searchParams.set("limit",""+t.limit),""+e}getAuthHeaders(){const t={"Content-Type":"application/json"};return this.apiKey&&(t["x-api-key"]=this.apiKey),t}async fetchWithTimeout(t,e){const s=new AbortController,i=setTimeout((()=>s.abort()),this.timeout);try{const o=await fetch(t,{...e,signal:s.signal});return clearTimeout(i),o}catch(t){if(clearTimeout(i),t instanceof Error&&"AbortError"===t.name)throw new p(`Request timed out after ${this.timeout}ms`);throw t}}validateIssuesResponse(t){if(!t||"object"!=typeof t)throw new d("Invalid API response: expected object");const e=t;if(!Array.isArray(e.issues))throw new d("Invalid API response: issues must be an array");if(!e.pagination||"object"!=typeof e.pagination)throw new d("Invalid API response: pagination is required");return{issues:e.issues.map((t=>this.validateIssue(t))),pagination:{cursor:e.pagination.cursor,hasMore:!!e.pagination.hasMore}}}validateIssue(t){if(!t||"object"!=typeof t)throw new d("Invalid issue: expected object");const e=t;if("string"!=typeof e.id)throw new d("Invalid issue: id is required and must be a string");if("string"!=typeof e.title)throw new d("Invalid issue: title is required and must be a string");if(!["bug","enhancement"].includes(e.type+""))throw new d('Invalid issue: type must be "bug" or "enhancement"');if(!["open","closed"].includes(e.status+""))throw new d('Invalid issue: status must be "open" or "closed"');if(!e.repository||"object"!=typeof e.repository)throw new d("Invalid issue: repository is required");const s=e.repository;if("string"!=typeof s.id||"string"!=typeof s.name||"string"!=typeof s.owner)throw new d("Invalid issue: repository must have id, name, and owner");const i=u(e.title+""),o=u((e.body||"")+"");return{id:e.id+"",type:e.type||"bug",status:e.status||"open",pinnedAt:e.pinnedAt?e.pinnedAt+"":null,revision:Number(e.revision)||1,title:i,body:o,repository:{id:s.id+"",name:s.name+"",owner:s.owner+""},updatedAt:e.updatedAt+""||(new Date).toISOString(),createdAt:e.createdAt+""||(new Date).toISOString(),upvoteCount:Number(e.upvoteCount)||0,hasUpvoted:!!e.hasUpvoted}}validateUpvoteResponse(t){if(!t||"object"!=typeof t)throw new d("Invalid upvote response: expected object");const e=t;if("boolean"!=typeof e.upvoted)throw new d("Invalid upvote response: upvoted must be a boolean");if("number"!=typeof e.upvoteCount)throw new d("Invalid upvote response: upvoteCount must be a number");if("string"!=typeof e.anonymousUserId)throw new d("Invalid upvote response: anonymousUserId must be a string");return{upvoted:e.upvoted,upvoteCount:e.upvoteCount,anonymousUserId:e.anonymousUserId}}getEndpoint(){return this.endpoint}getTimeout(){return this.timeout}}const g=e(class extends s{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.feedlogUpvote=i(this,"feedlogUpvote"),this.feedlogThemeChange=i(this,"feedlogThemeChange"),this.feedlogError=i(this,"feedlogError"),this.maxWidth="42rem",this.theme="light",this.showThemeToggle=!0,this.issues=[],this.loading=!0,this.error=null,this.cursor=null,this.hasMore=!1,this.isLoadingMore=!1,this.sdk=null,this.handleUpvote=async t=>{if(!this.sdk)return;const{issueId:e,currentUpvoted:s,currentCount:i}=t.detail;this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:!s,upvoteCount:s?i-1:i+1}):t));try{const t=await this.sdk.toggleUpvote(e);this.issues=this.issues.map((s=>s.id===e?Object.assign(Object.assign({},s),{hasUpvoted:t.upvoted,upvoteCount:t.upvoteCount}):s)),this.feedlogUpvote.emit({issueId:e,upvoted:t.upvoted,upvoteCount:t.upvoteCount})}catch(t){this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:s,upvoteCount:i}):t)),this.feedlogError.emit({error:t instanceof Error?t.message:"Failed to toggle upvote"})}},this.handleThemeChange=t=>{this.theme=t.detail,this.feedlogThemeChange.emit(t.detail)}}componentWillLoad(){this.previousType=this.type,this.previousLimit=this.limit,this.initializeSDK(),this.fetchIssues()}componentDidUpdate(){(this.previousType!==this.type||this.previousLimit!==this.limit)&&(this.cursor=null,this.hasMore=!1,this.issues=[],this.fetchIssues(),this.previousType=this.type,this.previousLimit=this.limit)}initializeSDK(){try{if(!this.apiKey)throw Error("API key is required for the Feedlog SDK");this.sdk=new f(Object.assign({apiKey:this.apiKey},this.endpoint&&{endpoint:this.endpoint})),this.error=null}catch(t){const e=t instanceof Error?t.message:"Failed to initialize SDK";this.error=e,this.feedlogError.emit({error:e})}}async fetchIssues(){if(this.sdk)try{this.loading=!0,this.error=null;const t={};this.type&&(t.type=this.type),this.limit&&(t.limit=this.limit),this.cursor&&(t.cursor=this.cursor);const e=await this.sdk.fetchIssues(t);this.issues=e.issues,this.cursor=e.pagination.cursor,this.hasMore=e.pagination.hasMore}catch(t){const e=t instanceof Error?t.message:"Failed to fetch issues";this.error=e,this.issues=[],this.feedlogError.emit({error:e,code:null==t?void 0:t.statusCode})}finally{this.loading=!1,this.isLoadingMore=!1}}async loadMore(){if(this.sdk&&this.hasMore&&!this.isLoadingMore&&!this.loading){this.isLoadingMore=!0;try{const t={};this.type&&(t.type=this.type),this.limit&&(t.limit=this.limit),this.cursor&&(t.cursor=this.cursor);const e=await this.sdk.fetchIssues(t);this.issues=[...this.issues,...e.issues],this.cursor=e.pagination.cursor,this.hasMore=e.pagination.hasMore}catch(t){this.feedlogError.emit({error:t instanceof Error?t.message:"Failed to load more issues",code:null==t?void 0:t.statusCode})}finally{this.isLoadingMore=!1}}}render(){return o("feedlog-github-issues",{key:"2c35408db4c6f52927112f8b07c03883238d5e8d",issues:this.issues,maxWidth:this.maxWidth,theme:this.theme,showThemeToggle:this.showThemeToggle,loading:this.loading,error:this.error,hasMore:this.hasMore,isLoadingMore:this.isLoadingMore,onFeedlogUpvote:this.handleUpvote,onFeedlogThemeChange:this.handleThemeChange,onFeedlogLoadMore:async()=>this.loadMore()})}},[1,"feedlog-github-issues-client",{apiKey:[1,"api-key"],type:[1],limit:[2],endpoint:[1],maxWidth:[1,"max-width"],theme:[1],showThemeToggle:[4,"show-theme-toggle"],issues:[32],loading:[32],error:[32],cursor:[32],hasMore:[32],isLoadingMore:[32]}]);function w(){"undefined"!=typeof customElements&&["feedlog-github-issues-client","feedlog-badge","feedlog-button","feedlog-github-issues","feedlog-issues-list"].forEach((e=>{switch(e){case"feedlog-github-issues-client":customElements.get(t(e))||customElements.define(t(e),g);break;case"feedlog-badge":customElements.get(t(e))||r();break;case"feedlog-button":customElements.get(t(e))||n();break;case"feedlog-github-issues":customElements.get(t(e))||h();break;case"feedlog-issues-list":customElements.get(t(e))||a()}}))}w();const m=g,b=w;export{m as FeedlogGithubIssuesClient,b as defineCustomElement}
@@ -83,6 +83,7 @@ class FeedlogSDK {
83
83
  credentials: 'include',
84
84
  ...config,
85
85
  };
86
+ this.apiKey = this.config.apiKey;
86
87
  this.endpoint = this.config.endpoint || 'https://api.feedlog.app';
87
88
  this.timeout = this.config.timeout || 30000;
88
89
  // Ensure endpoint doesn't have trailing slash
@@ -185,9 +186,13 @@ class FeedlogSDK {
185
186
  * Get request headers
186
187
  */
187
188
  getAuthHeaders() {
188
- return {
189
+ const headers = {
189
190
  'Content-Type': 'application/json',
190
191
  };
192
+ if (this.apiKey) {
193
+ headers['x-api-key'] = this.apiKey;
194
+ }
195
+ return headers;
191
196
  }
192
197
  /**
193
198
  * Fetch with timeout support using AbortController
@@ -381,7 +386,6 @@ const FeedlogGithubIssuesClient = class {
381
386
  };
382
387
  }
383
388
  componentWillLoad() {
384
- this.previousRepos = this.repos;
385
389
  this.previousType = this.type;
386
390
  this.previousLimit = this.limit;
387
391
  this.initializeSDK();
@@ -389,23 +393,24 @@ const FeedlogGithubIssuesClient = class {
389
393
  }
390
394
  componentDidUpdate() {
391
395
  // Re-fetch if any props changed
392
- const reposChanged = JSON.stringify(this.previousRepos) !== JSON.stringify(this.repos);
393
396
  const typeChanged = this.previousType !== this.type;
394
397
  const limitChanged = this.previousLimit !== this.limit;
395
- if (reposChanged || typeChanged || limitChanged) {
398
+ if (typeChanged || limitChanged) {
396
399
  // Reset pagination when filters change
397
400
  this.cursor = null;
398
401
  this.hasMore = false;
399
402
  this.issues = [];
400
403
  this.fetchIssues();
401
- this.previousRepos = this.repos;
402
404
  this.previousType = this.type;
403
405
  this.previousLimit = this.limit;
404
406
  }
405
407
  }
406
408
  initializeSDK() {
407
409
  try {
408
- this.sdk = new FeedlogSDK(Object.assign({}, (this.endpoint && { endpoint: this.endpoint })));
410
+ if (!this.apiKey) {
411
+ throw new Error('API key is required for the Feedlog SDK');
412
+ }
413
+ this.sdk = new FeedlogSDK(Object.assign({ apiKey: this.apiKey }, (this.endpoint && { endpoint: this.endpoint })));
409
414
  this.error = null;
410
415
  }
411
416
  catch (err) {
@@ -414,39 +419,14 @@ const FeedlogGithubIssuesClient = class {
414
419
  this.feedlogError.emit({ error: errorMsg });
415
420
  }
416
421
  }
417
- parseRepos() {
418
- if (!this.repos) {
419
- return [];
420
- }
421
- if (typeof this.repos === 'string') {
422
- try {
423
- const parsed = JSON.parse(this.repos);
424
- return Array.isArray(parsed) ? parsed : [this.repos];
425
- }
426
- catch (_a) {
427
- // If not valid JSON, treat as single repo ID
428
- return [this.repos];
429
- }
430
- }
431
- return Array.isArray(this.repos) ? this.repos : [];
432
- }
433
422
  async fetchIssues() {
434
423
  if (!this.sdk) {
435
424
  return;
436
425
  }
437
- const repos = this.parseRepos();
438
- if (repos.length === 0) {
439
- this.error = 'At least one repository is required';
440
- this.loading = false;
441
- this.feedlogError.emit({ error: 'At least one repository is required' });
442
- return;
443
- }
444
426
  try {
445
427
  this.loading = true;
446
428
  this.error = null;
447
- const params = {
448
- repositoryIds: repos,
449
- };
429
+ const params = {};
450
430
  if (this.type) {
451
431
  params.type = this.type;
452
432
  }
@@ -481,10 +461,7 @@ const FeedlogGithubIssuesClient = class {
481
461
  }
482
462
  this.isLoadingMore = true;
483
463
  try {
484
- const repos = this.parseRepos();
485
- const params = {
486
- repositoryIds: repos,
487
- };
464
+ const params = {};
488
465
  if (this.type) {
489
466
  params.type = this.type;
490
467
  }
@@ -511,7 +488,7 @@ const FeedlogGithubIssuesClient = class {
511
488
  }
512
489
  }
513
490
  render() {
514
- return (h("feedlog-github-issues", { key: '38b9e7ec8a5473acbab39df1d0476fcb357866bf', issues: this.issues, maxWidth: this.maxWidth, theme: this.theme, showThemeToggle: this.showThemeToggle, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogThemeChange: this.handleThemeChange, onFeedlogLoadMore: async () => this.loadMore() }));
491
+ return (h("feedlog-github-issues", { key: '2c35408db4c6f52927112f8b07c03883238d5e8d', issues: this.issues, maxWidth: this.maxWidth, theme: this.theme, showThemeToggle: this.showThemeToggle, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogThemeChange: this.handleThemeChange, onFeedlogLoadMore: async () => this.loadMore() }));
515
492
  }
516
493
  };
517
494
 
@@ -16,5 +16,5 @@ var patchBrowser = () => {
16
16
 
17
17
  patchBrowser().then(async (options) => {
18
18
  await globalScripts();
19
- return bootstrapLazy([["feedlog-card",[[257,"feedlog-card"]]],["feedlog-badge_3",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client",[[1,"feedlog-github-issues-client",{"repos":[1],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
19
+ return bootstrapLazy([["feedlog-card",[[257,"feedlog-card"]]],["feedlog-badge_3",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client",[[1,"feedlog-github-issues-client",{"apiKey":[1,"api-key"],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
20
20
  });
@@ -4,7 +4,7 @@ export { s as setNonce } from './index-CkB6Yzeb.js';
4
4
  const defineCustomElements = async (win, options) => {
5
5
  if (typeof window === 'undefined') return undefined;
6
6
  await globalScripts();
7
- return bootstrapLazy([["feedlog-card",[[257,"feedlog-card"]]],["feedlog-badge_3",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client",[[1,"feedlog-github-issues-client",{"repos":[1],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
7
+ return bootstrapLazy([["feedlog-card",[[257,"feedlog-card"]]],["feedlog-badge_3",[[1,"feedlog-issues-list",{"issues":[16],"theme":[1]}],[257,"feedlog-button",{"variant":[1],"size":[1],"disabled":[4],"type":[1]}],[257,"feedlog-badge",{"variant":[1]}]]],["feedlog-github-issues",[[1,"feedlog-github-issues",{"issues":[16],"maxWidth":[1,"max-width"],"theme":[1025],"loading":[4],"error":[1],"showThemeToggle":[4,"show-theme-toggle"],"hasMore":[4,"has-more"],"isLoadingMore":[4,"is-loading-more"],"currentTheme":[32]}]]],["feedlog-github-issues-client",[[1,"feedlog-github-issues-client",{"apiKey":[1,"api-key"],"type":[1],"limit":[2],"endpoint":[1],"maxWidth":[1,"max-width"],"theme":[1],"showThemeToggle":[4,"show-theme-toggle"],"issues":[32],"loading":[32],"error":[32],"cursor":[32],"hasMore":[32],"isLoadingMore":[32]}]]]], options);
8
8
  };
9
9
 
10
10
  export { defineCustomElements };
@@ -1 +1 @@
1
- import{p as e,g as o,b as i}from"./p-CkB6Yzeb.js";export{s as setNonce}from"./p-CkB6Yzeb.js";(()=>{const s=import.meta.url,o={};return""!==s&&(o.resourcesUrl=new URL(".",s).href),e(o)})().then((async e=>(await o(),i([["p-cdb2b098",[[257,"feedlog-card"]]],["p-2f7954f7",[[1,"feedlog-issues-list",{issues:[16],theme:[1]}],[257,"feedlog-button",{variant:[1],size:[1],disabled:[4],type:[1]}],[257,"feedlog-badge",{variant:[1]}]]],["p-b3d26272",[[1,"feedlog-github-issues",{issues:[16],maxWidth:[1,"max-width"],theme:[1025],loading:[4],error:[1],showThemeToggle:[4,"show-theme-toggle"],hasMore:[4,"has-more"],isLoadingMore:[4,"is-loading-more"],currentTheme:[32]}]]],["p-399e0281",[[1,"feedlog-github-issues-client",{repos:[1],type:[1],limit:[2],endpoint:[1],maxWidth:[1,"max-width"],theme:[1],showThemeToggle:[4,"show-theme-toggle"],issues:[32],loading:[32],error:[32],cursor:[32],hasMore:[32],isLoadingMore:[32]}]]]],e))));
1
+ import{p as e,g as o,b as i}from"./p-CkB6Yzeb.js";export{s as setNonce}from"./p-CkB6Yzeb.js";(()=>{const s=import.meta.url,o={};return""!==s&&(o.resourcesUrl=new URL(".",s).href),e(o)})().then((async e=>(await o(),i([["p-cdb2b098",[[257,"feedlog-card"]]],["p-2f7954f7",[[1,"feedlog-issues-list",{issues:[16],theme:[1]}],[257,"feedlog-button",{variant:[1],size:[1],disabled:[4],type:[1]}],[257,"feedlog-badge",{variant:[1]}]]],["p-b3d26272",[[1,"feedlog-github-issues",{issues:[16],maxWidth:[1,"max-width"],theme:[1025],loading:[4],error:[1],showThemeToggle:[4,"show-theme-toggle"],hasMore:[4,"has-more"],isLoadingMore:[4,"is-loading-more"],currentTheme:[32]}]]],["p-a01a3115",[[1,"feedlog-github-issues-client",{apiKey:[1,"api-key"],type:[1],limit:[2],endpoint:[1],maxWidth:[1,"max-width"],theme:[1],showThemeToggle:[4,"show-theme-toggle"],issues:[32],loading:[32],error:[32],cursor:[32],hasMore:[32],isLoadingMore:[32]}]]]],e))));
@@ -0,0 +1 @@
1
+ import{r as t,c as e,h as s}from"./p-CkB6Yzeb.js";function i(t){if("string"!=typeof t)return"";let e=t.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");return e=e.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi,""),e=e.replace(/\s*on\w+\s*=\s*[^\s>]*/gi,""),e=e.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,""),e=e.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,""),e=e.replace(/<(embed|object)\b[^<]*>/gi,""),e=e.replace(/javascript:/gi,""),e=e.replace(/data:(?!image\/(?:png|jpg|jpeg|gif|webp);)/gi,""),e}class o extends Error{constructor(t,e,s){super(t),this.statusCode=e,this.originalError=s,this.name="FeedlogError",Object.setPrototypeOf(this,o.prototype)}}class r extends o{constructor(t){super(t),this.name="FeedlogValidationError",Object.setPrototypeOf(this,r.prototype)}}class n extends o{constructor(t,e,s){super(t,e,s),this.name="FeedlogNetworkError",Object.setPrototypeOf(this,n.prototype)}}class h extends o{constructor(t="Request timed out"){super(t),this.name="FeedlogTimeoutError",Object.setPrototypeOf(this,h.prototype)}}class a{constructor(t={}){this.config={credentials:"include",...t},this.apiKey=this.config.apiKey,this.endpoint=this.config.endpoint||"https://api.feedlog.app",this.timeout=this.config.timeout||3e4,this.endpoint=this.endpoint.replace(/\/$/,"")}async fetchIssues(t={}){try{const e=this.buildIssuesUrl(t),s=await this.fetchWithTimeout(e,{method:"GET",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(!s.ok)throw new n(`Failed to fetch issues: ${s.statusText}`,s.status);const i=await s.json();return this.validateIssuesResponse(i)}catch(t){if(t instanceof o)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new n("Network error: Unable to reach API",void 0,t);throw new o(`Failed to fetch issues: ${t instanceof Error?t.message:"Unknown error"}`,void 0,t)}}async toggleUpvote(t){if(!t||"string"!=typeof t)throw new r("Issue ID is required");try{const e=`${this.endpoint}/api/issues/${encodeURIComponent(t)}/upvote`,s=await this.fetchWithTimeout(e,{method:"POST",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(404===s.status)throw new n("Issue not found",404);if(401===s.status)throw new n("Unauthorized",401);if(403===s.status)throw new n("Forbidden: Domain not allowed for this repository",403);if(!s.ok)throw new n(`Failed to toggle upvote: ${s.statusText}`,s.status);const i=await s.json();return this.validateUpvoteResponse(i)}catch(t){if(t instanceof o)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new n("Network error: Unable to reach API",void 0,t);throw new o(`Failed to toggle upvote: ${t instanceof Error?t.message:"Unknown error"}`,void 0,t)}}buildIssuesUrl(t){const e=new URL(`${this.endpoint}/api/issues`);if(t.repositoryIds){const s=Array.isArray(t.repositoryIds)?t.repositoryIds:[t.repositoryIds];for(const t of s)e.searchParams.append("repositoryIds",t)}return t.type&&e.searchParams.set("type",t.type),t.cursor&&e.searchParams.set("cursor",t.cursor),void 0!==t.limit&&e.searchParams.set("limit",t.limit.toString()),e.toString()}getAuthHeaders(){const t={"Content-Type":"application/json"};return this.apiKey&&(t["x-api-key"]=this.apiKey),t}async fetchWithTimeout(t,e){const s=new AbortController,i=setTimeout((()=>s.abort()),this.timeout);try{const o=await fetch(t,{...e,signal:s.signal});return clearTimeout(i),o}catch(t){if(clearTimeout(i),t instanceof Error&&"AbortError"===t.name)throw new h(`Request timed out after ${this.timeout}ms`);throw t}}validateIssuesResponse(t){if(!t||"object"!=typeof t)throw new r("Invalid API response: expected object");const e=t;if(!Array.isArray(e.issues))throw new r("Invalid API response: issues must be an array");if(!e.pagination||"object"!=typeof e.pagination)throw new r("Invalid API response: pagination is required");return{issues:e.issues.map((t=>this.validateIssue(t))),pagination:{cursor:e.pagination.cursor,hasMore:Boolean(e.pagination.hasMore)}}}validateIssue(t){if(!t||"object"!=typeof t)throw new r("Invalid issue: expected object");const e=t;if("string"!=typeof e.id)throw new r("Invalid issue: id is required and must be a string");if("string"!=typeof e.title)throw new r("Invalid issue: title is required and must be a string");if(!["bug","enhancement"].includes(String(e.type)))throw new r('Invalid issue: type must be "bug" or "enhancement"');if(!["open","closed"].includes(String(e.status)))throw new r('Invalid issue: status must be "open" or "closed"');if(!e.repository||"object"!=typeof e.repository)throw new r("Invalid issue: repository is required");const s=e.repository;if("string"!=typeof s.id||"string"!=typeof s.name||"string"!=typeof s.owner)throw new r("Invalid issue: repository must have id, name, and owner");const o=i(String(e.title)),n=i(String(e.body||""));return{id:String(e.id),type:e.type||"bug",status:e.status||"open",pinnedAt:e.pinnedAt?String(e.pinnedAt):null,revision:Number(e.revision)||1,title:o,body:n,repository:{id:String(s.id),name:String(s.name),owner:String(s.owner)},updatedAt:String(e.updatedAt)||(new Date).toISOString(),createdAt:String(e.createdAt)||(new Date).toISOString(),upvoteCount:Number(e.upvoteCount)||0,hasUpvoted:Boolean(e.hasUpvoted)}}validateUpvoteResponse(t){if(!t||"object"!=typeof t)throw new r("Invalid upvote response: expected object");const e=t;if("boolean"!=typeof e.upvoted)throw new r("Invalid upvote response: upvoted must be a boolean");if("number"!=typeof e.upvoteCount)throw new r("Invalid upvote response: upvoteCount must be a number");if("string"!=typeof e.anonymousUserId)throw new r("Invalid upvote response: anonymousUserId must be a string");return{upvoted:e.upvoted,upvoteCount:e.upvoteCount,anonymousUserId:e.anonymousUserId}}getEndpoint(){return this.endpoint}getTimeout(){return this.timeout}}const c=class{constructor(s){t(this,s),this.feedlogUpvote=e(this,"feedlogUpvote"),this.feedlogThemeChange=e(this,"feedlogThemeChange"),this.feedlogError=e(this,"feedlogError"),this.maxWidth="42rem",this.theme="light",this.showThemeToggle=!0,this.issues=[],this.loading=!0,this.error=null,this.cursor=null,this.hasMore=!1,this.isLoadingMore=!1,this.sdk=null,this.handleUpvote=async t=>{if(!this.sdk)return;const{issueId:e,currentUpvoted:s,currentCount:i}=t.detail;this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:!s,upvoteCount:s?i-1:i+1}):t));try{const t=await this.sdk.toggleUpvote(e);this.issues=this.issues.map((s=>s.id===e?Object.assign(Object.assign({},s),{hasUpvoted:t.upvoted,upvoteCount:t.upvoteCount}):s)),this.feedlogUpvote.emit({issueId:e,upvoted:t.upvoted,upvoteCount:t.upvoteCount})}catch(t){this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:s,upvoteCount:i}):t));const o=t instanceof Error?t.message:"Failed to toggle upvote";this.feedlogError.emit({error:o})}},this.handleThemeChange=t=>{this.theme=t.detail,this.feedlogThemeChange.emit(t.detail)}}componentWillLoad(){this.previousType=this.type,this.previousLimit=this.limit,this.initializeSDK(),this.fetchIssues()}componentDidUpdate(){(this.previousType!==this.type||this.previousLimit!==this.limit)&&(this.cursor=null,this.hasMore=!1,this.issues=[],this.fetchIssues(),this.previousType=this.type,this.previousLimit=this.limit)}initializeSDK(){try{if(!this.apiKey)throw new Error("API key is required for the Feedlog SDK");this.sdk=new a(Object.assign({apiKey:this.apiKey},this.endpoint&&{endpoint:this.endpoint})),this.error=null}catch(t){const e=t instanceof Error?t.message:"Failed to initialize SDK";this.error=e,this.feedlogError.emit({error:e})}}async fetchIssues(){if(this.sdk)try{this.loading=!0,this.error=null;const t={};this.type&&(t.type=this.type),this.limit&&(t.limit=this.limit),this.cursor&&(t.cursor=this.cursor);const e=await this.sdk.fetchIssues(t);this.issues=e.issues,this.cursor=e.pagination.cursor,this.hasMore=e.pagination.hasMore}catch(t){const e=t instanceof Error?t.message:"Failed to fetch issues";this.error=e,this.issues=[],this.feedlogError.emit({error:e,code:null==t?void 0:t.statusCode})}finally{this.loading=!1,this.isLoadingMore=!1}}async loadMore(){if(this.sdk&&this.hasMore&&!this.isLoadingMore&&!this.loading){this.isLoadingMore=!0;try{const t={};this.type&&(t.type=this.type),this.limit&&(t.limit=this.limit),this.cursor&&(t.cursor=this.cursor);const e=await this.sdk.fetchIssues(t);this.issues=[...this.issues,...e.issues],this.cursor=e.pagination.cursor,this.hasMore=e.pagination.hasMore}catch(t){const e=t instanceof Error?t.message:"Failed to load more issues";this.feedlogError.emit({error:e,code:null==t?void 0:t.statusCode})}finally{this.isLoadingMore=!1}}}render(){return s("feedlog-github-issues",{key:"2c35408db4c6f52927112f8b07c03883238d5e8d",issues:this.issues,maxWidth:this.maxWidth,theme:this.theme,showThemeToggle:this.showThemeToggle,loading:this.loading,error:this.error,hasMore:this.hasMore,isLoadingMore:this.isLoadingMore,onFeedlogUpvote:this.handleUpvote,onFeedlogThemeChange:this.handleThemeChange,onFeedlogLoadMore:async()=>this.loadMore()})}};export{c as feedlog_github_issues_client}
@@ -8,10 +8,10 @@ import { FeedlogIssue } from '@feedlog-ai/core';
8
8
  */
9
9
  export declare class FeedlogGithubIssuesClient {
10
10
  /**
11
- * Array of repository public IDs or single ID
12
- * Format: repository public ID (not owner/repo)
11
+ * API key for Feedlog authentication (required)
12
+ * The API key determines which repositories' issues are fetched
13
13
  */
14
- repos?: string[] | string;
14
+ apiKey: string;
15
15
  /**
16
16
  * Filter issues by type: 'bug' or 'enhancement'
17
17
  */
@@ -62,13 +62,11 @@ export declare class FeedlogGithubIssuesClient {
62
62
  hasMore: boolean;
63
63
  isLoadingMore: boolean;
64
64
  private sdk;
65
- private previousRepos?;
66
65
  private previousType?;
67
66
  private previousLimit?;
68
67
  componentWillLoad(): void;
69
68
  componentDidUpdate(): void;
70
69
  private initializeSDK;
71
- private parseRepos;
72
70
  private fetchIssues;
73
71
  private loadMore;
74
72
  private handleUpvote;
@@ -104,6 +104,10 @@ export namespace Components {
104
104
  * This component uses the SDK internally to fetch data and delegates to feedlog-github-issues for rendering.
105
105
  */
106
106
  interface FeedlogGithubIssuesClient {
107
+ /**
108
+ * API key for Feedlog authentication (required) The API key determines which repositories' issues are fetched
109
+ */
110
+ "apiKey": string;
107
111
  /**
108
112
  * Custom API endpoint
109
113
  */
@@ -117,10 +121,6 @@ export namespace Components {
117
121
  * @default '42rem'
118
122
  */
119
123
  "maxWidth": string;
120
- /**
121
- * Array of repository public IDs or single ID Format: repository public ID (not owner/repo)
122
- */
123
- "repos"?: string[] | string;
124
124
  /**
125
125
  * Whether to show the theme toggle button
126
126
  * @default true
@@ -414,6 +414,10 @@ declare namespace LocalJSX {
414
414
  * This component uses the SDK internally to fetch data and delegates to feedlog-github-issues for rendering.
415
415
  */
416
416
  interface FeedlogGithubIssuesClient {
417
+ /**
418
+ * API key for Feedlog authentication (required) The API key determines which repositories' issues are fetched
419
+ */
420
+ "apiKey": string;
417
421
  /**
418
422
  * Custom API endpoint
419
423
  */
@@ -439,10 +443,6 @@ declare namespace LocalJSX {
439
443
  * Event emitted when an issue is upvoted
440
444
  */
441
445
  "onFeedlogUpvote"?: (event: FeedlogGithubIssuesClientCustomEvent<{ issueId: string; upvoted: boolean; upvoteCount: number }>) => void;
442
- /**
443
- * Array of repository public IDs or single ID Format: repository public ID (not owner/repo)
444
- */
445
- "repos"?: string[] | string;
446
446
  /**
447
447
  * Whether to show the theme toggle button
448
448
  * @default true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feedlog-ai/webcomponents",
3
- "version": "0.0.1",
3
+ "version": "0.0.4",
4
4
  "description": "Stencil web components for Feedlog Toolkit - Data visualization components",
5
5
  "main": "./dist/index.cjs.js",
6
6
  "module": "./dist/index.js",
@@ -44,5 +44,8 @@
44
44
  "webcomponents",
45
45
  "stencil",
46
46
  "data-visualization"
47
- ]
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public"
50
+ }
48
51
  }
@@ -1 +0,0 @@
1
- import{r as t,c as e,h as s}from"./p-CkB6Yzeb.js";function i(t){if("string"!=typeof t)return"";let e=t.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");return e=e.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi,""),e=e.replace(/\s*on\w+\s*=\s*[^\s>]*/gi,""),e=e.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,""),e=e.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,""),e=e.replace(/<(embed|object)\b[^<]*>/gi,""),e=e.replace(/javascript:/gi,""),e=e.replace(/data:(?!image\/(?:png|jpg|jpeg|gif|webp);)/gi,""),e}class o extends Error{constructor(t,e,s){super(t),this.statusCode=e,this.originalError=s,this.name="FeedlogError",Object.setPrototypeOf(this,o.prototype)}}class r extends o{constructor(t){super(t),this.name="FeedlogValidationError",Object.setPrototypeOf(this,r.prototype)}}class n extends o{constructor(t,e,s){super(t,e,s),this.name="FeedlogNetworkError",Object.setPrototypeOf(this,n.prototype)}}class h extends o{constructor(t="Request timed out"){super(t),this.name="FeedlogTimeoutError",Object.setPrototypeOf(this,h.prototype)}}class a{constructor(t={}){this.config={credentials:"include",...t},this.endpoint=this.config.endpoint||"https://api.feedlog.app",this.timeout=this.config.timeout||3e4,this.endpoint=this.endpoint.replace(/\/$/,"")}async fetchIssues(t={}){try{const e=this.buildIssuesUrl(t),s=await this.fetchWithTimeout(e,{method:"GET",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(!s.ok)throw new n(`Failed to fetch issues: ${s.statusText}`,s.status);const i=await s.json();return this.validateIssuesResponse(i)}catch(t){if(t instanceof o)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new n("Network error: Unable to reach API",void 0,t);throw new o(`Failed to fetch issues: ${t instanceof Error?t.message:"Unknown error"}`,void 0,t)}}async toggleUpvote(t){if(!t||"string"!=typeof t)throw new r("Issue ID is required");try{const e=`${this.endpoint}/api/issues/${encodeURIComponent(t)}/upvote`,s=await this.fetchWithTimeout(e,{method:"POST",headers:this.getAuthHeaders(),credentials:this.config.credentials||"include"});if(404===s.status)throw new n("Issue not found",404);if(401===s.status)throw new n("Unauthorized",401);if(403===s.status)throw new n("Forbidden: Domain not allowed for this repository",403);if(!s.ok)throw new n(`Failed to toggle upvote: ${s.statusText}`,s.status);const i=await s.json();return this.validateUpvoteResponse(i)}catch(t){if(t instanceof o)throw t;if(t instanceof TypeError&&t.message.includes("fetch"))throw new n("Network error: Unable to reach API",void 0,t);throw new o(`Failed to toggle upvote: ${t instanceof Error?t.message:"Unknown error"}`,void 0,t)}}buildIssuesUrl(t){const e=new URL(`${this.endpoint}/api/issues`);if(t.repositoryIds){const s=Array.isArray(t.repositoryIds)?t.repositoryIds:[t.repositoryIds];for(const t of s)e.searchParams.append("repositoryIds",t)}return t.type&&e.searchParams.set("type",t.type),t.cursor&&e.searchParams.set("cursor",t.cursor),void 0!==t.limit&&e.searchParams.set("limit",t.limit.toString()),e.toString()}getAuthHeaders(){return{"Content-Type":"application/json"}}async fetchWithTimeout(t,e){const s=new AbortController,i=setTimeout((()=>s.abort()),this.timeout);try{const o=await fetch(t,{...e,signal:s.signal});return clearTimeout(i),o}catch(t){if(clearTimeout(i),t instanceof Error&&"AbortError"===t.name)throw new h(`Request timed out after ${this.timeout}ms`);throw t}}validateIssuesResponse(t){if(!t||"object"!=typeof t)throw new r("Invalid API response: expected object");const e=t;if(!Array.isArray(e.issues))throw new r("Invalid API response: issues must be an array");if(!e.pagination||"object"!=typeof e.pagination)throw new r("Invalid API response: pagination is required");return{issues:e.issues.map((t=>this.validateIssue(t))),pagination:{cursor:e.pagination.cursor,hasMore:Boolean(e.pagination.hasMore)}}}validateIssue(t){if(!t||"object"!=typeof t)throw new r("Invalid issue: expected object");const e=t;if("string"!=typeof e.id)throw new r("Invalid issue: id is required and must be a string");if("string"!=typeof e.title)throw new r("Invalid issue: title is required and must be a string");if(!["bug","enhancement"].includes(String(e.type)))throw new r('Invalid issue: type must be "bug" or "enhancement"');if(!["open","closed"].includes(String(e.status)))throw new r('Invalid issue: status must be "open" or "closed"');if(!e.repository||"object"!=typeof e.repository)throw new r("Invalid issue: repository is required");const s=e.repository;if("string"!=typeof s.id||"string"!=typeof s.name||"string"!=typeof s.owner)throw new r("Invalid issue: repository must have id, name, and owner");const o=i(String(e.title)),n=i(String(e.body||""));return{id:String(e.id),type:e.type||"bug",status:e.status||"open",pinnedAt:e.pinnedAt?String(e.pinnedAt):null,revision:Number(e.revision)||1,title:o,body:n,repository:{id:String(s.id),name:String(s.name),owner:String(s.owner)},updatedAt:String(e.updatedAt)||(new Date).toISOString(),createdAt:String(e.createdAt)||(new Date).toISOString(),upvoteCount:Number(e.upvoteCount)||0,hasUpvoted:Boolean(e.hasUpvoted)}}validateUpvoteResponse(t){if(!t||"object"!=typeof t)throw new r("Invalid upvote response: expected object");const e=t;if("boolean"!=typeof e.upvoted)throw new r("Invalid upvote response: upvoted must be a boolean");if("number"!=typeof e.upvoteCount)throw new r("Invalid upvote response: upvoteCount must be a number");if("string"!=typeof e.anonymousUserId)throw new r("Invalid upvote response: anonymousUserId must be a string");return{upvoted:e.upvoted,upvoteCount:e.upvoteCount,anonymousUserId:e.anonymousUserId}}getEndpoint(){return this.endpoint}getTimeout(){return this.timeout}}const c=class{constructor(s){t(this,s),this.feedlogUpvote=e(this,"feedlogUpvote"),this.feedlogThemeChange=e(this,"feedlogThemeChange"),this.feedlogError=e(this,"feedlogError"),this.maxWidth="42rem",this.theme="light",this.showThemeToggle=!0,this.issues=[],this.loading=!0,this.error=null,this.cursor=null,this.hasMore=!1,this.isLoadingMore=!1,this.sdk=null,this.handleUpvote=async t=>{if(!this.sdk)return;const{issueId:e,currentUpvoted:s,currentCount:i}=t.detail;this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:!s,upvoteCount:s?i-1:i+1}):t));try{const t=await this.sdk.toggleUpvote(e);this.issues=this.issues.map((s=>s.id===e?Object.assign(Object.assign({},s),{hasUpvoted:t.upvoted,upvoteCount:t.upvoteCount}):s)),this.feedlogUpvote.emit({issueId:e,upvoted:t.upvoted,upvoteCount:t.upvoteCount})}catch(t){this.issues=this.issues.map((t=>t.id===e?Object.assign(Object.assign({},t),{hasUpvoted:s,upvoteCount:i}):t));const o=t instanceof Error?t.message:"Failed to toggle upvote";this.feedlogError.emit({error:o})}},this.handleThemeChange=t=>{this.theme=t.detail,this.feedlogThemeChange.emit(t.detail)}}componentWillLoad(){this.previousRepos=this.repos,this.previousType=this.type,this.previousLimit=this.limit,this.initializeSDK(),this.fetchIssues()}componentDidUpdate(){(JSON.stringify(this.previousRepos)!==JSON.stringify(this.repos)||this.previousType!==this.type||this.previousLimit!==this.limit)&&(this.cursor=null,this.hasMore=!1,this.issues=[],this.fetchIssues(),this.previousRepos=this.repos,this.previousType=this.type,this.previousLimit=this.limit)}initializeSDK(){try{this.sdk=new a(Object.assign({},this.endpoint&&{endpoint:this.endpoint})),this.error=null}catch(t){const e=t instanceof Error?t.message:"Failed to initialize SDK";this.error=e,this.feedlogError.emit({error:e})}}parseRepos(){if(!this.repos)return[];if("string"==typeof this.repos)try{const t=JSON.parse(this.repos);return Array.isArray(t)?t:[this.repos]}catch(t){return[this.repos]}return Array.isArray(this.repos)?this.repos:[]}async fetchIssues(){if(!this.sdk)return;const t=this.parseRepos();if(0===t.length)return this.error="At least one repository is required",this.loading=!1,void this.feedlogError.emit({error:"At least one repository is required"});try{this.loading=!0,this.error=null;const e={repositoryIds:t};this.type&&(e.type=this.type),this.limit&&(e.limit=this.limit),this.cursor&&(e.cursor=this.cursor);const s=await this.sdk.fetchIssues(e);this.issues=s.issues,this.cursor=s.pagination.cursor,this.hasMore=s.pagination.hasMore}catch(t){const e=t instanceof Error?t.message:"Failed to fetch issues";this.error=e,this.issues=[],this.feedlogError.emit({error:e,code:null==t?void 0:t.statusCode})}finally{this.loading=!1,this.isLoadingMore=!1}}async loadMore(){if(this.sdk&&this.hasMore&&!this.isLoadingMore&&!this.loading){this.isLoadingMore=!0;try{const t={repositoryIds:this.parseRepos()};this.type&&(t.type=this.type),this.limit&&(t.limit=this.limit),this.cursor&&(t.cursor=this.cursor);const e=await this.sdk.fetchIssues(t);this.issues=[...this.issues,...e.issues],this.cursor=e.pagination.cursor,this.hasMore=e.pagination.hasMore}catch(t){const e=t instanceof Error?t.message:"Failed to load more issues";this.feedlogError.emit({error:e,code:null==t?void 0:t.statusCode})}finally{this.isLoadingMore=!1}}}render(){return s("feedlog-github-issues",{key:"38b9e7ec8a5473acbab39df1d0476fcb357866bf",issues:this.issues,maxWidth:this.maxWidth,theme:this.theme,showThemeToggle:this.showThemeToggle,loading:this.loading,error:this.error,hasMore:this.hasMore,isLoadingMore:this.isLoadingMore,onFeedlogUpvote:this.handleUpvote,onFeedlogThemeChange:this.handleThemeChange,onFeedlogLoadMore:async()=>this.loadMore()})}};export{c as feedlog_github_issues_client}