@letsrunit/journal 0.1.0 → 0.2.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/dist/index.d.ts +18 -1
- package/dist/index.js +40 -2
- package/dist/index.js.map +1 -1
- package/package.json +19 -9
- package/src/sink/index.ts +1 -0
- package/src/sink/memory-sink.ts +55 -0
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,23 @@ declare class CliSink implements Sink {
|
|
|
56
56
|
private storeArtifacts;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
interface MemoryEntry {
|
|
60
|
+
timestamp: number;
|
|
61
|
+
type: JournalEntry['type'];
|
|
62
|
+
message: string;
|
|
63
|
+
artifacts: string[];
|
|
64
|
+
}
|
|
65
|
+
declare class MemorySink implements Sink {
|
|
66
|
+
private readonly artifactDir;
|
|
67
|
+
private _entries;
|
|
68
|
+
constructor(artifactDir: string);
|
|
69
|
+
publish(...entries: JournalEntry[]): Promise<void>;
|
|
70
|
+
getEntries(): MemoryEntry[];
|
|
71
|
+
getArtifactPaths(): string[];
|
|
72
|
+
clear(): void;
|
|
73
|
+
private storeArtifacts;
|
|
74
|
+
}
|
|
75
|
+
|
|
59
76
|
declare class NoSink implements Sink {
|
|
60
77
|
publish(): Promise<void>;
|
|
61
78
|
}
|
|
@@ -112,4 +129,4 @@ declare class Journal<TSink extends Sink = Sink> {
|
|
|
112
129
|
failure(message: string, options?: Options): Promise<void>;
|
|
113
130
|
}
|
|
114
131
|
|
|
115
|
-
export { CliSink, Journal, type JournalEntry, NoSink, type Sink, SupabaseSink };
|
|
132
|
+
export { CliSink, Journal, type JournalEntry, type MemoryEntry, MemorySink, NoSink, type Sink, SupabaseSink };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { statusSymbol } from '@letsrunit/utils';
|
|
2
2
|
import { cursorUp, cursorLeft, eraseDown } from 'ansi-escapes';
|
|
3
|
-
import { writeFile } from 'fs/promises';
|
|
3
|
+
import { writeFile, mkdir } from 'fs/promises';
|
|
4
4
|
import YAML from 'yaml';
|
|
5
|
+
import { join } from 'path';
|
|
5
6
|
|
|
6
7
|
// src/journal-batch.ts
|
|
7
8
|
var JournalBatch = class {
|
|
@@ -164,6 +165,43 @@ ${yaml}`));
|
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
};
|
|
168
|
+
var MemorySink = class {
|
|
169
|
+
constructor(artifactDir) {
|
|
170
|
+
this.artifactDir = artifactDir;
|
|
171
|
+
}
|
|
172
|
+
_entries = [];
|
|
173
|
+
async publish(...entries) {
|
|
174
|
+
await mkdir(this.artifactDir, { recursive: true });
|
|
175
|
+
for (const entry of entries) {
|
|
176
|
+
const paths = await this.storeArtifacts(entry.artifacts);
|
|
177
|
+
this._entries.push({
|
|
178
|
+
timestamp: entry.timestamp,
|
|
179
|
+
type: entry.type,
|
|
180
|
+
message: entry.message,
|
|
181
|
+
artifacts: paths
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
getEntries() {
|
|
186
|
+
return this._entries;
|
|
187
|
+
}
|
|
188
|
+
getArtifactPaths() {
|
|
189
|
+
return this._entries.flatMap((e) => e.artifacts);
|
|
190
|
+
}
|
|
191
|
+
clear() {
|
|
192
|
+
this._entries = [];
|
|
193
|
+
}
|
|
194
|
+
async storeArtifacts(artifacts) {
|
|
195
|
+
const paths = [];
|
|
196
|
+
for (const artifact of artifacts) {
|
|
197
|
+
const dest = join(this.artifactDir, artifact.name);
|
|
198
|
+
const data = await artifact.bytes();
|
|
199
|
+
await writeFile(dest, data);
|
|
200
|
+
paths.push(dest);
|
|
201
|
+
}
|
|
202
|
+
return paths;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
167
205
|
|
|
168
206
|
// src/sink/no-sink.ts
|
|
169
207
|
var NoSink = class {
|
|
@@ -313,6 +351,6 @@ var Journal = class _Journal {
|
|
|
313
351
|
}
|
|
314
352
|
};
|
|
315
353
|
|
|
316
|
-
export { CliSink, Journal, NoSink, SupabaseSink };
|
|
354
|
+
export { CliSink, Journal, MemorySink, NoSink, SupabaseSink };
|
|
317
355
|
//# sourceMappingURL=index.js.map
|
|
318
356
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/journal-batch.ts","../src/sink/cli-sink.ts","../src/sink/no-sink.ts","../src/sink/supabase-sink.ts","../src/journal.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Sink, JournalEntry } from './types';\n\ntype Options = Partial<Pick<JournalEntry, 'artifacts' | 'meta'>>;\n\nexport class JournalBatch {\n private entries: JournalEntry[] = [];\n\n constructor(private sink: Sink) {}\n\n log(message: string | undefined, options: Options & { type: JournalEntry['type'] }): JournalBatch {\n if (message) {\n this.entries.push({\n timestamp: Date.now(),\n message,\n type: options.type,\n artifacts: options.artifacts ?? [],\n meta: options.meta ?? {},\n });\n }\n\n return this;\n }\n\n async flush() {\n await this.sink.publish(...this.entries);\n }\n\n debug(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'debug' });\n }\n\n info(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'info' });\n }\n\n title(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'title' });\n }\n\n warn(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'warn' });\n }\n\n error(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'error' });\n }\n\n prepare(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'prepare' });\n }\n\n success(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'success' });\n }\n\n failure(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'failure' });\n }\n\n each<T>(items: Array<T>, fn: (journal: JournalBatch, item: T) => void): JournalBatch {\n for (const item of items) {\n fn(this, item);\n }\n\n return this;\n }\n}\n","import { statusSymbol } from '@letsrunit/utils';\nimport { cursorLeft, cursorUp, eraseDown } from 'ansi-escapes';\nimport { writeFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport type { JournalEntry, Sink } from '../types';\n\ntype WriteFile = typeof writeFile;\n\ninterface CliSinkOptions {\n stream?: NodeJS.WriteStream;\n verbosity?: number;\n artifactPath?: string;\n writeFile?: WriteFile;\n}\n\nfunction colorize(type: JournalEntry['type'], text: string): string {\n // ANSI escape codes: debug=bright black (gray), warn=yellow, error=red, info=no color\n switch (type) {\n case 'debug':\n case 'prepare':\n return `\\x1b[90m${text}\\x1b[0m`;\n case 'warn':\n return `\\x1b[33m${text}\\x1b[0m`;\n case 'error':\n case 'failure':\n return `\\x1b[31m${text}\\x1b[0m`;\n case 'success':\n return `\\x1b[32m${text}\\x1b[0m`;\n case 'title':\n return `\\x1b[1m${text}\\x1b[0m`;\n case 'info':\n default:\n return text;\n }\n}\n\nexport class CliSink implements Sink {\n public readonly stream: NodeJS.WriteStream;\n public readonly verbosity: number;\n public readonly artifactPath: string | undefined;\n private readonly writeFile: WriteFile;\n\n private entries: JournalEntry[] = [];\n\n constructor(options: CliSinkOptions = {}) {\n this.stream = options.stream ?? process.stdout;\n this.verbosity = options.verbosity ?? 1;\n this.artifactPath = options.artifactPath;\n this.writeFile = options.writeFile ?? writeFile;\n }\n\n async publish(...entries: JournalEntry[]): Promise<void> {\n for (const entry of entries) {\n if (entry.type === 'debug' && this.verbosity < 2) continue;\n if (entry.type !== 'error' && this.verbosity < 1) continue;\n\n if (entry.type === 'title') this.endSection();\n\n this.replace(entry) || this.append(entry);\n\n await this.storeArtifacts(entry.artifacts);\n }\n }\n\n endSection() {\n this.entries = [];\n }\n\n private replace(entry: JournalEntry): boolean {\n if (entry.type !== 'start' && entry.type !== 'success' && entry.type !== 'failure') return false;\n\n const index = this.entries.findLastIndex(\n (e) => e.message === entry.message &&\n (e.type === 'prepare' || (e.type === 'start' && entry.type !== 'start'))\n );\n if (index < 0) return false;\n\n const oldTexts = this.entries.slice(index).map((e) => this.format(e));\n const columns = this.stream.columns ?? 0;\n const oldLength = oldTexts.reduce((total, current) => total + this.countDisplayLines(current, columns), 0);\n\n this.entries[index] = entry;\n const newTexts = this.entries.slice(index).map((e) => this.format(e));\n\n this.stream.write(cursorUp(oldLength));\n this.stream.write(cursorLeft);\n this.stream.write(newTexts.join('\\n') + '\\n');\n this.stream.write(eraseDown);\n\n return true;\n }\n\n private append(entry: JournalEntry): void {\n this.entries.push(entry);\n\n const text = this.format(entry);\n this.stream.write(text + '\\n');\n }\n\n private format(entry: JournalEntry): string {\n const lines = [];\n\n const message = entry.message.trim();\n\n if (['prepare', 'start', 'success', 'failure'].includes(entry.type)) {\n const prefix = colorize(entry.type, statusSymbol(entry.type));\n lines.push(`${prefix} ${message}`);\n } else {\n lines.push(colorize(entry.type, message));\n }\n\n if (this.verbosity >= 3) {\n if (entry.meta && Object.values(entry.meta).length && Object.keys(entry.meta).length) {\n const yaml = YAML.stringify(entry.meta).trimEnd();\n lines.push(colorize('debug', `[Meta]\\n${yaml}`));\n }\n }\n\n return lines.join('\\n');\n }\n\n private stripAnsi(input: string): string {\n // Regex from chalk/strip-ansi to remove ANSI escape sequences\n const pattern = /[\\u001B\\u009B][[\\]()#;?]*(?:((?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)|(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~])/g;\n return input.replace(pattern, '');\n }\n\n private countDisplayLines(text: string, columns: number): number {\n // If columns is not available (non-TTY), fall back to newline-based counting\n if (!columns || columns <= 0 || !Number.isFinite(columns)) {\n return text.split('\\n').length;\n }\n\n let count = 0;\n const lines = text.split('\\n');\n for (const line of lines) {\n const visible = this.stripAnsi(line);\n const len = [...visible].length; // handles surrogate pairs reasonably\n const wraps = Math.max(1, Math.ceil(len / columns));\n count += wraps;\n }\n return count;\n }\n\n private async storeArtifacts(artifacts: File[]) {\n if (!this.artifactPath || artifacts.length === 0) return;\n\n for (const artifact of artifacts) {\n const data = await artifact.bytes();\n await this.writeFile(`${this.artifactPath}/${artifact.name}`, data);\n }\n }\n}\n","import type { Sink } from '../types';\n\n/* v8 ignore start */\nexport class NoSink implements Sink {\n async publish(): Promise<void> {}\n}\n","import { SupabaseClient } from '@supabase/supabase-js';\nimport type { JournalEntry, Sink } from '../types';\n\ninterface SupabaseSinkOptions {\n supabase: SupabaseClient;\n run: { id: string; projectId: string };\n tableName?: string;\n bucket?: string;\n console?: { error: (...args: any[]) => void; warn: (...args: any[]) => void };\n}\n\nexport class SupabaseSink implements Sink {\n private readonly supabase: SupabaseClient;\n private readonly projectId: string;\n private readonly runId: string;\n private readonly tableName: string;\n private readonly bucket?: string;\n private readonly console: { error: (...args: any[]) => void; warn: (...args: any[]) => void };\n private bucketEnsured = false;\n\n constructor(options: SupabaseSinkOptions) {\n this.supabase = options.supabase;\n this.runId = options.run.id;\n this.projectId = options.run.projectId;\n this.tableName = options.tableName ?? 'log_entries';\n this.bucket = options.bucket;\n this.console = options.console || console;\n }\n\n async publish(...entries: JournalEntry[]): Promise<void> {\n for (const entry of entries) {\n const artifactList = await this.storeArtifacts(entry.artifacts);\n\n const { error } = await this.supabase.from(this.tableName).insert({\n run_id: this.runId,\n type: entry.type,\n message: entry.message,\n meta: entry.meta ?? {},\n artifacts: artifactList,\n created_at: new Date().toISOString(),\n });\n\n if (error) {\n this.console.error('SupabaseSink insert failed:', error);\n }\n }\n }\n\n private async ensureBucket() {\n if (!this.bucket || this.bucketEnsured) return;\n\n try {\n await this.supabase.storage?.createBucket?.(this.bucket, { public: true });\n this.bucketEnsured = true;\n } catch (error) {\n this.console.warn(error);\n }\n }\n\n private async storeArtifacts(artifacts: File[]): Promise<any[]> {\n if (!this.bucket || artifacts.length === 0) return [];\n\n await this.ensureBucket();\n\n const stored: any[] = [];\n\n const uniqueArtifacts = artifacts.filter(\n (artifact, index, self) => index === self.findIndex((a) => a.name === artifact.name),\n );\n\n for (const artifact of uniqueArtifacts) {\n try {\n const path = `${this.projectId}/${artifact.name}`;\n const { data } = this.supabase.storage.from(this.bucket).getPublicUrl(path);\n const publicUrl = data.publicUrl;\n\n const exists = await this.artifactExists(publicUrl);\n\n if (!exists) {\n const { error } = await this.supabase.storage\n .from(this.bucket)\n .upload(path, await artifact.bytes(), { contentType: artifact.type, upsert: true });\n if (error) throw error;\n }\n\n stored.push({\n name: artifact.name,\n url: publicUrl,\n size: artifact.size,\n });\n } catch (error) {\n this.console.warn('SupabaseSink upload failed:', error);\n }\n }\n\n return stored;\n }\n\n private async artifactExists(url: string): Promise<boolean> {\n try {\n const response = await fetch(url, { method: 'HEAD' });\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n","import { JournalBatch } from './journal-batch';\nimport { NoSink } from './sink';\nimport type { JournalEntry, Sink } from './types';\n\ntype Options = Partial<Pick<JournalEntry, 'artifacts' | 'meta'>>;\n\nexport class Journal<TSink extends Sink = Sink> {\n constructor(readonly sink: TSink) {}\n\n static nil() {\n return new Journal(new NoSink());\n }\n\n async log(message: string, options: Options & { type: JournalEntry['type'] }): Promise<void> {\n const entry: JournalEntry = {\n timestamp: Date.now(),\n message,\n type: options.type,\n artifacts: options.artifacts ?? [],\n meta: options.meta ?? {},\n };\n\n await this.sink.publish(entry);\n }\n\n batch() {\n return new JournalBatch(this.sink);\n }\n\n async do<T>(\n message: string,\n callback: () => T | Promise<T>,\n metaFn?: (result: T) => { meta?: Record<string, any>; artifacts?: File[] },\n ): Promise<T> {\n try {\n await this.start(message);\n\n const result = await callback();\n\n const { meta, artifacts } = metaFn?.(result) ?? {};\n await this.success(message, { meta, artifacts });\n\n return result;\n } catch (e) {\n await this.failure(message);\n throw e;\n }\n }\n\n async debug(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'debug' });\n }\n\n async info(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'info' });\n }\n\n async warn(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'warn' });\n }\n\n async error(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'error' });\n }\n\n async title(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'title' });\n }\n\n async prepare(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'prepare' });\n }\n\n async start(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'start' });\n }\n\n async success(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'success' });\n }\n\n async failure(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'failure' });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/journal-batch.ts","../src/sink/cli-sink.ts","../src/sink/memory-sink.ts","../src/sink/no-sink.ts","../src/sink/supabase-sink.ts","../src/journal.ts"],"names":["writeFile"],"mappings":"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","file":"index.js","sourcesContent":["import type { Sink, JournalEntry } from './types';\n\ntype Options = Partial<Pick<JournalEntry, 'artifacts' | 'meta'>>;\n\nexport class JournalBatch {\n private entries: JournalEntry[] = [];\n\n constructor(private sink: Sink) {}\n\n log(message: string | undefined, options: Options & { type: JournalEntry['type'] }): JournalBatch {\n if (message) {\n this.entries.push({\n timestamp: Date.now(),\n message,\n type: options.type,\n artifacts: options.artifacts ?? [],\n meta: options.meta ?? {},\n });\n }\n\n return this;\n }\n\n async flush() {\n await this.sink.publish(...this.entries);\n }\n\n debug(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'debug' });\n }\n\n info(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'info' });\n }\n\n title(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'title' });\n }\n\n warn(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'warn' });\n }\n\n error(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'error' });\n }\n\n prepare(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'prepare' });\n }\n\n success(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'success' });\n }\n\n failure(message: string | undefined, options: Options = {}): JournalBatch {\n return this.log(message, { ...options, type: 'failure' });\n }\n\n each<T>(items: Array<T>, fn: (journal: JournalBatch, item: T) => void): JournalBatch {\n for (const item of items) {\n fn(this, item);\n }\n\n return this;\n }\n}\n","import { statusSymbol } from '@letsrunit/utils';\nimport { cursorLeft, cursorUp, eraseDown } from 'ansi-escapes';\nimport { writeFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport type { JournalEntry, Sink } from '../types';\n\ntype WriteFile = typeof writeFile;\n\ninterface CliSinkOptions {\n stream?: NodeJS.WriteStream;\n verbosity?: number;\n artifactPath?: string;\n writeFile?: WriteFile;\n}\n\nfunction colorize(type: JournalEntry['type'], text: string): string {\n // ANSI escape codes: debug=bright black (gray), warn=yellow, error=red, info=no color\n switch (type) {\n case 'debug':\n case 'prepare':\n return `\\x1b[90m${text}\\x1b[0m`;\n case 'warn':\n return `\\x1b[33m${text}\\x1b[0m`;\n case 'error':\n case 'failure':\n return `\\x1b[31m${text}\\x1b[0m`;\n case 'success':\n return `\\x1b[32m${text}\\x1b[0m`;\n case 'title':\n return `\\x1b[1m${text}\\x1b[0m`;\n case 'info':\n default:\n return text;\n }\n}\n\nexport class CliSink implements Sink {\n public readonly stream: NodeJS.WriteStream;\n public readonly verbosity: number;\n public readonly artifactPath: string | undefined;\n private readonly writeFile: WriteFile;\n\n private entries: JournalEntry[] = [];\n\n constructor(options: CliSinkOptions = {}) {\n this.stream = options.stream ?? process.stdout;\n this.verbosity = options.verbosity ?? 1;\n this.artifactPath = options.artifactPath;\n this.writeFile = options.writeFile ?? writeFile;\n }\n\n async publish(...entries: JournalEntry[]): Promise<void> {\n for (const entry of entries) {\n if (entry.type === 'debug' && this.verbosity < 2) continue;\n if (entry.type !== 'error' && this.verbosity < 1) continue;\n\n if (entry.type === 'title') this.endSection();\n\n this.replace(entry) || this.append(entry);\n\n await this.storeArtifacts(entry.artifacts);\n }\n }\n\n endSection() {\n this.entries = [];\n }\n\n private replace(entry: JournalEntry): boolean {\n if (entry.type !== 'start' && entry.type !== 'success' && entry.type !== 'failure') return false;\n\n const index = this.entries.findLastIndex(\n (e) => e.message === entry.message &&\n (e.type === 'prepare' || (e.type === 'start' && entry.type !== 'start'))\n );\n if (index < 0) return false;\n\n const oldTexts = this.entries.slice(index).map((e) => this.format(e));\n const columns = this.stream.columns ?? 0;\n const oldLength = oldTexts.reduce((total, current) => total + this.countDisplayLines(current, columns), 0);\n\n this.entries[index] = entry;\n const newTexts = this.entries.slice(index).map((e) => this.format(e));\n\n this.stream.write(cursorUp(oldLength));\n this.stream.write(cursorLeft);\n this.stream.write(newTexts.join('\\n') + '\\n');\n this.stream.write(eraseDown);\n\n return true;\n }\n\n private append(entry: JournalEntry): void {\n this.entries.push(entry);\n\n const text = this.format(entry);\n this.stream.write(text + '\\n');\n }\n\n private format(entry: JournalEntry): string {\n const lines = [];\n\n const message = entry.message.trim();\n\n if (['prepare', 'start', 'success', 'failure'].includes(entry.type)) {\n const prefix = colorize(entry.type, statusSymbol(entry.type));\n lines.push(`${prefix} ${message}`);\n } else {\n lines.push(colorize(entry.type, message));\n }\n\n if (this.verbosity >= 3) {\n if (entry.meta && Object.values(entry.meta).length && Object.keys(entry.meta).length) {\n const yaml = YAML.stringify(entry.meta).trimEnd();\n lines.push(colorize('debug', `[Meta]\\n${yaml}`));\n }\n }\n\n return lines.join('\\n');\n }\n\n private stripAnsi(input: string): string {\n // Regex from chalk/strip-ansi to remove ANSI escape sequences\n const pattern = /[\\u001B\\u009B][[\\]()#;?]*(?:((?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)|(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~])/g;\n return input.replace(pattern, '');\n }\n\n private countDisplayLines(text: string, columns: number): number {\n // If columns is not available (non-TTY), fall back to newline-based counting\n if (!columns || columns <= 0 || !Number.isFinite(columns)) {\n return text.split('\\n').length;\n }\n\n let count = 0;\n const lines = text.split('\\n');\n for (const line of lines) {\n const visible = this.stripAnsi(line);\n const len = [...visible].length; // handles surrogate pairs reasonably\n const wraps = Math.max(1, Math.ceil(len / columns));\n count += wraps;\n }\n return count;\n }\n\n private async storeArtifacts(artifacts: File[]) {\n if (!this.artifactPath || artifacts.length === 0) return;\n\n for (const artifact of artifacts) {\n const data = await artifact.bytes();\n await this.writeFile(`${this.artifactPath}/${artifact.name}`, data);\n }\n }\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { JournalEntry, Sink } from '../types.js';\n\nexport interface MemoryEntry {\n timestamp: number;\n type: JournalEntry['type'];\n message: string;\n artifacts: string[]; // file paths on disk\n}\n\nexport class MemorySink implements Sink {\n private _entries: MemoryEntry[] = [];\n\n constructor(private readonly artifactDir: string) {}\n\n async publish(...entries: JournalEntry[]): Promise<void> {\n await mkdir(this.artifactDir, { recursive: true });\n\n for (const entry of entries) {\n const paths = await this.storeArtifacts(entry.artifacts);\n this._entries.push({\n timestamp: entry.timestamp,\n type: entry.type,\n message: entry.message,\n artifacts: paths,\n });\n }\n }\n\n getEntries(): MemoryEntry[] {\n return this._entries;\n }\n\n getArtifactPaths(): string[] {\n return this._entries.flatMap((e) => e.artifacts);\n }\n\n clear(): void {\n this._entries = [];\n }\n\n private async storeArtifacts(artifacts: File[]): Promise<string[]> {\n const paths: string[] = [];\n\n for (const artifact of artifacts) {\n const dest = join(this.artifactDir, artifact.name);\n const data = await artifact.bytes();\n await writeFile(dest, data);\n paths.push(dest);\n }\n\n return paths;\n }\n}\n","import type { Sink } from '../types';\n\n/* v8 ignore start */\nexport class NoSink implements Sink {\n async publish(): Promise<void> {}\n}\n","import { SupabaseClient } from '@supabase/supabase-js';\nimport type { JournalEntry, Sink } from '../types';\n\ninterface SupabaseSinkOptions {\n supabase: SupabaseClient;\n run: { id: string; projectId: string };\n tableName?: string;\n bucket?: string;\n console?: { error: (...args: any[]) => void; warn: (...args: any[]) => void };\n}\n\nexport class SupabaseSink implements Sink {\n private readonly supabase: SupabaseClient;\n private readonly projectId: string;\n private readonly runId: string;\n private readonly tableName: string;\n private readonly bucket?: string;\n private readonly console: { error: (...args: any[]) => void; warn: (...args: any[]) => void };\n private bucketEnsured = false;\n\n constructor(options: SupabaseSinkOptions) {\n this.supabase = options.supabase;\n this.runId = options.run.id;\n this.projectId = options.run.projectId;\n this.tableName = options.tableName ?? 'log_entries';\n this.bucket = options.bucket;\n this.console = options.console || console;\n }\n\n async publish(...entries: JournalEntry[]): Promise<void> {\n for (const entry of entries) {\n const artifactList = await this.storeArtifacts(entry.artifacts);\n\n const { error } = await this.supabase.from(this.tableName).insert({\n run_id: this.runId,\n type: entry.type,\n message: entry.message,\n meta: entry.meta ?? {},\n artifacts: artifactList,\n created_at: new Date().toISOString(),\n });\n\n if (error) {\n this.console.error('SupabaseSink insert failed:', error);\n }\n }\n }\n\n private async ensureBucket() {\n if (!this.bucket || this.bucketEnsured) return;\n\n try {\n await this.supabase.storage?.createBucket?.(this.bucket, { public: true });\n this.bucketEnsured = true;\n } catch (error) {\n this.console.warn(error);\n }\n }\n\n private async storeArtifacts(artifacts: File[]): Promise<any[]> {\n if (!this.bucket || artifacts.length === 0) return [];\n\n await this.ensureBucket();\n\n const stored: any[] = [];\n\n const uniqueArtifacts = artifacts.filter(\n (artifact, index, self) => index === self.findIndex((a) => a.name === artifact.name),\n );\n\n for (const artifact of uniqueArtifacts) {\n try {\n const path = `${this.projectId}/${artifact.name}`;\n const { data } = this.supabase.storage.from(this.bucket).getPublicUrl(path);\n const publicUrl = data.publicUrl;\n\n const exists = await this.artifactExists(publicUrl);\n\n if (!exists) {\n const { error } = await this.supabase.storage\n .from(this.bucket)\n .upload(path, await artifact.bytes(), { contentType: artifact.type, upsert: true });\n if (error) throw error;\n }\n\n stored.push({\n name: artifact.name,\n url: publicUrl,\n size: artifact.size,\n });\n } catch (error) {\n this.console.warn('SupabaseSink upload failed:', error);\n }\n }\n\n return stored;\n }\n\n private async artifactExists(url: string): Promise<boolean> {\n try {\n const response = await fetch(url, { method: 'HEAD' });\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n","import { JournalBatch } from './journal-batch';\nimport { NoSink } from './sink';\nimport type { JournalEntry, Sink } from './types';\n\ntype Options = Partial<Pick<JournalEntry, 'artifacts' | 'meta'>>;\n\nexport class Journal<TSink extends Sink = Sink> {\n constructor(readonly sink: TSink) {}\n\n static nil() {\n return new Journal(new NoSink());\n }\n\n async log(message: string, options: Options & { type: JournalEntry['type'] }): Promise<void> {\n const entry: JournalEntry = {\n timestamp: Date.now(),\n message,\n type: options.type,\n artifacts: options.artifacts ?? [],\n meta: options.meta ?? {},\n };\n\n await this.sink.publish(entry);\n }\n\n batch() {\n return new JournalBatch(this.sink);\n }\n\n async do<T>(\n message: string,\n callback: () => T | Promise<T>,\n metaFn?: (result: T) => { meta?: Record<string, any>; artifacts?: File[] },\n ): Promise<T> {\n try {\n await this.start(message);\n\n const result = await callback();\n\n const { meta, artifacts } = metaFn?.(result) ?? {};\n await this.success(message, { meta, artifacts });\n\n return result;\n } catch (e) {\n await this.failure(message);\n throw e;\n }\n }\n\n async debug(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'debug' });\n }\n\n async info(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'info' });\n }\n\n async warn(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'warn' });\n }\n\n async error(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'error' });\n }\n\n async title(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'title' });\n }\n\n async prepare(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'prepare' });\n }\n\n async start(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'start' });\n }\n\n async success(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'success' });\n }\n\n async failure(message: string, options: Options = {}): Promise<void> {\n await this.log(message, { ...options, type: 'failure' });\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letsrunit/journal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Logging and journaling system for letsrunit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"testing",
|
|
@@ -11,16 +11,25 @@
|
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/letsrunit/letsrunit.git",
|
|
14
|
+
"url": "https://github.com/letsrunit-hq/letsrunit.git",
|
|
15
15
|
"directory": "packages/journal"
|
|
16
16
|
},
|
|
17
|
-
"bugs": "https://github.com/letsrunit/letsrunit/issues",
|
|
18
|
-
"homepage": "https://github.com/letsrunit/letsrunit#readme",
|
|
19
|
-
"private": false,
|
|
17
|
+
"bugs": "https://github.com/letsrunit-hq/letsrunit/issues",
|
|
18
|
+
"homepage": "https://github.com/letsrunit-hq/letsrunit#readme",
|
|
20
19
|
"type": "module",
|
|
21
20
|
"main": "./dist/index.js",
|
|
22
21
|
"publishConfig": {
|
|
23
|
-
"access": "public"
|
|
22
|
+
"access": "public",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"module": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
24
33
|
},
|
|
25
34
|
"files": [
|
|
26
35
|
"dist",
|
|
@@ -35,7 +44,7 @@
|
|
|
35
44
|
},
|
|
36
45
|
"packageManager": "yarn@4.10.3",
|
|
37
46
|
"dependencies": {
|
|
38
|
-
"@letsrunit/utils": "
|
|
47
|
+
"@letsrunit/utils": "0.2.4",
|
|
39
48
|
"@supabase/supabase-js": "^2.91.0",
|
|
40
49
|
"ansi-escapes": "^7.2.0",
|
|
41
50
|
"yaml": "^2.8.2"
|
|
@@ -51,7 +60,8 @@
|
|
|
51
60
|
"exports": {
|
|
52
61
|
".": {
|
|
53
62
|
"types": "./dist/index.d.ts",
|
|
54
|
-
"import": "./dist/index.js"
|
|
63
|
+
"import": "./dist/index.js",
|
|
64
|
+
"default": "./dist/index.js"
|
|
55
65
|
}
|
|
56
66
|
}
|
|
57
|
-
}
|
|
67
|
+
}
|
package/src/sink/index.ts
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import type { JournalEntry, Sink } from '../types.js';
|
|
4
|
+
|
|
5
|
+
export interface MemoryEntry {
|
|
6
|
+
timestamp: number;
|
|
7
|
+
type: JournalEntry['type'];
|
|
8
|
+
message: string;
|
|
9
|
+
artifacts: string[]; // file paths on disk
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class MemorySink implements Sink {
|
|
13
|
+
private _entries: MemoryEntry[] = [];
|
|
14
|
+
|
|
15
|
+
constructor(private readonly artifactDir: string) {}
|
|
16
|
+
|
|
17
|
+
async publish(...entries: JournalEntry[]): Promise<void> {
|
|
18
|
+
await mkdir(this.artifactDir, { recursive: true });
|
|
19
|
+
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const paths = await this.storeArtifacts(entry.artifacts);
|
|
22
|
+
this._entries.push({
|
|
23
|
+
timestamp: entry.timestamp,
|
|
24
|
+
type: entry.type,
|
|
25
|
+
message: entry.message,
|
|
26
|
+
artifacts: paths,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getEntries(): MemoryEntry[] {
|
|
32
|
+
return this._entries;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getArtifactPaths(): string[] {
|
|
36
|
+
return this._entries.flatMap((e) => e.artifacts);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
clear(): void {
|
|
40
|
+
this._entries = [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private async storeArtifacts(artifacts: File[]): Promise<string[]> {
|
|
44
|
+
const paths: string[] = [];
|
|
45
|
+
|
|
46
|
+
for (const artifact of artifacts) {
|
|
47
|
+
const dest = join(this.artifactDir, artifact.name);
|
|
48
|
+
const data = await artifact.bytes();
|
|
49
|
+
await writeFile(dest, data);
|
|
50
|
+
paths.push(dest);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return paths;
|
|
54
|
+
}
|
|
55
|
+
}
|