@bjornpagen/bumbledb-log 0.20.3 → 1.0.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/README.md +275 -114
- package/dist/admin.d.ts +24 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +12 -0
- package/dist/admin.js.map +1 -0
- package/dist/bridge.d.ts +30 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +92 -0
- package/dist/bridge.js.map +1 -0
- package/dist/codes.d.ts +11 -0
- package/dist/codes.d.ts.map +1 -0
- package/dist/codes.js +53 -0
- package/dist/codes.js.map +1 -0
- package/dist/command.d.ts +21 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +12 -0
- package/dist/command.js.map +1 -0
- package/dist/errors.d.ts +78 -197
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +144 -114
- package/dist/errors.js.map +1 -1
- package/dist/history.d.ts +22 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +12 -0
- package/dist/history.js.map +1 -0
- package/dist/identity.d.ts +144 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +223 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +24 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -21
- package/dist/index.js.map +1 -1
- package/dist/machine.d.ts +151 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +1128 -0
- package/dist/machine.js.map +1 -0
- package/dist/migration-ops.d.ts +20 -0
- package/dist/migration-ops.d.ts.map +1 -0
- package/dist/migration-ops.js +7 -0
- package/dist/migration-ops.js.map +1 -0
- package/dist/migrations/bin.d.ts +3 -0
- package/dist/migrations/bin.d.ts.map +1 -0
- package/dist/migrations/bin.js +43 -0
- package/dist/migrations/bin.js.map +1 -0
- package/dist/migrations/canonical.d.ts +40 -0
- package/dist/migrations/canonical.d.ts.map +1 -0
- package/dist/migrations/canonical.js +156 -0
- package/dist/migrations/canonical.js.map +1 -0
- package/dist/migrations/cli.d.ts +32 -0
- package/dist/migrations/cli.d.ts.map +1 -0
- package/dist/migrations/cli.js +147 -0
- package/dist/migrations/cli.js.map +1 -0
- package/dist/migrations/codec.d.ts +74 -0
- package/dist/migrations/codec.d.ts.map +1 -0
- package/dist/migrations/codec.js +2 -0
- package/dist/migrations/codec.js.map +1 -0
- package/dist/migrations/decode.d.ts +16 -0
- package/dist/migrations/decode.d.ts.map +1 -0
- package/dist/migrations/decode.js +302 -0
- package/dist/migrations/decode.js.map +1 -0
- package/dist/migrations/diff.d.ts +39 -0
- package/dist/migrations/diff.d.ts.map +1 -0
- package/dist/migrations/diff.js +385 -0
- package/dist/migrations/diff.js.map +1 -0
- package/dist/migrations/expr.d.ts +22 -0
- package/dist/migrations/expr.d.ts.map +1 -0
- package/dist/migrations/expr.js +228 -0
- package/dist/migrations/expr.js.map +1 -0
- package/dist/migrations/fail.d.ts +34 -0
- package/dist/migrations/fail.d.ts.map +1 -0
- package/dist/migrations/fail.js +69 -0
- package/dist/migrations/fail.js.map +1 -0
- package/dist/migrations/fsops.d.ts +37 -0
- package/dist/migrations/fsops.d.ts.map +1 -0
- package/dist/migrations/fsops.js +222 -0
- package/dist/migrations/fsops.js.map +1 -0
- package/dist/migrations/generate.d.ts +11 -0
- package/dist/migrations/generate.d.ts.map +1 -0
- package/dist/migrations/generate.js +479 -0
- package/dist/migrations/generate.js.map +1 -0
- package/dist/migrations/index.d.ts +25 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +6 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/intent.d.ts +86 -0
- package/dist/migrations/intent.d.ts.map +1 -0
- package/dist/migrations/intent.js +97 -0
- package/dist/migrations/intent.js.map +1 -0
- package/dist/migrations/lock.d.ts +27 -0
- package/dist/migrations/lock.d.ts.map +1 -0
- package/dist/migrations/lock.js +14 -0
- package/dist/migrations/lock.js.map +1 -0
- package/dist/migrations/native.d.ts +37 -0
- package/dist/migrations/native.d.ts.map +1 -0
- package/dist/migrations/native.js +135 -0
- package/dist/migrations/native.js.map +1 -0
- package/dist/migrations/repo.d.ts +38 -0
- package/dist/migrations/repo.d.ts.map +1 -0
- package/dist/migrations/repo.js +191 -0
- package/dist/migrations/repo.js.map +1 -0
- package/dist/migrations/theory.d.ts +21 -0
- package/dist/migrations/theory.d.ts.map +1 -0
- package/dist/migrations/theory.js +107 -0
- package/dist/migrations/theory.js.map +1 -0
- package/dist/migrations/types.d.ts +243 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +2 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/migrations/workflow.d.ts +11 -0
- package/dist/migrations/workflow.d.ts.map +1 -0
- package/dist/migrations/workflow.js +14 -0
- package/dist/migrations/workflow.js.map +1 -0
- package/dist/native.d.ts +600 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +8 -0
- package/dist/native.js.map +1 -0
- package/dist/options.d.ts +106 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +2 -0
- package/dist/options.js.map +1 -0
- package/dist/outcome.d.ts +291 -0
- package/dist/outcome.d.ts.map +1 -0
- package/dist/outcome.js +2 -0
- package/dist/outcome.js.map +1 -0
- package/dist/production.d.ts +12 -0
- package/dist/production.d.ts.map +1 -0
- package/dist/production.js +29 -0
- package/dist/production.js.map +1 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +9 -0
- package/dist/schema.js.map +1 -0
- package/dist/surface.d.ts +80 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +2 -0
- package/dist/surface.js.map +1 -0
- package/dist/tenants.d.ts +20 -52
- package/dist/tenants.d.ts.map +1 -1
- package/dist/tenants.js +11 -330
- package/dist/tenants.js.map +1 -1
- package/pack-provenance.json +7 -0
- package/package.json +20 -23
- package/dist/braids.d.ts +0 -28
- package/dist/braids.d.ts.map +0 -1
- package/dist/braids.js +0 -45
- package/dist/braids.js.map +0 -1
- package/dist/bytes.d.ts +0 -26
- package/dist/bytes.d.ts.map +0 -1
- package/dist/bytes.js +0 -86
- package/dist/bytes.js.map +0 -1
- package/dist/chain.d.ts +0 -56
- package/dist/chain.d.ts.map +0 -1
- package/dist/chain.js +0 -137
- package/dist/chain.js.map +0 -1
- package/dist/codec.d.ts +0 -71
- package/dist/codec.d.ts.map +0 -1
- package/dist/codec.js +0 -179
- package/dist/codec.js.map +0 -1
- package/dist/descriptor.d.ts +0 -61
- package/dist/descriptor.d.ts.map +0 -1
- package/dist/descriptor.js +0 -160
- package/dist/descriptor.js.map +0 -1
- package/dist/keys.d.ts +0 -51
- package/dist/keys.d.ts.map +0 -1
- package/dist/keys.js +0 -119
- package/dist/keys.js.map +0 -1
- package/dist/manifest.d.ts +0 -42
- package/dist/manifest.d.ts.map +0 -1
- package/dist/manifest.js +0 -116
- package/dist/manifest.js.map +0 -1
- package/dist/replica.d.ts +0 -154
- package/dist/replica.d.ts.map +0 -1
- package/dist/replica.js +0 -820
- package/dist/replica.js.map +0 -1
- package/dist/store-s3.d.ts +0 -31
- package/dist/store-s3.d.ts.map +0 -1
- package/dist/store-s3.js +0 -299
- package/dist/store-s3.js.map +0 -1
- package/dist/store.d.ts +0 -129
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -577
- package/dist/store.js.map +0 -1
- package/dist/vector.d.ts +0 -31
- package/dist/vector.d.ts.map +0 -1
- package/dist/vector.js +0 -87
- package/dist/vector.js.map +0 -1
- package/dist/writer.d.ts +0 -106
- package/dist/writer.d.ts.map +0 -1
- package/dist/writer.js +0 -677
- package/dist/writer.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,127 +1,288 @@
|
|
|
1
1
|
# @bjornpagen/bumbledb-log
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
a thin peer of
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
BDBL v2 command codec — a batch is header + ops, nothing else) and
|
|
10
|
-
`braidsOf(descriptor)` (the schema's own shard map, as data — with
|
|
11
|
-
`serialAtStatementsOf` naming the degenerate-serial statements beside it).
|
|
12
|
-
2. **The five-verb object store** — `get`, `getIfChanged`, `putCreate`,
|
|
13
|
-
`putSwap`, `delete` — taking a branded `StoreKey` parsed once by
|
|
14
|
-
`storeKey`. `fsStore` is the tier-1 local-directory implementation;
|
|
15
|
-
`memStore` is the same five verbs over one in-process map
|
|
16
|
-
(single-process only; third `Etag` producer, blake3 like `fsStore`);
|
|
17
|
-
`s3Store` is the five verbs over S3-compatible storage (the official
|
|
18
|
-
`@aws-sdk/client-s3` client signs and talks; R2 rides region `auto`).
|
|
19
|
-
3. **Replica and writer** composed from the engine SDK's existing verbs:
|
|
20
|
-
`openReplica` hands out the SDK's own `Db`; `openWriter` adds the
|
|
21
|
-
right to create log objects; `openTenants` is an LRU of per-tenant
|
|
22
|
-
replicas. No engine surface is duplicated.
|
|
23
|
-
|
|
24
|
-
The package `engines` and the `.ts` test runner require Node >=24.
|
|
25
|
-
|
|
26
|
-
The exported vocabulary reads as English at the call site: `Value`,
|
|
27
|
-
`Interval`, `Batch`, `Theory`, `Descriptor`, `Op`, `Pending`,
|
|
28
|
-
`ChainEntry`, plus the branded scalars `StoreKey`, `Generation`,
|
|
29
|
-
`Etag`, and `Braid` (`storeKey`, `generation`, `etag`, `braid` parse
|
|
30
|
-
at the boundary; the verbs take the proof).
|
|
31
|
-
|
|
32
|
-
Async ⟺ network: `openReplica`, `refresh`, `waitFor`, `commit`,
|
|
33
|
-
`commitSplit`, and disposal await store verbs; everything on
|
|
34
|
-
`replica.db`, the `batch.*` recorders, and the pure pair are synchronous.
|
|
35
|
-
|
|
36
|
-
## A Fluid host
|
|
3
|
+
Durable named application commands over
|
|
4
|
+
[Bumbledb](https://github.com/bjornpagen/bumbledb): a thin peer of
|
|
5
|
+
`@bjornpagen/bumbledb` (exact peer `1.0.0`). The package adds a durable
|
|
6
|
+
envelope around the exact core change/read machinery — it never duplicates
|
|
7
|
+
the engine surface. Core types (`ChangeSet`, `QueryReader`,
|
|
8
|
+
`ExecutionPolicy`, `DbError`, …) are the peer's own exports.
|
|
37
9
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
10
|
+
The API is **Effect-native**: every operation constructs a lazy
|
|
11
|
+
[`Effect`](https://effect.website) and every native resource is scoped.
|
|
12
|
+
There is no Promise, synchronous, or disposal twin. The package requires
|
|
13
|
+
Effect `4.0.0-rc.112` exactly, as a peer dependency, and Node >= 24.
|
|
14
|
+
|
|
15
|
+
The surface is small:
|
|
41
16
|
|
|
42
|
-
|
|
43
|
-
|
|
17
|
+
1. **`LocalHistory` / `HostedHistory`** — one durable history per database.
|
|
18
|
+
Local authority is one LMDB directory; hosted authority is S3-compatible
|
|
19
|
+
object storage over immutable decisions, with a disposable local
|
|
20
|
+
materialization directory beside it. `open` of a missing or unreadable
|
|
21
|
+
configured database never creates a replacement; `create` is the explicit
|
|
22
|
+
constructor: it refuses existing authority and validates a stable
|
|
23
|
+
creation identity plus a **checked initialization artifact** (the
|
|
24
|
+
canonical schema snapshot the migration tooling renders) instead of
|
|
25
|
+
fabricating genesis.
|
|
26
|
+
2. **`Command`** — `Command.seal` turns `{ scope, id, changes, precondition,
|
|
27
|
+
result }` into one owned sealed command with a copyable pre-dispatch
|
|
28
|
+
`ref`; `Command.encode`/`Command.decode` are the one bounded versioned
|
|
29
|
+
command codec. The `changes` are the core's own `ChangeSet`.
|
|
30
|
+
3. **`PublishedSnapshot`** — the read side. It extends the core
|
|
31
|
+
`QueryReader` exactly (same `get`/`execute`/`session`, policies, errors
|
|
32
|
+
and result owners) and adds durable provenance: `identity`,
|
|
33
|
+
`decisionStamp`, `stateStamp`, `freshness`. `ReadOptions.consistency`
|
|
34
|
+
selects `cached`, `latest`, or `at-least` a known stamp.
|
|
35
|
+
4. **`TenantCache`** — one bounded native registry of histories for
|
|
36
|
+
multi-tenant hosts: `make`/`acquire` (a `HistoryBorrow` whose `release`
|
|
37
|
+
frees only the borrow)/`inspect`/`evict`/`close`. Pressure is byte and
|
|
38
|
+
count budgets; evicting a borrowed slot refuses instead of revoking.
|
|
39
|
+
5. **Maintenance and migrations** — explicit admin operations
|
|
40
|
+
(`checkpoint`, `pinRestorePoint`/`releaseRestorePoint`,
|
|
41
|
+
`rotateReceiptEpoch`, `retireReceipts`, `collectGarbage`, `backup`/
|
|
42
|
+
`verifyBackup`/`restore`, `erase`) and the generated-migration workflow
|
|
43
|
+
under the `./migrations` subpath (below).
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
pnpm add @bjornpagen/bumbledb-log@1.0.0 @bjornpagen/bumbledb@1.0.0 effect@4.0.0-rc.112
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`{ braid, generation }`; a session token is the pointwise max of every
|
|
56
|
-
pair a flow has seen; `replica.waitFor(vector)` refreshes until the
|
|
57
|
-
local vector dominates it. The committing instance always reads its
|
|
58
|
-
own writes without waiting. A singleton map is the single-braid form.
|
|
59
|
-
- **The `ErrContention` runbook**: the error carries its cause, sourced
|
|
60
|
-
from the terminal re-judgment itself — `{ kind: "hot-key", statement,
|
|
61
|
-
determinants }` names the statement and carries the offending facts'
|
|
62
|
-
raw values from the engine's own violation; the remedies are a
|
|
63
|
-
reservation relation on the hot capacity (an ordinary weighted child
|
|
64
|
-
row — the schema idiom) or resident mode. `{ kind: "slot-race", tip }`
|
|
65
|
-
means the terminal losses were accepted but out-raced: an operational
|
|
66
|
-
signal to shard the theory into more braids or move the hot braid to
|
|
67
|
-
a resident Rust writer, whose group commit batches the queue.
|
|
68
|
-
|
|
69
|
-
## A local fleet
|
|
51
|
+
## Quick start: one durable round trip
|
|
52
|
+
|
|
53
|
+
Create a local history with its checked initialization artifact, seal one
|
|
54
|
+
insert command, submit it to a decided receipt, then reopen the directory
|
|
55
|
+
and resolve the retained ref to the exact recorded outcome.
|
|
70
56
|
|
|
71
57
|
```ts
|
|
72
|
-
|
|
73
|
-
import {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
58
|
+
import * as fs from "node:fs/promises"
|
|
59
|
+
import { ChangeSet, key, NativeRuntime, relation, Schema, schema, str, u64 } from "@bjornpagen/bumbledb"
|
|
60
|
+
import type { ExecutionPolicy, NativeRuntimeOptions } from "@bjornpagen/bumbledb"
|
|
61
|
+
import { Command, DatabaseId, IncarnationId, LocalHistory, OperationId, ReceiptEpoch, RequestId } from "@bjornpagen/bumbledb-log"
|
|
62
|
+
import type { DatabaseIdentity, LocalBinding, ReadOptions, SubmitOptions } from "@bjornpagen/bumbledb-log"
|
|
63
|
+
import { Effect, ManagedRuntime, Result } from "effect"
|
|
64
|
+
|
|
65
|
+
const Entry = relation("Entry", { id: u64, body: str })
|
|
66
|
+
const Ledger = schema("Ledger", { Entry }, [key(Entry, ["id"])])
|
|
67
|
+
|
|
68
|
+
const runtimeOptions: NativeRuntimeOptions = {
|
|
69
|
+
workers: 2,
|
|
70
|
+
queueCapacity: 16,
|
|
71
|
+
cleanupCapacity: 16,
|
|
72
|
+
ownerCapacity: 16,
|
|
73
|
+
nativeHandleCapacity: 64,
|
|
74
|
+
inputBytes: 8_000_000n,
|
|
75
|
+
workingBytes: 8_000_000n,
|
|
76
|
+
scratchBytes: 8_000_000n,
|
|
77
|
+
resultBytes: 1_000_000n,
|
|
78
|
+
chunkBytes: 1_000_000n,
|
|
79
|
+
cleanupTimeout: "2 seconds"
|
|
80
|
+
}
|
|
81
|
+
const work: ExecutionPolicy = {
|
|
82
|
+
inputBytes: 1_000_000n,
|
|
83
|
+
workingBytes: 1_000_000n,
|
|
84
|
+
scratchBytes: 1_000_000n,
|
|
85
|
+
resultBytes: 100_000n,
|
|
86
|
+
rows: 100_000n,
|
|
87
|
+
workUnits: 10_000_000n,
|
|
88
|
+
timeout: "10 seconds"
|
|
89
|
+
}
|
|
90
|
+
const submitOptions: SubmitOptions = { ...work, attempts: 4, backoff: { baseMillis: 5, capMillis: 100 } }
|
|
91
|
+
const readOptions: ReadOptions = { ...work, consistency: { kind: "cached" } }
|
|
92
|
+
|
|
93
|
+
// Genuinely fallible small parsing is Result, not Effect.
|
|
94
|
+
const unwrap = <A, E>(result: Result.Result<A, E>): A => Result.getOrThrow(result)
|
|
95
|
+
|
|
96
|
+
const program = Effect.gen(function* () {
|
|
97
|
+
const compiled = yield* Schema.compile(Ledger, work)
|
|
98
|
+
// The checked initialization artifact: the canonical schema snapshot the
|
|
99
|
+
// migration generator wrote to your checked-in repository. Its native
|
|
100
|
+
// fingerprint IS the identity's schemaId — creation re-judges both.
|
|
101
|
+
const artifact: Uint8Array = yield* Effect.tryPromise(() =>
|
|
102
|
+
fs.readFile("bumbledb/migrations/meta/0000.schema.json")
|
|
103
|
+
)
|
|
104
|
+
const identity: DatabaseIdentity = {
|
|
105
|
+
databaseId: unwrap(DatabaseId.parse("abababab-abab-abab-abab-abababababab")),
|
|
106
|
+
incarnationId: unwrap(IncarnationId.parse("cdcdcdcd-cdcd-cdcd-cdcd-cdcdcdcdcdcd")),
|
|
107
|
+
schemaId: compiled.schemaId
|
|
108
|
+
}
|
|
109
|
+
const binding: LocalBinding = { kind: "local", directory: "/tmp/ledger", identity }
|
|
110
|
+
|
|
111
|
+
// Scope 1: create, seal, submit; retain the ref and receipt.
|
|
112
|
+
const retained = yield* Effect.scoped(
|
|
113
|
+
Effect.gen(function* () {
|
|
114
|
+
const history = yield* LocalHistory.create(binding, Ledger, {
|
|
115
|
+
...work,
|
|
116
|
+
creation: {
|
|
117
|
+
operationId: unwrap(OperationId.parse("e1e1e1e1-e1e1-e1e1-e1e1-e1e1e1e1e1e1")),
|
|
118
|
+
artifact
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
const draft = yield* ChangeSet.builder(Ledger, work)
|
|
122
|
+
yield* draft.insert(Entry, [{ id: 42n, body: "hello" }])
|
|
123
|
+
const changes = yield* draft.finish()
|
|
124
|
+
const command = yield* Command.seal(
|
|
125
|
+
{
|
|
126
|
+
scope: history.identity,
|
|
127
|
+
// Generate ids ONCE for an original intent and persist them;
|
|
128
|
+
// a retry resubmits the identical sealed command.
|
|
129
|
+
id: {
|
|
130
|
+
receiptEpoch: unwrap(ReceiptEpoch.from(1n)),
|
|
131
|
+
requestId: unwrap(RequestId.parse("0b0b0b0b-0b0b-0b0b-0b0b-0b0b0b0b0b0b"))
|
|
132
|
+
},
|
|
133
|
+
changes,
|
|
134
|
+
precondition: { kind: "blind" },
|
|
135
|
+
result: {}
|
|
136
|
+
},
|
|
137
|
+
work
|
|
138
|
+
)
|
|
139
|
+
// Submission certainty is data; interruption remains interruption.
|
|
140
|
+
const outcome = yield* history.submit(command, submitOptions)
|
|
141
|
+
if (outcome.kind !== "decided") {
|
|
142
|
+
return yield* Effect.die("expected a decided submit in this example")
|
|
143
|
+
}
|
|
144
|
+
return { ref: command.ref, receipt: outcome.receipt }
|
|
145
|
+
})
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
// Scope 2: reopen; the retained ref resolves to the recorded receipt,
|
|
149
|
+
// and the committed fact reads back through the core QueryReader.
|
|
150
|
+
yield* Effect.scoped(
|
|
151
|
+
Effect.gen(function* () {
|
|
152
|
+
const history = yield* LocalHistory.open(binding, Ledger, work)
|
|
153
|
+
const resolved = yield* history.resolve(retained.ref, work)
|
|
154
|
+
if (resolved.kind === "found" && resolved.receipt.outcome.kind === "committed") {
|
|
155
|
+
const snapshot = yield* history.snapshot(readOptions)
|
|
156
|
+
const fact = yield* snapshot.get(Entry, { id: 42n }, work)
|
|
157
|
+
yield* Effect.log(fact._tag === "Some" ? fact.value.body : "missing")
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
)
|
|
80
161
|
})
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
162
|
+
|
|
163
|
+
const runtime = ManagedRuntime.make(NativeRuntime.layer(runtimeOptions))
|
|
164
|
+
await runtime.runPromise(program)
|
|
165
|
+
await Effect.runPromise(runtime.disposeEffect)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Certainty, receipts, and errors
|
|
169
|
+
|
|
170
|
+
`submit` returns `Effect<SubmitOutcome>` with `E = never` — the outcome is a
|
|
171
|
+
three-armed certainty sum, never an exception channel:
|
|
172
|
+
|
|
173
|
+
- `decided` — the authority recorded a decision; the arm carries the
|
|
174
|
+
`TerminalReceipt` (`committed`, `no-change`, `precondition-failed`, or
|
|
175
|
+
`invariant-rejected` with canonical violation evidence).
|
|
176
|
+
- `not-submitted` — proven never registered (a typed cause rides along);
|
|
177
|
+
safe to fix and submit a NEW command.
|
|
178
|
+
- `outcome-unknown` — dispatch crossed the authority boundary but the
|
|
179
|
+
decision could not be read back. Never retried blindly: `resolve(ref)`
|
|
180
|
+
later returns `found`, `not-recorded-at`, `command-epoch-closed`, or
|
|
181
|
+
`receipt-expired-unknown`. Absence at one decision is not proof that an
|
|
182
|
+
in-flight command will never publish.
|
|
183
|
+
|
|
184
|
+
Fiber interruption remains interruption in Effect's `Cause`; it joins native
|
|
185
|
+
cleanup, not an invented successful outcome. Retain the command ref or admin
|
|
186
|
+
operation identity before dispatch and resolve it after cancellation. A failed
|
|
187
|
+
cleanup adds a `CloseFailure` defect without erasing the interruption.
|
|
188
|
+
|
|
189
|
+
Receipts and refs are plain owned data: they outlive their scope, survive
|
|
190
|
+
process restarts (render/parse with `renderCommandRef`/`parseCommandRef`),
|
|
191
|
+
and `resolve` after reopen returns the exact recorded outcome.
|
|
192
|
+
|
|
193
|
+
Failures that ARE errors use exactly two classes, checked by `_tag`, never
|
|
194
|
+
message strings: the core's own `DbError`, unchanged, for core failures
|
|
195
|
+
crossing the log; and `ProtocolError` for the log-specific reason roster
|
|
196
|
+
(`protocolErrorCodes` spells it natively — contention, consistency
|
|
197
|
+
not-yet-available, artifact/authority/identity refusals, maintenance
|
|
198
|
+
backpressure, migration reasons). `LogError = DbError | ProtocolError` and
|
|
199
|
+
nothing else. Interruption and finalizer defects stay in `Cause`.
|
|
200
|
+
|
|
201
|
+
The same core `QueryReader` helper that lists a local `Db` snapshot lists a
|
|
202
|
+
published history snapshot. There is no log-specific query wrapper. The
|
|
203
|
+
packed consumer spells this as `readAttempts(snapshot, student, work)` on
|
|
204
|
+
both `Db.snapshot` and `history.snapshot`.
|
|
205
|
+
|
|
206
|
+
Retain the command or admin `operationId` **before** `submit` / `initialize` /
|
|
207
|
+
`backup` / `restore`. `outcome-unknown` is resolved under that identity.
|
|
208
|
+
A later missing receipt is not proved loss.
|
|
209
|
+
|
|
210
|
+
## Backup and restore
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { NativeRuntime } from "@bjornpagen/bumbledb"
|
|
214
|
+
import type { ExecutionPolicy, NativeRuntimeOptions } from "@bjornpagen/bumbledb"
|
|
215
|
+
import {
|
|
216
|
+
backup,
|
|
217
|
+
OperationId,
|
|
218
|
+
restore,
|
|
219
|
+
verifyBackup,
|
|
220
|
+
type LocalBinding
|
|
221
|
+
} from "@bjornpagen/bumbledb-log"
|
|
222
|
+
import { Effect, Result } from "effect"
|
|
223
|
+
|
|
224
|
+
declare const runtimeOptions: NativeRuntimeOptions
|
|
225
|
+
declare const work: ExecutionPolicy
|
|
226
|
+
declare const binding: LocalBinding
|
|
227
|
+
|
|
228
|
+
const unwrap = <A, E>(result: Result.Result<A, E>): A => Result.getOrThrow(result)
|
|
229
|
+
|
|
230
|
+
const cycle = Effect.gen(function* () {
|
|
231
|
+
const operationId = unwrap(OperationId.parse("a1a1a1a1-a1a1-a1a1-a1a1-a1a1a1a1a1a1"))
|
|
232
|
+
const destination = { kind: "filesystem" as const, directory: "/tmp/ledger-backup" }
|
|
233
|
+
const backed = yield* backup(binding, { ...work, operationId, destination })
|
|
234
|
+
if (backed.kind !== "completed") {
|
|
235
|
+
return backed
|
|
236
|
+
}
|
|
237
|
+
yield* verifyBackup(destination, work)
|
|
238
|
+
return yield* restore(destination, binding, { ...work, operationId })
|
|
89
239
|
})
|
|
90
|
-
|
|
91
|
-
|
|
240
|
+
void NativeRuntime.layer(runtimeOptions)
|
|
241
|
+
void cycle
|
|
92
242
|
```
|
|
93
243
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
is
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
is
|
|
126
|
-
|
|
127
|
-
|
|
244
|
+
## Migrations
|
|
245
|
+
|
|
246
|
+
Schema evolution is generated, checked-in, inert data — never inferred at
|
|
247
|
+
runtime:
|
|
248
|
+
|
|
249
|
+
- `@bjornpagen/bumbledb-log/schema` — pure intent constructors
|
|
250
|
+
(`migrationIntent`, `renameField`, `renameRelation`, `convert`,
|
|
251
|
+
`backfill`, `seed`, `dropField`, `dropRelation`). No native work at
|
|
252
|
+
import or call.
|
|
253
|
+
- `@bjornpagen/bumbledb-log/migrations` — `generateMigrations` diffs the
|
|
254
|
+
declared schema against the recorded chain and appends one validated,
|
|
255
|
+
canonically rendered plan to the repository (`manifest.json`,
|
|
256
|
+
`NNNN-<label>.plan.json`, `meta/NNNN.schema.json`, `snapshots.json`,
|
|
257
|
+
`index.ts` exporting `{ manifest, plans, snapshots }`, and the
|
|
258
|
+
`runtime-contract.json` your deploy pins). The admin runner decodes that
|
|
259
|
+
triple — snapshots are the empty-base schema plus one target per entry.
|
|
260
|
+
`checkMigrations` is the same judgment without writes. Ordinary onboarding
|
|
261
|
+
is generated `initialize`,
|
|
262
|
+
then `LocalHistory.open`. `HostedHistory.open` requires an already
|
|
263
|
+
initialized hosted authority. `LocalHistory.create`
|
|
264
|
+
remains the explicit constructor when a checked artifact is already in
|
|
265
|
+
hand — it is not the Notes/Alchemy path. The runner verbs —
|
|
266
|
+
`migrationStatus`, `initialize`, `migrate`, `activateMigration`,
|
|
267
|
+
`abortMigration` — execute generated plans through the one native
|
|
268
|
+
executor, with `AdminOutcome` certainty (`completed` / `not-started` /
|
|
269
|
+
`outcome-unknown`).
|
|
270
|
+
|
|
271
|
+
**Current limitation:** these generated migration runner verbs target local
|
|
272
|
+
authorities only. The TypeScript/native bridge refuses hosted migration
|
|
273
|
+
execution; a hosted tenant's cache is not an authoritative local migration
|
|
274
|
+
target. Hosted migration orchestration is not supported in 1.0; the
|
|
275
|
+
production-ready scope is local history. Real-S3 and Graviton qualification
|
|
276
|
+
remain deferred, not passed.
|
|
277
|
+
- Field arithmetic such as `Scalar.add(Scalar.field("units"), Scalar.u64(1n))`
|
|
278
|
+
is valid intent metadata. Native chain compilation binds it before any
|
|
279
|
+
new manifest write or source freeze, including zero input rows.
|
|
280
|
+
- The `bumbledb-log` bin is the same generator/checker as a CLI.
|
|
281
|
+
|
|
282
|
+
## Platform and packaging
|
|
283
|
+
|
|
284
|
+
The native engine arrives through the peer `@bjornpagen/bumbledb`
|
|
285
|
+
(darwin-arm64, linux-arm64, linux-x64); this package ships TypeScript only
|
|
286
|
+
and declares both peers exactly (`@bjornpagen/bumbledb 1.0.0`, `effect
|
|
287
|
+
4.0.0-rc.112`). Version lockstep across the package family is enforced in
|
|
288
|
+
CI.
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintenance operations as Effects with the chapter 35 admin certainty:
|
|
3
|
+
* mutating operations return `AdminOutcome<Value>` in A with E = never
|
|
4
|
+
* (completed / not-started / outcome-unknown around a small immutable
|
|
5
|
+
* operation reference derived BEFORE dispatch); read-only verification has
|
|
6
|
+
* typed E. These are language wrappers over each operation's existing
|
|
7
|
+
* protocol report and identity (database/epoch/root/barrier/operation) —
|
|
8
|
+
* no generic admin journal, manufactured maintenance receipts, or shared
|
|
9
|
+
* durable state machine is added. Interruption stays in Cause; the retained
|
|
10
|
+
* operation reference resolves it through `migrationStatus`/`inspect`.
|
|
11
|
+
*/
|
|
12
|
+
import type { AdminOperations } from "./machine.js";
|
|
13
|
+
export declare const checkpoint: AdminOperations["checkpoint"];
|
|
14
|
+
export declare const pinRestorePoint: AdminOperations["pinRestorePoint"];
|
|
15
|
+
export declare const releaseRestorePoint: AdminOperations["releaseRestorePoint"];
|
|
16
|
+
export declare const rotateReceiptEpoch: AdminOperations["rotateReceiptEpoch"];
|
|
17
|
+
export declare const retireReceipts: AdminOperations["retireReceipts"];
|
|
18
|
+
export declare const collectGarbage: AdminOperations["collectGarbage"];
|
|
19
|
+
export declare const backup: AdminOperations["backup"];
|
|
20
|
+
export declare const verifyBackup: AdminOperations["verifyBackup"];
|
|
21
|
+
export declare const restore: AdminOperations["restore"];
|
|
22
|
+
export declare const erase: AdminOperations["erase"];
|
|
23
|
+
export type { AdminIdentityOptions, AdminOperations, BackupDestination, TenantOpenOptions } from "./machine.js";
|
|
24
|
+
//# sourceMappingURL=admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAGlD,eAAO,MAAM,UAAU,EAAE,eAAe,CAAC,YAAY,CAAwB,CAAA;AAC7E,eAAO,MAAM,eAAe,EAAE,eAAe,CAAC,iBAAiB,CAA6B,CAAA;AAC5F,eAAO,MAAM,mBAAmB,EAAE,eAAe,CAAC,qBAAqB,CAAiC,CAAA;AACxG,eAAO,MAAM,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAgC,CAAA;AACrG,eAAO,MAAM,cAAc,EAAE,eAAe,CAAC,gBAAgB,CAA4B,CAAA;AACzF,eAAO,MAAM,cAAc,EAAE,eAAe,CAAC,gBAAgB,CAA4B,CAAA;AACzF,eAAO,MAAM,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAoB,CAAA;AACjE,eAAO,MAAM,YAAY,EAAE,eAAe,CAAC,cAAc,CAA0B,CAAA;AACnF,eAAO,MAAM,OAAO,EAAE,eAAe,CAAC,SAAS,CAAqB,CAAA;AACpE,eAAO,MAAM,KAAK,EAAE,eAAe,CAAC,OAAO,CAAmB,CAAA;AAE9D,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/admin.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { log } from "#production.ts";
|
|
2
|
+
export const checkpoint = log.admin.checkpoint;
|
|
3
|
+
export const pinRestorePoint = log.admin.pinRestorePoint;
|
|
4
|
+
export const releaseRestorePoint = log.admin.releaseRestorePoint;
|
|
5
|
+
export const rotateReceiptEpoch = log.admin.rotateReceiptEpoch;
|
|
6
|
+
export const retireReceipts = log.admin.retireReceipts;
|
|
7
|
+
export const collectGarbage = log.admin.collectGarbage;
|
|
8
|
+
export const backup = log.admin.backup;
|
|
9
|
+
export const verifyBackup = log.admin.verifyBackup;
|
|
10
|
+
export const restore = log.admin.restore;
|
|
11
|
+
export const erase = log.admin.erase;
|
|
12
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAEpC,MAAM,CAAC,MAAM,UAAU,GAAkC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAA;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAuC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAA;AAC5F,MAAM,CAAC,MAAM,mBAAmB,GAA2C,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAA;AACxG,MAAM,CAAC,MAAM,kBAAkB,GAA0C,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAA;AACrG,MAAM,CAAC,MAAM,cAAc,GAAsC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAA;AACzF,MAAM,CAAC,MAAM,cAAc,GAAsC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAA;AACzF,MAAM,CAAC,MAAM,MAAM,GAA8B,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA;AACjE,MAAM,CAAC,MAAM,YAAY,GAAoC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAA;AACnF,MAAM,CAAC,MAAM,OAAO,GAA+B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAA;AACpE,MAAM,CAAC,MAAM,KAAK,GAA6B,GAAG,CAAC,KAAK,CAAC,KAAK,CAAA"}
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { CloseReport, CloseWire, OperationHandle } from "@bjornpagen/bumbledb/internal/log";
|
|
2
|
+
import { Effect, type Scope } from "effect";
|
|
3
|
+
import type { LogError } from "./errors.js";
|
|
4
|
+
export type CancelVerb = (operation: OperationHandle, callback: (report: CloseWire) => void) => void;
|
|
5
|
+
export declare function closeReportOf(operation: string, report: CloseWire): CloseReport;
|
|
6
|
+
/**
|
|
7
|
+
* Run one native close/release transition to completion. Uninterruptible:
|
|
8
|
+
* teardown uses the runtime's reserved cleanup envelope, and abandoning the
|
|
9
|
+
* callback would fake quiescence.
|
|
10
|
+
*/
|
|
11
|
+
export declare function drainClose(operation: string, start: (callback: (report: CloseWire) => void) => void): Effect.Effect<CloseReport>;
|
|
12
|
+
/**
|
|
13
|
+
* One bounded log operation with typed E. Registration failures and
|
|
14
|
+
* completion decode failures both fail with the typed union; interruption
|
|
15
|
+
* cancels and joins the native lease, including a late successful result.
|
|
16
|
+
*/
|
|
17
|
+
export declare function logOperation<Value, A>(operation: string, cancel: CancelVerb, start: (callback: () => void) => OperationHandle, take: (operation: OperationHandle) => Value, accept: (value: Value) => A): Effect.Effect<A, LogError>;
|
|
18
|
+
/**
|
|
19
|
+
* Transport completion/refusal is data in the certainty union. Fiber
|
|
20
|
+
* interruption stays in Cause: it joins native cancellation, but cannot prove
|
|
21
|
+
* nonpublication. Resolve the command/operation ref retained before dispatch.
|
|
22
|
+
*/
|
|
23
|
+
export declare function certaintyOperation<Value, A>(operation: string, cancel: CancelVerb, start: (callback: () => void) => OperationHandle, take: (operation: OperationHandle) => Value, accept: (value: Value) => A, beforeDispatch: (error: LogError) => A, afterDispatch: (error: LogError) => A): Effect.Effect<A>;
|
|
24
|
+
/**
|
|
25
|
+
* Scoped ownership of a native resource: interruptible acquisition through
|
|
26
|
+
* the cancellation-safe bridge above, and a finalizer that runs the stored
|
|
27
|
+
* native close and dies with `CloseFailure` on incomplete/failed drain.
|
|
28
|
+
*/
|
|
29
|
+
export declare function scopedResource<A, E>(operation: string, acquire: Effect.Effect<A, E>, close: (resource: A) => Effect.Effect<CloseReport>): Effect.Effect<A, E, Scope.Scope>;
|
|
30
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AAEhG,OAAO,EAAE,MAAM,EAAQ,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAG1C,MAAM,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,KAAK,IAAI,CAAA;AAEpG,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,WAAW,CAK/E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACzB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,KAAK,IAAI,GACpD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAQ5B;AAOD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,CAAC,EACpC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,eAAe,EAChD,IAAI,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,KAAK,EAC3C,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,GACzB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAE5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,CAAC,EAC1C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,eAAe,EAChD,IAAI,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,KAAK,EAC3C,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,EAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,CAAC,EACtC,aAAa,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,CAAC,GACnC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAUlB;AA6CD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAClC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5B,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,GAChD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAMlC"}
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect-side adaptation of the C09 executor pattern for log operations.
|
|
3
|
+
* Registration returns the native lease before any completion runs in JS;
|
|
4
|
+
* interruption signals native cancellation and JOINS the drain (an
|
|
5
|
+
* incomplete or failed drain surfaces as a structured `CloseFailure` defect
|
|
6
|
+
* in the finalizer `Cause`, never false quiescence). No Promise or libuv
|
|
7
|
+
* job is created; there is no JS critical section, timer, or queue here.
|
|
8
|
+
*/
|
|
9
|
+
import { DbError } from "@bjornpagen/bumbledb";
|
|
10
|
+
import { finalizeClose } from "@bjornpagen/bumbledb/internal/log";
|
|
11
|
+
import { Effect, Exit } from "effect";
|
|
12
|
+
import { logFailure } from "#errors.ts";
|
|
13
|
+
export function closeReportOf(operation, report) {
|
|
14
|
+
if (report.kind === "failed") {
|
|
15
|
+
return { kind: "failed", error: new DbError({ operation, reason: { _tag: "Internal" } }) };
|
|
16
|
+
}
|
|
17
|
+
return report;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run one native close/release transition to completion. Uninterruptible:
|
|
21
|
+
* teardown uses the runtime's reserved cleanup envelope, and abandoning the
|
|
22
|
+
* callback would fake quiescence.
|
|
23
|
+
*/
|
|
24
|
+
export function drainClose(operation, start) {
|
|
25
|
+
return Effect.callback((resume) => {
|
|
26
|
+
try {
|
|
27
|
+
start((report) => resume(Effect.succeed(closeReportOf(operation, report))));
|
|
28
|
+
}
|
|
29
|
+
catch (cause) {
|
|
30
|
+
resume(Effect.succeed({ kind: "failed", error: toDbError(operation, cause) }));
|
|
31
|
+
}
|
|
32
|
+
}).pipe(Effect.uninterruptible);
|
|
33
|
+
}
|
|
34
|
+
function toDbError(operation, cause) {
|
|
35
|
+
const typed = logFailure(operation, cause);
|
|
36
|
+
return typed instanceof DbError ? typed : new DbError({ operation, reason: { _tag: "Internal" } });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* One bounded log operation with typed E. Registration failures and
|
|
40
|
+
* completion decode failures both fail with the typed union; interruption
|
|
41
|
+
* cancels and joins the native lease, including a late successful result.
|
|
42
|
+
*/
|
|
43
|
+
export function logOperation(operation, cancel, start, take, accept) {
|
|
44
|
+
return nativeOperation(operation, cancel, start, take, accept, Effect.fail, Effect.fail);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Transport completion/refusal is data in the certainty union. Fiber
|
|
48
|
+
* interruption stays in Cause: it joins native cancellation, but cannot prove
|
|
49
|
+
* nonpublication. Resolve the command/operation ref retained before dispatch.
|
|
50
|
+
*/
|
|
51
|
+
export function certaintyOperation(operation, cancel, start, take, accept, beforeDispatch, afterDispatch) {
|
|
52
|
+
return nativeOperation(operation, cancel, start, take, accept, (error) => Effect.succeed(beforeDispatch(error)), (error) => Effect.succeed(afterDispatch(error)));
|
|
53
|
+
}
|
|
54
|
+
/** The one lease lifecycle shared by typed-error and certainty operations. */
|
|
55
|
+
function nativeOperation(operation, cancel, start, take, accept, beforeDispatch, afterDispatch) {
|
|
56
|
+
return Effect.suspend(() => {
|
|
57
|
+
let report;
|
|
58
|
+
return Effect.callback((resume, signal) => {
|
|
59
|
+
let lease;
|
|
60
|
+
try {
|
|
61
|
+
lease = start(() => {
|
|
62
|
+
if (signal.aborted)
|
|
63
|
+
return;
|
|
64
|
+
try {
|
|
65
|
+
resume(Effect.succeed(accept(take(lease))));
|
|
66
|
+
}
|
|
67
|
+
catch (cause) {
|
|
68
|
+
resume(afterDispatch(logFailure(operation, cause)));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (cause) {
|
|
73
|
+
resume(beforeDispatch(logFailure(operation, cause)));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Callback finalizers must succeed so Effect retains the interrupt.
|
|
77
|
+
return drainClose(`${operation}.cancel`, (callback) => cancel(lease, callback)).pipe(Effect.tap((closed) => {
|
|
78
|
+
report = closed;
|
|
79
|
+
return Effect.void;
|
|
80
|
+
}), Effect.asVoid);
|
|
81
|
+
}).pipe(Effect.onExit((exit) => Exit.hasInterrupts(exit) && report !== undefined ? finalizeClose(`${operation}.cancel`, report) : Effect.void));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Scoped ownership of a native resource: interruptible acquisition through
|
|
86
|
+
* the cancellation-safe bridge above, and a finalizer that runs the stored
|
|
87
|
+
* native close and dies with `CloseFailure` on incomplete/failed drain.
|
|
88
|
+
*/
|
|
89
|
+
export function scopedResource(operation, acquire, close) {
|
|
90
|
+
return Effect.acquireRelease(acquire, (resource) => close(resource).pipe(Effect.flatMap((report) => finalizeClose(operation, report))), { interruptible: true });
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/codes.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The log-specific error-code roster. This list must stay pinned to the
|
|
3
|
+
* native `logErrorCodes()` export (one speller, the internal Rust machine);
|
|
4
|
+
* an authored roster test compares them exactly. Core failures are never
|
|
5
|
+
* respelled here: a core failure crossing the log surface remains the exact
|
|
6
|
+
* core `DbError` with its own roster. These codes are only the protocol's
|
|
7
|
+
* additions.
|
|
8
|
+
*/
|
|
9
|
+
export declare const protocolErrorCodes: readonly ["ForeignIdentity", "CommandIdentityConflict", "DatabaseDeleted", "DatabaseFrozen", "CommandEpochClosed", "ReceiptExpiredUnknown", "NotInitialized", "DatabaseMissing", "AuthorityExists", "CacheIdentityMismatch", "WrongLineage", "NotYetAvailable", "WitnessUnavailable", "SnapshotExpired", "MaintenanceRequired", "MaterializationStale", "RootCapacityExceeded", "SlotBorrowed", "Contention", "IncompleteRejectionEvidence", "MigrationRequired", "MigrationDrift", "MigrationIntentRequired", "MigrationUnsupported", "MigrationRepository", "DatabaseAhead", "MigrationOutputMismatch", "OperationConflict", "InsufficientLocalDisk", "UnsupportedArtifact", "Corruption", "Backend", "Misuse"];
|
|
10
|
+
export type ProtocolCode = (typeof protocolErrorCodes)[number];
|
|
11
|
+
//# sourceMappingURL=codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,YAE9B,iBAAiB,EACjB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EAEvB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EAEjB,qBAAqB,EAKrB,sBAAsB,EACtB,sBAAsB,EACtB,cAAc,EACd,YAAY,EACZ,6BAA6B,EAE7B,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EACf,yBAAyB,EACzB,mBAAmB,EAEnB,uBAAuB,EACvB,qBAAqB,EACrB,YAAY,EACZ,SAAS,EACT,QAAQ,CACC,CAAA;AAEV,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAA"}
|