@feedlog-ai/webcomponents 0.0.3 → 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 +246 -0
- package/dist/cjs/feedlog-github-issues-client.cjs.entry.js +14 -37
- package/dist/cjs/feedlog-toolkit.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/feedlog-github-issues-client/feedlog-github-issues-client.js +15 -43
- package/dist/components/feedlog-github-issues-client.js +1 -1
- package/dist/esm/feedlog-github-issues-client.entry.js +14 -37
- package/dist/esm/feedlog-toolkit.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/feedlog-toolkit/feedlog-toolkit.esm.js +1 -1
- package/dist/feedlog-toolkit/p-a01a3115.entry.js +1 -0
- package/dist/types/components/feedlog-github-issues-client/feedlog-github-issues-client.d.ts +3 -5
- package/dist/types/components.d.ts +8 -8
- package/package.json +5 -2
- package/dist/feedlog-toolkit/p-399e0281.entry.js +0 -1
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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: '
|
|
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",{"
|
|
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;
|
package/dist/cjs/loader.cjs.js
CHANGED
|
@@ -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",{"
|
|
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;
|
package/dist/collection/components/feedlog-github-issues-client/feedlog-github-issues-client.js
CHANGED
|
@@ -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 (
|
|
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
|
-
|
|
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
|
|
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: '
|
|
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
|
-
"
|
|
171
|
+
"apiKey": {
|
|
200
172
|
"type": "string",
|
|
201
173
|
"mutable": false,
|
|
202
174
|
"complexType": {
|
|
203
|
-
"original": "string
|
|
204
|
-
"resolved": "string
|
|
175
|
+
"original": "string",
|
|
176
|
+
"resolved": "string",
|
|
205
177
|
"references": {}
|
|
206
178
|
},
|
|
207
|
-
"required":
|
|
208
|
-
"optional":
|
|
179
|
+
"required": true,
|
|
180
|
+
"optional": false,
|
|
209
181
|
"docs": {
|
|
210
182
|
"tags": [],
|
|
211
|
-
"text": "
|
|
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": "
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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: '
|
|
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",{"
|
|
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
|
});
|
package/dist/esm/loader.js
CHANGED
|
@@ -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",{"
|
|
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-
|
|
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}
|
package/dist/types/components/feedlog-github-issues-client/feedlog-github-issues-client.d.ts
CHANGED
|
@@ -8,10 +8,10 @@ import { FeedlogIssue } from '@feedlog-ai/core';
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class FeedlogGithubIssuesClient {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* API key for Feedlog authentication (required)
|
|
12
|
+
* The API key determines which repositories' issues are fetched
|
|
13
13
|
*/
|
|
14
|
-
|
|
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.
|
|
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}
|