@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 CHANGED
@@ -79,9 +79,10 @@ declare class NoSink implements Sink {
79
79
 
80
80
  interface SupabaseSinkOptions {
81
81
  supabase: SupabaseClient;
82
- run: {
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.runId = options.run.id;
224
- this.projectId = options.run.projectId;
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: entry.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.18.3",
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.18.3",
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
- run: { id: string; projectId: string };
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: string;
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.runId = options.run.id;
24
- this.projectId = options.run.projectId;
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: entry.meta ?? {},
44
+ meta,
39
45
  artifacts: artifactList,
40
46
  created_at: new Date().toISOString(),
41
47
  });