@autumnsgrove/groveengine 0.6.2 → 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.
Files changed (77) hide show
  1. package/dist/auth/jwt.d.ts +10 -4
  2. package/dist/auth/jwt.js +18 -4
  3. package/dist/auth/session.d.ts +22 -15
  4. package/dist/auth/session.js +35 -16
  5. package/dist/components/admin/GutterManager.svelte +81 -139
  6. package/dist/components/admin/GutterManager.svelte.d.ts +6 -6
  7. package/dist/components/admin/MarkdownEditor.svelte +80 -23
  8. package/dist/components/admin/MarkdownEditor.svelte.d.ts +14 -8
  9. package/dist/components/admin/composables/useAmbientSounds.svelte.d.ts +52 -2
  10. package/dist/components/admin/composables/useAmbientSounds.svelte.js +38 -4
  11. package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +80 -10
  12. package/dist/components/admin/composables/useCommandPalette.svelte.js +45 -5
  13. package/dist/components/admin/composables/useDraftManager.svelte.d.ts +76 -14
  14. package/dist/components/admin/composables/useDraftManager.svelte.js +44 -10
  15. package/dist/components/admin/composables/useEditorTheme.svelte.d.ts +168 -2
  16. package/dist/components/admin/composables/useEditorTheme.svelte.js +40 -7
  17. package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +94 -22
  18. package/dist/components/admin/composables/useSlashCommands.svelte.js +58 -9
  19. package/dist/components/admin/composables/useSnippets.svelte.d.ts +51 -2
  20. package/dist/components/admin/composables/useSnippets.svelte.js +35 -3
  21. package/dist/components/admin/composables/useWritingSession.svelte.d.ts +64 -6
  22. package/dist/components/admin/composables/useWritingSession.svelte.js +42 -5
  23. package/dist/components/custom/ContentWithGutter.svelte +53 -23
  24. package/dist/components/custom/ContentWithGutter.svelte.d.ts +6 -14
  25. package/dist/components/custom/GutterItem.svelte +1 -1
  26. package/dist/components/custom/LeftGutter.svelte +43 -13
  27. package/dist/components/custom/LeftGutter.svelte.d.ts +6 -6
  28. package/dist/config/ai-models.js +1 -1
  29. package/dist/groveauth/client.js +11 -11
  30. package/dist/index.d.ts +3 -1
  31. package/dist/index.js +2 -2
  32. package/dist/server/logger.d.ts +74 -26
  33. package/dist/server/logger.js +133 -184
  34. package/dist/server/services/cache.js +1 -10
  35. package/dist/ui/components/charts/ActivityOverview.svelte +14 -3
  36. package/dist/ui/components/charts/ActivityOverview.svelte.d.ts +10 -7
  37. package/dist/ui/components/charts/RepoBreakdown.svelte +9 -3
  38. package/dist/ui/components/charts/RepoBreakdown.svelte.d.ts +12 -11
  39. package/dist/ui/components/charts/Sparkline.svelte +18 -7
  40. package/dist/ui/components/charts/Sparkline.svelte.d.ts +21 -2
  41. package/dist/ui/components/gallery/ImageGallery.svelte +12 -8
  42. package/dist/ui/components/gallery/ImageGallery.svelte.d.ts +2 -2
  43. package/dist/ui/components/gallery/Lightbox.svelte +5 -2
  44. package/dist/ui/components/gallery/ZoomableImage.svelte +8 -5
  45. package/dist/ui/components/primitives/accordion/index.d.ts +1 -1
  46. package/dist/ui/components/primitives/input/input.svelte.d.ts +1 -1
  47. package/dist/ui/components/primitives/tabs/index.d.ts +1 -1
  48. package/dist/ui/components/primitives/textarea/textarea.svelte.d.ts +1 -1
  49. package/dist/ui/components/ui/Button.svelte +5 -0
  50. package/dist/ui/components/ui/Button.svelte.d.ts +4 -1
  51. package/dist/ui/components/ui/Input.svelte +4 -0
  52. package/dist/ui/components/ui/Input.svelte.d.ts +3 -1
  53. package/dist/ui/components/ui/Logo.svelte +86 -0
  54. package/dist/ui/components/ui/Logo.svelte.d.ts +25 -0
  55. package/dist/ui/components/ui/LogoLoader.svelte +71 -0
  56. package/dist/ui/components/ui/LogoLoader.svelte.d.ts +9 -0
  57. package/dist/ui/components/ui/index.d.ts +2 -0
  58. package/dist/ui/components/ui/index.js +2 -0
  59. package/dist/ui/tailwind.preset.js +8 -8
  60. package/dist/utils/api.js +2 -1
  61. package/dist/utils/debounce.d.ts +4 -3
  62. package/dist/utils/debounce.js +10 -6
  63. package/dist/utils/gallery.d.ts +58 -32
  64. package/dist/utils/gallery.js +111 -129
  65. package/dist/utils/gutter.d.ts +47 -26
  66. package/dist/utils/gutter.js +116 -124
  67. package/dist/utils/imageProcessor.d.ts +66 -19
  68. package/dist/utils/imageProcessor.js +31 -10
  69. package/dist/utils/index.d.ts +11 -11
  70. package/dist/utils/index.js +4 -3
  71. package/dist/utils/json.js +1 -1
  72. package/dist/utils/markdown.d.ts +183 -103
  73. package/dist/utils/markdown.js +517 -678
  74. package/dist/utils/sanitize.d.ts +22 -12
  75. package/dist/utils/sanitize.js +268 -282
  76. package/dist/utils/validation.js +4 -3
  77. package/package.json +3 -2
@@ -2,251 +2,200 @@
2
2
  * Server-side logging utility with in-memory circular buffers
3
3
  * Supports real-time log streaming to admin console
4
4
  */
5
-
6
5
  // Circular buffer implementation
7
6
  class CircularBuffer {
8
- constructor(maxSize = 1000) {
9
- this.maxSize = maxSize;
10
- this.buffer = [];
11
- }
12
-
13
- push(item) {
14
- this.buffer.push(item);
15
- if (this.buffer.length > this.maxSize) {
16
- this.buffer.shift(); // Remove oldest item
7
+ maxSize;
8
+ buffer;
9
+ constructor(maxSize = 1000) {
10
+ this.maxSize = maxSize;
11
+ this.buffer = [];
12
+ }
13
+ push(item) {
14
+ this.buffer.push(item);
15
+ if (this.buffer.length > this.maxSize) {
16
+ this.buffer.shift(); // Remove oldest item
17
+ }
18
+ }
19
+ getAll() {
20
+ return [...this.buffer]; // Return copy to prevent external mutations
21
+ }
22
+ getSince(timestamp) {
23
+ return this.buffer.filter((log) => new Date(log.timestamp) > new Date(timestamp));
24
+ }
25
+ clear() {
26
+ this.buffer = [];
27
+ }
28
+ get length() {
29
+ return this.buffer.length;
17
30
  }
18
- }
19
-
20
- getAll() {
21
- return [...this.buffer]; // Return copy to prevent external mutations
22
- }
23
-
24
- getSince(timestamp) {
25
- return this.buffer.filter(
26
- (log) => new Date(log.timestamp) > new Date(timestamp),
27
- );
28
- }
29
-
30
- clear() {
31
- this.buffer = [];
32
- }
33
-
34
- get length() {
35
- return this.buffer.length;
36
- }
37
31
  }
38
-
39
32
  // Log buffers for each category (module-level, persists across requests in same worker)
40
33
  const logBuffers = {
41
- api: new CircularBuffer(1000),
42
- github: new CircularBuffer(500),
43
- errors: new CircularBuffer(500),
44
- cache: new CircularBuffer(1000),
34
+ api: new CircularBuffer(1000),
35
+ github: new CircularBuffer(500),
36
+ errors: new CircularBuffer(500),
37
+ cache: new CircularBuffer(1000),
45
38
  };
46
-
47
39
  // Subscribers for SSE streaming
48
40
  const subscribers = new Set();
49
-
50
41
  /**
51
42
  * Create a log entry with consistent format
52
43
  */
53
44
  function createLogEntry(level, category, message, metadata = {}) {
54
- return {
55
- id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
56
- timestamp: new Date().toISOString(),
57
- level, // 'info' | 'warn' | 'error' | 'success'
58
- category, // 'api' | 'github' | 'errors' | 'cache'
59
- message,
60
- metadata,
61
- };
45
+ return {
46
+ id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
47
+ timestamp: new Date().toISOString(),
48
+ level,
49
+ category,
50
+ message,
51
+ metadata,
52
+ };
62
53
  }
63
-
64
54
  /**
65
55
  * Broadcast log to all SSE subscribers
66
56
  */
67
57
  function broadcast(log) {
68
- subscribers.forEach((subscriber) => {
69
- try {
70
- subscriber(log);
71
- } catch (error) {
72
- console.error("[Logger] Failed to broadcast to subscriber:", error);
73
- }
74
- });
58
+ subscribers.forEach((subscriber) => {
59
+ try {
60
+ subscriber(log);
61
+ }
62
+ catch (error) {
63
+ console.error("[Logger] Failed to broadcast to subscriber:", error);
64
+ }
65
+ });
75
66
  }
76
-
77
67
  /**
78
68
  * Log API activity (requests, responses, timing)
79
69
  */
80
70
  export function logAPI(endpoint, method, status, metadata = {}) {
81
- const level =
82
- status >= 500
83
- ? "error"
84
- : status >= 400
85
- ? "warn"
86
- : status >= 200
87
- ? "success"
88
- : "info";
89
- const log = createLogEntry(
90
- level,
91
- "api",
92
- `${method} ${endpoint} → ${status}`,
93
- {
94
- endpoint,
95
- method,
96
- status,
97
- ...metadata,
98
- },
99
- );
100
-
101
- logBuffers.api.push(log);
102
- broadcast(log);
103
-
104
- // Also log to console in development
105
- if (metadata.duration) {
106
- console.log(
107
- `[API] ${method} ${endpoint} ${status} (${metadata.duration}ms)`,
108
- );
109
- }
71
+ const level = status >= 500
72
+ ? "error"
73
+ : status >= 400
74
+ ? "warn"
75
+ : status >= 200
76
+ ? "success"
77
+ : "info";
78
+ const log = createLogEntry(level, "api", `${method} ${endpoint} → ${status}`, {
79
+ endpoint,
80
+ method,
81
+ status,
82
+ ...metadata,
83
+ });
84
+ logBuffers.api.push(log);
85
+ broadcast(log);
86
+ // Also log to console in development
87
+ if (metadata.duration) {
88
+ console.log(`[API] ${method} ${endpoint} ${status} (${metadata.duration}ms)`);
89
+ }
110
90
  }
111
-
112
91
  /**
113
92
  * Log GitHub API operations (rate limits, queries, errors)
114
93
  */
115
94
  export function logGitHub(operation, metadata = {}) {
116
- const level = metadata.error ? "error" : metadata.warning ? "warn" : "info";
117
- const log = createLogEntry(level, "github", operation, metadata);
118
-
119
- logBuffers.github.push(log);
120
- broadcast(log);
121
-
122
- console.log(
123
- `[GitHub] ${operation}`,
124
- metadata.rateLimit
125
- ? `(${metadata.rateLimit.remaining}/${metadata.rateLimit.limit} remaining)`
126
- : "",
127
- );
95
+ const level = metadata.error ? "error" : metadata.warning ? "warn" : "info";
96
+ const log = createLogEntry(level, "github", operation, metadata);
97
+ logBuffers.github.push(log);
98
+ broadcast(log);
99
+ console.log(`[GitHub] ${operation}`, metadata.rateLimit
100
+ ? `(${metadata.rateLimit.remaining}/${metadata.rateLimit.limit} remaining)`
101
+ : "");
128
102
  }
129
-
130
103
  /**
131
104
  * Log errors (exceptions, failed operations, validation errors)
132
105
  */
133
106
  export function logError(message, error = null, metadata = {}) {
134
- const log = createLogEntry("error", "errors", message, {
135
- error: error
136
- ? {
137
- message: error.message,
138
- stack: error.stack,
139
- name: error.name,
140
- }
141
- : null,
142
- ...metadata,
143
- });
144
-
145
- logBuffers.errors.push(log);
146
- broadcast(log);
147
-
148
- console.error(`[Error] ${message}`, error || "");
107
+ const log = createLogEntry("error", "errors", message, {
108
+ error: error
109
+ ? {
110
+ message: error.message,
111
+ stack: error.stack,
112
+ name: error.name,
113
+ }
114
+ : null,
115
+ ...metadata,
116
+ });
117
+ logBuffers.errors.push(log);
118
+ broadcast(log);
119
+ console.error(`[Error] ${message}`, error || "");
149
120
  }
150
-
151
121
  /**
152
122
  * Log cache operations (KV get/set, hits/misses)
153
123
  */
154
124
  export function logCache(operation, key, metadata = {}) {
155
- const level = metadata.error ? "error" : "info";
156
- const log = createLogEntry(
157
- level,
158
- "cache",
159
- `${operation.toUpperCase()} ${key}`,
160
- {
161
- operation, // 'get', 'set', 'delete'
162
- key,
163
- ...metadata,
164
- },
165
- );
166
-
167
- logBuffers.cache.push(log);
168
- broadcast(log);
125
+ const level = metadata.error ? "error" : "info";
126
+ const log = createLogEntry(level, "cache", `${operation.toUpperCase()} ${key}`, {
127
+ operation,
128
+ key,
129
+ ...metadata,
130
+ });
131
+ logBuffers.cache.push(log);
132
+ broadcast(log);
169
133
  }
170
-
171
134
  /**
172
135
  * Get logs from a specific category
173
136
  */
174
137
  export function getLogs(category, since = null) {
175
- if (!logBuffers[category]) {
176
- return [];
177
- }
178
-
179
- if (since) {
180
- return logBuffers[category].getSince(since);
181
- }
182
-
183
- return logBuffers[category].getAll();
138
+ if (!logBuffers[category]) {
139
+ return [];
140
+ }
141
+ if (since) {
142
+ return logBuffers[category].getSince(since);
143
+ }
144
+ return logBuffers[category].getAll();
184
145
  }
185
-
186
146
  /**
187
147
  * Get all logs across all categories
188
148
  */
189
149
  export function getAllLogs(since = null) {
190
- const allLogs = [];
191
-
192
- for (const category of Object.keys(logBuffers)) {
193
- const logs = since
194
- ? logBuffers[category].getSince(since)
195
- : logBuffers[category].getAll();
196
- allLogs.push(...logs);
197
- }
198
-
199
- // Sort by timestamp (newest first)
200
- return allLogs.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
150
+ const allLogs = [];
151
+ for (const category of Object.keys(logBuffers)) {
152
+ const logs = since
153
+ ? logBuffers[category].getSince(since)
154
+ : logBuffers[category].getAll();
155
+ allLogs.push(...logs);
156
+ }
157
+ // Sort by timestamp (newest first)
158
+ return allLogs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
201
159
  }
202
-
203
160
  /**
204
161
  * Get log statistics
205
162
  */
206
163
  export function getLogStats() {
207
- return {
208
- api: {
209
- total: logBuffers.api.length,
210
- recent: logBuffers.api.getSince(
211
- new Date(Date.now() - 60000).toISOString(),
212
- ).length, // Last minute
213
- },
214
- github: {
215
- total: logBuffers.github.length,
216
- recent: logBuffers.github.getSince(
217
- new Date(Date.now() - 60000).toISOString(),
218
- ).length,
219
- },
220
- errors: {
221
- total: logBuffers.errors.length,
222
- recent: logBuffers.errors.getSince(
223
- new Date(Date.now() - 60000).toISOString(),
224
- ).length,
225
- },
226
- cache: {
227
- total: logBuffers.cache.length,
228
- recent: logBuffers.cache.getSince(
229
- new Date(Date.now() - 60000).toISOString(),
230
- ).length,
231
- },
232
- };
164
+ const oneMinuteAgo = new Date(Date.now() - 60000).toISOString();
165
+ return {
166
+ api: {
167
+ total: logBuffers.api.length,
168
+ recent: logBuffers.api.getSince(oneMinuteAgo).length,
169
+ },
170
+ github: {
171
+ total: logBuffers.github.length,
172
+ recent: logBuffers.github.getSince(oneMinuteAgo).length,
173
+ },
174
+ errors: {
175
+ total: logBuffers.errors.length,
176
+ recent: logBuffers.errors.getSince(oneMinuteAgo).length,
177
+ },
178
+ cache: {
179
+ total: logBuffers.cache.length,
180
+ recent: logBuffers.cache.getSince(oneMinuteAgo).length,
181
+ },
182
+ };
233
183
  }
234
-
235
184
  /**
236
185
  * Subscribe to log events (for SSE streaming)
237
186
  */
238
187
  export function subscribe(callback) {
239
- subscribers.add(callback);
240
- return () => subscribers.delete(callback);
188
+ subscribers.add(callback);
189
+ return () => subscribers.delete(callback);
241
190
  }
242
-
243
191
  /**
244
192
  * Clear logs for a specific category or all categories
245
193
  */
246
194
  export function clearLogs(category = null) {
247
- if (category && logBuffers[category]) {
248
- logBuffers[category].clear();
249
- } else if (!category) {
250
- Object.values(logBuffers).forEach((buffer) => buffer.clear());
251
- }
195
+ if (category && logBuffers[category]) {
196
+ logBuffers[category].clear();
197
+ }
198
+ else if (!category) {
199
+ Object.values(logBuffers).forEach((buffer) => buffer.clear());
200
+ }
252
201
  }
@@ -1,13 +1,4 @@
1
- /**
2
- * Cache Service - KV Key-Value Store Abstraction
3
- *
4
- * Provides typed caching operations with:
5
- * - Automatic JSON serialization/deserialization
6
- * - TTL management with sensible defaults
7
- * - Namespace prefixing to avoid key collisions
8
- * - Compute-if-missing pattern (getOrSet)
9
- * - Specific error types for debugging
10
- */
1
+ /// <reference types="@cloudflare/workers-types" />
11
2
  // ============================================================================
12
3
  // Errors
13
4
  // ============================================================================
@@ -9,16 +9,26 @@
9
9
  import Sparkline from './Sparkline.svelte';
10
10
 
11
11
  /**
12
- * @type {{ activity_date: string, commit_count: number }[]}
12
+ * @typedef {Object} ActivityData
13
+ * @property {string} activity_date
14
+ * @property {number} commit_count
13
15
  */
16
+
17
+ /**
18
+ * @typedef {Object} LocData
19
+ * @property {number} additions
20
+ * @property {number} deletions
21
+ */
22
+
14
23
  let {
15
- data = [],
16
- locData = { additions: 0, deletions: 0 }, // LOC from separate DB fetch
24
+ data = /** @type {ActivityData[]} */ ([]),
25
+ locData = /** @type {LocData} */ ({ additions: 0, deletions: 0 }),
17
26
  days = 14
18
27
  } = $props();
19
28
 
20
29
  // Format date as YYYY-MM-DD in local timezone (not UTC!)
21
30
  // This matches how GitHub attributes contributions to user's timezone
31
+ /** @param {Date} date */
22
32
  function formatDateKey(date) {
23
33
  const year = date.getFullYear();
24
34
  const month = String(date.getMonth() + 1).padStart(2, '0');
@@ -61,6 +71,7 @@
61
71
  const peakCommits = $derived(Math.max(...filledData().map(d => d.commits), 0));
62
72
 
63
73
  // Get intensity level for heatmap (0-4)
74
+ /** @param {number} commits */
64
75
  function getIntensity(commits) {
65
76
  if (commits === 0) return 0;
66
77
  if (commits <= 2) return 1;
@@ -1,12 +1,15 @@
1
1
  export default ActivityOverview;
2
2
  type ActivityOverview = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: ({
5
- activity_date: string;
6
- commit_count: number;
7
- } | undefined)[]): void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
8
5
  };
9
6
  declare const ActivityOverview: import("svelte").Component<{
10
- activity_date: string;
11
- commit_count: number;
12
- }[], {}, "">;
7
+ data?: any;
8
+ locData?: any;
9
+ days?: number;
10
+ }, {}, "">;
11
+ type $$ComponentProps = {
12
+ data?: any;
13
+ locData?: any;
14
+ days?: number;
15
+ };
@@ -5,11 +5,16 @@
5
5
  */
6
6
 
7
7
  /**
8
- * @type {{ name: string, commits?: number, additions?: number, deletions?: number }[]}
8
+ * @typedef {Object} RepoData
9
+ * @property {string} name
10
+ * @property {number} [commits]
11
+ * @property {number} [additions]
12
+ * @property {number} [deletions]
9
13
  */
14
+
10
15
  let {
11
- repos = [],
12
- mode = 'commits', // 'commits' or 'loc'
16
+ repos = /** @type {RepoData[]} */ ([]),
17
+ mode = /** @type {'commits' | 'loc'} */ ('commits'),
13
18
  maxWidth = 150,
14
19
  showLegend = true
15
20
  } = $props();
@@ -33,6 +38,7 @@
33
38
  return repos.reduce((sum, r) => sum + (r.additions || 0) + (r.deletions || 0), 0) || 1;
34
39
  }
35
40
 
41
+ /** @param {RepoData} repo */
36
42
  function getValue(repo) {
37
43
  if (mode === 'commits') {
38
44
  return repo.commits || 1;
@@ -1,16 +1,17 @@
1
1
  export default RepoBreakdown;
2
2
  type RepoBreakdown = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: ({
5
- name: string;
6
- commits?: number | undefined;
7
- additions?: number | undefined;
8
- deletions?: number | undefined;
9
- } | undefined)[]): void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
10
5
  };
11
6
  declare const RepoBreakdown: import("svelte").Component<{
12
- name: string;
13
- commits?: number;
14
- additions?: number;
15
- deletions?: number;
16
- }[], {}, "">;
7
+ repos?: any;
8
+ mode?: any;
9
+ maxWidth?: number;
10
+ showLegend?: boolean;
11
+ }, {}, "">;
12
+ type $$ComponentProps = {
13
+ repos?: any;
14
+ mode?: any;
15
+ maxWidth?: number;
16
+ showLegend?: boolean;
17
+ };
@@ -4,9 +4,20 @@
4
4
  * Shows activity trend over time (commits, LOC, etc.)
5
5
  */
6
6
 
7
- /** @type {number[]} */
7
+ /**
8
+ * @typedef {Object} SparklineProps
9
+ * @property {number[]} [data] - Data points for the sparkline
10
+ * @property {number} [width] - Width of the chart
11
+ * @property {number} [height] - Height of the chart
12
+ * @property {string} [strokeColor] - Line color
13
+ * @property {string} [fillColor] - Fill color for area
14
+ * @property {number} [strokeWidth] - Line thickness
15
+ * @property {boolean} [showDots] - Show data point dots
16
+ * @property {boolean} [showArea] - Show filled area
17
+ */
18
+
8
19
  let {
9
- data = [],
20
+ data = /** @type {number[]} */ ([]),
10
21
  width = 120,
11
22
  height = 24,
12
23
  strokeColor = '#5cb85f',
@@ -24,14 +35,14 @@
24
35
  const min = Math.min(...data, 0);
25
36
  const range = max - min || 1;
26
37
 
27
- const points = data.map((value, i) => {
38
+ const points = data.map((/** @type {number} */ value, /** @type {number} */ i) => {
28
39
  const x = (i / (data.length - 1)) * width;
29
40
  const y = height - ((value - min) / range) * (height - 4) - 2; // 2px padding
30
41
  return { x, y };
31
42
  });
32
43
 
33
44
  // Create line path
34
- const linePath = points.map((p, i) =>
45
+ const linePath = points.map((/** @type {{ x: number, y: number }} */ p, /** @type {number} */ i) =>
35
46
  `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`
36
47
  ).join(' ');
37
48
 
@@ -45,14 +56,14 @@
45
56
  const min = Math.min(...data, 0);
46
57
  const range = max - min || 1;
47
58
 
48
- const points = data.map((value, i) => {
59
+ const points = data.map((/** @type {number} */ value, /** @type {number} */ i) => {
49
60
  const x = (i / (data.length - 1)) * width;
50
61
  const y = height - ((value - min) / range) * (height - 4) - 2;
51
62
  return { x, y };
52
63
  });
53
64
 
54
65
  // Create closed area path
55
- const linePath = points.map((p, i) =>
66
+ const linePath = points.map((/** @type {{ x: number, y: number }} */ p, /** @type {number} */ i) =>
56
67
  `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`
57
68
  ).join(' ');
58
69
 
@@ -66,7 +77,7 @@
66
77
  const min = Math.min(...data, 0);
67
78
  const range = max - min || 1;
68
79
 
69
- return data.map((value, i) => ({
80
+ return data.map((/** @type {number} */ value, /** @type {number} */ i) => ({
70
81
  x: (i / (data.length - 1)) * width,
71
82
  y: height - ((value - min) / range) * (height - 4) - 2,
72
83
  value
@@ -1,6 +1,25 @@
1
1
  export default Sparkline;
2
2
  type Sparkline = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: (number | undefined)[]): void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Sparkline: import("svelte").Component<{
7
+ data?: any;
8
+ width?: number;
9
+ height?: number;
10
+ strokeColor?: string;
11
+ fillColor?: string;
12
+ strokeWidth?: number;
13
+ showDots?: boolean;
14
+ showArea?: boolean;
15
+ }, {}, "">;
16
+ type $$ComponentProps = {
17
+ data?: any;
18
+ width?: number;
19
+ height?: number;
20
+ strokeColor?: string;
21
+ fillColor?: string;
22
+ strokeWidth?: number;
23
+ showDots?: boolean;
24
+ showArea?: boolean;
5
25
  };
6
- declare const Sparkline: import("svelte").Component<number[], {}, "">;