@milaboratories/pl-middle-layer 1.67.6 → 1.68.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/index.d.ts +3 -2
- package/dist/middle_layer/build_stamp.cjs +34 -0
- package/dist/middle_layer/build_stamp.cjs.map +1 -0
- package/dist/middle_layer/build_stamp.js +34 -0
- package/dist/middle_layer/build_stamp.js.map +1 -0
- package/dist/middle_layer/index.d.ts +3 -2
- package/dist/middle_layer/middle_layer.cjs +48 -0
- package/dist/middle_layer/middle_layer.cjs.map +1 -1
- package/dist/middle_layer/middle_layer.d.ts +19 -0
- package/dist/middle_layer/middle_layer.d.ts.map +1 -1
- package/dist/middle_layer/middle_layer.js +48 -0
- package/dist/middle_layer/middle_layer.js.map +1 -1
- package/dist/middle_layer/ops.cjs +8 -2
- package/dist/middle_layer/ops.cjs.map +1 -1
- package/dist/middle_layer/ops.d.ts +35 -2
- package/dist/middle_layer/ops.d.ts.map +1 -1
- package/dist/middle_layer/ops.js +8 -2
- package/dist/middle_layer/ops.js.map +1 -1
- package/dist/middle_layer/project.cjs +163 -8
- package/dist/middle_layer/project.cjs.map +1 -1
- package/dist/middle_layer/project.d.ts +51 -1
- package/dist/middle_layer/project.d.ts.map +1 -1
- package/dist/middle_layer/project.js +165 -11
- package/dist/middle_layer/project.js.map +1 -1
- package/dist/middle_layer/tree_snapshot_store.cjs +283 -0
- package/dist/middle_layer/tree_snapshot_store.cjs.map +1 -0
- package/dist/middle_layer/tree_snapshot_store.d.ts +143 -0
- package/dist/middle_layer/tree_snapshot_store.d.ts.map +1 -0
- package/dist/middle_layer/tree_snapshot_store.js +280 -0
- package/dist/middle_layer/tree_snapshot_store.js.map +1 -0
- package/package.json +10 -10
- package/src/middle_layer/build_stamp.ts +36 -0
- package/src/middle_layer/index.ts +1 -0
- package/src/middle_layer/middle_layer.ts +77 -0
- package/src/middle_layer/ops.ts +46 -1
- package/src/middle_layer/project.ts +234 -14
- package/src/middle_layer/project_failsafe.test.ts +47 -0
- package/src/middle_layer/tree_snapshot_scenarios.test.ts +337 -0
- package/src/middle_layer/tree_snapshot_store.test.ts +331 -0
- package/src/middle_layer/tree_snapshot_store.ts +419 -0
package/dist/index.d.ts
CHANGED
|
@@ -13,8 +13,9 @@ import { BlockPackExplicit, BlockPackSpecAny, BlockPackSpecPrepared, FrontendFro
|
|
|
13
13
|
import { TemplateParseOutcome, parseProjectTemplateV1Yaml } from "./model/template_parser.js";
|
|
14
14
|
import "./model/index.js";
|
|
15
15
|
import { Project } from "./middle_layer/project.js";
|
|
16
|
-
import { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, MiddleLayerDebugOptions, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings } from "./middle_layer/ops.js";
|
|
16
|
+
import { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, MiddleLayerDebugOptions, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings, TreeSnapshotOps } from "./middle_layer/ops.js";
|
|
17
17
|
import { MiddleLayerDriverKit, initDriverKit } from "./middle_layer/driver_kit.js";
|
|
18
|
+
import { TreeSnapshotMiss, TreeSnapshotStat } from "./middle_layer/tree_snapshot_store.js";
|
|
18
19
|
import { MiddleLayer } from "./middle_layer/middle_layer.js";
|
|
19
20
|
import { ProjectsField } from "./middle_layer/project_list.js";
|
|
20
21
|
import "./middle_layer/index.js";
|
|
@@ -31,4 +32,4 @@ export * from "@platforma-sdk/model";
|
|
|
31
32
|
export * from "@milaboratories/pl-model-middle-layer";
|
|
32
33
|
export * from "@milaboratories/pl-deployments";
|
|
33
34
|
export * from "@milaboratories/pl-client";
|
|
34
|
-
export { ACCESS_COUNT_KEY, ACCESS_KEY_PREFIX, AcceptanceFieldPrefix, type AppliedEntry, BlockArgsAuthorKeyPrefix, BlockPackExplicit, type BlockPackProvider, BlockPackRegistry, BlockPackSpecAny, BlockPackSpecPrepared, CachedTemplate, CentralBlockRegistry, CheckNetworkOpts, DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, EnvelopeAcceptance, EnvelopeData, EnvelopeMode, EnvelopeProject, type ExactResolution, ExplicitTemplate, type FieldType, FrontendFromFolder, FrontendFromFolderData, FrontendFromFolderResourceType, FrontendFromLocalTgz, FrontendFromLocalTgzData, FrontendFromLocalTgzResourceType, FrontendFromUrl, FrontendFromUrlData, FrontendFromUrlResourceType, FrontendSpec, GC_ACCESS_THRESHOLD, GC_MAX_ENTRIES, type InternalLsDriver, KindAwareRegistry, type KindResolution, MiddleLayer, MiddleLayerDebugOptions, MiddleLayerDriverKit, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings, type OutgoingShare, type PendingShare, PreparedTemplate, Project, ProjectChangeAction, ProjectCreatedTimestamp, type ProjectField, ProjectFieldUuid, type ProjectId, ProjectLastModifiedTimestamp, type ProjectListEntry, ProjectMetaKey, ProjectResourceType, ProjectStructureAuthorKey, ProjectStructureKey, ProjectsField, type ResolvedEntry, type ResourceType, SchemaVersionCurrent, SchemaVersionKey, ShareId, ShareProjectsOptions, SharedEnvelopeResourceType, SharingDecision, SharingOutboxField, SharingOutboxResourceType, SharingStateField, SharingStateResourceType, type TemplateApplyProblem, type TemplateApplyReport, TemplateCacheFieldName, TemplateCacheStat, TemplateCacheType, TemplateEntryRejected, TemplateFromFile, TemplateFromRegistry, type TemplateParseOutcome, type TemplateResolveOutcome, TemplateSpecAny, TemplateSpecPrepared, TengoTemplateGet, TengoTemplateGetRegistry, TengoTemplateGetTemplate, TengoTemplateGetTemplateURI, TengoTemplatePack, TengoTemplatePackConvert, TengoTemplatePackConvertTemplate, TengoTemplatePackConvertTemplatePack, V1CentralDevSnapshotRegistry, V1CentralRegistry, V2RegistryProvider, acceptanceField, acceptanceFieldLogin, asShareId, cacheBlockPackTemplate, canGrantToEveryone, canImpersonate, checkNetwork, createRenderTemplate, decisionField, decodeEnvelopeData, deriveGlobalPObjectId, deriveLocalPObjectId, dropTemplateCache, duplicateProject, flattenTemplateTree, getDevV1PacketMtime, getDevV2PacketMtime, getFromPackV2Mtime, getOrCreateTemplateCache, initDriverKit, initNetworkCheck, invalidateTemplateCacheId, isAcceptanceField, kindCapableRegistryIds, loadTemplate, loadTemplateCached, newShareId, parseBlockPackName, parseFinalPObjectCollection, parseProjectTemplateV1Yaml, prepareTemplateSpec, resolveTemplateEntries, runGc, templateBlockPackProvider };
|
|
35
|
+
export { ACCESS_COUNT_KEY, ACCESS_KEY_PREFIX, AcceptanceFieldPrefix, type AppliedEntry, BlockArgsAuthorKeyPrefix, BlockPackExplicit, type BlockPackProvider, BlockPackRegistry, BlockPackSpecAny, BlockPackSpecPrepared, CachedTemplate, CentralBlockRegistry, CheckNetworkOpts, DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, EnvelopeAcceptance, EnvelopeData, EnvelopeMode, EnvelopeProject, type ExactResolution, ExplicitTemplate, type FieldType, FrontendFromFolder, FrontendFromFolderData, FrontendFromFolderResourceType, FrontendFromLocalTgz, FrontendFromLocalTgzData, FrontendFromLocalTgzResourceType, FrontendFromUrl, FrontendFromUrlData, FrontendFromUrlResourceType, FrontendSpec, GC_ACCESS_THRESHOLD, GC_MAX_ENTRIES, type InternalLsDriver, KindAwareRegistry, type KindResolution, MiddleLayer, MiddleLayerDebugOptions, MiddleLayerDriverKit, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings, type OutgoingShare, type PendingShare, PreparedTemplate, Project, ProjectChangeAction, ProjectCreatedTimestamp, type ProjectField, ProjectFieldUuid, type ProjectId, ProjectLastModifiedTimestamp, type ProjectListEntry, ProjectMetaKey, ProjectResourceType, ProjectStructureAuthorKey, ProjectStructureKey, ProjectsField, type ResolvedEntry, type ResourceType, SchemaVersionCurrent, SchemaVersionKey, ShareId, ShareProjectsOptions, SharedEnvelopeResourceType, SharingDecision, SharingOutboxField, SharingOutboxResourceType, SharingStateField, SharingStateResourceType, type TemplateApplyProblem, type TemplateApplyReport, TemplateCacheFieldName, TemplateCacheStat, TemplateCacheType, TemplateEntryRejected, TemplateFromFile, TemplateFromRegistry, type TemplateParseOutcome, type TemplateResolveOutcome, TemplateSpecAny, TemplateSpecPrepared, TengoTemplateGet, TengoTemplateGetRegistry, TengoTemplateGetTemplate, TengoTemplateGetTemplateURI, TengoTemplatePack, TengoTemplatePackConvert, TengoTemplatePackConvertTemplate, TengoTemplatePackConvertTemplatePack, type TreeSnapshotMiss, TreeSnapshotOps, type TreeSnapshotStat, V1CentralDevSnapshotRegistry, V1CentralRegistry, V2RegistryProvider, acceptanceField, acceptanceFieldLogin, asShareId, cacheBlockPackTemplate, canGrantToEveryone, canImpersonate, checkNetwork, createRenderTemplate, decisionField, decodeEnvelopeData, deriveGlobalPObjectId, deriveLocalPObjectId, dropTemplateCache, duplicateProject, flattenTemplateTree, getDevV1PacketMtime, getDevV2PacketMtime, getFromPackV2Mtime, getOrCreateTemplateCache, initDriverKit, initNetworkCheck, invalidateTemplateCacheId, isAcceptanceField, kindCapableRegistryIds, loadTemplate, loadTemplateCached, newShareId, parseBlockPackName, parseFinalPObjectCollection, parseProjectTemplateV1Yaml, prepareTemplateSpec, resolveTemplateEntries, runGc, templateBlockPackProvider };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/middle_layer/build_stamp.ts
|
|
2
|
+
function injectedStamp() {
|
|
3
|
+
try {
|
|
4
|
+
return "48a74953f8cd-dirty-1787671552027";
|
|
5
|
+
} catch {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Identifies the build of this package, and through it the rules that shape what a persisted
|
|
11
|
+
* tree mirror contains: the pruning function, the field filter and the traversal stop rules,
|
|
12
|
+
* all of which live in this package. (The finality predicate comes from pl-client and is NOT
|
|
13
|
+
* covered, which is harmless: finality is recomputed on restore, so it is the one rule that
|
|
14
|
+
* cannot poison a stored file.)
|
|
15
|
+
*
|
|
16
|
+
* Used as a cache-key component, so a change to those rules invalidates every snapshot, costing
|
|
17
|
+
* one cold open. Each built artifact bakes in one stamp, so reopens stay warm across restarts
|
|
18
|
+
* of an installed version. A build from a dirty worktree includes the build time, so editing
|
|
19
|
+
* those rules locally can never hit a snapshot written under the old ones. In practice release
|
|
20
|
+
* builds are dirty too, because CI writes version bumps into the worktree before building; that
|
|
21
|
+
* costs nothing, since the stamp only has to be stable within an artifact.
|
|
22
|
+
*
|
|
23
|
+
* With no build at all (sources mode) the value is a constant. That deliberately trades away
|
|
24
|
+
* the dirty-worktree guarantee: it means someone running from sources exercises the restore
|
|
25
|
+
* path at all, rather than every snapshot being a guaranteed miss for the one audience most
|
|
26
|
+
* likely to find its defects. The exposure it reintroduces, editing pruning rules from sources
|
|
27
|
+
* and hitting a mirror written under the old ones, is the local-development gap the design
|
|
28
|
+
* already accepts, and `treeSnapshots: false` or deleting the directory clears it.
|
|
29
|
+
*/
|
|
30
|
+
const ML_BUILD_STAMP = injectedStamp() ?? "sources";
|
|
31
|
+
//#endregion
|
|
32
|
+
exports.ML_BUILD_STAMP = ML_BUILD_STAMP;
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=build_stamp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build_stamp.cjs","names":[],"sources":["../../src/middle_layer/build_stamp.ts"],"sourcesContent":["/** Injected by rolldown at build time, see `build.node.config.js`. Absent when the package is\n * consumed straight from sources (`USE_SOURCES=1`), because no build step runs then. */\ndeclare const __PL_ML_BUILD_STAMP__: string | undefined;\n\nfunction injectedStamp(): string | undefined {\n try {\n // Read inside a try: with no build step the identifier is an undeclared global, and\n // reading it throws a ReferenceError rather than yielding undefined.\n return __PL_ML_BUILD_STAMP__;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Identifies the build of this package, and through it the rules that shape what a persisted\n * tree mirror contains: the pruning function, the field filter and the traversal stop rules,\n * all of which live in this package. (The finality predicate comes from pl-client and is NOT\n * covered, which is harmless: finality is recomputed on restore, so it is the one rule that\n * cannot poison a stored file.)\n *\n * Used as a cache-key component, so a change to those rules invalidates every snapshot, costing\n * one cold open. Each built artifact bakes in one stamp, so reopens stay warm across restarts\n * of an installed version. A build from a dirty worktree includes the build time, so editing\n * those rules locally can never hit a snapshot written under the old ones. In practice release\n * builds are dirty too, because CI writes version bumps into the worktree before building; that\n * costs nothing, since the stamp only has to be stable within an artifact.\n *\n * With no build at all (sources mode) the value is a constant. That deliberately trades away\n * the dirty-worktree guarantee: it means someone running from sources exercises the restore\n * path at all, rather than every snapshot being a guaranteed miss for the one audience most\n * likely to find its defects. The exposure it reintroduces, editing pruning rules from sources\n * and hitting a mirror written under the old ones, is the local-development gap the design\n * already accepts, and `treeSnapshots: false` or deleting the directory clears it.\n */\nexport const ML_BUILD_STAMP: string = injectedStamp() ?? \"sources\";\n"],"mappings":";AAIA,SAAS,gBAAoC;CAC3C,IAAI;EAGF,OAAA;CACF,QAAQ;EACN;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,iBAAyB,cAAc,KAAK"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/middle_layer/build_stamp.ts
|
|
2
|
+
function injectedStamp() {
|
|
3
|
+
try {
|
|
4
|
+
return "48a74953f8cd-dirty-1787671551997";
|
|
5
|
+
} catch {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Identifies the build of this package, and through it the rules that shape what a persisted
|
|
11
|
+
* tree mirror contains: the pruning function, the field filter and the traversal stop rules,
|
|
12
|
+
* all of which live in this package. (The finality predicate comes from pl-client and is NOT
|
|
13
|
+
* covered, which is harmless: finality is recomputed on restore, so it is the one rule that
|
|
14
|
+
* cannot poison a stored file.)
|
|
15
|
+
*
|
|
16
|
+
* Used as a cache-key component, so a change to those rules invalidates every snapshot, costing
|
|
17
|
+
* one cold open. Each built artifact bakes in one stamp, so reopens stay warm across restarts
|
|
18
|
+
* of an installed version. A build from a dirty worktree includes the build time, so editing
|
|
19
|
+
* those rules locally can never hit a snapshot written under the old ones. In practice release
|
|
20
|
+
* builds are dirty too, because CI writes version bumps into the worktree before building; that
|
|
21
|
+
* costs nothing, since the stamp only has to be stable within an artifact.
|
|
22
|
+
*
|
|
23
|
+
* With no build at all (sources mode) the value is a constant. That deliberately trades away
|
|
24
|
+
* the dirty-worktree guarantee: it means someone running from sources exercises the restore
|
|
25
|
+
* path at all, rather than every snapshot being a guaranteed miss for the one audience most
|
|
26
|
+
* likely to find its defects. The exposure it reintroduces, editing pruning rules from sources
|
|
27
|
+
* and hitting a mirror written under the old ones, is the local-development gap the design
|
|
28
|
+
* already accepts, and `treeSnapshots: false` or deleting the directory clears it.
|
|
29
|
+
*/
|
|
30
|
+
const ML_BUILD_STAMP = injectedStamp() ?? "sources";
|
|
31
|
+
//#endregion
|
|
32
|
+
export { ML_BUILD_STAMP };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=build_stamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build_stamp.js","names":[],"sources":["../../src/middle_layer/build_stamp.ts"],"sourcesContent":["/** Injected by rolldown at build time, see `build.node.config.js`. Absent when the package is\n * consumed straight from sources (`USE_SOURCES=1`), because no build step runs then. */\ndeclare const __PL_ML_BUILD_STAMP__: string | undefined;\n\nfunction injectedStamp(): string | undefined {\n try {\n // Read inside a try: with no build step the identifier is an undeclared global, and\n // reading it throws a ReferenceError rather than yielding undefined.\n return __PL_ML_BUILD_STAMP__;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Identifies the build of this package, and through it the rules that shape what a persisted\n * tree mirror contains: the pruning function, the field filter and the traversal stop rules,\n * all of which live in this package. (The finality predicate comes from pl-client and is NOT\n * covered, which is harmless: finality is recomputed on restore, so it is the one rule that\n * cannot poison a stored file.)\n *\n * Used as a cache-key component, so a change to those rules invalidates every snapshot, costing\n * one cold open. Each built artifact bakes in one stamp, so reopens stay warm across restarts\n * of an installed version. A build from a dirty worktree includes the build time, so editing\n * those rules locally can never hit a snapshot written under the old ones. In practice release\n * builds are dirty too, because CI writes version bumps into the worktree before building; that\n * costs nothing, since the stamp only has to be stable within an artifact.\n *\n * With no build at all (sources mode) the value is a constant. That deliberately trades away\n * the dirty-worktree guarantee: it means someone running from sources exercises the restore\n * path at all, rather than every snapshot being a guaranteed miss for the one audience most\n * likely to find its defects. The exposure it reintroduces, editing pruning rules from sources\n * and hitting a mirror written under the old ones, is the local-development gap the design\n * already accepts, and `treeSnapshots: false` or deleting the directory clears it.\n */\nexport const ML_BUILD_STAMP: string = injectedStamp() ?? \"sources\";\n"],"mappings":";AAIA,SAAS,gBAAoC;CAC3C,IAAI;EAGF,OAAA;CACF,QAAQ;EACN;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,iBAAyB,cAAc,KAAK"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { OutgoingShare, PendingShare } from "./sharing_list.js";
|
|
2
2
|
import { Project } from "./project.js";
|
|
3
|
-
import { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, MiddleLayerDebugOptions, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings } from "./ops.js";
|
|
3
|
+
import { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, MiddleLayerDebugOptions, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings, TreeSnapshotOps } from "./ops.js";
|
|
4
4
|
import { MiddleLayerDriverKit, initDriverKit } from "./driver_kit.js";
|
|
5
|
+
import { TreeSnapshotMiss, TreeSnapshotStat } from "./tree_snapshot_store.js";
|
|
5
6
|
import { MiddleLayer } from "./middle_layer.js";
|
|
6
7
|
import { ProjectsField } from "./project_list.js";
|
|
7
|
-
export { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, MiddleLayer, MiddleLayerDebugOptions, MiddleLayerDriverKit, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings, type OutgoingShare, type PendingShare, Project, ProjectsField, initDriverKit };
|
|
8
|
+
export { DefaultDriverKitOpsPaths, DefaultDriverKitOpsSettings, DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings, DriverKitOps, DriverKitOpsConstructor, DriverKitOpsPaths, DriverKitOpsSettings, MiddleLayer, MiddleLayerDebugOptions, MiddleLayerDriverKit, MiddleLayerOps, MiddleLayerOpsConstructor, MiddleLayerOpsPaths, MiddleLayerOpsSettings, type OutgoingShare, type PendingShare, Project, ProjectsField, type TreeSnapshotMiss, TreeSnapshotOps, type TreeSnapshotStat, initDriverKit };
|
|
@@ -18,6 +18,7 @@ const require_watcher = require("../block_registry/watcher.cjs");
|
|
|
18
18
|
const require_driver_kit = require("./driver_kit.cjs");
|
|
19
19
|
const require_service_factories = require("../service_factories.cjs");
|
|
20
20
|
const require_project_helper = require("../model/project_helper.cjs");
|
|
21
|
+
const require_tree_snapshot_store = require("./tree_snapshot_store.cjs");
|
|
21
22
|
let _platforma_sdk_model = require("@platforma-sdk/model");
|
|
22
23
|
let undici = require("undici");
|
|
23
24
|
let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
@@ -28,6 +29,10 @@ let _milaboratories_computable = require("@milaboratories/computable");
|
|
|
28
29
|
let node_crypto = require("node:crypto");
|
|
29
30
|
let quickjs_emscripten = require("quickjs-emscripten");
|
|
30
31
|
//#region src/middle_layer/middle_layer.ts
|
|
32
|
+
/** How long shutdown waits for close-boundary snapshot writes that are already running. Long
|
|
33
|
+
* enough for a ten-megabyte encode and write on ordinary storage, short enough that a wedged
|
|
34
|
+
* filesystem does not hold the quit open. */
|
|
35
|
+
const SNAPSHOT_DRAIN_TIMEOUT_MS = 5e3;
|
|
31
36
|
/**
|
|
32
37
|
* Main access object to work with pl from UI.
|
|
33
38
|
*
|
|
@@ -757,6 +762,32 @@ var MiddleLayer = class MiddleLayer {
|
|
|
757
762
|
}
|
|
758
763
|
}
|
|
759
764
|
openedProjects = /* @__PURE__ */ new Map();
|
|
765
|
+
/** Snapshot writes started by {@link closeProject} and not yet finished. Held only so
|
|
766
|
+
* {@link close} can give them a bounded chance to land. */
|
|
767
|
+
pendingSnapshotWrites = /* @__PURE__ */ new Set();
|
|
768
|
+
trackSnapshotWrite(write) {
|
|
769
|
+
this.pendingSnapshotWrites.add(write);
|
|
770
|
+
write.finally(() => this.pendingSnapshotWrites.delete(write));
|
|
771
|
+
}
|
|
772
|
+
/** Waits for close-boundary snapshot writes that are already running, up to `timeoutMs`.
|
|
773
|
+
*
|
|
774
|
+
* This starts no work: quitting still performs no snapshot of its own. It only lets a write
|
|
775
|
+
* that a project close already began finish, so closing a project and immediately quitting
|
|
776
|
+
* does not routinely lose it. Bounded, because a wedged filesystem must not hang the quit,
|
|
777
|
+
* and losing the write costs one cold open rather than any correctness. */
|
|
778
|
+
async drainSnapshotWrites(timeoutMs) {
|
|
779
|
+
if (this.pendingSnapshotWrites.size === 0) return;
|
|
780
|
+
let timer;
|
|
781
|
+
const expiry = new Promise((resolve) => {
|
|
782
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
783
|
+
timer.unref?.();
|
|
784
|
+
});
|
|
785
|
+
try {
|
|
786
|
+
await Promise.race([Promise.allSettled(this.pendingSnapshotWrites), expiry]);
|
|
787
|
+
} finally {
|
|
788
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
760
791
|
/** Opens a project, and starts corresponding project maintenance loop. */
|
|
761
792
|
async openProject(id) {
|
|
762
793
|
if (this.openedProjects.has(id)) throw new Error(`Project ${id} already opened`);
|
|
@@ -769,6 +800,7 @@ var MiddleLayer = class MiddleLayer {
|
|
|
769
800
|
const prj = this.openedProjects.get(id);
|
|
770
801
|
if (prj === void 0) throw new Error(`Project ${id} not found among opened projects`);
|
|
771
802
|
this.openedProjects.delete(id);
|
|
803
|
+
this.trackSnapshotWrite(prj.snapshotOnClose());
|
|
772
804
|
await prj.destroy();
|
|
773
805
|
this.openedProjectsList.setValue([...this.openedProjects.keys()]);
|
|
774
806
|
}
|
|
@@ -782,6 +814,12 @@ var MiddleLayer = class MiddleLayer {
|
|
|
782
814
|
isProjectOpened(id) {
|
|
783
815
|
return this.openedProjects.has(id);
|
|
784
816
|
}
|
|
817
|
+
/** Counters for the persisted project tree mirrors, or undefined when they are switched off.
|
|
818
|
+
* Reads and hits are what show whether a reopen was actually warm, and the miss breakdown
|
|
819
|
+
* says why it was not. */
|
|
820
|
+
get treeSnapshotStats() {
|
|
821
|
+
return this.env.treeSnapshots?.getStats();
|
|
822
|
+
}
|
|
785
823
|
/**
|
|
786
824
|
* Deallocates all runtime resources consumed by this object and awaits
|
|
787
825
|
* actual termination of event loops and other processes associated with
|
|
@@ -796,6 +834,7 @@ var MiddleLayer = class MiddleLayer {
|
|
|
796
834
|
this.sharingStateTree.terminate(),
|
|
797
835
|
this.pendingSharesTree.terminate()
|
|
798
836
|
]);
|
|
837
|
+
await this.drainSnapshotWrites(SNAPSHOT_DRAIN_TIMEOUT_MS);
|
|
799
838
|
await this.env.dispose();
|
|
800
839
|
await this.pl.close();
|
|
801
840
|
}
|
|
@@ -858,6 +897,14 @@ var MiddleLayer = class MiddleLayer {
|
|
|
858
897
|
runtimeCapabilities.addSupportedRequirement("requiresPFramesVersion", _milaboratories_pl_model_common.REQUIRES_PFRAMES_VERSION);
|
|
859
898
|
(0, _milaboratories_pl_model_common.registerServiceCapabilities)((flag, value) => runtimeCapabilities.addSupportedRequirement(flag, value));
|
|
860
899
|
const serviceRegistry = require_service_factories.createModelServiceRegistry({ logger });
|
|
900
|
+
const treeSnapshots = require_tree_snapshot_store.TreeSnapshotStore.create(pl, {
|
|
901
|
+
dir: ops.treeSnapshotPath,
|
|
902
|
+
maxSizeBytes: ops.treeSnapshotOps.maxSizeBytes,
|
|
903
|
+
enabled: ops.treeSnapshotOps.enabled,
|
|
904
|
+
logger
|
|
905
|
+
});
|
|
906
|
+
if (ops.treeSnapshotOps.enabled) await treeSnapshots?.evict();
|
|
907
|
+
else await require_tree_snapshot_store.TreeSnapshotStore.purge(ops.treeSnapshotPath, logger);
|
|
861
908
|
const env = {
|
|
862
909
|
pl,
|
|
863
910
|
blockEventDispatcher: new _milaboratories_ts_helpers.BlockEventDispatcher(),
|
|
@@ -878,6 +925,7 @@ var MiddleLayer = class MiddleLayer {
|
|
|
878
925
|
serviceRegistry,
|
|
879
926
|
quickJs,
|
|
880
927
|
projectHelper: new require_project_helper.ProjectHelper(quickJs, logger),
|
|
928
|
+
treeSnapshots,
|
|
881
929
|
dispose: async () => {
|
|
882
930
|
await serviceRegistry.dispose();
|
|
883
931
|
await retryHttpDispatcher.destroy();
|