@volter/world-core 2.0.37 → 3.0.1
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 +4 -5
- package/app-route.cjs +12 -6
- package/app-route.d.cts +1 -1
- package/dist/app-route.cjs +12 -6
- package/dist/app-route.d.cts +1 -1
- package/dist/generated/pack-facts.json +1410 -3069
- package/dist/inject.cjs +64 -9
- package/dist/pack-facts.cjs +44 -0
- package/dist/src/actions.d.ts +3 -3
- package/dist/src/actions.js +22 -16
- package/dist/src/ancestry.d.ts +14 -2
- package/dist/src/ancestry.js +92 -2
- package/dist/src/anthropic-wire.d.ts +39 -0
- package/dist/src/anthropic-wire.js +136 -0
- package/dist/src/bytes.d.ts +7 -0
- package/dist/src/bytes.js +35 -0
- package/dist/src/changeset.d.ts +1 -1
- package/dist/src/changeset.js +0 -0
- package/dist/src/clickhouse/index.d.ts +3 -0
- package/dist/src/clickhouse/index.js +6 -0
- package/dist/src/clickhouse/sql.d.ts +233 -0
- package/dist/src/clickhouse/sql.js +4329 -0
- package/dist/src/clickhouse/types.d.ts +18 -0
- package/dist/src/clickhouse/types.js +47 -0
- package/dist/src/clickhouse/values.d.ts +146 -0
- package/dist/src/clickhouse/values.js +858 -0
- package/dist/src/client-bundle.js +2 -3
- package/dist/src/cors.d.ts +15 -0
- package/dist/src/cors.js +31 -0
- package/dist/src/derived-core.d.ts +487 -24
- package/dist/src/derived-core.js +788 -144
- package/dist/src/derived-real.d.ts +13 -0
- package/dist/src/derived-real.js +518 -0
- package/dist/src/derived.d.ts +35 -1
- package/dist/src/derived.js +61 -9
- package/dist/src/emit.js +1 -2
- package/dist/src/events.d.ts +206 -0
- package/dist/src/events.js +341 -0
- package/dist/src/executor.d.ts +3 -0
- package/dist/src/executor.js +19 -2
- package/dist/src/file-response.d.ts +6 -0
- package/dist/src/file-response.js +30 -0
- package/dist/src/fork.js +3 -2
- package/dist/src/git/history.d.ts +7 -0
- package/dist/src/git/history.js +24 -0
- package/dist/src/git/index.d.ts +1 -0
- package/dist/src/git/index.js +1 -0
- package/dist/src/git/lfs.d.ts +28 -0
- package/dist/src/git/lfs.js +66 -0
- package/dist/src/git/objects.js +3 -8
- package/dist/src/git/smart-http.d.ts +3 -1
- package/dist/src/git/smart-http.js +67 -6
- package/dist/src/graphql-wire.d.ts +29 -0
- package/dist/src/graphql-wire.js +101 -0
- package/dist/src/grpc-wire.d.ts +67 -0
- package/dist/src/grpc-wire.js +170 -0
- package/dist/src/h2.d.ts +40 -0
- package/dist/src/h2.js +656 -0
- package/dist/src/head.d.ts +32 -3
- package/dist/src/head.js +161 -40
- package/dist/src/history.d.ts +1 -1
- package/dist/src/history.js +6 -6
- package/dist/src/hpack.json +1 -0
- package/dist/src/index.d.ts +64 -75
- package/dist/src/index.js +58 -101
- package/dist/src/log.js +28 -19
- package/dist/src/machines.d.ts +50 -0
- package/dist/src/machines.js +151 -0
- package/dist/src/managed-database.d.ts +86 -0
- package/dist/src/managed-database.js +283 -0
- package/dist/src/multipart.d.ts +11 -0
- package/dist/src/multipart.js +51 -0
- package/dist/src/observe.d.ts +15 -5
- package/dist/src/observe.js +23 -9
- package/dist/src/openai-wire.d.ts +108 -0
- package/dist/src/openai-wire.js +337 -0
- package/dist/src/pack-assets.d.ts +3 -4
- package/dist/src/pack-assets.js +15 -10
- package/dist/src/pack-fetch.d.ts +77 -0
- package/dist/src/pack-fetch.js +449 -0
- package/dist/src/pack-paths.d.ts +12 -0
- package/dist/src/pack-paths.js +86 -0
- package/dist/src/packRegistry.d.ts +69 -162
- package/dist/src/packRegistry.js +55 -20
- package/dist/src/people.d.ts +13 -0
- package/dist/src/people.js +18 -0
- package/dist/src/placeholder-image.d.ts +5 -0
- package/dist/src/placeholder-image.js +114 -0
- package/dist/src/protobuf.d.ts +28 -0
- package/dist/src/protobuf.js +332 -0
- package/dist/src/redis/engine.js +1 -1
- package/dist/src/request-scope.d.ts +1 -1
- package/dist/src/request-scope.js +6 -4
- package/dist/src/resource-blob.d.ts +5 -0
- package/dist/src/resource-blob.js +11 -0
- package/dist/src/runtime.d.ts +85 -0
- package/dist/src/runtime.js +104 -0
- package/dist/src/s3/wire.d.ts +60 -0
- package/dist/src/s3/wire.js +157 -0
- package/dist/src/scenario.d.ts +3 -0
- package/dist/src/scenario.js +2 -0
- package/dist/src/schema-sample.d.ts +1 -0
- package/dist/src/schema-sample.js +21 -0
- package/dist/src/sealed-box.d.ts +14 -0
- package/dist/src/sealed-box.js +225 -0
- package/dist/src/serve-http.d.ts +14 -0
- package/dist/src/serve-http.js +27 -3
- package/dist/src/serve.d.ts +6 -0
- package/dist/src/serve.js +69 -14
- package/dist/src/signing.d.ts +135 -0
- package/dist/src/signing.js +222 -0
- package/dist/src/sigv4.d.ts +48 -0
- package/dist/src/sigv4.js +167 -0
- package/dist/src/smtp.d.ts +16 -0
- package/dist/src/smtp.js +72 -0
- package/dist/src/sockets.d.ts +51 -0
- package/dist/src/sockets.js +90 -0
- package/dist/src/state-system.d.ts +1 -0
- package/dist/src/state-system.js +1 -1
- package/dist/src/storage.d.ts +1 -1
- package/dist/src/storage.js +3 -3
- package/dist/src/trace-context.js +1 -1
- package/dist/src/twin-fetch.d.ts +0 -7
- package/dist/src/twin-fetch.js +0 -14
- package/dist/src/vendor-call.d.ts +6 -0
- package/dist/src/vendor-call.js +41 -0
- package/dist/src/world-store.js +1 -1
- package/dist/vendor-hosts.cjs +36 -125
- package/dist/vendor-hosts.d.cts +8 -0
- package/generated/pack-facts.json +1410 -3069
- package/inject.cjs +64 -9
- package/pack-facts.cjs +44 -0
- package/package.json +17 -3
- package/src/actions.ts +23 -16
- package/src/ancestry.ts +74 -2
- package/src/anthropic-wire.ts +137 -0
- package/src/bytes.ts +42 -0
- package/src/changeset.ts +5 -5
- package/src/clickhouse/index.ts +6 -0
- package/src/clickhouse/sql.ts +3059 -0
- package/src/clickhouse/types.ts +44 -0
- package/src/clickhouse/values.ts +697 -0
- package/src/client-bundle.ts +2 -3
- package/src/cors.ts +34 -0
- package/src/derived-core.ts +1013 -146
- package/src/derived-real.ts +434 -0
- package/src/derived.ts +73 -3
- package/src/emit.ts +1 -2
- package/src/events.ts +449 -0
- package/src/executor.ts +24 -2
- package/src/file-response.ts +27 -0
- package/src/fork.ts +3 -2
- package/src/git/history.ts +19 -0
- package/src/git/index.ts +1 -0
- package/src/git/lfs.ts +67 -0
- package/src/git/objects.ts +3 -5
- package/src/git/smart-http.ts +56 -6
- package/src/graphql-wire.ts +106 -0
- package/src/grpc-wire.ts +159 -0
- package/src/h2.ts +627 -0
- package/src/head.ts +132 -41
- package/src/history.ts +6 -6
- package/src/hpack.json +1 -0
- package/src/index.ts +82 -329
- package/src/log.ts +27 -18
- package/src/machines.ts +151 -0
- package/src/managed-database.ts +299 -0
- package/src/multipart.ts +51 -0
- package/src/observe.ts +31 -15
- package/src/openai-wire.ts +371 -0
- package/src/pack-assets.ts +15 -11
- package/src/pack-fetch.ts +458 -0
- package/src/pack-paths.ts +72 -0
- package/src/packRegistry.ts +79 -167
- package/src/people.ts +31 -0
- package/src/placeholder-image.ts +88 -0
- package/src/protobuf.ts +251 -0
- package/src/redis/engine.ts +1 -1
- package/src/request-scope.ts +8 -4
- package/src/resource-blob.ts +13 -0
- package/src/runtime.ts +344 -0
- package/src/s3/wire.ts +172 -0
- package/src/scenario.ts +4 -0
- package/src/schema-sample.ts +24 -0
- package/src/sealed-box.ts +182 -0
- package/src/serve-http.ts +31 -3
- package/src/serve.ts +58 -14
- package/src/signing.ts +231 -0
- package/src/sigv4.ts +158 -0
- package/src/smtp.ts +76 -0
- package/src/sockets.ts +140 -0
- package/src/state-system.ts +2 -2
- package/src/storage.ts +3 -3
- package/src/trace-context.ts +1 -1
- package/src/twin-fetch.ts +0 -20
- package/src/vendor-call.ts +41 -0
- package/src/world-store.ts +1 -1
- package/vendor-hosts.cjs +36 -125
- package/vendor-hosts.d.cts +8 -0
- package/dist/src/mirror-shell.d.ts +0 -2
- package/dist/src/mirror-shell.js +0 -13
- package/dist/src/v1-removed.d.ts +0 -159
- package/dist/src/v1-removed.js +0 -124
- package/src/mirror-shell.ts +0 -15
- package/src/v1-removed.ts +0 -172
package/dist/src/index.js
CHANGED
|
@@ -1,102 +1,59 @@
|
|
|
1
|
-
// @volter/world-core — the
|
|
2
|
-
// Protocol
|
|
3
|
-
//
|
|
4
|
-
// and
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export {
|
|
36
|
-
export {
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
export {
|
|
54
|
-
export {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export { FsBlobStore, MemoryBlobStore, blobDigest, getActiveBlobStore, setActiveBlobStore, withBlobStore, readBlobRange, } from "./blob-store.js";
|
|
58
|
-
export { applyTwinWrite, applyTwinWriteAtomic, createTwinServer, CALLER_HEADER, journalTwinRequest, twinRequestJournalFailures, twinRequestCredentials, readTwinRequestJournal, resolveTwinRead, twinRequestJournalEnabled, twinRequestJournalPath, readTwinRequestJournalFrom, twinResources, } from "./serve.js";
|
|
59
|
-
export { createTwinProxy } from "./proxy.js";
|
|
60
|
-
export { forkTwin, isFork, readForkMeta, } from "./fork.js";
|
|
61
|
-
export { appendAction, appendTransactionCommit, checkPrecondition, confirmAction, listActions, listTransactionCommits, pendingActions, pushablePendingActions, isTwinBookkeeping, pendingTransactionCommits, projectResources, projectOwnerResources, OwnerStoreAmbiguousError, revertAction, TwinActionPreconditionError, subjectAliases, resolveSubjectId, runWithCorrelationId, currentCorrelationId } from "./actions.js";
|
|
62
|
-
// ── Operator control plane (R19/R20): remote refs, queue lifecycle, push ledger,
|
|
63
|
-
// apply leases, plan, status. (the twins architecture notes)
|
|
64
|
-
// The CHANGESET primitive + the ledger DIFF (docs/concepts/the-model.md v0) — "commit" and
|
|
65
|
-
// "diff" for operational reality: a cross-service base marker, the ledger delta since it, and
|
|
66
|
-
// the content-addressed, replayable changeset over that delta. State-level by construction
|
|
67
|
-
// (it reads the same per-service action ledgers `actions.ts` writes); `volter-world` supplies
|
|
68
|
-
// world discovery and thin verbs on top.
|
|
69
|
-
export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, approverOf, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from "./changeset.js";
|
|
70
|
-
export { getActivePackAssets, setActivePackAssets, packAsset, assetContentType, confinedAssetPath, LocalPackAssets, BindingPackAssets } from "./pack-assets.js";
|
|
71
|
-
// The git plane (contract "The git plane is a kernel library"): objects, packs, refs, smart HTTP.
|
|
1
|
+
// @volter/world-core — the pack contract (docs/contributing/architecture.md, "The pack contract: the kernel's root").
|
|
2
|
+
// This root is everything a Protocol 3 pack may import from the kernel, and nothing else: the manifest's and the
|
|
3
|
+
// descriptor's types, the handler contract, the derived fetch and core a pack's fetch.ts builds, the serve factory's
|
|
4
|
+
// pieces, the kernel's deterministic helpers and the scenario grammar. The kernel itself (the log and the tree read
|
|
5
|
+
// and written directly, the head, the stores, the runtime's scopes) and the plugin contract's surfaces are
|
|
6
|
+
// `@volter/world-core/runtime`, which a pack never imports.
|
|
7
|
+
import { bindSemantics as bindAny } from "./derived-core.js";
|
|
8
|
+
import { packOf as packOfAny, registerPack as registerAny } from "./packRegistry.js";
|
|
9
|
+
/** The descriptor a manifest declares, with its vendor ("The descriptor"); given the pack's generated surface (a vendor of
|
|
10
|
+
* lanes: each lane's manifest and surface), with the real-system adapters the kernel derives from them. */
|
|
11
|
+
export const packOf = (manifest, surface) => packOfAny(manifest, surface);
|
|
12
|
+
/** The pack registered, so the World finds it. */
|
|
13
|
+
export const registerPack = (pack) => registerAny(pack);
|
|
14
|
+
export { verifyEvent } from "./events.js";
|
|
15
|
+
export { deriveStateSystem, deriveVendorStateSystem } from "./derived-real.js";
|
|
16
|
+
export { machinePool } from "./machines.js";
|
|
17
|
+
/** A pack's handlers, by operationId, bound to the manifest: each is answered over the contract's context. */
|
|
18
|
+
export const bindSemantics = (m, handlers, scope = {}) => bindAny(m, handlers, scope);
|
|
19
|
+
// ── the derived fetch ──────────────────────────────────────────────────────────────────────────
|
|
20
|
+
export { createPackFetch, createVendorFetch } from "./pack-fetch.js";
|
|
21
|
+
export { createDerivedFetch } from "./derived.js";
|
|
22
|
+
export { coreFor, crossCutting, derivedRequestScopes, vendorError } from "./derived-core.js";
|
|
23
|
+
export { answerVendorErrors, RefusedWriteError } from "./head.js";
|
|
24
|
+
// a GraphQL API's resolvers (`semantics/graphql.ts`), and the error one answers with the vendor's type
|
|
25
|
+
export { GraphqlError } from "./graphql-wire.js";
|
|
26
|
+
// what `ctx.vendorFetch` throws when the other vendor cannot be reached (a vendor's call to another as its own behaviour)
|
|
27
|
+
export { VendorUnreachableError } from "./vendor-call.js";
|
|
28
|
+
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER } from "./request-scope.js";
|
|
29
|
+
// ── the serve factory ──────────────────────────────────────────────────────────────────────────
|
|
30
|
+
export { serveHttp, serveStream } from "./serve-http.js";
|
|
31
|
+
export { statefulTwinManifest, twinManifest } from "./scenario.js";
|
|
32
|
+
export { assetContentType, packAsset } from "./pack-assets.js";
|
|
33
|
+
export { bytesResponse, contentTypeOf, fileResponse } from "./file-response.js";
|
|
34
|
+
// ── the kernel's deterministic helpers ─────────────────────────────────────────────────────────
|
|
35
|
+
export { certificateOf, digest, digestBytes, equalSecrets, oauth1BaseString, oauth1Encode, oauth1Header, oauth1Signature, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, publicKeyOf, sha256, signWith, SIGNING_ALGORITHMS, uuidFrom, verifyWith } from "./signing.js";
|
|
36
|
+
export { blobDigest } from "./blob-store.js";
|
|
37
|
+
// compressed bytes a wire carries (a SARIF upload), over web streams
|
|
38
|
+
export { gunzip, gzip } from "./bytes.js";
|
|
39
|
+
// a row's own fields, where the tree's reserved ones (id, type, updatedAt) shadow the vendor's of the same name
|
|
40
|
+
export { ownFields } from "./log.js";
|
|
41
|
+
// the people a vendor's pages sign in (a `_person` row with its password's hash)
|
|
42
|
+
export { passwordHash, personOf, personWith, recordPerson } from "./people.js";
|
|
43
|
+
// the World's managed Postgres a handler reaches as `ctx.engine` (managed-database.ts), and a mail's route (`ctx.mail`)
|
|
44
|
+
export { EngineDatabaseError, EngineUnavailableError, quoteIdent, worldClockSql } from "./managed-database.js";
|
|
45
|
+
// S3's wire (contract "S3's wire is a kernel library too") and the git plane (contract "The git plane is a kernel library")
|
|
46
|
+
export * as s3 from "./s3/wire.js";
|
|
47
|
+
export * as clickhouse from "./clickhouse/index.js";
|
|
48
|
+
export { sampleFromSchema } from "./schema-sample.js";
|
|
49
|
+
export * as openaiWire from "./openai-wire.js";
|
|
50
|
+
export * as anthropicWire from "./anthropic-wire.js";
|
|
51
|
+
export * as protobuf from "./protobuf.js";
|
|
52
|
+
export * as grpc from "./grpc-wire.js";
|
|
53
|
+
export { acceptH2Connection } from "./h2.js";
|
|
54
|
+
export { placeholderPng } from "./placeholder-image.js";
|
|
55
|
+
export { presignSigV4, signSigV4, verifySigV4 } from "./sigv4.js";
|
|
56
|
+
export * as redis from "./redis/index.js";
|
|
72
57
|
export * as git from "./git/index.js";
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
export { PLACEHOLDER_REMOTE, beginPlaceholderPull, endPlaceholderPull, placeholderPullActive, placeholderPullMarkerPath, withPlaceholderPull, placeholderEventsFor } from "./placeholder-remote.js";
|
|
76
|
-
export { ownFields, subjectHistory, rebaseBranch, cutCheckpoint, appendParentEntry, wholeLog, branchEntries, branchLogPath, branchMetaPath, CHECKPOINT_EVERY, dropCheckpoint, foldEntries, landedCopy, landedIds, parentEntries, parentLogPath, position, readBranchMeta, readTree, toEntry, toEvent, unpushedEntries, writeBranchMeta } from "./log.js";
|
|
77
|
-
export { sealCredential, openSealedCredential, MemoryCredentialStorage, keySealer, transitSealer } from "./credential.js";
|
|
78
|
-
export { validateRemoteOrigin, buildRemoteExecute } from "./executor.js";
|
|
79
|
-
export { clearRoot, authStrategyFor, clearStateSystems, NO_SECRETS_CHECK, readRoot, registerAuthStrategy, registerStateSystem, rootPath, runChecks, stateSystemFor, writeRoot } from "./state-system.js";
|
|
80
|
-
export { observeAppends } from "./actions.js";
|
|
81
|
-
export { appendActionIfAbsent, appendActionOccurrence } from "./actions.js";
|
|
82
|
-
// PROTOCOL 2 — the head and the fold (company contract "The head", "Refresh is the kernel's fold")
|
|
83
|
-
export { answerVendorErrors, performEntries, performAtHead, deployableEntries, headOf, boundRoot, loadChecks, loadCheck, openRootCredential, resealRootCredential, destinationOf, openSealedRecord, sealsThroughVault, rootCustody, sealingKey, setCheckLoader, setSealingKeySource, setSealer, currentSealer, openSealedAt, userKek, userKekPath, vendorOf, worldRootOf, RefusedWriteError, VendorWriteError, HeadError } from "./head.js";
|
|
84
|
-
export { observeResource, observeResources, collectObservations, foldObservations } from "./observe.js";
|
|
85
|
-
export { readTreeMap, readParentTreeMap, treeStamp, treeChangesSince, originEntries, appendOriginEntry, originLogPath, isUrlParent, parentPosition, positionAt, splitsBatch, assertBatchBoundary } from "./log.js";
|
|
86
|
-
// v1 left the kernel (contract "Just like Neon", 5): the names a protocol 1 pack still imports throw on
|
|
87
|
-
// their first call, so the catalog stays importable and a pack out of date fails loudly.
|
|
88
|
-
export * from "./v1-removed.js";
|
|
89
|
-
export { referenceField, registerReferences, packReferences, resolveReferences } from "./references.js";
|
|
90
|
-
// the HTTP server seam: the one place the serve path meets the runtime (Bun or Node)
|
|
91
|
-
export { serveHttp, nodeBuiltin, WORLD_BOOT_PATH } from "./serve-http.js";
|
|
92
|
-
// two runtime-neutral helpers for a pack's serve path: a file as a Response, a mirror's client bundle
|
|
93
|
-
export { fileResponse, contentTypeOf } from "./file-response.js";
|
|
94
|
-
export { bundleClient, filePathOf } from "./client-bundle.js";
|
|
95
|
-
// the brand's tokens and faces for a Volter page (the console, the site, the UI kit), fetched at build
|
|
96
|
-
export { brandTokensResponse } from "./brand-tokens.js";
|
|
97
|
-
export { readResourceBlob, readResourceBlobRange, resourceBlobSize, resourceChain } from "./resource-blob.js";
|
|
98
|
-
export { mirrorShellUnder } from "./mirror-shell.js";
|
|
99
|
-
export { assertStateRemovable, checkParent, stateGeneration, withAncestryLock, withStateRemoval } from "./ancestry.js";
|
|
100
|
-
export { captureHistory, captureParentHistory, historyChanges, historyAtInstant, historyDigest, historyEntries, historyLength, historyPrefix, inheritedHistory, originHead, publishOriginHistory, readHistoryView } from "./history.js";
|
|
101
|
-
export { foldHistory } from "./log.js";
|
|
102
|
-
export { volterHome } from "./volter-home.js";
|
|
58
|
+
// ── the scenario grammar (architecture, "Behaviour") ───────────────────────────────────────────
|
|
59
|
+
export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError } from "./scenario.js";
|
package/dist/src/log.js
CHANGED
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
// and the fold skips a branch entry whose id the parent already holds. Nothing is suppressed,
|
|
21
21
|
// rebound or quarantined by a bookkeeping row; `unpushed` is the branch log minus what the parent
|
|
22
22
|
// holds. The parent log accepts the v1 observed-event rows too (`toEntry` reads a delta event as
|
|
23
|
-
// an entry; a non-delta observation folds nothing and is kept for `listEvents`), so a
|
|
24
|
-
//
|
|
23
|
+
// an entry; a non-delta observation folds nothing and is kept for `listEvents`), so a World whose
|
|
24
|
+
// log was written in that form still reads.
|
|
25
25
|
import { captureHistory, historyChanges, historyEntryTime, historyEntries, historyLength, historyPrefix, inheritedHistory, inheritedHistoryKey, originHead, readHistoryView, replaceHistoryOrigin, saveHistoryView, validateHistoryOrigin } from "./history.js";
|
|
26
26
|
import { dirname, join } from 'node:path';
|
|
27
|
-
import { canonicalStatePath, checkParent, commitParentPin, pinParent, withAncestryLock } from "./ancestry.js";
|
|
27
|
+
import { canonicalStatePath, checkParent, commitParentPin, pinParent, withAncestryLock, withHistoryLock } from "./ancestry.js";
|
|
28
28
|
import { resolveReferences } from "./references.js";
|
|
29
29
|
import { hashFieldValue } from "./hash.js";
|
|
30
30
|
import { worldPaths } from "./storage.js";
|
|
@@ -122,7 +122,9 @@ export function readBranchMeta(service, root) {
|
|
|
122
122
|
return meta;
|
|
123
123
|
}
|
|
124
124
|
export function writeBranchMeta(service, meta, root) {
|
|
125
|
-
|
|
125
|
+
// Under the branch's own history lock (a capture of its parent's nests inside it, child before ancestor); only the
|
|
126
|
+
// pin and the pointer's publication take the coordinator.
|
|
127
|
+
withHistoryLock(worldPaths(service, root).dir, () => {
|
|
126
128
|
if (meta.parent && (!Number.isInteger(meta.parent.position) || meta.parent.position < 0))
|
|
127
129
|
throw new Error('Invalid branch position');
|
|
128
130
|
const path = branchMetaPath(service, root);
|
|
@@ -141,6 +143,7 @@ export function writeBranchMeta(service, meta, root) {
|
|
|
141
143
|
previousParents.push({ directory: old.parent.directory, generation: old.parent.generation });
|
|
142
144
|
if (previousParents.length)
|
|
143
145
|
meta = { ...meta, previousParents: [...new Map(previousParents.map(p => [p.directory, p])).values()] };
|
|
146
|
+
let local;
|
|
144
147
|
if (meta.parent && !isUrlParent(meta.parent.at)) {
|
|
145
148
|
const directory = canonicalStatePath(worldPaths(service, meta.parent.at).dir);
|
|
146
149
|
const view = meta.parent.view ?? captureHistory(service, meta.parent.at).view;
|
|
@@ -149,9 +152,8 @@ export function writeBranchMeta(service, meta, root) {
|
|
|
149
152
|
throw new Error('Composed history view must belong to this branch');
|
|
150
153
|
const descriptor = readHistoryView(viewDirectory, view);
|
|
151
154
|
historyPrefix(descriptor, meta.parent.position);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
meta = { ...meta, parent: { ...parent, view, at: canonicalStatePath(parent.at), directory, generation } };
|
|
155
|
+
// the parent the view was captured from: a parent removed or re-created since is refused at the pin
|
|
156
|
+
local = { directory, view, generation: meta.parent.generation ?? (viewDirectory === directory ? descriptor.owner.generation : undefined) };
|
|
155
157
|
}
|
|
156
158
|
if (meta.parent && isUrlParent(meta.parent.at) && !meta.parent.view) {
|
|
157
159
|
const head = originHead(service, root);
|
|
@@ -164,10 +166,17 @@ export function writeBranchMeta(service, meta, root) {
|
|
|
164
166
|
else
|
|
165
167
|
throw new Error('Origin has no completed immutable history view');
|
|
166
168
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
withAncestryLock(() => {
|
|
170
|
+
if (local && meta.parent) {
|
|
171
|
+
const parent = meta.parent;
|
|
172
|
+
const generation = pinParent(local.directory, path, local.generation);
|
|
173
|
+
meta = { ...meta, parent: { ...parent, view: local.view, at: canonicalStatePath(parent.at), directory: local.directory, generation } };
|
|
174
|
+
}
|
|
175
|
+
getActiveWorldStore().mkdir(dirname(path));
|
|
176
|
+
getActiveWorldStore().writeAtomic(path, `${JSON.stringify(meta, null, 2)}\n`);
|
|
177
|
+
if (meta.parent?.directory && !isUrlParent(meta.parent.at))
|
|
178
|
+
commitParentPin(meta.parent.directory, path);
|
|
179
|
+
});
|
|
171
180
|
});
|
|
172
181
|
}
|
|
173
182
|
/** A v1 observed row as an entry: a delta event folds its `changed.*.after`; anything else folds
|
|
@@ -234,7 +243,7 @@ export function appendOriginEntry(entry, root) {
|
|
|
234
243
|
const path = originLogPath(entry.service, root);
|
|
235
244
|
const store = getActiveWorldStore();
|
|
236
245
|
store.mkdir(dirname(path));
|
|
237
|
-
return
|
|
246
|
+
return withHistoryLock(worldPaths(entry.service, root).dir, () => store.withLock(`${path}.lock`, () => {
|
|
238
247
|
if (readRows(path).some((r) => r.id === entry.id))
|
|
239
248
|
return { appended: false };
|
|
240
249
|
store.append(path, `${JSON.stringify(entry)}\n`);
|
|
@@ -386,7 +395,7 @@ export function readTree(service, root, opts = {}) {
|
|
|
386
395
|
/** The upstream view for observation diffing, without this root's local overlay. Inherited
|
|
387
396
|
* history keeps its own layout: an ancestor's local writes are part of our pinned base. */
|
|
388
397
|
export function readParentTreeMap(service, root) {
|
|
389
|
-
return
|
|
398
|
+
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
390
399
|
const inherited = inheritedHistory(service, root);
|
|
391
400
|
const own = ownParentEntries(service, root);
|
|
392
401
|
return foldHistory([...(inherited ? historyEntries(inherited) : []), ...own], {
|
|
@@ -459,12 +468,12 @@ function currentTree(service, root) {
|
|
|
459
468
|
treeMemos.set(store, memos);
|
|
460
469
|
}
|
|
461
470
|
const slot = `${service}\u0000${root ?? ''}`;
|
|
462
|
-
// A hit needs no
|
|
471
|
+
// A hit needs no lock: a memo is only ever stored from a fold made under the history lock, and while the
|
|
463
472
|
// facts still match that fold, nothing was written since. A writer mid-batch has moved them.
|
|
464
473
|
const unlocked = memos.get(slot);
|
|
465
474
|
if (unlocked && unlocked.parentKey === parentKeyOf(service, root) && unlocked.branchKey === statKey(branchLogPath(service, root)))
|
|
466
475
|
return { tree: unlocked.tree, memo: unlocked };
|
|
467
|
-
return
|
|
476
|
+
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
468
477
|
const parentKey = parentKeyOf(service, root);
|
|
469
478
|
const branchKey = statKey(branchLogPath(service, root));
|
|
470
479
|
const held = memos.get(slot);
|
|
@@ -548,7 +557,7 @@ export function treeChangesSince(service, root, since) {
|
|
|
548
557
|
return { stamp, changed: treeResources(present), removed, appended: [...order.keys()].filter((k) => tree.has(k)) };
|
|
549
558
|
}
|
|
550
559
|
function readTreeMapFull(service, root, opts = {}) {
|
|
551
|
-
return
|
|
560
|
+
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
552
561
|
if (opts.at !== undefined || opts.view !== undefined) {
|
|
553
562
|
const view = opts.view ? readHistoryView(worldPaths(service, root).dir, opts.view) : captureHistory(service, root).descriptor;
|
|
554
563
|
const at = opts.at ?? historyLength(view.layout);
|
|
@@ -603,7 +612,7 @@ function readTreeMapFull(service, root, opts = {}) {
|
|
|
603
612
|
});
|
|
604
613
|
}
|
|
605
614
|
export function cutCheckpoint(service, root) {
|
|
606
|
-
return
|
|
615
|
+
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
607
616
|
dropCheckpoint(service, root);
|
|
608
617
|
const subjects = [...readTreeMap(service, root).values()];
|
|
609
618
|
const inherited = inheritedHistory(service, root);
|
|
@@ -691,7 +700,7 @@ export function appendParentEntry(entry, root) {
|
|
|
691
700
|
const path = parentLogPath(entry.service, root);
|
|
692
701
|
const store = getActiveWorldStore();
|
|
693
702
|
store.mkdir(dirname(path));
|
|
694
|
-
return
|
|
703
|
+
return withHistoryLock(worldPaths(entry.service, root).dir, () => store.withLock(`${path}.lock`, () => {
|
|
695
704
|
let indexes = parentIdIndex.get(store);
|
|
696
705
|
if (!indexes) {
|
|
697
706
|
indexes = new Map();
|
|
@@ -724,7 +733,7 @@ export function wholeLog(service, root) {
|
|
|
724
733
|
* result, never a stop. An unbranched world (no pointer) has nothing to rebase.
|
|
725
734
|
*/
|
|
726
735
|
export function rebaseBranch(service, root, opts = {}) {
|
|
727
|
-
return
|
|
736
|
+
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
728
737
|
const meta = readBranchMeta(service, root);
|
|
729
738
|
if (!meta?.parent)
|
|
730
739
|
return { moved: false, from: 0, to: 0, conflicts: [] };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type MachineSpec = {
|
|
2
|
+
name: string;
|
|
3
|
+
image: string;
|
|
4
|
+
env?: Record<string, string>;
|
|
5
|
+
ports?: number[];
|
|
6
|
+
command?: string[];
|
|
7
|
+
};
|
|
8
|
+
export type MachineRun = {
|
|
9
|
+
ports: Array<{
|
|
10
|
+
internal: number;
|
|
11
|
+
host: number;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
/** A process started in a machine: its pid, and what it writes and how it ends, as they happen. */
|
|
15
|
+
export type MachineProcess = {
|
|
16
|
+
pid: number;
|
|
17
|
+
events: AsyncIterable<{
|
|
18
|
+
stdout?: string;
|
|
19
|
+
} | {
|
|
20
|
+
stderr?: string;
|
|
21
|
+
} | {
|
|
22
|
+
exit: number;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
export type ExecSpec = {
|
|
26
|
+
args: string[];
|
|
27
|
+
env?: Record<string, string>;
|
|
28
|
+
cwd?: string;
|
|
29
|
+
};
|
|
30
|
+
export type MachinePool = {
|
|
31
|
+
readonly kind: 'docker' | 'none' | 'fake';
|
|
32
|
+
/** runs the image; a failure (no container runtime, an image that will not start) rejects with the runtime's message */
|
|
33
|
+
run(spec: MachineSpec): Promise<MachineRun>;
|
|
34
|
+
/** starts a process in a running machine; a machine the pool does not run rejects */
|
|
35
|
+
exec(name: string, spec: ExecSpec): Promise<MachineProcess>;
|
|
36
|
+
stop(name: string): Promise<void>;
|
|
37
|
+
remove(name: string): Promise<void>;
|
|
38
|
+
/** the fake pool's record of what it was asked */
|
|
39
|
+
readonly asked?: Array<{
|
|
40
|
+
act: 'run' | 'exec' | 'stop' | 'remove';
|
|
41
|
+
name: string;
|
|
42
|
+
spec?: MachineSpec;
|
|
43
|
+
exec?: ExecSpec;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
46
|
+
export declare const MACHINE_POOL = "_machine_pool";
|
|
47
|
+
export declare const POOL_KINDS: readonly ["docker", "none", "fake"];
|
|
48
|
+
/** The pool of a kind, for a World (`world`: the mark its containers carry). */
|
|
49
|
+
export declare function machinePool(kind: MachinePool['kind'], world?: string): MachinePool;
|
|
50
|
+
export declare function poolFor(service: string, root: string | undefined, kind: MachinePool['kind']): MachinePool;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// The World's machine pool (architecture, "Other wires: … machines"): what runs a vendor's customer's image when the
|
|
2
|
+
// vendor is one that runs images (Fly's Machines). It is a platform provider enrolled through the kernel's door
|
|
3
|
+
// `POST /_twin/machine-pool`, recorded in the pack's own tree; a handler reaches it as `ctx.machines`. `docker` runs
|
|
4
|
+
// each machine as a local container with its internal ports published on loopback; `none` runs nothing; `fake`
|
|
5
|
+
// records what it was asked (capability verification). Nothing here runs at module scope, and `node:child_process`
|
|
6
|
+
// is reached only when a docker pool is asked to act.
|
|
7
|
+
import { nodeBuiltin } from "./serve-http.js";
|
|
8
|
+
export const MACHINE_POOL = '_machine_pool';
|
|
9
|
+
export const POOL_KINDS = ['docker', 'none', 'fake'];
|
|
10
|
+
/** A container's name for a machine: the World's prefix, the World's own mark (a machine id repeats across Worlds and
|
|
11
|
+
* branches, which mint alike), then the vendor's machine name made safe for docker. */
|
|
12
|
+
const containerName = (world, name) => `volter-world-machine-${world}-${name.replace(/[^A-Za-z0-9_.-]/g, '-')}`;
|
|
13
|
+
// an image's pull is the slow step: a run may take two minutes before the pool gives up; anything else, thirty seconds
|
|
14
|
+
const RUN_TIMEOUT_MS = 120_000;
|
|
15
|
+
const STEP_TIMEOUT_MS = 30_000;
|
|
16
|
+
function dockerPool(world) {
|
|
17
|
+
// asynchronous, so a pull never holds the World's other requests (or a socket's heartbeats) behind it
|
|
18
|
+
const docker = (args, timeout = STEP_TIMEOUT_MS) => new Promise((resolve, reject) => {
|
|
19
|
+
const { execFile } = nodeBuiltin('node:child_process');
|
|
20
|
+
execFile('docker', args, { encoding: 'utf8', timeout }, (error, stdout, stderr) => (error ? reject(new Error(String(stderr || error.message).trim())) : resolve(String(stdout).trim())));
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
kind: 'docker',
|
|
24
|
+
async run(spec) {
|
|
25
|
+
const name = containerName(world, spec.name);
|
|
26
|
+
await docker(['rm', '-f', name]).catch(() => undefined);
|
|
27
|
+
const env = Object.entries(spec.env ?? {}).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
|
|
28
|
+
const ports = (spec.ports ?? []).flatMap((p) => ['-p', `127.0.0.1::${p}`]);
|
|
29
|
+
await docker(['run', '-d', '--name', name, ...env, ...ports, spec.image, ...(spec.command ?? [])], RUN_TIMEOUT_MS);
|
|
30
|
+
const published = [];
|
|
31
|
+
for (const internal of spec.ports ?? []) {
|
|
32
|
+
const line = (await docker(['port', name, String(internal)])).split('\n')[0] ?? '';
|
|
33
|
+
published.push({ internal, host: Number(line.split(':').at(-1)) });
|
|
34
|
+
}
|
|
35
|
+
return { ports: published };
|
|
36
|
+
},
|
|
37
|
+
async exec(name, spec) {
|
|
38
|
+
const { spawn } = nodeBuiltin('node:child_process');
|
|
39
|
+
const env = Object.entries(spec.env ?? {}).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
|
|
40
|
+
// the shell names its own pid first, then becomes the process: its pid is the process's
|
|
41
|
+
const child = spawn('docker', ['exec', '-i', ...env, ...(spec.cwd ? ['-w', spec.cwd] : []), containerName(world, name), 'sh', '-c', 'echo "@pid $$"; exec "$@"', 'sh', ...spec.args], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
42
|
+
const queue = [];
|
|
43
|
+
let wake;
|
|
44
|
+
let done = false;
|
|
45
|
+
let pid;
|
|
46
|
+
let head = '';
|
|
47
|
+
let stderr = '';
|
|
48
|
+
let settle;
|
|
49
|
+
const pidKnown = new Promise((resolve, reject) => { settle = { resolve, reject }; child.on('error', reject); });
|
|
50
|
+
const push = (e) => { queue.push(e); wake?.(); };
|
|
51
|
+
child.stdout.setEncoding('utf8').on('data', (chunk) => {
|
|
52
|
+
if (pid === undefined) {
|
|
53
|
+
// the pid line may arrive split across chunks: nothing is output until its newline is read
|
|
54
|
+
head += chunk;
|
|
55
|
+
const nl = head.indexOf('\n');
|
|
56
|
+
if (nl < 0)
|
|
57
|
+
return;
|
|
58
|
+
const m = /^@pid (\d+)$/.exec(head.slice(0, nl));
|
|
59
|
+
if (!m) {
|
|
60
|
+
push({ stdout: head });
|
|
61
|
+
head = '';
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
pid = Number(m[1]);
|
|
65
|
+
settle?.resolve(pid);
|
|
66
|
+
chunk = head.slice(nl + 1);
|
|
67
|
+
head = '';
|
|
68
|
+
}
|
|
69
|
+
if (chunk)
|
|
70
|
+
push({ stdout: chunk });
|
|
71
|
+
});
|
|
72
|
+
child.stderr.setEncoding('utf8').on('data', (chunk) => { if (pid === undefined)
|
|
73
|
+
stderr += chunk; push({ stderr: chunk }); });
|
|
74
|
+
child.on('close', (code, signal) => {
|
|
75
|
+
// a machine the pool does not run (docker exec fails before the shell starts) rejects, with docker's words
|
|
76
|
+
if (pid === undefined)
|
|
77
|
+
settle?.reject(new Error(stderr.trim() || `the process did not start (exit ${code ?? signal})`));
|
|
78
|
+
// a process ended by a signal exits as a shell reports it: 128 and the signal's number
|
|
79
|
+
const signals = { SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGTERM: 15 };
|
|
80
|
+
push({ exit: code ?? (signal ? 128 + (signals[signal] ?? 0) : 0) });
|
|
81
|
+
done = true;
|
|
82
|
+
wake?.();
|
|
83
|
+
});
|
|
84
|
+
const events = {
|
|
85
|
+
async *[Symbol.asyncIterator]() {
|
|
86
|
+
for (;;) {
|
|
87
|
+
while (queue.length) {
|
|
88
|
+
const e = queue.shift();
|
|
89
|
+
yield e;
|
|
90
|
+
if ('exit' in e)
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (done)
|
|
94
|
+
return;
|
|
95
|
+
await new Promise((r) => { wake = r; });
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
let timer;
|
|
100
|
+
const timeout = new Promise((_, reject) => { timer = setTimeout(() => reject(new Error('the process did not start')), STEP_TIMEOUT_MS); });
|
|
101
|
+
try {
|
|
102
|
+
return { pid: await Promise.race([pidKnown, timeout]), events };
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
async stop(name) { await docker(['stop', containerName(world, name)]).catch(() => undefined); },
|
|
109
|
+
async remove(name) { await docker(['rm', '-f', containerName(world, name)]).catch(() => undefined); },
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** The pool of a kind, for a World (`world`: the mark its containers carry). */
|
|
113
|
+
export function machinePool(kind, world = 'world') {
|
|
114
|
+
if (kind === 'docker')
|
|
115
|
+
return dockerPool(world);
|
|
116
|
+
if (kind === 'fake') {
|
|
117
|
+
const asked = [];
|
|
118
|
+
return {
|
|
119
|
+
kind, asked,
|
|
120
|
+
async run(spec) { asked.push({ act: 'run', name: spec.name, spec }); return { ports: (spec.ports ?? []).map((internal) => ({ internal, host: 40_000 + internal })) }; },
|
|
121
|
+
async exec(name, spec) {
|
|
122
|
+
asked.push({ act: 'exec', name, exec: spec });
|
|
123
|
+
// a fake process: its pid the count of processes asked, and it ends at once
|
|
124
|
+
const pid = asked.filter((a) => a.act === 'exec').length + 100;
|
|
125
|
+
return { pid, events: (async function* () { yield { exit: 0 }; })() };
|
|
126
|
+
},
|
|
127
|
+
async stop(name) { asked.push({ act: 'stop', name }); },
|
|
128
|
+
async remove(name) { asked.push({ act: 'remove', name }); },
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
kind: 'none', async run() { return { ports: [] }; },
|
|
133
|
+
async exec() { throw new Error('no machine runs in this World: its machine pool is none'); },
|
|
134
|
+
async stop() { }, async remove() { },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/** A vendor's pool in a World, one per World and kind for the life of the process (a fake pool keeps what it was asked). */
|
|
138
|
+
const pools = new Map();
|
|
139
|
+
export function poolFor(service, root, kind) {
|
|
140
|
+
const key = `${service}\0${root ?? ''}\0${kind}`;
|
|
141
|
+
let pool = pools.get(key);
|
|
142
|
+
if (!pool) {
|
|
143
|
+
// the World's mark: a short digest of the vendor and the World's tree, so two Worlds' machines never share a name
|
|
144
|
+
let h = 0;
|
|
145
|
+
for (const ch of `${service}:${root ?? ''}`)
|
|
146
|
+
h = (Math.imul(h, 31) + ch.charCodeAt(0)) >>> 0;
|
|
147
|
+
pool = machinePool(kind, h.toString(16).padStart(8, '0'));
|
|
148
|
+
pools.set(key, pool);
|
|
149
|
+
}
|
|
150
|
+
return pool;
|
|
151
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** One statement of a batch; `values` travel as bind parameters (text, or null), never in the SQL text. */
|
|
2
|
+
export type Statement = {
|
|
3
|
+
text: string;
|
|
4
|
+
values?: ReadonlyArray<string | null>;
|
|
5
|
+
};
|
|
6
|
+
/** What one statement answered: its columns and rows in Postgres's text format, and its command tag. */
|
|
7
|
+
export type StatementResult = {
|
|
8
|
+
fields: string[];
|
|
9
|
+
rows: Array<Array<string | null>>;
|
|
10
|
+
command: string;
|
|
11
|
+
};
|
|
12
|
+
/** A Postgres error as the backend reported it (SQLSTATE and its fields), what a vendor's server passes through. */
|
|
13
|
+
export declare class EngineDatabaseError extends Error {
|
|
14
|
+
readonly code: string;
|
|
15
|
+
readonly detail: string | null;
|
|
16
|
+
readonly hint: string | null;
|
|
17
|
+
constructor(message: string, fields: {
|
|
18
|
+
code?: string;
|
|
19
|
+
detail?: string;
|
|
20
|
+
hint?: string;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/** The World's database cannot be reached: none is bound, or it does not answer. */
|
|
24
|
+
export declare class EngineUnavailableError extends Error {
|
|
25
|
+
constructor(message: string);
|
|
26
|
+
}
|
|
27
|
+
/** One transaction: as `role` (none: the twin's own login role, the vendor's servers' own work), with transaction-local
|
|
28
|
+
* `settings` (`request.jwt.claims`, `search_path`), READ ONLY when `readOnly` (a write is refused by Postgres itself,
|
|
29
|
+
* 25006), ended with ROLLBACK when `rollback` (a permission probe asked of Postgres and undone). */
|
|
30
|
+
export type Batch = {
|
|
31
|
+
role?: string;
|
|
32
|
+
settings?: Record<string, string>;
|
|
33
|
+
readOnly?: boolean;
|
|
34
|
+
rollback?: boolean;
|
|
35
|
+
statements: Statement[];
|
|
36
|
+
};
|
|
37
|
+
export interface ManagedDatabase {
|
|
38
|
+
/** Whether the World binds a database at all (a World with none refuses every batch). */
|
|
39
|
+
readonly bound: boolean;
|
|
40
|
+
/** One transaction as one pipeline and one Sync; the answer is the batch's own statements', in order. */
|
|
41
|
+
batch(batch: Batch): Promise<StatementResult[]>;
|
|
42
|
+
/** A whole SQL script as one simple Query (a vendor's migrations, several statements to a file). */
|
|
43
|
+
script(text: string): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
/** The transaction-local setting every batch a handler makes carries: the World clock at the call (ctx.occurredAt). */
|
|
46
|
+
export declare const WORLD_CLOCK_SETTING = "volter.world_clock";
|
|
47
|
+
/** The World clock inside the database, for the schemas a vendor lays (its migrations stamp rows with Postgres's
|
|
48
|
+
* `now()`, which reads the wall clock): `volter.now()`, the World clock the batch set or the wall clock where none is
|
|
49
|
+
* set, and every column default in `schemas` that reads `now()` or `CURRENT_TIMESTAMP` (alone or inside an expression,
|
|
50
|
+
* GoTrue's `timezone('utc', now())`) rewritten to read it. Run after the schemas are laid; running it again changes
|
|
51
|
+
* nothing. A trigger or function that calls `now()` itself is the pack's to redefine. */
|
|
52
|
+
export declare function worldClockSql(schemas: string[]): string;
|
|
53
|
+
/** Quote an identifier the way Postgres's quote_ident does for a name that needs it. */
|
|
54
|
+
export declare function quoteIdent(name: string): string;
|
|
55
|
+
/** The part of a Postgres driver the kernel uses: node-postgres's (`pg`) Pool and its clients. */
|
|
56
|
+
type PgClient = {
|
|
57
|
+
query(query: unknown): unknown;
|
|
58
|
+
release(error?: Error): void;
|
|
59
|
+
};
|
|
60
|
+
type PgPool = {
|
|
61
|
+
connect(): Promise<PgClient>;
|
|
62
|
+
end(): Promise<void>;
|
|
63
|
+
on(event: 'error', listener: (error: Error) => void): unknown;
|
|
64
|
+
};
|
|
65
|
+
export type DatabaseDriver = {
|
|
66
|
+
Pool: new (config: {
|
|
67
|
+
connectionString: string;
|
|
68
|
+
max: number;
|
|
69
|
+
idleTimeoutMillis: number;
|
|
70
|
+
connectionTimeoutMillis: number;
|
|
71
|
+
}) => PgPool;
|
|
72
|
+
};
|
|
73
|
+
/** A Postgres driver a host registers in place of node-postgres. */
|
|
74
|
+
export declare function useDatabaseDriver(given: DatabaseDriver): void;
|
|
75
|
+
/** The World's Postgres at `url` (the runtime's binding, never the environment); with `readOnly`, every transaction is
|
|
76
|
+
* READ ONLY whatever the batch asks (a read-only twin or request: Postgres itself refuses a write, 25006); with `clock`,
|
|
77
|
+
* every batch carries the World clock as `volter.world_clock`. */
|
|
78
|
+
export declare function managedDatabase(url: string, options?: {
|
|
79
|
+
readOnly?: boolean;
|
|
80
|
+
clock?: string;
|
|
81
|
+
}): ManagedDatabase;
|
|
82
|
+
/** A handler's database when the World binds none: every use is the refusal naming what to add. */
|
|
83
|
+
export declare function unboundDatabase(service: string): ManagedDatabase;
|
|
84
|
+
/** Close every connection this process holds (a test's teardown; a served twin's connections end with it). */
|
|
85
|
+
export declare function closeManagedDatabases(): Promise<void>;
|
|
86
|
+
export {};
|