@hasna/loops 0.4.12 → 0.4.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/CHANGELOG.md +106 -3
- package/README.md +70 -17
- package/dist/api/index.d.ts +35 -0
- package/dist/api/index.js +750 -10
- package/dist/cli/index.js +1744 -361
- package/dist/cli/ui.d.ts +44 -0
- package/dist/daemon/index.js +948 -212
- package/dist/generated/storage-kit/health.d.ts +19 -0
- package/dist/generated/storage-kit/index.d.ts +7 -0
- package/dist/generated/storage-kit/migrations.d.ts +47 -0
- package/dist/generated/storage-kit/mode.d.ts +47 -0
- package/dist/generated/storage-kit/pool.d.ts +33 -0
- package/dist/generated/storage-kit/query.d.ts +35 -0
- package/dist/generated/storage-kit/tls.d.ts +25 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6513 -4840
- package/dist/lib/health.d.ts +83 -3
- package/dist/lib/mode.d.ts +27 -0
- package/dist/lib/mode.js +69 -2
- package/dist/lib/scheduler.d.ts +5 -2
- package/dist/lib/storage/index.d.ts +1 -0
- package/dist/lib/storage/index.js +1329 -211
- package/dist/lib/storage/pg-executor.d.ts +27 -0
- package/dist/lib/storage/pg-runner-claim.d.ts +40 -0
- package/dist/lib/storage/postgres-loop-storage.d.ts +114 -0
- package/dist/lib/storage/sqlite.js +336 -8
- package/dist/lib/store.d.ts +234 -0
- package/dist/lib/store.js +350 -8
- package/dist/mcp/index.js +1447 -479
- package/dist/runner/index.js +179 -25
- package/dist/sdk/http.d.ts +115 -0
- package/dist/sdk/http.js +145 -0
- package/dist/sdk/index.d.ts +5 -1
- package/dist/sdk/index.js +1106 -296
- package/dist/serve/index.d.ts +4 -0
- package/dist/serve/index.js +7619 -0
- package/dist/types.d.ts +3 -0
- package/docs/CUTOVER-RUNBOOK.md +61 -0
- package/docs/DEPLOYMENT_MODES.md +23 -1
- package/docs/USAGE.md +66 -16
- package/package.json +14 -2
package/dist/lib/health.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { Loop, LoopRun } from "../types.js";
|
|
1
|
+
import type { Loop, LoopRun, LoopStatus } from "../types.js";
|
|
2
|
+
import type { DaemonStatus } from "../daemon/control.js";
|
|
3
|
+
import type { DoctorCheck, DoctorReport } from "./doctor.js";
|
|
2
4
|
import type { Store } from "./store.js";
|
|
3
|
-
export type RunFailureClassification = "rate_limit" | "auth" | "model_not_found" | "context_length" | "schema_response_format" | "node_init" | "preflight" | "route_functional" | "timeout" | "sigsegv" | "skipped_previous_active" | "circuit_breaker" | "unknown";
|
|
5
|
+
export type RunFailureClassification = "rate_limit" | "auth" | "provider_unavailable" | "model_not_found" | "context_length" | "schema_response_format" | "node_init" | "preflight" | "route_functional" | "timeout" | "sigsegv" | "restart_interrupted" | "skipped_previous_active" | "circuit_breaker" | "unknown";
|
|
4
6
|
export interface RunFailureSignal {
|
|
5
7
|
classification: RunFailureClassification;
|
|
6
8
|
fingerprint: string;
|
|
7
9
|
evidence: {
|
|
10
|
+
summary?: string;
|
|
8
11
|
error?: string;
|
|
9
12
|
stdout?: string;
|
|
10
13
|
stderr?: string;
|
|
@@ -31,7 +34,7 @@ export interface RecommendedTaskUpsert {
|
|
|
31
34
|
};
|
|
32
35
|
}
|
|
33
36
|
export interface LoopExpectationResult {
|
|
34
|
-
loop: Pick<Loop, "id" | "name" | "status" | "nextRunAt">;
|
|
37
|
+
loop: Pick<Loop, "id" | "name" | "status" | "nextRunAt" | "retryScheduledFor">;
|
|
35
38
|
ok: boolean;
|
|
36
39
|
check: {
|
|
37
40
|
id: "latest-run-succeeded" | "route-functional-health";
|
|
@@ -62,6 +65,81 @@ export interface LoopsHealthReport {
|
|
|
62
65
|
classifications: Record<RunFailureClassification, number>;
|
|
63
66
|
expectations: LoopExpectationResult[];
|
|
64
67
|
}
|
|
68
|
+
export type HealthScanStatus = "ok" | "degraded" | "critical";
|
|
69
|
+
export type HealthScanFindingKind = "daemon" | "doctor" | "preflight" | "latest-run" | "stale-running";
|
|
70
|
+
export type HealthScanFindingSeverity = "critical" | "high" | "medium" | "low";
|
|
71
|
+
export interface HealthScanSelfHealAction {
|
|
72
|
+
kind: "daemon-start";
|
|
73
|
+
attempted: boolean;
|
|
74
|
+
ok?: boolean;
|
|
75
|
+
reason: string;
|
|
76
|
+
result?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
export interface HealthScanFinding {
|
|
79
|
+
kind: HealthScanFindingKind;
|
|
80
|
+
severity: HealthScanFindingSeverity;
|
|
81
|
+
fingerprint: string;
|
|
82
|
+
title: string;
|
|
83
|
+
message: string;
|
|
84
|
+
loop?: Pick<Loop, "id" | "name" | "status" | "nextRunAt"> & {
|
|
85
|
+
leaseMs?: number;
|
|
86
|
+
};
|
|
87
|
+
run?: LoopRun;
|
|
88
|
+
route?: LoopExpectationResult["route"];
|
|
89
|
+
ageMs?: number;
|
|
90
|
+
staleThresholdMs?: number;
|
|
91
|
+
classification?: RunFailureClassification;
|
|
92
|
+
doctorCheck?: DoctorCheck;
|
|
93
|
+
recommendedTask?: RecommendedTaskUpsert;
|
|
94
|
+
}
|
|
95
|
+
export interface LoopsHealthScan {
|
|
96
|
+
ok: boolean;
|
|
97
|
+
status: HealthScanStatus;
|
|
98
|
+
generatedAt: string;
|
|
99
|
+
includedStatuses: LoopStatus[];
|
|
100
|
+
counts: {
|
|
101
|
+
loops: number;
|
|
102
|
+
active: number;
|
|
103
|
+
paused: number;
|
|
104
|
+
stopped: number;
|
|
105
|
+
expired: number;
|
|
106
|
+
latestRunFindings: number;
|
|
107
|
+
staleRunning: number;
|
|
108
|
+
daemonFindings: number;
|
|
109
|
+
doctorFindings: number;
|
|
110
|
+
preflightFindings: number;
|
|
111
|
+
findings: number;
|
|
112
|
+
reportedFindings: number;
|
|
113
|
+
truncatedFindings: number;
|
|
114
|
+
};
|
|
115
|
+
daemon?: Pick<DaemonStatus, "running" | "stale" | "pid" | "host" | "loops" | "runs" | "logPath">;
|
|
116
|
+
doctor?: DoctorReport;
|
|
117
|
+
health: LoopsHealthReport;
|
|
118
|
+
selfHeals: HealthScanSelfHealAction[];
|
|
119
|
+
findings: HealthScanFinding[];
|
|
120
|
+
reports?: {
|
|
121
|
+
dir: string;
|
|
122
|
+
json: string;
|
|
123
|
+
markdown: string;
|
|
124
|
+
};
|
|
125
|
+
todos?: Record<string, unknown>;
|
|
126
|
+
}
|
|
127
|
+
export interface BuildHealthScanOptions {
|
|
128
|
+
includeStatuses?: LoopStatus[];
|
|
129
|
+
includeArchived?: boolean;
|
|
130
|
+
limit?: number;
|
|
131
|
+
latestRun?: boolean;
|
|
132
|
+
doctor?: DoctorReport;
|
|
133
|
+
daemon?: DaemonStatus;
|
|
134
|
+
selfHeals?: HealthScanSelfHealAction[];
|
|
135
|
+
maxFindings?: number;
|
|
136
|
+
staleRunningMs?: number;
|
|
137
|
+
now?: Date;
|
|
138
|
+
}
|
|
139
|
+
export interface WriteHealthScanReportsOptions {
|
|
140
|
+
reportDir?: string;
|
|
141
|
+
}
|
|
142
|
+
export declare const RESTART_INTERRUPTED_RUN_PREFIX = "daemon restart interrupted active run";
|
|
65
143
|
export declare function classifyRunFailure(run: LoopRun): RunFailureSignal | undefined;
|
|
66
144
|
export declare function expectationForLoop(store: Store, loop: Loop): LoopExpectationResult;
|
|
67
145
|
export declare function buildHealthReport(store: Store, opts?: {
|
|
@@ -69,3 +147,5 @@ export declare function buildHealthReport(store: Store, opts?: {
|
|
|
69
147
|
includeInactive?: boolean;
|
|
70
148
|
limit?: number;
|
|
71
149
|
}): LoopsHealthReport;
|
|
150
|
+
export declare function buildHealthScan(store: Store, opts?: BuildHealthScanOptions): LoopsHealthScan;
|
|
151
|
+
export declare function writeHealthScanReports(scan: LoopsHealthScan, opts?: WriteHealthScanReportsOptions): LoopsHealthScan;
|
package/dist/lib/mode.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export declare const LOOP_DEPLOYMENT_MODES: readonly ["local", "self_hosted", "cloud"];
|
|
2
2
|
export type LoopDeploymentMode = (typeof LOOP_DEPLOYMENT_MODES)[number];
|
|
3
3
|
export type LoopSourceOfTruth = "local_sqlite" | "self_hosted_control_plane" | "cloud_control_plane";
|
|
4
|
+
export type LoopRemoteSchedulerBackend = "none" | "unconfigured" | "api_control_plane_contract" | "postgres_contract" | "hosted_control_plane_contract";
|
|
5
|
+
export type LoopRemoteArtifactStore = "none" | "object_store_contract";
|
|
6
|
+
export type LoopRouteAdmissionStateStore = "local_sqlite" | "control_plane_contract";
|
|
7
|
+
export type LoopRouteAdmissionGate = "max_dispatch" | "max_active" | "max_active_per_project" | "max_active_per_project_group" | "max_active_scope" | "max_per_profile";
|
|
4
8
|
export interface LoopModeResolution {
|
|
5
9
|
deploymentMode: LoopDeploymentMode;
|
|
6
10
|
source: string;
|
|
@@ -34,8 +38,31 @@ export interface LoopDeploymentStatus {
|
|
|
34
38
|
required: boolean;
|
|
35
39
|
role: "daemon" | "control_plane_worker";
|
|
36
40
|
};
|
|
41
|
+
schedulerState: LoopSchedulerStateStatus;
|
|
37
42
|
warnings: string[];
|
|
38
43
|
}
|
|
44
|
+
export interface LoopSchedulerStateStatus {
|
|
45
|
+
authority: LoopSourceOfTruth;
|
|
46
|
+
localStore: {
|
|
47
|
+
backend: "sqlite";
|
|
48
|
+
role: "authoritative" | "cache_and_spool";
|
|
49
|
+
runArtifacts: "local_files";
|
|
50
|
+
routeAdmissionState: "workflow_work_items";
|
|
51
|
+
};
|
|
52
|
+
remoteStore: {
|
|
53
|
+
backend: LoopRemoteSchedulerBackend;
|
|
54
|
+
configured: boolean;
|
|
55
|
+
applySupported: boolean;
|
|
56
|
+
objectArtifacts: LoopRemoteArtifactStore;
|
|
57
|
+
mutatesAws: false;
|
|
58
|
+
};
|
|
59
|
+
routeAdmission: {
|
|
60
|
+
stateStore: LoopRouteAdmissionStateStore;
|
|
61
|
+
activeStatuses: readonly ["admitted", "running"];
|
|
62
|
+
gates: readonly LoopRouteAdmissionGate[];
|
|
63
|
+
dryRunEvaluatesLiveCounts: false;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
39
66
|
type Env = Record<string, string | undefined>;
|
|
40
67
|
export declare function normalizeLoopDeploymentMode(value: string): LoopDeploymentMode;
|
|
41
68
|
export declare function resolveLoopDeploymentMode(env?: Env): LoopModeResolution;
|
package/dist/lib/mode.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// package.json
|
|
3
3
|
var package_default = {
|
|
4
4
|
name: "@hasna/loops",
|
|
5
|
-
version: "0.4.
|
|
5
|
+
version: "0.4.14",
|
|
6
6
|
description: "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
|
|
7
7
|
type: "module",
|
|
8
8
|
main: "dist/index.js",
|
|
@@ -11,6 +11,7 @@ var package_default = {
|
|
|
11
11
|
loops: "dist/cli/index.js",
|
|
12
12
|
"loops-daemon": "dist/daemon/index.js",
|
|
13
13
|
"loops-api": "dist/api/index.js",
|
|
14
|
+
"loops-serve": "dist/serve/index.js",
|
|
14
15
|
"loops-runner": "dist/runner/index.js",
|
|
15
16
|
"loops-mcp": "dist/mcp/index.js"
|
|
16
17
|
},
|
|
@@ -23,6 +24,14 @@ var package_default = {
|
|
|
23
24
|
types: "./dist/sdk/index.d.ts",
|
|
24
25
|
import: "./dist/sdk/index.js"
|
|
25
26
|
},
|
|
27
|
+
"./sdk/http": {
|
|
28
|
+
types: "./dist/sdk/http.d.ts",
|
|
29
|
+
import: "./dist/sdk/http.js"
|
|
30
|
+
},
|
|
31
|
+
"./serve": {
|
|
32
|
+
types: "./dist/serve/index.d.ts",
|
|
33
|
+
import: "./dist/serve/index.js"
|
|
34
|
+
},
|
|
26
35
|
"./mcp": {
|
|
27
36
|
types: "./dist/mcp/index.d.ts",
|
|
28
37
|
import: "./dist/mcp/index.js"
|
|
@@ -68,7 +77,7 @@ var package_default = {
|
|
|
68
77
|
"LICENSE"
|
|
69
78
|
],
|
|
70
79
|
scripts: {
|
|
71
|
-
build: "rm -rf dist && bun build src/cli/index.ts src/daemon/index.ts src/api/index.ts src/runner/index.ts src/mcp/index.ts src/index.ts src/sdk/index.ts src/lib/store.ts src/lib/mode.ts src/lib/storage/index.ts src/lib/storage/contract.ts src/lib/storage/sqlite.ts src/lib/storage/postgres.ts src/lib/storage/postgres-schema.ts --root src --outdir dist --target bun --packages external && chmod +x dist/cli/index.js dist/daemon/index.js dist/api/index.js dist/runner/index.js dist/mcp/index.js && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
|
|
80
|
+
build: "rm -rf dist && bun build src/cli/index.ts src/daemon/index.ts src/api/index.ts src/serve/index.ts src/runner/index.ts src/mcp/index.ts src/index.ts src/sdk/index.ts src/sdk/http.ts src/lib/store.ts src/lib/mode.ts src/lib/storage/index.ts src/lib/storage/contract.ts src/lib/storage/sqlite.ts src/lib/storage/postgres.ts src/lib/storage/postgres-schema.ts --root src --outdir dist --target bun --packages external && chmod +x dist/cli/index.js dist/daemon/index.js dist/api/index.js dist/serve/index.js dist/runner/index.js dist/mcp/index.js && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
|
|
72
81
|
"build:bin": "bun build src/cli/index.ts --compile --outfile dist/loops",
|
|
73
82
|
typecheck: "tsc --noEmit",
|
|
74
83
|
test: "bun test",
|
|
@@ -103,11 +112,13 @@ var package_default = {
|
|
|
103
112
|
bun: ">=1.0.0"
|
|
104
113
|
},
|
|
105
114
|
dependencies: {
|
|
115
|
+
"@hasna/contracts": "^0.4.1",
|
|
106
116
|
"@hasna/events": "^0.1.9",
|
|
107
117
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
108
118
|
"@openrouter/ai-sdk-provider": "2.9.1",
|
|
109
119
|
ai: "6.0.204",
|
|
110
120
|
commander: "^13.1.0",
|
|
121
|
+
pg: "^8.13.1",
|
|
111
122
|
zod: "4.4.3"
|
|
112
123
|
},
|
|
113
124
|
optionalDependencies: {
|
|
@@ -115,6 +126,7 @@ var package_default = {
|
|
|
115
126
|
},
|
|
116
127
|
devDependencies: {
|
|
117
128
|
"@types/bun": "latest",
|
|
129
|
+
"@types/pg": "^8.11.10",
|
|
118
130
|
typescript: "^5.7.3"
|
|
119
131
|
},
|
|
120
132
|
publishConfig: {
|
|
@@ -193,6 +205,50 @@ function sourceOfTruthForMode(mode) {
|
|
|
193
205
|
return "self_hosted_control_plane";
|
|
194
206
|
return "cloud_control_plane";
|
|
195
207
|
}
|
|
208
|
+
var ROUTE_ADMISSION_GATES = [
|
|
209
|
+
"max_dispatch",
|
|
210
|
+
"max_active",
|
|
211
|
+
"max_active_per_project",
|
|
212
|
+
"max_active_per_project_group",
|
|
213
|
+
"max_active_scope",
|
|
214
|
+
"max_per_profile"
|
|
215
|
+
];
|
|
216
|
+
function remoteSchedulerBackendForMode(mode, config) {
|
|
217
|
+
if (mode === "local")
|
|
218
|
+
return "none";
|
|
219
|
+
if (mode === "cloud")
|
|
220
|
+
return config.cloudApiUrl ? "hosted_control_plane_contract" : "unconfigured";
|
|
221
|
+
if (config.databaseUrlPresent)
|
|
222
|
+
return "postgres_contract";
|
|
223
|
+
if (config.apiUrl)
|
|
224
|
+
return "api_control_plane_contract";
|
|
225
|
+
return "unconfigured";
|
|
226
|
+
}
|
|
227
|
+
function schedulerStateForMode(args) {
|
|
228
|
+
const nonLocal = args.deploymentMode !== "local";
|
|
229
|
+
return {
|
|
230
|
+
authority: args.sourceOfTruth,
|
|
231
|
+
localStore: {
|
|
232
|
+
backend: "sqlite",
|
|
233
|
+
role: args.localRole,
|
|
234
|
+
runArtifacts: "local_files",
|
|
235
|
+
routeAdmissionState: "workflow_work_items"
|
|
236
|
+
},
|
|
237
|
+
remoteStore: {
|
|
238
|
+
backend: remoteSchedulerBackendForMode(args.deploymentMode, args.config),
|
|
239
|
+
configured: nonLocal && args.controlPlaneConfigured,
|
|
240
|
+
applySupported: false,
|
|
241
|
+
objectArtifacts: nonLocal ? "object_store_contract" : "none",
|
|
242
|
+
mutatesAws: false
|
|
243
|
+
},
|
|
244
|
+
routeAdmission: {
|
|
245
|
+
stateStore: nonLocal ? "control_plane_contract" : "local_sqlite",
|
|
246
|
+
activeStatuses: ["admitted", "running"],
|
|
247
|
+
gates: ROUTE_ADMISSION_GATES,
|
|
248
|
+
dryRunEvaluatesLiveCounts: false
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
196
252
|
function displayControlPlaneUrl(value) {
|
|
197
253
|
if (!value)
|
|
198
254
|
return;
|
|
@@ -218,6 +274,9 @@ function buildDeploymentStatus(opts = {}) {
|
|
|
218
274
|
if (deploymentMode === "self_hosted" && !controlPlaneConfigured) {
|
|
219
275
|
warnings.push("self_hosted mode needs LOOPS_API_URL or LOOPS_DATABASE_URL before it can become authoritative");
|
|
220
276
|
}
|
|
277
|
+
if (deploymentMode === "self_hosted" && config.databaseUrlPresent && !config.apiUrl) {
|
|
278
|
+
warnings.push("LOOPS_DATABASE_URL selects the self_hosted storage contract; loops-runner still needs LOOPS_API_URL to claim remote work");
|
|
279
|
+
}
|
|
221
280
|
if (deploymentMode === "cloud" && config.apiUrl && !config.cloudApiUrl) {
|
|
222
281
|
warnings.push("LOOPS_API_URL selects self_hosted; cloud mode uses LOOPS_CLOUD_API_URL");
|
|
223
282
|
}
|
|
@@ -251,6 +310,13 @@ function buildDeploymentStatus(opts = {}) {
|
|
|
251
310
|
required: deploymentMode !== "local",
|
|
252
311
|
role: deploymentMode === "local" ? "daemon" : "control_plane_worker"
|
|
253
312
|
},
|
|
313
|
+
schedulerState: schedulerStateForMode({
|
|
314
|
+
deploymentMode,
|
|
315
|
+
sourceOfTruth: sourceOfTruthForMode(deploymentMode),
|
|
316
|
+
localRole: deploymentMode === "local" ? "authoritative" : "cache_and_spool",
|
|
317
|
+
controlPlaneConfigured,
|
|
318
|
+
config
|
|
319
|
+
}),
|
|
254
320
|
warnings
|
|
255
321
|
};
|
|
256
322
|
}
|
|
@@ -263,6 +329,7 @@ function deploymentStatusLine(status) {
|
|
|
263
329
|
`source=${status.deploymentModeSource}`,
|
|
264
330
|
`truth=${status.sourceOfTruth}`,
|
|
265
331
|
`local=${status.localStore.role}`,
|
|
332
|
+
`scheduler=${status.schedulerState.routeAdmission.stateStore}`,
|
|
266
333
|
`control_plane=${configured}`
|
|
267
334
|
].join(" ");
|
|
268
335
|
}
|
package/dist/lib/scheduler.d.ts
CHANGED
|
@@ -97,8 +97,8 @@ export declare const MAX_SKIPS_PER_LOOP_PER_TICK = 10;
|
|
|
97
97
|
/**
|
|
98
98
|
* Exponential retry backoff with jitter:
|
|
99
99
|
* delay = retryDelayMs * 2^(attempt-1) * (0.5 + random), capped at 6h.
|
|
100
|
-
* Failures classified as
|
|
101
|
-
* a throttled or
|
|
100
|
+
* Failures classified as provider-gated back off 4x harder, since hammering
|
|
101
|
+
* a throttled, misconfigured, or unavailable provider only makes things worse.
|
|
102
102
|
*/
|
|
103
103
|
export declare function retryBackoffDelayMs(loop: Loop, run: LoopRun, random?: () => number): number;
|
|
104
104
|
export interface AdvanceLoopOptions {
|
|
@@ -129,6 +129,9 @@ export declare function executeClaimedRun(deps: {
|
|
|
129
129
|
beforeFinalize?: (loop: Loop, run: LoopRun) => void;
|
|
130
130
|
daemonLeaseId?: string;
|
|
131
131
|
execute?: (loop: Loop, run: LoopRun) => Promise<ExecutorResult>;
|
|
132
|
+
finalizeResult?: (result: ExecutorResult, loop: Loop, run: LoopRun) => Omit<ExecutorResult, "status"> & {
|
|
133
|
+
status: LoopRun["status"];
|
|
134
|
+
};
|
|
132
135
|
onError?: (loop: Loop, error: unknown) => void;
|
|
133
136
|
}): Promise<LoopRun>;
|
|
134
137
|
export declare function claimDueRuns(deps: SchedulerDeps & {
|
|
@@ -2,5 +2,6 @@ export type { AppliedStorageMigration, AuditEventRecord, LoopStorageBackend, Loo
|
|
|
2
2
|
export { SqliteLoopStorage, createSqliteLoopStorage } from "./sqlite.js";
|
|
3
3
|
export { PostgresStorage, createPostgresStorage } from "./postgres.js";
|
|
4
4
|
export type { PostgresQueryExecutor } from "./postgres.js";
|
|
5
|
+
export { PostgresLoopStorage, createPostgresLoopStorage, NotImplementedError, } from "./postgres-loop-storage.js";
|
|
5
6
|
export { POSTGRES_MIGRATION_LEDGER_TABLE, POSTGRES_STORAGE_MIGRATIONS, checksumStorageSql, } from "./postgres-schema.js";
|
|
6
7
|
export { Store } from "../store.js";
|