@letsrunit/journal 0.18.3 → 0.19.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.
- package/dist/index.d.ts +5 -3
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/sink/supabase-sink.ts +11 -5
package/dist/index.d.ts
CHANGED
|
@@ -79,9 +79,10 @@ declare class NoSink implements Sink {
|
|
|
79
79
|
|
|
80
80
|
interface SupabaseSinkOptions {
|
|
81
81
|
supabase: SupabaseClient;
|
|
82
|
-
|
|
83
|
-
id: string;
|
|
82
|
+
source: {
|
|
84
83
|
projectId: string;
|
|
84
|
+
runId?: string;
|
|
85
|
+
processId?: string;
|
|
85
86
|
};
|
|
86
87
|
tableName?: string;
|
|
87
88
|
bucket?: string;
|
|
@@ -93,7 +94,8 @@ interface SupabaseSinkOptions {
|
|
|
93
94
|
declare class SupabaseSink implements Sink {
|
|
94
95
|
private readonly supabase;
|
|
95
96
|
private readonly projectId;
|
|
96
|
-
private readonly runId
|
|
97
|
+
private readonly runId?;
|
|
98
|
+
private readonly processId?;
|
|
97
99
|
private readonly tableName;
|
|
98
100
|
private readonly bucket?;
|
|
99
101
|
private readonly console;
|
package/dist/index.js
CHANGED
|
@@ -214,14 +214,16 @@ var SupabaseSink = class {
|
|
|
214
214
|
supabase;
|
|
215
215
|
projectId;
|
|
216
216
|
runId;
|
|
217
|
+
processId;
|
|
217
218
|
tableName;
|
|
218
219
|
bucket;
|
|
219
220
|
console;
|
|
220
221
|
bucketEnsured = false;
|
|
221
222
|
constructor(options) {
|
|
222
223
|
this.supabase = options.supabase;
|
|
223
|
-
this.
|
|
224
|
-
this.
|
|
224
|
+
this.projectId = options.source.projectId;
|
|
225
|
+
this.runId = options.source.runId;
|
|
226
|
+
this.processId = options.source.processId;
|
|
225
227
|
this.tableName = options.tableName ?? "log_entries";
|
|
226
228
|
this.bucket = options.bucket;
|
|
227
229
|
this.console = options.console || console;
|
|
@@ -229,11 +231,15 @@ var SupabaseSink = class {
|
|
|
229
231
|
async publish(...entries) {
|
|
230
232
|
for (const entry of entries) {
|
|
231
233
|
const artifactList = await this.storeArtifacts(entry.artifacts);
|
|
234
|
+
const { testId, ...meta } = entry.meta ?? {};
|
|
232
235
|
const { error } = await this.supabase.from(this.tableName).insert({
|
|
236
|
+
project_id: this.projectId,
|
|
233
237
|
run_id: this.runId,
|
|
238
|
+
test_id: this.runId ? testId : void 0,
|
|
239
|
+
process_id: this.processId,
|
|
234
240
|
type: entry.type,
|
|
235
241
|
message: entry.message,
|
|
236
|
-
meta
|
|
242
|
+
meta,
|
|
237
243
|
artifacts: artifactList,
|
|
238
244
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
239
245
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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"]}
|
|
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 source: { projectId: string; runId?: string; processId?: 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 processId?: 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.projectId = options.source.projectId;\n this.runId = options.source.runId;\n this.processId = options.source.processId;\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 const { testId, ...meta } = entry.meta ?? {}\n\n const { error } = await this.supabase.from(this.tableName).insert({\n project_id: this.projectId,\n run_id: this.runId,\n test_id: this.runId ? testId : undefined,\n process_id: this.processId,\n type: entry.type,\n message: entry.message,\n 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.19.1",
|
|
4
4
|
"description": "Logging and journaling system for letsrunit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"testing",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"packageManager": "yarn@4.10.3",
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@letsrunit/utils": "0.
|
|
54
|
+
"@letsrunit/utils": "0.19.1",
|
|
55
55
|
"@supabase/supabase-js": "^2.91.0",
|
|
56
56
|
"ansi-escapes": "^7.2.0",
|
|
57
57
|
"yaml": "^2.8.2"
|
|
@@ -3,7 +3,7 @@ import type { JournalEntry, Sink } from '../types';
|
|
|
3
3
|
|
|
4
4
|
interface SupabaseSinkOptions {
|
|
5
5
|
supabase: SupabaseClient;
|
|
6
|
-
|
|
6
|
+
source: { projectId: string; runId?: string; processId?: string };
|
|
7
7
|
tableName?: string;
|
|
8
8
|
bucket?: string;
|
|
9
9
|
console?: { error: (...args: any[]) => void; warn: (...args: any[]) => void };
|
|
@@ -12,7 +12,8 @@ interface SupabaseSinkOptions {
|
|
|
12
12
|
export class SupabaseSink implements Sink {
|
|
13
13
|
private readonly supabase: SupabaseClient;
|
|
14
14
|
private readonly projectId: string;
|
|
15
|
-
private readonly runId
|
|
15
|
+
private readonly runId?: string;
|
|
16
|
+
private readonly processId?: string;
|
|
16
17
|
private readonly tableName: string;
|
|
17
18
|
private readonly bucket?: string;
|
|
18
19
|
private readonly console: { error: (...args: any[]) => void; warn: (...args: any[]) => void };
|
|
@@ -20,8 +21,9 @@ export class SupabaseSink implements Sink {
|
|
|
20
21
|
|
|
21
22
|
constructor(options: SupabaseSinkOptions) {
|
|
22
23
|
this.supabase = options.supabase;
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
24
|
+
this.projectId = options.source.projectId;
|
|
25
|
+
this.runId = options.source.runId;
|
|
26
|
+
this.processId = options.source.processId;
|
|
25
27
|
this.tableName = options.tableName ?? 'log_entries';
|
|
26
28
|
this.bucket = options.bucket;
|
|
27
29
|
this.console = options.console || console;
|
|
@@ -30,12 +32,16 @@ export class SupabaseSink implements Sink {
|
|
|
30
32
|
async publish(...entries: JournalEntry[]): Promise<void> {
|
|
31
33
|
for (const entry of entries) {
|
|
32
34
|
const artifactList = await this.storeArtifacts(entry.artifacts);
|
|
35
|
+
const { testId, ...meta } = entry.meta ?? {}
|
|
33
36
|
|
|
34
37
|
const { error } = await this.supabase.from(this.tableName).insert({
|
|
38
|
+
project_id: this.projectId,
|
|
35
39
|
run_id: this.runId,
|
|
40
|
+
test_id: this.runId ? testId : undefined,
|
|
41
|
+
process_id: this.processId,
|
|
36
42
|
type: entry.type,
|
|
37
43
|
message: entry.message,
|
|
38
|
-
meta
|
|
44
|
+
meta,
|
|
39
45
|
artifacts: artifactList,
|
|
40
46
|
created_at: new Date().toISOString(),
|
|
41
47
|
});
|