target-supabase-sdk 0.2.23 → 0.2.25
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/README.md +3 -3
- package/dist/browser.d.ts +3 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -2
- package/dist/browser.js.map +1 -1
- package/dist/chunks/{enable-C7lFooTG.js → enable-DkiKPHDl.js} +20 -121
- package/dist/chunks/enable-DkiKPHDl.js.map +1 -0
- package/dist/chunks/{list.api-BzbTJBsM.js → list.api-B-aM4vzv.js} +46 -10
- package/dist/chunks/list.api-B-aM4vzv.js.map +1 -0
- package/dist/chunks/{task-queue-Ba8S21I6.js → task-queue-BYfO0Nzm.js} +212 -28
- package/dist/chunks/task-queue-BYfO0Nzm.js.map +1 -0
- package/dist/link/index.d.ts +2 -0
- package/dist/link/index.d.ts.map +1 -1
- package/dist/link/link.query.d.ts +9 -0
- package/dist/link/link.query.d.ts.map +1 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +157 -27
- package/dist/node.js.map +1 -1
- package/dist/preload.js +3 -3
- package/dist/shared/feed/feed.query.d.ts.map +1 -1
- package/dist/shared/idea/idea.build.d.ts +35 -0
- package/dist/shared/idea/idea.build.d.ts.map +1 -0
- package/dist/shared/idea/idea.interface.d.ts +23 -0
- package/dist/shared/idea/idea.interface.d.ts.map +1 -0
- package/dist/shared/idea/idea.normalize.d.ts +3 -0
- package/dist/shared/idea/idea.normalize.d.ts.map +1 -0
- package/dist/shared/idea/idea.parse.d.ts +3 -0
- package/dist/shared/idea/idea.parse.d.ts.map +1 -0
- package/dist/shared/idea/idea.query.d.ts +6 -0
- package/dist/shared/idea/idea.query.d.ts.map +1 -0
- package/dist/shared/idea/idea.schema.d.ts +60 -0
- package/dist/shared/idea/idea.schema.d.ts.map +1 -0
- package/dist/shared/idea/index.d.ts +15 -0
- package/dist/shared/idea/index.d.ts.map +1 -0
- package/dist/shared/idea/node/idea.hash.d.ts +3 -0
- package/dist/shared/idea/node/idea.hash.d.ts.map +1 -0
- package/dist/shared/idea/node/idea.locator.d.ts +9 -0
- package/dist/shared/idea/node/idea.locator.d.ts.map +1 -0
- package/dist/shared/idea/node/index.d.ts +3 -0
- package/dist/shared/idea/node/index.d.ts.map +1 -0
- package/dist/shared/log/core/log-batch.d.ts +4 -4
- package/dist/shared/log/core/log-batch.d.ts.map +1 -1
- package/dist/shared/log/index.d.ts +2 -1
- package/dist/shared/log/index.d.ts.map +1 -1
- package/dist/shared/log/spool/collector.d.ts +1 -1
- package/dist/shared/log/spool/collector.d.ts.map +1 -1
- package/dist/shared/log/spool/file.d.ts +2 -8
- package/dist/shared/log/spool/file.d.ts.map +1 -1
- package/dist/shared/log/spool/writer.d.ts.map +1 -1
- package/dist/shared/log/upload/flush.d.ts.map +1 -1
- package/dist/shared/log/upload/interface.d.ts +3 -11
- package/dist/shared/log/upload/interface.d.ts.map +1 -1
- package/dist/shared/media/media.query.d.ts.map +1 -1
- package/dist/shared/review/review.query.d.ts.map +1 -1
- package/dist/shared/utils/config-path.utils.d.ts +1 -1
- package/dist/shared/utils/postgrest.utils.d.ts +1 -1
- package/dist/task/index.d.ts +1 -1
- package/dist/task/local-task-registry.d.ts +1 -1
- package/dist/trigger/trigger.api.d.ts +6 -1
- package/dist/trigger/trigger.api.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/browser.ts +23 -2
- package/src/link/index.ts +2 -0
- package/src/link/link.query.ts +18 -0
- package/src/node.ts +8 -0
- package/src/shared/feed/README.md +1 -1
- package/src/shared/feed/feed.query.ts +2 -7
- package/src/shared/idea/README.md +82 -0
- package/src/shared/idea/VALIDATION-MATRIX.md +69 -0
- package/src/shared/idea/idea.build.ts +160 -0
- package/src/shared/idea/idea.interface.ts +34 -0
- package/src/shared/idea/idea.normalize.ts +17 -0
- package/src/shared/idea/idea.parse.ts +16 -0
- package/src/shared/idea/idea.query.ts +16 -0
- package/src/shared/idea/idea.schema.ts +32 -0
- package/src/shared/idea/index.ts +21 -0
- package/src/shared/idea/node/idea.hash.ts +6 -0
- package/src/shared/idea/node/idea.locator.ts +61 -0
- package/src/shared/idea/node/index.ts +7 -0
- package/src/shared/log/README.md +2 -3
- package/src/shared/log/core/log-batch.ts +12 -10
- package/src/shared/log/index.ts +2 -1
- package/src/shared/log/spool/collector.ts +46 -20
- package/src/shared/log/spool/file.ts +12 -25
- package/src/shared/log/spool/writer.ts +2 -7
- package/src/shared/log/upload/flush.ts +23 -38
- package/src/shared/log/upload/interface.ts +3 -12
- package/src/shared/media/README.md +1 -1
- package/src/shared/media/media.query.ts +2 -7
- package/src/shared/review/review.query.ts +2 -7
- package/src/shared/utils/config-path.utils.ts +1 -1
- package/src/shared/utils/postgrest.utils.ts +1 -1
- package/src/task/index.ts +1 -1
- package/src/task/local-task-registry.ts +1 -1
- package/src/trigger/trigger.api.ts +6 -1
- package/dist/chunks/enable-C7lFooTG.js.map +0 -1
- package/dist/chunks/list.api-BzbTJBsM.js.map +0 -1
- package/dist/chunks/task-queue-Ba8S21I6.js.map +0 -1
- package/dist/resource/resource.interface.d.ts +0 -20
- package/dist/resource/resource.interface.d.ts.map +0 -1
- package/dist/shared/log/upload/batch-id.d.ts +0 -13
- package/dist/shared/log/upload/batch-id.d.ts.map +0 -1
- package/dist/task/task.utils.d.ts +0 -1
- package/dist/task/task.utils.d.ts.map +0 -1
- package/src/resource/resource.interface.ts +0 -37
- package/src/shared/log/upload/batch-id.ts +0 -43
- package/src/task/task.utils.ts +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { access, constants, readdir, readFile, rename, stat, unlink } from "node:fs/promises";
|
|
1
|
+
import { access, constants, readdir, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { isLogEntry } from "../core/log-batch";
|
|
4
|
-
import { computeLogBatchIdempotencyKey } from "../upload/batch-id";
|
|
5
4
|
import { buildLogListDraft, postLogBatch } from "../upload/flush";
|
|
6
5
|
import { spoolLogger } from "../upload/logger";
|
|
7
6
|
import { type DEFAULT_LOG_SPOOL_CONFIG, resolveLogSpoolConfig } from "./config";
|
|
@@ -11,6 +10,7 @@ import { logSpoolProcessDir, resolveLogSpoolRoot } from "./paths";
|
|
|
11
10
|
import { resolveAllLogSpoolProcessRoles } from "./process-roles";
|
|
12
11
|
|
|
13
12
|
const UPLOAD_LANE = "slow";
|
|
13
|
+
const MAX_UPLOADS_PER_COLLECT_TICK = 20;
|
|
14
14
|
|
|
15
15
|
/** Per serviceId — guard collect-log tick runs GC at most once per `gc.intervalMs`. */
|
|
16
16
|
const lastGcAtMsByServiceId = new Map<string, number>();
|
|
@@ -61,6 +61,10 @@ function processMetaKey(serviceId: string, processRole: LogSpoolProcessRole): st
|
|
|
61
61
|
return `${serviceId}:${processRole}`;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
function syncedMarkerPath(jsonPath: string): string {
|
|
65
|
+
return jsonPath.replace(/\.json$/, ".synced");
|
|
66
|
+
}
|
|
67
|
+
|
|
64
68
|
async function uploadTmpBatch(input: {
|
|
65
69
|
serviceId: string;
|
|
66
70
|
serviceValue: string;
|
|
@@ -78,6 +82,7 @@ async function uploadTmpBatch(input: {
|
|
|
78
82
|
|
|
79
83
|
const jsonFileName = input.fileName.replace(/\.tmp$/, ".json");
|
|
80
84
|
const jsonPath = join(logSpoolProcessDir(input.spoolRoot, input.serviceId, input.processRole), jsonFileName);
|
|
85
|
+
const syncedPath = syncedMarkerPath(jsonPath);
|
|
81
86
|
|
|
82
87
|
if (await pathExists(jsonPath)) {
|
|
83
88
|
try {
|
|
@@ -92,6 +97,19 @@ async function uploadTmpBatch(input: {
|
|
|
92
97
|
return "skipped";
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
if (await pathExists(syncedPath)) {
|
|
101
|
+
try {
|
|
102
|
+
await rename(input.tmpPath, jsonPath);
|
|
103
|
+
} catch {
|
|
104
|
+
try {
|
|
105
|
+
await unlink(input.tmpPath);
|
|
106
|
+
} catch {
|
|
107
|
+
// best-effort
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return "skipped";
|
|
111
|
+
}
|
|
112
|
+
|
|
95
113
|
const batch = await readBatchTmpFile(input.tmpPath);
|
|
96
114
|
if (batch == null) {
|
|
97
115
|
spoolLogger.warn("collect-log skipped — tmp failed validation", {
|
|
@@ -108,19 +126,10 @@ async function uploadTmpBatch(input: {
|
|
|
108
126
|
}
|
|
109
127
|
|
|
110
128
|
const processKey = processMetaKey(input.serviceId, input.processRole);
|
|
111
|
-
// TODO: `lane` is legacy transport metadata — scheduled for removal; fixed to "slow" for downstream decode compatibility.
|
|
112
|
-
const idempotencyKey = computeLogBatchIdempotencyKey({
|
|
113
|
-
service: input.serviceValue,
|
|
114
|
-
process: processKey,
|
|
115
|
-
lane: UPLOAD_LANE,
|
|
116
|
-
entries: batch.entries,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
129
|
const draft = buildLogListDraft({
|
|
120
130
|
service: input.serviceValue,
|
|
121
131
|
process: processKey,
|
|
122
132
|
lane: UPLOAD_LANE,
|
|
123
|
-
idempotencyKey,
|
|
124
133
|
entries: batch.entries,
|
|
125
134
|
});
|
|
126
135
|
|
|
@@ -136,8 +145,20 @@ async function uploadTmpBatch(input: {
|
|
|
136
145
|
return "failed";
|
|
137
146
|
}
|
|
138
147
|
|
|
148
|
+
try {
|
|
149
|
+
await writeFile(syncedPath, `${Date.now()}\n`, "utf8");
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
152
|
+
spoolLogger.warn("collect-log synced marker write failed", { syncedPath, error: message });
|
|
153
|
+
}
|
|
154
|
+
|
|
139
155
|
try {
|
|
140
156
|
await rename(input.tmpPath, jsonPath);
|
|
157
|
+
try {
|
|
158
|
+
await unlink(syncedPath);
|
|
159
|
+
} catch {
|
|
160
|
+
// best-effort
|
|
161
|
+
}
|
|
141
162
|
} catch (error) {
|
|
142
163
|
const message = error instanceof Error ? error.message : String(error);
|
|
143
164
|
spoolLogger.error("collect-log rename tmp→json failed after upload", {
|
|
@@ -145,14 +166,13 @@ async function uploadTmpBatch(input: {
|
|
|
145
166
|
jsonPath,
|
|
146
167
|
error: message,
|
|
147
168
|
});
|
|
148
|
-
return "
|
|
169
|
+
return "uploaded";
|
|
149
170
|
}
|
|
150
171
|
|
|
151
172
|
spoolLogger.info("collect-log uploaded batch", {
|
|
152
173
|
processRole: input.processRole,
|
|
153
174
|
fileName: jsonFileName,
|
|
154
175
|
entryCount: batch.entries.length,
|
|
155
|
-
idempotencyKey,
|
|
156
176
|
});
|
|
157
177
|
|
|
158
178
|
return "uploaded";
|
|
@@ -217,22 +237,22 @@ async function gcSyncedJsonFiles(input: {
|
|
|
217
237
|
}
|
|
218
238
|
|
|
219
239
|
for (const name of names) {
|
|
220
|
-
if (!name.endsWith(".json")) {
|
|
240
|
+
if (!name.endsWith(".json") && !name.endsWith(".synced")) {
|
|
221
241
|
continue;
|
|
222
242
|
}
|
|
223
|
-
if (parseLogSpoolBatchFilename(name) == null) {
|
|
243
|
+
if (parseLogSpoolBatchFilename(name) == null && !name.endsWith(".synced")) {
|
|
224
244
|
continue;
|
|
225
245
|
}
|
|
226
246
|
|
|
227
|
-
const
|
|
247
|
+
const filePath = join(processDir, name);
|
|
228
248
|
try {
|
|
229
|
-
const fileStat = await stat(
|
|
249
|
+
const fileStat = await stat(filePath);
|
|
230
250
|
if (input.nowMs - fileStat.mtimeMs <= input.syncedRetentionMs) {
|
|
231
251
|
continue;
|
|
232
252
|
}
|
|
233
|
-
await unlink(
|
|
253
|
+
await unlink(filePath);
|
|
234
254
|
removed += 1;
|
|
235
|
-
spoolLogger.info("collect-log gc removed synced
|
|
255
|
+
spoolLogger.info("collect-log gc removed synced file", {
|
|
236
256
|
fileName: name,
|
|
237
257
|
processRole,
|
|
238
258
|
});
|
|
@@ -256,7 +276,7 @@ function shouldRunGc(serviceId: string, nowMs: number, intervalMs: number): bool
|
|
|
256
276
|
|
|
257
277
|
/**
|
|
258
278
|
* Guard-only: upload pending `.tmp` batches, rename to `.json`, then periodic GC.
|
|
259
|
-
*
|
|
279
|
+
* Post success is tracked via `.json` or `.synced` marker (prevents duplicate DB inserts).
|
|
260
280
|
*/
|
|
261
281
|
export async function runCollectLogTick(input: RunCollectLogTickInput): Promise<RunCollectLogTickResult> {
|
|
262
282
|
const config = resolveLogSpoolConfig(input.config);
|
|
@@ -271,6 +291,8 @@ export async function runCollectLogTick(input: RunCollectLogTickInput): Promise<
|
|
|
271
291
|
gcSyncedRemoved: 0,
|
|
272
292
|
};
|
|
273
293
|
|
|
294
|
+
let uploadsThisTick = 0;
|
|
295
|
+
|
|
274
296
|
for (const processRole of resolveAllLogSpoolProcessRoles()) {
|
|
275
297
|
const processDir = logSpoolProcessDir(spoolRoot, input.serviceId, processRole);
|
|
276
298
|
let names: string[] = [];
|
|
@@ -284,6 +306,9 @@ export async function runCollectLogTick(input: RunCollectLogTickInput): Promise<
|
|
|
284
306
|
if (!name.endsWith(".tmp")) {
|
|
285
307
|
continue;
|
|
286
308
|
}
|
|
309
|
+
if (uploadsThisTick >= MAX_UPLOADS_PER_COLLECT_TICK) {
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
287
312
|
const status = await uploadTmpBatch({
|
|
288
313
|
serviceId: input.serviceId,
|
|
289
314
|
serviceValue: input.serviceValue,
|
|
@@ -295,6 +320,7 @@ export async function runCollectLogTick(input: RunCollectLogTickInput): Promise<
|
|
|
295
320
|
});
|
|
296
321
|
if (status === "uploaded") {
|
|
297
322
|
result.uploaded += 1;
|
|
323
|
+
uploadsThisTick += 1;
|
|
298
324
|
} else if (status === "skipped") {
|
|
299
325
|
result.skipped += 1;
|
|
300
326
|
} else {
|
|
@@ -1,37 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { computeLogBatchIdempotencyKey } from "../upload/batch-id";
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
3
2
|
import type { LogSpoolProcessRole } from "./interface";
|
|
4
3
|
|
|
5
4
|
/** `role.timestamp.hash.tmp|json` — role is lowercase alphanumeric + hyphen. */
|
|
6
|
-
const BATCH_FILE_PATTERN = /^([a-z][a-z0-9-]*)\.(\d{14})\.([a-f0-9]{8})\.(tmp|json)$/;
|
|
5
|
+
const BATCH_FILE_PATTERN = /^([a-z][a-z0-9-]*)\.(\d{14})\.([a-f0-9]{8})\.(tmp|json|synced)$/;
|
|
7
6
|
|
|
8
7
|
export function formatLogSpoolBatchTimestamp(ms: number): string {
|
|
9
8
|
const d = new Date(ms);
|
|
10
9
|
const pad = (n: number) => String(n).padStart(2, "0");
|
|
11
10
|
return (
|
|
12
|
-
`${d.
|
|
13
|
-
`${pad(d.
|
|
14
|
-
`${pad(d.
|
|
15
|
-
`${pad(d.
|
|
16
|
-
`${pad(d.
|
|
17
|
-
`${pad(d.
|
|
11
|
+
`${d.getUTCFullYear()}` +
|
|
12
|
+
`${pad(d.getUTCMonth() + 1)}` +
|
|
13
|
+
`${pad(d.getUTCDate())}` +
|
|
14
|
+
`${pad(d.getUTCHours())}` +
|
|
15
|
+
`${pad(d.getUTCMinutes())}` +
|
|
16
|
+
`${pad(d.getUTCSeconds())}`
|
|
18
17
|
);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
export function
|
|
22
|
-
|
|
23
|
-
serviceId: string;
|
|
24
|
-
processRole: LogSpoolProcessRole;
|
|
25
|
-
entries: LogEntry[];
|
|
26
|
-
}): string {
|
|
27
|
-
const processKey = `${input.serviceId}:${input.processRole}`;
|
|
28
|
-
const idempotencyKey = computeLogBatchIdempotencyKey({
|
|
29
|
-
service: input.serviceValue,
|
|
30
|
-
process: processKey,
|
|
31
|
-
lane: "slow",
|
|
32
|
-
entries: input.entries,
|
|
33
|
-
});
|
|
34
|
-
return idempotencyKey.slice(0, 8);
|
|
20
|
+
export function randomLogSpoolShortId(): string {
|
|
21
|
+
return randomBytes(4).toString("hex");
|
|
35
22
|
}
|
|
36
23
|
|
|
37
24
|
export function buildLogSpoolBatchBaseName(input: {
|
|
@@ -47,7 +34,7 @@ export function parseLogSpoolBatchFilename(filename: string): {
|
|
|
47
34
|
processRole: LogSpoolProcessRole;
|
|
48
35
|
timestampMs: number;
|
|
49
36
|
shortHash: string;
|
|
50
|
-
extension: "tmp" | "json";
|
|
37
|
+
extension: "tmp" | "json" | "synced";
|
|
51
38
|
} | null {
|
|
52
39
|
const match = BATCH_FILE_PATTERN.exec(filename);
|
|
53
40
|
if (match == null) {
|
|
@@ -57,7 +44,7 @@ export function parseLogSpoolBatchFilename(filename: string): {
|
|
|
57
44
|
const processRole = match[1] as LogSpoolProcessRole;
|
|
58
45
|
const tsRaw = match[2];
|
|
59
46
|
const shortHash = match[3];
|
|
60
|
-
const extension = match[4] as "tmp" | "json";
|
|
47
|
+
const extension = match[4] as "tmp" | "json" | "synced";
|
|
61
48
|
|
|
62
49
|
const year = Number(tsRaw.slice(0, 4));
|
|
63
50
|
const month = Number(tsRaw.slice(4, 6));
|
|
@@ -5,7 +5,7 @@ import { estimateEntriesBytes, takeEntriesWithinBytes } from "../upload/flush";
|
|
|
5
5
|
import { registerLogPersistOffer } from "../upload/hook";
|
|
6
6
|
import { isLogPersistInternalTopic, spoolLogger } from "../upload/logger";
|
|
7
7
|
import { DEFAULT_LOG_SPOOL_CONFIG, resolveLogSpoolConfig } from "./config";
|
|
8
|
-
import { buildLogSpoolBatchBaseName,
|
|
8
|
+
import { buildLogSpoolBatchBaseName, randomLogSpoolShortId } from "./file";
|
|
9
9
|
import type { EnableLogSpoolOptions, LogSpoolBatchFile, LogSpoolProcessRole, LogSpoolWriterStats } from "./interface";
|
|
10
10
|
import { logSpoolProcessDir, resolveLogSpoolRoot } from "./paths";
|
|
11
11
|
|
|
@@ -224,12 +224,7 @@ class LogSpoolWriter {
|
|
|
224
224
|
spoolRoot: string;
|
|
225
225
|
}): Promise<{ fileName: string; tmpPath: string }> {
|
|
226
226
|
const first = input.entries[0];
|
|
227
|
-
const shortHash =
|
|
228
|
-
serviceValue: input.serviceValue,
|
|
229
|
-
serviceId: input.serviceId,
|
|
230
|
-
processRole: input.processRole,
|
|
231
|
-
entries: input.entries,
|
|
232
|
-
});
|
|
227
|
+
const shortHash = randomLogSpoolShortId();
|
|
233
228
|
const baseName = buildLogSpoolBatchBaseName({
|
|
234
229
|
processRole: input.processRole,
|
|
235
230
|
firstEntryTimestamp: first.timestamp,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { postLogListCreate } from "../../../list/list.api";
|
|
1
|
+
import { postListCreate } from "../../../list/list.api";
|
|
3
2
|
import { CategoryList } from "../../../list/list.interface";
|
|
4
3
|
import type { LogEntry } from "../core/log-manager";
|
|
5
4
|
import type { BuildLogListDraftInput, LogListDraft } from "./interface";
|
|
6
|
-
import {
|
|
5
|
+
import { LOG_BATCH_LIST_VALUE } from "./interface";
|
|
7
6
|
import { persistLogger } from "./logger";
|
|
8
7
|
|
|
9
8
|
export function estimateEntriesBytes(entries: LogEntry[]): number {
|
|
@@ -18,19 +17,18 @@ export function estimateEntriesBytes(entries: LogEntry[]): number {
|
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
export function buildLogListDraft(input: BuildLogListDraftInput): LogListDraft {
|
|
21
|
-
const { service, process, lane,
|
|
22
|
-
// TODO: `lane` is legacy transport metadata — scheduled for removal; callers still pass a fixed value for decode compatibility.
|
|
20
|
+
const { service, process, lane, entries } = input;
|
|
23
21
|
const first = entries[0];
|
|
24
22
|
const last = entries[entries.length - 1];
|
|
25
23
|
|
|
26
24
|
return {
|
|
27
|
-
name:
|
|
28
|
-
value:
|
|
25
|
+
name: service,
|
|
26
|
+
value: LOG_BATCH_LIST_VALUE,
|
|
29
27
|
category: CategoryList.LIST,
|
|
30
28
|
tagList: ["log", lane, service],
|
|
31
29
|
details: {
|
|
32
30
|
manifestVersion: 0,
|
|
33
|
-
loaderKey:
|
|
31
|
+
loaderKey: LOG_BATCH_LIST_VALUE,
|
|
34
32
|
meta: {
|
|
35
33
|
service,
|
|
36
34
|
process,
|
|
@@ -40,7 +38,6 @@ export function buildLogListDraft(input: BuildLogListDraftInput): LogListDraft {
|
|
|
40
38
|
from: first?.timestamp ?? null,
|
|
41
39
|
to: last?.timestamp ?? null,
|
|
42
40
|
flushedAt: Date.now(),
|
|
43
|
-
idempotencyKey,
|
|
44
41
|
},
|
|
45
42
|
preview: first?.message ?? "",
|
|
46
43
|
items: entries,
|
|
@@ -67,36 +64,24 @@ async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: str
|
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
export async function postLogBatch(draft: LogListDraft, postTimeoutMs: number): Promise<void> {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
67
|
+
const result = await withTimeout(
|
|
68
|
+
postListCreate({
|
|
69
|
+
name: draft.name,
|
|
70
|
+
value: draft.value,
|
|
71
|
+
category: draft.category,
|
|
72
|
+
details: draft.details,
|
|
73
|
+
}),
|
|
74
|
+
postTimeoutMs,
|
|
75
|
+
"postListCreate",
|
|
76
|
+
);
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
throw new Error(message);
|
|
90
|
-
}
|
|
91
|
-
} catch (error) {
|
|
92
|
-
if (isCreateTargetAlreadyExistsError(error)) {
|
|
93
|
-
persistLogger.error("post log batch idempotent duplicate — treating as success", {
|
|
94
|
-
idempotencyKey: draft.value,
|
|
95
|
-
name: draft.name,
|
|
96
|
-
});
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
throw error;
|
|
78
|
+
if (!result.success) {
|
|
79
|
+
const message = result.error?.message ?? "postListCreate failed";
|
|
80
|
+
persistLogger.error("post log batch failed", {
|
|
81
|
+
name: draft.name,
|
|
82
|
+
error: message,
|
|
83
|
+
});
|
|
84
|
+
throw new Error(message);
|
|
100
85
|
}
|
|
101
86
|
}
|
|
102
87
|
|
|
@@ -2,17 +2,10 @@ import type { TargetDraft } from "../../../core.interface";
|
|
|
2
2
|
import type { List } from "../../../list/list.interface";
|
|
3
3
|
import type { LogEntry } from "../core/log-manager";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
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";
|
|
5
|
+
/** Discriminator on `List.value` and `details.loaderKey` — query by `value` only, not JSON loaderKey. */
|
|
6
|
+
export const LOG_BATCH_LIST_VALUE = "log-batch";
|
|
11
7
|
|
|
12
|
-
/**
|
|
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. */
|
|
8
|
+
/** Legacy transport metadata — fixed `"slow"` for spool uploads. */
|
|
16
9
|
export type LogPersistLane = "fast" | "medium" | "slow";
|
|
17
10
|
|
|
18
11
|
export interface LogBatchMeta {
|
|
@@ -24,14 +17,12 @@ export interface LogBatchMeta {
|
|
|
24
17
|
from: number | null;
|
|
25
18
|
to: number | null;
|
|
26
19
|
flushedAt: number;
|
|
27
|
-
idempotencyKey: string;
|
|
28
20
|
}
|
|
29
21
|
|
|
30
22
|
export interface BuildLogListDraftInput {
|
|
31
23
|
service: string;
|
|
32
24
|
process: string;
|
|
33
25
|
lane: LogPersistLane;
|
|
34
|
-
idempotencyKey: string;
|
|
35
26
|
entries: LogEntry[];
|
|
36
27
|
}
|
|
37
28
|
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import type { QueryFilter } from "../../core.interface";
|
|
2
|
-
import {
|
|
2
|
+
import { linkDedupFilters } from "../../link/link.query";
|
|
3
3
|
import type { MediaValue } from "./media.interface";
|
|
4
4
|
|
|
5
5
|
/** Dedup key: `category=link` + `value` + `name` (matches register / find). */
|
|
6
6
|
export function mediaLinkDedupFilters(input: { value: MediaValue; name: string }): QueryFilter[] {
|
|
7
|
-
|
|
8
|
-
return [
|
|
9
|
-
{ field: "category", operator: "eq", value: CategoryLink.LINK },
|
|
10
|
-
{ field: "value", operator: "eq", value: input.value },
|
|
11
|
-
{ field: "name", operator: "eq", value: name },
|
|
12
|
-
];
|
|
7
|
+
return linkDedupFilters(input);
|
|
13
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { QueryFilter } from "../../core.interface";
|
|
2
|
-
import {
|
|
2
|
+
import { linkDedupFilters } from "../../link/link.query";
|
|
3
3
|
import { REVIEW_VALUE } from "./review.interface";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -7,10 +7,5 @@ import { REVIEW_VALUE } from "./review.interface";
|
|
|
7
7
|
* Many rows may match — the SDK does not define dedup for reviews.
|
|
8
8
|
*/
|
|
9
9
|
export function reviewLinksForNameFilters(name: string): QueryFilter[] {
|
|
10
|
-
|
|
11
|
-
return [
|
|
12
|
-
{ field: "category", operator: "eq", value: CategoryLink.LINK },
|
|
13
|
-
{ field: "value", operator: "eq", value: REVIEW_VALUE },
|
|
14
|
-
{ field: "name", operator: "eq", value: trimmed },
|
|
15
|
-
];
|
|
10
|
+
return linkDedupFilters({ value: REVIEW_VALUE, name });
|
|
16
11
|
}
|
|
@@ -15,7 +15,7 @@ export function getConfigFileDir(configFilePath: string): string {
|
|
|
15
15
|
* - Absolute `pathInConfig` → returned as-is
|
|
16
16
|
* - Relative `pathInConfig` → `resolve(dirname(configFilePath), pathInConfig)`
|
|
17
17
|
*
|
|
18
|
-
* **Not** relative to `process.cwd()`. See `.cursor/skills/
|
|
18
|
+
* **Not** relative to `process.cwd()`. See `.cursor/skills/task-local-discovery/SKILL.md`.
|
|
19
19
|
*/
|
|
20
20
|
export function resolvePathFromConfigFile(configFilePath: string, pathInConfig: string): string {
|
|
21
21
|
const trimmed = pathInConfig.trim();
|
package/src/task/index.ts
CHANGED
|
@@ -244,7 +244,7 @@ async function runBootstrapScan(options: BootstrapLocalTasksOptions): Promise<Bo
|
|
|
244
244
|
* ./tasks/my-task/index.mjs
|
|
245
245
|
* ```
|
|
246
246
|
*
|
|
247
|
-
* `taskDir` / `entry` paths are relative to **their config file's directory** (see
|
|
247
|
+
* `taskDir` / `entry` paths are relative to **their config file's directory** (see task-local-discovery skill).
|
|
248
248
|
*
|
|
249
249
|
* Legacy fallback: `./task.config.js` at project root (`taskDir: "./tasks"`).
|
|
250
250
|
*/
|
|
@@ -60,7 +60,12 @@ function enabledTriggerFilter() {
|
|
|
60
60
|
return [{ field: TRIGGER_STATUS_FIELD, operator: "eq" as const, value: TriggerStatus.ENABLED }];
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* List all ENABLED triggers. Due-check is in-memory on the caller:
|
|
65
|
+
* filter with `isTriggerDue`, then `patchTriggerFired` with `buildFireKey`
|
|
66
|
+
* (both from `trigger.utils`, exported on `/node`).
|
|
67
|
+
* Do not call this from TriggerNode (local interval runners only).
|
|
68
|
+
*/
|
|
64
69
|
export const scanEnabledTriggers = validateWithSchema(
|
|
65
70
|
scanEnabledTriggersSchema,
|
|
66
71
|
"scanEnabledTriggersSchema",
|