spawnfile 0.1.12 → 0.1.14
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 +58 -12
- package/dist/audit/auditCli.d.ts +19 -0
- package/dist/audit/auditCli.js +63 -0
- package/dist/audit/checks.d.ts +100 -0
- package/dist/audit/checks.js +279 -0
- package/dist/audit/checksShared.d.ts +74 -0
- package/dist/audit/checksShared.js +37 -0
- package/dist/audit/generateAudit.d.ts +19 -0
- package/dist/audit/generateAudit.js +122 -0
- package/dist/audit/index.d.ts +4 -0
- package/dist/audit/index.js +4 -0
- package/dist/audit/readAudit.d.ts +50 -0
- package/dist/audit/readAudit.js +59 -0
- package/dist/audit/types.d.ts +40 -0
- package/dist/audit/types.js +8 -0
- package/dist/auth/credentialEnvFile.d.ts +11 -0
- package/dist/auth/credentialEnvFile.js +60 -0
- package/dist/auth/credentialProvisioning.d.ts +15 -0
- package/dist/auth/credentialProvisioning.js +75 -0
- package/dist/auth/credentialProvisioningReceipt.d.ts +28 -0
- package/dist/auth/credentialProvisioningReceipt.js +70 -0
- package/dist/auth/credentialProvisioningRequest.d.ts +51 -0
- package/dist/auth/credentialProvisioningRequest.js +169 -0
- package/dist/auth/credentialWorldBindings.d.ts +21 -0
- package/dist/auth/credentialWorldBindings.js +104 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.js +7 -0
- package/dist/auth/paths.d.ts +11 -0
- package/dist/auth/paths.js +21 -0
- package/dist/auth/runtimeCredentials.js +18 -2
- package/dist/auth/targetSecretSourceAuthor.d.ts +18 -0
- package/dist/auth/targetSecretSourceAuthor.js +52 -0
- package/dist/auth/targetSecretSourceFsPublish.d.ts +15 -0
- package/dist/auth/targetSecretSourceFsPublish.js +49 -0
- package/dist/auth/targetSecretSourceFsPublishImmutable.d.ts +16 -0
- package/dist/auth/targetSecretSourceFsPublishImmutable.js +435 -0
- package/dist/auth/targetSecretSourceFsRead.d.ts +14 -0
- package/dist/auth/targetSecretSourceFsRead.js +198 -0
- package/dist/auth/targetSecretSourceGrant.d.ts +16 -0
- package/dist/auth/targetSecretSourceGrant.js +99 -0
- package/dist/auth/targetSecretSourceGrantRecords.d.ts +84 -0
- package/dist/auth/targetSecretSourceGrantRecords.js +214 -0
- package/dist/auth/targetSecretSourceLifecycle.d.ts +30 -0
- package/dist/auth/targetSecretSourceLifecycle.js +52 -0
- package/dist/auth/targetSecretSourceOwnerEntropy.d.ts +6 -0
- package/dist/auth/targetSecretSourceOwnerEntropy.js +28 -0
- package/dist/auth/targetSecretSourceRecordCommon.d.ts +14 -0
- package/dist/auth/targetSecretSourceRecordCommon.js +100 -0
- package/dist/auth/targetSecretSourceRecordPublish.d.ts +10 -0
- package/dist/auth/targetSecretSourceRecordPublish.js +104 -0
- package/dist/auth/targetSecretSourceResolver.d.ts +10 -0
- package/dist/auth/targetSecretSourceResolver.js +137 -0
- package/dist/auth/targetSecretSourceRevoke.d.ts +20 -0
- package/dist/auth/targetSecretSourceRevoke.js +92 -0
- package/dist/auth/targetSecretSourceRotate.d.ts +19 -0
- package/dist/auth/targetSecretSourceRotate.js +121 -0
- package/dist/auth/targetSecretSourceVersionRecords.d.ts +49 -0
- package/dist/auth/targetSecretSourceVersionRecords.js +166 -0
- package/dist/cli/artifactsCommands.d.ts +27 -0
- package/dist/cli/artifactsCommands.js +132 -0
- package/dist/cli/authCommands.d.ts +5 -0
- package/dist/cli/authCommands.js +221 -0
- package/dist/cli/compileBuildCommands.d.ts +3 -0
- package/dist/cli/compileBuildCommands.js +35 -0
- package/dist/cli/containerBundleCommand.d.ts +6 -0
- package/dist/cli/containerBundleCommand.js +116 -0
- package/dist/cli/devCommands.d.ts +3 -0
- package/dist/cli/devCommands.js +115 -0
- package/dist/cli/downCommand.d.ts +25 -0
- package/dist/cli/downCommand.js +134 -0
- package/dist/cli/index.js +6 -3
- package/dist/cli/lifecycleCommands.d.ts +1 -1
- package/dist/cli/lifecycleCommands.js +11 -179
- package/dist/cli/lifecycleMachine.d.ts +19 -0
- package/dist/cli/lifecycleMachine.js +78 -0
- package/dist/cli/lifecyclePlan.d.ts +35 -0
- package/dist/cli/lifecyclePlan.js +240 -0
- package/dist/cli/lifecyclePlanningCommands.d.ts +3 -0
- package/dist/cli/lifecyclePlanningCommands.js +30 -0
- package/dist/cli/runCli.d.ts +15 -2
- package/dist/cli/runCli.js +31 -71
- package/dist/cli/runPublishCommands.d.ts +3 -0
- package/dist/cli/runPublishCommands.js +70 -0
- package/dist/cli/statusCommand.d.ts +3 -32
- package/dist/cli/statusCommand.js +37 -233
- package/dist/cli/statusCommandLive.d.ts +20 -0
- package/dist/cli/statusCommandLive.js +188 -0
- package/dist/cli/statusCommandOptions.d.ts +40 -0
- package/dist/cli/statusCommandOptions.js +42 -0
- package/dist/cli/targetCliRoute.d.ts +2 -0
- package/dist/cli/targetCliRoute.js +30 -0
- package/dist/cli/targetCommands.d.ts +33 -0
- package/dist/cli/targetCommands.js +257 -0
- package/dist/cli/targetComposedPreparationCommand.d.ts +6 -0
- package/dist/cli/targetComposedPreparationCommand.js +39 -0
- package/dist/cli/targetDefaultArtifactAuthority.d.ts +5 -0
- package/dist/cli/targetDefaultArtifactAuthority.js +28 -0
- package/dist/cli/targetDefaultAuthorities.d.ts +53 -0
- package/dist/cli/targetDefaultAuthorities.js +210 -0
- package/dist/cli/targetDefaultConfig.d.ts +68 -0
- package/dist/cli/targetDefaultConfig.js +317 -0
- package/dist/cli/targetDefaultConfigStdin.d.ts +13 -0
- package/dist/cli/targetDefaultConfigStdin.js +215 -0
- package/dist/cli/targetDefaultEnvelope.d.ts +1 -0
- package/dist/cli/targetDefaultEnvelope.js +13 -0
- package/dist/cli/targetDefaultHandlerFactory.d.ts +28 -0
- package/dist/cli/targetDefaultHandlerFactory.js +247 -0
- package/dist/cli/targetDefaultHandlers.d.ts +21 -0
- package/dist/cli/targetDefaultHandlers.js +72 -0
- package/dist/cli/targetDefaultJournalAuthority.d.ts +35 -0
- package/dist/cli/targetDefaultJournalAuthority.js +135 -0
- package/dist/cli/targetDefaultWorldClock.d.ts +4 -0
- package/dist/cli/targetDefaultWorldClock.js +14 -0
- package/dist/cli/targetDefaultWorldQueries.d.ts +5 -0
- package/dist/cli/targetDefaultWorldQueries.js +11 -0
- package/dist/cli/targetDefaultWorldReadiness.d.ts +4 -0
- package/dist/cli/targetDefaultWorldReadiness.js +17 -0
- package/dist/cli/targetEvidenceHelperResolution.d.ts +14 -0
- package/dist/cli/targetEvidenceHelperResolution.js +23 -0
- package/dist/cli/targetLookupCli.d.ts +3 -0
- package/dist/cli/targetLookupCli.js +31 -0
- package/dist/cli/targetLookupCommands.d.ts +12 -0
- package/dist/cli/targetLookupCommands.js +69 -0
- package/dist/cli/targetOperationDispatch.d.ts +58 -0
- package/dist/cli/targetOperationDispatch.js +21 -0
- package/dist/cli/targetReceiptOutput.d.ts +14 -0
- package/dist/cli/targetReceiptOutput.js +21 -0
- package/dist/cli/targetRequestFile.d.ts +14 -0
- package/dist/cli/targetRequestFile.js +63 -0
- package/dist/cli/targetSecretSourceInput.d.ts +28 -0
- package/dist/cli/targetSecretSourceInput.js +121 -0
- package/dist/cli/targetWorldClockCommand.d.ts +10 -0
- package/dist/cli/targetWorldClockCommand.js +42 -0
- package/dist/cli/targetWorldClockCrossProcess.test-helper.d.ts +13 -0
- package/dist/cli/targetWorldClockCrossProcess.test-helper.js +109 -0
- package/dist/cli/targetWorldReadinessCommand.d.ts +10 -0
- package/dist/cli/targetWorldReadinessCommand.js +43 -0
- package/dist/cli/upCommand.d.ts +3 -0
- package/dist/cli/upCommand.js +133 -0
- package/dist/cli/upImageCommand.d.ts +11 -0
- package/dist/cli/upImageCommand.js +41 -0
- package/dist/cli/upLifecycleInvocation.d.ts +41 -0
- package/dist/cli/upLifecycleInvocation.js +48 -0
- package/dist/cli/upLifecycleRecovery.d.ts +4 -0
- package/dist/cli/upLifecycleRecovery.js +53 -0
- package/dist/compiler/agentNodeMerge.d.ts +2 -0
- package/dist/compiler/agentNodeMerge.js +79 -0
- package/dist/compiler/agentSurfaces.js +11 -1
- package/dist/compiler/buildCompilePlan.js +17 -0
- package/dist/compiler/buildCompilePlanAgent.d.ts +11 -0
- package/dist/compiler/buildCompilePlanAgent.js +56 -0
- package/dist/compiler/buildCompilePlanTeams.d.ts +1 -0
- package/dist/compiler/buildCompilePlanTeams.js +4 -1
- package/dist/compiler/buildCompilePlanTraversal.js +75 -82
- package/dist/compiler/buildProject.d.ts +20 -1
- package/dist/compiler/buildProject.js +121 -7
- package/dist/compiler/compilePlanHelpers.js +2 -0
- package/dist/compiler/compileProject.d.ts +15 -0
- package/dist/compiler/compileProject.js +29 -75
- package/dist/compiler/compileProjectPolicy.d.ts +5 -0
- package/dist/compiler/compileProjectPolicy.js +21 -0
- package/dist/compiler/compileProjectReports.d.ts +9 -0
- package/dist/compiler/compileProjectReports.js +52 -0
- package/dist/compiler/containerArtifactSummaries.d.ts +7 -0
- package/dist/compiler/containerArtifactSummaries.js +138 -0
- package/dist/compiler/containerArtifacts.d.ts +10 -0
- package/dist/compiler/containerArtifacts.js +126 -125
- package/dist/compiler/containerArtifactsPlans.d.ts +5 -3
- package/dist/compiler/containerArtifactsPlans.js +31 -118
- package/dist/compiler/containerArtifactsRender.d.ts +3 -1
- package/dist/compiler/containerArtifactsRender.js +40 -81
- package/dist/compiler/containerArtifactsTypes.d.ts +12 -0
- package/dist/compiler/containerConfigEnvRender.d.ts +3 -0
- package/dist/compiler/containerConfigEnvRender.js +54 -0
- package/dist/compiler/containerEntrypointRender.d.ts +1 -0
- package/dist/compiler/containerEntrypointRender.js +60 -53
- package/dist/compiler/containerEntrypointShell.d.ts +5 -0
- package/dist/compiler/containerEntrypointShell.js +29 -0
- package/dist/compiler/containerPackageOverrides.d.ts +27 -0
- package/dist/compiler/containerPackageOverrides.js +63 -0
- package/dist/compiler/containerPackageRender.d.ts +15 -0
- package/dist/compiler/containerPackageRender.js +63 -0
- package/dist/compiler/containerTargetPlanResolution.d.ts +20 -0
- package/dist/compiler/containerTargetPlanResolution.js +97 -0
- package/dist/compiler/containerTargetResources.js +3 -1
- package/dist/compiler/daimonTelemetryArtifacts.d.ts +22 -0
- package/dist/compiler/daimonTelemetryArtifacts.js +61 -0
- package/dist/compiler/dockerBuildContext.d.ts +16 -0
- package/dist/compiler/dockerBuildContext.js +159 -0
- package/dist/compiler/dockerBuildSkip.d.ts +30 -0
- package/dist/compiler/dockerBuildSkip.js +81 -0
- package/dist/compiler/index.d.ts +4 -0
- package/dist/compiler/index.js +4 -0
- package/dist/compiler/memoryArtifacts.d.ts +26 -0
- package/dist/compiler/memoryArtifacts.js +134 -0
- package/dist/compiler/memoryResolution.d.ts +4 -0
- package/dist/compiler/memoryResolution.js +147 -0
- package/dist/compiler/modelEnv.d.ts +2 -0
- package/dist/compiler/modelEnv.js +6 -0
- package/dist/compiler/moltnetAllowedWakeSendersValidation.d.ts +2 -0
- package/dist/compiler/moltnetAllowedWakeSendersValidation.js +42 -0
- package/dist/compiler/moltnetArtifactPaths.d.ts +26 -0
- package/dist/compiler/moltnetArtifactPaths.js +49 -0
- package/dist/compiler/moltnetArtifactTypes.d.ts +46 -0
- package/dist/compiler/moltnetArtifactTypes.js +1 -0
- package/dist/compiler/moltnetArtifacts.d.ts +2 -40
- package/dist/compiler/moltnetArtifacts.js +56 -95
- package/dist/compiler/moltnetBinaries.d.ts +21 -1
- package/dist/compiler/moltnetBinaries.js +156 -28
- package/dist/compiler/moltnetClientConfig.js +18 -2
- package/dist/compiler/moltnetConfigLowering.d.ts +16 -1
- package/dist/compiler/moltnetConfigLowering.js +67 -5
- package/dist/compiler/moltnetExternalParticipantArtifact.d.ts +38 -0
- package/dist/compiler/moltnetExternalParticipantArtifact.js +188 -0
- package/dist/compiler/moltnetNodeConfig.js +7 -2
- package/dist/compiler/moltnetReleaseAuthority.d.ts +17 -0
- package/dist/compiler/moltnetReleaseAuthority.js +73 -0
- package/dist/compiler/moltnetReleaseDownload.d.ts +12 -0
- package/dist/compiler/moltnetReleaseDownload.js +85 -0
- package/dist/compiler/moltnetRepresentativeResolution.d.ts +1 -0
- package/dist/compiler/moltnetRepresentativeResolution.js +16 -2
- package/dist/compiler/moltnetResolution.js +72 -20
- package/dist/compiler/moltnetRoomMemberships.js +37 -9
- package/dist/compiler/moltnetRuntimeConfig.js +11 -0
- package/dist/compiler/moltnetServerPlans.d.ts +9 -0
- package/dist/compiler/moltnetServerPlans.js +132 -0
- package/dist/compiler/organizationIdentity.d.ts +27 -0
- package/dist/compiler/organizationIdentity.js +297 -0
- package/dist/compiler/organizationReadyEvidence.d.ts +49 -0
- package/dist/compiler/organizationReadyEvidence.js +261 -0
- package/dist/compiler/projectManifestGraph.d.ts +4 -0
- package/dist/compiler/projectManifestGraph.js +24 -0
- package/dist/compiler/runProject.d.ts +4 -0
- package/dist/compiler/runProject.js +37 -22
- package/dist/compiler/runProjectAuth.d.ts +7 -1
- package/dist/compiler/runProjectAuth.js +87 -9
- package/dist/compiler/runProjectDocker.d.ts +7 -0
- package/dist/compiler/runProjectDocker.js +187 -19
- package/dist/compiler/runProjectLifecycle.d.ts +7 -0
- package/dist/compiler/runProjectLifecycle.js +40 -0
- package/dist/compiler/syncProjectAuth.js +4 -1
- package/dist/compiler/teamContextActiveEnvironments.d.ts +13 -0
- package/dist/compiler/teamContextActiveEnvironments.js +255 -0
- package/dist/compiler/teamContextSupport.js +32 -40
- package/dist/compiler/teamContextTypes.d.ts +2 -0
- package/dist/compiler/types.d.ts +82 -1
- package/dist/compiler/upProject.d.ts +5 -0
- package/dist/compiler/upProject.js +257 -20
- package/dist/compiler/upReceipt.d.ts +36 -0
- package/dist/compiler/upReceipt.js +82 -0
- package/dist/compiler/updateProjectModels.js +42 -60
- package/dist/compiler/updateProjectRuntime.js +22 -35
- package/dist/compiler/updateProjectSurfaces.js +53 -47
- package/dist/compiler/worldBindings.d.ts +39 -0
- package/dist/compiler/worldBindings.js +247 -0
- package/dist/compiler/worldBindingsFile.d.ts +5 -0
- package/dist/compiler/worldBindingsFile.js +162 -0
- package/dist/deployment/artifactsExport.d.ts +49 -0
- package/dist/deployment/artifactsExport.js +217 -0
- package/dist/deployment/artifactsExportDocker.d.ts +48 -0
- package/dist/deployment/artifactsExportDocker.js +91 -0
- package/dist/deployment/artifactsExportPlan.d.ts +24 -0
- package/dist/deployment/artifactsExportPlan.js +135 -0
- package/dist/deployment/artifactsExportTypes.d.ts +50 -0
- package/dist/deployment/artifactsExportTypes.js +52 -0
- package/dist/deployment/buildImageCacheStore.d.ts +23 -0
- package/dist/deployment/buildImageCacheStore.js +54 -0
- package/dist/deployment/deploymentLifecycleCorrelation.d.ts +11 -0
- package/dist/deployment/deploymentLifecycleCorrelation.js +33 -0
- package/dist/deployment/dockerInspect.d.ts +9 -0
- package/dist/deployment/dockerInspect.js +24 -1
- package/dist/deployment/dockerLabels.d.ts +2 -0
- package/dist/deployment/dockerLabels.js +2 -0
- package/dist/deployment/dockerLogs.js +2 -10
- package/dist/deployment/dockerManager.d.ts +51 -0
- package/dist/deployment/dockerManager.js +118 -1
- package/dist/deployment/dockerProbeGateway.js +64 -5
- package/dist/deployment/dockerRecover.d.ts +17 -0
- package/dist/deployment/dockerRecover.js +137 -0
- package/dist/deployment/dockerTeardown.d.ts +32 -0
- package/dist/deployment/dockerTeardown.js +61 -0
- package/dist/deployment/downDeployment.d.ts +34 -0
- package/dist/deployment/downDeployment.js +147 -0
- package/dist/deployment/downReceiptTypes.d.ts +21 -0
- package/dist/deployment/downReceiptTypes.js +30 -0
- package/dist/deployment/index.d.ts +17 -0
- package/dist/deployment/index.js +18 -0
- package/dist/deployment/lifecycleCompletion.d.ts +37 -0
- package/dist/deployment/lifecycleCompletion.js +236 -0
- package/dist/deployment/lifecycleCompletionContracts.d.ts +158 -0
- package/dist/deployment/lifecycleCompletionContracts.js +106 -0
- package/dist/deployment/lifecycleCompletionHeartbeat.d.ts +2 -0
- package/dist/deployment/lifecycleCompletionHeartbeat.js +50 -0
- package/dist/deployment/lifecycleCompletionLookup.d.ts +18 -0
- package/dist/deployment/lifecycleCompletionLookup.js +88 -0
- package/dist/deployment/lifecycleCompletionOwner.d.ts +8 -0
- package/dist/deployment/lifecycleCompletionOwner.js +31 -0
- package/dist/deployment/lifecycleCompletionParsing.d.ts +12 -0
- package/dist/deployment/lifecycleCompletionParsing.js +108 -0
- package/dist/deployment/lifecycleCompletionPaths.d.ts +9 -0
- package/dist/deployment/lifecycleCompletionPaths.js +16 -0
- package/dist/deployment/lifecycleCompletionPublication.d.ts +5 -0
- package/dist/deployment/lifecycleCompletionPublication.js +35 -0
- package/dist/deployment/lifecycleCompletionRecovery.d.ts +21 -0
- package/dist/deployment/lifecycleCompletionRecovery.js +56 -0
- package/dist/deployment/lifecycleCompletionRoot.d.ts +21 -0
- package/dist/deployment/lifecycleCompletionRoot.js +243 -0
- package/dist/deployment/lifecycleCompletionStore.d.ts +6 -0
- package/dist/deployment/lifecycleCompletionStore.js +151 -0
- package/dist/deployment/organizationHandoffAuthorityFsClient.d.ts +17 -0
- package/dist/deployment/organizationHandoffAuthorityFsClient.js +132 -0
- package/dist/deployment/organizationHandoffAuthorityFsWorker.d.ts +1 -0
- package/dist/deployment/organizationHandoffAuthorityFsWorker.js +285 -0
- package/dist/deployment/organizationHandoffAuthorityFsWorkerParent.fixture.d.ts +1 -0
- package/dist/deployment/organizationHandoffAuthorityFsWorkerParent.fixture.js +26 -0
- package/dist/deployment/organizationHandoffAuthorityStore.d.ts +41 -0
- package/dist/deployment/organizationHandoffAuthorityStore.js +348 -0
- package/dist/deployment/organizationHandoffAuthorityTypes.d.ts +76 -0
- package/dist/deployment/organizationHandoffAuthorityTypes.js +148 -0
- package/dist/deployment/organizationHandoffTypes.d.ts +29 -0
- package/dist/deployment/organizationHandoffTypes.js +80 -0
- package/dist/deployment/organizationReady.d.ts +52 -0
- package/dist/deployment/organizationReady.js +200 -0
- package/dist/deployment/privateArtifactsExport.d.ts +18 -0
- package/dist/deployment/privateArtifactsExport.js +80 -0
- package/dist/deployment/providerRuntimeBoundaryScanner.test-helper.d.ts +8 -0
- package/dist/deployment/providerRuntimeBoundaryScanner.test-helper.js +60 -0
- package/dist/deployment/record.d.ts +26 -1
- package/dist/deployment/record.js +49 -4
- package/dist/deployment/simfileFixtureBoundary.test-helper.d.ts +8 -0
- package/dist/deployment/simfileFixtureBoundary.test-helper.js +103 -0
- package/dist/deployment/target.d.ts +1 -35
- package/dist/deployment/target.js +1 -96
- package/dist/deployment/upReceiptTypes.d.ts +111 -0
- package/dist/deployment/upReceiptTypes.js +164 -0
- package/dist/dev/activity.d.ts +14 -0
- package/dist/dev/activity.js +48 -0
- package/dist/dev/docker.d.ts +16 -0
- package/dist/dev/docker.js +71 -0
- package/dist/dev/index.d.ts +2 -0
- package/dist/dev/index.js +2 -0
- package/dist/dev/project.d.ts +35 -0
- package/dist/dev/project.js +170 -0
- package/dist/distribution/buildDistributionReport.d.ts +2 -1
- package/dist/distribution/buildDistributionReport.js +2 -1
- package/dist/distribution/distributionReportSchema.d.ts +5 -0
- package/dist/distribution/distributionReportSchema.js +7 -2
- package/dist/distribution/index.d.ts +2 -2
- package/dist/distribution/index.js +1 -1
- package/dist/distribution/types.d.ts +7 -0
- package/dist/distribution/types.js +1 -0
- package/dist/filesystem/paths.js +10 -1
- package/dist/ledger/causalConformanceCli.d.ts +1 -0
- package/dist/ledger/causalConformanceCli.js +41 -0
- package/dist/ledger/causeNamespace.d.ts +8 -0
- package/dist/ledger/causeNamespace.js +24 -0
- package/dist/ledger/conformance.d.ts +83 -0
- package/dist/ledger/conformance.js +259 -0
- package/dist/ledger/emitters.d.ts +76 -0
- package/dist/ledger/emitters.js +188 -0
- package/dist/ledger/index.d.ts +4 -0
- package/dist/ledger/index.js +4 -0
- package/dist/ledger/principal.d.ts +96 -0
- package/dist/ledger/principal.js +121 -0
- package/dist/manifest/externalParticipantSchemas.d.ts +18 -0
- package/dist/manifest/externalParticipantSchemas.js +17 -0
- package/dist/manifest/index.d.ts +1 -0
- package/dist/manifest/index.js +1 -0
- package/dist/manifest/inlineAgentMember.d.ts +2 -0
- package/dist/manifest/inlineAgentMember.js +9 -0
- package/dist/manifest/loadManifest.js +14 -8
- package/dist/manifest/mcpSchemas.d.ts +17 -0
- package/dist/manifest/mcpSchemas.js +41 -0
- package/dist/manifest/memorySchemas.d.ts +245 -0
- package/dist/manifest/memorySchemas.js +148 -0
- package/dist/manifest/renderSpawnfile.js +22 -131
- package/dist/manifest/renderSpawnfileNetworks.js +9 -2
- package/dist/manifest/renderSpawnfileSurfaces.d.ts +2 -0
- package/dist/manifest/renderSpawnfileSurfaces.js +134 -0
- package/dist/manifest/schemas.d.ts +1868 -99
- package/dist/manifest/schemas.js +78 -32
- package/dist/manifest/surfaceSchemas.d.ts +17 -0
- package/dist/manifest/surfaceSchemas.js +24 -1
- package/dist/manifest/teamNetworkAccessSchemas.d.ts +1 -1
- package/dist/manifest/teamNetworkAuthSchemas.d.ts +48 -0
- package/dist/manifest/teamNetworkAuthSchemas.js +103 -0
- package/dist/manifest/teamNetworkSchemas.d.ts +8 -187
- package/dist/manifest/teamNetworkSchemas.js +3 -317
- package/dist/manifest/teamNetworkServerSchemas.d.ts +150 -0
- package/dist/manifest/teamNetworkServerSchemas.js +199 -0
- package/dist/ownership/siblingBuildFreshness.d.ts +20 -0
- package/dist/ownership/siblingBuildFreshness.js +20 -0
- package/dist/ownership/simfileRunOperatorInputs.d.ts +103 -0
- package/dist/ownership/simfileRunOperatorInputs.js +139 -0
- package/dist/report/types.d.ts +142 -0
- package/dist/runtime/common.d.ts +37 -0
- package/dist/runtime/common.js +56 -1
- package/dist/runtime/container.d.ts +29 -1
- package/dist/runtime/container.js +127 -11
- package/dist/runtime/containerPackageOverrides.d.ts +37 -0
- package/dist/runtime/containerPackageOverrides.js +33 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/install.d.ts +1 -1
- package/dist/runtime/install.js +43 -1
- package/dist/runtime/mnemeMcp.d.ts +15 -0
- package/dist/runtime/mnemeMcp.js +109 -0
- package/dist/runtime/openclaw/adapter.js +15 -4
- package/dist/runtime/openclaw/mcp.d.ts +10 -0
- package/dist/runtime/openclaw/mcp.js +69 -0
- package/dist/runtime/openclaw/runAuth.js +2 -2
- package/dist/runtime/openclaw/scaffold.js +1 -1
- package/dist/runtime/openclaw/schedules.d.ts +38 -0
- package/dist/runtime/openclaw/schedules.js +74 -0
- package/dist/runtime/pi/adapter.d.ts +4 -0
- package/dist/runtime/pi/adapter.js +231 -0
- package/dist/runtime/pi/appActivitySource.d.ts +1 -0
- package/dist/runtime/pi/appActivitySource.js +199 -0
- package/dist/runtime/pi/appAgentConfig.d.ts +11 -0
- package/dist/runtime/pi/appAgentConfig.js +264 -0
- package/dist/runtime/pi/appCliEnginesSource.d.ts +1 -0
- package/dist/runtime/pi/appCliEnginesSource.js +183 -0
- package/dist/runtime/pi/appCliSource.d.ts +1 -0
- package/dist/runtime/pi/appCliSource.js +353 -0
- package/dist/runtime/pi/appControlSource.d.ts +1 -0
- package/dist/runtime/pi/appControlSource.js +390 -0
- package/dist/runtime/pi/appControlWakeIdentitySource.d.ts +1 -0
- package/dist/runtime/pi/appControlWakeIdentitySource.js +19 -0
- package/dist/runtime/pi/appCoreSource.d.ts +4 -0
- package/dist/runtime/pi/appCoreSource.js +244 -0
- package/dist/runtime/pi/appPreludeSource.d.ts +1 -0
- package/dist/runtime/pi/appPreludeSource.js +191 -0
- package/dist/runtime/pi/appScheduleSource.d.ts +1 -0
- package/dist/runtime/pi/appScheduleSource.js +80 -0
- package/dist/runtime/pi/appScriptedEngine.d.ts +31 -0
- package/dist/runtime/pi/appScriptedEngine.js +42 -0
- package/dist/runtime/pi/appSource.d.ts +4 -0
- package/dist/runtime/pi/appSource.js +12 -0
- package/dist/runtime/pi/appTemplate.d.ts +14 -0
- package/dist/runtime/pi/appTemplate.js +27 -0
- package/dist/runtime/pi/appTemplateTypes.d.ts +64 -0
- package/dist/runtime/pi/appTemplateTypes.js +18 -0
- package/dist/runtime/pi/appWakeContextSource.d.ts +1 -0
- package/dist/runtime/pi/appWakeContextSource.js +398 -0
- package/dist/runtime/pi/containerTargets.d.ts +4 -0
- package/dist/runtime/pi/containerTargets.js +57 -0
- package/dist/runtime/pi/runAuth.d.ts +2 -0
- package/dist/runtime/pi/runAuth.js +185 -0
- package/dist/runtime/pi/testHelpers.d.ts +2 -0
- package/dist/runtime/pi/testHelpers.js +40 -0
- package/dist/runtime/picoclaw/adapter.js +23 -27
- package/dist/runtime/picoclaw/mcp.d.ts +4 -0
- package/dist/runtime/picoclaw/mcp.js +43 -0
- package/dist/runtime/picoclaw/memory.d.ts +7 -0
- package/dist/runtime/picoclaw/memory.js +17 -0
- package/dist/runtime/picoclaw/runAuth.js +1 -1
- package/dist/runtime/picoclaw/scaffold.js +1 -1
- package/dist/runtime/picoclaw/schedules.d.ts +26 -0
- package/dist/runtime/picoclaw/schedules.js +62 -3
- package/dist/runtime/registry.js +3 -0
- package/dist/runtime/scheduleUtils.d.ts +2 -0
- package/dist/runtime/scheduleUtils.js +15 -0
- package/dist/runtime/types.d.ts +26 -2
- package/dist/shared/errors.d.ts +1 -1
- package/dist/shared/errors.js +2 -2
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/redaction.d.ts +2 -0
- package/dist/shared/redaction.js +10 -0
- package/dist/status/buildStatus.d.ts +1 -0
- package/dist/status/buildStatus.js +2 -0
- package/dist/status/compileReport.d.ts +22 -0
- package/dist/status/compileReport.js +16 -2
- package/dist/status/compiledProbeCollection.d.ts +21 -0
- package/dist/status/compiledProbeCollection.js +27 -0
- package/dist/status/deployments.js +5 -12
- package/dist/status/imageStatusReport.js +6 -0
- package/dist/status/index.d.ts +3 -0
- package/dist/status/index.js +3 -0
- package/dist/status/lifecycleProbes.d.ts +19 -0
- package/dist/status/lifecycleProbes.js +174 -0
- package/dist/status/moltnetProbes.d.ts +7 -8
- package/dist/status/moltnetProbes.js +27 -198
- package/dist/status/moltnetWiringProbes.d.ts +19 -0
- package/dist/status/moltnetWiringProbes.js +178 -0
- package/dist/target/cleanupRun.d.ts +41 -0
- package/dist/target/cleanupRun.js +139 -0
- package/dist/target/cleanupRunDocker.d.ts +16 -0
- package/dist/target/cleanupRunDocker.js +66 -0
- package/dist/target/cleanupRunDocker.test-helper.d.ts +67 -0
- package/dist/target/cleanupRunDocker.test-helper.js +238 -0
- package/dist/target/cleanupRunDockerPreflight.d.ts +17 -0
- package/dist/target/cleanupRunDockerPreflight.js +224 -0
- package/dist/target/composedPreparation.d.ts +205 -0
- package/dist/target/composedPreparation.js +223 -0
- package/dist/target/containerBundle.d.ts +82 -0
- package/dist/target/containerBundle.js +243 -0
- package/dist/target/containerBundleArchive.d.ts +31 -0
- package/dist/target/containerBundleArchive.js +140 -0
- package/dist/target/containerBundleAuthority.d.ts +25 -0
- package/dist/target/containerBundleAuthority.js +65 -0
- package/dist/target/containerBundleContracts.d.ts +114 -0
- package/dist/target/containerBundleContracts.js +173 -0
- package/dist/target/containerBundleFilesystemStore.d.ts +3 -0
- package/dist/target/containerBundleFilesystemStore.js +247 -0
- package/dist/target/containerBundlePolicy.d.ts +33 -0
- package/dist/target/containerBundlePolicy.js +64 -0
- package/dist/target/containerBundleStore.d.ts +127 -0
- package/dist/target/containerBundleStore.js +284 -0
- package/dist/target/contracts.d.ts +538 -0
- package/dist/target/contracts.js +373 -0
- package/dist/target/dockerArtifactIdentityTypes.d.ts +56 -0
- package/dist/target/dockerArtifactIdentityTypes.js +1 -0
- package/dist/target/dockerArtifactInspection.d.ts +40 -0
- package/dist/target/dockerArtifactInspection.js +125 -0
- package/dist/target/dockerArtifacts.d.ts +21 -0
- package/dist/target/dockerArtifacts.js +110 -0
- package/dist/target/dockerArtifactsProvider.d.ts +41 -0
- package/dist/target/dockerArtifactsProvider.js +449 -0
- package/dist/target/dockerCommandExecutor.d.ts +27 -0
- package/dist/target/dockerCommandExecutor.js +200 -0
- package/dist/target/dockerCommandExecutorCore.d.ts +34 -0
- package/dist/target/dockerCommandExecutorCore.js +273 -0
- package/dist/target/dockerContainerBundleBuilder.d.ts +8 -0
- package/dist/target/dockerContainerBundleBuilder.js +256 -0
- package/dist/target/dockerContextSnapshot.d.ts +21 -0
- package/dist/target/dockerContextSnapshot.js +158 -0
- package/dist/target/dockerEndpointFingerprint.d.ts +1 -0
- package/dist/target/dockerEndpointFingerprint.js +9 -0
- package/dist/target/dockerPreparedArtifact.d.ts +48 -0
- package/dist/target/dockerPreparedArtifact.js +131 -0
- package/dist/target/dockerProjectionJson.d.ts +1 -0
- package/dist/target/dockerProjectionJson.js +80 -0
- package/dist/target/dockerPublicArtifactSnapshot.d.ts +17 -0
- package/dist/target/dockerPublicArtifactSnapshot.js +99 -0
- package/dist/target/dockerResources.d.ts +26 -0
- package/dist/target/dockerResources.js +162 -0
- package/dist/target/dockerResourcesProvider.d.ts +44 -0
- package/dist/target/dockerResourcesProvider.js +207 -0
- package/dist/target/dockerSecrets.d.ts +39 -0
- package/dist/target/dockerSecrets.js +249 -0
- package/dist/target/dockerSecretsAuthority.d.ts +26 -0
- package/dist/target/dockerSecretsAuthority.js +216 -0
- package/dist/target/dockerSecretsLifecycle.d.ts +25 -0
- package/dist/target/dockerSecretsLifecycle.js +133 -0
- package/dist/target/dockerSecretsProvider.d.ts +68 -0
- package/dist/target/dockerSecretsProvider.js +329 -0
- package/dist/target/dockerTarget.d.ts +52 -0
- package/dist/target/dockerTarget.js +48 -0
- package/dist/target/dockerTargetBinding.d.ts +14 -0
- package/dist/target/dockerTargetBinding.js +96 -0
- package/dist/target/dockerWorldClock.d.ts +17 -0
- package/dist/target/dockerWorldClock.js +111 -0
- package/dist/target/dockerWorldReadiness.d.ts +17 -0
- package/dist/target/dockerWorldReadiness.js +119 -0
- package/dist/target/dockerWorldService.d.ts +23 -0
- package/dist/target/dockerWorldService.js +216 -0
- package/dist/target/dockerWorldServiceAuthority.d.ts +80 -0
- package/dist/target/dockerWorldServiceAuthority.js +182 -0
- package/dist/target/dockerWorldServiceLifecycle.d.ts +41 -0
- package/dist/target/dockerWorldServiceLifecycle.js +275 -0
- package/dist/target/dockerWorldServiceProvider.d.ts +60 -0
- package/dist/target/dockerWorldServiceProvider.js +318 -0
- package/dist/target/dockerWorldServiceStore.d.ts +73 -0
- package/dist/target/dockerWorldServiceStore.js +367 -0
- package/dist/target/evidenceExport.d.ts +55 -0
- package/dist/target/evidenceExport.js +518 -0
- package/dist/target/evidenceExportArchive.d.ts +10 -0
- package/dist/target/evidenceExportArchive.js +302 -0
- package/dist/target/evidenceExportContract.d.ts +27 -0
- package/dist/target/evidenceExportContract.js +40 -0
- package/dist/target/evidenceExportOperationsTestKit.d.ts +87 -0
- package/dist/target/evidenceExportOperationsTestKit.js +312 -0
- package/dist/target/evidenceExportProvider.d.ts +85 -0
- package/dist/target/evidenceExportProvider.js +187 -0
- package/dist/target/evidenceExportPublicationTypes.d.ts +16 -0
- package/dist/target/evidenceExportPublicationTypes.js +1 -0
- package/dist/target/evidenceExportStore.d.ts +70 -0
- package/dist/target/evidenceExportStore.js +498 -0
- package/dist/target/evidenceExportStorePublication.d.ts +7 -0
- package/dist/target/evidenceExportStorePublication.js +395 -0
- package/dist/target/handles.d.ts +20 -0
- package/dist/target/handles.js +56 -0
- package/dist/target/index.d.ts +12 -0
- package/dist/target/index.js +11 -0
- package/dist/target/journal.d.ts +59 -0
- package/dist/target/journal.js +529 -0
- package/dist/target/journalFilesystem.d.ts +3 -0
- package/dist/target/journalFilesystem.js +111 -0
- package/dist/target/journalRoot.d.ts +4 -0
- package/dist/target/journalRoot.js +6 -0
- package/dist/target/organizationAttachment.d.ts +23 -0
- package/dist/target/organizationAttachment.js +263 -0
- package/dist/target/organizationAttachmentAuthority.d.ts +65 -0
- package/dist/target/organizationAttachmentAuthority.js +161 -0
- package/dist/target/organizationAttachmentLifecycle.d.ts +17 -0
- package/dist/target/organizationAttachmentLifecycle.js +101 -0
- package/dist/target/organizationAttachmentProvider.d.ts +76 -0
- package/dist/target/organizationAttachmentProvider.js +289 -0
- package/dist/target/organizationAttachmentStore.d.ts +51 -0
- package/dist/target/organizationAttachmentStore.js +316 -0
- package/dist/target/publicArtifactSnapshot.d.ts +41 -0
- package/dist/target/publicArtifactSnapshot.js +150 -0
- package/dist/target/topologyActivation.d.ts +51 -0
- package/dist/target/topologyActivation.js +149 -0
- package/dist/target/topologyAttestation.d.ts +37 -0
- package/dist/target/topologyAttestation.js +300 -0
- package/dist/target/topologyAttestationErrors.d.ts +1 -0
- package/dist/target/topologyAttestationErrors.js +1 -0
- package/dist/target/worldClock.d.ts +60 -0
- package/dist/target/worldClock.js +129 -0
- package/dist/target/worldReadiness.d.ts +103 -0
- package/dist/target/worldReadiness.js +153 -0
- package/moltnet-releases.json +20 -0
- package/package.json +29 -8
- package/runtimes.yaml +28 -27
- package/dist/runtime/openclaw/scaffold-assets/CLAUDE.md +0 -5
- package/dist/runtime/picoclaw/scaffold-assets/CLAUDE.md +0 -5
- /package/dist/runtime/openclaw/scaffold-assets/{AGENTS.md → WORKSPACE_AGENTS.md} +0 -0
- /package/dist/runtime/picoclaw/scaffold-assets/{AGENTS.md → WORKSPACE_AGENTS.md} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type LifecycleAdmission, type LifecycleAmbiguousReason, type LifecycleCompletion, type LifecycleInvocation, type LifecycleOwnerCapability } from "./lifecycleCompletionContracts.js";
|
|
2
|
+
interface RecoveryStorage {
|
|
3
|
+
exactAdmission: (invocation: LifecycleInvocation) => Promise<LifecycleAdmission | null>;
|
|
4
|
+
exactCompletion: (invocation: LifecycleInvocation) => Promise<LifecycleCompletion | null>;
|
|
5
|
+
publish: (invocation: LifecycleInvocation, kind: "completion" | "recovery", content: string) => Promise<boolean>;
|
|
6
|
+
readRecovery: (invocation: LifecycleInvocation) => Promise<string | null>;
|
|
7
|
+
readHeartbeat: (invocation: LifecycleInvocation) => Promise<{
|
|
8
|
+
epoch: string;
|
|
9
|
+
lease_expires_at: number;
|
|
10
|
+
} | null>;
|
|
11
|
+
}
|
|
12
|
+
export type LifecycleRecoveryClaim = {
|
|
13
|
+
capability: LifecycleOwnerCapability;
|
|
14
|
+
status: "owner";
|
|
15
|
+
} | {
|
|
16
|
+
status: "ambiguous" | "pending" | "replay";
|
|
17
|
+
};
|
|
18
|
+
export declare const materializeDeadRecoveryAmbiguous: (invocation: LifecycleInvocation, publish: RecoveryStorage["publish"]) => Promise<void>;
|
|
19
|
+
export declare const claimLifecycleRecoveryRecord: (invocation: LifecycleInvocation, storage: RecoveryStorage) => Promise<LifecycleRecoveryClaim>;
|
|
20
|
+
export declare const markLifecycleAmbiguousRecord: (invocation: LifecycleInvocation, reasonCode: LifecycleAmbiguousReason, capability: LifecycleOwnerCapability, storage: RecoveryStorage) => Promise<void>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { canonicalLifecycleJson, lifecycleAmbiguousSchema, lifecycleDigest, LIFECYCLE_TERMINAL_VERSION, } from "./lifecycleCompletionContracts.js";
|
|
2
|
+
import { assertLifecycleOwnerCapability, createLifecycleAdmission, lifecycleOwnerIsAlive, } from "./lifecycleCompletionOwner.js";
|
|
3
|
+
import { parseLifecycleAdmission } from "./lifecycleCompletionParsing.js";
|
|
4
|
+
const ambiguousTerminal = (invocation, reasonCode) => {
|
|
5
|
+
const ambiguous = lifecycleAmbiguousSchema.parse({
|
|
6
|
+
invocation_digest: lifecycleDigest(invocation),
|
|
7
|
+
reason_code: reasonCode,
|
|
8
|
+
version: "spawnfile.lifecycle-ambiguous.v1",
|
|
9
|
+
});
|
|
10
|
+
return `${canonicalLifecycleJson({
|
|
11
|
+
ambiguous,
|
|
12
|
+
status: "ambiguous",
|
|
13
|
+
version: LIFECYCLE_TERMINAL_VERSION,
|
|
14
|
+
})}\n`;
|
|
15
|
+
};
|
|
16
|
+
export const materializeDeadRecoveryAmbiguous = async (invocation, publish) => {
|
|
17
|
+
await publish(invocation, "completion", ambiguousTerminal(invocation, "recovery_owner_died"));
|
|
18
|
+
};
|
|
19
|
+
export const claimLifecycleRecoveryRecord = async (invocation, storage) => {
|
|
20
|
+
const stored = await storage.exactAdmission(invocation);
|
|
21
|
+
const completion = await storage.exactCompletion(invocation);
|
|
22
|
+
if (!stored)
|
|
23
|
+
throw new Error("missing admission");
|
|
24
|
+
if (completion)
|
|
25
|
+
return { status: "replay" };
|
|
26
|
+
if (lifecycleOwnerIsAlive(stored.owner, await storage.readHeartbeat(invocation)))
|
|
27
|
+
return { status: "pending" };
|
|
28
|
+
const recovery = createLifecycleAdmission(invocation);
|
|
29
|
+
if (await storage.publish(invocation, "recovery", `${canonicalLifecycleJson(recovery)}\n`))
|
|
30
|
+
return {
|
|
31
|
+
capability: { epoch: recovery.owner.epoch, role: "recovery" },
|
|
32
|
+
status: "owner",
|
|
33
|
+
};
|
|
34
|
+
const text = await storage.readRecovery(invocation);
|
|
35
|
+
if (text === null)
|
|
36
|
+
throw new Error("missing recovery owner");
|
|
37
|
+
const prior = parseLifecycleAdmission(text);
|
|
38
|
+
if (canonicalLifecycleJson(prior.invocation) !==
|
|
39
|
+
canonicalLifecycleJson(invocation))
|
|
40
|
+
throw new Error("invocation id drift");
|
|
41
|
+
if (lifecycleOwnerIsAlive(prior.owner, await storage.readHeartbeat(invocation)))
|
|
42
|
+
return { status: "pending" };
|
|
43
|
+
await materializeDeadRecoveryAmbiguous(invocation, storage.publish);
|
|
44
|
+
return { status: "ambiguous" };
|
|
45
|
+
};
|
|
46
|
+
export const markLifecycleAmbiguousRecord = async (invocation, reasonCode, capability, storage) => {
|
|
47
|
+
const admitted = await storage.exactAdmission(invocation);
|
|
48
|
+
if (!admitted)
|
|
49
|
+
throw new Error("missing admission");
|
|
50
|
+
const recoveryText = await storage.readRecovery(invocation);
|
|
51
|
+
const recovered = recoveryText ? parseLifecycleAdmission(recoveryText) : null;
|
|
52
|
+
assertLifecycleOwnerCapability(invocation, admitted, recovered, capability);
|
|
53
|
+
if (capability.role !== "recovery")
|
|
54
|
+
throw new Error("invalid owner capability");
|
|
55
|
+
await storage.publish(invocation, "completion", ambiguousTerminal(invocation, reasonCode));
|
|
56
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { open } from "node:fs/promises";
|
|
2
|
+
interface PathIdentity {
|
|
3
|
+
readonly dev: number;
|
|
4
|
+
readonly ino: number;
|
|
5
|
+
readonly path: string;
|
|
6
|
+
}
|
|
7
|
+
export interface LifecycleRootAuthority {
|
|
8
|
+
readonly canonicalHome: string;
|
|
9
|
+
readonly configuredHome: string;
|
|
10
|
+
readonly identities: readonly PathIdentity[];
|
|
11
|
+
readonly root: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const revalidateLifecycleRootAuthority: (authority: LifecycleRootAuthority) => Promise<void>;
|
|
14
|
+
export declare const validateLifecycleRoot: (create: boolean) => Promise<LifecycleRootAuthority | null>;
|
|
15
|
+
export declare const lifecycleRoot: () => Promise<string>;
|
|
16
|
+
export declare const existingLifecycleRoot: () => Promise<string | null>;
|
|
17
|
+
export declare const requireLifecycleRootAuthority: () => Promise<LifecycleRootAuthority>;
|
|
18
|
+
export declare const openLifecycleAuthorityRoot: (authority: LifecycleRootAuthority) => Promise<import("fs/promises").FileHandle>;
|
|
19
|
+
export declare const revalidateHeldLifecycleRoot: (authority: LifecycleRootAuthority, handle: Awaited<ReturnType<typeof open>>) => Promise<void>;
|
|
20
|
+
export declare const syncLifecycleDirectory: (directory: string) => Promise<void>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { lstat, mkdir, open, realpath } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { resolveSpawnfileHome } from "../auth/index.js";
|
|
5
|
+
import { failLifecycleStore } from "./lifecycleCompletionPaths.js";
|
|
6
|
+
const OWNER = process.getuid?.() ?? -1;
|
|
7
|
+
const authorities = new Map();
|
|
8
|
+
const chain = (value) => {
|
|
9
|
+
const parsed = path.parse(value);
|
|
10
|
+
const result = [parsed.root];
|
|
11
|
+
let current = parsed.root;
|
|
12
|
+
for (const part of value.slice(parsed.root.length).split(path.sep).filter(Boolean)) {
|
|
13
|
+
current = path.join(current, part);
|
|
14
|
+
result.push(current);
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
const isKnownDarwinAlias = async (value) => {
|
|
19
|
+
if (process.platform !== "darwin" || (value !== "/var" && value !== "/tmp"))
|
|
20
|
+
return false;
|
|
21
|
+
const resolved = await realpath(value).catch(() => "");
|
|
22
|
+
return resolved === (value === "/var" ? "/private/var" : "/private/tmp");
|
|
23
|
+
};
|
|
24
|
+
const validateConfiguredAliases = async (configuredHome, canonicalHome) => {
|
|
25
|
+
for (const value of chain(configuredHome)) {
|
|
26
|
+
const info = await lstat(value).catch(() => failLifecycleStore("unsafe root"));
|
|
27
|
+
if (info.isSymbolicLink()) {
|
|
28
|
+
if (info.uid !== 0 || (info.mode & 0o022) !== 0 || !(await isKnownDarwinAlias(value))) {
|
|
29
|
+
failLifecycleStore("unsafe root");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (!info.isDirectory()) {
|
|
33
|
+
failLifecycleStore("unsafe root");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if ((await realpath(configuredHome).catch(() => "")) !== canonicalHome) {
|
|
37
|
+
failLifecycleStore("root changed");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const captureCanonicalChain = async (canonicalHome, root) => {
|
|
41
|
+
const identities = [];
|
|
42
|
+
for (const value of chain(root)) {
|
|
43
|
+
const info = await lstat(value).catch(() => failLifecycleStore("unsafe root"));
|
|
44
|
+
const writable = (info.mode & 0o022) !== 0;
|
|
45
|
+
const stickyRootTemp = info.uid === 0 && writable && (info.mode & 0o1000) !== 0;
|
|
46
|
+
if (!info.isDirectory() ||
|
|
47
|
+
info.isSymbolicLink() ||
|
|
48
|
+
(info.uid !== OWNER && info.uid !== 0) ||
|
|
49
|
+
(writable && !stickyRootTemp))
|
|
50
|
+
failLifecycleStore("unsafe root");
|
|
51
|
+
if ((value === canonicalHome || value === root) &&
|
|
52
|
+
(info.uid !== OWNER || (info.mode & 0o777) !== 0o700))
|
|
53
|
+
failLifecycleStore("unsafe root");
|
|
54
|
+
identities.push({ dev: info.dev, ino: info.ino, path: value });
|
|
55
|
+
}
|
|
56
|
+
return identities;
|
|
57
|
+
};
|
|
58
|
+
const revalidateIdentities = async (identities) => {
|
|
59
|
+
for (const expected of identities) {
|
|
60
|
+
const current = await lstat(expected.path).catch(() => failLifecycleStore("root changed"));
|
|
61
|
+
const writable = (current.mode & 0o022) !== 0;
|
|
62
|
+
const stickyRootTemp = current.uid === 0 && writable && (current.mode & 0o1000) !== 0;
|
|
63
|
+
if (!current.isDirectory() ||
|
|
64
|
+
current.isSymbolicLink() ||
|
|
65
|
+
(current.uid !== OWNER && current.uid !== 0) ||
|
|
66
|
+
(writable && !stickyRootTemp))
|
|
67
|
+
failLifecycleStore("unsafe root");
|
|
68
|
+
if (current.dev !== expected.dev || current.ino !== expected.ino) {
|
|
69
|
+
failLifecycleStore("root changed");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const captureSafeExistingChain = async (value) => {
|
|
74
|
+
const identities = [];
|
|
75
|
+
for (const current of chain(value)) {
|
|
76
|
+
const info = await lstat(current).catch(() => failLifecycleStore("unsafe root"));
|
|
77
|
+
const writable = (info.mode & 0o022) !== 0;
|
|
78
|
+
const stickyRootTemp = info.uid === 0 && writable && (info.mode & 0o1000) !== 0;
|
|
79
|
+
if (!info.isDirectory() ||
|
|
80
|
+
info.isSymbolicLink() ||
|
|
81
|
+
(info.uid !== OWNER && info.uid !== 0) ||
|
|
82
|
+
(writable && !stickyRootTemp))
|
|
83
|
+
failLifecycleStore("unsafe root");
|
|
84
|
+
identities.push({ dev: info.dev, ino: info.ino, path: current });
|
|
85
|
+
}
|
|
86
|
+
return identities;
|
|
87
|
+
};
|
|
88
|
+
const resolveOrCreateConfiguredHome = async (configuredHome, create) => {
|
|
89
|
+
const logical = chain(configuredHome);
|
|
90
|
+
let existing = logical[0];
|
|
91
|
+
let missingAt = logical.length;
|
|
92
|
+
for (let index = 0; index < logical.length; index += 1) {
|
|
93
|
+
const current = logical[index];
|
|
94
|
+
let info;
|
|
95
|
+
try {
|
|
96
|
+
info = await lstat(current);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (error.code !== "ENOENT")
|
|
100
|
+
failLifecycleStore("unsafe root");
|
|
101
|
+
missingAt = index;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
if (info.isSymbolicLink()) {
|
|
105
|
+
if (info.uid !== 0 || (info.mode & 0o022) !== 0 || !(await isKnownDarwinAlias(current))) {
|
|
106
|
+
failLifecycleStore("unsafe root");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (!info.isDirectory()) {
|
|
110
|
+
failLifecycleStore("unsafe root");
|
|
111
|
+
}
|
|
112
|
+
existing = current;
|
|
113
|
+
}
|
|
114
|
+
if (missingAt === logical.length) {
|
|
115
|
+
return realpath(configuredHome).catch(() => failLifecycleStore("unsafe root"));
|
|
116
|
+
}
|
|
117
|
+
if (!create)
|
|
118
|
+
return null;
|
|
119
|
+
let canonicalParent = await realpath(existing).catch(() => failLifecycleStore("unsafe root"));
|
|
120
|
+
let identities = await captureSafeExistingChain(canonicalParent);
|
|
121
|
+
for (let index = missingAt; index < logical.length; index += 1) {
|
|
122
|
+
const name = path.basename(logical[index]);
|
|
123
|
+
const next = path.join(canonicalParent, name);
|
|
124
|
+
await revalidateIdentities(identities);
|
|
125
|
+
await mkdir(next, { mode: 0o700 }).catch((error) => {
|
|
126
|
+
if (error.code !== "EEXIST")
|
|
127
|
+
failLifecycleStore("unsafe root");
|
|
128
|
+
});
|
|
129
|
+
await revalidateIdentities(identities);
|
|
130
|
+
const created = await lstat(next).catch(() => failLifecycleStore("unsafe root"));
|
|
131
|
+
if (!created.isDirectory() ||
|
|
132
|
+
created.isSymbolicLink() ||
|
|
133
|
+
created.uid !== OWNER ||
|
|
134
|
+
(created.mode & 0o777) !== 0o700)
|
|
135
|
+
failLifecycleStore("unsafe root");
|
|
136
|
+
canonicalParent = next;
|
|
137
|
+
identities = [...identities, { dev: created.dev, ino: created.ino, path: next }];
|
|
138
|
+
}
|
|
139
|
+
return canonicalParent;
|
|
140
|
+
};
|
|
141
|
+
export const revalidateLifecycleRootAuthority = async (authority) => {
|
|
142
|
+
await validateConfiguredAliases(authority.configuredHome, authority.canonicalHome);
|
|
143
|
+
for (const expected of authority.identities) {
|
|
144
|
+
const current = await lstat(expected.path).catch(() => failLifecycleStore("root changed"));
|
|
145
|
+
const writable = (current.mode & 0o022) !== 0;
|
|
146
|
+
const stickyRootTemp = current.uid === 0 && writable && (current.mode & 0o1000) !== 0;
|
|
147
|
+
if (!current.isDirectory() ||
|
|
148
|
+
current.isSymbolicLink() ||
|
|
149
|
+
(current.uid !== OWNER && current.uid !== 0) ||
|
|
150
|
+
(writable && !stickyRootTemp) ||
|
|
151
|
+
((expected.path === authority.canonicalHome || expected.path === authority.root) &&
|
|
152
|
+
(current.uid !== OWNER || (current.mode & 0o777) !== 0o700)))
|
|
153
|
+
failLifecycleStore("unsafe root");
|
|
154
|
+
if (current.dev !== expected.dev || current.ino !== expected.ino) {
|
|
155
|
+
failLifecycleStore("root changed");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
export const validateLifecycleRoot = async (create) => {
|
|
160
|
+
const configuredHome = resolveSpawnfileHome();
|
|
161
|
+
const cached = authorities.get(configuredHome);
|
|
162
|
+
if (cached) {
|
|
163
|
+
await revalidateLifecycleRootAuthority(cached);
|
|
164
|
+
return cached;
|
|
165
|
+
}
|
|
166
|
+
const canonicalHome = await resolveOrCreateConfiguredHome(configuredHome, create);
|
|
167
|
+
if (canonicalHome === null)
|
|
168
|
+
return null;
|
|
169
|
+
await validateConfiguredAliases(configuredHome, canonicalHome);
|
|
170
|
+
const homeIdentities = await captureSafeExistingChain(canonicalHome);
|
|
171
|
+
const homeInfo = await lstat(canonicalHome).catch(() => failLifecycleStore("unsafe root"));
|
|
172
|
+
if (homeInfo.uid !== OWNER || (homeInfo.mode & 0o777) !== 0o700) {
|
|
173
|
+
failLifecycleStore("unsafe root");
|
|
174
|
+
}
|
|
175
|
+
const root = path.join(canonicalHome, "lifecycle-completions");
|
|
176
|
+
if (create) {
|
|
177
|
+
await revalidateIdentities(homeIdentities);
|
|
178
|
+
await mkdir(root, { mode: 0o700 }).catch((error) => {
|
|
179
|
+
if (error.code !== "EEXIST")
|
|
180
|
+
failLifecycleStore("unsafe root");
|
|
181
|
+
});
|
|
182
|
+
await revalidateIdentities(homeIdentities);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
try {
|
|
186
|
+
await lstat(root);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (error.code === "ENOENT")
|
|
190
|
+
return null;
|
|
191
|
+
failLifecycleStore("unsafe root");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const authority = {
|
|
195
|
+
canonicalHome,
|
|
196
|
+
configuredHome,
|
|
197
|
+
identities: await captureCanonicalChain(canonicalHome, root),
|
|
198
|
+
root
|
|
199
|
+
};
|
|
200
|
+
const prior = authorities.get(configuredHome);
|
|
201
|
+
if (prior) {
|
|
202
|
+
await revalidateLifecycleRootAuthority(prior);
|
|
203
|
+
return prior;
|
|
204
|
+
}
|
|
205
|
+
authorities.set(configuredHome, authority);
|
|
206
|
+
return authority;
|
|
207
|
+
};
|
|
208
|
+
export const lifecycleRoot = async () => (await validateLifecycleRoot(true))?.root ?? failLifecycleStore("unsafe root");
|
|
209
|
+
export const existingLifecycleRoot = async () => (await validateLifecycleRoot(false))?.root ?? null;
|
|
210
|
+
export const requireLifecycleRootAuthority = async () => (await validateLifecycleRoot(true)) ?? failLifecycleStore("unsafe root");
|
|
211
|
+
export const openLifecycleAuthorityRoot = async (authority) => {
|
|
212
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
213
|
+
const handle = await open(authority.root, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW).catch(() => failLifecycleStore("root changed"));
|
|
214
|
+
const expected = authority.identities.at(-1);
|
|
215
|
+
const info = await handle.stat();
|
|
216
|
+
if (info.dev !== expected.dev || info.ino !== expected.ino) {
|
|
217
|
+
await handle.close().catch(() => undefined);
|
|
218
|
+
failLifecycleStore("root changed");
|
|
219
|
+
}
|
|
220
|
+
return handle;
|
|
221
|
+
};
|
|
222
|
+
export const revalidateHeldLifecycleRoot = async (authority, handle) => {
|
|
223
|
+
const expected = authority.identities.at(-1);
|
|
224
|
+
const info = await handle.stat();
|
|
225
|
+
if (info.dev !== expected.dev || info.ino !== expected.ino)
|
|
226
|
+
failLifecycleStore("root changed");
|
|
227
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
228
|
+
};
|
|
229
|
+
export const syncLifecycleDirectory = async (directory) => {
|
|
230
|
+
const authority = await requireLifecycleRootAuthority();
|
|
231
|
+
if (path.resolve(directory) !== authority.root)
|
|
232
|
+
failLifecycleStore("unsafe root");
|
|
233
|
+
const handle = await openLifecycleAuthorityRoot(authority);
|
|
234
|
+
try {
|
|
235
|
+
await revalidateHeldLifecycleRoot(authority, handle);
|
|
236
|
+
await handle.sync();
|
|
237
|
+
await revalidateHeldLifecycleRoot(authority, handle);
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
await handle.close();
|
|
241
|
+
}
|
|
242
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
243
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { admissionPath, evidencePath, failLifecycleStore, heartbeatPath, lifecycleRecordName, planPath, recoveryPath, resolveLifecycleCompletionDirectory, resolveLifecycleCompletionPath } from "./lifecycleCompletionPaths.js";
|
|
2
|
+
export { existingLifecycleRoot, lifecycleRoot, syncLifecycleDirectory } from "./lifecycleCompletionRoot.js";
|
|
3
|
+
export type LifecycleStoreTestHookPoint = "before_missing_return" | "before_record_open" | "before_publish_link" | "before_publish_temp_open" | "before_publish_unlink";
|
|
4
|
+
export declare const setLifecycleStoreTestHook: (hook: ((point: LifecycleStoreTestHookPoint) => Promise<void> | void) | null) => void;
|
|
5
|
+
export declare const readLifecycleRecord: (file: string, links?: readonly number[]) => Promise<string | null>;
|
|
6
|
+
export declare const publishLifecycleRecord: (directory: string, file: string, content: string, existing?: "ignore" | "match") => Promise<boolean>;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { link, lstat, open, unlink } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { LIFECYCLE_RECORD_MAX_BYTES } from "./lifecycleCompletionContracts.js";
|
|
6
|
+
import { failLifecycleStore, resolveLifecycleCompletionDirectory } from "./lifecycleCompletionPaths.js";
|
|
7
|
+
import { openLifecycleAuthorityRoot, requireLifecycleRootAuthority, revalidateHeldLifecycleRoot, revalidateLifecycleRootAuthority, syncLifecycleDirectory, validateLifecycleRoot } from "./lifecycleCompletionRoot.js";
|
|
8
|
+
import { matchesSettledLifecyclePublication, readSettledLifecycleRecord } from "./lifecycleCompletionPublication.js";
|
|
9
|
+
export { admissionPath, evidencePath, failLifecycleStore, heartbeatPath, lifecycleRecordName, planPath, recoveryPath, resolveLifecycleCompletionDirectory, resolveLifecycleCompletionPath } from "./lifecycleCompletionPaths.js";
|
|
10
|
+
export { existingLifecycleRoot, lifecycleRoot, syncLifecycleDirectory } from "./lifecycleCompletionRoot.js";
|
|
11
|
+
const OWNER = process.getuid?.() ?? -1;
|
|
12
|
+
let testHook = null;
|
|
13
|
+
export const setLifecycleStoreTestHook = (hook) => {
|
|
14
|
+
testHook = hook;
|
|
15
|
+
};
|
|
16
|
+
const runTestHook = async (point) => {
|
|
17
|
+
await testHook?.(point);
|
|
18
|
+
};
|
|
19
|
+
const canonicalRecordPath = (file, authority) => {
|
|
20
|
+
const directory = path.dirname(path.resolve(file));
|
|
21
|
+
const configuredRoot = resolveLifecycleCompletionDirectory();
|
|
22
|
+
if (directory !== authority.root && directory !== configuredRoot) {
|
|
23
|
+
failLifecycleStore("unsafe record");
|
|
24
|
+
}
|
|
25
|
+
const base = path.basename(file);
|
|
26
|
+
if (base.includes(path.sep) || base === "." || base === "..") {
|
|
27
|
+
failLifecycleStore("unsafe record");
|
|
28
|
+
}
|
|
29
|
+
return path.join(authority.root, base);
|
|
30
|
+
};
|
|
31
|
+
export const readLifecycleRecord = async (file, links = [1]) => {
|
|
32
|
+
const authority = await validateLifecycleRoot(false);
|
|
33
|
+
if (!authority)
|
|
34
|
+
return null;
|
|
35
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
36
|
+
const exactFile = canonicalRecordPath(file, authority);
|
|
37
|
+
let before;
|
|
38
|
+
try {
|
|
39
|
+
before = await lstat(exactFile);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.code === "ENOENT") {
|
|
43
|
+
await runTestHook("before_missing_return");
|
|
44
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
failLifecycleStore("unsafe record");
|
|
48
|
+
}
|
|
49
|
+
if (!before.isFile() || before.isSymbolicLink() || before.uid !== OWNER ||
|
|
50
|
+
before.size > LIFECYCLE_RECORD_MAX_BYTES || (before.mode & 0o777) !== 0o600 ||
|
|
51
|
+
!links.includes(before.nlink)) {
|
|
52
|
+
failLifecycleStore("unsafe record");
|
|
53
|
+
}
|
|
54
|
+
await runTestHook("before_record_open");
|
|
55
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
56
|
+
const handle = await open(exactFile, constants.O_RDONLY | constants.O_NOFOLLOW)
|
|
57
|
+
.catch(() => failLifecycleStore("unsafe record"));
|
|
58
|
+
try {
|
|
59
|
+
const info = await handle.stat();
|
|
60
|
+
if (!info.isFile() || info.uid !== OWNER || info.size > LIFECYCLE_RECORD_MAX_BYTES ||
|
|
61
|
+
(info.mode & 0o777) !== 0o600 || !links.includes(info.nlink)) {
|
|
62
|
+
failLifecycleStore("unsafe record");
|
|
63
|
+
}
|
|
64
|
+
if (before.dev !== info.dev || before.ino !== info.ino)
|
|
65
|
+
failLifecycleStore("record changed");
|
|
66
|
+
const content = await handle.readFile({ encoding: "utf8" });
|
|
67
|
+
const after = await lstat(exactFile).catch(() => failLifecycleStore("record changed"));
|
|
68
|
+
if (after.dev !== info.dev || after.ino !== info.ino)
|
|
69
|
+
failLifecycleStore("record changed");
|
|
70
|
+
await revalidateLifecycleRootAuthority(authority);
|
|
71
|
+
return content;
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
await handle.close().catch(() => undefined);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
export const publishLifecycleRecord = async (directory, file, content, existing = "match") => {
|
|
78
|
+
const authority = await requireLifecycleRootAuthority();
|
|
79
|
+
if (path.resolve(directory) !== authority.root)
|
|
80
|
+
failLifecycleStore("unsafe root");
|
|
81
|
+
const rootHandle = await openLifecycleAuthorityRoot(authority);
|
|
82
|
+
try {
|
|
83
|
+
if (Buffer.byteLength(content) > LIFECYCLE_RECORD_MAX_BYTES) {
|
|
84
|
+
failLifecycleStore("oversize record");
|
|
85
|
+
}
|
|
86
|
+
const final = path.join(authority.root, file);
|
|
87
|
+
if (existing === "match") {
|
|
88
|
+
if (await matchesSettledLifecyclePublication(final, content, readLifecycleRecord))
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
else if ((await readSettledLifecycleRecord(final, readLifecycleRecord)) !== null) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const temp = path.join(authority.root, `.${file}.${process.pid}.${randomUUID()}.tmp`);
|
|
95
|
+
let handle;
|
|
96
|
+
let linked = false;
|
|
97
|
+
try {
|
|
98
|
+
await runTestHook("before_publish_temp_open");
|
|
99
|
+
await revalidateHeldLifecycleRoot(authority, rootHandle);
|
|
100
|
+
handle = await open(temp, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | constants.O_NOFOLLOW, 0o600);
|
|
101
|
+
await handle.chmod(0o600);
|
|
102
|
+
await handle.writeFile(content, "utf8");
|
|
103
|
+
await handle.sync();
|
|
104
|
+
await handle.close();
|
|
105
|
+
handle = undefined;
|
|
106
|
+
try {
|
|
107
|
+
await runTestHook("before_publish_link");
|
|
108
|
+
await revalidateHeldLifecycleRoot(authority, rootHandle);
|
|
109
|
+
await link(temp, final);
|
|
110
|
+
linked = true;
|
|
111
|
+
await syncLifecycleDirectory(authority.root);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (error.code !== "EEXIST") {
|
|
115
|
+
failLifecycleStore("publication failed");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
if (handle)
|
|
121
|
+
await handle.close().catch(() => undefined);
|
|
122
|
+
await runTestHook("before_publish_unlink");
|
|
123
|
+
await revalidateHeldLifecycleRoot(authority, rootHandle);
|
|
124
|
+
await unlink(temp).catch((error) => {
|
|
125
|
+
if (error.code !== "ENOENT")
|
|
126
|
+
failLifecycleStore("publication cleanup failed");
|
|
127
|
+
});
|
|
128
|
+
await syncLifecycleDirectory(authority.root);
|
|
129
|
+
}
|
|
130
|
+
if (!linked && existing === "ignore") {
|
|
131
|
+
if ((await readSettledLifecycleRecord(final, readLifecycleRecord)) === null) {
|
|
132
|
+
failLifecycleStore("publication changed");
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
for (let attempt = 0; attempt < 16; attempt += 1) {
|
|
137
|
+
const exact = await readLifecycleRecord(final, [1, 2]);
|
|
138
|
+
if (exact !== content)
|
|
139
|
+
failLifecycleStore("publication changed");
|
|
140
|
+
if ((await lstat(final).catch(() => null))?.nlink === 1) {
|
|
141
|
+
await revalidateHeldLifecycleRoot(authority, rootHandle);
|
|
142
|
+
return linked;
|
|
143
|
+
}
|
|
144
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
145
|
+
}
|
|
146
|
+
return failLifecycleStore("publication did not settle");
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
await rootHandle.close().catch(() => undefined);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
export interface OrganizationHandoffAuthorityFsClientOptions {
|
|
3
|
+
readonly cwd: string;
|
|
4
|
+
readonly dev: number;
|
|
5
|
+
readonly ino: number;
|
|
6
|
+
readonly parentPid?: number;
|
|
7
|
+
readonly uid?: number;
|
|
8
|
+
readonly workerPath?: string;
|
|
9
|
+
readonly testOnChildStarted?: (child: ChildProcess) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface OrganizationHandoffAuthorityFsClient {
|
|
12
|
+
create(name: string, content: string): Promise<boolean>;
|
|
13
|
+
dispose(): Promise<void>;
|
|
14
|
+
read(name: string): Promise<string | null>;
|
|
15
|
+
write(name: string, content: string): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare const initializeOrganizationHandoffAuthorityFsClient: (options: OrganizationHandoffAuthorityFsClientOptions) => Promise<OrganizationHandoffAuthorityFsClient>;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { fork } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const VERSION = "spawnfile.organization-handoff-fs-worker.v1";
|
|
5
|
+
const MAX_BYTES = 32_768;
|
|
6
|
+
const fail = () => { throw new Error("Organization handoff authority failed"); };
|
|
7
|
+
const bytes = (value) => Buffer.byteLength(value, "utf8");
|
|
8
|
+
const name = (value) => typeof value === "string" && /^(?:[a-f0-9]{128}|[a-f0-9]{142})\.json$/u.test(value) ? value : fail();
|
|
9
|
+
class Client {
|
|
10
|
+
#child;
|
|
11
|
+
#closed = false;
|
|
12
|
+
#next = 1;
|
|
13
|
+
#exited;
|
|
14
|
+
#pending = new Map();
|
|
15
|
+
constructor(child) {
|
|
16
|
+
this.#child = child;
|
|
17
|
+
let settleExit;
|
|
18
|
+
this.#exited = new Promise((resolve) => { settleExit = resolve; });
|
|
19
|
+
const settle = () => { this.rejectPending(); settleExit(); };
|
|
20
|
+
child.on("message", (raw) => this.message(raw));
|
|
21
|
+
child.on("error", () => this.rejectPending());
|
|
22
|
+
child.on("disconnect", () => this.rejectPending());
|
|
23
|
+
child.once("exit", settle);
|
|
24
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
25
|
+
settle();
|
|
26
|
+
// `fork(..., { silent: true })` creates pipes. Consume them so a failing
|
|
27
|
+
// helper cannot block on a full pipe or accumulate stream listeners.
|
|
28
|
+
child.stdout?.resume();
|
|
29
|
+
child.stderr?.resume();
|
|
30
|
+
}
|
|
31
|
+
terminal() { return this.#child.exitCode !== null || this.#child.signalCode !== null; }
|
|
32
|
+
rejectPending() { for (const pending of this.#pending.values())
|
|
33
|
+
pending.reject(); this.#pending.clear(); }
|
|
34
|
+
message(raw) {
|
|
35
|
+
if (!raw || typeof raw !== "object")
|
|
36
|
+
return;
|
|
37
|
+
const value = raw;
|
|
38
|
+
if (value.version !== VERSION)
|
|
39
|
+
return;
|
|
40
|
+
if (value.ready === true)
|
|
41
|
+
return;
|
|
42
|
+
if (!Number.isSafeInteger(value.id) || typeof value.ok !== "boolean")
|
|
43
|
+
return;
|
|
44
|
+
const pending = this.#pending.get(value.id);
|
|
45
|
+
if (!pending)
|
|
46
|
+
return;
|
|
47
|
+
this.#pending.delete(value.id);
|
|
48
|
+
if (value.ok !== true || value.content !== undefined && typeof value.content !== "string"
|
|
49
|
+
|| value.created !== undefined && typeof value.created !== "boolean")
|
|
50
|
+
pending.reject();
|
|
51
|
+
else
|
|
52
|
+
pending.resolve(value);
|
|
53
|
+
}
|
|
54
|
+
request(op, file, content) {
|
|
55
|
+
if (this.#closed || content !== undefined && bytes(content) > MAX_BYTES)
|
|
56
|
+
return Promise.reject(new Error("Organization handoff authority failed"));
|
|
57
|
+
const id = this.#next++;
|
|
58
|
+
const packet = { version: VERSION, id, op, name: name(file), ...(content === undefined ? {} : { content }) };
|
|
59
|
+
if (bytes(JSON.stringify(packet)) > MAX_BYTES)
|
|
60
|
+
return Promise.reject(new Error("Organization handoff authority failed"));
|
|
61
|
+
return new Promise((resolve, reject) => { const timer = setTimeout(() => { this.#pending.delete(id); reject(new Error("Organization handoff authority failed")); }, 3_000); this.#pending.set(id, { resolve: (value) => { clearTimeout(timer); resolve(value); }, reject: () => { clearTimeout(timer); reject(new Error("Organization handoff authority failed")); } }); if (!this.#child.send(packet)) {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
this.#pending.delete(id);
|
|
64
|
+
reject(new Error("Organization handoff authority failed"));
|
|
65
|
+
} });
|
|
66
|
+
}
|
|
67
|
+
async create(file, content) {
|
|
68
|
+
const result = await this.request("create", file, content);
|
|
69
|
+
return result.created === true;
|
|
70
|
+
}
|
|
71
|
+
async read(file) { return (await this.request("read", file)).content ?? null; }
|
|
72
|
+
async write(file, content) { await this.request("write", file, content); }
|
|
73
|
+
async dispose() {
|
|
74
|
+
if (this.#closed)
|
|
75
|
+
return;
|
|
76
|
+
this.#closed = true;
|
|
77
|
+
this.rejectPending();
|
|
78
|
+
if (!this.terminal()) {
|
|
79
|
+
if (this.#child.connected) {
|
|
80
|
+
try {
|
|
81
|
+
this.#child.disconnect();
|
|
82
|
+
}
|
|
83
|
+
catch { /* already disconnected */ }
|
|
84
|
+
}
|
|
85
|
+
this.#child.kill();
|
|
86
|
+
}
|
|
87
|
+
let clear;
|
|
88
|
+
const graceful = await Promise.race([this.#exited.then(() => true), new Promise((resolve) => {
|
|
89
|
+
const timer = setTimeout(() => resolve(false), 1_000);
|
|
90
|
+
clear = () => clearTimeout(timer);
|
|
91
|
+
})]);
|
|
92
|
+
clear?.();
|
|
93
|
+
if (!graceful && !this.terminal())
|
|
94
|
+
this.#child.kill("SIGKILL");
|
|
95
|
+
await this.#exited;
|
|
96
|
+
this.#child.stdout?.destroy();
|
|
97
|
+
this.#child.stderr?.destroy();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export const initializeOrganizationHandoffAuthorityFsClient = async (options) => {
|
|
101
|
+
const source = import.meta.url.endsWith(".ts");
|
|
102
|
+
const workerPath = options.workerPath ?? fileURLToPath(new URL(source ? "./organizationHandoffAuthorityFsWorker.ts" : "./organizationHandoffAuthorityFsWorker.js", import.meta.url));
|
|
103
|
+
const tsWorker = workerPath.endsWith(".ts");
|
|
104
|
+
// The helper's cwd is the protected state directory, which is intentionally
|
|
105
|
+
// outside the repository. Resolve the source loader before changing cwd so
|
|
106
|
+
// source-mode tests do not depend on module lookup from that directory.
|
|
107
|
+
const tsxLoader = tsWorker ? createRequire(import.meta.url).resolve("tsx") : undefined;
|
|
108
|
+
const child = fork(workerPath, [], { cwd: options.cwd, env: { SPAWNFILE_AUTHORITY_FS_ANCHOR: JSON.stringify({ dev: options.dev, ino: options.ino, uid: options.uid, parent_pid: options.parentPid ?? process.pid }) }, silent: true, ...(tsxLoader === undefined ? {} : { execArgv: ["--import", tsxLoader] }) });
|
|
109
|
+
const client = new Client(child);
|
|
110
|
+
options.testOnChildStarted?.(child);
|
|
111
|
+
try {
|
|
112
|
+
await new Promise((resolve, reject) => {
|
|
113
|
+
let timer;
|
|
114
|
+
const message = (raw) => { if (typeof raw === "object" && raw !== null && raw.ready === true)
|
|
115
|
+
doneResolve(); };
|
|
116
|
+
const exited = () => doneReject();
|
|
117
|
+
const errored = () => doneReject();
|
|
118
|
+
const clean = () => { clearTimeout(timer); child.off("message", message); child.off("exit", exited); child.off("error", errored); };
|
|
119
|
+
function doneResolve() { clean(); resolve(); }
|
|
120
|
+
function doneReject() { clean(); reject(new Error("Organization handoff authority failed")); }
|
|
121
|
+
timer = setTimeout(doneReject, 3_000);
|
|
122
|
+
child.on("message", message);
|
|
123
|
+
child.once("exit", exited);
|
|
124
|
+
child.once("error", errored);
|
|
125
|
+
});
|
|
126
|
+
return client;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
await client.dispose();
|
|
130
|
+
return fail();
|
|
131
|
+
}
|
|
132
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|