@microsoft/opentelemetry 1.3.0 → 1.4.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/README.md +130 -37
- package/dist/commonjs/a365/configuration/A365Configuration.d.ts +3 -0
- package/dist/commonjs/a365/configuration/A365Configuration.d.ts.map +1 -1
- package/dist/commonjs/a365/configuration/A365Configuration.js +5 -1
- package/dist/commonjs/a365/configuration/A365Configuration.js.map +1 -1
- package/dist/commonjs/a365/configuration/A365ConfigurationOptions.d.ts +3 -0
- package/dist/commonjs/a365/configuration/A365ConfigurationOptions.d.ts.map +1 -1
- package/dist/commonjs/a365/constants.d.ts +1 -1
- package/dist/commonjs/a365/exporter/Agent365Exporter.d.ts +29 -3
- package/dist/commonjs/a365/exporter/Agent365Exporter.d.ts.map +1 -1
- package/dist/commonjs/a365/exporter/Agent365Exporter.js +327 -73
- package/dist/commonjs/a365/exporter/Agent365Exporter.js.map +1 -1
- package/dist/commonjs/a365/exporter/Agent365ExporterOptions.d.ts +5 -0
- package/dist/commonjs/a365/exporter/Agent365ExporterOptions.d.ts.map +1 -1
- package/dist/commonjs/a365/exporter/Agent365ExporterOptions.js +3 -0
- package/dist/commonjs/a365/exporter/Agent365ExporterOptions.js.map +1 -1
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryManager.d.ts +70 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryManager.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryManager.js +346 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryManager.js.map +1 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryOptions.d.ts +31 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryOptions.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryOptions.js +48 -0
- package/dist/commonjs/a365/exporter/durable/DurableDeliveryOptions.js.map +1 -0
- package/dist/commonjs/a365/exporter/durable/DurableRecord.d.ts +20 -0
- package/dist/commonjs/a365/exporter/durable/DurableRecord.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/DurableRecord.js +98 -0
- package/dist/commonjs/a365/exporter/durable/DurableRecord.js.map +1 -0
- package/dist/commonjs/a365/exporter/durable/PersistentStore.d.ts +48 -0
- package/dist/commonjs/a365/exporter/durable/PersistentStore.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/PersistentStore.js +637 -0
- package/dist/commonjs/a365/exporter/durable/PersistentStore.js.map +1 -0
- package/dist/commonjs/a365/exporter/durable/TransmissionGate.d.ts +24 -0
- package/dist/commonjs/a365/exporter/durable/TransmissionGate.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/TransmissionGate.js +85 -0
- package/dist/commonjs/a365/exporter/durable/TransmissionGate.js.map +1 -0
- package/dist/commonjs/a365/exporter/durable/WindowsFileAccessControl.d.ts +35 -0
- package/dist/commonjs/a365/exporter/durable/WindowsFileAccessControl.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/WindowsFileAccessControl.js +169 -0
- package/dist/commonjs/a365/exporter/durable/WindowsFileAccessControl.js.map +1 -0
- package/dist/commonjs/a365/exporter/durable/index.d.ts +12 -0
- package/dist/commonjs/a365/exporter/durable/index.d.ts.map +1 -0
- package/dist/commonjs/a365/exporter/durable/index.js +27 -0
- package/dist/commonjs/a365/exporter/durable/index.js.map +1 -0
- package/dist/commonjs/a365/exporter/index.d.ts +1 -1
- package/dist/commonjs/a365/exporter/index.d.ts.map +1 -1
- package/dist/commonjs/a365/exporter/index.js.map +1 -1
- package/dist/commonjs/a365/index.d.ts +1 -1
- package/dist/commonjs/a365/index.d.ts.map +1 -1
- package/dist/commonjs/a365/index.js.map +1 -1
- package/dist/commonjs/azureMonitor/index.d.ts.map +1 -1
- package/dist/commonjs/azureMonitor/index.js +4 -10
- package/dist/commonjs/azureMonitor/index.js.map +1 -1
- package/dist/commonjs/azureMonitor/logs/handler.d.ts +0 -7
- package/dist/commonjs/azureMonitor/logs/handler.d.ts.map +1 -1
- package/dist/commonjs/azureMonitor/logs/handler.js +0 -27
- package/dist/commonjs/azureMonitor/logs/handler.js.map +1 -1
- package/dist/commonjs/azureMonitor/metrics/performanceCounters.d.ts +3 -0
- package/dist/commonjs/azureMonitor/metrics/performanceCounters.d.ts.map +1 -1
- package/dist/commonjs/azureMonitor/metrics/performanceCounters.js +21 -12
- package/dist/commonjs/azureMonitor/metrics/performanceCounters.js.map +1 -1
- package/dist/commonjs/azureMonitor/traces/handler.d.ts +2 -9
- package/dist/commonjs/azureMonitor/traces/handler.d.ts.map +1 -1
- package/dist/commonjs/azureMonitor/traces/handler.js +2 -54
- package/dist/commonjs/azureMonitor/traces/handler.js.map +1 -1
- package/dist/commonjs/azureMonitor/utils/common.d.ts +29 -0
- package/dist/commonjs/azureMonitor/utils/common.d.ts.map +1 -1
- package/dist/commonjs/azureMonitor/utils/common.js +55 -0
- package/dist/commonjs/azureMonitor/utils/common.js.map +1 -1
- package/dist/commonjs/distro/distro.d.ts.map +1 -1
- package/dist/commonjs/distro/distro.js +3 -0
- package/dist/commonjs/distro/distro.js.map +1 -1
- package/dist/commonjs/genai/instrumentations/langchain/tracer.d.ts.map +1 -1
- package/dist/commonjs/genai/instrumentations/langchain/tracer.js +1 -0
- package/dist/commonjs/genai/instrumentations/langchain/tracer.js.map +1 -1
- package/dist/commonjs/genai/instrumentations/langchain/utils.d.ts +1 -0
- package/dist/commonjs/genai/instrumentations/langchain/utils.d.ts.map +1 -1
- package/dist/commonjs/genai/instrumentations/langchain/utils.js +109 -0
- package/dist/commonjs/genai/instrumentations/langchain/utils.js.map +1 -1
- package/dist/commonjs/genai/semconv.d.ts +10 -0
- package/dist/commonjs/genai/semconv.d.ts.map +1 -1
- package/dist/commonjs/genai/semconv.js +11 -1
- package/dist/commonjs/genai/semconv.js.map +1 -1
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/shared/config.d.ts +7 -0
- package/dist/commonjs/shared/config.d.ts.map +1 -1
- package/dist/commonjs/shared/config.js +19 -3
- package/dist/commonjs/shared/config.js.map +1 -1
- package/dist/commonjs/types.d.ts +1 -1
- package/dist/commonjs/types.js +1 -1
- package/dist/commonjs/utils/sdkStats.d.ts +7 -0
- package/dist/commonjs/utils/sdkStats.d.ts.map +1 -1
- package/dist/commonjs/utils/sdkStats.js +12 -2
- package/dist/commonjs/utils/sdkStats.js.map +1 -1
- package/dist/esm/a365/configuration/A365Configuration.d.ts +3 -0
- package/dist/esm/a365/configuration/A365Configuration.d.ts.map +1 -1
- package/dist/esm/a365/configuration/A365Configuration.js +5 -1
- package/dist/esm/a365/configuration/A365Configuration.js.map +1 -1
- package/dist/esm/a365/configuration/A365ConfigurationOptions.d.ts +3 -0
- package/dist/esm/a365/configuration/A365ConfigurationOptions.d.ts.map +1 -1
- package/dist/esm/a365/constants.d.ts +1 -1
- package/dist/esm/a365/exporter/Agent365Exporter.d.ts +29 -3
- package/dist/esm/a365/exporter/Agent365Exporter.d.ts.map +1 -1
- package/dist/esm/a365/exporter/Agent365Exporter.js +325 -71
- package/dist/esm/a365/exporter/Agent365Exporter.js.map +1 -1
- package/dist/esm/a365/exporter/Agent365ExporterOptions.d.ts +5 -0
- package/dist/esm/a365/exporter/Agent365ExporterOptions.d.ts.map +1 -1
- package/dist/esm/a365/exporter/Agent365ExporterOptions.js +3 -0
- package/dist/esm/a365/exporter/Agent365ExporterOptions.js.map +1 -1
- package/dist/esm/a365/exporter/durable/DurableDeliveryManager.d.ts +70 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryManager.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryManager.js +342 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryManager.js.map +1 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryOptions.d.ts +31 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryOptions.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryOptions.js +44 -0
- package/dist/esm/a365/exporter/durable/DurableDeliveryOptions.js.map +1 -0
- package/dist/esm/a365/exporter/durable/DurableRecord.d.ts +20 -0
- package/dist/esm/a365/exporter/durable/DurableRecord.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/DurableRecord.js +93 -0
- package/dist/esm/a365/exporter/durable/DurableRecord.js.map +1 -0
- package/dist/esm/a365/exporter/durable/PersistentStore.d.ts +48 -0
- package/dist/esm/a365/exporter/durable/PersistentStore.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/PersistentStore.js +599 -0
- package/dist/esm/a365/exporter/durable/PersistentStore.js.map +1 -0
- package/dist/esm/a365/exporter/durable/TransmissionGate.d.ts +24 -0
- package/dist/esm/a365/exporter/durable/TransmissionGate.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/TransmissionGate.js +80 -0
- package/dist/esm/a365/exporter/durable/TransmissionGate.js.map +1 -0
- package/dist/esm/a365/exporter/durable/WindowsFileAccessControl.d.ts +35 -0
- package/dist/esm/a365/exporter/durable/WindowsFileAccessControl.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/WindowsFileAccessControl.js +164 -0
- package/dist/esm/a365/exporter/durable/WindowsFileAccessControl.js.map +1 -0
- package/dist/esm/a365/exporter/durable/index.d.ts +12 -0
- package/dist/esm/a365/exporter/durable/index.d.ts.map +1 -0
- package/dist/esm/a365/exporter/durable/index.js +9 -0
- package/dist/esm/a365/exporter/durable/index.js.map +1 -0
- package/dist/esm/a365/exporter/index.d.ts +1 -1
- package/dist/esm/a365/exporter/index.d.ts.map +1 -1
- package/dist/esm/a365/exporter/index.js.map +1 -1
- package/dist/esm/a365/index.d.ts +1 -1
- package/dist/esm/a365/index.d.ts.map +1 -1
- package/dist/esm/a365/index.js.map +1 -1
- package/dist/esm/azureMonitor/index.d.ts.map +1 -1
- package/dist/esm/azureMonitor/index.js +4 -10
- package/dist/esm/azureMonitor/index.js.map +1 -1
- package/dist/esm/azureMonitor/logs/handler.d.ts +0 -7
- package/dist/esm/azureMonitor/logs/handler.d.ts.map +1 -1
- package/dist/esm/azureMonitor/logs/handler.js +0 -27
- package/dist/esm/azureMonitor/logs/handler.js.map +1 -1
- package/dist/esm/azureMonitor/metrics/performanceCounters.d.ts +3 -0
- package/dist/esm/azureMonitor/metrics/performanceCounters.d.ts.map +1 -1
- package/dist/esm/azureMonitor/metrics/performanceCounters.js +21 -12
- package/dist/esm/azureMonitor/metrics/performanceCounters.js.map +1 -1
- package/dist/esm/azureMonitor/traces/handler.d.ts +2 -9
- package/dist/esm/azureMonitor/traces/handler.d.ts.map +1 -1
- package/dist/esm/azureMonitor/traces/handler.js +2 -54
- package/dist/esm/azureMonitor/traces/handler.js.map +1 -1
- package/dist/esm/azureMonitor/utils/common.d.ts +29 -0
- package/dist/esm/azureMonitor/utils/common.d.ts.map +1 -1
- package/dist/esm/azureMonitor/utils/common.js +52 -0
- package/dist/esm/azureMonitor/utils/common.js.map +1 -1
- package/dist/esm/distro/distro.d.ts.map +1 -1
- package/dist/esm/distro/distro.js +3 -0
- package/dist/esm/distro/distro.js.map +1 -1
- package/dist/esm/genai/instrumentations/langchain/tracer.d.ts.map +1 -1
- package/dist/esm/genai/instrumentations/langchain/tracer.js +1 -0
- package/dist/esm/genai/instrumentations/langchain/tracer.js.map +1 -1
- package/dist/esm/genai/instrumentations/langchain/utils.d.ts +1 -0
- package/dist/esm/genai/instrumentations/langchain/utils.d.ts.map +1 -1
- package/dist/esm/genai/instrumentations/langchain/utils.js +109 -1
- package/dist/esm/genai/instrumentations/langchain/utils.js.map +1 -1
- package/dist/esm/genai/semconv.d.ts +10 -0
- package/dist/esm/genai/semconv.d.ts.map +1 -1
- package/dist/esm/genai/semconv.js +10 -0
- package/dist/esm/genai/semconv.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/shared/config.d.ts +7 -0
- package/dist/esm/shared/config.d.ts.map +1 -1
- package/dist/esm/shared/config.js +19 -3
- package/dist/esm/shared/config.js.map +1 -1
- package/dist/esm/types.d.ts +1 -1
- package/dist/esm/types.js +1 -1
- package/dist/esm/utils/sdkStats.d.ts +7 -0
- package/dist/esm/utils/sdkStats.d.ts.map +1 -1
- package/dist/esm/utils/sdkStats.js +12 -2
- package/dist/esm/utils/sdkStats.js.map +1 -1
- package/package.json +7 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DurableRecord.js","sourceRoot":"","sources":["../../../../../src/a365/exporter/durable/DurableRecord.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ILogger } from "../../logging.js";
|
|
2
|
+
import { ResolvedDurableDeliveryOptions } from "./DurableDeliveryOptions.js";
|
|
3
|
+
import { type DurableRecordV1 } from "./DurableRecord.js";
|
|
4
|
+
import { type DirectoryAccessControl } from "./WindowsFileAccessControl.js";
|
|
5
|
+
export interface ClaimedRecord {
|
|
6
|
+
record: DurableRecordV1;
|
|
7
|
+
leasePath: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ClaimBatchOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Record ids to skip during this claim scan. Matching pending records are
|
|
12
|
+
* left in place (released back to pending if already leased for
|
|
13
|
+
* inspection) so callers can exclude records they already determined are
|
|
14
|
+
* temporarily unusable without starving unrelated records that sort later.
|
|
15
|
+
*/
|
|
16
|
+
excludeRecordIds?: ReadonlySet<string>;
|
|
17
|
+
}
|
|
18
|
+
export interface PersistentStoreDependencies {
|
|
19
|
+
directoryAccessControl?: DirectoryAccessControl;
|
|
20
|
+
}
|
|
21
|
+
export declare class PersistentStore {
|
|
22
|
+
private readonly root;
|
|
23
|
+
private readonly options;
|
|
24
|
+
private readonly logger;
|
|
25
|
+
private static readonly persistenceQueues;
|
|
26
|
+
private claimQueue;
|
|
27
|
+
private constructor();
|
|
28
|
+
static create(options: ResolvedDurableDeliveryOptions, logger: ILogger, dependencies?: PersistentStoreDependencies): Promise<PersistentStore>;
|
|
29
|
+
persist(record: DurableRecordV1): Promise<string>;
|
|
30
|
+
private persistInternal;
|
|
31
|
+
claimBatch(limit: number, options?: ClaimBatchOptions): Promise<ClaimedRecord[]>;
|
|
32
|
+
complete(claim: ClaimedRecord): Promise<void>;
|
|
33
|
+
release(claim: ClaimedRecord): Promise<void>;
|
|
34
|
+
private quarantinePendingFile;
|
|
35
|
+
private pruneForCapacity;
|
|
36
|
+
private recoverStaleLeases;
|
|
37
|
+
private pendingPath;
|
|
38
|
+
private recoveredPendingPath;
|
|
39
|
+
private leasePath;
|
|
40
|
+
private migratedLeasePath;
|
|
41
|
+
private temporaryPath;
|
|
42
|
+
private readManagedFiles;
|
|
43
|
+
private listManagedFilePaths;
|
|
44
|
+
private withClaimLock;
|
|
45
|
+
private withPersistenceLock;
|
|
46
|
+
}
|
|
47
|
+
export declare function applicationPartition(): string;
|
|
48
|
+
//# sourceMappingURL=PersistentStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PersistentStore.d.ts","sourceRoot":"","sources":["../../../../../src/a365/exporter/durable/PersistentStore.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,+BAA+B,CAAC;AAiBvC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACxC;AAUD,MAAM,WAAW,2BAA2B;IAC1C,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;CACjD;AAED,qBAAa,eAAe;IAKxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAoC;IAC7E,OAAO,CAAC,UAAU,CAAoC;IAEtD,OAAO;WAMa,MAAM,CACxB,OAAO,EAAE,8BAA8B,EACvC,MAAM,EAAE,OAAO,EACf,YAAY,GAAE,2BAAgC,GAC7C,OAAO,CAAC,eAAe,CAAC;IASpB,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;YAI1C,eAAe;IA8BhB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAsHhF,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7C,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;YAW3C,qBAAqB;YAkBrB,gBAAgB;YAsDhB,kBAAkB;IAqChC,OAAO,CAAC,WAAW;YAQL,oBAAoB;IAUlC,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,aAAa;YAOP,gBAAgB;YA2BhB,oBAAoB;YAcpB,aAAa;YAeb,mBAAmB;CAkBlC;AAgID,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C"}
|
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.PersistentStore = void 0;
|
|
39
|
+
exports.applicationPartition = applicationPartition;
|
|
40
|
+
const node_crypto_1 = require("node:crypto");
|
|
41
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
42
|
+
const os = __importStar(require("node:os"));
|
|
43
|
+
const node_path_1 = require("node:path");
|
|
44
|
+
const DurableRecord_js_1 = require("./DurableRecord.js");
|
|
45
|
+
const WindowsFileAccessControl_js_1 = require("./WindowsFileAccessControl.js");
|
|
46
|
+
const OWNER_DIRECTORY_MODE = 0o700;
|
|
47
|
+
const OWNER_FILE_MODE = 0o600;
|
|
48
|
+
const PENDING_SUFFIX = ".pending";
|
|
49
|
+
const QUARANTINE_SUFFIX = ".quarantine";
|
|
50
|
+
const TEMPORARY_SUFFIX = ".tmp";
|
|
51
|
+
// NAME_MAX: the largest single path component most filesystems (ext4, NTFS,
|
|
52
|
+
// APFS, etc.) accept. Renaming a pending file to its lease name appends
|
|
53
|
+
// lease metadata to the basename, so a pending basename that itself fits
|
|
54
|
+
// can still overflow this limit once that metadata is appended.
|
|
55
|
+
const MAX_FILENAME_COMPONENT_BYTES = 255;
|
|
56
|
+
const WINDOWS_PROBE_DIRECTORY = ["Microsoft", "A365", "otel-durable"];
|
|
57
|
+
const POSIX_DEFAULT_LEAF_PREFIX = "a365-otel-durable";
|
|
58
|
+
const APPLICATION_PARTITION_PREFIX = "app-";
|
|
59
|
+
const PROCESS_START_CWD = process.cwd();
|
|
60
|
+
class PersistentStore {
|
|
61
|
+
root;
|
|
62
|
+
options;
|
|
63
|
+
logger;
|
|
64
|
+
static persistenceQueues = new Map();
|
|
65
|
+
claimQueue = Promise.resolve();
|
|
66
|
+
constructor(root, options, logger) {
|
|
67
|
+
this.root = root;
|
|
68
|
+
this.options = options;
|
|
69
|
+
this.logger = logger;
|
|
70
|
+
}
|
|
71
|
+
static async create(options, logger, dependencies = {}) {
|
|
72
|
+
const root = await resolveStorageRoot(options, logger, resolveDirectoryAccessControl(dependencies.directoryAccessControl));
|
|
73
|
+
return new PersistentStore(root, options, logger);
|
|
74
|
+
}
|
|
75
|
+
persist(record) {
|
|
76
|
+
return this.withPersistenceLock(() => this.persistInternal(record));
|
|
77
|
+
}
|
|
78
|
+
async persistInternal(record) {
|
|
79
|
+
const serialized = JSON.stringify(record);
|
|
80
|
+
const recordBytes = Buffer.byteLength(serialized, "utf8");
|
|
81
|
+
if (recordBytes > this.options.maxStorageBytes) {
|
|
82
|
+
throw new RangeError("Durable record exceeds maxStorageBytes");
|
|
83
|
+
}
|
|
84
|
+
await this.pruneForCapacity(recordBytes);
|
|
85
|
+
const temporaryPath = this.temporaryPath(record);
|
|
86
|
+
const pendingPath = this.pendingPath(record);
|
|
87
|
+
const handle = await fs.open(temporaryPath, "wx", OWNER_FILE_MODE);
|
|
88
|
+
try {
|
|
89
|
+
try {
|
|
90
|
+
await handle.writeFile(serialized, "utf8");
|
|
91
|
+
await handle.sync();
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await handle.close();
|
|
95
|
+
}
|
|
96
|
+
await this.pruneForCapacity(0);
|
|
97
|
+
await fs.rename(temporaryPath, pendingPath);
|
|
98
|
+
await syncDirectory(this.root);
|
|
99
|
+
return pendingPath;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
await ignoreEnoent(() => fs.unlink(temporaryPath));
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async claimBatch(limit, options) {
|
|
107
|
+
return this.withClaimLock(async () => {
|
|
108
|
+
if (limit <= 0) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
await this.recoverStaleLeases();
|
|
112
|
+
const excludeRecordIds = options?.excludeRecordIds;
|
|
113
|
+
const claims = [];
|
|
114
|
+
const pendingFiles = await this.listManagedFilePaths((name) => name.endsWith(PENDING_SUFFIX));
|
|
115
|
+
pendingFiles.sort();
|
|
116
|
+
for (const pendingPath of pendingFiles) {
|
|
117
|
+
if (claims.length >= limit) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
const leasePath = this.leasePath(pendingPath);
|
|
121
|
+
// Preflight before ever attempting the pending -> lease rename:
|
|
122
|
+
// appending lease metadata to an already-near-limit pending
|
|
123
|
+
// basename can push it past the filesystem's per-component name
|
|
124
|
+
// limit, and that failure surfaces inconsistently across platforms
|
|
125
|
+
// (ENAMETOOLONG on POSIX; an unhelpful ENOENT on this Windows/NTFS
|
|
126
|
+
// setup that the benign-race handling below would otherwise
|
|
127
|
+
// swallow silently). Validating basename length and content here,
|
|
128
|
+
// before the rename, guarantees a poison pending file is always
|
|
129
|
+
// quarantined -- deterministically, regardless of OS-specific
|
|
130
|
+
// rename errno behavior -- instead of wedging replay or aborting
|
|
131
|
+
// the batch.
|
|
132
|
+
if (!isSafeLeaseBasename(leasePath)) {
|
|
133
|
+
await this.quarantinePendingFile(pendingPath);
|
|
134
|
+
this.logger.warn("[PersistentStore] Quarantined pending durable record with an oversized basename", { path: pendingPath });
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
let preflightText;
|
|
138
|
+
try {
|
|
139
|
+
preflightText = await fs.readFile(pendingPath, "utf8");
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (isEnoent(error)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
(0, DurableRecord_js_1.parseDurableRecord)(preflightText);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
await this.quarantinePendingFile(pendingPath);
|
|
152
|
+
this.logger.warn("[PersistentStore] Quarantined malformed pending durable record", error);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
await fs.rename(pendingPath, leasePath);
|
|
157
|
+
await syncDirectory(this.root);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (isEnoent(error)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (isEnametoolong(error)) {
|
|
164
|
+
// Defense in depth: the dynamic-length preflight above should
|
|
165
|
+
// make this unreachable, but an OS-specific errno must never be
|
|
166
|
+
// the only guard against aborting the batch.
|
|
167
|
+
await this.quarantinePendingFile(pendingPath);
|
|
168
|
+
this.logger.warn("[PersistentStore] Quarantined pending durable record after an unexpected ENAMETOOLONG", error);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
// Re-read and re-parse from the claimed lease path rather than
|
|
174
|
+
// trusting the preflight-parsed content above: the preflight read
|
|
175
|
+
// and this rename are not atomic with each other, so a same-user
|
|
176
|
+
// actor could have replaced the pending file's content in between.
|
|
177
|
+
// The rename is the atomic claim boundary; only content observed
|
|
178
|
+
// after it succeeds is trustworthy.
|
|
179
|
+
let text;
|
|
180
|
+
try {
|
|
181
|
+
text = await fs.readFile(leasePath, "utf8");
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (isEnoent(error)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
let record;
|
|
190
|
+
try {
|
|
191
|
+
record = (0, DurableRecord_js_1.parseDurableRecord)(text);
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
await quarantineFile(leasePath);
|
|
195
|
+
this.logger.warn("[PersistentStore] Quarantined malformed durable record", error);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (excludeRecordIds?.has(record.id)) {
|
|
199
|
+
// Leave this record for a later pass instead of starving records
|
|
200
|
+
// that sort after it: release it back to pending and keep scanning.
|
|
201
|
+
await this.release({ record, leasePath });
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
claims.push({ record, leasePath });
|
|
205
|
+
}
|
|
206
|
+
return claims;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
async complete(claim) {
|
|
210
|
+
try {
|
|
211
|
+
await fs.unlink(claim.leasePath);
|
|
212
|
+
await syncDirectory(this.root);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (!isEnoent(error)) {
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async release(claim) {
|
|
221
|
+
try {
|
|
222
|
+
await fs.rename(claim.leasePath, this.pendingPath(claim.record, `release-${(0, node_crypto_1.randomUUID)()}`));
|
|
223
|
+
await syncDirectory(this.root);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (!isEnoent(error)) {
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async quarantinePendingFile(pendingPath) {
|
|
232
|
+
// The quarantine destination is always a short, fixed-shape name built
|
|
233
|
+
// only from the current timestamp/pid/a fresh UUID -- never derived
|
|
234
|
+
// from the poison file's basename or content -- so it can never exceed
|
|
235
|
+
// filesystem name limits and can never escape this.root, no matter how
|
|
236
|
+
// large or unsafe the source basename/id is. An ENOENT here means
|
|
237
|
+
// another process already claimed or quarantined this exact pending
|
|
238
|
+
// file first, which is a benign race, not a failure.
|
|
239
|
+
try {
|
|
240
|
+
await fs.rename(pendingPath, (0, node_path_1.join)(this.root, poisonQuarantineName()));
|
|
241
|
+
await syncDirectory(this.root);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
if (!isEnoent(error)) {
|
|
245
|
+
throw error;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async pruneForCapacity(incomingBytes) {
|
|
250
|
+
const minimumCreatedAt = Date.now() - this.options.maxRecordAgeMilliseconds;
|
|
251
|
+
let files = await this.readManagedFiles();
|
|
252
|
+
let usedBytes = sumBytes(files);
|
|
253
|
+
for (const file of files.sort((left, right) => left.createdAt - right.createdAt)) {
|
|
254
|
+
if (!file.removableWhenExpired || file.createdAt >= minimumCreatedAt) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (await unlinkIfExists(file.path)) {
|
|
258
|
+
this.logger.warn("[PersistentStore] Evicted expired durable record", {
|
|
259
|
+
path: file.path,
|
|
260
|
+
bytes: file.size,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
usedBytes -= file.size;
|
|
264
|
+
}
|
|
265
|
+
if (usedBytes + incomingBytes <= this.options.maxStorageBytes) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
files = await this.readManagedFiles();
|
|
269
|
+
usedBytes = sumBytes(files);
|
|
270
|
+
for (const file of files.sort((left, right) => left.createdAt - right.createdAt)) {
|
|
271
|
+
if (usedBytes + incomingBytes <= this.options.maxStorageBytes) {
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
if (!file.evictable) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (await unlinkIfExists(file.path)) {
|
|
278
|
+
this.logger.warn("[PersistentStore] Evicted durable record for capacity", {
|
|
279
|
+
path: file.path,
|
|
280
|
+
bytes: file.size,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
usedBytes -= file.size;
|
|
284
|
+
}
|
|
285
|
+
if (usedBytes + incomingBytes <= this.options.maxStorageBytes) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const survivingFiles = await this.readManagedFiles();
|
|
289
|
+
if (sumBytes(survivingFiles) + incomingBytes <= this.options.maxStorageBytes) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
throw new RangeError("Durable storage capacity is occupied by active durable files");
|
|
293
|
+
}
|
|
294
|
+
async recoverStaleLeases() {
|
|
295
|
+
const now = Date.now();
|
|
296
|
+
const leasePaths = await this.listManagedFilePaths(isActiveLeaseFileName);
|
|
297
|
+
for (const leasePath of leasePaths) {
|
|
298
|
+
const claimedAt = parseLeaseClaimedAt(leasePath);
|
|
299
|
+
if (claimedAt === undefined) {
|
|
300
|
+
const migratedLeasePath = this.migratedLeasePath(leasePath, now);
|
|
301
|
+
try {
|
|
302
|
+
await fs.rename(leasePath, migratedLeasePath);
|
|
303
|
+
await syncDirectory(this.root);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
if (isEnoent(error)) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (now - claimedAt <= this.options.leaseDurationMilliseconds) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
const recoveredPath = await this.recoveredPendingPath(leasePath);
|
|
318
|
+
await fs.rename(leasePath, recoveredPath);
|
|
319
|
+
await syncDirectory(this.root);
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
if (isEnoent(error)) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
pendingPath(record, suffix) {
|
|
330
|
+
const baseName = recordBasename(record);
|
|
331
|
+
return (0, node_path_1.join)(this.root, suffix ? `${baseName}.${suffix}${PENDING_SUFFIX}` : `${baseName}${PENDING_SUFFIX}`);
|
|
332
|
+
}
|
|
333
|
+
async recoveredPendingPath(leasePath) {
|
|
334
|
+
const text = await fs.readFile(leasePath, "utf8");
|
|
335
|
+
const suffix = `recovered-${(0, node_crypto_1.randomUUID)()}`;
|
|
336
|
+
try {
|
|
337
|
+
return this.pendingPath((0, DurableRecord_js_1.parseDurableRecord)(text), suffix);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
return (0, node_path_1.join)(this.root, `${stableRecordBasename(leasePath)}.${suffix}${PENDING_SUFFIX}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
leasePath(pendingPath) {
|
|
344
|
+
return pendingPath.replace(/\.pending$/, `.lease-at-${Date.now()}-${process.pid}-${(0, node_crypto_1.randomUUID)()}`);
|
|
345
|
+
}
|
|
346
|
+
migratedLeasePath(leasePath, claimedAt) {
|
|
347
|
+
return (0, node_path_1.join)(this.root, `${leasePrefix(leasePath)}.lease-at-${claimedAt}-${process.pid}-${(0, node_crypto_1.randomUUID)()}`);
|
|
348
|
+
}
|
|
349
|
+
temporaryPath(record) {
|
|
350
|
+
return (0, node_path_1.join)(this.root, `${Date.now()}-${record.id}.${process.pid}-${(0, node_crypto_1.randomUUID)()}${TEMPORARY_SUFFIX}`);
|
|
351
|
+
}
|
|
352
|
+
async readManagedFiles() {
|
|
353
|
+
const names = await this.listManagedFilePaths(isManagedFileName);
|
|
354
|
+
const files = [];
|
|
355
|
+
for (const fullPath of names) {
|
|
356
|
+
try {
|
|
357
|
+
const stats = await fs.stat(fullPath);
|
|
358
|
+
const name = (0, node_path_1.basename)(fullPath);
|
|
359
|
+
const activeLease = isActiveLeaseFileName(name);
|
|
360
|
+
files.push({
|
|
361
|
+
path: fullPath,
|
|
362
|
+
size: stats.size,
|
|
363
|
+
createdAt: parseCreatedAt(fullPath) ?? Math.floor(stats.mtimeMs),
|
|
364
|
+
evictable: isEvictableFileName(name),
|
|
365
|
+
removableWhenExpired: !activeLease,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
if (isEnoent(error)) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return files;
|
|
376
|
+
}
|
|
377
|
+
async listManagedFilePaths(predicate) {
|
|
378
|
+
try {
|
|
379
|
+
const entries = await fs.readdir(this.root, { withFileTypes: true });
|
|
380
|
+
return entries
|
|
381
|
+
.filter((entry) => entry.isFile() && predicate(entry.name))
|
|
382
|
+
.map((entry) => (0, node_path_1.join)(this.root, entry.name));
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
if (isEnoent(error)) {
|
|
386
|
+
return [];
|
|
387
|
+
}
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async withClaimLock(callback) {
|
|
392
|
+
const previous = this.claimQueue;
|
|
393
|
+
let release = () => { };
|
|
394
|
+
this.claimQueue = new Promise((resolve) => {
|
|
395
|
+
release = resolve;
|
|
396
|
+
});
|
|
397
|
+
await previous;
|
|
398
|
+
try {
|
|
399
|
+
return await callback();
|
|
400
|
+
}
|
|
401
|
+
finally {
|
|
402
|
+
release();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async withPersistenceLock(callback) {
|
|
406
|
+
const previous = PersistentStore.persistenceQueues.get(this.root) ?? Promise.resolve();
|
|
407
|
+
let release = () => { };
|
|
408
|
+
const current = new Promise((resolve) => {
|
|
409
|
+
release = resolve;
|
|
410
|
+
});
|
|
411
|
+
PersistentStore.persistenceQueues.set(this.root, current);
|
|
412
|
+
await previous;
|
|
413
|
+
try {
|
|
414
|
+
return await callback();
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
release();
|
|
418
|
+
if (PersistentStore.persistenceQueues.get(this.root) === current) {
|
|
419
|
+
PersistentStore.persistenceQueues.delete(this.root);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
exports.PersistentStore = PersistentStore;
|
|
425
|
+
async function resolveStorageRoot(options, logger, directoryAccessControl) {
|
|
426
|
+
if (options.storageDirectory !== undefined) {
|
|
427
|
+
return initializeExplicitRoot(options.storageDirectory, directoryAccessControl);
|
|
428
|
+
}
|
|
429
|
+
let lastError;
|
|
430
|
+
for (const candidate of storageRootCandidates()) {
|
|
431
|
+
const root = defaultStorageBaseRoot(candidate);
|
|
432
|
+
try {
|
|
433
|
+
return await initializeDefaultRoot(root, directoryAccessControl);
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
436
|
+
lastError = error;
|
|
437
|
+
logger.warn("[PersistentStore] Durable storage candidate unavailable", partitionedStorageRoot(root), error);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (lastError instanceof Error) {
|
|
441
|
+
throw lastError;
|
|
442
|
+
}
|
|
443
|
+
throw new Error("Unable to initialize durable storage root");
|
|
444
|
+
}
|
|
445
|
+
async function initializeRoot(root, recursive = true, directoryAccessControl) {
|
|
446
|
+
try {
|
|
447
|
+
await fs.mkdir(root, { recursive, mode: OWNER_DIRECTORY_MODE });
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
if (error.code !== "EEXIST") {
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return verifyRoot(root, directoryAccessControl);
|
|
455
|
+
}
|
|
456
|
+
async function initializeExplicitRoot(root, directoryAccessControl) {
|
|
457
|
+
const baseRoot = await initializeRoot(root, true, directoryAccessControl);
|
|
458
|
+
return initializeRoot(partitionedStorageRoot(baseRoot), false, directoryAccessControl);
|
|
459
|
+
}
|
|
460
|
+
async function initializeDefaultRoot(root, directoryAccessControl) {
|
|
461
|
+
const baseRoot = await initializeRoot(root, process.platform === "win32", directoryAccessControl);
|
|
462
|
+
return initializeRoot(partitionedStorageRoot(baseRoot), false, directoryAccessControl);
|
|
463
|
+
}
|
|
464
|
+
async function verifyRoot(root, directoryAccessControl) {
|
|
465
|
+
let stats = await fs.lstat(root);
|
|
466
|
+
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
467
|
+
throw new Error(`Durable storage root must be a real directory: ${root}`);
|
|
468
|
+
}
|
|
469
|
+
if (process.platform === "win32") {
|
|
470
|
+
await directoryAccessControl?.hardenDirectory(root);
|
|
471
|
+
stats = await fs.lstat(root);
|
|
472
|
+
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
473
|
+
throw new Error(`Durable storage root must be a real directory: ${root}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
const uid = process.getuid?.();
|
|
478
|
+
if (uid !== undefined && stats.uid !== uid) {
|
|
479
|
+
throw new Error(`Durable storage root must be owned by the current user: ${root}`);
|
|
480
|
+
}
|
|
481
|
+
await fs.chmod(root, OWNER_DIRECTORY_MODE);
|
|
482
|
+
stats = await fs.lstat(root);
|
|
483
|
+
if (stats.isSymbolicLink() ||
|
|
484
|
+
!stats.isDirectory() ||
|
|
485
|
+
(uid !== undefined && stats.uid !== uid)) {
|
|
486
|
+
throw new Error(`Durable storage root must be a real directory owned by the current user: ${root}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
await probeRoot(root);
|
|
490
|
+
return root;
|
|
491
|
+
}
|
|
492
|
+
let defaultDirectoryAccessControl;
|
|
493
|
+
function resolveDirectoryAccessControl(directoryAccessControl) {
|
|
494
|
+
if (directoryAccessControl !== undefined) {
|
|
495
|
+
return directoryAccessControl;
|
|
496
|
+
}
|
|
497
|
+
if (process.platform !== "win32") {
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
defaultDirectoryAccessControl ??= new WindowsFileAccessControl_js_1.WindowsFileAccessControl();
|
|
501
|
+
return defaultDirectoryAccessControl;
|
|
502
|
+
}
|
|
503
|
+
function defaultStorageBaseRoot(candidate) {
|
|
504
|
+
if (process.platform === "win32") {
|
|
505
|
+
return (0, node_path_1.join)(candidate, ...WINDOWS_PROBE_DIRECTORY);
|
|
506
|
+
}
|
|
507
|
+
return (0, node_path_1.join)(candidate, `${POSIX_DEFAULT_LEAF_PREFIX}-${process.getuid?.() ?? "unknown"}`);
|
|
508
|
+
}
|
|
509
|
+
function applicationPartition() {
|
|
510
|
+
const identity = [
|
|
511
|
+
process.getuid?.() ?? "unknown",
|
|
512
|
+
process.execPath,
|
|
513
|
+
stableApplicationIdentityBase(),
|
|
514
|
+
].join("\0");
|
|
515
|
+
const partition = (0, node_crypto_1.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
|
|
516
|
+
return `${APPLICATION_PARTITION_PREFIX}${partition}`;
|
|
517
|
+
}
|
|
518
|
+
function stableApplicationIdentityBase() {
|
|
519
|
+
const entryPoint = process.argv[1];
|
|
520
|
+
if (typeof entryPoint === "string" && entryPoint.length > 0) {
|
|
521
|
+
return (0, node_path_1.isAbsolute)(entryPoint) ? entryPoint : (0, node_path_1.resolve)(PROCESS_START_CWD, entryPoint);
|
|
522
|
+
}
|
|
523
|
+
return PROCESS_START_CWD;
|
|
524
|
+
}
|
|
525
|
+
function partitionedStorageRoot(root) {
|
|
526
|
+
return (0, node_path_1.join)(root, applicationPartition());
|
|
527
|
+
}
|
|
528
|
+
function storageRootCandidates() {
|
|
529
|
+
const candidates = process.platform === "win32"
|
|
530
|
+
? [process.env.LOCALAPPDATA, process.env.TEMP, os.tmpdir()]
|
|
531
|
+
: [process.env.TMPDIR, "/var/tmp", "/tmp"];
|
|
532
|
+
return [...new Set(candidates.filter(isNonEmptyString))];
|
|
533
|
+
}
|
|
534
|
+
function isNonEmptyString(value) {
|
|
535
|
+
return typeof value === "string" && value.length > 0;
|
|
536
|
+
}
|
|
537
|
+
async function probeRoot(root) {
|
|
538
|
+
const probePath = (0, node_path_1.join)(root, `.probe-${process.pid}-${(0, node_crypto_1.randomUUID)()}`);
|
|
539
|
+
const handle = await fs.open(probePath, "wx", OWNER_FILE_MODE);
|
|
540
|
+
try {
|
|
541
|
+
await handle.writeFile("probe", "utf8");
|
|
542
|
+
await handle.sync();
|
|
543
|
+
}
|
|
544
|
+
finally {
|
|
545
|
+
await handle.close();
|
|
546
|
+
}
|
|
547
|
+
await fs.unlink(probePath);
|
|
548
|
+
await syncDirectory(root);
|
|
549
|
+
}
|
|
550
|
+
async function quarantineFile(path) {
|
|
551
|
+
await fs.rename(path, (0, node_path_1.join)((0, node_path_1.dirname)(path), `${leasePrefix(path)}${QUARANTINE_SUFFIX}`));
|
|
552
|
+
await syncDirectory((0, node_path_1.dirname)(path));
|
|
553
|
+
}
|
|
554
|
+
async function syncDirectory(root) {
|
|
555
|
+
if (process.platform === "win32") {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const handle = await fs.open(root, "r");
|
|
559
|
+
try {
|
|
560
|
+
await handle.sync();
|
|
561
|
+
}
|
|
562
|
+
finally {
|
|
563
|
+
await handle.close();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
function parseCreatedAt(path) {
|
|
567
|
+
const match = /^(\d+)-/.exec((0, node_path_1.basename)(path));
|
|
568
|
+
if (!match) {
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|
|
571
|
+
const createdAt = Number.parseInt(match[1], 10);
|
|
572
|
+
return Number.isFinite(createdAt) ? createdAt : undefined;
|
|
573
|
+
}
|
|
574
|
+
function leasePrefix(path) {
|
|
575
|
+
return (0, node_path_1.basename)(path).split(".lease-")[0];
|
|
576
|
+
}
|
|
577
|
+
function recordBasename(record) {
|
|
578
|
+
return `${record.createdAt}-${record.id}`;
|
|
579
|
+
}
|
|
580
|
+
function stableRecordBasename(path) {
|
|
581
|
+
return leasePrefix(path).split(".")[0];
|
|
582
|
+
}
|
|
583
|
+
function parseLeaseClaimedAt(path) {
|
|
584
|
+
const match = /\.lease-at-(\d+)-\d+-[^.]+$/.exec((0, node_path_1.basename)(path));
|
|
585
|
+
if (!match) {
|
|
586
|
+
return undefined;
|
|
587
|
+
}
|
|
588
|
+
const claimedAt = Number.parseInt(match[1], 10);
|
|
589
|
+
return Number.isFinite(claimedAt) ? claimedAt : undefined;
|
|
590
|
+
}
|
|
591
|
+
function isActiveLeaseFileName(name) {
|
|
592
|
+
return /\.lease-[^.]+$/.test(name);
|
|
593
|
+
}
|
|
594
|
+
function isEvictableFileName(name) {
|
|
595
|
+
return name.endsWith(PENDING_SUFFIX) || name.endsWith(QUARANTINE_SUFFIX);
|
|
596
|
+
}
|
|
597
|
+
function isManagedFileName(name) {
|
|
598
|
+
return (isEvictableFileName(name) || name.endsWith(TEMPORARY_SUFFIX) || isActiveLeaseFileName(name));
|
|
599
|
+
}
|
|
600
|
+
function isEnoent(error) {
|
|
601
|
+
return error.code === "ENOENT";
|
|
602
|
+
}
|
|
603
|
+
function isEnametoolong(error) {
|
|
604
|
+
return error.code === "ENAMETOOLONG";
|
|
605
|
+
}
|
|
606
|
+
function isSafeLeaseBasename(candidateLeasePath) {
|
|
607
|
+
return Buffer.byteLength((0, node_path_1.basename)(candidateLeasePath), "utf8") <= MAX_FILENAME_COMPONENT_BYTES;
|
|
608
|
+
}
|
|
609
|
+
function poisonQuarantineName() {
|
|
610
|
+
return `${Date.now()}-quarantined-${process.pid}-${(0, node_crypto_1.randomUUID)()}${QUARANTINE_SUFFIX}`;
|
|
611
|
+
}
|
|
612
|
+
async function unlinkIfExists(path) {
|
|
613
|
+
try {
|
|
614
|
+
await fs.unlink(path);
|
|
615
|
+
return true;
|
|
616
|
+
}
|
|
617
|
+
catch (error) {
|
|
618
|
+
if (isEnoent(error)) {
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
throw error;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function ignoreEnoent(action) {
|
|
625
|
+
try {
|
|
626
|
+
await action();
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
if (!isEnoent(error)) {
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function sumBytes(files) {
|
|
635
|
+
return files.reduce((total, file) => total + file.size, 0);
|
|
636
|
+
}
|
|
637
|
+
//# sourceMappingURL=PersistentStore.js.map
|