@autumnsgrove/groveengine 0.6.1 → 0.6.3
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/auth/jwt.d.ts +10 -4
- package/dist/auth/jwt.js +18 -4
- package/dist/auth/session.d.ts +22 -15
- package/dist/auth/session.js +35 -16
- package/dist/components/admin/GutterManager.svelte +81 -139
- package/dist/components/admin/GutterManager.svelte.d.ts +6 -6
- package/dist/components/admin/MarkdownEditor.svelte +80 -23
- package/dist/components/admin/MarkdownEditor.svelte.d.ts +14 -8
- package/dist/components/admin/composables/useAmbientSounds.svelte.d.ts +52 -2
- package/dist/components/admin/composables/useAmbientSounds.svelte.js +38 -4
- package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +80 -10
- package/dist/components/admin/composables/useCommandPalette.svelte.js +45 -5
- package/dist/components/admin/composables/useDraftManager.svelte.d.ts +76 -14
- package/dist/components/admin/composables/useDraftManager.svelte.js +44 -10
- package/dist/components/admin/composables/useEditorTheme.svelte.d.ts +168 -2
- package/dist/components/admin/composables/useEditorTheme.svelte.js +40 -7
- package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +94 -22
- package/dist/components/admin/composables/useSlashCommands.svelte.js +58 -9
- package/dist/components/admin/composables/useSnippets.svelte.d.ts +51 -2
- package/dist/components/admin/composables/useSnippets.svelte.js +35 -3
- package/dist/components/admin/composables/useWritingSession.svelte.d.ts +64 -6
- package/dist/components/admin/composables/useWritingSession.svelte.js +42 -5
- package/dist/components/custom/ContentWithGutter.svelte +53 -23
- package/dist/components/custom/ContentWithGutter.svelte.d.ts +6 -14
- package/dist/components/custom/GutterItem.svelte +1 -1
- package/dist/components/custom/LeftGutter.svelte +43 -13
- package/dist/components/custom/LeftGutter.svelte.d.ts +6 -6
- package/dist/config/ai-models.js +1 -1
- package/dist/groveauth/client.js +11 -11
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -2
- package/dist/server/logger.d.ts +74 -26
- package/dist/server/logger.js +133 -184
- package/dist/server/services/cache.js +1 -10
- package/dist/ui/components/charts/ActivityOverview.svelte +14 -3
- package/dist/ui/components/charts/ActivityOverview.svelte.d.ts +10 -7
- package/dist/ui/components/charts/RepoBreakdown.svelte +9 -3
- package/dist/ui/components/charts/RepoBreakdown.svelte.d.ts +12 -11
- package/dist/ui/components/charts/Sparkline.svelte +18 -7
- package/dist/ui/components/charts/Sparkline.svelte.d.ts +21 -2
- package/dist/ui/components/gallery/ImageGallery.svelte +12 -8
- package/dist/ui/components/gallery/ImageGallery.svelte.d.ts +2 -2
- package/dist/ui/components/gallery/Lightbox.svelte +5 -2
- package/dist/ui/components/gallery/ZoomableImage.svelte +8 -5
- package/dist/ui/components/primitives/accordion/index.d.ts +1 -1
- package/dist/ui/components/primitives/input/input.svelte.d.ts +1 -1
- package/dist/ui/components/primitives/tabs/index.d.ts +1 -1
- package/dist/ui/components/primitives/textarea/textarea.svelte.d.ts +1 -1
- package/dist/ui/components/ui/Button.svelte +5 -0
- package/dist/ui/components/ui/Button.svelte.d.ts +4 -1
- package/dist/ui/components/ui/Input.svelte +4 -0
- package/dist/ui/components/ui/Input.svelte.d.ts +3 -1
- package/dist/ui/components/ui/Logo.svelte +86 -0
- package/dist/ui/components/ui/Logo.svelte.d.ts +25 -0
- package/dist/ui/components/ui/LogoLoader.svelte +71 -0
- package/dist/ui/components/ui/LogoLoader.svelte.d.ts +9 -0
- package/dist/ui/components/ui/index.d.ts +2 -0
- package/dist/ui/components/ui/index.js +2 -0
- package/dist/ui/tailwind.preset.js +8 -8
- package/dist/utils/api.js +2 -1
- package/dist/utils/debounce.d.ts +4 -3
- package/dist/utils/debounce.js +10 -6
- package/dist/utils/gallery.d.ts +58 -32
- package/dist/utils/gallery.js +111 -129
- package/dist/utils/gutter.d.ts +47 -26
- package/dist/utils/gutter.js +116 -124
- package/dist/utils/imageProcessor.d.ts +66 -19
- package/dist/utils/imageProcessor.js +31 -10
- package/dist/utils/index.d.ts +11 -11
- package/dist/utils/index.js +4 -3
- package/dist/utils/json.js +1 -1
- package/dist/utils/markdown.d.ts +183 -103
- package/dist/utils/markdown.js +517 -678
- package/dist/utils/sanitize.d.ts +22 -12
- package/dist/utils/sanitize.js +268 -282
- package/dist/utils/validation.js +4 -3
- package/package.json +4 -3
|
@@ -2,15 +2,31 @@
|
|
|
2
2
|
import { tick } from 'svelte';
|
|
3
3
|
import GutterItem from './GutterItem.svelte';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {{ type?: string; file?: string; src?: string; url?: string; anchor?: string; content?: string; [key: string]: unknown }} GutterItemType
|
|
7
|
+
* @typedef {{ id: string; text: string; level?: number }} HeaderType
|
|
8
|
+
*/
|
|
6
9
|
|
|
10
|
+
let {
|
|
11
|
+
items = /** @type {GutterItemType[]} */ ([]),
|
|
12
|
+
headers = /** @type {HeaderType[]} */ ([]),
|
|
13
|
+
contentHeight = 0,
|
|
14
|
+
onOverflowChange = /** @type {(anchors: string[]) => void} */ (() => {})
|
|
15
|
+
} = $props();
|
|
16
|
+
|
|
17
|
+
/** @type {HTMLElement | undefined} */
|
|
7
18
|
let gutterElement = $state();
|
|
19
|
+
/** @type {Record<string, number>} */
|
|
8
20
|
let itemPositions = $state({});
|
|
21
|
+
/** @type {Record<string, HTMLElement>} */
|
|
9
22
|
let anchorGroupElements = $state({});
|
|
23
|
+
/** @type {string[]} */
|
|
10
24
|
let overflowingAnchors = $state([]);
|
|
11
25
|
|
|
12
26
|
/**
|
|
13
27
|
* Parse anchor string to determine anchor type and value
|
|
28
|
+
* @param {string | undefined} anchor
|
|
29
|
+
* @returns {{ type: string; value: string | number | null }}
|
|
14
30
|
*/
|
|
15
31
|
function parseAnchor(anchor) {
|
|
16
32
|
if (!anchor) {
|
|
@@ -41,6 +57,8 @@
|
|
|
41
57
|
|
|
42
58
|
/**
|
|
43
59
|
* Generate a unique key for an anchor (used for grouping and positioning)
|
|
60
|
+
* @param {string} anchor
|
|
61
|
+
* @returns {string}
|
|
44
62
|
*/
|
|
45
63
|
function getAnchorKey(anchor) {
|
|
46
64
|
const parsed = parseAnchor(anchor);
|
|
@@ -48,7 +66,7 @@
|
|
|
48
66
|
case 'header':
|
|
49
67
|
// For headers, use the header ID
|
|
50
68
|
const headerText = anchor.replace(/^#+\s*/, '');
|
|
51
|
-
const header = headers.find(h => h.text === headerText);
|
|
69
|
+
const header = headers.find((/** @type {HeaderType} */ h) => h.text === headerText);
|
|
52
70
|
return header ? `header:${header.id}` : `header:${anchor}`;
|
|
53
71
|
case 'paragraph':
|
|
54
72
|
return `paragraph:${parsed.value}`;
|
|
@@ -61,6 +79,7 @@
|
|
|
61
79
|
|
|
62
80
|
/**
|
|
63
81
|
* Get all unique anchors from items (preserving order)
|
|
82
|
+
* @returns {string[]}
|
|
64
83
|
*/
|
|
65
84
|
function getUniqueAnchors() {
|
|
66
85
|
const seen = new Set();
|
|
@@ -74,19 +93,26 @@
|
|
|
74
93
|
return anchors;
|
|
75
94
|
}
|
|
76
95
|
|
|
77
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Group items by their anchor
|
|
98
|
+
* @param {string} anchor
|
|
99
|
+
* @returns {GutterItemType[]}
|
|
100
|
+
*/
|
|
78
101
|
function getItemsForAnchor(anchor) {
|
|
79
|
-
return items.filter(item => item.anchor === anchor);
|
|
102
|
+
return items.filter((/** @type {GutterItemType} */ item) => item.anchor === anchor);
|
|
80
103
|
}
|
|
81
104
|
|
|
82
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Get items that don't have a valid anchor (show at top)
|
|
107
|
+
* @returns {GutterItemType[]}
|
|
108
|
+
*/
|
|
83
109
|
function getOrphanItems() {
|
|
84
|
-
return items.filter(item => {
|
|
110
|
+
return items.filter((/** @type {GutterItemType} */ item) => {
|
|
85
111
|
if (!item.anchor) return true;
|
|
86
112
|
const parsed = parseAnchor(item.anchor);
|
|
87
113
|
if (parsed.type === 'header') {
|
|
88
114
|
const headerText = item.anchor.replace(/^#+\s*/, '');
|
|
89
|
-
return !headers.find(h => h.text === headerText);
|
|
115
|
+
return !headers.find((/** @type {HeaderType} */ h) => h.text === headerText);
|
|
90
116
|
}
|
|
91
117
|
// Paragraph and tag anchors are valid if they have values
|
|
92
118
|
return parsed.type === 'none';
|
|
@@ -95,6 +121,8 @@
|
|
|
95
121
|
|
|
96
122
|
/**
|
|
97
123
|
* Find the DOM element for an anchor
|
|
124
|
+
* @param {string} anchor
|
|
125
|
+
* @returns {HTMLElement | null}
|
|
98
126
|
*/
|
|
99
127
|
function findAnchorElement(anchor) {
|
|
100
128
|
const parsed = parseAnchor(anchor);
|
|
@@ -104,7 +132,7 @@
|
|
|
104
132
|
switch (parsed.type) {
|
|
105
133
|
case 'header': {
|
|
106
134
|
const headerText = anchor.replace(/^#+\s*/, '');
|
|
107
|
-
const header = headers.find(h => h.text === headerText);
|
|
135
|
+
const header = headers.find((/** @type {HeaderType} */ h) => h.text === headerText);
|
|
108
136
|
if (header) {
|
|
109
137
|
return document.getElementById(header.id);
|
|
110
138
|
}
|
|
@@ -112,14 +140,15 @@
|
|
|
112
140
|
}
|
|
113
141
|
case 'paragraph': {
|
|
114
142
|
const paragraphs = contentEl.querySelectorAll('p');
|
|
143
|
+
if (typeof parsed.value !== 'number') return null;
|
|
115
144
|
const index = parsed.value - 1; // Convert to 0-based index
|
|
116
145
|
if (index >= 0 && index < paragraphs.length) {
|
|
117
|
-
return paragraphs[index];
|
|
146
|
+
return /** @type {HTMLElement} */ (paragraphs[index]);
|
|
118
147
|
}
|
|
119
148
|
return null;
|
|
120
149
|
}
|
|
121
150
|
case 'tag': {
|
|
122
|
-
return contentEl.querySelector(`[data-anchor="${parsed.value}"]`);
|
|
151
|
+
return /** @type {HTMLElement | null} */ (contentEl.querySelector(`[data-anchor="${parsed.value}"]`));
|
|
123
152
|
}
|
|
124
153
|
default:
|
|
125
154
|
return null;
|
|
@@ -137,13 +166,14 @@
|
|
|
137
166
|
const bottomPadding = 32; // Padding from bottom of content
|
|
138
167
|
|
|
139
168
|
let lastBottom = 0; // Track the bottom edge of the last positioned item
|
|
169
|
+
/** @type {string[]} */
|
|
140
170
|
const newOverflowingAnchors = [];
|
|
141
171
|
|
|
142
172
|
// Get all unique anchors that have items
|
|
143
173
|
const anchors = getUniqueAnchors();
|
|
144
174
|
|
|
145
175
|
// Sort anchors by their position in the document
|
|
146
|
-
const anchorPositions = anchors.map(anchor => {
|
|
176
|
+
const anchorPositions = anchors.map((/** @type {string} */ anchor) => {
|
|
147
177
|
const el = findAnchorElement(anchor);
|
|
148
178
|
return {
|
|
149
179
|
anchor,
|
|
@@ -151,9 +181,9 @@
|
|
|
151
181
|
element: el,
|
|
152
182
|
top: el ? el.offsetTop : Infinity
|
|
153
183
|
};
|
|
154
|
-
}).sort((a, b) => a.top - b.top);
|
|
184
|
+
}).sort((/** @type {{ top: number }} */ a, /** @type {{ top: number }} */ b) => a.top - b.top);
|
|
155
185
|
|
|
156
|
-
anchorPositions.forEach(({ anchor, key, element }) => {
|
|
186
|
+
anchorPositions.forEach((/** @type {{ anchor: string; key: string; element: HTMLElement | null; top: number }} */ { anchor, key, element }) => {
|
|
157
187
|
const groupEl = anchorGroupElements[key];
|
|
158
188
|
|
|
159
189
|
if (element && groupEl) {
|
|
@@ -4,14 +4,14 @@ type LeftGutter = {
|
|
|
4
4
|
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
5
|
};
|
|
6
6
|
declare const LeftGutter: import("svelte").Component<{
|
|
7
|
-
items?: any
|
|
8
|
-
headers?: any
|
|
7
|
+
items?: any;
|
|
8
|
+
headers?: any;
|
|
9
9
|
contentHeight?: number;
|
|
10
|
-
onOverflowChange?:
|
|
10
|
+
onOverflowChange?: any;
|
|
11
11
|
}, {}, "">;
|
|
12
12
|
type $$ComponentProps = {
|
|
13
|
-
items?: any
|
|
14
|
-
headers?: any
|
|
13
|
+
items?: any;
|
|
14
|
+
headers?: any;
|
|
15
15
|
contentHeight?: number;
|
|
16
|
-
onOverflowChange?:
|
|
16
|
+
onOverflowChange?: any;
|
|
17
17
|
};
|
package/dist/config/ai-models.js
CHANGED
|
@@ -23,7 +23,7 @@ const CHARS_PER_TOKEN = 4;
|
|
|
23
23
|
* @returns {{ inputTokens: number, outputTokens: number, cost: number }}
|
|
24
24
|
*/
|
|
25
25
|
export function calculateCost(content, model = 'haiku') {
|
|
26
|
-
const pricing = MODEL_PRICING[model] || MODEL_PRICING.haiku;
|
|
26
|
+
const pricing = MODEL_PRICING[/** @type {keyof typeof MODEL_PRICING} */ (model)] || MODEL_PRICING.haiku;
|
|
27
27
|
const inputTokens = Math.ceil(content.length / CHARS_PER_TOKEN);
|
|
28
28
|
// Estimate output tokens as ~10% of input for analysis tasks
|
|
29
29
|
const outputTokens = Math.ceil(inputTokens * 0.1);
|
package/dist/groveauth/client.js
CHANGED
|
@@ -190,7 +190,7 @@ export class GroveAuthClient {
|
|
|
190
190
|
code_verifier: codeVerifier,
|
|
191
191
|
}),
|
|
192
192
|
});
|
|
193
|
-
const data = await response.json();
|
|
193
|
+
const data = (await response.json());
|
|
194
194
|
if (!response.ok) {
|
|
195
195
|
throw new GroveAuthError(data.error || "token_error", data.error_description || data.message || "Failed to exchange code", response.status);
|
|
196
196
|
}
|
|
@@ -219,7 +219,7 @@ export class GroveAuthClient {
|
|
|
219
219
|
client_secret: this.config.clientSecret,
|
|
220
220
|
}),
|
|
221
221
|
});
|
|
222
|
-
const data = await response.json();
|
|
222
|
+
const data = (await response.json());
|
|
223
223
|
if (!response.ok) {
|
|
224
224
|
throw new GroveAuthError(data.error || "refresh_error", data.error_description || data.message || "Failed to refresh token", response.status);
|
|
225
225
|
}
|
|
@@ -255,7 +255,7 @@ export class GroveAuthClient {
|
|
|
255
255
|
}),
|
|
256
256
|
});
|
|
257
257
|
if (!response.ok) {
|
|
258
|
-
const data = await response.json();
|
|
258
|
+
const data = (await response.json());
|
|
259
259
|
throw new GroveAuthError(data.error || "revoke_error", data.error_description || data.message || "Failed to revoke token", response.status);
|
|
260
260
|
}
|
|
261
261
|
}
|
|
@@ -287,7 +287,7 @@ export class GroveAuthClient {
|
|
|
287
287
|
},
|
|
288
288
|
});
|
|
289
289
|
if (!response.ok) {
|
|
290
|
-
const data = await response.json();
|
|
290
|
+
const data = (await response.json());
|
|
291
291
|
throw new GroveAuthError(data.error || "userinfo_error", data.error_description || data.message || "Failed to get user info", response.status);
|
|
292
292
|
}
|
|
293
293
|
return response.json();
|
|
@@ -305,7 +305,7 @@ export class GroveAuthClient {
|
|
|
305
305
|
},
|
|
306
306
|
});
|
|
307
307
|
if (!response.ok) {
|
|
308
|
-
const data = await response.json();
|
|
308
|
+
const data = (await response.json());
|
|
309
309
|
throw new GroveAuthError(data.error || "subscription_error", data.message || "Failed to get subscription", response.status);
|
|
310
310
|
}
|
|
311
311
|
return response.json();
|
|
@@ -359,7 +359,7 @@ export class GroveAuthClient {
|
|
|
359
359
|
},
|
|
360
360
|
});
|
|
361
361
|
if (!response.ok) {
|
|
362
|
-
const data = await response.json();
|
|
362
|
+
const data = (await response.json());
|
|
363
363
|
throw new GroveAuthError(data.error || "subscription_error", data.message || "Failed to get subscription", response.status);
|
|
364
364
|
}
|
|
365
365
|
const data = (await response.json());
|
|
@@ -381,7 +381,7 @@ export class GroveAuthClient {
|
|
|
381
381
|
},
|
|
382
382
|
});
|
|
383
383
|
if (!response.ok) {
|
|
384
|
-
const data = await response.json();
|
|
384
|
+
const data = (await response.json());
|
|
385
385
|
throw new GroveAuthError(data.error || "limit_check_error", data.message || "Failed to check post limit", response.status);
|
|
386
386
|
}
|
|
387
387
|
return response.json();
|
|
@@ -401,7 +401,7 @@ export class GroveAuthClient {
|
|
|
401
401
|
body: JSON.stringify({ action: "increment" }),
|
|
402
402
|
});
|
|
403
403
|
if (!response.ok) {
|
|
404
|
-
const data = await response.json();
|
|
404
|
+
const data = (await response.json());
|
|
405
405
|
throw new GroveAuthError(data.error || "count_error", data.message || "Failed to update post count", response.status);
|
|
406
406
|
}
|
|
407
407
|
const data = (await response.json());
|
|
@@ -427,7 +427,7 @@ export class GroveAuthClient {
|
|
|
427
427
|
body: JSON.stringify({ action: "decrement" }),
|
|
428
428
|
});
|
|
429
429
|
if (!response.ok) {
|
|
430
|
-
const data = await response.json();
|
|
430
|
+
const data = (await response.json());
|
|
431
431
|
throw new GroveAuthError(data.error || "count_error", data.message || "Failed to update post count", response.status);
|
|
432
432
|
}
|
|
433
433
|
const data = (await response.json());
|
|
@@ -453,7 +453,7 @@ export class GroveAuthClient {
|
|
|
453
453
|
body: JSON.stringify({ count }),
|
|
454
454
|
});
|
|
455
455
|
if (!response.ok) {
|
|
456
|
-
const data = await response.json();
|
|
456
|
+
const data = (await response.json());
|
|
457
457
|
throw new GroveAuthError(data.error || "count_error", data.message || "Failed to update post count", response.status);
|
|
458
458
|
}
|
|
459
459
|
const data = (await response.json());
|
|
@@ -479,7 +479,7 @@ export class GroveAuthClient {
|
|
|
479
479
|
body: JSON.stringify({ tier }),
|
|
480
480
|
});
|
|
481
481
|
if (!response.ok) {
|
|
482
|
-
const data = await response.json();
|
|
482
|
+
const data = (await response.json());
|
|
483
483
|
throw new GroveAuthError(data.error || "tier_error", data.message || "Failed to update tier", response.status);
|
|
484
484
|
}
|
|
485
485
|
const data = (await response.json());
|
package/dist/index.d.ts
CHANGED
|
@@ -13,4 +13,6 @@ export { default as LightboxCaption } from './ui/components/gallery/LightboxCapt
|
|
|
13
13
|
export { default as ZoomableImage } from './ui/components/gallery/ZoomableImage.svelte';
|
|
14
14
|
export * from './ui/index';
|
|
15
15
|
export { cn } from './utils/cn';
|
|
16
|
-
export
|
|
16
|
+
export { GroveAuthClient, createGroveAuthClient, generateCodeVerifier, generateCodeChallenge, generateState, GroveAuthError, TIER_POST_LIMITS, TIER_NAMES, getQuotaDescription, getQuotaUrgency, getSuggestedActions, getUpgradeRecommendation, getQuotaWidgetData, getPreSubmitCheck, STATUS_COLORS, ALERT_VARIANTS, getStatusColorFromPercentage, getAlertVariantFromColor, RateLimiter, RateLimitError, withRateLimit, DEFAULT_RATE_LIMITS, } from './groveauth/index';
|
|
17
|
+
export type { GroveAuthConfig, TokenResponse, TokenInfo, UserInfo, LoginUrlResult, UserSubscription, SubscriptionStatus, SubscriptionResponse, CanPostResponse, SubscriptionTier, AuthError, QuotaWidgetData, PreSubmitCheckResult, AlertVariant, } from './groveauth/index';
|
|
18
|
+
export type { StatusColor as GroveAuthStatusColor } from './groveauth/index';
|
package/dist/index.js
CHANGED
|
@@ -20,5 +20,5 @@ export { default as ZoomableImage } from './ui/components/gallery/ZoomableImage.
|
|
|
20
20
|
export * from './ui/index';
|
|
21
21
|
// Utilities
|
|
22
22
|
export { cn } from './utils/cn';
|
|
23
|
-
// GroveAuth client (re-export
|
|
24
|
-
export
|
|
23
|
+
// GroveAuth client (re-export explicitly to avoid StatusColor conflict with UI)
|
|
24
|
+
export { GroveAuthClient, createGroveAuthClient, generateCodeVerifier, generateCodeChallenge, generateState, GroveAuthError, TIER_POST_LIMITS, TIER_NAMES, getQuotaDescription, getQuotaUrgency, getSuggestedActions, getUpgradeRecommendation, getQuotaWidgetData, getPreSubmitCheck, STATUS_COLORS, ALERT_VARIANTS, getStatusColorFromPercentage, getAlertVariantFromColor, RateLimiter, RateLimitError, withRateLimit, DEFAULT_RATE_LIMITS, } from './groveauth/index';
|
package/dist/server/logger.d.ts
CHANGED
|
@@ -1,53 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side logging utility with in-memory circular buffers
|
|
3
|
+
* Supports real-time log streaming to admin console
|
|
4
|
+
*/
|
|
5
|
+
/** Log severity levels */
|
|
6
|
+
export type LogLevel = "info" | "warn" | "error" | "success";
|
|
7
|
+
/** Log categories */
|
|
8
|
+
export type LogCategory = "api" | "github" | "errors" | "cache";
|
|
9
|
+
/** Metadata for API logs */
|
|
10
|
+
export interface APIMetadata {
|
|
11
|
+
endpoint?: string;
|
|
12
|
+
method?: string;
|
|
13
|
+
status?: number;
|
|
14
|
+
duration?: number;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Metadata for GitHub logs */
|
|
18
|
+
export interface GitHubMetadata {
|
|
19
|
+
error?: boolean;
|
|
20
|
+
warning?: boolean;
|
|
21
|
+
rateLimit?: {
|
|
22
|
+
remaining: number;
|
|
23
|
+
limit: number;
|
|
24
|
+
};
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
/** Metadata for error logs */
|
|
28
|
+
export interface ErrorMetadata {
|
|
29
|
+
error?: {
|
|
30
|
+
message: string;
|
|
31
|
+
stack?: string;
|
|
32
|
+
name: string;
|
|
33
|
+
} | null;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
/** Metadata for cache logs */
|
|
37
|
+
export interface CacheMetadata {
|
|
38
|
+
operation?: string;
|
|
39
|
+
key?: string;
|
|
40
|
+
error?: boolean;
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
/** Log entry structure */
|
|
44
|
+
export interface LogEntry {
|
|
45
|
+
id: string;
|
|
46
|
+
timestamp: string;
|
|
47
|
+
level: LogLevel;
|
|
48
|
+
category: LogCategory;
|
|
49
|
+
message: string;
|
|
50
|
+
metadata: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
/** Log statistics for a category */
|
|
53
|
+
export interface CategoryStats {
|
|
54
|
+
total: number;
|
|
55
|
+
recent: number;
|
|
56
|
+
}
|
|
57
|
+
/** Overall log statistics */
|
|
58
|
+
export interface LogStats {
|
|
59
|
+
api: CategoryStats;
|
|
60
|
+
github: CategoryStats;
|
|
61
|
+
errors: CategoryStats;
|
|
62
|
+
cache: CategoryStats;
|
|
63
|
+
}
|
|
64
|
+
/** Subscriber callback type */
|
|
65
|
+
export type LogSubscriber = (log: LogEntry) => void;
|
|
1
66
|
/**
|
|
2
67
|
* Log API activity (requests, responses, timing)
|
|
3
68
|
*/
|
|
4
|
-
export function logAPI(endpoint:
|
|
69
|
+
export declare function logAPI(endpoint: string, method: string, status: number, metadata?: APIMetadata): void;
|
|
5
70
|
/**
|
|
6
71
|
* Log GitHub API operations (rate limits, queries, errors)
|
|
7
72
|
*/
|
|
8
|
-
export function logGitHub(operation:
|
|
73
|
+
export declare function logGitHub(operation: string, metadata?: GitHubMetadata): void;
|
|
9
74
|
/**
|
|
10
75
|
* Log errors (exceptions, failed operations, validation errors)
|
|
11
76
|
*/
|
|
12
|
-
export function logError(message:
|
|
77
|
+
export declare function logError(message: string, error?: Error | null, metadata?: Record<string, unknown>): void;
|
|
13
78
|
/**
|
|
14
79
|
* Log cache operations (KV get/set, hits/misses)
|
|
15
80
|
*/
|
|
16
|
-
export function logCache(operation:
|
|
81
|
+
export declare function logCache(operation: string, key: string, metadata?: CacheMetadata): void;
|
|
17
82
|
/**
|
|
18
83
|
* Get logs from a specific category
|
|
19
84
|
*/
|
|
20
|
-
export function getLogs(category:
|
|
85
|
+
export declare function getLogs(category: LogCategory, since?: string | null): LogEntry[];
|
|
21
86
|
/**
|
|
22
87
|
* Get all logs across all categories
|
|
23
88
|
*/
|
|
24
|
-
export function getAllLogs(since?: null):
|
|
89
|
+
export declare function getAllLogs(since?: string | null): LogEntry[];
|
|
25
90
|
/**
|
|
26
91
|
* Get log statistics
|
|
27
92
|
*/
|
|
28
|
-
export function getLogStats():
|
|
29
|
-
api: {
|
|
30
|
-
total: number;
|
|
31
|
-
recent: number;
|
|
32
|
-
};
|
|
33
|
-
github: {
|
|
34
|
-
total: number;
|
|
35
|
-
recent: number;
|
|
36
|
-
};
|
|
37
|
-
errors: {
|
|
38
|
-
total: number;
|
|
39
|
-
recent: number;
|
|
40
|
-
};
|
|
41
|
-
cache: {
|
|
42
|
-
total: number;
|
|
43
|
-
recent: number;
|
|
44
|
-
};
|
|
45
|
-
};
|
|
93
|
+
export declare function getLogStats(): LogStats;
|
|
46
94
|
/**
|
|
47
95
|
* Subscribe to log events (for SSE streaming)
|
|
48
96
|
*/
|
|
49
|
-
export function subscribe(callback:
|
|
97
|
+
export declare function subscribe(callback: LogSubscriber): () => boolean;
|
|
50
98
|
/**
|
|
51
99
|
* Clear logs for a specific category or all categories
|
|
52
100
|
*/
|
|
53
|
-
export function clearLogs(category?: null): void;
|
|
101
|
+
export declare function clearLogs(category?: LogCategory | null): void;
|