@alliance-droid/status-feedback-system 0.1.0 → 0.1.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.
Files changed (52) hide show
  1. package/dist/api.d.ts +57 -0
  2. package/dist/api.js +76 -0
  3. package/dist/components/FeedbackButton.svelte +3 -3
  4. package/dist/components/FeedbackButton.svelte.d.ts +1 -1
  5. package/dist/components/FeedbackForm.svelte +3 -3
  6. package/dist/components/FeedbackForm.svelte.d.ts +1 -1
  7. package/dist/components/StatusBanner.svelte +36 -3
  8. package/dist/components/StatusBanner.svelte.d.ts +7 -1
  9. package/dist/components/StatusPage.svelte +150 -83
  10. package/dist/components/StatusPage.svelte.d.ts +10 -3
  11. package/dist/index.d.ts +6 -9
  12. package/dist/index.js +5 -8
  13. package/dist/types.d.ts +0 -6
  14. package/package.json +2 -13
  15. package/dist/components/admin/AdminDashboard.svelte +0 -274
  16. package/dist/components/admin/AdminDashboard.svelte.d.ts +0 -9
  17. package/dist/components/admin/ApiKeyManager.svelte +0 -68
  18. package/dist/components/admin/ApiKeyManager.svelte.d.ts +0 -7
  19. package/dist/components/admin/FeedbackList.svelte +0 -160
  20. package/dist/components/admin/FeedbackList.svelte.d.ts +0 -17
  21. package/dist/components/admin/IncidentForm.svelte +0 -135
  22. package/dist/components/admin/IncidentForm.svelte.d.ts +0 -14
  23. package/dist/components/admin/IncidentManager.svelte +0 -153
  24. package/dist/components/admin/IncidentManager.svelte.d.ts +0 -13
  25. package/dist/components/admin/ProjectForm.svelte +0 -106
  26. package/dist/components/admin/ProjectForm.svelte.d.ts +0 -13
  27. package/dist/components/admin/ProjectList.svelte +0 -57
  28. package/dist/components/admin/ProjectList.svelte.d.ts +0 -10
  29. package/dist/components/admin/StatusControl.svelte +0 -62
  30. package/dist/components/admin/StatusControl.svelte.d.ts +0 -8
  31. package/dist/components/admin/SystemManager.svelte +0 -119
  32. package/dist/components/admin/SystemManager.svelte.d.ts +0 -13
  33. package/dist/components/admin/index.d.ts +0 -9
  34. package/dist/components/admin/index.js +0 -9
  35. package/dist/server/db.d.ts +0 -17
  36. package/dist/server/db.js +0 -68
  37. package/dist/server/feedback.d.ts +0 -27
  38. package/dist/server/feedback.js +0 -124
  39. package/dist/server/handlers.d.ts +0 -41
  40. package/dist/server/handlers.js +0 -251
  41. package/dist/server/incidents.d.ts +0 -27
  42. package/dist/server/incidents.js +0 -180
  43. package/dist/server/index.d.ts +0 -101
  44. package/dist/server/index.js +0 -71
  45. package/dist/server/projects.d.ts +0 -45
  46. package/dist/server/projects.js +0 -156
  47. package/dist/server/schema.d.ts +0 -9
  48. package/dist/server/schema.js +0 -94
  49. package/dist/server/systems.d.ts +0 -20
  50. package/dist/server/systems.js +0 -146
  51. package/dist/server/types.d.ts +0 -4
  52. package/dist/server/types.js +0 -4
package/dist/api.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * API client for communicating with the status-feedback-admin backend.
3
+ *
4
+ * Usage:
5
+ * import { createStatusClient } from '@alliance-droid/status-feedback-system';
6
+ *
7
+ * const client = createStatusClient({
8
+ * apiUrl: 'https://status-admin.yourcompany.com',
9
+ * apiKey: 'sf_abc123...',
10
+ * });
11
+ *
12
+ * const { systems, incidents } = await client.getStatus();
13
+ */
14
+ import type { System, Incident, StatusHistoryEntry, Feedback } from './types.js';
15
+ export interface StatusClientConfig {
16
+ /** Base URL of the status-feedback-admin app */
17
+ apiUrl: string;
18
+ /** API key for the project (sf_ prefixed) */
19
+ apiKey: string;
20
+ /** Optional custom fetch function (for SSR) */
21
+ fetch?: typeof globalThis.fetch;
22
+ }
23
+ export interface StatusData {
24
+ systems: System[];
25
+ overallStatus: string;
26
+ }
27
+ export interface IncidentData {
28
+ incidents: Incident[];
29
+ }
30
+ export interface UptimeData {
31
+ history: Record<string, StatusHistoryEntry[]>;
32
+ }
33
+ export interface StatusClient {
34
+ /** Get current system statuses */
35
+ getStatus(): Promise<StatusData>;
36
+ /** Get incidents (active + recent resolved) */
37
+ getIncidents(options?: {
38
+ limit?: number;
39
+ includeResolved?: boolean;
40
+ }): Promise<IncidentData>;
41
+ /** Get uptime history for all systems (90 days) */
42
+ getUptime(options?: {
43
+ days?: number;
44
+ }): Promise<UptimeData>;
45
+ /** Submit user feedback */
46
+ submitFeedback(data: {
47
+ message: string;
48
+ category?: string;
49
+ email?: string;
50
+ pageUrl?: string;
51
+ metadata?: Record<string, unknown>;
52
+ }): Promise<Feedback>;
53
+ }
54
+ /**
55
+ * Create a status API client instance
56
+ */
57
+ export declare function createStatusClient(config: StatusClientConfig): StatusClient;
package/dist/api.js ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * API client for communicating with the status-feedback-admin backend.
3
+ *
4
+ * Usage:
5
+ * import { createStatusClient } from '@alliance-droid/status-feedback-system';
6
+ *
7
+ * const client = createStatusClient({
8
+ * apiUrl: 'https://status-admin.yourcompany.com',
9
+ * apiKey: 'sf_abc123...',
10
+ * });
11
+ *
12
+ * const { systems, incidents } = await client.getStatus();
13
+ */
14
+ /**
15
+ * Create a status API client instance
16
+ */
17
+ export function createStatusClient(config) {
18
+ const { apiUrl, apiKey } = config;
19
+ const fetchFn = config.fetch ?? globalThis.fetch;
20
+ const baseUrl = apiUrl.replace(/\/$/, '');
21
+ async function request(path, options) {
22
+ const url = `${baseUrl}${path}${path.includes('?') ? '&' : '?'}key=${encodeURIComponent(apiKey)}`;
23
+ const response = await fetchFn(url, {
24
+ ...options,
25
+ headers: {
26
+ 'Content-Type': 'application/json',
27
+ ...options?.headers,
28
+ },
29
+ });
30
+ if (!response.ok) {
31
+ const body = await response.text();
32
+ let message = `API error: ${response.status}`;
33
+ try {
34
+ const parsed = JSON.parse(body);
35
+ if (parsed.error)
36
+ message = parsed.error;
37
+ }
38
+ catch {
39
+ // ignore parse errors
40
+ }
41
+ throw new Error(message);
42
+ }
43
+ const json = (await response.json());
44
+ if (!json.success) {
45
+ throw new Error(json.error ?? 'Unknown API error');
46
+ }
47
+ return json.data;
48
+ }
49
+ return {
50
+ async getStatus() {
51
+ return request('/api/status');
52
+ },
53
+ async getIncidents(options) {
54
+ const params = new URLSearchParams();
55
+ if (options?.limit)
56
+ params.set('limit', String(options.limit));
57
+ if (options?.includeResolved !== undefined)
58
+ params.set('includeResolved', String(options.includeResolved));
59
+ const qs = params.toString();
60
+ return request(`/api/incidents${qs ? `?${qs}` : ''}`);
61
+ },
62
+ async getUptime(options) {
63
+ const params = new URLSearchParams();
64
+ if (options?.days)
65
+ params.set('days', String(options.days));
66
+ const qs = params.toString();
67
+ return request(`/api/uptime${qs ? `?${qs}` : ''}`);
68
+ },
69
+ async submitFeedback(data) {
70
+ return request('/api/feedback', {
71
+ method: 'POST',
72
+ body: JSON.stringify(data),
73
+ });
74
+ },
75
+ };
76
+ }
@@ -3,7 +3,7 @@
3
3
 
4
4
  interface Props {
5
5
  apiKey: string;
6
- endpoint: string;
6
+ apiUrl: string;
7
7
  categories?: string[];
8
8
  userEmail?: string;
9
9
  position?: 'bottom-right' | 'bottom-left';
@@ -11,7 +11,7 @@
11
11
 
12
12
  let {
13
13
  apiKey,
14
- endpoint,
14
+ apiUrl,
15
15
  categories,
16
16
  userEmail,
17
17
  position = 'bottom-right',
@@ -51,7 +51,7 @@
51
51
  <div class="p-4">
52
52
  <FeedbackForm
53
53
  {apiKey}
54
- {endpoint}
54
+ {apiUrl}
55
55
  {categories}
56
56
  {userEmail}
57
57
  onSuccess={() => {
@@ -1,6 +1,6 @@
1
1
  interface Props {
2
2
  apiKey: string;
3
- endpoint: string;
3
+ apiUrl: string;
4
4
  categories?: string[];
5
5
  userEmail?: string;
6
6
  position?: 'bottom-right' | 'bottom-left';
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
3
  apiKey: string;
4
- endpoint: string;
4
+ apiUrl: string;
5
5
  categories?: string[];
6
6
  userEmail?: string;
7
7
  onSuccess?: () => void;
@@ -10,7 +10,7 @@
10
10
 
11
11
  let {
12
12
  apiKey,
13
- endpoint,
13
+ apiUrl,
14
14
  categories = ['Bug', 'Feature Request', 'General'],
15
15
  userEmail,
16
16
  onSuccess,
@@ -32,7 +32,7 @@
32
32
  errorMsg = '';
33
33
 
34
34
  try {
35
- const res = await fetch(`${endpoint}/feedback`, {
35
+ const res = await fetch(`${apiUrl.replace(/\/$/, '')}/api/feedback`, {
36
36
  method: 'POST',
37
37
  headers: {
38
38
  'Content-Type': 'application/json',
@@ -1,6 +1,6 @@
1
1
  interface Props {
2
2
  apiKey: string;
3
- endpoint: string;
3
+ apiUrl: string;
4
4
  categories?: string[];
5
5
  userEmail?: string;
6
6
  onSuccess?: () => void;
@@ -1,13 +1,41 @@
1
1
  <script lang="ts">
2
+ import { onMount } from 'svelte';
2
3
  import type { System, SystemStatus } from '../types.js';
4
+ import { createStatusClient } from '../api.js';
3
5
  import StatusIndicator from './shared/StatusIndicator.svelte';
4
6
 
5
7
  interface Props {
6
- systems: System[];
8
+ /** Systems data (pass-through mode) */
9
+ systems?: System[];
10
+ /** API URL for self-fetching mode */
11
+ apiUrl?: string;
12
+ /** API key for self-fetching mode */
13
+ apiKey?: string;
14
+ /** Link to full status page */
7
15
  statusUrl?: string;
8
16
  }
9
17
 
10
- let { systems, statusUrl }: Props = $props();
18
+ let { systems: systemsProp, apiUrl, apiKey, statusUrl }: Props = $props();
19
+
20
+ let systems: System[] = $state(systemsProp ?? []);
21
+ let loading = $state(!systemsProp && !!apiUrl && !!apiKey);
22
+
23
+ onMount(async () => {
24
+ if (systemsProp || !apiUrl || !apiKey) return;
25
+ try {
26
+ const client = createStatusClient({ apiUrl, apiKey });
27
+ const data = await client.getStatus();
28
+ systems = data.systems;
29
+ } catch (err) {
30
+ console.error('StatusBanner fetch error:', err);
31
+ } finally {
32
+ loading = false;
33
+ }
34
+ });
35
+
36
+ $effect(() => {
37
+ if (systemsProp) systems = systemsProp;
38
+ });
11
39
 
12
40
  let overallStatus = $derived.by((): SystemStatus => {
13
41
  if (systems.length === 0) return 'operational';
@@ -25,7 +53,12 @@
25
53
  };
26
54
  </script>
27
55
 
28
- {#if statusUrl}
56
+ {#if loading}
57
+ <div class="inline-flex items-center gap-2 rounded-full border border-border px-3 py-1.5 text-xs text-foreground-tertiary">
58
+ <div class="h-2 w-2 animate-pulse rounded-full bg-foreground-tertiary"></div>
59
+ <span>Loading...</span>
60
+ </div>
61
+ {:else if statusUrl}
29
62
  <a
30
63
  href={statusUrl}
31
64
  class="inline-flex items-center gap-2 rounded-full border border-border px-3 py-1.5 text-xs text-foreground-secondary transition-colors hover:bg-surface-hover"
@@ -1,6 +1,12 @@
1
1
  import type { System } from '../types.js';
2
2
  interface Props {
3
- systems: System[];
3
+ /** Systems data (pass-through mode) */
4
+ systems?: System[];
5
+ /** API URL for self-fetching mode */
6
+ apiUrl?: string;
7
+ /** API key for self-fetching mode */
8
+ apiKey?: string;
9
+ /** Link to full status page */
4
10
  statusUrl?: string;
5
11
  }
6
12
  declare const StatusBanner: import("svelte").Component<Props, {}, "">;
@@ -1,26 +1,81 @@
1
1
  <script lang="ts">
2
+ import { onMount } from 'svelte';
2
3
  import type { System, Incident, StatusHistoryEntry, SystemStatus } from '../types.js';
4
+ import { createStatusClient } from '../api.js';
3
5
  import StatusIndicator from './shared/StatusIndicator.svelte';
4
6
  import SystemCard from './shared/SystemCard.svelte';
5
7
  import IncidentTimeline from './shared/IncidentTimeline.svelte';
6
8
 
7
9
  interface Props {
10
+ /** Project display name */
8
11
  projectName: string;
9
- systems: System[];
10
- incidents: Incident[];
11
- /** Map of systemId → StatusHistoryEntry[] for uptime bars */
12
+ /** API URL for fetching data (self-fetching mode) */
13
+ apiUrl?: string;
14
+ /** API key for fetching data (self-fetching mode) */
15
+ apiKey?: string;
16
+ /** Systems data (pass-through mode — overrides API fetching) */
17
+ systems?: System[];
18
+ /** Incidents data (pass-through mode) */
19
+ incidents?: Incident[];
20
+ /** Map of systemId → StatusHistoryEntry[] for uptime bars (pass-through mode) */
12
21
  statusHistory?: Record<string, StatusHistoryEntry[]>;
13
22
  showUptime?: boolean;
14
23
  }
15
24
 
16
25
  let {
17
26
  projectName,
18
- systems,
19
- incidents,
20
- statusHistory = {},
27
+ apiUrl,
28
+ apiKey,
29
+ systems: systemsProp,
30
+ incidents: incidentsProp,
31
+ statusHistory: statusHistoryProp,
21
32
  showUptime = true,
22
33
  }: Props = $props();
23
34
 
35
+ // ── State ──
36
+ let systems: System[] = $state(systemsProp ?? []);
37
+ let incidents: Incident[] = $state(incidentsProp ?? []);
38
+ let statusHistory: Record<string, StatusHistoryEntry[]> = $state(statusHistoryProp ?? {});
39
+ let loading = $state(!systemsProp);
40
+ let error = $state('');
41
+
42
+ // ── Self-fetching mode ──
43
+ const usesApi = $derived(!!apiUrl && !!apiKey && !systemsProp);
44
+
45
+ onMount(async () => {
46
+ if (!usesApi) return;
47
+
48
+ try {
49
+ const client = createStatusClient({ apiUrl: apiUrl!, apiKey: apiKey! });
50
+
51
+ const [statusData, incidentData, uptimeData] = await Promise.all([
52
+ client.getStatus(),
53
+ client.getIncidents(),
54
+ client.getUptime(),
55
+ ]);
56
+
57
+ systems = statusData.systems;
58
+ incidents = incidentData.incidents;
59
+ statusHistory = uptimeData.history;
60
+ } catch (err) {
61
+ error = err instanceof Error ? err.message : 'Failed to load status data';
62
+ console.error('StatusPage fetch error:', err);
63
+ } finally {
64
+ loading = false;
65
+ }
66
+ });
67
+
68
+ // ── Sync props when in pass-through mode ──
69
+ $effect(() => {
70
+ if (systemsProp) systems = systemsProp;
71
+ });
72
+ $effect(() => {
73
+ if (incidentsProp) incidents = incidentsProp;
74
+ });
75
+ $effect(() => {
76
+ if (statusHistoryProp) statusHistory = statusHistoryProp;
77
+ });
78
+
24
79
  // ── Derived state ──
25
80
 
26
81
  let overallStatus = $derived.by((): SystemStatus => {
@@ -65,92 +120,104 @@
65
120
  <h1 class="text-2xl font-semibold text-foreground">{projectName} Status</h1>
66
121
  </div>
67
122
 
68
- <!-- Overall Status Banner -->
69
- <div class="rounded-lg border p-4 text-center {overallBgClasses[overallStatus]}">
70
- <div class="flex items-center justify-center gap-2">
71
- <StatusIndicator status={overallStatus} size="lg" />
72
- <span class="text-lg font-semibold text-foreground">{overallMessages[overallStatus]}</span>
123
+ {#if loading}
124
+ <div class="rounded-lg border border-border bg-surface p-12 text-center">
125
+ <div class="mx-auto mb-3 h-8 w-8 animate-spin rounded-full border-2 border-foreground-tertiary border-t-primary"></div>
126
+ <p class="text-sm text-foreground-secondary">Loading status...</p>
73
127
  </div>
74
- </div>
75
-
76
- <!-- Systems -->
77
- {#if systems.length > 0}
78
- <section>
79
- <h2 class="mb-4 text-lg font-semibold text-foreground">Systems</h2>
80
- <div class="space-y-3">
81
- {#each systems as system}
82
- <SystemCard
83
- {system}
84
- history={statusHistory[system.id] || []}
85
- {showUptime}
86
- />
87
- {/each}
128
+ {:else if error}
129
+ <div class="rounded-lg border border-red-500/30 bg-red-500/10 p-6 text-center">
130
+ <i class="fa-solid fa-circle-exclamation mb-2 text-2xl text-red-500"></i>
131
+ <p class="text-sm text-red-400">{error}</p>
132
+ </div>
133
+ {:else}
134
+ <!-- Overall Status Banner -->
135
+ <div class="rounded-lg border p-4 text-center {overallBgClasses[overallStatus]}">
136
+ <div class="flex items-center justify-center gap-2">
137
+ <StatusIndicator status={overallStatus} size="lg" />
138
+ <span class="text-lg font-semibold text-foreground">{overallMessages[overallStatus]}</span>
88
139
  </div>
89
- </section>
90
- {/if}
140
+ </div>
91
141
 
92
- <!-- Active Incidents -->
93
- {#if activeIncidents.length > 0}
94
- <section>
95
- <h2 class="mb-4 text-lg font-semibold text-foreground">Active Incidents</h2>
96
- <div class="space-y-4">
97
- {#each activeIncidents as incident}
98
- <div class="rounded-lg border border-border bg-surface p-4">
99
- <div class="flex items-start justify-between">
100
- <div>
101
- <h3 class="font-semibold text-foreground">{incident.title}</h3>
102
- <div class="mt-1 flex items-center gap-2 text-xs text-foreground-tertiary">
103
- <span class="rounded bg-red-500/10 px-1.5 py-0.5 text-red-500">
104
- {incident.severity}
105
- </span>
106
- <span>{formatDate(incident.createdAt)}</span>
142
+ <!-- Systems -->
143
+ {#if systems.length > 0}
144
+ <section>
145
+ <h2 class="mb-4 text-lg font-semibold text-foreground">Systems</h2>
146
+ <div class="space-y-3">
147
+ {#each systems as system}
148
+ <SystemCard
149
+ {system}
150
+ history={statusHistory[system.id] || []}
151
+ {showUptime}
152
+ />
153
+ {/each}
154
+ </div>
155
+ </section>
156
+ {/if}
157
+
158
+ <!-- Active Incidents -->
159
+ {#if activeIncidents.length > 0}
160
+ <section>
161
+ <h2 class="mb-4 text-lg font-semibold text-foreground">Active Incidents</h2>
162
+ <div class="space-y-4">
163
+ {#each activeIncidents as incident}
164
+ <div class="rounded-lg border border-border bg-surface p-4">
165
+ <div class="flex items-start justify-between">
166
+ <div>
167
+ <h3 class="font-semibold text-foreground">{incident.title}</h3>
168
+ <div class="mt-1 flex items-center gap-2 text-xs text-foreground-tertiary">
169
+ <span class="rounded bg-red-500/10 px-1.5 py-0.5 text-red-500">
170
+ {incident.severity}
171
+ </span>
172
+ <span>{formatDate(incident.createdAt)}</span>
173
+ </div>
107
174
  </div>
175
+ <StatusIndicator status={incident.status === 'resolved' ? 'operational' : 'outage'} size="sm" />
108
176
  </div>
109
- <StatusIndicator status={incident.status === 'resolved' ? 'operational' : 'outage'} size="sm" />
177
+ {#if incident.updates && incident.updates.length > 0}
178
+ <div class="mt-4 border-t border-border pt-4">
179
+ <IncidentTimeline updates={incident.updates} />
180
+ </div>
181
+ {/if}
110
182
  </div>
111
- {#if incident.updates && incident.updates.length > 0}
112
- <div class="mt-4 border-t border-border pt-4">
113
- <IncidentTimeline updates={incident.updates} />
114
- </div>
115
- {/if}
116
- </div>
117
- {/each}
118
- </div>
119
- </section>
120
- {/if}
183
+ {/each}
184
+ </div>
185
+ </section>
186
+ {/if}
121
187
 
122
- <!-- Resolved Incidents -->
123
- {#if recentResolved.length > 0}
124
- <section>
125
- <h2 class="mb-4 text-lg font-semibold text-foreground">Past Incidents</h2>
126
- <div class="space-y-4">
127
- {#each recentResolved as incident}
128
- <div class="rounded-lg border border-border bg-surface p-4">
129
- <div class="flex items-start justify-between">
130
- <div>
131
- <h3 class="font-semibold text-foreground">{incident.title}</h3>
132
- <p class="mt-1 text-xs text-foreground-tertiary">
133
- Resolved {incident.resolvedAt ? formatDate(incident.resolvedAt) : ''}
134
- </p>
188
+ <!-- Resolved Incidents -->
189
+ {#if recentResolved.length > 0}
190
+ <section>
191
+ <h2 class="mb-4 text-lg font-semibold text-foreground">Past Incidents</h2>
192
+ <div class="space-y-4">
193
+ {#each recentResolved as incident}
194
+ <div class="rounded-lg border border-border bg-surface p-4">
195
+ <div class="flex items-start justify-between">
196
+ <div>
197
+ <h3 class="font-semibold text-foreground">{incident.title}</h3>
198
+ <p class="mt-1 text-xs text-foreground-tertiary">
199
+ Resolved {incident.resolvedAt ? formatDate(incident.resolvedAt) : ''}
200
+ </p>
201
+ </div>
202
+ <StatusIndicator status="operational" size="sm" />
135
203
  </div>
136
- <StatusIndicator status="operational" size="sm" />
204
+ {#if incident.updates && incident.updates.length > 0}
205
+ <div class="mt-4 border-t border-border pt-4">
206
+ <IncidentTimeline updates={incident.updates} />
207
+ </div>
208
+ {/if}
137
209
  </div>
138
- {#if incident.updates && incident.updates.length > 0}
139
- <div class="mt-4 border-t border-border pt-4">
140
- <IncidentTimeline updates={incident.updates} />
141
- </div>
142
- {/if}
143
- </div>
144
- {/each}
145
- </div>
146
- </section>
147
- {/if}
210
+ {/each}
211
+ </div>
212
+ </section>
213
+ {/if}
148
214
 
149
- <!-- No Incidents -->
150
- {#if activeIncidents.length === 0 && recentResolved.length === 0}
151
- <div class="rounded-lg border border-border bg-surface p-8 text-center">
152
- <i class="fa-solid fa-circle-check mb-2 text-2xl text-green-500"></i>
153
- <p class="text-sm text-foreground-secondary">No incidents reported</p>
154
- </div>
215
+ <!-- No Incidents -->
216
+ {#if activeIncidents.length === 0 && recentResolved.length === 0}
217
+ <div class="rounded-lg border border-border bg-surface p-8 text-center">
218
+ <i class="fa-solid fa-circle-check mb-2 text-2xl text-green-500"></i>
219
+ <p class="text-sm text-foreground-secondary">No incidents reported</p>
220
+ </div>
221
+ {/if}
155
222
  {/if}
156
223
  </div>
@@ -1,9 +1,16 @@
1
1
  import type { System, Incident, StatusHistoryEntry } from '../types.js';
2
2
  interface Props {
3
+ /** Project display name */
3
4
  projectName: string;
4
- systems: System[];
5
- incidents: Incident[];
6
- /** Map of systemId → StatusHistoryEntry[] for uptime bars */
5
+ /** API URL for fetching data (self-fetching mode) */
6
+ apiUrl?: string;
7
+ /** API key for fetching data (self-fetching mode) */
8
+ apiKey?: string;
9
+ /** Systems data (pass-through mode — overrides API fetching) */
10
+ systems?: System[];
11
+ /** Incidents data (pass-through mode) */
12
+ incidents?: Incident[];
13
+ /** Map of systemId → StatusHistoryEntry[] for uptime bars (pass-through mode) */
7
14
  statusHistory?: Record<string, StatusHistoryEntry[]>;
8
15
  showUptime?: boolean;
9
16
  }
package/dist/index.d.ts CHANGED
@@ -2,17 +2,14 @@
2
2
  * @alliance-droid/status-feedback-system
3
3
  *
4
4
  * Drop-in system status pages and user feedback forms for SvelteKit apps.
5
+ * All data is fetched from a remote status-feedback-admin backend via API.
5
6
  *
6
- * Client exports (components):
7
- * import { StatusPage, FeedbackForm } from '@alliance-droid/status-feedback-system';
8
- *
9
- * Server exports:
10
- * import { createStatusServer } from '@alliance-droid/status-feedback-system/server';
11
- *
12
- * Admin exports:
13
- * import { AdminDashboard } from '@alliance-droid/status-feedback-system/admin';
7
+ * Usage:
8
+ * import { StatusPage, FeedbackButton, createStatusClient } from '@alliance-droid/status-feedback-system';
14
9
  */
15
- export type { Project, System, Incident, IncidentUpdate, Feedback, StatusHistoryEntry, SystemStatus, IncidentStatus, IncidentSeverity, FeedbackStatus, StatusServerConfig, ApiResponse, } from './types.js';
10
+ export type { Project, System, Incident, IncidentUpdate, Feedback, StatusHistoryEntry, SystemStatus, IncidentStatus, IncidentSeverity, FeedbackStatus, ApiResponse, } from './types.js';
11
+ export { createStatusClient } from './api.js';
12
+ export type { StatusClient, StatusClientConfig, StatusData, IncidentData, UptimeData } from './api.js';
16
13
  export { default as StatusPage } from './components/StatusPage.svelte';
17
14
  export { default as StatusBanner } from './components/StatusBanner.svelte';
18
15
  export { default as FeedbackForm } from './components/FeedbackForm.svelte';
package/dist/index.js CHANGED
@@ -2,16 +2,13 @@
2
2
  * @alliance-droid/status-feedback-system
3
3
  *
4
4
  * Drop-in system status pages and user feedback forms for SvelteKit apps.
5
+ * All data is fetched from a remote status-feedback-admin backend via API.
5
6
  *
6
- * Client exports (components):
7
- * import { StatusPage, FeedbackForm } from '@alliance-droid/status-feedback-system';
8
- *
9
- * Server exports:
10
- * import { createStatusServer } from '@alliance-droid/status-feedback-system/server';
11
- *
12
- * Admin exports:
13
- * import { AdminDashboard } from '@alliance-droid/status-feedback-system/admin';
7
+ * Usage:
8
+ * import { StatusPage, FeedbackButton, createStatusClient } from '@alliance-droid/status-feedback-system';
14
9
  */
10
+ // ── API Client ──
11
+ export { createStatusClient } from './api.js';
15
12
  // ── Client Components ──
16
13
  export { default as StatusPage } from './components/StatusPage.svelte';
17
14
  export { default as StatusBanner } from './components/StatusBanner.svelte';
package/dist/types.d.ts CHANGED
@@ -8,7 +8,6 @@ export type FeedbackStatus = 'new' | 'reviewed' | 'resolved' | 'archived';
8
8
  export interface Project {
9
9
  id: string;
10
10
  name: string;
11
- apiKey: string;
12
11
  description: string | null;
13
12
  allowedOrigins: string[];
14
13
  createdAt: number;
@@ -61,11 +60,6 @@ export interface StatusHistoryEntry {
61
60
  status: SystemStatus;
62
61
  changedAt: number;
63
62
  }
64
- export interface StatusServerConfig {
65
- database: {
66
- connectionString: string;
67
- };
68
- }
69
63
  export interface ApiResponse<T = unknown> {
70
64
  success: boolean;
71
65
  data?: T;