target-supabase-sdk 0.2.24 → 0.3.0
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/browser.d.ts +3 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -2
- package/dist/browser.js.map +1 -1
- package/dist/chunks/{list.api-BzbTJBsM.js → config-BNxsVKR4.js} +163 -10
- package/dist/chunks/config-BNxsVKR4.js.map +1 -0
- package/dist/chunks/{enable-C7lFooTG.js → enable-CF77OsXr.js} +20 -238
- package/dist/chunks/enable-CF77OsXr.js.map +1 -0
- package/dist/chunks/{task-queue-C_nUaM2S.js → task-queue-BL-KwAGW.js} +39 -13
- package/dist/chunks/task-queue-BL-KwAGW.js.map +1 -0
- package/dist/node/{node-runtime.base.d.ts → base-node-runtime.d.ts} +4 -1
- package/dist/node/base-node-runtime.d.ts.map +1 -0
- package/dist/node/node-liveness.d.ts +2 -0
- package/dist/node/node-liveness.d.ts.map +1 -1
- package/dist/node/node-service-id.d.ts +3 -0
- package/dist/node/node-service-id.d.ts.map +1 -0
- package/dist/node/node.api.d.ts +9 -1
- package/dist/node/node.api.d.ts.map +1 -1
- package/dist/node/node.interface.d.ts +9 -2
- package/dist/node/node.interface.d.ts.map +1 -1
- package/dist/node/service-guard/run-service-guard-tick.d.ts.map +1 -1
- package/dist/node/service-guard/service-guard-node.d.ts +3 -1
- package/dist/node/service-guard/service-guard-node.d.ts.map +1 -1
- package/dist/node/service-host/service-host.d.ts.map +1 -1
- package/dist/node/service-host/single-process-service.d.ts.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +244 -198
- package/dist/node.js.map +1 -1
- package/dist/preload.js +3 -3
- package/dist/service/service.interface.d.ts +2 -2
- package/dist/service/service.interface.d.ts.map +1 -1
- 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/task/task-node.d.ts +3 -1
- package/dist/task/task-node.d.ts.map +1 -1
- package/dist/trigger/trigger-manager.d.ts +1 -1
- package/dist/trigger/trigger-node.d.ts +3 -1
- package/dist/trigger/trigger-node.d.ts.map +1 -1
- package/dist/trigger/trigger.api.d.ts +10 -10
- package/package.json +1 -1
- package/src/browser.ts +4 -3
- package/src/node/{node-runtime.base.ts → base-node-runtime.ts} +11 -2
- package/src/node/node-liveness.ts +6 -1
- package/src/node/node-service-id.ts +12 -0
- package/src/node/node.api.ts +7 -5
- package/src/node/node.interface.ts +10 -2
- package/src/node/service-guard/run-service-guard-tick.ts +12 -6
- package/src/node/service-guard/service-guard-node.ts +6 -1
- package/src/node/service-host/service-host.ts +2 -1
- package/src/node/service-host/single-process-service.ts +3 -0
- package/src/node.ts +2 -2
- package/src/service/service.interface.ts +2 -2
- 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/task/task-node.ts +6 -1
- package/src/trigger/trigger-manager.ts +1 -1
- package/src/trigger/trigger-node.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-C_nUaM2S.js.map +0 -1
- package/dist/node/node-runtime.base.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/src/shared/log/upload/batch-id.ts +0 -43
package/dist/node.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { M as MAX_POLL_TARGET_LIST_SIZE, V as validateWithSchema,
|
|
3
|
-
export { B as BaseValidator, C as CREATE_TARGET_ALREADY_EXISTS_MESSAGE, a as CategoryList, L as
|
|
4
|
-
import { l as loadEnvFiles, b as readEnv, c as requireEnv, d as resolveLogSpoolSpawnEnvForLabel, e as resolveLogSpoolConfig, f as resolveLogSpoolRoot, g as resolveAllLogSpoolProcessRoles, h as logSpoolProcessDir, s as spoolLogger, i as parseLogSpoolBatchFilename, j as computeLogBatchIdempotencyKey, k as buildLogListDraft, n as postLogBatch, a as logSpoolEnabledFromEnv, o as logSpoolConfigFromEnv, L as LOG_SPOOL_SERVICE_ID_ENV, q as ensureLogSpoolFromEnv, t as shutdownLogSpoolFromEnv, u as getLogSpoolStats } from './chunks/enable-C7lFooTG.js';
|
|
5
|
-
export { C as CLI_PROD_FLAG, S as SERVICE_ENV_PROFILE_ENV_KEY, w as SERVICE_ENV_PROFILE_PROD, x as buildLogSpoolSpawnEnv, y as envBool, z as envInt, A as envMs, B as envNumber, D as envPort, E as envProfileFromProcess, F as resolveDefaultEnvFiles, r as resolveProjectRootByPackageName, G as resolveProjectRootFromModule, v as validateLogSpoolPreloadEnv } from './chunks/enable-C7lFooTG.js';
|
|
2
|
+
import { M as MAX_POLL_TARGET_LIST_SIZE, V as validateWithSchema, f as createLogger, z as pollTargetList, k as generateResponse, g as createTarget, w as logManager, a3 as createScope, c as LogLevel, a4 as patchScope, K as supabase, a5 as readEnv, a6 as requireEnv, J as scanTargetList, a7 as withModule, Y as resolveLogSpoolConfig, a8 as parseLogSpoolBatchFilename, a2 as logSpoolConfigFromEnv, a0 as LOG_SPOOL_SERVICE_ID_ENV, l as getPossibleTarget, E as postTarget, q as isCreateTargetAlreadyExistsError, m as getTarget, Q as updateTarget, t as isOptimisticLockResponse, R as updateTargetDetails } from './chunks/config-BNxsVKR4.js';
|
|
3
|
+
export { B as BaseValidator, C as CREATE_TARGET_ALREADY_EXISTS_MESSAGE, a as CategoryList, L as LOG_BATCH_LIST_VALUE, b as LOG_MIN_LEVEL_ENV_KEY, d as MAX_TARGET_LIST_PAGE_SIZE, O as OPTIMISTIC_LOCK_ERROR_CODE, e as OPTIMISTIC_LOCK_FAILED_MESSAGE, P as PostListValidator, S as StatusCode, U as UPDATE_TARGET_NOT_FOUND_MESSAGE, h as deleteTarget, W as envBool, a9 as envInt, aa as envMs, ab as envNumber, ac as envPort, i as formatLogSpoolBatchTimestamp, j as formatZodError, n as getTargetList, o as getTargetTotalCount, p as handleSupabaseError, r as isDevEnvironment, s as isOptimisticLockError, u as logDev, v as logDevGroup, x as logMinLevelFromEnv, y as patchTarget, A as postListCreate, D as postLogListCreate, F as postTargetPayloadSchema, G as queryFilterSchema, H as resolveLogMinLevel, I as safeParseWithSchema, N as targetDraftSchema, T as validateWith } from './chunks/config-BNxsVKR4.js';
|
|
6
4
|
import { randomBytes, createHash } from 'node:crypto';
|
|
5
|
+
import { bT as getErrorMessage, bU as LOG_TOPIC_NODE, bv as requireNodeServiceIdFromEnv, bd as postRegisterNode, aT as patchChangeNodeStatus, n as NodeStatus, b2 as patchStopNode, a$ as patchNodeHeartBeat, bN as sha256Hex, E as EMPTY_REGISTRY_SLOT_RUNTIME_STATE, bD as runRegistrySlotGuardCheck, br as registrySlotRuntimePatchFromGuardResult, c as CategoryNode, a8 as evaluateBusyNodeLiveness, aL as nodesForTaskLiveness, b1 as patchServiceRuntime, aE as isLogEntry, N as NodeKind, X as claimServiceRegistrySlot, q as ServiceRegistryError, ab as fetchWithRetry, aH as isRetryableHttpStatus, aa as fetchBinaryWithRetry, aG as isOpaqueChunkUrl, e as CategoryRepo, aA as isHttpUrl, az as isFeedValue, bV as isFeedIngestSource, bW as resolveFeedOriginalStorageProvider, a9 as feedLinkDedupFilters, B as buildFeedLinkDraft, b as CategoryLink, bX as buildFeedTagList, i as IDEA_IMAGE_TEMP_DIR, au as guessMediaMime, M as MEDIA_CONTENT_HASH_ALGORITHM, aF as isMediaValue, aK as mediaLinkDedupFilters, Q as buildMediaLinkDraft, R as ResultCode, bY as LOG_TOPIC_TASK, s as TASK_REPO_USAGE, ao as getScanRemoteRepoValues, aX as patchClaimTask, bZ as CRITICAL_UNKNOWN_TASK_TRACE_ID, aV as patchChangeTaskStatus, u as TaskStatusAction, b_ as toError, bl as postTaskSchema, b$ as createTaskRow, t as TaskStatus } from './chunks/task-queue-BL-KwAGW.js';
|
|
6
|
+
export { A as ApiMethod, C as CategoryConfig, a as CategoryExtraction, d as CategoryParcel, f as CategoryService, g as CategoryTask, D as DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS, c0 as FEED_INGEST_SOURCES, F as FEED_VALUES, I as IDEA_IMAGE_LINK_NAME, h as IDEA_IMAGE_TAG_RAW, j as IDEA_LINK_VALUE, L as LINK_MANIFEST_VERSION, k as LIST_MANIFEST_VERSION, l as MEDIA_CONTENT_HASH_PREFIX_LENGTH, m as MEDIA_VALUES, P as POST_TASK_DEFAULT_MAX_ATTEMPTS, o as ParcelManager, p as PostLinkValidator, S as ServiceLifecycleStatus, r as ServiceSlotStatus, T as TARGET_SYSTEM_REGISTRY_KEY, v as apiDetailsSchema, w as appendSystemRegistryEmptySlots, x as assertRegistrySlotAvailable, y as assertRegistrySlotOwner, z as buildEmptyServiceSlots, G as buildFeedLinkName, H as buildIdeaImageLinkDraft, J as buildIdeaLinkDraft, K as buildLinkTargetDraft, O as buildListTargetDraft, U as buildMediaNameFromLocator, V as buildReviewLinkDraft, W as buildSystemRegistryConfigDetails, Y as classifyNetworkError, Z as countTasksByType, _ as createActiveServiceLifecycle, $ as createClaimedRegistrySlotRuntimeState, a0 as createStorageProviderRegistry, a1 as createUploadTracker, a2 as decodeLogBatch, a3 as decodeLogBatchList, a4 as defaultL3ServiceDetails, a5 as deleteParcel, a6 as deleteParcelSchema, a7 as escapeIlikePattern, ac as fieldDefinitionSchema, ad as flattenLogBatch, ae as flattenLogBatches, af as formatNetworkError, ag as getApi, ah as getApiSchema, ai as getConfig, aj as getConfigSchema, ak as getExtraction, al as getExtractionSchema, am as getParcel, an as getParcelSchema, ap as getScanRemoteRepoValuesSchema, aq as getService, ar as getServiceSchema, as as getTargetSystemRegistry, at as getValueAtPath, av as ideaCreateSchema, aw as ideaLinkValueFilters, ax as ideaUpdateSchema, ay as installChunkFetchRegistry, aB as isIdeaImageLinkName, aC as isLocalFilesystemPath, aD as isLogBatchList, aI as linkDedupFilters, aJ as linkTargetDraftBuildInputSchema, aM as normalizeStringList, aN as parcelDetailsSchema, aO as parseIdeaOriginal, aP as parseLogBatchMeta, aQ as parseProviderPrefixedUrl, aR as parseServiceSlot, aS as parseServiceSlots, aU as patchChangeNodeStatusSchema, aW as patchChangeTaskStatusSchema, aY as patchClaimTaskSchema, aZ as patchExtractionObjects, a_ as patchExtractionObjectsSchema, b0 as patchNodeHeartBeatSchema, b3 as patchStopNodeSchema, b4 as patchTaskProgress, b5 as patchTaskProgressSchema, b6 as postApi, b7 as postApiSchema, b8 as postExtraction, b9 as postExtractionSchema, ba as postLinkCreate, bb as postParcel, bc as postParcelSchema, be as postRegisterNodeSchema, bf as postService, bg as postServiceInstance, bh as postServiceSchema, bi as postSystemRegistryConfig, bj as postSystemRegistryConfigSchema, bk as postTask, bm as postTaskWithRetry, bn as publishParcel, bo as registerProviderChunkResolver, bp as registerService, bq as registerServiceAtStartup, bs as releaseSystemRegistrySlots, bt as releaseSystemRegistrySlotsByServiceId, bu as requestHasBody, bw as resetSystemRegistryConfig, bx as resetSystemRegistryConfigSchema, by as resolveActiveRegistryServiceId, bz as resolveFetchUrl, bA as restoreParcel, bB as restoreParcelById, bC as reviewLinksForNameFilters, bE as sanitizeFileName, bF as sanitizeParcelFileName, bG as scanExtractionList, bH as scanExtractionListSchema, bI as schemaDefinitionSchema, bJ as serviceDetailsSchema, bK as serviceLifecycleSchema, bL as serviceNodeSnapshotSchema, bM as serviceRuntimeSchema, bO as summarizeTaskQueue, bP as systemRegistrySeedSlotSchema, bQ as toPostgrestTextArrayLiteral, bR as unregisterService, bS as unregisterServiceAtShutdown } from './chunks/task-queue-BL-KwAGW.js';
|
|
7
|
+
import { l as loadEnvFiles, b as resolveLogSpoolSpawnEnvForLabel, c as resolveLogSpoolRoot, d as resolveAllLogSpoolProcessRoles, e as logSpoolProcessDir, s as spoolLogger, f as buildLogListDraft, g as postLogBatch, a as logSpoolEnabledFromEnv, h as ensureLogSpoolFromEnv, i as shutdownLogSpoolFromEnv, j as getLogSpoolStats } from './chunks/enable-CF77OsXr.js';
|
|
8
|
+
export { C as CLI_PROD_FLAG, S as SERVICE_ENV_PROFILE_ENV_KEY, k as SERVICE_ENV_PROFILE_PROD, n as buildLogSpoolSpawnEnv, o as envProfileFromProcess, q as resolveDefaultEnvFiles, r as resolveProjectRootByPackageName, t as resolveProjectRootFromModule, v as validateLogSpoolPreloadEnv } from './chunks/enable-CF77OsXr.js';
|
|
7
9
|
import { readFile, unlink, mkdir, writeFile, rename, access, stat, readdir, constants } from 'node:fs/promises';
|
|
8
10
|
import { dirname, resolve, join, isAbsolute } from 'node:path';
|
|
9
|
-
import { bK as sha256Hex, bQ as getErrorMessage, bR as LOG_TOPIC_NODE, bb as postRegisterNode, aR as patchChangeNodeStatus, N as NodeStatus, b0 as patchStopNode, aZ as patchNodeHeartBeat, E as EMPTY_REGISTRY_SLOT_RUNTIME_STATE, bA as runRegistrySlotGuardCheck, bp as registrySlotRuntimePatchFromGuardResult, c as CategoryNode, a7 as evaluateBusyNodeLiveness, a$ as patchServiceRuntime, aD as isLogEntry, W as claimServiceRegistrySlot, p as ServiceRegistryError, aa as fetchWithRetry, aG as isRetryableHttpStatus, a9 as fetchBinaryWithRetry, aF as isOpaqueChunkUrl, e as CategoryRepo, az as isHttpUrl, ay as isFeedValue, bS as isFeedIngestSource, bT as resolveFeedOriginalStorageProvider, a8 as feedLinkDedupFilters, z as buildFeedLinkDraft, b as CategoryLink, bU as buildFeedTagList, i as IDEA_IMAGE_TEMP_DIR, at as guessMediaMime, M as MEDIA_CONTENT_HASH_ALGORITHM, aE as isMediaValue, aJ as mediaLinkDedupFilters, O as buildMediaLinkDraft, R as ResultCode, bV as LOG_TOPIC_TASK, r as TASK_REPO_USAGE, an as getScanRemoteRepoValues, aV as patchClaimTask, bW as CRITICAL_UNKNOWN_TASK_TRACE_ID, aT as patchChangeTaskStatus, t as TaskStatusAction, bX as toError, bj as postTaskSchema, bY as createTaskRow, s as TaskStatus } from './chunks/task-queue-C_nUaM2S.js';
|
|
10
|
-
export { A as ApiMethod, C as CategoryConfig, a as CategoryExtraction, d as CategoryParcel, f as CategoryService, g as CategoryTask, D as DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS, bZ as FEED_INGEST_SOURCES, F as FEED_VALUES, I as IDEA_IMAGE_LINK_NAME, h as IDEA_IMAGE_TAG_RAW, j as IDEA_LINK_VALUE, L as LINK_MANIFEST_VERSION, k as LIST_MANIFEST_VERSION, l as MEDIA_CONTENT_HASH_PREFIX_LENGTH, m as MEDIA_VALUES, P as POST_TASK_DEFAULT_MAX_ATTEMPTS, n as ParcelManager, o as PostLinkValidator, S as ServiceLifecycleStatus, q as ServiceSlotStatus, T as TARGET_SYSTEM_REGISTRY_KEY, u as apiDetailsSchema, v as appendSystemRegistryEmptySlots, w as assertRegistrySlotAvailable, x as assertRegistrySlotOwner, y as buildEmptyServiceSlots, B as buildFeedLinkName, G as buildIdeaImageLinkDraft, H as buildIdeaLinkDraft, J as buildLinkTargetDraft, K as buildListTargetDraft, Q as buildMediaNameFromLocator, U as buildReviewLinkDraft, V as buildSystemRegistryConfigDetails, X as classifyNetworkError, Y as countTasksByType, Z as createActiveServiceLifecycle, _ as createClaimedRegistrySlotRuntimeState, $ as createStorageProviderRegistry, a0 as createUploadTracker, a1 as decodeLogBatch, a2 as decodeLogBatchList, a3 as defaultL3ServiceDetails, a4 as deleteParcel, a5 as deleteParcelSchema, a6 as escapeIlikePattern, ab as fieldDefinitionSchema, ac as flattenLogBatch, ad as flattenLogBatches, ae as formatNetworkError, af as getApi, ag as getApiSchema, ah as getConfig, ai as getConfigSchema, aj as getExtraction, ak as getExtractionSchema, al as getParcel, am as getParcelSchema, ao as getScanRemoteRepoValuesSchema, ap as getService, aq as getServiceSchema, ar as getTargetSystemRegistry, as as getValueAtPath, au as ideaCreateSchema, av as ideaLinkValueFilters, aw as ideaUpdateSchema, ax as installChunkFetchRegistry, aA as isIdeaImageLinkName, aB as isLocalFilesystemPath, aC as isLogBatchList, aH as linkDedupFilters, aI as linkTargetDraftBuildInputSchema, aK as normalizeStringList, aL as parcelDetailsSchema, aM as parseIdeaOriginal, aN as parseLogBatchMeta, aO as parseProviderPrefixedUrl, aP as parseServiceSlot, aQ as parseServiceSlots, aS as patchChangeNodeStatusSchema, aU as patchChangeTaskStatusSchema, aW as patchClaimTaskSchema, aX as patchExtractionObjects, aY as patchExtractionObjectsSchema, a_ as patchNodeHeartBeatSchema, b1 as patchStopNodeSchema, b2 as patchTaskProgress, b3 as patchTaskProgressSchema, b4 as postApi, b5 as postApiSchema, b6 as postExtraction, b7 as postExtractionSchema, b8 as postLinkCreate, b9 as postParcel, ba as postParcelSchema, bc as postRegisterNodeSchema, bd as postService, be as postServiceInstance, bf as postServiceSchema, bg as postSystemRegistryConfig, bh as postSystemRegistryConfigSchema, bi as postTask, bk as postTaskWithRetry, bl as publishParcel, bm as registerProviderChunkResolver, bn as registerService, bo as registerServiceAtStartup, bq as releaseSystemRegistrySlots, br as releaseSystemRegistrySlotsByServiceId, bs as requestHasBody, bt as resetSystemRegistryConfig, bu as resetSystemRegistryConfigSchema, bv as resolveActiveRegistryServiceId, bw as resolveFetchUrl, bx as restoreParcel, by as restoreParcelById, bz as reviewLinksForNameFilters, bB as sanitizeFileName, bC as sanitizeParcelFileName, bD as scanExtractionList, bE as scanExtractionListSchema, bF as schemaDefinitionSchema, bG as serviceDetailsSchema, bH as serviceLifecycleSchema, bI as serviceNodeSnapshotSchema, bJ as serviceRuntimeSchema, bL as summarizeTaskQueue, bM as systemRegistrySeedSlotSchema, bN as toPostgrestTextArrayLiteral, bO as unregisterService, bP as unregisterServiceAtShutdown } from './chunks/task-queue-C_nUaM2S.js';
|
|
11
11
|
import { spawn } from 'node:child_process';
|
|
12
12
|
import { ProxyAgent } from 'undici';
|
|
13
13
|
import { tmpdir } from 'node:os';
|
|
@@ -86,173 +86,6 @@ const getPollCommandList = validateWithSchema(getPollCommandListSchema, "getPoll
|
|
|
86
86
|
return generateResponse.success(dequeuedList);
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
/**
|
|
90
|
-
* Load standard Supabase env vars and initialize the process-wide Supabase holder.
|
|
91
|
-
*
|
|
92
|
-
* Required: `SUPABASE_URL`, `SUPABASE_ANON_KEY`
|
|
93
|
-
* Optional: `SUPABASE_NEED_AUTH_URL`, `SUPABASE_NEED_AUTH_ANON_KEY`
|
|
94
|
-
*/
|
|
95
|
-
async function initSupabaseFromStandardEnv(options = {}) {
|
|
96
|
-
const env = options.env ?? process.env;
|
|
97
|
-
const loadEnv = options.loadEnv ?? true;
|
|
98
|
-
if (loadEnv) {
|
|
99
|
-
if (options.root == null || options.root === "") {
|
|
100
|
-
throw new Error("initSupabaseFromStandardEnv: root is required when loadEnv is true");
|
|
101
|
-
}
|
|
102
|
-
loadEnvFiles(options.root, { env, afterLoad: options.afterLoadEnv });
|
|
103
|
-
}
|
|
104
|
-
await supabase.initialize({
|
|
105
|
-
supabaseUrl: requireEnv("SUPABASE_URL", env),
|
|
106
|
-
supabaseAnonKey: requireEnv("SUPABASE_ANON_KEY", env),
|
|
107
|
-
supabaseNeedAuthUrl: readEnv("SUPABASE_NEED_AUTH_URL", env),
|
|
108
|
-
supabaseNeedAuthAnonKey: readEnv("SUPABASE_NEED_AUTH_ANON_KEY", env),
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Public base URL: `envKey` if set (trailing slash stripped), else `http://localhost:{port}`.
|
|
114
|
-
*/
|
|
115
|
-
function publicBaseUrlFromEnv(port, options) {
|
|
116
|
-
const configured = readEnv(options.envKey, options.env ?? process.env);
|
|
117
|
-
if (configured != null) {
|
|
118
|
-
return configured.replace(/\/$/, "");
|
|
119
|
-
}
|
|
120
|
-
return `http://localhost:${port}`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/** Per-file write queue — serializes read-modify-write for a single JSON path within one process. */
|
|
124
|
-
const writeChains = new Map();
|
|
125
|
-
function withSerializedFileWrites(filePath, operation) {
|
|
126
|
-
const previous = writeChains.get(filePath) ?? Promise.resolve();
|
|
127
|
-
const next = previous.then(operation, operation);
|
|
128
|
-
writeChains.set(filePath, next.then(() => undefined, () => undefined));
|
|
129
|
-
return next;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function mergeWithNested(defaults, current, patch, nestedKeys) {
|
|
133
|
-
const merged = {
|
|
134
|
-
...defaults,
|
|
135
|
-
...current,
|
|
136
|
-
...patch,
|
|
137
|
-
};
|
|
138
|
-
for (const key of nestedKeys) {
|
|
139
|
-
const defaultNested = defaults[key];
|
|
140
|
-
if (defaultNested != null && typeof defaultNested === "object") {
|
|
141
|
-
merged[key] = {
|
|
142
|
-
...defaultNested,
|
|
143
|
-
...current?.[key],
|
|
144
|
-
...patch[key],
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return merged;
|
|
149
|
-
}
|
|
150
|
-
async function atomicWriteJson(filePath, data) {
|
|
151
|
-
await mkdir(dirname(filePath), { recursive: true });
|
|
152
|
-
const content = `${JSON.stringify(data, null, 2)}\n`;
|
|
153
|
-
JSON.parse(content);
|
|
154
|
-
const tempPath = `${filePath}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
155
|
-
try {
|
|
156
|
-
await writeFile(tempPath, content, "utf8");
|
|
157
|
-
await rename(tempPath, filePath);
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
await unlink(tempPath).catch(() => undefined);
|
|
161
|
-
throw error;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
/** JSON file-backed state with optional nested key merge and atomic writes. */
|
|
165
|
-
function createJsonFileStateStore(options) {
|
|
166
|
-
const { filePath, defaultState, nestedKeys = [], updatedAtKey } = options;
|
|
167
|
-
function touchUpdatedAt(state) {
|
|
168
|
-
if (updatedAtKey == null) {
|
|
169
|
-
return state;
|
|
170
|
-
}
|
|
171
|
-
return {
|
|
172
|
-
...state,
|
|
173
|
-
[updatedAtKey]: new Date().toISOString(),
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
async function readFromDisk() {
|
|
177
|
-
try {
|
|
178
|
-
const raw = await readFile(filePath, "utf8");
|
|
179
|
-
const parsed = JSON.parse(raw);
|
|
180
|
-
return mergeWithNested(defaultState, parsed, {}, nestedKeys);
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
if (error.code === "ENOENT") {
|
|
184
|
-
return mergeWithNested(defaultState, {}, {}, nestedKeys);
|
|
185
|
-
}
|
|
186
|
-
if (error instanceof SyntaxError) {
|
|
187
|
-
await unlink(filePath).catch(() => undefined);
|
|
188
|
-
return mergeWithNested(defaultState, {}, {}, nestedKeys);
|
|
189
|
-
}
|
|
190
|
-
throw error;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
read() {
|
|
195
|
-
return readFromDisk();
|
|
196
|
-
},
|
|
197
|
-
write(patch) {
|
|
198
|
-
return withSerializedFileWrites(filePath, async () => {
|
|
199
|
-
const current = await readFromDisk();
|
|
200
|
-
const next = touchUpdatedAt(mergeWithNested(defaultState, current, patch, nestedKeys));
|
|
201
|
-
await atomicWriteJson(filePath, next);
|
|
202
|
-
return next;
|
|
203
|
-
});
|
|
204
|
-
},
|
|
205
|
-
reset() {
|
|
206
|
-
return withSerializedFileWrites(filePath, async () => {
|
|
207
|
-
const next = touchUpdatedAt({ ...defaultState });
|
|
208
|
-
await atomicWriteJson(filePath, next);
|
|
209
|
-
return next;
|
|
210
|
-
});
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/** Copy a Node.js Buffer view to a standalone ArrayBuffer. */
|
|
216
|
-
function nodeBufferToArrayBuffer(nodeBuffer) {
|
|
217
|
-
return nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.byteLength);
|
|
218
|
-
}
|
|
219
|
-
/** Read a local file with basic validation and SHA-256 digest. */
|
|
220
|
-
async function readAndVerifySourceFile(filePath, options = {}) {
|
|
221
|
-
const absolutePath = resolve(filePath);
|
|
222
|
-
const allowEmpty = options.allowEmpty === true;
|
|
223
|
-
try {
|
|
224
|
-
await access(absolutePath);
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
throw new Error(`Source file not found: ${absolutePath}`);
|
|
228
|
-
}
|
|
229
|
-
const fileStat = await stat(absolutePath);
|
|
230
|
-
if (!fileStat.isFile()) {
|
|
231
|
-
throw new Error(`Source path is not a file: ${absolutePath}`);
|
|
232
|
-
}
|
|
233
|
-
if (!allowEmpty && fileStat.size <= 0) {
|
|
234
|
-
throw new Error(`Source file is empty: ${absolutePath}`);
|
|
235
|
-
}
|
|
236
|
-
if (options.maxBytes != null && fileStat.size > options.maxBytes) {
|
|
237
|
-
throw new Error(`Source file exceeds maxBytes (${fileStat.size} > ${options.maxBytes}): ${absolutePath}`);
|
|
238
|
-
}
|
|
239
|
-
const nodeBuffer = await readFile(absolutePath);
|
|
240
|
-
const buffer = nodeBufferToArrayBuffer(nodeBuffer);
|
|
241
|
-
if (buffer.byteLength !== fileStat.size) {
|
|
242
|
-
throw new Error(`Source file size mismatch after read (${buffer.byteLength} !== ${fileStat.size}): ${absolutePath}`);
|
|
243
|
-
}
|
|
244
|
-
const digest = await sha256Hex(buffer);
|
|
245
|
-
if (options.expectedSha256 != null && digest.toLowerCase() !== options.expectedSha256.toLowerCase()) {
|
|
246
|
-
throw new Error(`Source file SHA-256 mismatch (expected ${options.expectedSha256}, got ${digest}): ${absolutePath}`);
|
|
247
|
-
}
|
|
248
|
-
return {
|
|
249
|
-
absolutePath,
|
|
250
|
-
buffer,
|
|
251
|
-
size: buffer.byteLength,
|
|
252
|
-
sha256: digest,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
89
|
const formatTimestamp = (timestamp) => {
|
|
257
90
|
return new Intl.DateTimeFormat("zh-CN", {
|
|
258
91
|
year: "numeric",
|
|
@@ -468,7 +301,12 @@ class BaseNodeRuntime {
|
|
|
468
301
|
}
|
|
469
302
|
logger.debug("開始向 Supabase 註冊節點", { topic: LOG_TOPIC_NODE });
|
|
470
303
|
try {
|
|
471
|
-
const
|
|
304
|
+
const serviceId = requireNodeServiceIdFromEnv();
|
|
305
|
+
const { data, error } = await postRegisterNode({
|
|
306
|
+
serviceId,
|
|
307
|
+
kind: this.getNodeKind(),
|
|
308
|
+
traceId: this.startupTraceId,
|
|
309
|
+
});
|
|
472
310
|
if (data == null || error) {
|
|
473
311
|
throw error ?? new Error("postRegisterNode 失敗");
|
|
474
312
|
}
|
|
@@ -765,6 +603,173 @@ class BaseNodeRuntime {
|
|
|
765
603
|
}
|
|
766
604
|
}
|
|
767
605
|
|
|
606
|
+
/**
|
|
607
|
+
* Load standard Supabase env vars and initialize the process-wide Supabase holder.
|
|
608
|
+
*
|
|
609
|
+
* Required: `SUPABASE_URL`, `SUPABASE_ANON_KEY`
|
|
610
|
+
* Optional: `SUPABASE_NEED_AUTH_URL`, `SUPABASE_NEED_AUTH_ANON_KEY`
|
|
611
|
+
*/
|
|
612
|
+
async function initSupabaseFromStandardEnv(options = {}) {
|
|
613
|
+
const env = options.env ?? process.env;
|
|
614
|
+
const loadEnv = options.loadEnv ?? true;
|
|
615
|
+
if (loadEnv) {
|
|
616
|
+
if (options.root == null || options.root === "") {
|
|
617
|
+
throw new Error("initSupabaseFromStandardEnv: root is required when loadEnv is true");
|
|
618
|
+
}
|
|
619
|
+
loadEnvFiles(options.root, { env, afterLoad: options.afterLoadEnv });
|
|
620
|
+
}
|
|
621
|
+
await supabase.initialize({
|
|
622
|
+
supabaseUrl: requireEnv("SUPABASE_URL", env),
|
|
623
|
+
supabaseAnonKey: requireEnv("SUPABASE_ANON_KEY", env),
|
|
624
|
+
supabaseNeedAuthUrl: readEnv("SUPABASE_NEED_AUTH_URL", env),
|
|
625
|
+
supabaseNeedAuthAnonKey: readEnv("SUPABASE_NEED_AUTH_ANON_KEY", env),
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Public base URL: `envKey` if set (trailing slash stripped), else `http://localhost:{port}`.
|
|
631
|
+
*/
|
|
632
|
+
function publicBaseUrlFromEnv(port, options) {
|
|
633
|
+
const configured = readEnv(options.envKey, options.env ?? process.env);
|
|
634
|
+
if (configured != null) {
|
|
635
|
+
return configured.replace(/\/$/, "");
|
|
636
|
+
}
|
|
637
|
+
return `http://localhost:${port}`;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/** Per-file write queue — serializes read-modify-write for a single JSON path within one process. */
|
|
641
|
+
const writeChains = new Map();
|
|
642
|
+
function withSerializedFileWrites(filePath, operation) {
|
|
643
|
+
const previous = writeChains.get(filePath) ?? Promise.resolve();
|
|
644
|
+
const next = previous.then(operation, operation);
|
|
645
|
+
writeChains.set(filePath, next.then(() => undefined, () => undefined));
|
|
646
|
+
return next;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function mergeWithNested(defaults, current, patch, nestedKeys) {
|
|
650
|
+
const merged = {
|
|
651
|
+
...defaults,
|
|
652
|
+
...current,
|
|
653
|
+
...patch,
|
|
654
|
+
};
|
|
655
|
+
for (const key of nestedKeys) {
|
|
656
|
+
const defaultNested = defaults[key];
|
|
657
|
+
if (defaultNested != null && typeof defaultNested === "object") {
|
|
658
|
+
merged[key] = {
|
|
659
|
+
...defaultNested,
|
|
660
|
+
...current?.[key],
|
|
661
|
+
...patch[key],
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return merged;
|
|
666
|
+
}
|
|
667
|
+
async function atomicWriteJson(filePath, data) {
|
|
668
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
669
|
+
const content = `${JSON.stringify(data, null, 2)}\n`;
|
|
670
|
+
JSON.parse(content);
|
|
671
|
+
const tempPath = `${filePath}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
672
|
+
try {
|
|
673
|
+
await writeFile(tempPath, content, "utf8");
|
|
674
|
+
await rename(tempPath, filePath);
|
|
675
|
+
}
|
|
676
|
+
catch (error) {
|
|
677
|
+
await unlink(tempPath).catch(() => undefined);
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
/** JSON file-backed state with optional nested key merge and atomic writes. */
|
|
682
|
+
function createJsonFileStateStore(options) {
|
|
683
|
+
const { filePath, defaultState, nestedKeys = [], updatedAtKey } = options;
|
|
684
|
+
function touchUpdatedAt(state) {
|
|
685
|
+
if (updatedAtKey == null) {
|
|
686
|
+
return state;
|
|
687
|
+
}
|
|
688
|
+
return {
|
|
689
|
+
...state,
|
|
690
|
+
[updatedAtKey]: new Date().toISOString(),
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
async function readFromDisk() {
|
|
694
|
+
try {
|
|
695
|
+
const raw = await readFile(filePath, "utf8");
|
|
696
|
+
const parsed = JSON.parse(raw);
|
|
697
|
+
return mergeWithNested(defaultState, parsed, {}, nestedKeys);
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
if (error.code === "ENOENT") {
|
|
701
|
+
return mergeWithNested(defaultState, {}, {}, nestedKeys);
|
|
702
|
+
}
|
|
703
|
+
if (error instanceof SyntaxError) {
|
|
704
|
+
await unlink(filePath).catch(() => undefined);
|
|
705
|
+
return mergeWithNested(defaultState, {}, {}, nestedKeys);
|
|
706
|
+
}
|
|
707
|
+
throw error;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return {
|
|
711
|
+
read() {
|
|
712
|
+
return readFromDisk();
|
|
713
|
+
},
|
|
714
|
+
write(patch) {
|
|
715
|
+
return withSerializedFileWrites(filePath, async () => {
|
|
716
|
+
const current = await readFromDisk();
|
|
717
|
+
const next = touchUpdatedAt(mergeWithNested(defaultState, current, patch, nestedKeys));
|
|
718
|
+
await atomicWriteJson(filePath, next);
|
|
719
|
+
return next;
|
|
720
|
+
});
|
|
721
|
+
},
|
|
722
|
+
reset() {
|
|
723
|
+
return withSerializedFileWrites(filePath, async () => {
|
|
724
|
+
const next = touchUpdatedAt({ ...defaultState });
|
|
725
|
+
await atomicWriteJson(filePath, next);
|
|
726
|
+
return next;
|
|
727
|
+
});
|
|
728
|
+
},
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/** Copy a Node.js Buffer view to a standalone ArrayBuffer. */
|
|
733
|
+
function nodeBufferToArrayBuffer(nodeBuffer) {
|
|
734
|
+
return nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.byteLength);
|
|
735
|
+
}
|
|
736
|
+
/** Read a local file with basic validation and SHA-256 digest. */
|
|
737
|
+
async function readAndVerifySourceFile(filePath, options = {}) {
|
|
738
|
+
const absolutePath = resolve(filePath);
|
|
739
|
+
const allowEmpty = options.allowEmpty === true;
|
|
740
|
+
try {
|
|
741
|
+
await access(absolutePath);
|
|
742
|
+
}
|
|
743
|
+
catch {
|
|
744
|
+
throw new Error(`Source file not found: ${absolutePath}`);
|
|
745
|
+
}
|
|
746
|
+
const fileStat = await stat(absolutePath);
|
|
747
|
+
if (!fileStat.isFile()) {
|
|
748
|
+
throw new Error(`Source path is not a file: ${absolutePath}`);
|
|
749
|
+
}
|
|
750
|
+
if (!allowEmpty && fileStat.size <= 0) {
|
|
751
|
+
throw new Error(`Source file is empty: ${absolutePath}`);
|
|
752
|
+
}
|
|
753
|
+
if (options.maxBytes != null && fileStat.size > options.maxBytes) {
|
|
754
|
+
throw new Error(`Source file exceeds maxBytes (${fileStat.size} > ${options.maxBytes}): ${absolutePath}`);
|
|
755
|
+
}
|
|
756
|
+
const nodeBuffer = await readFile(absolutePath);
|
|
757
|
+
const buffer = nodeBufferToArrayBuffer(nodeBuffer);
|
|
758
|
+
if (buffer.byteLength !== fileStat.size) {
|
|
759
|
+
throw new Error(`Source file size mismatch after read (${buffer.byteLength} !== ${fileStat.size}): ${absolutePath}`);
|
|
760
|
+
}
|
|
761
|
+
const digest = await sha256Hex(buffer);
|
|
762
|
+
if (options.expectedSha256 != null && digest.toLowerCase() !== options.expectedSha256.toLowerCase()) {
|
|
763
|
+
throw new Error(`Source file SHA-256 mismatch (expected ${options.expectedSha256}, got ${digest}): ${absolutePath}`);
|
|
764
|
+
}
|
|
765
|
+
return {
|
|
766
|
+
absolutePath,
|
|
767
|
+
buffer,
|
|
768
|
+
size: buffer.byteLength,
|
|
769
|
+
sha256: digest,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
768
773
|
/**
|
|
769
774
|
* Build argv for `node --import … --import tsx <entry>`.
|
|
770
775
|
* Use **relative** preload paths with `cwd: projectRoot` — Node 24 on Windows rejects
|
|
@@ -1607,11 +1612,14 @@ async function runServiceGuardTick(input) {
|
|
|
1607
1612
|
}
|
|
1608
1613
|
decision = "slot_ok";
|
|
1609
1614
|
}
|
|
1610
|
-
const
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
+
const nodes = serviceId == null
|
|
1616
|
+
? []
|
|
1617
|
+
: ((await scanTargetList({
|
|
1618
|
+
category: CategoryNode.NODE,
|
|
1619
|
+
filterList: [{ field: "name", operator: "eq", value: serviceId }],
|
|
1620
|
+
maxRows: maxNodes,
|
|
1621
|
+
})).data ?? []);
|
|
1622
|
+
const liveness = evaluateBusyNodeLiveness(nodesForTaskLiveness(nodes), {
|
|
1615
1623
|
staleMs: taskNodeStaleMs,
|
|
1616
1624
|
now: nowMs,
|
|
1617
1625
|
excludeNodeId: nodeId,
|
|
@@ -1728,6 +1736,7 @@ function registerServiceGuardRunner(options) {
|
|
|
1728
1736
|
}
|
|
1729
1737
|
|
|
1730
1738
|
const UPLOAD_LANE = "slow";
|
|
1739
|
+
const MAX_UPLOADS_PER_COLLECT_TICK = 20;
|
|
1731
1740
|
/** Per serviceId — guard collect-log tick runs GC at most once per `gc.intervalMs`. */
|
|
1732
1741
|
const lastGcAtMsByServiceId = new Map();
|
|
1733
1742
|
async function pathExists$1(filePath) {
|
|
@@ -1759,6 +1768,9 @@ async function readBatchTmpFile(tmpPath) {
|
|
|
1759
1768
|
function processMetaKey(serviceId, processRole) {
|
|
1760
1769
|
return `${serviceId}:${processRole}`;
|
|
1761
1770
|
}
|
|
1771
|
+
function syncedMarkerPath(jsonPath) {
|
|
1772
|
+
return jsonPath.replace(/\.json$/, ".synced");
|
|
1773
|
+
}
|
|
1762
1774
|
async function uploadTmpBatch(input) {
|
|
1763
1775
|
const parsed = parseLogSpoolBatchFilename(input.fileName);
|
|
1764
1776
|
if (parsed == null) {
|
|
@@ -1767,6 +1779,7 @@ async function uploadTmpBatch(input) {
|
|
|
1767
1779
|
}
|
|
1768
1780
|
const jsonFileName = input.fileName.replace(/\.tmp$/, ".json");
|
|
1769
1781
|
const jsonPath = join(logSpoolProcessDir(input.spoolRoot, input.serviceId, input.processRole), jsonFileName);
|
|
1782
|
+
const syncedPath = syncedMarkerPath(jsonPath);
|
|
1770
1783
|
if (await pathExists$1(jsonPath)) {
|
|
1771
1784
|
try {
|
|
1772
1785
|
await unlink(input.tmpPath);
|
|
@@ -1780,6 +1793,20 @@ async function uploadTmpBatch(input) {
|
|
|
1780
1793
|
}
|
|
1781
1794
|
return "skipped";
|
|
1782
1795
|
}
|
|
1796
|
+
if (await pathExists$1(syncedPath)) {
|
|
1797
|
+
try {
|
|
1798
|
+
await rename(input.tmpPath, jsonPath);
|
|
1799
|
+
}
|
|
1800
|
+
catch {
|
|
1801
|
+
try {
|
|
1802
|
+
await unlink(input.tmpPath);
|
|
1803
|
+
}
|
|
1804
|
+
catch {
|
|
1805
|
+
// best-effort
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
return "skipped";
|
|
1809
|
+
}
|
|
1783
1810
|
const batch = await readBatchTmpFile(input.tmpPath);
|
|
1784
1811
|
if (batch == null) {
|
|
1785
1812
|
spoolLogger.warn("collect-log skipped — tmp failed validation", {
|
|
@@ -1796,18 +1823,10 @@ async function uploadTmpBatch(input) {
|
|
|
1796
1823
|
return "failed";
|
|
1797
1824
|
}
|
|
1798
1825
|
const processKey = processMetaKey(input.serviceId, input.processRole);
|
|
1799
|
-
// TODO: `lane` is legacy transport metadata — scheduled for removal; fixed to "slow" for downstream decode compatibility.
|
|
1800
|
-
const idempotencyKey = computeLogBatchIdempotencyKey({
|
|
1801
|
-
service: input.serviceValue,
|
|
1802
|
-
process: processKey,
|
|
1803
|
-
lane: UPLOAD_LANE,
|
|
1804
|
-
entries: batch.entries,
|
|
1805
|
-
});
|
|
1806
1826
|
const draft = buildLogListDraft({
|
|
1807
1827
|
service: input.serviceValue,
|
|
1808
1828
|
process: processKey,
|
|
1809
1829
|
lane: UPLOAD_LANE,
|
|
1810
|
-
idempotencyKey,
|
|
1811
1830
|
entries: batch.entries,
|
|
1812
1831
|
});
|
|
1813
1832
|
try {
|
|
@@ -1822,8 +1841,21 @@ async function uploadTmpBatch(input) {
|
|
|
1822
1841
|
});
|
|
1823
1842
|
return "failed";
|
|
1824
1843
|
}
|
|
1844
|
+
try {
|
|
1845
|
+
await writeFile(syncedPath, `${Date.now()}\n`, "utf8");
|
|
1846
|
+
}
|
|
1847
|
+
catch (error) {
|
|
1848
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1849
|
+
spoolLogger.warn("collect-log synced marker write failed", { syncedPath, error: message });
|
|
1850
|
+
}
|
|
1825
1851
|
try {
|
|
1826
1852
|
await rename(input.tmpPath, jsonPath);
|
|
1853
|
+
try {
|
|
1854
|
+
await unlink(syncedPath);
|
|
1855
|
+
}
|
|
1856
|
+
catch {
|
|
1857
|
+
// best-effort
|
|
1858
|
+
}
|
|
1827
1859
|
}
|
|
1828
1860
|
catch (error) {
|
|
1829
1861
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1832,13 +1864,12 @@ async function uploadTmpBatch(input) {
|
|
|
1832
1864
|
jsonPath,
|
|
1833
1865
|
error: message,
|
|
1834
1866
|
});
|
|
1835
|
-
return "
|
|
1867
|
+
return "uploaded";
|
|
1836
1868
|
}
|
|
1837
1869
|
spoolLogger.info("collect-log uploaded batch", {
|
|
1838
1870
|
processRole: input.processRole,
|
|
1839
1871
|
fileName: jsonFileName,
|
|
1840
1872
|
entryCount: batch.entries.length,
|
|
1841
|
-
idempotencyKey,
|
|
1842
1873
|
});
|
|
1843
1874
|
return "uploaded";
|
|
1844
1875
|
}
|
|
@@ -1888,21 +1919,21 @@ async function gcSyncedJsonFiles(input) {
|
|
|
1888
1919
|
continue;
|
|
1889
1920
|
}
|
|
1890
1921
|
for (const name of names) {
|
|
1891
|
-
if (!name.endsWith(".json")) {
|
|
1922
|
+
if (!name.endsWith(".json") && !name.endsWith(".synced")) {
|
|
1892
1923
|
continue;
|
|
1893
1924
|
}
|
|
1894
|
-
if (parseLogSpoolBatchFilename(name) == null) {
|
|
1925
|
+
if (parseLogSpoolBatchFilename(name) == null && !name.endsWith(".synced")) {
|
|
1895
1926
|
continue;
|
|
1896
1927
|
}
|
|
1897
|
-
const
|
|
1928
|
+
const filePath = join(processDir, name);
|
|
1898
1929
|
try {
|
|
1899
|
-
const fileStat = await stat(
|
|
1930
|
+
const fileStat = await stat(filePath);
|
|
1900
1931
|
if (input.nowMs - fileStat.mtimeMs <= input.syncedRetentionMs) {
|
|
1901
1932
|
continue;
|
|
1902
1933
|
}
|
|
1903
|
-
await unlink(
|
|
1934
|
+
await unlink(filePath);
|
|
1904
1935
|
removed += 1;
|
|
1905
|
-
spoolLogger.info("collect-log gc removed synced
|
|
1936
|
+
spoolLogger.info("collect-log gc removed synced file", {
|
|
1906
1937
|
fileName: name,
|
|
1907
1938
|
processRole,
|
|
1908
1939
|
});
|
|
@@ -1924,7 +1955,7 @@ function shouldRunGc(serviceId, nowMs, intervalMs) {
|
|
|
1924
1955
|
}
|
|
1925
1956
|
/**
|
|
1926
1957
|
* Guard-only: upload pending `.tmp` batches, rename to `.json`, then periodic GC.
|
|
1927
|
-
*
|
|
1958
|
+
* Post success is tracked via `.json` or `.synced` marker (prevents duplicate DB inserts).
|
|
1928
1959
|
*/
|
|
1929
1960
|
async function runCollectLogTick(input) {
|
|
1930
1961
|
const config = resolveLogSpoolConfig(input.config);
|
|
@@ -1937,6 +1968,7 @@ async function runCollectLogTick(input) {
|
|
|
1937
1968
|
gcTmpRemoved: 0,
|
|
1938
1969
|
gcSyncedRemoved: 0,
|
|
1939
1970
|
};
|
|
1971
|
+
let uploadsThisTick = 0;
|
|
1940
1972
|
for (const processRole of resolveAllLogSpoolProcessRoles()) {
|
|
1941
1973
|
const processDir = logSpoolProcessDir(spoolRoot, input.serviceId, processRole);
|
|
1942
1974
|
let names = [];
|
|
@@ -1950,6 +1982,9 @@ async function runCollectLogTick(input) {
|
|
|
1950
1982
|
if (!name.endsWith(".tmp")) {
|
|
1951
1983
|
continue;
|
|
1952
1984
|
}
|
|
1985
|
+
if (uploadsThisTick >= MAX_UPLOADS_PER_COLLECT_TICK) {
|
|
1986
|
+
break;
|
|
1987
|
+
}
|
|
1953
1988
|
const status = await uploadTmpBatch({
|
|
1954
1989
|
serviceId: input.serviceId,
|
|
1955
1990
|
serviceValue: input.serviceValue,
|
|
@@ -1961,6 +1996,7 @@ async function runCollectLogTick(input) {
|
|
|
1961
1996
|
});
|
|
1962
1997
|
if (status === "uploaded") {
|
|
1963
1998
|
result.uploaded += 1;
|
|
1999
|
+
uploadsThisTick += 1;
|
|
1964
2000
|
}
|
|
1965
2001
|
else if (status === "skipped") {
|
|
1966
2002
|
result.skipped += 1;
|
|
@@ -2056,6 +2092,9 @@ class TriggerNode extends BaseNodeRuntime {
|
|
|
2056
2092
|
}
|
|
2057
2093
|
this.loopIntervalMs = loopIntervalMs;
|
|
2058
2094
|
}
|
|
2095
|
+
getNodeKind() {
|
|
2096
|
+
return NodeKind.TRIGGER;
|
|
2097
|
+
}
|
|
2059
2098
|
getLoopIntervalMs() {
|
|
2060
2099
|
return this.loopIntervalMs;
|
|
2061
2100
|
}
|
|
@@ -2131,6 +2170,9 @@ class ServiceGuardNode extends TriggerNode {
|
|
|
2131
2170
|
this.options = options;
|
|
2132
2171
|
this.businessReadyTimeoutMs = options.businessReadyTimeoutMs ?? DEFAULT_BUSINESS_READY_TIMEOUT_MS;
|
|
2133
2172
|
}
|
|
2173
|
+
getNodeKind() {
|
|
2174
|
+
return NodeKind.GUARD;
|
|
2175
|
+
}
|
|
2134
2176
|
/** Register the guard runner and return a ready-to-start node. */
|
|
2135
2177
|
static create(options) {
|
|
2136
2178
|
registerServiceGuardRunner({
|
|
@@ -2541,9 +2583,9 @@ function createServiceHost(options) {
|
|
|
2541
2583
|
if (options.onRegistryClaimed != null) {
|
|
2542
2584
|
await options.onRegistryClaimed(hostCtx);
|
|
2543
2585
|
}
|
|
2586
|
+
process.env[LOG_SPOOL_SERVICE_ID_ENV] = session.service.id;
|
|
2544
2587
|
const enableSpool = options.enableLogSpoolAfterClaim ?? true;
|
|
2545
2588
|
if (enableSpool && logSpoolEnabledFromEnv()) {
|
|
2546
|
-
process.env[LOG_SPOOL_SERVICE_ID_ENV] = session.service.id;
|
|
2547
2589
|
await ensureLogSpoolFromEnv({
|
|
2548
2590
|
serviceId: session.service.id,
|
|
2549
2591
|
serviceValue: options.serviceValue,
|
|
@@ -2601,6 +2643,7 @@ async function runSingleProcessService(options) {
|
|
|
2601
2643
|
logger,
|
|
2602
2644
|
logTopic,
|
|
2603
2645
|
});
|
|
2646
|
+
process.env[LOG_SPOOL_SERVICE_ID_ENV] = session.service.id;
|
|
2604
2647
|
try {
|
|
2605
2648
|
await options.run({ service: session.service, session });
|
|
2606
2649
|
}
|
|
@@ -4580,6 +4623,9 @@ class TaskNode extends BaseNodeRuntime {
|
|
|
4580
4623
|
constructor() {
|
|
4581
4624
|
super("taskNode");
|
|
4582
4625
|
}
|
|
4626
|
+
getNodeKind() {
|
|
4627
|
+
return NodeKind.TASK;
|
|
4628
|
+
}
|
|
4583
4629
|
async onBeforeRegisterNode(logger) {
|
|
4584
4630
|
const { availableTaskList, includeRemote } = await TaskManager.registerTasks({ logger });
|
|
4585
4631
|
this._availableTaskList = availableTaskList;
|
|
@@ -5034,5 +5080,5 @@ function buildFireKey(trigger, now = new Date()) {
|
|
|
5034
5080
|
return buildDailyFireKey(schedule, now);
|
|
5035
5081
|
}
|
|
5036
5082
|
|
|
5037
|
-
export { BaseNodeRuntime, COLLECT_LOG_RUNNER_KEY, CategoryCommand, CategoryLink, CategoryNode, CategoryRepo, CategoryTrigger, CommandType, EMPTY_REGISTRY_SLOT_RUNTIME_STATE, IDEA_IMAGE_TEMP_DIR, IDEA_TEMP_DOWNLOAD_PATH_SUFFIX, LOG_SPOOL_SERVICE_ID_ENV, LOG_TOPIC_TRIGGER, LogLevel, MAX_POLL_TARGET_LIST_SIZE, MEDIA_CONTENT_HASH_ALGORITHM, ManagedChildProcesses, NodeStatus, PROVIDER_TELEGRAM, RepoManager, ResultCode, SERVICE_GUARD_RUNNER_KEY, ServiceGuardNode, ServiceRegistryError, TASK_LOCAL_PACKAGE_CONFIG_FILENAME, TASK_REPO_SCRIPT_CATEGORY, TASK_REPO_USAGE, TASK_RUNNER_CONFIG_DIR, TASK_RUNNER_ROOT_CONFIG_FILENAME, TASK_RUNNER_ROOT_CONFIG_LEGACY_RELATIVE_PATH, TASK_RUNNER_ROOT_CONFIG_RELATIVE_PATH, TRIGGER_LOOP_INTERVAL_MS, TRIGGER_RUNNER_DEFAULT_RETRY_COUNT, TRIGGER_RUNNER_DEFAULT_RETRY_DELAY_MS, TaskManager, TaskNode, TaskRepoValidation, TaskStatus, TaskStatusAction, TriggerManager, TriggerNode, TriggerStatus, applyRegistrySlotGuardStep, buildDailyFireKey, buildFeedLinkDraft, buildFireKey, buildIdeaPasteRelativePath, buildIdeaTempDownloadLocator, buildMediaLinkDraft, buildNodeImportArgs, callTelegramApi, checkFeedLocalAvailability, checkFeedOssAvailability, checkMediaAvailability, claimServiceRegistrySlot, createFeed, createJsonFileStateStore, createL3ChildLauncher, createLogSpoolCoordinator, createLogger, createManagedChildProcesses, createPathsExistCheck, createRequiredEnvCheck, createServiceHost, createServiceRuntimeStateStore, createSupabaseReachableCheck, createTarget, createTelegramStorageProvider, downloadTelegramChunk, enableLogSpoolFromEnvInChild, encodeTelegramChunkUrl, ensureLogSpoolFromEnv, evaluateBusyNodeLiveness, feedLinkDedupFilters, fetchBinaryWithRetry, fetchWithRetry, findMediaLink, generateResponse, getConfigFileDir, getLogSpoolStats, getMainLogSpoolWriterStats, getPollCommandList, getPollCommandListSchema, getPossibleTarget, getScanRemoteRepoValues, getTarget, guardRetryAfterSec, guessMediaMime, hashIdeaPasteImage, importJsConfigModule, initSupabaseFromStandardEnv, isChildProcessRunning, isCreateTargetAlreadyExistsError, isDailyScheduleDue, isFeedIngestSource, isFeedValue, isGuardAvailable, isHttpUrl, isLogEntry, isLogSpoolEnabled, isMediaValue, isOpaqueChunkUrl, isOptimisticLockResponse, isRetryableHttpStatus, isTriggerDue, loadCachedJsConfigModule, loadEnvFiles, logManager, logSpoolEnabledFromEnv, markWorkerSpawned, mediaLinkDedupFilters, nodeBufferToArrayBuffer, parseIdeaTempDownloadLocator, parseTelegramChunkUrl, patchChangeNodeStatus, patchChangeTaskStatus, patchClaimTask, patchNodeHeartBeat, patchServiceRuntime, patchStopNode, patchTriggerFired, patchTriggerFiredSchema, pathExists, pollTargetList, pollUntil, postCommand, postCommandSchema, postRegisterNode, postTarget, postTaskSchema, postTaskWithValidation, postTrigger, postTriggerSchema, probeMediaOriginal, publicBaseUrlFromEnv, readAndVerifySourceFile, readEnv, registerCollectLogRunner, registerFeed, registerMediaLink, registerServiceGuardRunner, registrySlotRuntimePatchFromGuardResult, requireEnv, resolveFirstExistingPath, resolveLogSpoolRoot, resolvePathFromBaseDir, resolvePathFromConfigFile, resolvePathFromCwd, resolveTelegramStorageOptions, runCollectLogTick, runReadinessChecks, runReadinessGate, runRegistrySlotGuardCheck, runServiceGuardTick, runSingleProcessService, scanEnabledTriggers, scanEnabledTriggersSchema, scanTargetList, sha256Hex, shutdownLogSpool, shutdownLogSpoolFromEnv, spawnTsxChild, supabase, telegramDownloadBinary, telegramFileDownloadUrl, toFileImportHref, updateTarget, updateTargetDetails, validateTaskRepoAndParams, validateWithSchema, waitForServiceReady };
|
|
5083
|
+
export { BaseNodeRuntime, COLLECT_LOG_RUNNER_KEY, CategoryCommand, CategoryLink, CategoryNode, CategoryRepo, CategoryTrigger, CommandType, EMPTY_REGISTRY_SLOT_RUNTIME_STATE, IDEA_IMAGE_TEMP_DIR, IDEA_TEMP_DOWNLOAD_PATH_SUFFIX, LOG_SPOOL_SERVICE_ID_ENV, LOG_TOPIC_TRIGGER, LogLevel, MAX_POLL_TARGET_LIST_SIZE, MEDIA_CONTENT_HASH_ALGORITHM, ManagedChildProcesses, NodeKind, NodeStatus, PROVIDER_TELEGRAM, RepoManager, ResultCode, SERVICE_GUARD_RUNNER_KEY, ServiceGuardNode, ServiceRegistryError, TASK_LOCAL_PACKAGE_CONFIG_FILENAME, TASK_REPO_SCRIPT_CATEGORY, TASK_REPO_USAGE, TASK_RUNNER_CONFIG_DIR, TASK_RUNNER_ROOT_CONFIG_FILENAME, TASK_RUNNER_ROOT_CONFIG_LEGACY_RELATIVE_PATH, TASK_RUNNER_ROOT_CONFIG_RELATIVE_PATH, TRIGGER_LOOP_INTERVAL_MS, TRIGGER_RUNNER_DEFAULT_RETRY_COUNT, TRIGGER_RUNNER_DEFAULT_RETRY_DELAY_MS, TaskManager, TaskNode, TaskRepoValidation, TaskStatus, TaskStatusAction, TriggerManager, TriggerNode, TriggerStatus, applyRegistrySlotGuardStep, buildDailyFireKey, buildFeedLinkDraft, buildFireKey, buildIdeaPasteRelativePath, buildIdeaTempDownloadLocator, buildMediaLinkDraft, buildNodeImportArgs, callTelegramApi, checkFeedLocalAvailability, checkFeedOssAvailability, checkMediaAvailability, claimServiceRegistrySlot, createFeed, createJsonFileStateStore, createL3ChildLauncher, createLogSpoolCoordinator, createLogger, createManagedChildProcesses, createPathsExistCheck, createRequiredEnvCheck, createServiceHost, createServiceRuntimeStateStore, createSupabaseReachableCheck, createTarget, createTelegramStorageProvider, downloadTelegramChunk, enableLogSpoolFromEnvInChild, encodeTelegramChunkUrl, ensureLogSpoolFromEnv, evaluateBusyNodeLiveness, feedLinkDedupFilters, fetchBinaryWithRetry, fetchWithRetry, findMediaLink, generateResponse, getConfigFileDir, getLogSpoolStats, getMainLogSpoolWriterStats, getPollCommandList, getPollCommandListSchema, getPossibleTarget, getScanRemoteRepoValues, getTarget, guardRetryAfterSec, guessMediaMime, hashIdeaPasteImage, importJsConfigModule, initSupabaseFromStandardEnv, isChildProcessRunning, isCreateTargetAlreadyExistsError, isDailyScheduleDue, isFeedIngestSource, isFeedValue, isGuardAvailable, isHttpUrl, isLogEntry, isLogSpoolEnabled, isMediaValue, isOpaqueChunkUrl, isOptimisticLockResponse, isRetryableHttpStatus, isTriggerDue, loadCachedJsConfigModule, loadEnvFiles, logManager, logSpoolEnabledFromEnv, markWorkerSpawned, mediaLinkDedupFilters, nodeBufferToArrayBuffer, nodesForTaskLiveness, parseIdeaTempDownloadLocator, parseTelegramChunkUrl, patchChangeNodeStatus, patchChangeTaskStatus, patchClaimTask, patchNodeHeartBeat, patchServiceRuntime, patchStopNode, patchTriggerFired, patchTriggerFiredSchema, pathExists, pollTargetList, pollUntil, postCommand, postCommandSchema, postRegisterNode, postTarget, postTaskSchema, postTaskWithValidation, postTrigger, postTriggerSchema, probeMediaOriginal, publicBaseUrlFromEnv, readAndVerifySourceFile, readEnv, registerCollectLogRunner, registerFeed, registerMediaLink, registerServiceGuardRunner, registrySlotRuntimePatchFromGuardResult, requireEnv, requireNodeServiceIdFromEnv, resolveFirstExistingPath, resolveLogSpoolRoot, resolvePathFromBaseDir, resolvePathFromConfigFile, resolvePathFromCwd, resolveTelegramStorageOptions, runCollectLogTick, runReadinessChecks, runReadinessGate, runRegistrySlotGuardCheck, runServiceGuardTick, runSingleProcessService, scanEnabledTriggers, scanEnabledTriggersSchema, scanTargetList, sha256Hex, shutdownLogSpool, shutdownLogSpoolFromEnv, spawnTsxChild, supabase, telegramDownloadBinary, telegramFileDownloadUrl, toFileImportHref, updateTarget, updateTargetDetails, validateTaskRepoAndParams, validateWithSchema, waitForServiceReady };
|
|
5038
5084
|
//# sourceMappingURL=node.js.map
|