@thomasfosterau/pulpit 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1272 -2
- package/dist/blobs.d.ts +249 -0
- package/dist/blobs.d.ts.map +1 -0
- package/dist/blobs.js +193 -0
- package/dist/blobs.js.map +1 -0
- package/dist/budgets.d.ts +255 -0
- package/dist/budgets.d.ts.map +1 -0
- package/dist/budgets.js +211 -0
- package/dist/budgets.js.map +1 -0
- package/dist/cache.d.ts +154 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +118 -0
- package/dist/cache.js.map +1 -0
- package/dist/collections.d.ts +242 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +215 -0
- package/dist/collections.js.map +1 -0
- package/dist/comments.d.ts +212 -0
- package/dist/comments.d.ts.map +1 -0
- package/dist/comments.js +192 -0
- package/dist/comments.js.map +1 -0
- package/dist/content.d.ts +231 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +204 -0
- package/dist/content.js.map +1 -0
- package/dist/documents.d.ts +184 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +190 -0
- package/dist/documents.js.map +1 -0
- package/dist/edges.d.ts +645 -0
- package/dist/edges.d.ts.map +1 -0
- package/dist/edges.js +558 -0
- package/dist/edges.js.map +1 -0
- package/dist/filter.d.ts +461 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +387 -0
- package/dist/filter.js.map +1 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/filter-columns.d.ts +8 -0
- package/dist/internal/filter-columns.d.ts.map +1 -0
- package/dist/internal/filter-columns.js +43 -0
- package/dist/internal/filter-columns.js.map +1 -0
- package/dist/internal/list-order.d.ts +26 -0
- package/dist/internal/list-order.d.ts.map +1 -0
- package/dist/internal/list-order.js +92 -0
- package/dist/internal/list-order.js.map +1 -0
- package/dist/internal/owned-columns.d.ts +93 -0
- package/dist/internal/owned-columns.d.ts.map +1 -0
- package/dist/internal/owned-columns.js +98 -0
- package/dist/internal/owned-columns.js.map +1 -0
- package/dist/internal/plain-rows.d.ts +32 -0
- package/dist/internal/plain-rows.d.ts.map +1 -0
- package/dist/internal/plain-rows.js +32 -0
- package/dist/internal/plain-rows.js.map +1 -0
- package/dist/internal/reference-columns.d.ts +80 -0
- package/dist/internal/reference-columns.d.ts.map +1 -0
- package/dist/internal/reference-columns.js +102 -0
- package/dist/internal/reference-columns.js.map +1 -0
- package/dist/moderation.d.ts +392 -0
- package/dist/moderation.d.ts.map +1 -0
- package/dist/moderation.js +375 -0
- package/dist/moderation.js.map +1 -0
- package/dist/paths.d.ts +204 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +165 -0
- package/dist/paths.js.map +1 -0
- package/dist/proposals.d.ts +523 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/proposals.js +505 -0
- package/dist/proposals.js.map +1 -0
- package/dist/publication.d.ts +148 -0
- package/dist/publication.d.ts.map +1 -0
- package/dist/publication.js +183 -0
- package/dist/publication.js.map +1 -0
- package/dist/purge.d.ts +224 -0
- package/dist/purge.d.ts.map +1 -0
- package/dist/purge.js +151 -0
- package/dist/purge.js.map +1 -0
- package/dist/reactions.d.ts +246 -0
- package/dist/reactions.d.ts.map +1 -0
- package/dist/reactions.js +183 -0
- package/dist/reactions.js.map +1 -0
- package/dist/registry.d.ts +316 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +305 -0
- package/dist/registry.js.map +1 -0
- package/dist/search.d.ts +366 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +273 -0
- package/dist/search.js.map +1 -0
- package/dist/social.d.ts +311 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +205 -0
- package/dist/social.js.map +1 -0
- package/dist/subtype.d.ts +1613 -0
- package/dist/subtype.d.ts.map +1 -0
- package/dist/subtype.js +1300 -0
- package/dist/subtype.js.map +1 -0
- package/dist/testing.d.ts +675 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +1022 -0
- package/dist/testing.js.map +1 -0
- package/dist/version-chain.d.ts +702 -0
- package/dist/version-chain.d.ts.map +1 -0
- package/dist/version-chain.js +489 -0
- package/dist/version-chain.js.map +1 -0
- package/dist/working-copy.d.ts +116 -0
- package/dist/working-copy.d.ts.map +1 -0
- package/dist/working-copy.js +95 -0
- package/dist/working-copy.js.map +1 -0
- package/package.json +145 -3
- package/src/blobs.ts +384 -0
- package/src/budgets.ts +338 -0
- package/src/cache.ts +218 -0
- package/src/collections.ts +427 -0
- package/src/comments.ts +392 -0
- package/src/content.ts +238 -0
- package/src/documents.ts +284 -0
- package/src/edges.ts +1185 -0
- package/src/filter.ts +523 -0
- package/src/index.ts +153 -0
- package/src/internal/filter-columns.ts +50 -0
- package/src/internal/list-order.ts +117 -0
- package/src/internal/owned-columns.ts +140 -0
- package/src/internal/plain-rows.ts +54 -0
- package/src/internal/reference-columns.ts +156 -0
- package/src/moderation.ts +728 -0
- package/src/paths.ts +267 -0
- package/src/proposals.ts +1014 -0
- package/src/publication.ts +225 -0
- package/src/purge.ts +313 -0
- package/src/reactions.ts +347 -0
- package/src/registry.ts +524 -0
- package/src/search.ts +540 -0
- package/src/social.ts +469 -0
- package/src/subtype.ts +3095 -0
- package/src/testing.ts +1873 -0
- package/src/version-chain.ts +1093 -0
- package/src/working-copy.ts +192 -0
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **In-memory fakes of the kernel's seams** — a store for each of the
|
|
3
|
+
* version-chain, leaf, document, edge, proposal, path, report, publication, purge and embedding seams, an
|
|
4
|
+
* endpoint view, a follower seam, a search branch (with a scope check) and a resource cache, all held in memory with no SQL. They are the reference semantics of
|
|
5
|
+
* each seam's contract in the package README → Seams, and the fakes the
|
|
6
|
+
* kernel's own suites run against; an adapter's or an application's tests can
|
|
7
|
+
* run the kernel's operations over them too.
|
|
8
|
+
*
|
|
9
|
+
* **Not for production.** Every store here keeps its rows in a closure for the
|
|
10
|
+
* life of the value, persists nothing, never opens a transaction and has no
|
|
11
|
+
* concurrency control beyond what a single JavaScript thread gives it. Each
|
|
12
|
+
* store enforces what the real table's schema enforces (a primary or unique
|
|
13
|
+
* key) and nothing the operations are responsible for, so a test of the
|
|
14
|
+
* operations over a fake exercises the operations' policy, not the store's.
|
|
15
|
+
* Each also carries a few test hooks (`rows`, `dropState`, `raceNextAppend`,
|
|
16
|
+
* …) that a real store has no counterpart for: they read what was written,
|
|
17
|
+
* or simulate a state a real database reaches only through a race or a
|
|
18
|
+
* missing row.
|
|
19
|
+
*
|
|
20
|
+
* The follower seam's `in` set is a `HashSet` of account ids
|
|
21
|
+
* ({@link InMemoryFollowing}) throughout, where a SQL store's is a subquery.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { deepStrictEqual } from "node:assert";
|
|
26
|
+
* import * as Effect from "effect/Effect";
|
|
27
|
+
* import * as Option from "effect/Option";
|
|
28
|
+
* import { defineVersionChain } from "@thomasfosterau/pulpit/version-chain";
|
|
29
|
+
* import { makeInMemoryChainStore } from "@thomasfosterau/pulpit/testing";
|
|
30
|
+
*
|
|
31
|
+
* const store = makeInMemoryChainStore();
|
|
32
|
+
* const chain = defineVersionChain("notes", store);
|
|
33
|
+
* const { id } = Effect.runSync(
|
|
34
|
+
* chain.create({ id: Option.none(), state: { title: "Hello" }, actorId: Option.none() }),
|
|
35
|
+
* );
|
|
36
|
+
*
|
|
37
|
+
* // The chain operations appended version 0, and the fake recorded it.
|
|
38
|
+
* deepStrictEqual(
|
|
39
|
+
* store.rows().map((row) => [row.id, row.version, row.action]),
|
|
40
|
+
* [[id, 0n, "create"]],
|
|
41
|
+
* );
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @copyright Thomas Foster
|
|
45
|
+
* @module pulpit/testing
|
|
46
|
+
* @since 0.1.0
|
|
47
|
+
*/
|
|
48
|
+
import * as HashMap from "effect/HashMap";
|
|
49
|
+
import * as HashSet from "effect/HashSet";
|
|
50
|
+
import * as Option from "effect/Option";
|
|
51
|
+
import * as Schema from "effect/Schema";
|
|
52
|
+
import { type BlobHead, type BlobStore } from "./blobs.ts";
|
|
53
|
+
import type { BudgetCounter, BudgetRequest, WriteCountStore } from "./budgets.ts";
|
|
54
|
+
import { type DocumentHash, type DocumentStore } from "./documents.ts";
|
|
55
|
+
import { type EdgeEnds, type EdgeRow, type EdgeStore, type EdgeValues, type EndpointView } from "./edges.ts";
|
|
56
|
+
import { type FilterRow } from "./filter.ts";
|
|
57
|
+
import type { PurgeStore } from "./purge.ts";
|
|
58
|
+
import { SearchScopeLeak, type EmbeddingStore, type SearchBranch } from "./search.ts";
|
|
59
|
+
import type { ReactionRow, ReactionStore } from "./reactions.ts";
|
|
60
|
+
import type { KvEntry, VersionedKv } from "./cache.ts";
|
|
61
|
+
import type { CollectionEntry, CollectionStore } from "./collections.ts";
|
|
62
|
+
import type { Relationship, SocialStore } from "./social.ts";
|
|
63
|
+
import { type PathEntry, type PathStore } from "./paths.ts";
|
|
64
|
+
import type { ReportRow, ReportStore } from "./moderation.ts";
|
|
65
|
+
import type { ProposalRow, ProposalStore } from "./proposals.ts";
|
|
66
|
+
import type { WorkingCopy, WorkingCopyStore } from "./working-copy.ts";
|
|
67
|
+
import type { FollowerSeam, LeafRow, LeafStore, LiveView, PublicationFact, PublicationStore, ResourceCacheSeam } from "./subtype.ts";
|
|
68
|
+
import { type VersionChainStore, type VersionRow } from "./version-chain.ts";
|
|
69
|
+
/**
|
|
70
|
+
* The follower seam's `in` set in every fake here: the ids of the accounts a
|
|
71
|
+
* viewer follows. A SQL store's is a subquery; the in-memory list filters
|
|
72
|
+
* test membership in this set instead.
|
|
73
|
+
*
|
|
74
|
+
* @since 0.1.0
|
|
75
|
+
*/
|
|
76
|
+
export type InMemoryFollowing = HashSet.HashSet<string>;
|
|
77
|
+
/**
|
|
78
|
+
* An in-memory {@link FollowerSeam} over an explicit table of who follows
|
|
79
|
+
* whom: each entry is a follower's id and the ids of the accounts it
|
|
80
|
+
* follows. `isFollower` answers from the table and `following` returns the
|
|
81
|
+
* follower's row as an {@link InMemoryFollowing} set (empty for an account the
|
|
82
|
+
* table doesn't name), the in-memory reading of effect-auth's `IsFollower`
|
|
83
|
+
* (README → Seams → the follower seam). In memory only; not for production.
|
|
84
|
+
*
|
|
85
|
+
* @since 0.1.0
|
|
86
|
+
*/
|
|
87
|
+
export declare const makeInMemoryFollowers: (table: Iterable<readonly [follower: string, followed: ReadonlyArray<string>]>) => FollowerSeam<InMemoryFollowing, never>;
|
|
88
|
+
/**
|
|
89
|
+
* An in-memory {@link VersionChainStore}, plus the hooks a test reads and
|
|
90
|
+
* steers it through. In memory only; not for production.
|
|
91
|
+
*
|
|
92
|
+
* @since 0.1.0
|
|
93
|
+
*/
|
|
94
|
+
export interface InMemoryChainStore extends VersionChainStore<never, never> {
|
|
95
|
+
/** Every row ever appended, in append order — what the append-only assertions read. */
|
|
96
|
+
readonly rows: () => ReadonlyArray<VersionRow>;
|
|
97
|
+
/** Simulate a partial chain: the state at `(id, version)` is no longer reconstructable. */
|
|
98
|
+
readonly dropState: (id: string, version: bigint) => void;
|
|
99
|
+
/** Simulate a concurrent writer: the next append for `id` finds its version taken. */
|
|
100
|
+
readonly raceNextAppend: (id: string) => void;
|
|
101
|
+
/**
|
|
102
|
+
* Hard-delete every row of `id` and return them: what
|
|
103
|
+
* {@link makeInMemoryPurgeStore} erases a node through, and nothing else
|
|
104
|
+
* may call (`VERSION-CHAIN-001/002`).
|
|
105
|
+
*/
|
|
106
|
+
readonly erase: (id: string) => ReadonlyArray<VersionRow>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* An in-memory {@link VersionChainStore}: the seam's contract (README → Seams
|
|
110
|
+
* → `VersionChainStore`) over an append log. It enforces what the Drizzle
|
|
111
|
+
* store's schema enforces, the `(id, version)` primary key (an `append` at a
|
|
112
|
+
* taken pair fails `VersionConflict`), and nothing the operations are
|
|
113
|
+
* responsible for. `mintId` mints sequential UUID-shaped ids.
|
|
114
|
+
*
|
|
115
|
+
* `dropState` simulates a partial chain (a level with no row at a version),
|
|
116
|
+
* which a real database reaches through a missing leaf row, and
|
|
117
|
+
* `raceNextAppend` a writer that takes the next version first. In memory
|
|
118
|
+
* only; not for production.
|
|
119
|
+
*
|
|
120
|
+
* @since 0.1.0
|
|
121
|
+
*/
|
|
122
|
+
export declare const makeInMemoryChainStore: () => InMemoryChainStore;
|
|
123
|
+
/**
|
|
124
|
+
* An in-memory {@link LeafStore} over an {@link InMemoryChainStore}, plus the
|
|
125
|
+
* hooks a test reads and steers its owner stamps through. In memory only; not
|
|
126
|
+
* for production.
|
|
127
|
+
*
|
|
128
|
+
* @since 0.1.0
|
|
129
|
+
*/
|
|
130
|
+
export interface InMemoryLeafStore extends LeafStore<LeafRow, InMemoryFollowing, never, never> {
|
|
131
|
+
/** Every owner stamp, node id → owner id — what the owner-stamp assertions read. */
|
|
132
|
+
readonly owners: () => HashMap.HashMap<string, string>;
|
|
133
|
+
/** Simulate an ownerless owned node: drop `id`'s owner stamp (the apps' `core.node_owner` row). */
|
|
134
|
+
readonly dropOwner: (id: string) => void;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Options for {@link makeInMemoryLeafStore}.
|
|
138
|
+
*
|
|
139
|
+
* @since 0.1.0
|
|
140
|
+
*/
|
|
141
|
+
export interface InMemoryLeafStoreOptions {
|
|
142
|
+
/** The view's leaf columns; `id`, `action` and `ownerId` are always in its `columns`. */
|
|
143
|
+
readonly columns: ReadonlyArray<string>;
|
|
144
|
+
/**
|
|
145
|
+
* A localised leaf's view (pulpit#56): its `columns` gain
|
|
146
|
+
* {@link LOCALE_COLUMN}, and `list` reads one row per `(id, locale)`.
|
|
147
|
+
* `get` / `getMany` read the shared row either way.
|
|
148
|
+
*/
|
|
149
|
+
readonly localised?: boolean | undefined;
|
|
150
|
+
/** The instant `published` / `notPublished` compare against; the Effect `Clock`'s at each `list` when absent. */
|
|
151
|
+
readonly now?: Date | undefined;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* An in-memory {@link LeafStore}: the seam's contract (README → Seams →
|
|
155
|
+
* `LeafStore`) as a current-version view over an {@link InMemoryChainStore}.
|
|
156
|
+
* Each node's row is its head version's state with its head `version` and `action`, and
|
|
157
|
+
* `ownerId` merged in from the owner stamps (the apps' `core.node_owner`
|
|
158
|
+
* join); `list` evaluates its {@link ListFilter} in memory, orders by its
|
|
159
|
+
* `orderBy` keys then `id` ascending as the seam's contract renders it
|
|
160
|
+
* (`NULLS LAST` in both directions, a string by code point as `COLLATE "C"`
|
|
161
|
+
* sorts it, a `Date` by its instant), and returns the unpaged total. Like a
|
|
162
|
+
* SQL store, it takes `orderBy` as already checked against `columns`. It
|
|
163
|
+
* applies no visibility policy, as a real view applies none. In memory only;
|
|
164
|
+
* not for production.
|
|
165
|
+
*
|
|
166
|
+
* @since 0.1.0
|
|
167
|
+
*/
|
|
168
|
+
export declare const makeInMemoryLeafStore: (chain: InMemoryChainStore, options: InMemoryLeafStoreOptions) => InMemoryLeafStore;
|
|
169
|
+
/**
|
|
170
|
+
* An in-memory {@link PathStore}, plus the read a test checks it through. In
|
|
171
|
+
* memory only; not for production.
|
|
172
|
+
*
|
|
173
|
+
* @since 0.1.0
|
|
174
|
+
*/
|
|
175
|
+
export interface InMemoryPathStore extends PathStore<never, never> {
|
|
176
|
+
/** Every stored path and its entry, aliases included. */
|
|
177
|
+
readonly entries: () => HashMap.HashMap<string, PathEntry>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* An in-memory {@link PathStore}: the seam's contract (README → Seams →
|
|
181
|
+
* `PathStore`) as one map from path to entry, its key the path table's
|
|
182
|
+
* primary key, so each path is stored once. `claim` fails {@link PathTaken}
|
|
183
|
+
* for another node's canonical path, replaces an alias at the path, and
|
|
184
|
+
* demotes the node's previous canonical path to its alias, in one step;
|
|
185
|
+
* `release` drops the node's canonical path and keeps its aliases. In memory
|
|
186
|
+
* only; not for production.
|
|
187
|
+
*
|
|
188
|
+
* @since 0.1.0
|
|
189
|
+
*/
|
|
190
|
+
export declare const makeInMemoryPathStore: () => InMemoryPathStore;
|
|
191
|
+
/**
|
|
192
|
+
* An in-memory {@link ResourceCacheSeam}, plus the reads a test checks it
|
|
193
|
+
* through. In memory only; not for production.
|
|
194
|
+
*
|
|
195
|
+
* @since 0.1.0
|
|
196
|
+
*/
|
|
197
|
+
export interface InMemoryResourceCache<Resource> extends ResourceCacheSeam<Resource, never> {
|
|
198
|
+
/** The resource the cache would serve for `id`: none when evicted, refused or never set. */
|
|
199
|
+
readonly get: (id: string) => Option.Option<Resource>;
|
|
200
|
+
/** The highest version the cache holds for `id`, set or evicted, or none. */
|
|
201
|
+
readonly versionOf: (id: string) => Option.Option<bigint>;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* An in-memory {@link ResourceCacheSeam}: the seam's compare-on-set contract
|
|
205
|
+
* (README → Seams → the resource cache, pulpit#121). It keeps, per id, the
|
|
206
|
+
* highest version either call has given it: a `set` below it is a no-op, a
|
|
207
|
+
* `set` at or above it stores the resource when `serveable` admits it and
|
|
208
|
+
* evicts it otherwise, and a `delete` evicts and raises the version. Each
|
|
209
|
+
* call compares and writes in one step, as the real cache's conditional write
|
|
210
|
+
* must. In memory only; not for production.
|
|
211
|
+
*
|
|
212
|
+
* @since 0.1.0
|
|
213
|
+
*/
|
|
214
|
+
export declare const makeInMemoryResourceCache: <Resource>(serveable: (resource: Resource) => boolean) => InMemoryResourceCache<Resource>;
|
|
215
|
+
/**
|
|
216
|
+
* An in-memory {@link DocumentStore}, plus the hooks a test reads it through.
|
|
217
|
+
* In memory only; not for production.
|
|
218
|
+
*
|
|
219
|
+
* @since 0.1.0
|
|
220
|
+
*/
|
|
221
|
+
export interface InMemoryDocumentStore<Document extends Schema.Json> extends DocumentStore<Document, never, never> {
|
|
222
|
+
/** Every stored document by hash — what the never-rewritten assertions read. */
|
|
223
|
+
readonly stored: () => HashMap.HashMap<DocumentHash, Document>;
|
|
224
|
+
/**
|
|
225
|
+
* How many times `put` wrote a row: a real insert counts, a no-op `put` of a
|
|
226
|
+
* stored hash does not. The never-rewritten assertions read it, because
|
|
227
|
+
* `HashMap.set` with a structurally equal value is indistinguishable from no
|
|
228
|
+
* write in {@link InMemoryDocumentStore.stored}.
|
|
229
|
+
*/
|
|
230
|
+
readonly writes: () => number;
|
|
231
|
+
/**
|
|
232
|
+
* Delete the documents at `hashes`: what {@link makeInMemoryPurgeStore}
|
|
233
|
+
* deletes an unreferenced document through, and nothing else may call
|
|
234
|
+
* (`DOC-001`).
|
|
235
|
+
*/
|
|
236
|
+
readonly remove: (hashes: ReadonlyArray<DocumentHash>) => void;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* An in-memory {@link DocumentStore}: the seam's contract (README → Seams →
|
|
240
|
+
* `DocumentStore`), hash contract included. It hashes exactly as a Postgres
|
|
241
|
+
* store does, SHA-256 over the UTF-8 bytes of the document's
|
|
242
|
+
* {@link canonicalText}, so its hashes are the ones the database generates
|
|
243
|
+
* (the kernel's suite pins it to hashes taken from Postgres). Like a store's
|
|
244
|
+
* primary key on the hash with `ON CONFLICT DO NOTHING`, it keeps the first
|
|
245
|
+
* document stored at a hash and never replaces it (`DOC-001`). It hashes with
|
|
246
|
+
* Web Crypto (`crypto.subtle`), which Node.js 22 and every browser provide.
|
|
247
|
+
* In memory only; not for production.
|
|
248
|
+
*
|
|
249
|
+
* @since 0.1.0
|
|
250
|
+
*/
|
|
251
|
+
export declare const makeInMemoryDocumentStore: <Document extends Schema.Json>() => InMemoryDocumentStore<Document>;
|
|
252
|
+
/**
|
|
253
|
+
* An in-memory {@link EndpointView} whose nodes a test writes directly. In
|
|
254
|
+
* memory only; not for production.
|
|
255
|
+
*
|
|
256
|
+
* @since 0.1.0
|
|
257
|
+
*/
|
|
258
|
+
export interface InMemoryNodes extends EndpointView<never, never> {
|
|
259
|
+
/** Store (or replace) a node's current-version row. */
|
|
260
|
+
readonly put: (row: LeafRow) => void;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* An in-memory {@link EndpointView}: an edge end's current-version view
|
|
264
|
+
* (README → Seams → `EdgeStore`) as rows a test puts by hand, for an edge
|
|
265
|
+
* suite that doesn't need the endpoint leaf's version chain. Its `columns`
|
|
266
|
+
* are `id`, `version`, `action` and `columns`. An {@link InMemoryLeafStore} is an
|
|
267
|
+
* endpoint view too. In memory only; not for production.
|
|
268
|
+
*
|
|
269
|
+
* @since 0.1.0
|
|
270
|
+
*/
|
|
271
|
+
export declare const makeInMemoryNodes: (columns: ReadonlyArray<string>) => InMemoryNodes;
|
|
272
|
+
/**
|
|
273
|
+
* An in-memory {@link EdgeStore}, plus the hooks a test reads and steers it
|
|
274
|
+
* through. In memory only; not for production.
|
|
275
|
+
*
|
|
276
|
+
* @since 0.1.0
|
|
277
|
+
*/
|
|
278
|
+
export interface InMemoryEdgeStore extends EdgeStore<EdgeRow, InMemoryFollowing, never, never> {
|
|
279
|
+
/** Every stored edge, hidden ones included, in insertion order. */
|
|
280
|
+
readonly rows: () => ReadonlyArray<EdgeRow>;
|
|
281
|
+
/**
|
|
282
|
+
* Simulate a concurrent writer: the next insert finds its unique key just
|
|
283
|
+
* taken by `winner`, which is stored in its place (the racing writer's
|
|
284
|
+
* values, which share the key and may differ elsewhere).
|
|
285
|
+
*/
|
|
286
|
+
readonly raceNextInsert: (winner: EdgeValues) => void;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Options for {@link makeInMemoryEdgeStore}.
|
|
290
|
+
*
|
|
291
|
+
* @since 0.1.0
|
|
292
|
+
*/
|
|
293
|
+
export interface InMemoryEdgeStoreOptions {
|
|
294
|
+
/** The ends the list joins, by alias (the family declaration's `ends`). */
|
|
295
|
+
readonly ends: EdgeEnds<never, never>;
|
|
296
|
+
/** The unique key's columns; empty for a family with none. */
|
|
297
|
+
readonly uniqueKey: ReadonlyArray<string>;
|
|
298
|
+
/**
|
|
299
|
+
* The instant `published` / `notPublished` compare against, and the base of
|
|
300
|
+
* the minted `createdAt`s; the Effect `Clock`'s at each call when absent.
|
|
301
|
+
*/
|
|
302
|
+
readonly now?: Date | undefined;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* An in-memory {@link EdgeStore}: the seam's contract (README → Seams →
|
|
306
|
+
* `EdgeStore`) over one edge family's rows. It enforces what an edge table's
|
|
307
|
+
* schema enforces, the family's unique key (with `NULLS NOT DISTINCT`, as
|
|
308
|
+
* gardeneria's `page_slugs_unique_variant`), and nothing the operations are
|
|
309
|
+
* responsible for. `list`, `countAt`, `members` and `countBy` join each end's view the way the SQL
|
|
310
|
+
* store's INNER JOIN does: under the end's alias, dropping an edge whose end
|
|
311
|
+
* has no row. `list` orders by `createdAt` then `id` and reports the unpaged
|
|
312
|
+
* total as the SQL store's window column does (`0` for an empty page).
|
|
313
|
+
*
|
|
314
|
+
* Ids are minted `edge-0001`, `edge-0002`, …; the n-th insert is stamped
|
|
315
|
+
* `now + n` milliseconds, except that every third shares its predecessor's
|
|
316
|
+
* instant, so the `id` tie-break of the list order is exercised. In memory
|
|
317
|
+
* only; not for production.
|
|
318
|
+
*
|
|
319
|
+
* @since 0.1.0
|
|
320
|
+
*/
|
|
321
|
+
export declare const makeInMemoryEdgeStore: (options: InMemoryEdgeStoreOptions) => InMemoryEdgeStore;
|
|
322
|
+
/**
|
|
323
|
+
* An in-memory {@link ProposalStore}, plus the hook a test reads it through.
|
|
324
|
+
* In memory only; not for production.
|
|
325
|
+
*
|
|
326
|
+
* @since 0.1.0
|
|
327
|
+
*/
|
|
328
|
+
export interface InMemoryProposalStore extends ProposalStore<never, never> {
|
|
329
|
+
/** Every row, in insert order, as it now stands. */
|
|
330
|
+
readonly rows: () => ReadonlyArray<ProposalRow>;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* An in-memory {@link ProposalStore}: the seam's contract (README → Seams →
|
|
334
|
+
* `ProposalStore`). A listing's `targetVersion` is the `chain`'s head for
|
|
335
|
+
* the target, and the `targetOwnerId` its `list` filters on is `leaves`'
|
|
336
|
+
* owner stamp (or `null`), as the SQL store's joins read them. `lock`
|
|
337
|
+
* locks nothing (one JavaScript thread has no concurrent decision to
|
|
338
|
+
* serialise). `mintId` mints sequential UUID-shaped ids. In memory only;
|
|
339
|
+
* not for production.
|
|
340
|
+
*
|
|
341
|
+
* @since 0.1.0
|
|
342
|
+
*/
|
|
343
|
+
export declare const makeInMemoryProposalStore: (options: {
|
|
344
|
+
readonly chain: InMemoryChainStore;
|
|
345
|
+
readonly leaves: InMemoryLeafStore;
|
|
346
|
+
}) => InMemoryProposalStore;
|
|
347
|
+
/**
|
|
348
|
+
* An in-memory {@link ReportStore}, plus the hook a test reads it through.
|
|
349
|
+
* In memory only; not for production.
|
|
350
|
+
*
|
|
351
|
+
* @since 0.1.0
|
|
352
|
+
*/
|
|
353
|
+
export interface InMemoryReportStore extends ReportStore<never, never> {
|
|
354
|
+
/** Every report, in filing order, as it now stands. */
|
|
355
|
+
readonly rows: () => ReadonlyArray<ReportRow>;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* An in-memory {@link ReportStore}: the seam's contract (README → Seams →
|
|
359
|
+
* `ReportStore`). `list` evaluates the filter in memory, newest first with
|
|
360
|
+
* `id` descending on a tie; `lock` locks nothing (one JavaScript thread has
|
|
361
|
+
* no concurrent resolution to serialise); `mintId` mints sequential
|
|
362
|
+
* UUID-shaped ids. In memory only; not for production.
|
|
363
|
+
*
|
|
364
|
+
* @since 0.1.0
|
|
365
|
+
*/
|
|
366
|
+
export declare const makeInMemoryReportStore: () => InMemoryReportStore;
|
|
367
|
+
declare const InMemoryBlobFailure_base: Schema.Class<InMemoryBlobFailure, Schema.TaggedStruct<"InMemoryBlobFailure", {
|
|
368
|
+
readonly key: Schema.String;
|
|
369
|
+
}>, import("effect/Cause").YieldableError & {
|
|
370
|
+
readonly brand: unique symbol;
|
|
371
|
+
}>;
|
|
372
|
+
/**
|
|
373
|
+
* The in-memory blob store's one failure: a simulated outage.
|
|
374
|
+
*
|
|
375
|
+
* @since 0.1.0
|
|
376
|
+
*/
|
|
377
|
+
export declare class InMemoryBlobFailure extends InMemoryBlobFailure_base {
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* One object in an {@link InMemoryBlobStore}.
|
|
381
|
+
*
|
|
382
|
+
* @since 0.1.0
|
|
383
|
+
*/
|
|
384
|
+
export interface InMemoryBlob {
|
|
385
|
+
readonly bytes: Uint8Array;
|
|
386
|
+
readonly head: BlobHead;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* An in-memory {@link BlobStore}, plus the hooks a test reads and steers it
|
|
390
|
+
* through. In memory only; not for production.
|
|
391
|
+
*
|
|
392
|
+
* @since 0.1.0
|
|
393
|
+
*/
|
|
394
|
+
export interface InMemoryBlobStore extends BlobStore<InMemoryBlobFailure, never> {
|
|
395
|
+
/** Every stored object by key. */
|
|
396
|
+
readonly objects: () => HashMap.HashMap<string, InMemoryBlob>;
|
|
397
|
+
/** Simulate an outage: the next `put` fails with {@link InMemoryBlobFailure}. */
|
|
398
|
+
readonly failNextPut: () => void;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* An in-memory {@link BlobStore}: the seam's contract (README → Seams →
|
|
402
|
+
* `BlobStore`). `publicUrl` is `memory://<key>`; there is no signed upload
|
|
403
|
+
* URL. `failNextPut` simulates the byte write failing after the commit. In
|
|
404
|
+
* memory only; not for production.
|
|
405
|
+
*
|
|
406
|
+
* @since 0.1.0
|
|
407
|
+
*/
|
|
408
|
+
export declare const makeInMemoryBlobStore: () => InMemoryBlobStore;
|
|
409
|
+
/**
|
|
410
|
+
* A publish-gated leaf's in-memory seams, over an in-memory chain and leaf
|
|
411
|
+
* store, plus the hook a test reads the log through. In memory only; not
|
|
412
|
+
* for production.
|
|
413
|
+
*
|
|
414
|
+
* @since 0.1.0
|
|
415
|
+
*/
|
|
416
|
+
export interface InMemoryPublication {
|
|
417
|
+
/** The publication log. */
|
|
418
|
+
readonly facts: PublicationStore<never, never>;
|
|
419
|
+
/** The live-version view. */
|
|
420
|
+
readonly live: LiveView<LeafRow, InMemoryFollowing, never, never>;
|
|
421
|
+
/** The leaf's current-version view, with `draft` computed from the log. */
|
|
422
|
+
readonly leaves: LeafStore<LeafRow, InMemoryFollowing, never, never>;
|
|
423
|
+
/** Every fact, in record order. */
|
|
424
|
+
readonly recorded: () => ReadonlyArray<PublicationFact>;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* The in-memory seams of a publish-gated leaf: the seam contracts (README →
|
|
428
|
+
* Seams → `PublicationStore`, `LiveView`). The effective fact is the last
|
|
429
|
+
* recorded one whose `at` has arrived at `now` (the Effect `Clock`'s when
|
|
430
|
+
* absent, so `TestClock` steers a schedule). A live row is the state at the
|
|
431
|
+
* effective fact's version, with that version as its `version`, the
|
|
432
|
+
* head's `action` and owner, `draft: false` and the fact's `at` as
|
|
433
|
+
* `publishedAt`; a head row's `draft`
|
|
434
|
+
* is whether the node has no live version. In memory only; not for
|
|
435
|
+
* production.
|
|
436
|
+
*
|
|
437
|
+
* @since 0.1.0
|
|
438
|
+
*/
|
|
439
|
+
export declare const makeInMemoryPublication: (options: {
|
|
440
|
+
readonly chain: InMemoryChainStore;
|
|
441
|
+
readonly leaves: InMemoryLeafStore;
|
|
442
|
+
readonly now?: Date | undefined;
|
|
443
|
+
}) => InMemoryPublication;
|
|
444
|
+
/**
|
|
445
|
+
* An in-memory {@link WorkingCopyStore}, plus the hook a test reads it
|
|
446
|
+
* through. In memory only; not for production.
|
|
447
|
+
*
|
|
448
|
+
* @since 0.1.0
|
|
449
|
+
*/
|
|
450
|
+
export interface InMemoryWorkingCopyStore extends WorkingCopyStore<never, never> {
|
|
451
|
+
/** Every copy, keyed `id:userId`. */
|
|
452
|
+
readonly copies: () => HashMap.HashMap<string, WorkingCopy>;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* An in-memory {@link WorkingCopyStore}: the seam's contract (README →
|
|
456
|
+
* Seams → `WorkingCopyStore`), one copy per `(id, userId)`. In memory only;
|
|
457
|
+
* not for production.
|
|
458
|
+
*
|
|
459
|
+
* @since 0.1.0
|
|
460
|
+
*/
|
|
461
|
+
export declare const makeInMemoryWorkingCopyStore: () => InMemoryWorkingCopyStore;
|
|
462
|
+
/**
|
|
463
|
+
* Options for {@link makeInMemoryPurgeStore}.
|
|
464
|
+
*
|
|
465
|
+
* @since 0.1.0
|
|
466
|
+
*/
|
|
467
|
+
export interface InMemoryPurgeStoreOptions {
|
|
468
|
+
/**
|
|
469
|
+
* Every chain whose version rows may reference a document or bytes: the
|
|
470
|
+
* purged node's rows are erased from each, and a hash is unreferenced when
|
|
471
|
+
* no row left in any of them carries it.
|
|
472
|
+
*/
|
|
473
|
+
readonly chains: ReadonlyArray<InMemoryChainStore>;
|
|
474
|
+
/** The documents an unreferenced hash is deleted from; omitted, none is deleted (or reported). */
|
|
475
|
+
readonly documents?: Pick<InMemoryDocumentStore<Schema.Json>, "remove"> | undefined;
|
|
476
|
+
/** The state columns that carry a `DocumentHash`; omitted, none do. */
|
|
477
|
+
readonly documentColumns?: ReadonlyArray<string> | undefined;
|
|
478
|
+
/** The state columns that carry a `ContentHash` (a file leaf's `contentHash`); omitted, none do. */
|
|
479
|
+
readonly blobColumns?: ReadonlyArray<string> | undefined;
|
|
480
|
+
/**
|
|
481
|
+
* What else `eraseNode` deletes for the node: the rows other fakes keep
|
|
482
|
+
* for it (an owner stamp through `InMemoryLeafStore.dropOwner`, working
|
|
483
|
+
* copies, edges, …), as a real store's `ON DELETE CASCADE` would.
|
|
484
|
+
*/
|
|
485
|
+
readonly dependents?: ReadonlyArray<(id: string) => void> | undefined;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* An in-memory {@link PurgeStore} over in-memory chains and a document
|
|
489
|
+
* store: the seam's contract (README → Seams → `PurgeStore`). `eraseNode`
|
|
490
|
+
* erases the node's rows from every chain and runs the `dependents`;
|
|
491
|
+
* a hash is referenced while any row left in any chain carries it in a
|
|
492
|
+
* declared column. In memory only; not for production.
|
|
493
|
+
*
|
|
494
|
+
* @since 0.1.0
|
|
495
|
+
*/
|
|
496
|
+
export declare const makeInMemoryPurgeStore: (options: InMemoryPurgeStoreOptions) => PurgeStore<never, never>;
|
|
497
|
+
/**
|
|
498
|
+
* An in-memory {@link SearchBranch} over `rows`: each row the scope admits
|
|
499
|
+
* (evaluated at `now` over {@link InMemoryFollowing}) and `score` gives a
|
|
500
|
+
* score for the query is a hit, best score first, ties by id, at most
|
|
501
|
+
* `request.limit`. The reference semantics of the branch contract: it
|
|
502
|
+
* applies the scope it is handed in the same pass that ranks.
|
|
503
|
+
*
|
|
504
|
+
* @since 0.1.0
|
|
505
|
+
*/
|
|
506
|
+
export declare const makeInMemorySearchBranch: (options: {
|
|
507
|
+
readonly name: string;
|
|
508
|
+
readonly weight?: number | undefined;
|
|
509
|
+
readonly rows: () => ReadonlyArray<FilterRow & {
|
|
510
|
+
readonly id: string;
|
|
511
|
+
}>;
|
|
512
|
+
/** The row's score for `query`, or none when it doesn't match. */
|
|
513
|
+
readonly score: (row: FilterRow, query: string) => Option.Option<number>;
|
|
514
|
+
readonly now: Date;
|
|
515
|
+
}) => SearchBranch<InMemoryFollowing, never, never>;
|
|
516
|
+
/**
|
|
517
|
+
* Wrap a {@link SearchBranch} so it fails {@link SearchScopeLeak} when it
|
|
518
|
+
* returns a hit whose row (looked up in `rows` by id) the scope it was
|
|
519
|
+
* handed does not admit, or that `rows` lacks: the test seam an
|
|
520
|
+
* application wraps around its own SQL branches to prove each applies the
|
|
521
|
+
* scope (`SEC-AUTH-ENUM-001`).
|
|
522
|
+
*
|
|
523
|
+
* @since 0.1.0
|
|
524
|
+
*/
|
|
525
|
+
export declare const scopeCheckedBranch: <E, R>(branch: SearchBranch<InMemoryFollowing, E, R>, options: {
|
|
526
|
+
readonly rows: () => ReadonlyArray<FilterRow & {
|
|
527
|
+
readonly id: string;
|
|
528
|
+
}>;
|
|
529
|
+
readonly now: Date;
|
|
530
|
+
}) => SearchBranch<InMemoryFollowing, E | SearchScopeLeak, R>;
|
|
531
|
+
/**
|
|
532
|
+
* {@link makeInMemoryEmbeddingStore}'s fake: the seam plus test hooks.
|
|
533
|
+
*
|
|
534
|
+
* @since 0.1.0
|
|
535
|
+
*/
|
|
536
|
+
export interface InMemoryEmbeddingStore extends EmbeddingStore<never, never> {
|
|
537
|
+
/** The queued hashes, in queue order. */
|
|
538
|
+
readonly queued: () => ReadonlyArray<DocumentHash>;
|
|
539
|
+
/** The written vectors, by hash. */
|
|
540
|
+
readonly vectors: () => HashMap.HashMap<DocumentHash, ReadonlyArray<number>>;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* An in-memory {@link EmbeddingStore}: a queue in insertion order
|
|
544
|
+
* (`enqueue` is idempotent, and a hash with a vector is never queued again),
|
|
545
|
+
* `pending` the oldest `limit` queued, `write` storing each vector and
|
|
546
|
+
* dequeuing it, and `discard` dequeuing.
|
|
547
|
+
*
|
|
548
|
+
* @since 0.1.0
|
|
549
|
+
*/
|
|
550
|
+
export declare const makeInMemoryEmbeddingStore: () => InMemoryEmbeddingStore;
|
|
551
|
+
/**
|
|
552
|
+
* One write {@link makeInMemoryWriteCountStore} has recorded.
|
|
553
|
+
*
|
|
554
|
+
* @since 0.1.0
|
|
555
|
+
*/
|
|
556
|
+
export interface RecordedWrite {
|
|
557
|
+
readonly type: string;
|
|
558
|
+
readonly action: string;
|
|
559
|
+
readonly accountId: string;
|
|
560
|
+
readonly at: Date;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* An in-memory atomic {@link BudgetCounter}, plus the hook a test reads it
|
|
564
|
+
* through. In memory only; not for production.
|
|
565
|
+
*
|
|
566
|
+
* @since 0.1.0
|
|
567
|
+
*/
|
|
568
|
+
export interface InMemoryBudgetCounter extends BudgetCounter<never, never> {
|
|
569
|
+
/** Every spend it admitted, in order. */
|
|
570
|
+
readonly spends: () => ReadonlyArray<BudgetRequest>;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* An in-memory atomic {@link BudgetCounter} (README → Seams →
|
|
574
|
+
* `BudgetCounter`): it counts the spends it admitted at or after the
|
|
575
|
+
* request's `since`, and records a spend only when it answers `true`. One
|
|
576
|
+
* JavaScript thread makes its check-and-record atomic. In memory only; not
|
|
577
|
+
* for production.
|
|
578
|
+
*
|
|
579
|
+
* @since 0.1.0
|
|
580
|
+
*/
|
|
581
|
+
export declare const makeInMemoryBudgetCounter: () => InMemoryBudgetCounter;
|
|
582
|
+
/**
|
|
583
|
+
* An in-memory {@link WriteCountStore}, plus `record`, the row a write
|
|
584
|
+
* inserts. In memory only; not for production.
|
|
585
|
+
*
|
|
586
|
+
* @since 0.1.0
|
|
587
|
+
*/
|
|
588
|
+
export interface InMemoryWriteCountStore extends WriteCountStore<never, never> {
|
|
589
|
+
/** Record one write, as the family's own row would. */
|
|
590
|
+
readonly record: (write: RecordedWrite) => void;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* An in-memory {@link WriteCountStore} (README → Seams →
|
|
594
|
+
* `WriteCountStore`): `countSince` counts the recorded writes of the key at
|
|
595
|
+
* or after `since`. In memory only; not for production.
|
|
596
|
+
*
|
|
597
|
+
* @since 0.1.0
|
|
598
|
+
*/
|
|
599
|
+
export declare const makeInMemoryWriteCountStore: () => InMemoryWriteCountStore;
|
|
600
|
+
/**
|
|
601
|
+
* {@link makeInMemoryReactionStore}'s fake: the seam plus a test hook.
|
|
602
|
+
*
|
|
603
|
+
* @since 0.1.0
|
|
604
|
+
*/
|
|
605
|
+
export interface InMemoryReactionStore extends ReactionStore<never, never> {
|
|
606
|
+
/** Every stored reaction. */
|
|
607
|
+
readonly rows: () => ReadonlyArray<ReactionRow>;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* An in-memory {@link ReactionStore}, keyed `(nodeId, accountId)` as the
|
|
611
|
+
* real table is: `upsert` replaces, `tally` groups by node and kind,
|
|
612
|
+
* `byAccount` is newest first (`nodeId` breaking a tie).
|
|
613
|
+
*
|
|
614
|
+
* @since 0.1.0
|
|
615
|
+
*/
|
|
616
|
+
export declare const makeInMemoryReactionStore: () => InMemoryReactionStore;
|
|
617
|
+
/**
|
|
618
|
+
* {@link makeInMemoryVersionedKv}'s fake: the seam plus test hooks.
|
|
619
|
+
*
|
|
620
|
+
* @since 0.1.0
|
|
621
|
+
*/
|
|
622
|
+
export interface InMemoryVersionedKv extends VersionedKv<never, never> {
|
|
623
|
+
/** The stored entry at `key` with its expiry instant (ms), expired or not. */
|
|
624
|
+
readonly peek: (key: string) => Option.Option<KvEntry & {
|
|
625
|
+
readonly expiresAt: number;
|
|
626
|
+
}>;
|
|
627
|
+
/** Overwrite `key` unconditionally (a corrupt or foreign value, for a decode test). */
|
|
628
|
+
readonly poke: (key: string, entry: KvEntry) => void;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* An in-memory {@link VersionedKv}: `putIfNotBehind` compares and writes in
|
|
632
|
+
* one step, and an entry past its TTL reads as absent (the Effect `Clock`,
|
|
633
|
+
* so `TestClock` steers expiry). In memory only; not for production.
|
|
634
|
+
*
|
|
635
|
+
* @since 0.1.0
|
|
636
|
+
*/
|
|
637
|
+
export declare const makeInMemoryVersionedKv: () => InMemoryVersionedKv;
|
|
638
|
+
/**
|
|
639
|
+
* {@link makeInMemoryCollectionStore}'s fake: the seam plus a test hook.
|
|
640
|
+
*
|
|
641
|
+
* @since 0.1.0
|
|
642
|
+
*/
|
|
643
|
+
export interface InMemoryCollectionStore extends CollectionStore<never, never> {
|
|
644
|
+
/** Every parent's entries, as stored. */
|
|
645
|
+
readonly rows: () => HashMap.HashMap<string, ReadonlyArray<CollectionEntry>>;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* An in-memory {@link CollectionStore}: each parent's entries, replaced
|
|
649
|
+
* whole, read back by position then member id. In memory only; not for
|
|
650
|
+
* production.
|
|
651
|
+
*
|
|
652
|
+
* @since 0.1.0
|
|
653
|
+
*/
|
|
654
|
+
export declare const makeInMemoryCollectionStore: () => InMemoryCollectionStore;
|
|
655
|
+
/**
|
|
656
|
+
* {@link makeInMemorySocialStore}'s fake: the seam plus a test hook.
|
|
657
|
+
*
|
|
658
|
+
* @since 0.1.0
|
|
659
|
+
*/
|
|
660
|
+
export interface InMemorySocialStore extends SocialStore<InMemoryFollowing, never, never> {
|
|
661
|
+
/** Every stored relationship. */
|
|
662
|
+
readonly rows: () => ReadonlyArray<Relationship>;
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* An in-memory {@link SocialStore}, keyed `(kind, from, to)` as the real
|
|
666
|
+
* table is; `followingOf` and `silencedBy` return {@link InMemoryFollowing}
|
|
667
|
+
* sets, where SQL's are subqueries. `addFollow` and `addBlock` each run as
|
|
668
|
+
* one synchronous step, so they are atomic against each other as the seam
|
|
669
|
+
* requires. In memory only; not for production.
|
|
670
|
+
*
|
|
671
|
+
* @since 0.1.0
|
|
672
|
+
*/
|
|
673
|
+
export declare const makeInMemorySocialStore: () => InMemorySocialStore;
|
|
674
|
+
export {};
|
|
675
|
+
//# sourceMappingURL=testing.d.ts.map
|