Highly ambitious ATProtocol AppView service and sdks

add jetstream logs command

+107
+101
packages/cli/src/commands/logs.ts
··· 1 + import { parseArgs } from "@std/cli/parse-args"; 2 + import { red, yellow, cyan, gray } from "@std/fmt/colors"; 3 + import { createAuthenticatedClient } from "../utils/client.ts"; 4 + import { logger } from "../utils/logger.ts"; 5 + import { SlicesConfigLoader, mergeConfig } from "../utils/config.ts"; 6 + 7 + function showLogsHelp() { 8 + console.log(` 9 + slices logs - View Jetstream logs for a slice 10 + 11 + USAGE: 12 + slices logs [OPTIONS] 13 + 14 + OPTIONS: 15 + --slice <SLICE_URI> Target slice URI (optional, or from slices.json) 16 + --limit <NUMBER> Maximum number of log entries to return (default: 100, max: 1000) 17 + --api-url <URL> Slices API base URL (default: https://api.slices.network or from slices.json) 18 + -h, --help Show this help message 19 + 20 + EXAMPLES: 21 + slices logs --slice at://did:plc:example/slice 22 + slices logs --limit 50 23 + slices logs # Uses config from slices.json 24 + `); 25 + } 26 + 27 + export async function logsCommand(commandArgs: unknown[], _globalArgs: Record<string, unknown>): Promise<void> { 28 + const args = parseArgs(commandArgs as string[], { 29 + boolean: ["help"], 30 + string: ["slice", "api-url", "limit"], 31 + alias: { 32 + h: "help", 33 + }, 34 + }); 35 + 36 + if (args.help) { 37 + showLogsHelp(); 38 + return; 39 + } 40 + 41 + const configLoader = new SlicesConfigLoader(); 42 + const slicesConfig = await configLoader.load(); 43 + const mergedConfig = mergeConfig(slicesConfig, args); 44 + 45 + const sliceUri = mergedConfig.slice; 46 + const apiUrl = mergedConfig.apiUrl || "https://api.slices.network"; 47 + const limit = args.limit ? parseInt(args.limit as string, 10) : 100; 48 + 49 + if (isNaN(limit) || limit < 1 || limit > 1000) { 50 + logger.error("--limit must be a number between 1 and 1000"); 51 + Deno.exit(1); 52 + } 53 + 54 + try { 55 + const client = await createAuthenticatedClient(sliceUri || "", apiUrl); 56 + 57 + const response = await client.network.slices.slice.getJetstreamLogs({ 58 + slice: sliceUri, 59 + limit, 60 + }); 61 + 62 + if (response.logs.length === 0) { 63 + logger.info("No logs found"); 64 + return; 65 + } 66 + 67 + logger.section(`Jetstream Logs (${response.logs.length} entries)`); 68 + 69 + for (const log of response.logs) { 70 + const timestamp = new Date(log.createdAt).toLocaleString(); 71 + const level = log.level.toUpperCase().padEnd(5); 72 + const coloredLevel = colorizeLevel(level, log.level); 73 + 74 + console.log(`${timestamp} ${coloredLevel} ${log.message}`); 75 + 76 + if (log.metadata && Object.keys(log.metadata).length > 0) { 77 + console.log(` ${gray(JSON.stringify(log.metadata))}`); 78 + } 79 + } 80 + 81 + } catch (error) { 82 + const err = error as Error; 83 + logger.error(`Failed to fetch logs: ${err.message}`); 84 + Deno.exit(1); 85 + } 86 + } 87 + 88 + function colorizeLevel(levelText: string, level: string): string { 89 + switch (level.toLowerCase()) { 90 + case "error": 91 + return red(levelText); 92 + case "warn": 93 + return yellow(levelText); 94 + case "info": 95 + return cyan(levelText); 96 + case "debug": 97 + return gray(levelText); 98 + default: 99 + return levelText; 100 + } 101 + }
+6
packages/cli/src/mod.ts
··· 7 7 import { statusCommand } from "./commands/status.ts"; 8 8 import { codegenCommand } from "./commands/codegen.ts"; 9 9 import { initCommand } from "./commands/init.ts"; 10 + import { logsCommand } from "./commands/logs.ts"; 10 11 11 12 const VERSION = "0.1.0"; 12 13 ··· 23 24 lexicon Manage lexicons (push, pull, list) 24 25 codegen Generate TypeScript client from lexicon files 25 26 status Show authentication and configuration status 27 + logs View Jetstream logs for a slice 26 28 help Show this help message 27 29 28 30 OPTIONS: ··· 36 38 slices lexicon push --path ./lexicons --slice at://did:plc:example/slice 37 39 slices lexicon list --slice at://did:plc:example/slice 38 40 slices status 41 + slices logs --slice at://did:plc:example/slice 39 42 `); 40 43 } 41 44 ··· 88 91 break; 89 92 case "status": 90 93 await statusCommand(commandArgs, args); 94 + break; 95 + case "logs": 96 + await logsCommand(commandArgs, args); 91 97 break; 92 98 case "help": 93 99 showHelp();