@intx/hub-sessions 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +176 -0
- package/README.md +82 -1
- package/dist/agent-repo.d.ts +93 -0
- package/dist/agent-repo.js +109 -0
- package/dist/agent-state-kind.d.ts +12 -0
- package/dist/agent-state-kind.js +189 -0
- package/dist/asset-service.d.ts +104 -0
- package/dist/asset-service.js +267 -0
- package/dist/committed-source-tree.d.ts +10 -0
- package/dist/committed-source-tree.js +35 -0
- package/dist/credential-push.d.ts +33 -0
- package/dist/credential-push.js +109 -0
- package/dist/event-collector-registry.d.ts +20 -0
- package/dist/event-collector-registry.js +115 -0
- package/dist/event-collector.d.ts +39 -0
- package/dist/event-collector.js +365 -0
- package/dist/hub-session-lookups.d.ts +135 -0
- package/dist/hub-session-lookups.js +663 -0
- package/dist/hub-session-orchestrator.d.ts +25 -0
- package/dist/hub-session-orchestrator.js +87 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +24 -0
- package/dist/package-registry-kind.d.ts +70 -0
- package/dist/package-registry-kind.js +260 -0
- package/dist/repo-store/index.d.ts +4 -0
- package/dist/repo-store/index.js +3 -0
- package/dist/repo-store/store.d.ts +41 -0
- package/dist/repo-store/store.js +1829 -0
- package/dist/repo-store/subscribe-kind.d.ts +56 -0
- package/dist/repo-store/subscribe-kind.js +144 -0
- package/dist/repo-store/types.d.ts +571 -0
- package/dist/repo-store/types.js +42 -0
- package/dist/session-service.d.ts +416 -0
- package/dist/session-service.js +1191 -0
- package/dist/sidecar-allocation/contracts.d.ts +78 -0
- package/dist/sidecar-allocation/contracts.js +21 -0
- package/dist/sidecar-allocation/index.d.ts +4 -0
- package/dist/sidecar-allocation/index.js +3 -0
- package/dist/sidecar-allocation/placement-policy.d.ts +11 -0
- package/dist/sidecar-allocation/placement-policy.js +21 -0
- package/dist/sidecar-allocation/plugin-registry.d.ts +11 -0
- package/dist/sidecar-allocation/plugin-registry.js +37 -0
- package/dist/sidecar-allocation/reconciler.d.ts +42 -0
- package/dist/sidecar-allocation/reconciler.js +431 -0
- package/dist/skill-kind.d.ts +41 -0
- package/dist/skill-kind.js +292 -0
- package/dist/substrate.d.ts +8 -0
- package/dist/substrate.js +21 -0
- package/dist/workflow-allocation-service.d.ts +58 -0
- package/dist/workflow-allocation-service.js +239 -0
- package/dist/workflow-closure-resolution.d.ts +106 -0
- package/dist/workflow-closure-resolution.js +123 -0
- package/dist/workflow-definition-ensure.d.ts +24 -0
- package/dist/workflow-definition-ensure.js +75 -0
- package/dist/workflow-dispatch-service.d.ts +40 -0
- package/dist/workflow-dispatch-service.js +146 -0
- package/dist/workflow-dispatch-settlement.d.ts +29 -0
- package/dist/workflow-dispatch-settlement.js +140 -0
- package/dist/workflow-kind.d.ts +37 -0
- package/dist/workflow-kind.js +310 -0
- package/dist/workflow-probe-gate.d.ts +214 -0
- package/dist/workflow-probe-gate.js +207 -0
- package/dist/workflow-run-event-log.d.ts +21 -0
- package/dist/workflow-run-event-log.js +51 -0
- package/dist/workflow-run-kind.d.ts +440 -0
- package/dist/workflow-run-kind.js +2916 -0
- package/dist/workflow-run-reader.d.ts +47 -0
- package/dist/workflow-run-reader.js +153 -0
- package/dist/workflow-run-restore.d.ts +15 -0
- package/dist/workflow-run-restore.js +26 -0
- package/dist/workflow-source-closure.d.ts +35 -0
- package/dist/workflow-source-closure.js +342 -0
- package/dist/ws/index.d.ts +3 -0
- package/dist/ws/index.js +3 -0
- package/dist/ws/sidecar-events.d.ts +222 -0
- package/dist/ws/sidecar-events.js +72 -0
- package/dist/ws/sidecar-handler.d.ts +305 -0
- package/dist/ws/sidecar-handler.js +2537 -0
- package/dist/ws/sidecar-token-authenticator.d.ts +17 -0
- package/dist/ws/sidecar-token-authenticator.js +81 -0
- package/package.json +35 -12
- package/src/agent-repo.test.ts +0 -310
- package/src/agent-repo.ts +0 -165
- package/src/agent-state-kind.test.ts +0 -247
- package/src/agent-state-kind.ts +0 -204
- package/src/asset-service.test.ts +0 -540
- package/src/asset-service.ts +0 -378
- package/src/available-skills-stanza.test.ts +0 -87
- package/src/available-skills-stanza.ts +0 -47
- package/src/credential-push.ts +0 -65
- package/src/event-collector-registry.test.ts +0 -73
- package/src/event-collector-registry.ts +0 -171
- package/src/event-collector.test.ts +0 -1387
- package/src/event-collector.ts +0 -424
- package/src/hub-session-lookups.ts +0 -206
- package/src/hub-session-orchestrator.test.ts +0 -510
- package/src/hub-session-orchestrator.ts +0 -213
- package/src/index.ts +0 -78
- package/src/repo-store/index.ts +0 -15
- package/src/repo-store/store.test.ts +0 -1169
- package/src/repo-store/store.ts +0 -428
- package/src/repo-store/types.ts +0 -253
- package/src/session-service.test.ts +0 -895
- package/src/session-service.ts +0 -464
- package/src/skill-kind.test.ts +0 -599
- package/src/skill-kind.ts +0 -350
- package/src/ws/index.ts +0 -18
- package/src/ws/sidecar-events.test.ts +0 -96
- package/src/ws/sidecar-events.ts +0 -231
- package/src/ws/sidecar-handler.test.ts +0 -2217
- package/src/ws/sidecar-handler.ts +0 -1574
- package/tsconfig.json +0 -4
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DB } from "@intx/db";
|
|
2
|
+
import type { AgentRepoStore } from "./agent-repo.js";
|
|
3
|
+
import type { EventCollectorRegistry } from "./event-collector-registry.js";
|
|
4
|
+
import type { SidecarEventEmitter } from "./ws/sidecar-events.js";
|
|
5
|
+
/** Subset of `SidecarRouter` the orchestrator drives outbound. The
|
|
6
|
+
* narrow surface keeps tests honest and decouples the orchestrator
|
|
7
|
+
* from the rest of the router API. */
|
|
8
|
+
export type HubSessionRouterFacade = {
|
|
9
|
+
sendPack(agentAddress: string, pack: Uint8Array, ref: string, commitSha: string): Promise<void>;
|
|
10
|
+
dispatchAgentEvent(agentAddress: string, event: unknown): void;
|
|
11
|
+
};
|
|
12
|
+
export type HubSessionOrchestratorDeps = {
|
|
13
|
+
events: SidecarEventEmitter;
|
|
14
|
+
router: HubSessionRouterFacade;
|
|
15
|
+
db: DB["db"];
|
|
16
|
+
eventCollectors: EventCollectorRegistry;
|
|
17
|
+
agentRepoStore: AgentRepoStore;
|
|
18
|
+
};
|
|
19
|
+
export type HubSessionOrchestrator = {
|
|
20
|
+
/** Unsubscribe all listeners. Tests use this between cases; the hub
|
|
21
|
+
* application doesn't need to dispose because the orchestrator's
|
|
22
|
+
* lifetime matches the process. */
|
|
23
|
+
dispose(): void;
|
|
24
|
+
};
|
|
25
|
+
export declare function createHubSessionOrchestrator(deps: HubSessionOrchestratorDeps): HubSessionOrchestrator;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Hub-side orchestrator for the sidecar event emitter.
|
|
2
|
+
//
|
|
3
|
+
// Subscribes to the sidecar router's events and runs the host-side
|
|
4
|
+
// reactions: dispatching inference events to the event collector,
|
|
5
|
+
// restoring the event collector on reconnect, re-deploying stale
|
|
6
|
+
// agents, and forwarding mail.delivered notifications back to
|
|
7
|
+
// subscribers.
|
|
8
|
+
//
|
|
9
|
+
// The orchestrator depends on a narrow `HubSessionRouterFacade` rather
|
|
10
|
+
// than the full SidecarRouter, so tests can drive subscriber behavior
|
|
11
|
+
// with a small stub and an isolated emitter.
|
|
12
|
+
import { eq } from "drizzle-orm";
|
|
13
|
+
import { type } from "arktype";
|
|
14
|
+
import { workflowRun } from "@intx/db/schema";
|
|
15
|
+
import { parseMailToEmail } from "@intx/mime";
|
|
16
|
+
import { parseInferenceEvent } from "@intx/types/runtime";
|
|
17
|
+
import { getLogger } from "@intx/log";
|
|
18
|
+
import { parseAgentId } from "./hub-session-lookups.js";
|
|
19
|
+
const log = getLogger(["hub", "orchestrator"]);
|
|
20
|
+
export function createHubSessionOrchestrator(deps) {
|
|
21
|
+
const { events, router, db, eventCollectors, agentRepoStore } = deps;
|
|
22
|
+
const unsubscribers = [];
|
|
23
|
+
unsubscribers.push(events.on("agent.event", ({ agentAddress, event }) => {
|
|
24
|
+
const validated = parseInferenceEvent(event);
|
|
25
|
+
if (validated instanceof type.errors) {
|
|
26
|
+
log.warn("Received invalid agent event for {agentAddress}: {summary}", {
|
|
27
|
+
agentAddress,
|
|
28
|
+
summary: validated.summary,
|
|
29
|
+
});
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
eventCollectors.dispatch(agentAddress, validated);
|
|
33
|
+
}));
|
|
34
|
+
unsubscribers.push(events.on("sidecar.disconnect", ({ ownedAddresses }) => {
|
|
35
|
+
for (const addr of ownedAddresses) {
|
|
36
|
+
eventCollectors.abandon(addr);
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
39
|
+
unsubscribers.push(events.on("mail.outbound.undelivered", ({ recipients }) => {
|
|
40
|
+
// The hub has no external mail transport today. Anything that
|
|
41
|
+
// could not be delivered locally or queued for a disconnected
|
|
42
|
+
// agent is dropped; log so operators can see it.
|
|
43
|
+
log.warn("Dropping mail with no local recipient: {recipients}", {
|
|
44
|
+
recipients: recipients.join(", "),
|
|
45
|
+
});
|
|
46
|
+
}));
|
|
47
|
+
unsubscribers.push(events.on("agent.deploy.ack", async (event) => {
|
|
48
|
+
const { agentAddress, publicKey, allocated } = event;
|
|
49
|
+
// Exclusive initialization publishes its key only after every deploy
|
|
50
|
+
// and asset pack succeeds under the allocation generation fence.
|
|
51
|
+
if (allocated !== undefined)
|
|
52
|
+
return;
|
|
53
|
+
// Every deploy address names a workflow run whose public key lives on its
|
|
54
|
+
// single self-anchored workflow_run row, keyed by address. Persist it
|
|
55
|
+
// there so the reconnect ownership challenge can verify the address off
|
|
56
|
+
// the same row `lookupPublicKey` reads. Only the deployment-level address
|
|
57
|
+
// owns a row, so a stray per-step ack updates nothing.
|
|
58
|
+
await db
|
|
59
|
+
.update(workflowRun)
|
|
60
|
+
.set({ publicKey })
|
|
61
|
+
.where(eq(workflowRun.address, agentAddress));
|
|
62
|
+
}));
|
|
63
|
+
unsubscribers.push(events.on("deploy.ref.stale", async ({ agentAddress }) => {
|
|
64
|
+
const agentId = parseAgentId(agentAddress);
|
|
65
|
+
const { pack, commitSha, ref } = await agentRepoStore.createDeployPack(agentId);
|
|
66
|
+
await router.sendPack(agentAddress, pack, ref, commitSha);
|
|
67
|
+
log.info("Re-deployed stale agent {agentAddress}", { agentAddress });
|
|
68
|
+
}));
|
|
69
|
+
unsubscribers.push(events.on("mail.persisted", (row) => {
|
|
70
|
+
const parsed = parseMailToEmail(row.raw, row.id);
|
|
71
|
+
router.dispatchAgentEvent(row.address, {
|
|
72
|
+
type: "mail.delivered",
|
|
73
|
+
data: {
|
|
74
|
+
...parsed,
|
|
75
|
+
id: row.id,
|
|
76
|
+
direction: row.direction,
|
|
77
|
+
receivedAt: row.createdAt.toISOString(),
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}));
|
|
81
|
+
return {
|
|
82
|
+
dispose() {
|
|
83
|
+
for (const off of unsubscribers)
|
|
84
|
+
off();
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export { createAgentRepoStore, type AgentRepoStore, type DeployContent, } from "./agent-repo.js";
|
|
2
|
+
export { createSessionService, SessionLaunchError, bridgeOrchestratorDeployContent, deployCodeSourcedWorkflow, type SessionService, type DeployWorkflowDefinitionResult, type DeployWorkflowFromSourceParams, type DeployPreparedCodeSourcedWorkflowParams, type InstallAndApproveWorkflowSourceParams, type PreparedWorkflowDeployer, type DeployCodeSourcedWorkflowArgs, } from "./session-service.js";
|
|
3
|
+
export { installAndApproveWorkflowDefinition, createDbFrozenApprovalWriter, type InstallAndApproveArgs, type InstallAndApproveResult, type ProbeGateResult, type ProbeApprovalPolicy, type ApproveProbedGrants, } from "./workflow-probe-gate.js";
|
|
4
|
+
export { committedReadsToSourceTree } from "./committed-source-tree.js";
|
|
5
|
+
export type { SourceTreeReads } from "./workflow-source-closure.js";
|
|
6
|
+
export type { WorkflowDefinition } from "@intx/workflow/definition";
|
|
7
|
+
export { createEventCollectorRegistry, type EventCollectorRegistry, } from "./event-collector-registry.js";
|
|
8
|
+
export { createSidecarRouter, type SidecarRouter, type SidecarRouterConfig, type SidecarAuthIdentity, type SidecarAuthenticator, type AllocatedSidecarTarget, type SidecarAllocationRouter, createSidecarCredentialResolver, createSidecarTokenAuthenticator, type CreateSidecarTokenAuthenticatorDeps, type WsHandle, createSidecarEmitter, type SidecarEventEmitter, type SidecarEventMap, type SidecarEventType, type SidecarEventListener, type SidecarLookups, type SidecarMailPersistedPayload, type SidecarMailPersistedRow, type MailTriggeredRunGrantsResult, type WorkflowRunPackSource, } from "./ws/index.js";
|
|
9
|
+
export { createHubSessionLookups, findRoutableById, parseAgentId, resolveRoutableAddress, resolveRunIdForSession, resolveRunSessionId, runRowToRoutableRecord, type HubSessionLookupsDeps, type RoutableEndpoint, type RoutableRecord, } from "./hub-session-lookups.js";
|
|
10
|
+
export { createHubSessionOrchestrator, type HubSessionOrchestrator, type HubSessionOrchestratorDeps, type HubSessionRouterFacade, } from "./hub-session-orchestrator.js";
|
|
11
|
+
export { pushSourceUpdates, pushSourceUpdatesSubtree } from "./credential-push.js";
|
|
12
|
+
export { createSidecarPluginRegistry, createSidecarAllocationReconciler, resolveEffectiveSidecarPlacement, type CreateSidecarPluginRegistryOpts, type DestroySidecarRequest, type DestroySidecarResult, type EnsureSidecarRequest, type EnsureSidecarResult, type ResolveEffectiveSidecarPlacementOpts, type SidecarCredentialIdentity, type SidecarCredentialResolver, type SidecarOperationFailure, type SidecarPluginRegistry, type SidecarProvisioner, type SidecarAllocationReconciler, type SidecarAllocationReconcilerDeps, } from "./sidecar-allocation/index.js";
|
|
13
|
+
export { ensureWorkflowDefinitionForAsset } from "./workflow-definition-ensure.js";
|
|
14
|
+
export { workflowSourceAssetMountPath } from "./workflow-closure-resolution.js";
|
|
15
|
+
export { createWorkflowAllocationService, ExclusiveWorkflowPlacementError, resolveWorkflowSidecarPlacement, type PrepareExclusiveWorkflowDeploymentArgs, type PreparedExclusiveWorkflowDeployment, type WorkflowAllocationService, type WorkflowAllocationServiceDeps, } from "./workflow-allocation-service.js";
|
|
16
|
+
export { createWorkflowDispatchService, type WorkflowDispatchAcknowledgement, type WorkflowDispatchService, type WorkflowDispatchServiceDeps, } from "./workflow-dispatch-service.js";
|
|
17
|
+
export { listAcceptedWorkflowDispatches, listConsumedWorkflowDispatches, listReceivedWorkflowSignals, type AcceptedWorkflowDispatch, type ConsumedWorkflowDispatch, type ReceivedWorkflowSignal, } from "./workflow-dispatch-settlement.js";
|
|
18
|
+
export { skillKindHandler, skillAuthorize, skillFrontmatterSchema, getSkillIndex, type SkillIndexEntry, type SkillFrontmatter, type SkillPrincipal, type SkillHubPrincipal, type SkillSidecarPrincipal, } from "./skill-kind.js";
|
|
19
|
+
export { packageRegistryKindHandler, packageRegistryAuthorize, asTarballEntry, validateTarballPackageJSON, TARBALLS_PREFIX, TARBALL_FILENAME_PATTERN, REGISTRY_INDEX_PATH, WORKSPACE_BUILTINS_REGISTRY, } from "./package-registry-kind.js";
|
|
20
|
+
export { workflowKindHandler, workflowAuthorize, workflowDefinitionEnvelopeSchema, WORKFLOW_JSON_PATH, CAPABILITY_DECLARATIONS_JSON_PATH, type WorkflowPrincipal, type WorkflowHubPrincipal, type WorkflowSidecarPrincipal, } from "./workflow-kind.js";
|
|
21
|
+
export { workflowRunKindHandler, workflowRunAuthorize, enqueueInbox, StaleInboxEnqueueError, dequeueToProcessing, readProcessingEntry, markConsumed, readOwnedMessageIds, readCommittedWorkflowRunLifecycle, readWorkflowRunLifecycle, replayProcessingToInbox, WORKFLOW_RUN_GITIGNORE_PATH, WORKFLOW_RUN_RUNS_PREFIX, WORKFLOW_RUN_EVENTS_DIR, WORKFLOW_RUN_GRANTS_FILE, WORKFLOW_RUN_AGENT_STATE_PREFIX, WORKFLOW_RUN_ADDRESSES_PREFIX, WORKFLOW_RUN_CONTROL_PREFIX, WORKFLOW_RUN_INBOX_DIR, WORKFLOW_RUN_PROCESSING_DIR, WORKFLOW_RUN_CONSUMED_DIR, WORKFLOW_RUN_WATERMARK_FILE, DEFAULT_CONSUMED_RETENTION_MS, type ClaimCheckEnvelope, type ConsumedEnvelope, type EnqueueAlreadyPresentReason, type EnqueueInboxArgs, type EnqueueInboxOutcome, type EnqueueInboxResult, type DequeueToProcessingResult, type ReadProcessingEntryResult, type MarkConsumedArgs, type MarkConsumedResult, type WorkflowRunLifecycle, type ReplayProcessingToInboxOpts, type ReplayProcessingToInboxResult, type WorkflowRunPrincipal, type WorkflowRunHubPrincipal, type WorkflowRunSidecarPrincipal, type WorkflowRunWorkflowProcessPrincipal, type WorkflowRunSupervisorPrincipal, } from "./workflow-run-kind.js";
|
|
22
|
+
export { restoreWorkflowRunToAllocation, WORKFLOW_RUN_RESTORE_REFS, } from "./workflow-run-restore.js";
|
|
23
|
+
export { createAssetService, AssetServiceError, DEFAULT_ASSET_REF, type AssetService, type Asset, type CreateAssetParams, type PopulateAssetParams, type AssetServiceErrorReason, type ReadAssetBlobParams, type ListAssetBlobsParams, } from "./asset-service.js";
|
|
24
|
+
export { createWorkflowRunReader, type WorkflowRunReader, type WorkflowRunEvent, } from "./workflow-run-reader.js";
|
|
25
|
+
export { WORKFLOW_RUN_EVENTS_FILE, splitCombinedEventLog, encodeCombinedEventLog, } from "./workflow-run-event-log.js";
|
|
26
|
+
export type { AuthorizeFn, CommittedReads, CommittedTreeEntry, CreateRepoStoreConfig, InitRepoOpts, KindHandler, NewlyTerminalRun, Principal, RefEntry, RepoAction, RepoId, RepoStore, SubscribeKindEntry, SubscribeKindOpts, ValidatePushResult, WriteResult, } from "./repo-store/index.js";
|
|
27
|
+
export { createRepoStore, subscribeKind, UserPrincipal } from "./repo-store/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { createAgentRepoStore, } from "./agent-repo.js";
|
|
2
|
+
export { createSessionService, SessionLaunchError, bridgeOrchestratorDeployContent, deployCodeSourcedWorkflow, } from "./session-service.js";
|
|
3
|
+
export { installAndApproveWorkflowDefinition, createDbFrozenApprovalWriter, } from "./workflow-probe-gate.js";
|
|
4
|
+
export { committedReadsToSourceTree } from "./committed-source-tree.js";
|
|
5
|
+
export { createEventCollectorRegistry, } from "./event-collector-registry.js";
|
|
6
|
+
export { createSidecarRouter, createSidecarCredentialResolver, createSidecarTokenAuthenticator, createSidecarEmitter, } from "./ws/index.js";
|
|
7
|
+
export { createHubSessionLookups, findRoutableById, parseAgentId, resolveRoutableAddress, resolveRunIdForSession, resolveRunSessionId, runRowToRoutableRecord, } from "./hub-session-lookups.js";
|
|
8
|
+
export { createHubSessionOrchestrator, } from "./hub-session-orchestrator.js";
|
|
9
|
+
export { pushSourceUpdates, pushSourceUpdatesSubtree } from "./credential-push.js";
|
|
10
|
+
export { createSidecarPluginRegistry, createSidecarAllocationReconciler, resolveEffectiveSidecarPlacement, } from "./sidecar-allocation/index.js";
|
|
11
|
+
export { ensureWorkflowDefinitionForAsset } from "./workflow-definition-ensure.js";
|
|
12
|
+
export { workflowSourceAssetMountPath } from "./workflow-closure-resolution.js";
|
|
13
|
+
export { createWorkflowAllocationService, ExclusiveWorkflowPlacementError, resolveWorkflowSidecarPlacement, } from "./workflow-allocation-service.js";
|
|
14
|
+
export { createWorkflowDispatchService, } from "./workflow-dispatch-service.js";
|
|
15
|
+
export { listAcceptedWorkflowDispatches, listConsumedWorkflowDispatches, listReceivedWorkflowSignals, } from "./workflow-dispatch-settlement.js";
|
|
16
|
+
export { skillKindHandler, skillAuthorize, skillFrontmatterSchema, getSkillIndex, } from "./skill-kind.js";
|
|
17
|
+
export { packageRegistryKindHandler, packageRegistryAuthorize, asTarballEntry, validateTarballPackageJSON, TARBALLS_PREFIX, TARBALL_FILENAME_PATTERN, REGISTRY_INDEX_PATH, WORKSPACE_BUILTINS_REGISTRY, } from "./package-registry-kind.js";
|
|
18
|
+
export { workflowKindHandler, workflowAuthorize, workflowDefinitionEnvelopeSchema, WORKFLOW_JSON_PATH, CAPABILITY_DECLARATIONS_JSON_PATH, } from "./workflow-kind.js";
|
|
19
|
+
export { workflowRunKindHandler, workflowRunAuthorize, enqueueInbox, StaleInboxEnqueueError, dequeueToProcessing, readProcessingEntry, markConsumed, readOwnedMessageIds, readCommittedWorkflowRunLifecycle, readWorkflowRunLifecycle, replayProcessingToInbox, WORKFLOW_RUN_GITIGNORE_PATH, WORKFLOW_RUN_RUNS_PREFIX, WORKFLOW_RUN_EVENTS_DIR, WORKFLOW_RUN_GRANTS_FILE, WORKFLOW_RUN_AGENT_STATE_PREFIX, WORKFLOW_RUN_ADDRESSES_PREFIX, WORKFLOW_RUN_CONTROL_PREFIX, WORKFLOW_RUN_INBOX_DIR, WORKFLOW_RUN_PROCESSING_DIR, WORKFLOW_RUN_CONSUMED_DIR, WORKFLOW_RUN_WATERMARK_FILE, DEFAULT_CONSUMED_RETENTION_MS, } from "./workflow-run-kind.js";
|
|
20
|
+
export { restoreWorkflowRunToAllocation, WORKFLOW_RUN_RESTORE_REFS, } from "./workflow-run-restore.js";
|
|
21
|
+
export { createAssetService, AssetServiceError, DEFAULT_ASSET_REF, } from "./asset-service.js";
|
|
22
|
+
export { createWorkflowRunReader, } from "./workflow-run-reader.js";
|
|
23
|
+
export { WORKFLOW_RUN_EVENTS_FILE, splitCombinedEventLog, encodeCombinedEventLog, } from "./workflow-run-event-log.js";
|
|
24
|
+
export { createRepoStore, subscribeKind, UserPrincipal } from "./repo-store/index.js";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { PackageJSON } from "@intx/types/package-json";
|
|
2
|
+
import { type AuthorizeFn, type KindHandler } from "./repo-store/index.js";
|
|
3
|
+
export declare const TARBALLS_PREFIX = "tarballs/";
|
|
4
|
+
export declare const REGISTRY_INDEX_PATH = "package-registry.json";
|
|
5
|
+
/**
|
|
6
|
+
* Canonical asset name for the workspace's bundled package-registry —
|
|
7
|
+
* the in-tree `@intx/tools-*` packages live in an asset of this name
|
|
8
|
+
* under the workspace's root tenant. The hub's scope-routing config
|
|
9
|
+
* maps `@intx` to this registry, the seed script ensures the asset
|
|
10
|
+
* row exists, and the publish-tool-packages CLI defaults its target
|
|
11
|
+
* registry to this name. The constant lives at one site so a rename
|
|
12
|
+
* does not have to chase three independent string literals.
|
|
13
|
+
*
|
|
14
|
+
* Callers:
|
|
15
|
+
* - `bin/dev.ts` — orchestrator default for the registry the dev
|
|
16
|
+
* stack publishes the built-ins into.
|
|
17
|
+
* - `bin/seed.ts` — seeder that pins the workspace-builtins into
|
|
18
|
+
* the registry asset at boot.
|
|
19
|
+
* - `bin/publish-tool-packages.ts` — CLI default for the
|
|
20
|
+
* `--registry` flag.
|
|
21
|
+
*
|
|
22
|
+
* No test asserts that the seed's pinned built-ins actually land
|
|
23
|
+
* under this exact name; a mismatch between the constant and a
|
|
24
|
+
* caller would surface at apply time as a `tarball.missing`
|
|
25
|
+
* structured failure, not as a build error.
|
|
26
|
+
*/
|
|
27
|
+
export declare const WORKSPACE_BUILTINS_REGISTRY = "workspace-builtins";
|
|
28
|
+
/**
|
|
29
|
+
* Filename rule for tarballs in the repo tree. Filenames must end in
|
|
30
|
+
* `.tgz`, start with an alphanumeric / underscore / scope-marker
|
|
31
|
+
* character, and otherwise contain only filename-safe characters. The
|
|
32
|
+
* leading-character constraint forbids hidden-style names like
|
|
33
|
+
* `..tgz` or `.hidden.tgz` that the filesystem treats as dotfiles —
|
|
34
|
+
* those would be invisible to a `readdir` shell expansion and split
|
|
35
|
+
* the resolver's view of the registry tree from the operator's. The
|
|
36
|
+
* same rule is enforced at the REST upload boundary so a push and a
|
|
37
|
+
* PUT cannot produce diverging contents.
|
|
38
|
+
*/
|
|
39
|
+
export declare const TARBALL_FILENAME_PATTERN: RegExp;
|
|
40
|
+
/**
|
|
41
|
+
* Validates that `path` belongs to a tarball entry shape
|
|
42
|
+
* `tarballs/<filename>.tgz`. Returns the bare filename when valid,
|
|
43
|
+
* `null` otherwise.
|
|
44
|
+
*/
|
|
45
|
+
export declare function asTarballEntry(path: string): string | null;
|
|
46
|
+
type TarballValidationOutcome = {
|
|
47
|
+
ok: true;
|
|
48
|
+
pkg: PackageJSON;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
reason: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Open an npm-style tarball, find the top-level `package.json` entry,
|
|
55
|
+
* parse and validate it. Returns the typed descriptor on success; a
|
|
56
|
+
* structured reason otherwise. The shape validation lives inside
|
|
57
|
+
* `extractTarballPackageJSON`; this wrapper only translates the
|
|
58
|
+
* outcome into the substrate's `ValidatePushResult`-shaped reason
|
|
59
|
+
* strings.
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateTarballPackageJSON(filename: string, bytes: Uint8Array): Promise<TarballValidationOutcome>;
|
|
62
|
+
export declare const packageRegistryKindHandler: KindHandler;
|
|
63
|
+
/**
|
|
64
|
+
* Authorize policy for package-registry repos. Sidecars never write
|
|
65
|
+
* to package-registry repos (they consume contents through the
|
|
66
|
+
* in-process read API, not the smart-HTTP layer); only the hub and
|
|
67
|
+
* authenticated users with the right grant may push.
|
|
68
|
+
*/
|
|
69
|
+
export declare const packageRegistryAuthorize: AuthorizeFn;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// KindHandler for the `package-registry` asset kind.
|
|
2
|
+
//
|
|
3
|
+
// A package-registry asset is a git repo whose top-level tree holds:
|
|
4
|
+
//
|
|
5
|
+
// - `tarballs/<filename>.tgz` — one or more npm-style tarballs. Each
|
|
6
|
+
// tarball is opened during validation; its inner `package.json`
|
|
7
|
+
// must validate against `PackageJSON`. Anything else under
|
|
8
|
+
// `tarballs/` is rejected.
|
|
9
|
+
// - `package-registry.json` (optional) — a hub-authored index. The
|
|
10
|
+
// substrate does not enforce its shape today; the resolver layer
|
|
11
|
+
// consumes it when present.
|
|
12
|
+
// - `.gitignore` — supplied by the asset routes' genesis init body.
|
|
13
|
+
//
|
|
14
|
+
// Any top-level entry outside this set fails the push.
|
|
15
|
+
import { getLogger } from "@intx/log";
|
|
16
|
+
import { extractTarballPackageJSON } from "@intx/tool-packaging";
|
|
17
|
+
import {} from "./repo-store/index.js";
|
|
18
|
+
const logger = getLogger(["hub-sessions", "package-registry-kind"]);
|
|
19
|
+
export const TARBALLS_PREFIX = "tarballs/";
|
|
20
|
+
export const REGISTRY_INDEX_PATH = "package-registry.json";
|
|
21
|
+
/**
|
|
22
|
+
* Canonical asset name for the workspace's bundled package-registry —
|
|
23
|
+
* the in-tree `@intx/tools-*` packages live in an asset of this name
|
|
24
|
+
* under the workspace's root tenant. The hub's scope-routing config
|
|
25
|
+
* maps `@intx` to this registry, the seed script ensures the asset
|
|
26
|
+
* row exists, and the publish-tool-packages CLI defaults its target
|
|
27
|
+
* registry to this name. The constant lives at one site so a rename
|
|
28
|
+
* does not have to chase three independent string literals.
|
|
29
|
+
*
|
|
30
|
+
* Callers:
|
|
31
|
+
* - `bin/dev.ts` — orchestrator default for the registry the dev
|
|
32
|
+
* stack publishes the built-ins into.
|
|
33
|
+
* - `bin/seed.ts` — seeder that pins the workspace-builtins into
|
|
34
|
+
* the registry asset at boot.
|
|
35
|
+
* - `bin/publish-tool-packages.ts` — CLI default for the
|
|
36
|
+
* `--registry` flag.
|
|
37
|
+
*
|
|
38
|
+
* No test asserts that the seed's pinned built-ins actually land
|
|
39
|
+
* under this exact name; a mismatch between the constant and a
|
|
40
|
+
* caller would surface at apply time as a `tarball.missing`
|
|
41
|
+
* structured failure, not as a build error.
|
|
42
|
+
*/
|
|
43
|
+
export const WORKSPACE_BUILTINS_REGISTRY = "workspace-builtins";
|
|
44
|
+
/**
|
|
45
|
+
* Filename rule for tarballs in the repo tree. Filenames must end in
|
|
46
|
+
* `.tgz`, start with an alphanumeric / underscore / scope-marker
|
|
47
|
+
* character, and otherwise contain only filename-safe characters. The
|
|
48
|
+
* leading-character constraint forbids hidden-style names like
|
|
49
|
+
* `..tgz` or `.hidden.tgz` that the filesystem treats as dotfiles —
|
|
50
|
+
* those would be invisible to a `readdir` shell expansion and split
|
|
51
|
+
* the resolver's view of the registry tree from the operator's. The
|
|
52
|
+
* same rule is enforced at the REST upload boundary so a push and a
|
|
53
|
+
* PUT cannot produce diverging contents.
|
|
54
|
+
*/
|
|
55
|
+
export const TARBALL_FILENAME_PATTERN = /^[A-Za-z0-9_@+][A-Za-z0-9_.@+-]*\.tgz$/;
|
|
56
|
+
/**
|
|
57
|
+
* Validates that `path` belongs to a tarball entry shape
|
|
58
|
+
* `tarballs/<filename>.tgz`. Returns the bare filename when valid,
|
|
59
|
+
* `null` otherwise.
|
|
60
|
+
*/
|
|
61
|
+
export function asTarballEntry(path) {
|
|
62
|
+
if (!path.startsWith(TARBALLS_PREFIX))
|
|
63
|
+
return null;
|
|
64
|
+
const filename = path.slice(TARBALLS_PREFIX.length);
|
|
65
|
+
if (filename.length === 0)
|
|
66
|
+
return null;
|
|
67
|
+
if (filename.includes("/"))
|
|
68
|
+
return null;
|
|
69
|
+
if (!TARBALL_FILENAME_PATTERN.test(filename))
|
|
70
|
+
return null;
|
|
71
|
+
return filename;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Open an npm-style tarball, find the top-level `package.json` entry,
|
|
75
|
+
* parse and validate it. Returns the typed descriptor on success; a
|
|
76
|
+
* structured reason otherwise. The shape validation lives inside
|
|
77
|
+
* `extractTarballPackageJSON`; this wrapper only translates the
|
|
78
|
+
* outcome into the substrate's `ValidatePushResult`-shaped reason
|
|
79
|
+
* strings.
|
|
80
|
+
*/
|
|
81
|
+
export async function validateTarballPackageJSON(filename, bytes) {
|
|
82
|
+
const outcome = await extractTarballPackageJSON(bytes);
|
|
83
|
+
if (outcome.kind === "missing-entry") {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
reason: `tarball ${filename} has no top-level package.json entry`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (outcome.kind === "multiple-entries") {
|
|
90
|
+
// The hub validates the first top-level package.json the tar walk
|
|
91
|
+
// emits, but the sidecar's `tar.extract({ strip: 1 })` overwrites
|
|
92
|
+
// on every subsequent path with the same stripped name and ends up
|
|
93
|
+
// loading the LAST entry. A tarball carrying more than one
|
|
94
|
+
// `<seg>/package.json` therefore would have its hub-side validation
|
|
95
|
+
// and sidecar-side runtime read different descriptors — exactly
|
|
96
|
+
// the kind of TOCTOU gap a single signed integrity hash cannot
|
|
97
|
+
// close. Reject the upload at the validation boundary.
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
reason: `tarball ${filename} contains multiple top-level package.json entries (${outcome.paths
|
|
101
|
+
.map((p) => JSON.stringify(p))
|
|
102
|
+
.join(", ")}); npm tarballs must hold exactly one top-level package directory`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (outcome.kind === "parse-error") {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
reason: `tarball ${filename} failed to parse: ${outcome.message}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (outcome.kind === "json-error") {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
reason: `tarball ${filename} package.json is not valid JSON: ${outcome.message}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (outcome.kind === "shape-invalid") {
|
|
118
|
+
return {
|
|
119
|
+
ok: false,
|
|
120
|
+
reason: `tarball ${filename} package.json failed validation: ${outcome.message}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return { ok: true, pkg: outcome.parsed };
|
|
124
|
+
}
|
|
125
|
+
export const packageRegistryKindHandler = {
|
|
126
|
+
kind: "package-registry",
|
|
127
|
+
directoryPrefix: "assets/package-registry",
|
|
128
|
+
async validatePush({ repoId, ref, topLevelTreePaths, readBlob, listDir, }) {
|
|
129
|
+
// The substrate hands us every top-level tree entry — both
|
|
130
|
+
// directories and files — from both the receivePack and writeTree
|
|
131
|
+
// adapters. The allowed set is `tarballs`, `.gitignore`, and
|
|
132
|
+
// `package-registry.json`.
|
|
133
|
+
for (const entry of topLevelTreePaths) {
|
|
134
|
+
if (entry === "tarballs" ||
|
|
135
|
+
entry === ".gitignore" ||
|
|
136
|
+
entry === REGISTRY_INDEX_PATH) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
reason: `unexpected top-level entry ${JSON.stringify(entry)}; allowed: "tarballs", "${REGISTRY_INDEX_PATH}", ".gitignore"`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// Enumerate every entry under `tarballs/`, validate the filename
|
|
145
|
+
// shape, then open each tarball and validate its package.json.
|
|
146
|
+
// Gate on `topLevelTreePaths` so a tree without a `tarballs/`
|
|
147
|
+
// subtree (the genesis commit, or any push that simply does not
|
|
148
|
+
// include tarballs yet) skips the enumeration: the substrate's
|
|
149
|
+
// `listDir` returns `[]` for an absent path, which is
|
|
150
|
+
// indistinguishable from a present-but-empty `tarballs/` subtree.
|
|
151
|
+
// "Is the subtree there at all" is therefore answered at the handler
|
|
152
|
+
// from the top-level enumeration the substrate already supplies, not
|
|
153
|
+
// from a probe call. With `tarballs` confirmed present, any throw
|
|
154
|
+
// from the `listDir` below is a real fault (EACCES, EIO, malformed
|
|
155
|
+
// tree, transient transport), so it is surfaced rather than treated
|
|
156
|
+
// as "no tarballs."
|
|
157
|
+
let tarballChildren;
|
|
158
|
+
if (!topLevelTreePaths.includes("tarballs")) {
|
|
159
|
+
tarballChildren = [];
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
try {
|
|
163
|
+
tarballChildren = await listDir("tarballs");
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
// The top-level enumeration already told us `tarballs` is
|
|
167
|
+
// present, so any failure here is a real listDir fault
|
|
168
|
+
// (EACCES, EIO, malformed-tree, transient transport) — not
|
|
169
|
+
// "the subtree is absent." Surface it as a push rejection
|
|
170
|
+
// rather than collapsing it into "no tarballs to validate,"
|
|
171
|
+
// which would silently let a push through whose tarballs
|
|
172
|
+
// subtree could not be enumerated.
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
reason: `failed to list tarballs subtree: ${err instanceof Error ? err.message : String(err)}`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Two tarballs publishing the same `${name}@${version}` make the
|
|
180
|
+
// resolver's AssetRegistrySource overwrite by fs.readdir order —
|
|
181
|
+
// an undefined-behaviour outcome across filesystems. Reject the
|
|
182
|
+
// collision at the substrate boundary so the registry asset's
|
|
183
|
+
// closure is unambiguous regardless of how the loader walks it.
|
|
184
|
+
const publishedNameVersions = new Set();
|
|
185
|
+
for (const child of tarballChildren) {
|
|
186
|
+
const repoPath = `${TARBALLS_PREFIX}${child}`;
|
|
187
|
+
const filename = asTarballEntry(repoPath);
|
|
188
|
+
if (filename === null) {
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
reason: `tarball path ${JSON.stringify(repoPath)} must match tarballs/<filename>.tgz with filename-safe characters and a .tgz extension`,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
let bytes;
|
|
195
|
+
try {
|
|
196
|
+
bytes = await readBlob(repoPath);
|
|
197
|
+
}
|
|
198
|
+
catch (cause) {
|
|
199
|
+
return {
|
|
200
|
+
ok: false,
|
|
201
|
+
reason: `tarball ${repoPath} could not be read from the tree: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const outcome = await validateTarballPackageJSON(filename, bytes);
|
|
205
|
+
if (!outcome.ok) {
|
|
206
|
+
logger.debug `package-registry validatePush rejected ${repoId.kind}/${repoId.id} on ${ref}: ${outcome.reason}`;
|
|
207
|
+
return { ok: false, reason: outcome.reason };
|
|
208
|
+
}
|
|
209
|
+
const key = `${outcome.pkg.name}@${outcome.pkg.version}`;
|
|
210
|
+
if (publishedNameVersions.has(key)) {
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
reason: `package-registry contains multiple tarballs publishing ${key}; each name@version pair must appear in exactly one tarball`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
publishedNameVersions.add(key);
|
|
217
|
+
}
|
|
218
|
+
return { ok: true };
|
|
219
|
+
},
|
|
220
|
+
onRefUpdated() {
|
|
221
|
+
// No cached index today. The resolver reads the asset's contents
|
|
222
|
+
// through `readAssetBlob`/`listAssetBlobs` at session time.
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Authorize policy for package-registry repos. Sidecars never write
|
|
227
|
+
* to package-registry repos (they consume contents through the
|
|
228
|
+
* in-process read API, not the smart-HTTP layer); only the hub and
|
|
229
|
+
* authenticated users with the right grant may push.
|
|
230
|
+
*/
|
|
231
|
+
export const packageRegistryAuthorize = (principal, repoId, _ref, action) => {
|
|
232
|
+
if (repoId.kind !== "package-registry") {
|
|
233
|
+
return {
|
|
234
|
+
allowed: false,
|
|
235
|
+
reason: `package-registry authorize received non-package-registry repo ${repoId.kind}/${repoId.id}`,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (principal.kind === "hub") {
|
|
239
|
+
return { allowed: true };
|
|
240
|
+
}
|
|
241
|
+
if (principal.kind === "sidecar") {
|
|
242
|
+
return {
|
|
243
|
+
allowed: false,
|
|
244
|
+
reason: `sidecars do not access package-registry assets via the substrate; action=${action}`,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// The smart-HTTP route layer treats package-registry repos as
|
|
248
|
+
// user-write-denied by design: tarball writes are constrained to the
|
|
249
|
+
// shape the kind handler validates (`tarballs/<filename>.tgz` plus a
|
|
250
|
+
// hub-authored index), and the REST PUT/DELETE endpoints on the
|
|
251
|
+
// asset routes (`PUT /api/tenants/:tid/assets/:assetId/tarballs/:filename`
|
|
252
|
+
// and the matching DELETE) are the supported path for users who
|
|
253
|
+
// need to publish a tarball. Smart-HTTP would let a user push
|
|
254
|
+
// arbitrary tree shapes that the kind handler would then have to
|
|
255
|
+
// reject after the fact; the REST surface validates ahead of write.
|
|
256
|
+
return {
|
|
257
|
+
allowed: false,
|
|
258
|
+
reason: `principal kind ${principal.kind} cannot push to package-registry over smart-HTTP; use the REST tarball endpoints (PUT/DELETE /api/tenants/:tid/assets/:assetId/tarballs/:filename)`,
|
|
259
|
+
};
|
|
260
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { AuthorizeFn, CommittedReads, CommittedTreeEntry, InitRepoOpts, KindHandler, NewlyTerminalRun, PriorDeltaReads, Principal, RefEntry, RepoAction, RepoId, RepoKind, RepoStore, RepoStoreSubscribeEvent, TreeContent, ValidatePushResult, WriteResult, WriteTreePreservingPrefixArgs, } from "./types.js";
|
|
2
|
+
export { UserPrincipal } from "./types.js";
|
|
3
|
+
export { createRepoStore, type CreateRepoStoreConfig } from "./store.js";
|
|
4
|
+
export { subscribeKind, type SubscribeKindOpts, type SubscribeKindEntry, } from "./subscribe-kind.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type CommitSigner, type GCPolicy } from "@intx/storage-isogit/node";
|
|
2
|
+
import type { AuthorizeFn, KindHandler, RepoId, RepoKind, RepoStore } from "./types.js";
|
|
3
|
+
type SigningKey = {
|
|
4
|
+
privateKey: Uint8Array;
|
|
5
|
+
publicKey: Uint8Array;
|
|
6
|
+
};
|
|
7
|
+
export type CreateRepoStoreConfig = {
|
|
8
|
+
dataDir: string;
|
|
9
|
+
signingKey: SigningKey;
|
|
10
|
+
/**
|
|
11
|
+
* Handler map keyed by repo kind. The substrate throws at request
|
|
12
|
+
* time when a kind has no registered handler, so callers may omit
|
|
13
|
+
* kinds they do not service (e.g. a per-asset-kind store that only
|
|
14
|
+
* registers `skill`).
|
|
15
|
+
*/
|
|
16
|
+
handlers: Partial<Record<RepoKind, KindHandler>>;
|
|
17
|
+
authorize: AuthorizeFn;
|
|
18
|
+
/**
|
|
19
|
+
* Optional per-repo signing callback. When supplied and the callback
|
|
20
|
+
* returns a `CommitSigner` for the given `repoId`, the substrate
|
|
21
|
+
* passes that signer to `initRepo` so the genesis commit is authored
|
|
22
|
+
* as `interchange-hub` and signed. When the callback returns
|
|
23
|
+
* `undefined`, or the field is omitted entirely, the substrate falls
|
|
24
|
+
* back to the unsigned harness-authored genesis.
|
|
25
|
+
*/
|
|
26
|
+
signingCallback?: (repoId: RepoId) => CommitSigner | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Optional write-path garbage-collection policy. When supplied, after
|
|
29
|
+
* every successful write under the repo lock the substrate applies the
|
|
30
|
+
* shared reclaim policy to repos whose kind is in `kinds`. Omitted
|
|
31
|
+
* entirely, the substrate never reclaims and never warns. The `kinds`
|
|
32
|
+
* allowlist keeps the policy scoped to the kinds the caller intends
|
|
33
|
+
* (e.g. `agent-state`) rather than every kind the store happens to
|
|
34
|
+
* service.
|
|
35
|
+
*/
|
|
36
|
+
gc?: GCPolicy & {
|
|
37
|
+
kinds: readonly RepoKind[];
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export declare function createRepoStore(config: CreateRepoStoreConfig): RepoStore;
|
|
41
|
+
export {};
|