@feedlog-ai/webcomponents 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/feedlog-badge_3.cjs.entry.js +119 -0
- package/dist/cjs/feedlog-card.cjs.entry.js +17 -0
- package/dist/cjs/feedlog-github-issues-client.cjs.entry.js +520 -0
- package/dist/cjs/feedlog-github-issues.cjs.entry.js +81 -0
- package/dist/cjs/feedlog-toolkit.cjs.js +24 -0
- package/dist/cjs/index-5lluu_3h.js +3144 -0
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/loader.cjs.js +12 -0
- package/dist/collection/collection-manifest.json +17 -0
- package/dist/collection/components/feedlog-badge/feedlog-badge.css +86 -0
- package/dist/collection/components/feedlog-badge/feedlog-badge.js +53 -0
- package/dist/collection/components/feedlog-badge/feedlog-badge.stories.js +38 -0
- package/dist/collection/components/feedlog-button/feedlog-button.css +155 -0
- package/dist/collection/components/feedlog-button/feedlog-button.js +154 -0
- package/dist/collection/components/feedlog-button/feedlog-button.stories.js +82 -0
- package/dist/collection/components/feedlog-card/feedlog-card.css +47 -0
- package/dist/collection/components/feedlog-card/feedlog-card.js +23 -0
- package/dist/collection/components/feedlog-card/feedlog-card.stories.js +22 -0
- package/dist/collection/components/feedlog-github-issues/feedlog-github-issues.css +69 -0
- package/dist/collection/components/feedlog-github-issues/feedlog-github-issues.js +308 -0
- package/dist/collection/components/feedlog-github-issues/feedlog-github-issues.stories.js +211 -0
- package/dist/collection/components/feedlog-github-issues-client/feedlog-github-issues-client.js +395 -0
- package/dist/collection/components/feedlog-issues-list/feedlog-issues-list.css +218 -0
- package/dist/collection/components/feedlog-issues-list/feedlog-issues-list.js +139 -0
- package/dist/collection/components/index.js +6 -0
- package/dist/collection/index.js +1 -0
- package/dist/components/feedlog-badge.d.ts +11 -0
- package/dist/components/feedlog-badge.js +1 -0
- package/dist/components/feedlog-button.d.ts +11 -0
- package/dist/components/feedlog-button.js +1 -0
- package/dist/components/feedlog-card.d.ts +11 -0
- package/dist/components/feedlog-card.js +1 -0
- package/dist/components/feedlog-github-issues-client.d.ts +11 -0
- package/dist/components/feedlog-github-issues-client.js +1 -0
- package/dist/components/feedlog-github-issues.d.ts +11 -0
- package/dist/components/feedlog-github-issues.js +1 -0
- package/dist/components/feedlog-issues-list.d.ts +11 -0
- package/dist/components/feedlog-issues-list.js +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/p-CHtSMTyP.js +1 -0
- package/dist/components/p-CPOiBAxu.js +1 -0
- package/dist/components/p-DMcNh5Ys.js +1 -0
- package/dist/components/p-DMdb-G26.js +1 -0
- package/dist/esm/feedlog-badge_3.entry.js +115 -0
- package/dist/esm/feedlog-card.entry.js +15 -0
- package/dist/esm/feedlog-github-issues-client.entry.js +518 -0
- package/dist/esm/feedlog-github-issues.entry.js +79 -0
- package/dist/esm/feedlog-toolkit.js +20 -0
- package/dist/esm/index-CkB6Yzeb.js +3135 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/loader.js +10 -0
- package/dist/feedlog-toolkit/feedlog-toolkit.css +1 -0
- package/dist/feedlog-toolkit/feedlog-toolkit.esm.js +1 -0
- package/dist/feedlog-toolkit/index.esm.js +0 -0
- package/dist/feedlog-toolkit/p-2f7954f7.entry.js +1 -0
- package/dist/feedlog-toolkit/p-399e0281.entry.js +1 -0
- package/dist/feedlog-toolkit/p-CkB6Yzeb.js +2 -0
- package/dist/feedlog-toolkit/p-b3d26272.entry.js +1 -0
- package/dist/feedlog-toolkit/p-cdb2b098.entry.js +1 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/types/components/feedlog-badge/feedlog-badge.d.ts +12 -0
- package/dist/types/components/feedlog-badge/feedlog-badge.stories.d.ts +9 -0
- package/dist/types/components/feedlog-button/feedlog-button.d.ts +30 -0
- package/dist/types/components/feedlog-button/feedlog-button.stories.d.ts +13 -0
- package/dist/types/components/feedlog-card/feedlog-card.d.ts +8 -0
- package/dist/types/components/feedlog-card/feedlog-card.stories.d.ts +9 -0
- package/dist/types/components/feedlog-github-issues/feedlog-github-issues.d.ts +67 -0
- package/dist/types/components/feedlog-github-issues/feedlog-github-issues.stories.d.ts +11 -0
- package/dist/types/components/feedlog-github-issues-client/feedlog-github-issues-client.d.ts +77 -0
- package/dist/types/components/feedlog-issues-list/feedlog-issues-list.d.ts +31 -0
- package/dist/types/components/index.d.ts +6 -0
- package/dist/types/components.d.ts +532 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/stencil-public-runtime.d.ts +1810 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +48 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { r as registerInstance, h } from './index-CkB6Yzeb.js';
|
|
2
|
+
|
|
3
|
+
const feedlogCardCss = () => `:host{display:block;font-family:ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;--feedlog-card:#ffffff;--feedlog-card-foreground:oklch(0.145 0 0);--feedlog-border:rgba(0, 0, 0, 0.1);--feedlog-radius:0.625rem;--feedlog-card-shadow:0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);--feedlog-card-hover-shadow:0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)}:host(.dark){--feedlog-card:oklch(0.145 0 0);--feedlog-card-foreground:oklch(0.985 0 0);--feedlog-border:oklch(0.269 0 0);--feedlog-card-shadow:0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.3);--feedlog-card-hover-shadow:0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -4px rgba(0, 0, 0, 0.3)}.feedlog-card{background-color:var(--feedlog-card);color:var(--feedlog-card-foreground);border:1px solid var(--feedlog-border);border-radius:var(--feedlog-radius);box-shadow:var(--feedlog-card-shadow);transition:box-shadow 0.15s ease;position:relative}.feedlog-card:hover{box-shadow:var(--feedlog-card-hover-shadow)}::slotted([slot="header"]){display:block}::slotted([slot="content"]){display:block}::slotted([slot="footer"]){display:block}`;
|
|
4
|
+
|
|
5
|
+
const FeedlogCard = class {
|
|
6
|
+
constructor(hostRef) {
|
|
7
|
+
registerInstance(this, hostRef);
|
|
8
|
+
}
|
|
9
|
+
render() {
|
|
10
|
+
return (h("div", { key: '293a80e66adedfc1af29daf72390a4f464321b96', class: "feedlog-card" }, h("slot", { key: 'b7e5a827f89035e791d9c756db0f66198e6c5a38', name: "header" }), h("slot", { key: 'da89fee0a01068c8438564848f218faa9c5d849e', name: "content" }), h("slot", { key: '30b05e80e4189c0f73810a48f64e072dfac83267', name: "footer" })));
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
FeedlogCard.style = feedlogCardCss();
|
|
14
|
+
|
|
15
|
+
export { FeedlogCard as feedlog_card };
|
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import { r as registerInstance, c as createEvent, h } from './index-CkB6Yzeb.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTML and XSS sanitization utilities
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Basic HTML entity escaping to prevent XSS
|
|
8
|
+
* This is a lightweight alternative to DOMPurify
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Sanitize HTML by removing dangerous tags and attributes
|
|
12
|
+
* Removes script tags, event handlers, and other potentially malicious content
|
|
13
|
+
*/
|
|
14
|
+
function sanitizeHtml(html) {
|
|
15
|
+
if (typeof html !== 'string') {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
// Remove script tags and content
|
|
19
|
+
let sanitized = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
|
20
|
+
// Remove on* event handlers
|
|
21
|
+
sanitized = sanitized.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi, '');
|
|
22
|
+
sanitized = sanitized.replace(/\s*on\w+\s*=\s*[^\s>]*/gi, '');
|
|
23
|
+
// Remove iframe tags
|
|
24
|
+
sanitized = sanitized.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, '');
|
|
25
|
+
// Remove style tags
|
|
26
|
+
sanitized = sanitized.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '');
|
|
27
|
+
// Remove embed and object tags
|
|
28
|
+
sanitized = sanitized.replace(/<(embed|object)\b[^<]*>/gi, '');
|
|
29
|
+
// Remove javascript: protocol
|
|
30
|
+
sanitized = sanitized.replace(/javascript:/gi, '');
|
|
31
|
+
// Remove data: protocol for potentially dangerous mime types
|
|
32
|
+
sanitized = sanitized.replace(/data:(?!image\/(?:png|jpg|jpeg|gif|webp);)/gi, '');
|
|
33
|
+
return sanitized;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Custom error types for Feedlog SDK
|
|
38
|
+
*/
|
|
39
|
+
class FeedlogError extends Error {
|
|
40
|
+
constructor(message, statusCode, originalError) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.statusCode = statusCode;
|
|
43
|
+
this.originalError = originalError;
|
|
44
|
+
this.name = 'FeedlogError';
|
|
45
|
+
Object.setPrototypeOf(this, FeedlogError.prototype);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class FeedlogValidationError extends FeedlogError {
|
|
49
|
+
constructor(message) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = 'FeedlogValidationError';
|
|
52
|
+
Object.setPrototypeOf(this, FeedlogValidationError.prototype);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
class FeedlogNetworkError extends FeedlogError {
|
|
56
|
+
constructor(message, statusCode, originalError) {
|
|
57
|
+
super(message, statusCode, originalError);
|
|
58
|
+
this.name = 'FeedlogNetworkError';
|
|
59
|
+
Object.setPrototypeOf(this, FeedlogNetworkError.prototype);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
class FeedlogTimeoutError extends FeedlogError {
|
|
63
|
+
constructor(message = 'Request timed out') {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = 'FeedlogTimeoutError';
|
|
66
|
+
Object.setPrototypeOf(this, FeedlogTimeoutError.prototype);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Core SDK for Feedlog Toolkit
|
|
72
|
+
*
|
|
73
|
+
* This package provides the core functionality and utilities
|
|
74
|
+
* used across all Feedlog Toolkit packages.
|
|
75
|
+
*/
|
|
76
|
+
/**
|
|
77
|
+
* Main Feedlog SDK class
|
|
78
|
+
* Provides methods to interact with the Feedlog API
|
|
79
|
+
*/
|
|
80
|
+
class FeedlogSDK {
|
|
81
|
+
constructor(config = {}) {
|
|
82
|
+
this.config = {
|
|
83
|
+
credentials: 'include',
|
|
84
|
+
...config,
|
|
85
|
+
};
|
|
86
|
+
this.endpoint = this.config.endpoint || 'https://api.feedlog.app';
|
|
87
|
+
this.timeout = this.config.timeout || 30000;
|
|
88
|
+
// Ensure endpoint doesn't have trailing slash
|
|
89
|
+
this.endpoint = this.endpoint.replace(/\/$/, '');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Fetch issues from the API
|
|
93
|
+
* Supports filtering by repository IDs, type, pagination, and limit
|
|
94
|
+
*/
|
|
95
|
+
async fetchIssues(params = {}) {
|
|
96
|
+
try {
|
|
97
|
+
const url = this.buildIssuesUrl(params);
|
|
98
|
+
const response = await this.fetchWithTimeout(url, {
|
|
99
|
+
method: 'GET',
|
|
100
|
+
headers: this.getAuthHeaders(),
|
|
101
|
+
credentials: this.config.credentials || 'include',
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
throw new FeedlogNetworkError(`Failed to fetch issues: ${response.statusText}`, response.status);
|
|
105
|
+
}
|
|
106
|
+
const data = await response.json();
|
|
107
|
+
return this.validateIssuesResponse(data);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error instanceof FeedlogError) {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
114
|
+
throw new FeedlogNetworkError('Network error: Unable to reach API', undefined, error);
|
|
115
|
+
}
|
|
116
|
+
throw new FeedlogError(`Failed to fetch issues: ${error instanceof Error ? error.message : 'Unknown error'}`, undefined, error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Toggle upvote on an issue
|
|
121
|
+
* Adds upvote if not already upvoted, removes if already upvoted
|
|
122
|
+
*/
|
|
123
|
+
async toggleUpvote(issueId) {
|
|
124
|
+
if (!issueId || typeof issueId !== 'string') {
|
|
125
|
+
throw new FeedlogValidationError('Issue ID is required');
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const url = `${this.endpoint}/api/issues/${encodeURIComponent(issueId)}/upvote`;
|
|
129
|
+
const response = await this.fetchWithTimeout(url, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
headers: this.getAuthHeaders(),
|
|
132
|
+
credentials: this.config.credentials || 'include',
|
|
133
|
+
});
|
|
134
|
+
if (response.status === 404) {
|
|
135
|
+
throw new FeedlogNetworkError('Issue not found', 404);
|
|
136
|
+
}
|
|
137
|
+
if (response.status === 401) {
|
|
138
|
+
throw new FeedlogNetworkError('Unauthorized', 401);
|
|
139
|
+
}
|
|
140
|
+
if (response.status === 403) {
|
|
141
|
+
throw new FeedlogNetworkError('Forbidden: Domain not allowed for this repository', 403);
|
|
142
|
+
}
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
throw new FeedlogNetworkError(`Failed to toggle upvote: ${response.statusText}`, response.status);
|
|
145
|
+
}
|
|
146
|
+
const data = await response.json();
|
|
147
|
+
return this.validateUpvoteResponse(data);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error instanceof FeedlogError) {
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
154
|
+
throw new FeedlogNetworkError('Network error: Unable to reach API', undefined, error);
|
|
155
|
+
}
|
|
156
|
+
throw new FeedlogError(`Failed to toggle upvote: ${error instanceof Error ? error.message : 'Unknown error'}`, undefined, error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Build the full URL for fetching issues with query parameters
|
|
161
|
+
*/
|
|
162
|
+
buildIssuesUrl(params) {
|
|
163
|
+
const url = new URL(`${this.endpoint}/api/issues`);
|
|
164
|
+
// Handle repositoryIds - can be single string or array
|
|
165
|
+
if (params.repositoryIds) {
|
|
166
|
+
const ids = Array.isArray(params.repositoryIds)
|
|
167
|
+
? params.repositoryIds
|
|
168
|
+
: [params.repositoryIds];
|
|
169
|
+
for (const id of ids) {
|
|
170
|
+
url.searchParams.append('repositoryIds', id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (params.type) {
|
|
174
|
+
url.searchParams.set('type', params.type);
|
|
175
|
+
}
|
|
176
|
+
if (params.cursor) {
|
|
177
|
+
url.searchParams.set('cursor', params.cursor);
|
|
178
|
+
}
|
|
179
|
+
if (params.limit !== undefined) {
|
|
180
|
+
url.searchParams.set('limit', params.limit.toString());
|
|
181
|
+
}
|
|
182
|
+
return url.toString();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get request headers
|
|
186
|
+
*/
|
|
187
|
+
getAuthHeaders() {
|
|
188
|
+
return {
|
|
189
|
+
'Content-Type': 'application/json',
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Fetch with timeout support using AbortController
|
|
194
|
+
*/
|
|
195
|
+
async fetchWithTimeout(url, init) {
|
|
196
|
+
const controller = new AbortController();
|
|
197
|
+
const timeout = setTimeout(() => controller.abort(), this.timeout);
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch(url, {
|
|
200
|
+
...init,
|
|
201
|
+
signal: controller.signal,
|
|
202
|
+
});
|
|
203
|
+
clearTimeout(timeout);
|
|
204
|
+
return response;
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
clearTimeout(timeout);
|
|
208
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
209
|
+
throw new FeedlogTimeoutError(`Request timed out after ${this.timeout}ms`);
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Validate and sanitize issues response
|
|
216
|
+
*/
|
|
217
|
+
validateIssuesResponse(data) {
|
|
218
|
+
if (!data || typeof data !== 'object') {
|
|
219
|
+
throw new FeedlogValidationError('Invalid API response: expected object');
|
|
220
|
+
}
|
|
221
|
+
const response = data;
|
|
222
|
+
if (!Array.isArray(response.issues)) {
|
|
223
|
+
throw new FeedlogValidationError('Invalid API response: issues must be an array');
|
|
224
|
+
}
|
|
225
|
+
if (!response.pagination || typeof response.pagination !== 'object') {
|
|
226
|
+
throw new FeedlogValidationError('Invalid API response: pagination is required');
|
|
227
|
+
}
|
|
228
|
+
const issues = response.issues.map(issue => this.validateIssue(issue));
|
|
229
|
+
return {
|
|
230
|
+
issues,
|
|
231
|
+
pagination: {
|
|
232
|
+
cursor: response.pagination.cursor,
|
|
233
|
+
hasMore: Boolean(response.pagination.hasMore),
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Validate and sanitize an individual issue
|
|
239
|
+
*/
|
|
240
|
+
validateIssue(data) {
|
|
241
|
+
if (!data || typeof data !== 'object') {
|
|
242
|
+
throw new FeedlogValidationError('Invalid issue: expected object');
|
|
243
|
+
}
|
|
244
|
+
const issue = data;
|
|
245
|
+
// Validate required fields
|
|
246
|
+
if (typeof issue.id !== 'string') {
|
|
247
|
+
throw new FeedlogValidationError('Invalid issue: id is required and must be a string');
|
|
248
|
+
}
|
|
249
|
+
if (typeof issue.title !== 'string') {
|
|
250
|
+
throw new FeedlogValidationError('Invalid issue: title is required and must be a string');
|
|
251
|
+
}
|
|
252
|
+
if (!['bug', 'enhancement'].includes(String(issue.type))) {
|
|
253
|
+
throw new FeedlogValidationError('Invalid issue: type must be "bug" or "enhancement"');
|
|
254
|
+
}
|
|
255
|
+
if (!['open', 'closed'].includes(String(issue.status))) {
|
|
256
|
+
throw new FeedlogValidationError('Invalid issue: status must be "open" or "closed"');
|
|
257
|
+
}
|
|
258
|
+
if (!issue.repository || typeof issue.repository !== 'object') {
|
|
259
|
+
throw new FeedlogValidationError('Invalid issue: repository is required');
|
|
260
|
+
}
|
|
261
|
+
const repo = issue.repository;
|
|
262
|
+
if (typeof repo.id !== 'string' ||
|
|
263
|
+
typeof repo.name !== 'string' ||
|
|
264
|
+
typeof repo.owner !== 'string') {
|
|
265
|
+
throw new FeedlogValidationError('Invalid issue: repository must have id, name, and owner');
|
|
266
|
+
}
|
|
267
|
+
// Sanitize string fields to prevent XSS
|
|
268
|
+
const sanitizedTitle = sanitizeHtml(String(issue.title));
|
|
269
|
+
const sanitizedBody = sanitizeHtml(String(issue.body || ''));
|
|
270
|
+
return {
|
|
271
|
+
id: String(issue.id),
|
|
272
|
+
type: issue.type || 'bug',
|
|
273
|
+
status: issue.status || 'open',
|
|
274
|
+
pinnedAt: issue.pinnedAt ? String(issue.pinnedAt) : null,
|
|
275
|
+
revision: Number(issue.revision) || 1,
|
|
276
|
+
title: sanitizedTitle,
|
|
277
|
+
body: sanitizedBody,
|
|
278
|
+
repository: {
|
|
279
|
+
id: String(repo.id),
|
|
280
|
+
name: String(repo.name),
|
|
281
|
+
owner: String(repo.owner),
|
|
282
|
+
},
|
|
283
|
+
updatedAt: String(issue.updatedAt) || new Date().toISOString(),
|
|
284
|
+
createdAt: String(issue.createdAt) || new Date().toISOString(),
|
|
285
|
+
upvoteCount: Number(issue.upvoteCount) || 0,
|
|
286
|
+
hasUpvoted: Boolean(issue.hasUpvoted),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Validate upvote response
|
|
291
|
+
*/
|
|
292
|
+
validateUpvoteResponse(data) {
|
|
293
|
+
if (!data || typeof data !== 'object') {
|
|
294
|
+
throw new FeedlogValidationError('Invalid upvote response: expected object');
|
|
295
|
+
}
|
|
296
|
+
const response = data;
|
|
297
|
+
if (typeof response.upvoted !== 'boolean') {
|
|
298
|
+
throw new FeedlogValidationError('Invalid upvote response: upvoted must be a boolean');
|
|
299
|
+
}
|
|
300
|
+
if (typeof response.upvoteCount !== 'number') {
|
|
301
|
+
throw new FeedlogValidationError('Invalid upvote response: upvoteCount must be a number');
|
|
302
|
+
}
|
|
303
|
+
if (typeof response.anonymousUserId !== 'string') {
|
|
304
|
+
throw new FeedlogValidationError('Invalid upvote response: anonymousUserId must be a string');
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
upvoted: response.upvoted,
|
|
308
|
+
upvoteCount: response.upvoteCount,
|
|
309
|
+
anonymousUserId: response.anonymousUserId,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Get the current endpoint
|
|
314
|
+
*/
|
|
315
|
+
getEndpoint() {
|
|
316
|
+
return this.endpoint;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get the current timeout setting
|
|
320
|
+
*/
|
|
321
|
+
getTimeout() {
|
|
322
|
+
return this.timeout;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const FeedlogGithubIssuesClient = class {
|
|
327
|
+
constructor(hostRef) {
|
|
328
|
+
registerInstance(this, hostRef);
|
|
329
|
+
this.feedlogUpvote = createEvent(this, "feedlogUpvote");
|
|
330
|
+
this.feedlogThemeChange = createEvent(this, "feedlogThemeChange");
|
|
331
|
+
this.feedlogError = createEvent(this, "feedlogError");
|
|
332
|
+
/**
|
|
333
|
+
* Maximum width of the container
|
|
334
|
+
*/
|
|
335
|
+
this.maxWidth = '42rem';
|
|
336
|
+
/**
|
|
337
|
+
* Theme variant: 'light' or 'dark'
|
|
338
|
+
*/
|
|
339
|
+
this.theme = 'light';
|
|
340
|
+
/**
|
|
341
|
+
* Whether to show the theme toggle button
|
|
342
|
+
*/
|
|
343
|
+
this.showThemeToggle = true;
|
|
344
|
+
this.issues = [];
|
|
345
|
+
this.loading = true;
|
|
346
|
+
this.error = null;
|
|
347
|
+
this.cursor = null;
|
|
348
|
+
this.hasMore = false;
|
|
349
|
+
this.isLoadingMore = false;
|
|
350
|
+
this.sdk = null;
|
|
351
|
+
this.handleUpvote = async (event) => {
|
|
352
|
+
if (!this.sdk) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const { issueId, currentUpvoted, currentCount } = event.detail;
|
|
356
|
+
// Optimistic update
|
|
357
|
+
this.issues = this.issues.map(issue => issue.id === issueId
|
|
358
|
+
? Object.assign(Object.assign({}, issue), { hasUpvoted: !currentUpvoted, upvoteCount: currentUpvoted ? currentCount - 1 : currentCount + 1 }) : issue);
|
|
359
|
+
try {
|
|
360
|
+
const result = await this.sdk.toggleUpvote(issueId);
|
|
361
|
+
// Update with server response
|
|
362
|
+
this.issues = this.issues.map(issue => issue.id === issueId
|
|
363
|
+
? Object.assign(Object.assign({}, issue), { hasUpvoted: result.upvoted, upvoteCount: result.upvoteCount }) : issue);
|
|
364
|
+
this.feedlogUpvote.emit({
|
|
365
|
+
issueId,
|
|
366
|
+
upvoted: result.upvoted,
|
|
367
|
+
upvoteCount: result.upvoteCount,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
// Revert optimistic update on error
|
|
372
|
+
this.issues = this.issues.map(issue => issue.id === issueId
|
|
373
|
+
? Object.assign(Object.assign({}, issue), { hasUpvoted: currentUpvoted, upvoteCount: currentCount }) : issue);
|
|
374
|
+
const errorMsg = err instanceof Error ? err.message : 'Failed to toggle upvote';
|
|
375
|
+
this.feedlogError.emit({ error: errorMsg });
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
this.handleThemeChange = (event) => {
|
|
379
|
+
this.theme = event.detail;
|
|
380
|
+
this.feedlogThemeChange.emit(event.detail);
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
componentWillLoad() {
|
|
384
|
+
this.previousRepos = this.repos;
|
|
385
|
+
this.previousType = this.type;
|
|
386
|
+
this.previousLimit = this.limit;
|
|
387
|
+
this.initializeSDK();
|
|
388
|
+
this.fetchIssues();
|
|
389
|
+
}
|
|
390
|
+
componentDidUpdate() {
|
|
391
|
+
// Re-fetch if any props changed
|
|
392
|
+
const reposChanged = JSON.stringify(this.previousRepos) !== JSON.stringify(this.repos);
|
|
393
|
+
const typeChanged = this.previousType !== this.type;
|
|
394
|
+
const limitChanged = this.previousLimit !== this.limit;
|
|
395
|
+
if (reposChanged || typeChanged || limitChanged) {
|
|
396
|
+
// Reset pagination when filters change
|
|
397
|
+
this.cursor = null;
|
|
398
|
+
this.hasMore = false;
|
|
399
|
+
this.issues = [];
|
|
400
|
+
this.fetchIssues();
|
|
401
|
+
this.previousRepos = this.repos;
|
|
402
|
+
this.previousType = this.type;
|
|
403
|
+
this.previousLimit = this.limit;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
initializeSDK() {
|
|
407
|
+
try {
|
|
408
|
+
this.sdk = new FeedlogSDK(Object.assign({}, (this.endpoint && { endpoint: this.endpoint })));
|
|
409
|
+
this.error = null;
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
412
|
+
const errorMsg = err instanceof Error ? err.message : 'Failed to initialize SDK';
|
|
413
|
+
this.error = errorMsg;
|
|
414
|
+
this.feedlogError.emit({ error: errorMsg });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
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
|
+
async fetchIssues() {
|
|
434
|
+
if (!this.sdk) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
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
|
+
try {
|
|
445
|
+
this.loading = true;
|
|
446
|
+
this.error = null;
|
|
447
|
+
const params = {
|
|
448
|
+
repositoryIds: repos,
|
|
449
|
+
};
|
|
450
|
+
if (this.type) {
|
|
451
|
+
params.type = this.type;
|
|
452
|
+
}
|
|
453
|
+
if (this.limit) {
|
|
454
|
+
params.limit = this.limit;
|
|
455
|
+
}
|
|
456
|
+
if (this.cursor) {
|
|
457
|
+
params.cursor = this.cursor;
|
|
458
|
+
}
|
|
459
|
+
const response = await this.sdk.fetchIssues(params);
|
|
460
|
+
this.issues = response.issues;
|
|
461
|
+
this.cursor = response.pagination.cursor;
|
|
462
|
+
this.hasMore = response.pagination.hasMore;
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
const errorMsg = err instanceof Error ? err.message : 'Failed to fetch issues';
|
|
466
|
+
this.error = errorMsg;
|
|
467
|
+
this.issues = [];
|
|
468
|
+
this.feedlogError.emit({
|
|
469
|
+
error: errorMsg,
|
|
470
|
+
code: err === null || err === void 0 ? void 0 : err.statusCode,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
finally {
|
|
474
|
+
this.loading = false;
|
|
475
|
+
this.isLoadingMore = false;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
async loadMore() {
|
|
479
|
+
if (!this.sdk || !this.hasMore || this.isLoadingMore || this.loading) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
this.isLoadingMore = true;
|
|
483
|
+
try {
|
|
484
|
+
const repos = this.parseRepos();
|
|
485
|
+
const params = {
|
|
486
|
+
repositoryIds: repos,
|
|
487
|
+
};
|
|
488
|
+
if (this.type) {
|
|
489
|
+
params.type = this.type;
|
|
490
|
+
}
|
|
491
|
+
if (this.limit) {
|
|
492
|
+
params.limit = this.limit;
|
|
493
|
+
}
|
|
494
|
+
if (this.cursor) {
|
|
495
|
+
params.cursor = this.cursor;
|
|
496
|
+
}
|
|
497
|
+
const response = await this.sdk.fetchIssues(params);
|
|
498
|
+
this.issues = [...this.issues, ...response.issues];
|
|
499
|
+
this.cursor = response.pagination.cursor;
|
|
500
|
+
this.hasMore = response.pagination.hasMore;
|
|
501
|
+
}
|
|
502
|
+
catch (err) {
|
|
503
|
+
const errorMsg = err instanceof Error ? err.message : 'Failed to load more issues';
|
|
504
|
+
this.feedlogError.emit({
|
|
505
|
+
error: errorMsg,
|
|
506
|
+
code: err === null || err === void 0 ? void 0 : err.statusCode,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
finally {
|
|
510
|
+
this.isLoadingMore = false;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
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() }));
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
export { FeedlogGithubIssuesClient as feedlog_github_issues_client };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { r as registerInstance, c as createEvent, h, H as Host } from './index-CkB6Yzeb.js';
|
|
2
|
+
|
|
3
|
+
const feedlogGithubIssuesCss = () => `:host{display:block;font-family:ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;--feedlog-background:#ffffff;--feedlog-foreground:oklch(0.145 0 0);--feedlog-muted-foreground:#717182;--feedlog-destructive:#d4183d;--feedlog-padding:2rem}:host(.dark){--feedlog-background:oklch(0.145 0 0);--feedlog-foreground:oklch(0.985 0 0);--feedlog-muted-foreground:oklch(0.708 0 0);--feedlog-destructive:oklch(0.637 0.237 25.331)}.github-issues-container{min-height:100vh;background-color:var(--feedlog-background);padding:var(--feedlog-padding);margin:0 auto}.issues-header{margin-bottom:1.5rem;display:flex;align-items:flex-start;justify-content:space-between}.header-content{flex:1}.issues-title{color:var(--feedlog-foreground);margin:0 0 0.25rem 0;font-size:1.5rem;font-weight:500;line-height:1.5}.issues-subtitle{color:var(--feedlog-muted-foreground);font-size:0.875rem;margin:0}.loading-state,.error-state{padding:2rem;text-align:center;color:var(--feedlog-muted-foreground)}.error-state{color:var(--feedlog-destructive)}.load-more-container{display:flex;justify-content:center;padding:2rem 0;gap:1rem}`;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sun icon SVG component
|
|
7
|
+
*/
|
|
8
|
+
const SunIcon = () => (h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("circle", { cx: "12", cy: "12", r: "4" }), h("path", { d: "M12 2v2" }), h("path", { d: "M12 20v2" }), h("path", { d: "m4.93 4.93 1.41 1.41" }), h("path", { d: "m17.66 17.66 1.41 1.41" }), h("path", { d: "M2 12h2" }), h("path", { d: "M20 12h2" }), h("path", { d: "m6.34 17.66-1.41 1.41" }), h("path", { d: "m19.07 4.93-1.41 1.41" })));
|
|
9
|
+
/**
|
|
10
|
+
* Moon icon SVG component
|
|
11
|
+
*/
|
|
12
|
+
const MoonIcon = () => (h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })));
|
|
13
|
+
const FeedlogGithubIssues = class {
|
|
14
|
+
constructor(hostRef) {
|
|
15
|
+
registerInstance(this, hostRef);
|
|
16
|
+
this.feedlogUpvote = createEvent(this, "feedlogUpvote");
|
|
17
|
+
this.feedlogThemeChange = createEvent(this, "feedlogThemeChange");
|
|
18
|
+
this.feedlogLoadMore = createEvent(this, "feedlogLoadMore");
|
|
19
|
+
/**
|
|
20
|
+
* Array of issues to display
|
|
21
|
+
*/
|
|
22
|
+
this.issues = [];
|
|
23
|
+
/**
|
|
24
|
+
* Maximum width of the container
|
|
25
|
+
*/
|
|
26
|
+
this.maxWidth = '42rem';
|
|
27
|
+
/**
|
|
28
|
+
* Theme variant: 'light' or 'dark'
|
|
29
|
+
*/
|
|
30
|
+
this.theme = 'light';
|
|
31
|
+
/**
|
|
32
|
+
* Loading state - shows loading indicator when true
|
|
33
|
+
*/
|
|
34
|
+
this.loading = false;
|
|
35
|
+
/**
|
|
36
|
+
* Error message - shows error state when set
|
|
37
|
+
*/
|
|
38
|
+
this.error = null;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to show the theme toggle button
|
|
41
|
+
*/
|
|
42
|
+
this.showThemeToggle = true;
|
|
43
|
+
/**
|
|
44
|
+
* Whether there are more issues to load
|
|
45
|
+
*/
|
|
46
|
+
this.hasMore = false;
|
|
47
|
+
/**
|
|
48
|
+
* Whether more issues are currently loading
|
|
49
|
+
*/
|
|
50
|
+
this.isLoadingMore = false;
|
|
51
|
+
/**
|
|
52
|
+
* Internal state for theme
|
|
53
|
+
*/
|
|
54
|
+
this.currentTheme = 'light';
|
|
55
|
+
this.handleUpvote = (event) => {
|
|
56
|
+
this.feedlogUpvote.emit(event.detail);
|
|
57
|
+
};
|
|
58
|
+
this.toggleTheme = () => {
|
|
59
|
+
this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
|
|
60
|
+
this.theme = this.currentTheme;
|
|
61
|
+
this.feedlogThemeChange.emit(this.currentTheme);
|
|
62
|
+
};
|
|
63
|
+
this.handleLoadMore = () => {
|
|
64
|
+
this.feedlogLoadMore.emit();
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
componentWillLoad() {
|
|
68
|
+
this.currentTheme = this.theme;
|
|
69
|
+
}
|
|
70
|
+
render() {
|
|
71
|
+
const containerStyle = {
|
|
72
|
+
maxWidth: this.maxWidth,
|
|
73
|
+
};
|
|
74
|
+
return (h(Host, { key: '8f238ab41f45799062270c84188596d770d6bde0', class: this.currentTheme === 'dark' ? 'dark' : '' }, h("div", { key: 'af0c2155ef3cdc12f228ec804ee906afd7d75477', class: "github-issues-container", style: containerStyle }, h("header", { key: 'ccf9a063df220f7a48e3600cb22df8203960a45b', class: "issues-header" }, h("div", { key: 'c261d6b0c8168a66faef9ec2fb381619f5175070', class: "header-content" }, h("h1", { key: '19203aa63dab0648b0a2865fe812233bfbbc225a', class: "issues-title" }, "GitHub Issues"), h("p", { key: 'e717a4e64cc747c81ad7a9e1cec234c247bfc329', class: "issues-subtitle" }, "Track bugs and enhancements for your project")), this.showThemeToggle && (h("feedlog-button", { key: '21057c7d384c53262e699e0384234077b0b36314', variant: "outline", size: "sm", onFeedlogClick: this.toggleTheme }, this.currentTheme === 'dark' ? h(SunIcon, null) : h(MoonIcon, null)))), this.loading && (h("div", { key: '2059c491247e0a48a81d802d9757d9fa97ac1a72', class: "loading-state" }, h("p", { key: '5654904e73b05bd5a05aa0243506e4bf074e5486' }, "Loading issues..."))), this.error && (h("div", { key: '7d2e09e0055e5d834aa870ed47bd4ebaba64dff1', class: "error-state" }, h("p", { key: 'd4cc2bb872c81234b4e81a4ec4ce21aff368ad74' }, "Error: ", this.error))), !this.loading && !this.error && (h("div", { key: 'e25eb90f7098416837a26a44e5811888530220a4' }, h("feedlog-issues-list", { key: 'a8e7ec5c5861cb31456738107b93f6e7adebbbe9', issues: this.issues, theme: this.currentTheme, onFeedlogUpvote: this.handleUpvote }), this.hasMore && (h("div", { key: '0d935e9247f44bff0700fce487d0bc4ccd104f2a', class: "load-more-container" }, h("feedlog-button", { key: '2858d701f5e3d219c39a6a28a7475c619464bc72', onFeedlogClick: this.handleLoadMore, disabled: this.isLoadingMore, variant: "outline" }, this.isLoadingMore ? 'Loading...' : 'Load More Issues'))))))));
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
FeedlogGithubIssues.style = feedlogGithubIssuesCss();
|
|
78
|
+
|
|
79
|
+
export { FeedlogGithubIssues as feedlog_github_issues };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { p as promiseResolve, g as globalScripts, b as bootstrapLazy } from './index-CkB6Yzeb.js';
|
|
2
|
+
export { s as setNonce } from './index-CkB6Yzeb.js';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Stencil Client Patch Browser v4.40.1 | MIT Licensed | https://stenciljs.com
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
var patchBrowser = () => {
|
|
9
|
+
const importMeta = import.meta.url;
|
|
10
|
+
const opts = {};
|
|
11
|
+
if (importMeta !== "") {
|
|
12
|
+
opts.resourcesUrl = new URL(".", importMeta).href;
|
|
13
|
+
}
|
|
14
|
+
return promiseResolve(opts);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
patchBrowser().then(async (options) => {
|
|
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);
|
|
20
|
+
});
|