target-supabase-sdk 0.2.12 → 0.2.13

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.
Files changed (144) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/browser.d.ts.map +1 -1
  3. package/dist/browser.js +1 -1
  4. package/dist/chunks/enable-DqnfLPsQ.js +874 -0
  5. package/dist/chunks/enable-DqnfLPsQ.js.map +1 -0
  6. package/dist/chunks/list.api-BzbTJBsM.js.map +1 -1
  7. package/dist/chunks/{task-queue-H4mpSW8R.js → task-queue-6X3aglJh.js} +108 -3
  8. package/dist/chunks/task-queue-6X3aglJh.js.map +1 -0
  9. package/dist/node/preload/run-service-preload.d.ts.map +1 -1
  10. package/dist/node/preload/service-preload.interface.d.ts +3 -1
  11. package/dist/node/preload/service-preload.interface.d.ts.map +1 -1
  12. package/dist/node/process/managed-child-processes.d.ts.map +1 -1
  13. package/dist/node/service-guard/service-guard-node.d.ts.map +1 -1
  14. package/dist/node/service-host/index.d.ts +1 -0
  15. package/dist/node/service-host/index.d.ts.map +1 -1
  16. package/dist/node/service-host/service-host.d.ts +5 -1
  17. package/dist/node/service-host/service-host.d.ts.map +1 -1
  18. package/dist/node.d.ts +10 -5
  19. package/dist/node.d.ts.map +1 -1
  20. package/dist/node.js +492 -47
  21. package/dist/node.js.map +1 -1
  22. package/dist/preload.js +9 -6
  23. package/dist/preload.js.map +1 -1
  24. package/dist/service/index.d.ts +2 -2
  25. package/dist/service/index.d.ts.map +1 -1
  26. package/dist/service/registry.service.d.ts +19 -0
  27. package/dist/service/registry.service.d.ts.map +1 -1
  28. package/dist/shared/log/core/create-logger.d.ts.map +1 -0
  29. package/dist/shared/log/{log-batch.d.ts → core/log-batch.d.ts} +4 -4
  30. package/dist/shared/log/core/log-batch.d.ts.map +1 -0
  31. package/dist/shared/log/core/log-manager.d.ts.map +1 -0
  32. package/dist/shared/log/core/log-min-level.d.ts.map +1 -0
  33. package/dist/shared/log/core/log-scope.d.ts.map +1 -0
  34. package/dist/shared/log/index.d.ts +13 -13
  35. package/dist/shared/log/index.d.ts.map +1 -1
  36. package/dist/shared/log/spool/collector.d.ts +21 -0
  37. package/dist/shared/log/spool/collector.d.ts.map +1 -0
  38. package/dist/shared/log/spool/config.d.ts +7 -0
  39. package/dist/shared/log/spool/config.d.ts.map +1 -0
  40. package/dist/shared/log/spool/coordinator.d.ts +18 -0
  41. package/dist/shared/log/spool/coordinator.d.ts.map +1 -0
  42. package/dist/shared/log/spool/enable.d.ts +23 -0
  43. package/dist/shared/log/spool/enable.d.ts.map +1 -0
  44. package/dist/shared/log/spool/file.d.ts +21 -0
  45. package/dist/shared/log/spool/file.d.ts.map +1 -0
  46. package/dist/shared/log/spool/interface.d.ts +55 -0
  47. package/dist/shared/log/spool/interface.d.ts.map +1 -0
  48. package/dist/shared/log/spool/paths.d.ts +6 -0
  49. package/dist/shared/log/spool/paths.d.ts.map +1 -0
  50. package/dist/shared/log/spool/process-roles.d.ts +17 -0
  51. package/dist/shared/log/spool/process-roles.d.ts.map +1 -0
  52. package/dist/shared/log/spool/register-collect-log-runner.d.ts +15 -0
  53. package/dist/shared/log/spool/register-collect-log-runner.d.ts.map +1 -0
  54. package/dist/shared/log/spool/service-lifecycle.d.ts +13 -0
  55. package/dist/shared/log/spool/service-lifecycle.d.ts.map +1 -0
  56. package/dist/shared/log/spool/writer.d.ts +32 -0
  57. package/dist/shared/log/spool/writer.d.ts.map +1 -0
  58. package/dist/shared/log/{log-persist-batch-id.d.ts → upload/batch-id.d.ts} +3 -3
  59. package/dist/shared/log/upload/batch-id.d.ts.map +1 -0
  60. package/dist/shared/log/upload/env.d.ts +7 -0
  61. package/dist/shared/log/upload/env.d.ts.map +1 -0
  62. package/dist/shared/log/{log-persist-flush.d.ts → upload/flush.d.ts} +3 -3
  63. package/dist/shared/log/upload/flush.d.ts.map +1 -0
  64. package/dist/shared/log/{log-persist-hook.d.ts → upload/hook.d.ts} +2 -2
  65. package/dist/shared/log/upload/hook.d.ts.map +1 -0
  66. package/dist/shared/log/upload/interface.d.ts +33 -0
  67. package/dist/shared/log/upload/interface.d.ts.map +1 -0
  68. package/dist/shared/log/upload/logger.d.ts +22 -0
  69. package/dist/shared/log/upload/logger.d.ts.map +1 -0
  70. package/package.json +1 -1
  71. package/src/browser.ts +1 -0
  72. package/src/node/preload/run-service-preload.ts +11 -6
  73. package/src/node/preload/service-preload.interface.ts +3 -1
  74. package/src/node/process/create-managed-child-processes.ts +1 -1
  75. package/src/node/process/managed-child-processes.ts +8 -1
  76. package/src/node/service-guard/service-guard-node.ts +5 -0
  77. package/src/node/service-host/index.ts +4 -0
  78. package/src/node/service-host/service-host.ts +22 -3
  79. package/src/node.ts +26 -19
  80. package/src/service/index.ts +3 -0
  81. package/src/service/registry.service.ts +142 -0
  82. package/src/shared/log/README.md +206 -0
  83. package/src/shared/log/{log-batch.ts → core/log-batch.ts} +4 -4
  84. package/src/shared/log/{log-manager.ts → core/log-manager.ts} +3 -3
  85. package/src/shared/log/{log-min-level.ts → core/log-min-level.ts} +1 -1
  86. package/src/shared/log/{log-scope.ts → core/log-scope.ts} +1 -1
  87. package/src/shared/log/index.ts +13 -18
  88. package/src/shared/log/spool/collector.ts +330 -0
  89. package/src/shared/log/spool/config.ts +56 -0
  90. package/src/shared/log/spool/coordinator.ts +55 -0
  91. package/src/shared/log/spool/enable.ts +136 -0
  92. package/src/shared/log/spool/file.ts +75 -0
  93. package/src/shared/log/spool/interface.ts +62 -0
  94. package/src/shared/log/spool/paths.ts +30 -0
  95. package/src/shared/log/spool/process-roles.ts +75 -0
  96. package/src/shared/log/spool/register-collect-log-runner.ts +63 -0
  97. package/src/shared/log/spool/service-lifecycle.ts +35 -0
  98. package/src/shared/log/spool/writer.ts +273 -0
  99. package/src/shared/log/{log-persist-batch-id.ts → upload/batch-id.ts} +2 -2
  100. package/src/shared/log/upload/env.ts +26 -0
  101. package/src/shared/log/{log-persist-flush.ts → upload/flush.ts} +8 -7
  102. package/src/shared/log/{log-persist-hook.ts → upload/hook.ts} +1 -1
  103. package/src/shared/log/upload/interface.ts +38 -0
  104. package/src/shared/log/upload/logger.ts +37 -0
  105. package/dist/chunks/enable-log-persist-Dl55_mv2.js +0 -1674
  106. package/dist/chunks/enable-log-persist-Dl55_mv2.js.map +0 -1
  107. package/dist/chunks/task-queue-H4mpSW8R.js.map +0 -1
  108. package/dist/shared/log/create-logger.d.ts.map +0 -1
  109. package/dist/shared/log/enable-log-persist.d.ts +0 -28
  110. package/dist/shared/log/enable-log-persist.d.ts.map +0 -1
  111. package/dist/shared/log/log-batch.d.ts.map +0 -1
  112. package/dist/shared/log/log-manager.d.ts.map +0 -1
  113. package/dist/shared/log/log-min-level.d.ts.map +0 -1
  114. package/dist/shared/log/log-persist-batch-id.d.ts.map +0 -1
  115. package/dist/shared/log/log-persist-coordinator.d.ts +0 -37
  116. package/dist/shared/log/log-persist-coordinator.d.ts.map +0 -1
  117. package/dist/shared/log/log-persist-errors.d.ts +0 -4
  118. package/dist/shared/log/log-persist-errors.d.ts.map +0 -1
  119. package/dist/shared/log/log-persist-flush.d.ts.map +0 -1
  120. package/dist/shared/log/log-persist-hook.d.ts.map +0 -1
  121. package/dist/shared/log/log-persist-logger.d.ts +0 -16
  122. package/dist/shared/log/log-persist-logger.d.ts.map +0 -1
  123. package/dist/shared/log/log-persist-registry.d.ts +0 -18
  124. package/dist/shared/log/log-persist-registry.d.ts.map +0 -1
  125. package/dist/shared/log/log-persist.config.d.ts +0 -9
  126. package/dist/shared/log/log-persist.config.d.ts.map +0 -1
  127. package/dist/shared/log/log-persist.d.ts +0 -62
  128. package/dist/shared/log/log-persist.d.ts.map +0 -1
  129. package/dist/shared/log/log-persist.interface.d.ts +0 -132
  130. package/dist/shared/log/log-persist.interface.d.ts.map +0 -1
  131. package/dist/shared/log/log-scope.d.ts.map +0 -1
  132. package/src/shared/log/enable-log-persist.ts +0 -225
  133. package/src/shared/log/log-persist-coordinator.ts +0 -107
  134. package/src/shared/log/log-persist-errors.ts +0 -16
  135. package/src/shared/log/log-persist-logger.ts +0 -61
  136. package/src/shared/log/log-persist-registry.ts +0 -252
  137. package/src/shared/log/log-persist.config.ts +0 -115
  138. package/src/shared/log/log-persist.interface.ts +0 -150
  139. package/src/shared/log/log-persist.ts +0 -822
  140. /package/dist/shared/log/{create-logger.d.ts → core/create-logger.d.ts} +0 -0
  141. /package/dist/shared/log/{log-manager.d.ts → core/log-manager.d.ts} +0 -0
  142. /package/dist/shared/log/{log-min-level.d.ts → core/log-min-level.d.ts} +0 -0
  143. /package/dist/shared/log/{log-scope.d.ts → core/log-scope.d.ts} +0 -0
  144. /package/src/shared/log/{create-logger.ts → core/create-logger.ts} +0 -0
@@ -0,0 +1,273 @@
1
+ import { mkdir, rename, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import type { LogEntry } from "../core/log-manager";
4
+ import { estimateEntriesBytes, takeEntriesWithinBytes } from "../upload/flush";
5
+ import { registerLogPersistOffer } from "../upload/hook";
6
+ import { isLogPersistInternalTopic, spoolLogger } from "../upload/logger";
7
+ import { DEFAULT_LOG_SPOOL_CONFIG, resolveLogSpoolConfig } from "./config";
8
+ import { buildLogSpoolBatchBaseName, computeLogSpoolShortHash } from "./file";
9
+ import type { EnableLogSpoolOptions, LogSpoolBatchFile, LogSpoolProcessRole, LogSpoolWriterStats } from "./interface";
10
+ import { logSpoolProcessDir, resolveLogSpoolRoot } from "./paths";
11
+
12
+ class LogSpoolWriter {
13
+ private static instance: LogSpoolWriter | null = null;
14
+
15
+ private enabled = false;
16
+ private buffer: LogEntry[] = [];
17
+ private flushInProgress = false;
18
+ private debounceTimer: ReturnType<typeof setTimeout> | null = null;
19
+ private ageTimer: ReturnType<typeof setTimeout> | null = null;
20
+ private serviceId: string | null = null;
21
+ private processRole: LogSpoolProcessRole | null = null;
22
+ private serviceValue: string | null = null;
23
+ private spoolRoot: string | null = null;
24
+ private config = DEFAULT_LOG_SPOOL_CONFIG.writer;
25
+
26
+ static getInstance(): LogSpoolWriter {
27
+ LogSpoolWriter.instance ??= new LogSpoolWriter();
28
+ return LogSpoolWriter.instance;
29
+ }
30
+
31
+ async enable(options: EnableLogSpoolOptions): Promise<void> {
32
+ if (this.enabled) {
33
+ spoolLogger.warn("log spool writer already enabled", {
34
+ serviceId: this.serviceId,
35
+ processRole: this.processRole,
36
+ });
37
+ return;
38
+ }
39
+
40
+ this.serviceId = options.serviceId;
41
+ this.processRole = options.processRole;
42
+ this.serviceValue = options.serviceValue;
43
+ this.spoolRoot = options.spoolRoot ?? resolveLogSpoolRoot();
44
+ this.config = resolveLogSpoolConfig(options.config).writer;
45
+ this.enabled = true;
46
+
47
+ registerLogPersistOffer((entry) => this.offer(entry));
48
+
49
+ spoolLogger.info("log spool writer enabled", {
50
+ serviceId: options.serviceId,
51
+ processRole: options.processRole,
52
+ serviceValue: options.serviceValue,
53
+ spoolRoot: this.spoolRoot,
54
+ config: this.config,
55
+ });
56
+ }
57
+
58
+ async shutdown(): Promise<void> {
59
+ this.cancelDebounce();
60
+ this.cancelAgeFlush();
61
+ registerLogPersistOffer(null);
62
+ this.enabled = false;
63
+
64
+ while (this.buffer.length > 0) {
65
+ await this.flushChunk({ reason: "shutdown" });
66
+ }
67
+
68
+ spoolLogger.info("log spool writer shutdown complete", {
69
+ serviceId: this.serviceId,
70
+ processRole: this.processRole,
71
+ });
72
+ }
73
+
74
+ getStats(): LogSpoolWriterStats {
75
+ return {
76
+ enabled: this.enabled,
77
+ bufferedEntries: this.buffer.length,
78
+ bufferedBytes: estimateEntriesBytes(this.buffer),
79
+ flushInProgress: this.flushInProgress,
80
+ debouncePending: this.debounceTimer != null,
81
+ ageFlushPending: this.ageTimer != null,
82
+ serviceId: this.serviceId,
83
+ processRole: this.processRole,
84
+ };
85
+ }
86
+
87
+ offer(entry: LogEntry): void {
88
+ if (isLogPersistInternalTopic(entry.topic)) {
89
+ return;
90
+ }
91
+
92
+ if (!this.enabled) {
93
+ return;
94
+ }
95
+
96
+ if (this.buffer.length === 0) {
97
+ this.scheduleAgeFlush();
98
+ }
99
+
100
+ this.buffer.push(entry);
101
+
102
+ if (this.shouldScheduleDebouncedFlush()) {
103
+ this.scheduleDebouncedFlush();
104
+ }
105
+ }
106
+
107
+ private shouldScheduleDebouncedFlush(): boolean {
108
+ return (
109
+ this.buffer.length >= this.config.maxEntries || estimateEntriesBytes(this.buffer) >= this.config.maxBytes
110
+ );
111
+ }
112
+
113
+ private scheduleDebouncedFlush(): void {
114
+ if (this.debounceTimer != null) {
115
+ return;
116
+ }
117
+
118
+ spoolLogger.debug("log spool flush debounce scheduled", {
119
+ debounceMs: this.config.flushDebounceMs,
120
+ bufferedEntries: this.buffer.length,
121
+ });
122
+
123
+ this.debounceTimer = setTimeout(() => {
124
+ this.debounceTimer = null;
125
+ void this.flushChunk({ reason: "debounce" });
126
+ }, this.config.flushDebounceMs);
127
+ this.debounceTimer.unref?.();
128
+ }
129
+
130
+ private scheduleAgeFlush(): void {
131
+ if (this.ageTimer != null) {
132
+ return;
133
+ }
134
+
135
+ spoolLogger.debug("log spool age flush scheduled", {
136
+ maxAgeMs: this.config.maxAgeMs,
137
+ });
138
+
139
+ this.ageTimer = setTimeout(() => {
140
+ this.ageTimer = null;
141
+ void this.flushChunk({ reason: "maxAge" });
142
+ }, this.config.maxAgeMs);
143
+ this.ageTimer.unref?.();
144
+ }
145
+
146
+ private cancelDebounce(): void {
147
+ if (this.debounceTimer != null) {
148
+ clearTimeout(this.debounceTimer);
149
+ this.debounceTimer = null;
150
+ }
151
+ }
152
+
153
+ private cancelAgeFlush(): void {
154
+ if (this.ageTimer != null) {
155
+ clearTimeout(this.ageTimer);
156
+ this.ageTimer = null;
157
+ }
158
+ }
159
+
160
+ private async flushChunk(input: { reason: string }): Promise<void> {
161
+ if (this.flushInProgress || this.buffer.length === 0) {
162
+ return;
163
+ }
164
+ if (this.serviceId == null || this.processRole == null || this.serviceValue == null || this.spoolRoot == null) {
165
+ return;
166
+ }
167
+
168
+ this.cancelDebounce();
169
+ this.cancelAgeFlush();
170
+ this.flushInProgress = true;
171
+ try {
172
+ const byCount = this.buffer.slice(0, this.config.maxEntries);
173
+ const entries = takeEntriesWithinBytes(byCount, this.config.maxBytes);
174
+ this.buffer = this.buffer.slice(entries.length);
175
+
176
+ if (entries.length === 0) {
177
+ if (this.buffer.length > 0) {
178
+ this.scheduleAgeFlush();
179
+ } else {
180
+ this.cancelAgeFlush();
181
+ }
182
+ return;
183
+ }
184
+
185
+ const batchFile = await this.writeBatchTmp({
186
+ entries,
187
+ serviceId: this.serviceId,
188
+ processRole: this.processRole,
189
+ serviceValue: this.serviceValue,
190
+ spoolRoot: this.spoolRoot,
191
+ });
192
+
193
+ spoolLogger.info("log spool flushed to tmp", {
194
+ reason: input.reason,
195
+ fileName: batchFile.fileName,
196
+ entryCount: entries.length,
197
+ remainingBuffered: this.buffer.length,
198
+ });
199
+
200
+ if (this.buffer.length > 0) {
201
+ this.scheduleAgeFlush();
202
+ if (this.shouldScheduleDebouncedFlush()) {
203
+ this.scheduleDebouncedFlush();
204
+ }
205
+ } else {
206
+ this.cancelAgeFlush();
207
+ }
208
+ } catch (error) {
209
+ const message = error instanceof Error ? error.message : String(error);
210
+ spoolLogger.error("log spool flush failed", { reason: input.reason, error: message });
211
+ if (this.buffer.length > 0) {
212
+ this.scheduleAgeFlush();
213
+ }
214
+ } finally {
215
+ this.flushInProgress = false;
216
+ }
217
+ }
218
+
219
+ private async writeBatchTmp(input: {
220
+ entries: LogEntry[];
221
+ serviceId: string;
222
+ processRole: LogSpoolProcessRole;
223
+ serviceValue: string;
224
+ spoolRoot: string;
225
+ }): Promise<{ fileName: string; tmpPath: string }> {
226
+ const first = input.entries[0];
227
+ const shortHash = computeLogSpoolShortHash({
228
+ serviceValue: input.serviceValue,
229
+ serviceId: input.serviceId,
230
+ processRole: input.processRole,
231
+ entries: input.entries,
232
+ });
233
+ const baseName = buildLogSpoolBatchBaseName({
234
+ processRole: input.processRole,
235
+ firstEntryTimestamp: first.timestamp,
236
+ shortHash,
237
+ });
238
+ const fileName = `${baseName}.tmp`;
239
+ const processDir = logSpoolProcessDir(input.spoolRoot, input.serviceId, input.processRole);
240
+ await mkdir(processDir, { recursive: true });
241
+
242
+ const tmpPath = join(processDir, fileName);
243
+ const partPath = `${tmpPath}.part`;
244
+ const payload: LogSpoolBatchFile = {
245
+ entries: input.entries,
246
+ meta: {
247
+ serviceId: input.serviceId,
248
+ processRole: input.processRole,
249
+ serviceValue: input.serviceValue,
250
+ },
251
+ };
252
+ const content = `${JSON.stringify(payload)}\n`;
253
+
254
+ await writeFile(partPath, content, "utf8");
255
+ await rename(partPath, tmpPath);
256
+
257
+ return { fileName, tmpPath };
258
+ }
259
+ }
260
+
261
+ export { LogSpoolWriter };
262
+
263
+ export async function enableLogSpoolWriter(options: EnableLogSpoolOptions): Promise<void> {
264
+ await LogSpoolWriter.getInstance().enable(options);
265
+ }
266
+
267
+ export async function shutdownLogSpoolWriter(): Promise<void> {
268
+ await LogSpoolWriter.getInstance().shutdown();
269
+ }
270
+
271
+ export function getLogSpoolWriterStats(): LogSpoolWriterStats {
272
+ return LogSpoolWriter.getInstance().getStats();
273
+ }
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
- import type { LogEntry } from "./log-manager";
3
- import type { LogPersistLane } from "./log-persist.interface";
2
+ import type { LogEntry } from "../core/log-manager";
3
+ import type { LogPersistLane } from "./interface";
4
4
 
5
5
  const BATCH_ID_VERSION = 1;
6
6
 
@@ -0,0 +1,26 @@
1
+ import { envBool } from "../../../node/env/env-parsers";
2
+
3
+ /** Master switch — env name kept for compatibility (`LOG_PERSIST_ENABLED`). */
4
+ export function logSpoolEnabledFromEnv(env: NodeJS.ProcessEnv = process.env): boolean {
5
+ return envBool("LOG_PERSIST_ENABLED", false, env);
6
+ }
7
+
8
+ export function logPersistServiceFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
9
+ const raw = env.LOG_PERSIST_SERVICE?.trim();
10
+ return raw != null && raw !== "" ? raw : undefined;
11
+ }
12
+
13
+ export function logPersistProcessFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
14
+ const raw = env.LOG_PERSIST_PROCESS?.trim();
15
+ return raw != null && raw !== "" ? raw : undefined;
16
+ }
17
+
18
+ /** `LOG_PERSIST_REGISTRY_DIR` or `RUNTIME_DATA_DIR`. */
19
+ export function runtimeDataDirFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
20
+ const configured = env.LOG_PERSIST_REGISTRY_DIR?.trim();
21
+ if (configured != null && configured !== "") {
22
+ return configured;
23
+ }
24
+ const runtime = env.RUNTIME_DATA_DIR?.trim();
25
+ return runtime != null && runtime !== "" ? runtime : undefined;
26
+ }
@@ -1,10 +1,10 @@
1
- import { isCreateTargetAlreadyExistsError } from "../../core.api";
2
- import { postLogListCreate } from "../../list/list.api";
3
- import { CategoryList } from "../../list/list.interface";
4
- import type { LogEntry } from "./log-manager";
5
- import type { BuildLogListDraftInput, LogListDraft } from "./log-persist.interface";
6
- import { LOG_PERSIST_LOADER_KEY } from "./log-persist.interface";
7
- import { persistLogger } from "./log-persist-logger";
1
+ import { isCreateTargetAlreadyExistsError } from "../../../core.api";
2
+ import { postLogListCreate } from "../../../list/list.api";
3
+ import { CategoryList } from "../../../list/list.interface";
4
+ import type { LogEntry } from "../core/log-manager";
5
+ import type { BuildLogListDraftInput, LogListDraft } from "./interface";
6
+ import { LOG_PERSIST_LOADER_KEY } from "./interface";
7
+ import { persistLogger } from "./logger";
8
8
 
9
9
  export function estimateEntriesBytes(entries: LogEntry[]): number {
10
10
  if (entries.length === 0) {
@@ -19,6 +19,7 @@ export function estimateEntriesBytes(entries: LogEntry[]): number {
19
19
 
20
20
  export function buildLogListDraft(input: BuildLogListDraftInput): LogListDraft {
21
21
  const { service, process, lane, idempotencyKey, entries } = input;
22
+ // TODO: `lane` is legacy transport metadata — scheduled for removal; callers still pass a fixed value for decode compatibility.
22
23
  const first = entries[0];
23
24
  const last = entries[entries.length - 1];
24
25
 
@@ -1,4 +1,4 @@
1
- import type { LogEntry } from "./log-manager";
1
+ import type { LogEntry } from "../core/log-manager";
2
2
 
3
3
  type LogPersistOfferFn = (entry: LogEntry) => void;
4
4
 
@@ -0,0 +1,38 @@
1
+ import type { TargetDraft } from "../../../core.interface";
2
+ import type { List } from "../../../list/list.interface";
3
+ import type { LogEntry } from "../core/log-manager";
4
+
5
+ /**
6
+ * `ListDetails.loaderKey` stamped on every persisted log batch (write + read side).
7
+ * Business type: **LogBatch** (transport flush). Pairs with log-service **LogTrace**
8
+ * (`LogTrace.0`) after rekeying by `traceId`.
9
+ */
10
+ export const LOG_PERSIST_LOADER_KEY = "LogBatch.0";
11
+
12
+ /** Alias for {@link LOG_PERSIST_LOADER_KEY} — preferred when contrasting with LogTrace. */
13
+ export const LOG_BATCH_LOADER_KEY = LOG_PERSIST_LOADER_KEY;
14
+
15
+ /** Legacy transport metadata — fixed `"slow"` for spool uploads; required for downstream decode today. */
16
+ export type LogPersistLane = "fast" | "medium" | "slow";
17
+
18
+ export interface LogBatchMeta {
19
+ service: string;
20
+ process: string;
21
+ pid: number;
22
+ lane: LogPersistLane;
23
+ count: number;
24
+ from: number | null;
25
+ to: number | null;
26
+ flushedAt: number;
27
+ idempotencyKey: string;
28
+ }
29
+
30
+ export interface BuildLogListDraftInput {
31
+ service: string;
32
+ process: string;
33
+ lane: LogPersistLane;
34
+ idempotencyKey: string;
35
+ entries: LogEntry[];
36
+ }
37
+
38
+ export type LogListDraft = TargetDraft<List>;
@@ -0,0 +1,37 @@
1
+ import { createLogger } from "../core/create-logger";
2
+
3
+ /** User-facing / lifecycle logs — may be persisted like normal app logs. */
4
+ export const LOG_PERSIST_TOPIC = "log-persist";
5
+
6
+ /** Operational logs from the persist pipeline — never re-offered to avoid feedback loops. */
7
+ export const LOG_PERSIST_INTERNAL_TOPIC = "log-persist-internal";
8
+
9
+ type PipelineLogData = Record<string, unknown>;
10
+
11
+ function createPipelineLogger(module: string) {
12
+ const logger = createLogger({ module });
13
+
14
+ function write(level: "debug" | "info" | "warn" | "error", message: string, data?: PipelineLogData): void {
15
+ logger[level](message, {
16
+ topic: LOG_PERSIST_INTERNAL_TOPIC,
17
+ ...(data != null ? { data } : {}),
18
+ });
19
+ }
20
+
21
+ return {
22
+ debug: (message: string, data?: PipelineLogData) => write("debug", message, data),
23
+ info: (message: string, data?: PipelineLogData) => write("info", message, data),
24
+ warn: (message: string, data?: PipelineLogData) => write("warn", message, data),
25
+ error: (message: string, data?: PipelineLogData) => write("error", message, data),
26
+ };
27
+ }
28
+
29
+ /** Supabase upload path (`postLogBatch`). */
30
+ export const persistLogger = createPipelineLogger("log-upload");
31
+
32
+ /** File spool writer + collector. */
33
+ export const spoolLogger = createPipelineLogger("log-spool");
34
+
35
+ export function isLogPersistInternalTopic(topic: string | undefined): boolean {
36
+ return topic === LOG_PERSIST_INTERNAL_TOPIC;
37
+ }