@sansavision/aurora 0.1.0-alpha.20260212.4
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 +4 -0
- package/package.json +17 -0
- package/src/ai-diagnostics.ts +156 -0
- package/src/ai.ts +574 -0
- package/src/analyze.ts +669 -0
- package/src/bin/aurora.ts +15 -0
- package/src/build.ts +431 -0
- package/src/bun-test-shims.d.ts +17 -0
- package/src/create-feature.ts +419 -0
- package/src/create-route.ts +581 -0
- package/src/create.ts +425 -0
- package/src/dev.ts +126 -0
- package/src/devtools.ts +1143 -0
- package/src/doctor.ts +611 -0
- package/src/explain.ts +855 -0
- package/src/help.ts +39 -0
- package/src/index.ts +34 -0
- package/src/init.ts +1011 -0
- package/src/inspect-cache.ts +464 -0
- package/src/lsp-inline-hints.ts +254 -0
- package/src/node-shims.d.ts +26 -0
- package/src/process.d.ts +11 -0
- package/src/query-profiler.ts +520 -0
- package/src/realtime-monitor.ts +389 -0
- package/src/registry.ts +303 -0
- package/src/run.ts +37 -0
- package/src/start.ts +56 -0
- package/src/test.ts +289 -0
- package/templates/basic/README.md +16 -0
- package/templates/basic/package.json +10 -0
- package/templates/basic/src/actions/createMessage.action.server.ts +22 -0
- package/templates/basic/src/lib/auth.server.ts +11 -0
- package/templates/basic/src/queries/listMessages.server.ts +17 -0
- package/templates/basic/src/routes/index.tsx +12 -0
- package/templates/blog/README.md +17 -0
- package/templates/blog/package.json +12 -0
- package/templates/blog/public/assets/og-default.svg +17 -0
- package/templates/blog/src/content/loadPosts.server.ts +22 -0
- package/templates/blog/src/content/posts/hello-world.md +11 -0
- package/templates/blog/src/content/posts/release-notes.md +9 -0
- package/templates/blog/src/routes/index.tsx +22 -0
- package/templates/blog/src/routes/posts/[slug].tsx +19 -0
- package/templates/blog/src/seo/meta.ts +19 -0
- package/templates/dashboard/README.md +18 -0
- package/templates/dashboard/package.json +10 -0
- package/templates/dashboard/src/actions/acknowledgeAlert.action.server.ts +6 -0
- package/templates/dashboard/src/queries/getDashboardMetrics.server.ts +30 -0
- package/templates/dashboard/src/realtime/useDashboardRealtime.client.ts +13 -0
- package/templates/dashboard/src/routes/index.tsx +19 -0
- package/templates/dashboard/src/widgets/DataGrid.client.ts +8 -0
- package/templates/dashboard/src/widgets/MetricChart.client.ts +8 -0
- package/templates/desktop/README.md +18 -0
- package/templates/desktop/package.json +11 -0
- package/templates/desktop/src/actions/saveDesktopPreference.action.server.ts +28 -0
- package/templates/desktop/src/desktop/secureStorage.client.ts +20 -0
- package/templates/desktop/src/desktop/tauriBridge.client.ts +14 -0
- package/templates/desktop/src/queries/getDesktopSyncStatus.server.ts +9 -0
- package/templates/desktop/src/routes/index.tsx +27 -0
- package/templates/desktop/src/sync/offlineSyncBoundary.server.ts +27 -0
- package/templates/feature-skeleton/README.md +13 -0
- package/templates/feature-skeleton/actions/createFeature.action.server.ts +19 -0
- package/templates/feature-skeleton/index.ts +8 -0
- package/templates/feature-skeleton/queries/listFeature.server.ts +15 -0
- package/templates/feature-skeleton/realtime/useFeatureRealtime.client.ts +16 -0
- package/templates/feature-skeleton/template.manifest.json +15 -0
- package/templates/feature-skeleton/ui/FeatureView.client.tsx +14 -0
- package/templates/mobile/README.md +17 -0
- package/templates/mobile/package.json +11 -0
- package/templates/mobile/src/mobile/auth/session-handoff.client.ts +69 -0
- package/templates/mobile/src/mobile/generated/mobile-api-sdk.ts +62 -0
- package/templates/mobile/src/mobile/transport/mobile-api-transport.client.ts +122 -0
- package/templates/mobile/src/routes/index.tsx +134 -0
- package/templates/monorepo/README.md +18 -0
- package/templates/monorepo/apps/web/package.json +9 -0
- package/templates/monorepo/apps/web/src/routes/index.tsx +1 -0
- package/templates/monorepo/package.json +13 -0
- package/templates/monorepo/packages/shared/README.md +3 -0
- package/templates/monorepo/packages/ui/README.md +3 -0
- package/templates/saas/README.md +17 -0
- package/templates/saas/package.json +10 -0
- package/templates/saas/src/admin/getDashboard.server.ts +18 -0
- package/templates/saas/src/auth/session.server.ts +13 -0
- package/templates/saas/src/billing/checkout.server.ts +11 -0
- package/templates/saas/src/email/sendWelcome.server.ts +8 -0
- package/templates/saas/src/realtime/notifications.server.ts +8 -0
- package/templates/saas/src/routes/index.tsx +20 -0
- package/test/ai.test.ts +94 -0
- package/test/analyze.test.ts +301 -0
- package/test/build.test.ts +135 -0
- package/test/create-feature.test.ts +145 -0
- package/test/create-route.test.ts +117 -0
- package/test/create.test.ts +222 -0
- package/test/dev.test.ts +52 -0
- package/test/devtools.test.ts +130 -0
- package/test/doctor.test.ts +129 -0
- package/test/explain.test.ts +232 -0
- package/test/feature-skeleton.test.ts +53 -0
- package/test/fixtures/analyze/cache-input.invalid.json +1 -0
- package/test/fixtures/analyze/cache-input.missing-keyhash.v1.json +10 -0
- package/test/fixtures/analyze/cache-input.unsupported-version.v2.json +10 -0
- package/test/fixtures/analyze/cache-input.v1.json +12 -0
- package/test/fixtures/analyze/compiler-manifest/manifest.json +11 -0
- package/test/fixtures/analyze/guardrails-input.unsupported-version.v2.json +4 -0
- package/test/fixtures/analyze/guardrails-input.v1.json +49 -0
- package/test/fixtures/analyze/query-input.invalid-cache-status.v1.json +11 -0
- package/test/fixtures/analyze/query-input.unsupported-version.v2.json +11 -0
- package/test/fixtures/analyze/query-input.v1.json +18 -0
- package/test/fixtures/analyze/realtime-input.missing-lag-p95.v1.json +10 -0
- package/test/fixtures/analyze/realtime-input.unsupported-version.v2.json +8 -0
- package/test/fixtures/analyze/realtime-input.v1.json +12 -0
- package/test/fixtures/cache-inspector/cache-input.v1.json +23 -0
- package/test/fixtures/cache-inspector/invalid.json +1 -0
- package/test/fixtures/cache-inspector/snapshot.v1.json +34 -0
- package/test/fixtures/cache-inspector/unsupported-version.v2.json +13 -0
- package/test/fixtures/devtools/healthy.v1.json +130 -0
- package/test/fixtures/devtools/invalid.json +1 -0
- package/test/fixtures/devtools/unsupported-version.v2.json +8 -0
- package/test/fixtures/devtools/warn.v1.json +114 -0
- package/test/fixtures/doctor/clean/src/page.tsx +3 -0
- package/test/fixtures/doctor/findings/src/accessibility.client.tsx +7 -0
- package/test/fixtures/doctor/findings/src/migration.config.ts +3 -0
- package/test/fixtures/doctor/findings/src/page.client.tsx +5 -0
- package/test/fixtures/doctor/findings/src/perf.server.ts +15 -0
- package/test/fixtures/doctor/findings/src/routes.js +3 -0
- package/test/fixtures/doctor/findings/src/security.server.ts +7 -0
- package/test/fixtures/doctor/findings/src/users.server.ts +3 -0
- package/test/fixtures/doctor/governance/src/features/analytics/OWNERS.ts +2 -0
- package/test/fixtures/doctor/governance/src/features/analytics/page.tsx +3 -0
- package/test/fixtures/doctor/governance/src/features/billing/page.tsx +3 -0
- package/test/fixtures/explain/invalid.json +1 -0
- package/test/fixtures/explain/module-report.unsupported-version.v2.json +6 -0
- package/test/fixtures/explain/module-report.v1.json +72 -0
- package/test/fixtures/query-profiler/healthy.v1.json +11 -0
- package/test/fixtures/query-profiler/invalid.json +1 -0
- package/test/fixtures/query-profiler/unsupported-version.v2.json +6 -0
- package/test/fixtures/query-profiler/warning.v1.json +10 -0
- package/test/fixtures/realtime-monitor/healthy.v1.json +8 -0
- package/test/fixtures/realtime-monitor/invalid.json +1 -0
- package/test/fixtures/realtime-monitor/unsupported-version.v2.json +8 -0
- package/test/fixtures/realtime-monitor/warning.v1.json +8 -0
- package/test/help-parity.test.ts +104 -0
- package/test/init.test.ts +164 -0
- package/test/inspect-cache.test.ts +112 -0
- package/test/lsp-inline-hints.test.ts +65 -0
- package/test/query-profiler.test.ts +123 -0
- package/test/realtime-monitor.test.ts +115 -0
- package/test/registry.test.ts +41 -0
- package/test/start.test.ts +23 -0
- package/test/test-command.test.ts +65 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { type CommandContext, type CommandResult } from "./registry";
|
|
5
|
+
|
|
6
|
+
type RealtimeMonitorFormat = "text" | "json";
|
|
7
|
+
type RealtimeMonitorStatus = "ok" | "warn";
|
|
8
|
+
|
|
9
|
+
interface RealtimeMonitorOptions {
|
|
10
|
+
inputPath: string;
|
|
11
|
+
format: RealtimeMonitorFormat;
|
|
12
|
+
maxDropRatio: number;
|
|
13
|
+
maxLagP95Ms: number;
|
|
14
|
+
minDeliveredRps?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface RealtimeMonitorIssue {
|
|
18
|
+
code: "DROP_RATIO_EXCEEDED" | "LAG_P95_EXCEEDED" | "DELIVERED_RPS_BELOW_MIN";
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface RealtimeMonitorReport {
|
|
23
|
+
mode: "realtime-monitor";
|
|
24
|
+
projectRoot: string;
|
|
25
|
+
inputPath: string;
|
|
26
|
+
status: RealtimeMonitorStatus;
|
|
27
|
+
received: number;
|
|
28
|
+
delivered: number;
|
|
29
|
+
dropped: number;
|
|
30
|
+
lagP95Ms: number;
|
|
31
|
+
windowSeconds: number;
|
|
32
|
+
deliveredRps: number;
|
|
33
|
+
droppedRps: number;
|
|
34
|
+
dropRatio: number;
|
|
35
|
+
thresholds: {
|
|
36
|
+
maxDropRatio: number;
|
|
37
|
+
maxLagP95Ms: number;
|
|
38
|
+
minDeliveredRps?: number;
|
|
39
|
+
};
|
|
40
|
+
issues: RealtimeMonitorIssue[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const DEFAULT_MAX_DROP_RATIO = 0.05;
|
|
44
|
+
const DEFAULT_MAX_LAG_P95_MS = 250;
|
|
45
|
+
const DEFAULT_WINDOW_SECONDS = 60;
|
|
46
|
+
|
|
47
|
+
function parseNonNegativeNumber(raw: string | undefined, flag: string): number | CommandResult {
|
|
48
|
+
if (!raw) {
|
|
49
|
+
return {
|
|
50
|
+
exitCode: 2,
|
|
51
|
+
stderr: `aurora monitor-realtime: ${flag} requires a numeric value`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const parsed = Number(raw);
|
|
56
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
57
|
+
return {
|
|
58
|
+
exitCode: 2,
|
|
59
|
+
stderr: `aurora monitor-realtime: ${flag} must be a non-negative number`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return parsed;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parseRealtimeMonitorOptions(args: ReadonlyArray<string>): RealtimeMonitorOptions | CommandResult {
|
|
67
|
+
const options: RealtimeMonitorOptions = {
|
|
68
|
+
inputPath: "",
|
|
69
|
+
format: "text",
|
|
70
|
+
maxDropRatio: DEFAULT_MAX_DROP_RATIO,
|
|
71
|
+
maxLagP95Ms: DEFAULT_MAX_LAG_P95_MS,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
75
|
+
const arg = args[i];
|
|
76
|
+
if (arg === "--input") {
|
|
77
|
+
const value = args[i + 1];
|
|
78
|
+
if (!value) {
|
|
79
|
+
return {
|
|
80
|
+
exitCode: 2,
|
|
81
|
+
stderr: "aurora monitor-realtime: --input requires a path value",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
options.inputPath = value;
|
|
86
|
+
i += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (arg === "--format") {
|
|
91
|
+
const value = args[i + 1];
|
|
92
|
+
if (!value) {
|
|
93
|
+
return {
|
|
94
|
+
exitCode: 2,
|
|
95
|
+
stderr: "aurora monitor-realtime: --format requires 'text' or 'json'",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (value !== "text" && value !== "json") {
|
|
100
|
+
return {
|
|
101
|
+
exitCode: 2,
|
|
102
|
+
stderr: `aurora monitor-realtime: invalid format '${value}'. Expected 'text' or 'json'`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
options.format = value;
|
|
107
|
+
i += 1;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (arg === "--max-drop-ratio") {
|
|
112
|
+
const parsed = parseNonNegativeNumber(args[i + 1], "--max-drop-ratio");
|
|
113
|
+
if (typeof parsed !== "number") {
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
options.maxDropRatio = parsed;
|
|
118
|
+
i += 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (arg === "--max-lag-p95-ms") {
|
|
123
|
+
const parsed = parseNonNegativeNumber(args[i + 1], "--max-lag-p95-ms");
|
|
124
|
+
if (typeof parsed !== "number") {
|
|
125
|
+
return parsed;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
options.maxLagP95Ms = parsed;
|
|
129
|
+
i += 1;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (arg === "--min-delivered-rps") {
|
|
134
|
+
const parsed = parseNonNegativeNumber(args[i + 1], "--min-delivered-rps");
|
|
135
|
+
if (typeof parsed !== "number") {
|
|
136
|
+
return parsed;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
options.minDeliveredRps = parsed;
|
|
140
|
+
i += 1;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
exitCode: 2,
|
|
146
|
+
stderr: `aurora monitor-realtime: unknown option '${arg}'`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!options.inputPath) {
|
|
151
|
+
return {
|
|
152
|
+
exitCode: 2,
|
|
153
|
+
stderr: "aurora monitor-realtime: --input is required",
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return options;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function toRecord(value: unknown): Record<string, unknown> | undefined {
|
|
161
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return value as Record<string, unknown>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function isCommandResult(value: unknown): value is CommandResult {
|
|
169
|
+
const source = toRecord(value);
|
|
170
|
+
return Boolean(source && typeof source.exitCode === "number");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getRequiredNumber(source: Record<string, unknown>, fields: ReadonlyArray<string>): number {
|
|
174
|
+
for (const field of fields) {
|
|
175
|
+
const value = source[field];
|
|
176
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
throw new Error(`missing required numeric field (${fields.join(" or ")})`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getOptionalNumber(source: Record<string, unknown>, fields: ReadonlyArray<string>): number | undefined {
|
|
185
|
+
for (const field of fields) {
|
|
186
|
+
const value = source[field];
|
|
187
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function readInputJson(inputPath: string, context: CommandContext): unknown | CommandResult {
|
|
196
|
+
const absolutePath = resolve(context.cwd, inputPath);
|
|
197
|
+
let raw = "";
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
raw = readFileSync(absolutePath, "utf8");
|
|
201
|
+
} catch {
|
|
202
|
+
return {
|
|
203
|
+
exitCode: 1,
|
|
204
|
+
stderr: `aurora monitor-realtime: unable to read input at ${inputPath}`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
return JSON.parse(raw);
|
|
210
|
+
} catch {
|
|
211
|
+
return {
|
|
212
|
+
exitCode: 1,
|
|
213
|
+
stderr: `aurora monitor-realtime: invalid json input at ${inputPath}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function assertSupportedSchemaVersion(payload: unknown): void {
|
|
219
|
+
const source = toRecord(payload);
|
|
220
|
+
if (!source) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const rawSchemaVersion = source.schemaVersion;
|
|
225
|
+
if (rawSchemaVersion === undefined) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (rawSchemaVersion !== 1) {
|
|
230
|
+
throw new Error(`unsupported schemaVersion ${String(rawSchemaVersion)} for realtime input; expected 1`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function buildRealtimeMonitorReport(
|
|
235
|
+
options: RealtimeMonitorOptions,
|
|
236
|
+
context: CommandContext,
|
|
237
|
+
): RealtimeMonitorReport | CommandResult {
|
|
238
|
+
const payload = readInputJson(options.inputPath, context);
|
|
239
|
+
if (isCommandResult(payload)) {
|
|
240
|
+
return payload;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let source: Record<string, unknown>;
|
|
244
|
+
try {
|
|
245
|
+
assertSupportedSchemaVersion(payload);
|
|
246
|
+
source = toRecord(payload) ?? {};
|
|
247
|
+
if (!toRecord(payload)) {
|
|
248
|
+
throw new Error("realtime monitor input must be an object");
|
|
249
|
+
}
|
|
250
|
+
} catch (error) {
|
|
251
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
252
|
+
return {
|
|
253
|
+
exitCode: 1,
|
|
254
|
+
stderr: `aurora monitor-realtime: ${reason}`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const received = getRequiredNumber(source, ["received", "rx", "totalReceived"]);
|
|
260
|
+
const delivered = getRequiredNumber(source, ["delivered", "tx", "totalDelivered"]);
|
|
261
|
+
const dropped = getRequiredNumber(source, ["dropped", "totalDropped"]);
|
|
262
|
+
const lagP95Ms = getRequiredNumber(source, ["lagP95Ms", "p95"]);
|
|
263
|
+
const windowSeconds =
|
|
264
|
+
getOptionalNumber(source, ["windowSeconds", "windowSec", "intervalSec"]) ??
|
|
265
|
+
DEFAULT_WINDOW_SECONDS;
|
|
266
|
+
|
|
267
|
+
if (windowSeconds <= 0) {
|
|
268
|
+
throw new Error("windowSeconds must be a positive number");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const dropRatio = received > 0 ? dropped / received : 0;
|
|
272
|
+
const deliveredRps = delivered / windowSeconds;
|
|
273
|
+
const droppedRps = dropped / windowSeconds;
|
|
274
|
+
const issues: RealtimeMonitorIssue[] = [];
|
|
275
|
+
|
|
276
|
+
if (dropRatio > options.maxDropRatio) {
|
|
277
|
+
issues.push({
|
|
278
|
+
code: "DROP_RATIO_EXCEEDED",
|
|
279
|
+
message:
|
|
280
|
+
`drop ratio ${dropRatio.toFixed(4)} exceeds threshold ${options.maxDropRatio.toFixed(4)}`,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (lagP95Ms > options.maxLagP95Ms) {
|
|
285
|
+
issues.push({
|
|
286
|
+
code: "LAG_P95_EXCEEDED",
|
|
287
|
+
message: `lag p95 ${lagP95Ms}ms exceeds threshold ${options.maxLagP95Ms}ms`,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (options.minDeliveredRps !== undefined && deliveredRps < options.minDeliveredRps) {
|
|
292
|
+
issues.push({
|
|
293
|
+
code: "DELIVERED_RPS_BELOW_MIN",
|
|
294
|
+
message:
|
|
295
|
+
`delivered rps ${deliveredRps.toFixed(4)} is below minimum ` +
|
|
296
|
+
`${options.minDeliveredRps.toFixed(4)}`,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const status: RealtimeMonitorStatus = issues.length > 0 ? "warn" : "ok";
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
mode: "realtime-monitor",
|
|
304
|
+
projectRoot: context.cwd,
|
|
305
|
+
inputPath: options.inputPath,
|
|
306
|
+
status,
|
|
307
|
+
received,
|
|
308
|
+
delivered,
|
|
309
|
+
dropped,
|
|
310
|
+
lagP95Ms,
|
|
311
|
+
windowSeconds,
|
|
312
|
+
deliveredRps,
|
|
313
|
+
droppedRps,
|
|
314
|
+
dropRatio,
|
|
315
|
+
thresholds: {
|
|
316
|
+
maxDropRatio: options.maxDropRatio,
|
|
317
|
+
maxLagP95Ms: options.maxLagP95Ms,
|
|
318
|
+
minDeliveredRps: options.minDeliveredRps,
|
|
319
|
+
},
|
|
320
|
+
issues,
|
|
321
|
+
};
|
|
322
|
+
} catch (error) {
|
|
323
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
324
|
+
return {
|
|
325
|
+
exitCode: 1,
|
|
326
|
+
stderr: `aurora monitor-realtime: ${reason}`,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function renderRealtimeMonitorText(report: RealtimeMonitorReport): string {
|
|
332
|
+
const lines = [
|
|
333
|
+
"aurora realtime monitor report",
|
|
334
|
+
`project_root: ${report.projectRoot}`,
|
|
335
|
+
`input_path: ${report.inputPath}`,
|
|
336
|
+
`status: ${report.status}`,
|
|
337
|
+
`received: ${report.received}`,
|
|
338
|
+
`delivered: ${report.delivered}`,
|
|
339
|
+
`dropped: ${report.dropped}`,
|
|
340
|
+
`drop_ratio: ${report.dropRatio.toFixed(4)}`,
|
|
341
|
+
`lag_p95_ms: ${report.lagP95Ms}`,
|
|
342
|
+
`window_seconds: ${report.windowSeconds}`,
|
|
343
|
+
`delivered_rps: ${report.deliveredRps.toFixed(4)}`,
|
|
344
|
+
`dropped_rps: ${report.droppedRps.toFixed(4)}`,
|
|
345
|
+
`max_drop_ratio: ${report.thresholds.maxDropRatio.toFixed(4)}`,
|
|
346
|
+
`max_lag_p95_ms: ${report.thresholds.maxLagP95Ms}`,
|
|
347
|
+
];
|
|
348
|
+
|
|
349
|
+
if (report.thresholds.minDeliveredRps !== undefined) {
|
|
350
|
+
lines.push(`min_delivered_rps: ${report.thresholds.minDeliveredRps.toFixed(4)}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (report.issues.length > 0) {
|
|
354
|
+
lines.push("issues:");
|
|
355
|
+
for (const issue of report.issues) {
|
|
356
|
+
lines.push(`- [${issue.code}] ${issue.message}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return lines.join("\n");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function runRealtimeMonitorCommand(
|
|
364
|
+
args: ReadonlyArray<string>,
|
|
365
|
+
context: CommandContext,
|
|
366
|
+
): CommandResult {
|
|
367
|
+
const options = parseRealtimeMonitorOptions(args);
|
|
368
|
+
if ("exitCode" in options) {
|
|
369
|
+
return options;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const report = buildRealtimeMonitorReport(options, context);
|
|
373
|
+
if ("exitCode" in report) {
|
|
374
|
+
return report;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const exitCode = report.status === "warn" ? 1 : 0;
|
|
378
|
+
if (options.format === "json") {
|
|
379
|
+
return {
|
|
380
|
+
exitCode,
|
|
381
|
+
stdout: JSON.stringify(report, null, 2),
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
exitCode,
|
|
387
|
+
stdout: renderRealtimeMonitorText(report),
|
|
388
|
+
};
|
|
389
|
+
}
|
package/src/registry.ts
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { runAnalyzeCommand } from "./analyze";
|
|
2
|
+
import { runAiCommand } from "./ai";
|
|
3
|
+
import { runBuildCommand } from "./build";
|
|
4
|
+
import { runCreateCommand } from "./create";
|
|
5
|
+
import { runCreateFeatureCommand } from "./create-feature";
|
|
6
|
+
import { runCreateRouteCommand } from "./create-route";
|
|
7
|
+
import { runDevCommand } from "./dev";
|
|
8
|
+
import { runDevtoolsCommand } from "./devtools";
|
|
9
|
+
import { runDoctorCommand } from "./doctor";
|
|
10
|
+
import { runExplainCommand } from "./explain";
|
|
11
|
+
import { runInitCommand } from "./init";
|
|
12
|
+
import { runInspectCacheCommand } from "./inspect-cache";
|
|
13
|
+
import { runQueryProfilerCommand } from "./query-profiler";
|
|
14
|
+
import { runRealtimeMonitorCommand } from "./realtime-monitor";
|
|
15
|
+
import { runStartCommand } from "./start";
|
|
16
|
+
import { runTestCommand } from "./test";
|
|
17
|
+
|
|
18
|
+
export interface CommandContext {
|
|
19
|
+
cwd: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CommandResult {
|
|
23
|
+
exitCode: number;
|
|
24
|
+
stdout?: string;
|
|
25
|
+
stderr?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CommandDefinition {
|
|
29
|
+
name: string;
|
|
30
|
+
synopsis: string;
|
|
31
|
+
summary: string;
|
|
32
|
+
options?: ReadonlyArray<{ flag: string; description: string }>;
|
|
33
|
+
run: (args: ReadonlyArray<string>, context: CommandContext) => CommandResult;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const commandRegistry: ReadonlyArray<CommandDefinition> = [
|
|
37
|
+
{
|
|
38
|
+
name: "create",
|
|
39
|
+
synopsis: "create <name>",
|
|
40
|
+
summary: "Create new project",
|
|
41
|
+
options: [
|
|
42
|
+
{ flag: "--template", description: "Choose starter template" },
|
|
43
|
+
{ flag: "--git", description: "Initialize git repo" },
|
|
44
|
+
],
|
|
45
|
+
run: (args, context) => runCreateCommand(args, context),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "init",
|
|
49
|
+
synopsis: "init",
|
|
50
|
+
summary: "Initialize migration/adoption scaffold",
|
|
51
|
+
options: [
|
|
52
|
+
{
|
|
53
|
+
flag: "--from next|remix|sveltekit",
|
|
54
|
+
description: "Select the source framework to migrate from",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
flag: "--mode incremental|side-by-side",
|
|
58
|
+
description: "Choose migration rollout strategy",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
flag: "--bridge react|none",
|
|
62
|
+
description: "Generate React interop bridge helper",
|
|
63
|
+
},
|
|
64
|
+
{ flag: "--out-dir <path>", description: "Output directory for migration scaffold files" },
|
|
65
|
+
{ flag: "--dry-run", description: "Preview migration output without writing files" },
|
|
66
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
67
|
+
],
|
|
68
|
+
run: (args, context) => runInitCommand(args, context),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "dev",
|
|
72
|
+
synopsis: "dev",
|
|
73
|
+
summary: "Start development server",
|
|
74
|
+
options: [
|
|
75
|
+
{ flag: "--port <n>", description: "Set dev server port" },
|
|
76
|
+
{ flag: "--open", description: "Open app in browser" },
|
|
77
|
+
{ flag: "--https", description: "Enable HTTPS dev mode" },
|
|
78
|
+
],
|
|
79
|
+
run: (args, context) => runDevCommand(args, context),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "devtools",
|
|
83
|
+
synopsis: "devtools",
|
|
84
|
+
summary: "DevTools v2 panel report",
|
|
85
|
+
options: [
|
|
86
|
+
{ flag: "--input <path>", description: "DevTools snapshot JSON path" },
|
|
87
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
88
|
+
{
|
|
89
|
+
flag: "--panel explain|waterfall|performance|realtime|auth",
|
|
90
|
+
description: "Select one panel (repeat or comma-separate to select multiple)",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
flag: "--max-waterfall-blocking-ms <n>",
|
|
94
|
+
description: "Warn threshold for blocking waterfall operations",
|
|
95
|
+
},
|
|
96
|
+
{ flag: "--max-lag-p95-ms <n>", description: "Warn threshold for realtime lag p95" },
|
|
97
|
+
{ flag: "--max-drop-ratio <n>", description: "Warn threshold for realtime drop ratio" },
|
|
98
|
+
{ flag: "--min-route-score <n>", description: "Warn threshold for per-route performance score" },
|
|
99
|
+
],
|
|
100
|
+
run: (args, context) => runDevtoolsCommand(args, context),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "build",
|
|
104
|
+
synopsis: "build",
|
|
105
|
+
summary: "Build for production",
|
|
106
|
+
options: [
|
|
107
|
+
{
|
|
108
|
+
flag: "--target node|edge|static",
|
|
109
|
+
description: "Choose deployment target",
|
|
110
|
+
},
|
|
111
|
+
{ flag: "--analyze", description: "Generate bundle analysis during build" },
|
|
112
|
+
{ flag: "--skip-audit", description: "Disable dependency vulnerability gate" },
|
|
113
|
+
{
|
|
114
|
+
flag: "--audit-severity low|moderate|high|critical",
|
|
115
|
+
description: "Fail build when vulnerabilities meet/exceed threshold",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
flag: "--audit-report <path>",
|
|
119
|
+
description: "Override dependency audit report JSON path",
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
run: (args, context) => runBuildCommand(args, context),
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "start",
|
|
126
|
+
synopsis: "start",
|
|
127
|
+
summary: "Run production build",
|
|
128
|
+
run: (args, context) => runStartCommand(args, context),
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "analyze",
|
|
132
|
+
synopsis: "analyze",
|
|
133
|
+
summary: "Bundle analysis",
|
|
134
|
+
options: [
|
|
135
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
136
|
+
{
|
|
137
|
+
flag: "--mode bundle|cache|realtime|query|guardrails",
|
|
138
|
+
description: "Select analyze report mode",
|
|
139
|
+
},
|
|
140
|
+
{ flag: "--out-dir <path>", description: "Compiler output directory" },
|
|
141
|
+
{
|
|
142
|
+
flag: "--input <path>",
|
|
143
|
+
description: "Input JSON path for cache/realtime/query modes",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
flag: "--max-drop-ratio <n>",
|
|
147
|
+
description: "Realtime warning threshold for drop ratio",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
flag: "--max-lag-p95-ms <n>",
|
|
151
|
+
description: "Realtime warning threshold for p95 lag",
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
run: (args, context) => runAnalyzeCommand(args, context),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "ai",
|
|
158
|
+
synopsis: "ai <description>",
|
|
159
|
+
summary: "AI-assisted feature scaffolding",
|
|
160
|
+
options: [
|
|
161
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
162
|
+
{ flag: "--dry-run", description: "Preview inferred scaffold plan without writing files" },
|
|
163
|
+
{ flag: "--name <feature-slug>", description: "Override inferred feature slug" },
|
|
164
|
+
{
|
|
165
|
+
flag: "--auth public|user|admin|permission:<name>",
|
|
166
|
+
description: "Override inferred route auth metadata",
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
run: (args, context) => runAiCommand(args, context),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "doctor",
|
|
173
|
+
synopsis: "doctor",
|
|
174
|
+
summary: "Project health checks",
|
|
175
|
+
options: [
|
|
176
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
177
|
+
],
|
|
178
|
+
run: (args, context) => runDoctorCommand(args, context),
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: "explain",
|
|
182
|
+
synopsis: "explain <module-path>",
|
|
183
|
+
summary: "Explain inferred module behavior",
|
|
184
|
+
options: [
|
|
185
|
+
{
|
|
186
|
+
flag: "--input <path>",
|
|
187
|
+
description: "Explain snapshot JSON path",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
flag: "--format text|json",
|
|
191
|
+
description: "Choose report output format",
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
run: (args, context) => runExplainCommand(args, context),
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "inspect-cache",
|
|
198
|
+
synopsis: "inspect-cache",
|
|
199
|
+
summary: "DevTools cache inspector",
|
|
200
|
+
options: [
|
|
201
|
+
{ flag: "--input <path>", description: "Cache snapshot or cache report JSON path" },
|
|
202
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
203
|
+
{ flag: "--tag <tag>", description: "Filter entries by cache tag" },
|
|
204
|
+
{ flag: "--limit <n>", description: "Cap largest_entries rows (default 20)" },
|
|
205
|
+
],
|
|
206
|
+
run: (args, context) => runInspectCacheCommand(args, context),
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "monitor-realtime",
|
|
210
|
+
synopsis: "monitor-realtime",
|
|
211
|
+
summary: "DevTools realtime monitor",
|
|
212
|
+
options: [
|
|
213
|
+
{ flag: "--input <path>", description: "Realtime metrics JSON path" },
|
|
214
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
215
|
+
{ flag: "--max-drop-ratio <n>", description: "Warn threshold for dropped/received ratio" },
|
|
216
|
+
{ flag: "--max-lag-p95-ms <n>", description: "Warn threshold for p95 lag in milliseconds" },
|
|
217
|
+
{ flag: "--min-delivered-rps <n>", description: "Warn threshold for minimum delivered rate" },
|
|
218
|
+
],
|
|
219
|
+
run: (args, context) => runRealtimeMonitorCommand(args, context),
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: "profile-query",
|
|
223
|
+
synopsis: "profile-query",
|
|
224
|
+
summary: "DevTools query profiler",
|
|
225
|
+
options: [
|
|
226
|
+
{ flag: "--input <path>", description: "Query metrics JSON path" },
|
|
227
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
228
|
+
{ flag: "--max-p95-ms <n>", description: "Warn threshold for aggregate p95 query latency" },
|
|
229
|
+
{ flag: "--min-cache-hit-ratio <n>", description: "Warn threshold for aggregate cache hit ratio" },
|
|
230
|
+
{ flag: "--limit <n>", description: "Cap slow_queries rows (default 10)" },
|
|
231
|
+
],
|
|
232
|
+
run: (args, context) => runQueryProfilerCommand(args, context),
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "test",
|
|
236
|
+
synopsis: "test",
|
|
237
|
+
summary: "Run tests",
|
|
238
|
+
options: [
|
|
239
|
+
{
|
|
240
|
+
flag: "--template basic|saas|blog|dashboard",
|
|
241
|
+
description: "Filter e2e matrix to one template",
|
|
242
|
+
},
|
|
243
|
+
{ flag: "--format text|json", description: "Choose report output format" },
|
|
244
|
+
],
|
|
245
|
+
run: (args, context) => runTestCommand(args, context),
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "create-feature",
|
|
249
|
+
synopsis: "create-feature <name>",
|
|
250
|
+
summary: "Scaffold a feature module",
|
|
251
|
+
options: [
|
|
252
|
+
{
|
|
253
|
+
flag: "--kind crud|read-only|form|dashboard|empty",
|
|
254
|
+
description: "Route scaffold pattern to pair with the feature",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
flag: "--data database|api|none",
|
|
258
|
+
description: "Primary data source mode for generated route boilerplate",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
flag: "--auth public|user|admin|permission:<name>",
|
|
262
|
+
description: "Route auth metadata default",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
flag: "--route|--no-route",
|
|
266
|
+
description: "Enable/disable paired route scaffolding (default enabled)",
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
flag: "--realtime|--no-realtime",
|
|
270
|
+
description: "Enable/disable realtime boilerplate in paired route",
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
run: (args, context) => runCreateFeatureCommand(args, context),
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "create-route",
|
|
277
|
+
synopsis: "create-route <name>",
|
|
278
|
+
summary: "Scaffold a route module",
|
|
279
|
+
options: [
|
|
280
|
+
{
|
|
281
|
+
flag: "--kind crud|read-only|form|dashboard|empty",
|
|
282
|
+
description: "Choose route scaffold pattern",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
flag: "--data database|api|none",
|
|
286
|
+
description: "Set generated data source hint metadata",
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
flag: "--auth public|user|admin|permission:<name>",
|
|
290
|
+
description: "Set generated route auth metadata",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
flag: "--realtime|--no-realtime",
|
|
294
|
+
description: "Enable/disable realtime scaffold metadata",
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
run: (args, context) => runCreateRouteCommand(args, context),
|
|
298
|
+
},
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
export function findCommand(name: string): CommandDefinition | undefined {
|
|
302
|
+
return commandRegistry.find((command) => command.name === name);
|
|
303
|
+
}
|