@littlebearapps/platform-admin-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +89 -0
- package/dist/prompts.d.ts +27 -0
- package/dist/prompts.js +80 -0
- package/dist/scaffold.d.ts +5 -0
- package/dist/scaffold.js +65 -0
- package/dist/templates.d.ts +16 -0
- package/dist/templates.js +131 -0
- package/package.json +46 -0
- package/templates/full/migrations/006_pattern_discovery.sql +199 -0
- package/templates/full/migrations/007_notifications_search.sql +127 -0
- package/templates/full/workers/lib/pattern-discovery/ai-prompt.ts +644 -0
- package/templates/full/workers/lib/pattern-discovery/clustering.ts +278 -0
- package/templates/full/workers/lib/pattern-discovery/shadow-evaluation.ts +603 -0
- package/templates/full/workers/lib/pattern-discovery/storage.ts +806 -0
- package/templates/full/workers/lib/pattern-discovery/types.ts +159 -0
- package/templates/full/workers/lib/pattern-discovery/validation.ts +278 -0
- package/templates/full/workers/pattern-discovery.ts +661 -0
- package/templates/full/workers/platform-alert-router.ts +1809 -0
- package/templates/full/workers/platform-notifications.ts +424 -0
- package/templates/full/workers/platform-search.ts +480 -0
- package/templates/full/workers/platform-settings.ts +436 -0
- package/templates/full/wrangler.alert-router.jsonc.hbs +34 -0
- package/templates/full/wrangler.notifications.jsonc.hbs +23 -0
- package/templates/full/wrangler.pattern-discovery.jsonc.hbs +33 -0
- package/templates/full/wrangler.search.jsonc.hbs +16 -0
- package/templates/full/wrangler.settings.jsonc.hbs +23 -0
- package/templates/shared/README.md.hbs +69 -0
- package/templates/shared/config/budgets.yaml.hbs +72 -0
- package/templates/shared/config/services.yaml.hbs +45 -0
- package/templates/shared/migrations/001_core_tables.sql +117 -0
- package/templates/shared/migrations/002_usage_warehouse.sql +830 -0
- package/templates/shared/migrations/003_feature_tracking.sql +250 -0
- package/templates/shared/migrations/004_settings_alerts.sql +452 -0
- package/templates/shared/migrations/seed.sql.hbs +4 -0
- package/templates/shared/package.json.hbs +21 -0
- package/templates/shared/scripts/sync-config.ts +242 -0
- package/templates/shared/tsconfig.json +12 -0
- package/templates/shared/workers/lib/analytics-engine.ts +357 -0
- package/templates/shared/workers/lib/billing.ts +293 -0
- package/templates/shared/workers/lib/circuit-breaker-middleware.ts +25 -0
- package/templates/shared/workers/lib/control.ts +292 -0
- package/templates/shared/workers/lib/economics.ts +368 -0
- package/templates/shared/workers/lib/metrics.ts +103 -0
- package/templates/shared/workers/lib/platform-settings.ts +407 -0
- package/templates/shared/workers/lib/shared/allowances.ts +333 -0
- package/templates/shared/workers/lib/shared/cloudflare.ts +1362 -0
- package/templates/shared/workers/lib/shared/types.ts +58 -0
- package/templates/shared/workers/lib/telemetry-sampling.ts +360 -0
- package/templates/shared/workers/lib/usage/collectors/example.ts +96 -0
- package/templates/shared/workers/lib/usage/collectors/index.ts +128 -0
- package/templates/shared/workers/lib/usage/handlers/audit.ts +306 -0
- package/templates/shared/workers/lib/usage/handlers/backfill.ts +845 -0
- package/templates/shared/workers/lib/usage/handlers/behavioral.ts +429 -0
- package/templates/shared/workers/lib/usage/handlers/data-queries.ts +507 -0
- package/templates/shared/workers/lib/usage/handlers/dlq-admin.ts +364 -0
- package/templates/shared/workers/lib/usage/handlers/health-trends.ts +222 -0
- package/templates/shared/workers/lib/usage/handlers/index.ts +35 -0
- package/templates/shared/workers/lib/usage/handlers/usage-admin.ts +421 -0
- package/templates/shared/workers/lib/usage/handlers/usage-features.ts +1262 -0
- package/templates/shared/workers/lib/usage/handlers/usage-metrics.ts +2420 -0
- package/templates/shared/workers/lib/usage/handlers/usage-settings.ts +610 -0
- package/templates/shared/workers/lib/usage/queue/budget-enforcement.ts +1032 -0
- package/templates/shared/workers/lib/usage/queue/cost-budget-enforcement.ts +128 -0
- package/templates/shared/workers/lib/usage/queue/cost-calculator.ts +77 -0
- package/templates/shared/workers/lib/usage/queue/dlq-handler.ts +161 -0
- package/templates/shared/workers/lib/usage/queue/index.ts +19 -0
- package/templates/shared/workers/lib/usage/queue/telemetry-processor.ts +790 -0
- package/templates/shared/workers/lib/usage/scheduled/anomaly-detection.ts +732 -0
- package/templates/shared/workers/lib/usage/scheduled/data-collection.ts +956 -0
- package/templates/shared/workers/lib/usage/scheduled/error-digest.ts +343 -0
- package/templates/shared/workers/lib/usage/scheduled/index.ts +18 -0
- package/templates/shared/workers/lib/usage/scheduled/rollups.ts +1561 -0
- package/templates/shared/workers/lib/usage/shared/constants.ts +362 -0
- package/templates/shared/workers/lib/usage/shared/index.ts +14 -0
- package/templates/shared/workers/lib/usage/shared/types.ts +1066 -0
- package/templates/shared/workers/lib/usage/shared/utils.ts +795 -0
- package/templates/shared/workers/platform-usage.ts +1915 -0
- package/templates/shared/wrangler.usage.jsonc.hbs +58 -0
- package/templates/standard/migrations/005_error_collection.sql +162 -0
- package/templates/standard/workers/error-collector.ts +2670 -0
- package/templates/standard/workers/lib/error-collector/capture.ts +213 -0
- package/templates/standard/workers/lib/error-collector/digest.ts +448 -0
- package/templates/standard/workers/lib/error-collector/email-health-alerts.ts +262 -0
- package/templates/standard/workers/lib/error-collector/fingerprint.ts +258 -0
- package/templates/standard/workers/lib/error-collector/gap-alerts.ts +293 -0
- package/templates/standard/workers/lib/error-collector/github.ts +329 -0
- package/templates/standard/workers/lib/error-collector/types.ts +262 -0
- package/templates/standard/workers/lib/sentinel/gap-detection.ts +734 -0
- package/templates/standard/workers/lib/shared/slack-alerts.ts +585 -0
- package/templates/standard/workers/platform-sentinel.ts +1744 -0
- package/templates/standard/wrangler.error-collector.jsonc.hbs +44 -0
- package/templates/standard/wrangler.sentinel.jsonc.hbs +45 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Handlers for platform-usage
|
|
3
|
+
*
|
|
4
|
+
* Provides API endpoints for accessing audit reports.
|
|
5
|
+
* Part of Phase 2 Usage Capture Audit.
|
|
6
|
+
*
|
|
7
|
+
* Endpoints:
|
|
8
|
+
* - GET /usage/audit - Latest comprehensive audit report
|
|
9
|
+
* - GET /usage/audit/history - Comprehensive audit history
|
|
10
|
+
* - GET /usage/audit/attribution - Latest attribution report
|
|
11
|
+
* - GET /usage/audit/features - Latest feature coverage report
|
|
12
|
+
*
|
|
13
|
+
* @module workers/lib/usage/handlers/audit
|
|
14
|
+
* @created 2026-01-29
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { D1Database, KVNamespace } from '@cloudflare/workers-types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Environment bindings for audit handlers
|
|
21
|
+
*/
|
|
22
|
+
export interface AuditHandlerEnv {
|
|
23
|
+
PLATFORM_DB: D1Database;
|
|
24
|
+
PLATFORM_CACHE: KVNamespace;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Handle GET /usage/audit - Get latest comprehensive audit report
|
|
29
|
+
*/
|
|
30
|
+
export async function handleGetAudit(env: AuditHandlerEnv): Promise<Response> {
|
|
31
|
+
try {
|
|
32
|
+
const result = await env.PLATFORM_DB.prepare(
|
|
33
|
+
`
|
|
34
|
+
SELECT report_json, generated_at
|
|
35
|
+
FROM comprehensive_audit_reports
|
|
36
|
+
ORDER BY generated_at DESC
|
|
37
|
+
LIMIT 1
|
|
38
|
+
`
|
|
39
|
+
).first<{ report_json: string; generated_at: string }>();
|
|
40
|
+
|
|
41
|
+
if (!result) {
|
|
42
|
+
return Response.json(
|
|
43
|
+
{
|
|
44
|
+
success: false,
|
|
45
|
+
error: 'No comprehensive audit reports found',
|
|
46
|
+
message: 'Run platform-auditor to generate a report',
|
|
47
|
+
},
|
|
48
|
+
{ status: 404 }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const report = JSON.parse(result.report_json);
|
|
53
|
+
|
|
54
|
+
return Response.json({
|
|
55
|
+
success: true,
|
|
56
|
+
data: report,
|
|
57
|
+
generatedAt: result.generated_at,
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
});
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
62
|
+
return Response.json(
|
|
63
|
+
{ success: false, error: 'Failed to get audit report', message },
|
|
64
|
+
{ status: 500 }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Handle GET /usage/audit/history - Get comprehensive audit history
|
|
71
|
+
*/
|
|
72
|
+
export async function handleGetAuditHistory(
|
|
73
|
+
request: Request,
|
|
74
|
+
env: AuditHandlerEnv
|
|
75
|
+
): Promise<Response> {
|
|
76
|
+
const url = new URL(request.url);
|
|
77
|
+
const limit = parseInt(url.searchParams.get('limit') || '10', 10);
|
|
78
|
+
const offset = parseInt(url.searchParams.get('offset') || '0', 10);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const result = await env.PLATFORM_DB.prepare(
|
|
82
|
+
`
|
|
83
|
+
SELECT
|
|
84
|
+
id,
|
|
85
|
+
generated_at,
|
|
86
|
+
gap_events_count,
|
|
87
|
+
total_missing_hours,
|
|
88
|
+
average_gap_severity,
|
|
89
|
+
total_resources,
|
|
90
|
+
attributed_count,
|
|
91
|
+
unattributed_count,
|
|
92
|
+
defined_features_count,
|
|
93
|
+
active_features_count,
|
|
94
|
+
dormant_features_count,
|
|
95
|
+
undefined_features_count,
|
|
96
|
+
ai_judge_avg_score,
|
|
97
|
+
action_items_count,
|
|
98
|
+
critical_items_count
|
|
99
|
+
FROM comprehensive_audit_reports
|
|
100
|
+
ORDER BY generated_at DESC
|
|
101
|
+
LIMIT ? OFFSET ?
|
|
102
|
+
`
|
|
103
|
+
)
|
|
104
|
+
.bind(limit, offset)
|
|
105
|
+
.all<{
|
|
106
|
+
id: string;
|
|
107
|
+
generated_at: string;
|
|
108
|
+
gap_events_count: number;
|
|
109
|
+
total_missing_hours: number;
|
|
110
|
+
average_gap_severity: string;
|
|
111
|
+
total_resources: number;
|
|
112
|
+
attributed_count: number;
|
|
113
|
+
unattributed_count: number;
|
|
114
|
+
defined_features_count: number;
|
|
115
|
+
active_features_count: number;
|
|
116
|
+
dormant_features_count: number;
|
|
117
|
+
undefined_features_count: number;
|
|
118
|
+
ai_judge_avg_score: number | null;
|
|
119
|
+
action_items_count: number;
|
|
120
|
+
critical_items_count: number;
|
|
121
|
+
}>();
|
|
122
|
+
|
|
123
|
+
// Get total count
|
|
124
|
+
const countResult = await env.PLATFORM_DB.prepare(
|
|
125
|
+
`SELECT COUNT(*) as count FROM comprehensive_audit_reports`
|
|
126
|
+
).first<{ count: number }>();
|
|
127
|
+
|
|
128
|
+
return Response.json({
|
|
129
|
+
success: true,
|
|
130
|
+
data: result.results ?? [],
|
|
131
|
+
pagination: {
|
|
132
|
+
limit,
|
|
133
|
+
offset,
|
|
134
|
+
total: countResult?.count ?? 0,
|
|
135
|
+
},
|
|
136
|
+
timestamp: new Date().toISOString(),
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
140
|
+
return Response.json(
|
|
141
|
+
{ success: false, error: 'Failed to get audit history', message },
|
|
142
|
+
{ status: 500 }
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Handle GET /usage/audit/attribution - Get latest attribution report
|
|
149
|
+
*/
|
|
150
|
+
export async function handleGetAttribution(env: AuditHandlerEnv): Promise<Response> {
|
|
151
|
+
try {
|
|
152
|
+
const result = await env.PLATFORM_DB.prepare(
|
|
153
|
+
`
|
|
154
|
+
SELECT
|
|
155
|
+
id,
|
|
156
|
+
discovery_time,
|
|
157
|
+
total_resources,
|
|
158
|
+
attributed_count,
|
|
159
|
+
unattributed_count,
|
|
160
|
+
report_json
|
|
161
|
+
FROM attribution_reports
|
|
162
|
+
ORDER BY discovery_time DESC
|
|
163
|
+
LIMIT 1
|
|
164
|
+
`
|
|
165
|
+
).first<{
|
|
166
|
+
id: string;
|
|
167
|
+
discovery_time: string;
|
|
168
|
+
total_resources: number;
|
|
169
|
+
attributed_count: number;
|
|
170
|
+
unattributed_count: number;
|
|
171
|
+
report_json: string;
|
|
172
|
+
}>();
|
|
173
|
+
|
|
174
|
+
if (!result) {
|
|
175
|
+
return Response.json(
|
|
176
|
+
{
|
|
177
|
+
success: false,
|
|
178
|
+
error: 'No attribution reports found',
|
|
179
|
+
message: 'platform-mapper has not yet run or attribution checking is not enabled',
|
|
180
|
+
},
|
|
181
|
+
{ status: 404 }
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const report = JSON.parse(result.report_json);
|
|
186
|
+
|
|
187
|
+
return Response.json({
|
|
188
|
+
success: true,
|
|
189
|
+
data: {
|
|
190
|
+
id: result.id,
|
|
191
|
+
discoveryTime: result.discovery_time,
|
|
192
|
+
summary: {
|
|
193
|
+
totalResources: result.total_resources,
|
|
194
|
+
attributedCount: result.attributed_count,
|
|
195
|
+
unattributedCount: result.unattributed_count,
|
|
196
|
+
attributionRate:
|
|
197
|
+
result.total_resources > 0
|
|
198
|
+
? Math.round((result.attributed_count / result.total_resources) * 100)
|
|
199
|
+
: 100,
|
|
200
|
+
},
|
|
201
|
+
unattributed: report.unattributed ?? [],
|
|
202
|
+
},
|
|
203
|
+
timestamp: new Date().toISOString(),
|
|
204
|
+
});
|
|
205
|
+
} catch (error) {
|
|
206
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
207
|
+
return Response.json(
|
|
208
|
+
{ success: false, error: 'Failed to get attribution report', message },
|
|
209
|
+
{ status: 500 }
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Handle GET /usage/audit/features - Get latest feature coverage report
|
|
216
|
+
*/
|
|
217
|
+
export async function handleGetFeatureCoverage(
|
|
218
|
+
request: Request,
|
|
219
|
+
env: AuditHandlerEnv
|
|
220
|
+
): Promise<Response> {
|
|
221
|
+
const url = new URL(request.url);
|
|
222
|
+
const project = url.searchParams.get('project');
|
|
223
|
+
const status = url.searchParams.get('status');
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
// Get latest audit time
|
|
227
|
+
const latestResult = await env.PLATFORM_DB.prepare(
|
|
228
|
+
`SELECT MAX(audit_time) as latest FROM feature_coverage_audit`
|
|
229
|
+
).first<{ latest: string | null }>();
|
|
230
|
+
|
|
231
|
+
if (!latestResult?.latest) {
|
|
232
|
+
return Response.json(
|
|
233
|
+
{
|
|
234
|
+
success: false,
|
|
235
|
+
error: 'No feature coverage audits found',
|
|
236
|
+
message: 'platform-auditor has not yet run feature coverage audit',
|
|
237
|
+
},
|
|
238
|
+
{ status: 404 }
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Build query with optional filters
|
|
243
|
+
let query = `
|
|
244
|
+
SELECT
|
|
245
|
+
project,
|
|
246
|
+
feature,
|
|
247
|
+
status,
|
|
248
|
+
last_heartbeat,
|
|
249
|
+
events_last_7d,
|
|
250
|
+
defined_budget,
|
|
251
|
+
budget_unit
|
|
252
|
+
FROM feature_coverage_audit
|
|
253
|
+
WHERE audit_time = ?
|
|
254
|
+
`;
|
|
255
|
+
const bindings: (string | number)[] = [latestResult.latest];
|
|
256
|
+
|
|
257
|
+
if (project) {
|
|
258
|
+
query += ' AND project = ?';
|
|
259
|
+
bindings.push(project);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (status) {
|
|
263
|
+
query += ' AND status = ?';
|
|
264
|
+
bindings.push(status);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
query += ' ORDER BY project, feature';
|
|
268
|
+
|
|
269
|
+
const result = await env.PLATFORM_DB.prepare(query)
|
|
270
|
+
.bind(...bindings)
|
|
271
|
+
.all<{
|
|
272
|
+
project: string;
|
|
273
|
+
feature: string;
|
|
274
|
+
status: string;
|
|
275
|
+
last_heartbeat: string | null;
|
|
276
|
+
events_last_7d: number;
|
|
277
|
+
defined_budget: number | null;
|
|
278
|
+
budget_unit: string | null;
|
|
279
|
+
}>();
|
|
280
|
+
|
|
281
|
+
// Build summary
|
|
282
|
+
const entries = result.results ?? [];
|
|
283
|
+
const summary = {
|
|
284
|
+
active: entries.filter((e) => e.status === 'active').length,
|
|
285
|
+
dormant: entries.filter((e) => e.status === 'dormant').length,
|
|
286
|
+
undefined: entries.filter((e) => e.status === 'undefined').length,
|
|
287
|
+
total: entries.length,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
return Response.json({
|
|
291
|
+
success: true,
|
|
292
|
+
data: {
|
|
293
|
+
auditTime: latestResult.latest,
|
|
294
|
+
summary,
|
|
295
|
+
features: entries,
|
|
296
|
+
},
|
|
297
|
+
timestamp: new Date().toISOString(),
|
|
298
|
+
});
|
|
299
|
+
} catch (error) {
|
|
300
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
301
|
+
return Response.json(
|
|
302
|
+
{ success: false, error: 'Failed to get feature coverage', message },
|
|
303
|
+
{ status: 500 }
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|