@thomasfosterau/pulpit 0.0.0 → 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 +1271 -1
- 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 +138 -4
- 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
package/dist/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@thomasfosterau/pulpit` — the versioned-content kernel.
|
|
3
|
+
*
|
|
4
|
+
* Every module is exported as a namespace from the package root, following
|
|
5
|
+
* the convention of `effect` and `@thomasfosterau/effect-jsonapi`; each is
|
|
6
|
+
* also a subpath (`@thomasfosterau/pulpit/content`, …) for a consumer that
|
|
7
|
+
* wants one module without the barrel. The in-memory fakes are the one
|
|
8
|
+
* exception: they are the subpath `@thomasfosterau/pulpit/testing` only, so
|
|
9
|
+
* that production code never pulls them in through the barrel.
|
|
10
|
+
*
|
|
11
|
+
* @copyright Thomas Foster
|
|
12
|
+
* @module pulpit
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The Content model fields: `Visibility`, the visibility / draft / timestamp /
|
|
16
|
+
* tombstone spreads, `ownerRef`, the base `content` resource.
|
|
17
|
+
*/
|
|
18
|
+
export * as Content from "./content.js";
|
|
19
|
+
/**
|
|
20
|
+
* The registry flag vocabulary, `validateRegistry`, and the derived families /
|
|
21
|
+
* branches.
|
|
22
|
+
*/
|
|
23
|
+
export * as Registry from "./registry.js";
|
|
24
|
+
/**
|
|
25
|
+
* The append-only node / version chain: create, update, restore, delete,
|
|
26
|
+
* getVersion, compare (with the pure `diffStates`), restoreVersion, history —
|
|
27
|
+
* over a store seam.
|
|
28
|
+
*/
|
|
29
|
+
export * as VersionChain from "./version-chain.js";
|
|
30
|
+
/** The list-filter vocabulary the read predicates render into, and its in-memory evaluator. */
|
|
31
|
+
export * as Filter from "./filter.js";
|
|
32
|
+
/**
|
|
33
|
+
* The subtype operation factory: `LeafAccess`, the read scope and viewer
|
|
34
|
+
* predicates, the write gates, `defineSubtype` and its handlers seam.
|
|
35
|
+
*/
|
|
36
|
+
export * as Subtype from "./subtype.js";
|
|
37
|
+
/**
|
|
38
|
+
* The publication axis, the moderation state, and the cache serveability
|
|
39
|
+
* policy (`isPubliclyServeable`, the `serveable` hook).
|
|
40
|
+
*/
|
|
41
|
+
export * as Publication from "./publication.js";
|
|
42
|
+
/**
|
|
43
|
+
* The content-addressed document store seam (`DocumentStore`), the
|
|
44
|
+
* `DocumentHash` it is keyed by, and the `documentRef` field spread a version
|
|
45
|
+
* row carries the reference in.
|
|
46
|
+
*/
|
|
47
|
+
export * as Documents from "./documents.js";
|
|
48
|
+
/**
|
|
49
|
+
* The edge operations factory: a relation between nodes as its own family
|
|
50
|
+
* (`defineEdgeOps` over an `EdgeStore` seam), readable only when every end
|
|
51
|
+
* is, with declared cardinality limits.
|
|
52
|
+
*/
|
|
53
|
+
export * as Edges from "./edges.js";
|
|
54
|
+
/**
|
|
55
|
+
* Suggested edits: a contributor's patch against a node's version, accepted
|
|
56
|
+
* through the target's own update or rejected (`defineProposals` over a
|
|
57
|
+
* `ProposalStore` seam), with its two-tier stale / conflict classification.
|
|
58
|
+
*/
|
|
59
|
+
export * as Proposals from "./proposals.js";
|
|
60
|
+
/**
|
|
61
|
+
* File and media leaves: the blob-store seam (`BlobStore`) keyed by the
|
|
62
|
+
* content hash, the file field spread, the commit-ordered byte write
|
|
63
|
+
* (`defineFileWrites`) and the usage index's edge ends.
|
|
64
|
+
*/
|
|
65
|
+
export * as Blobs from "./blobs.js";
|
|
66
|
+
/**
|
|
67
|
+
* Routable content: a leaf's path claims tied to its version chain
|
|
68
|
+
* (`routable` over a `PathStore` seam), the aliases a path change leaves
|
|
69
|
+
* behind, and the gated resolution of a path.
|
|
70
|
+
*/
|
|
71
|
+
export * as Paths from "./paths.js";
|
|
72
|
+
/**
|
|
73
|
+
* The moderation workflow: the transition rules as a before hook
|
|
74
|
+
* (`moderationHook`), the decision (`defineModeration`), the review-queue
|
|
75
|
+
* filter, threshold grading (`gradeScores`) and member reports
|
|
76
|
+
* (`defineReports` over a `ReportStore` seam).
|
|
77
|
+
*/
|
|
78
|
+
export * as Moderation from "./moderation.js";
|
|
79
|
+
/**
|
|
80
|
+
* The working copy: an editor's autosave buffer outside the version chain
|
|
81
|
+
* (`WorkingCopyStore`), committed as one ordinary version
|
|
82
|
+
* (`defineWorkingCopy`).
|
|
83
|
+
*/
|
|
84
|
+
export * as WorkingCopy from "./working-copy.js";
|
|
85
|
+
/**
|
|
86
|
+
* The comments family: threaded comments on any node as versioned owned
|
|
87
|
+
* leaves (`defineComments`), behind the target's read gate and the
|
|
88
|
+
* moderation gate.
|
|
89
|
+
*/
|
|
90
|
+
export * as Comments from "./comments.js";
|
|
91
|
+
/**
|
|
92
|
+
* Purge: erasure, the one destructive path through a node's history. It
|
|
93
|
+
* hard-deletes a node's chain and the rows kept for it, then the documents
|
|
94
|
+
* and bytes nothing else references (`definePurge` over a `PurgeStore`).
|
|
95
|
+
*/
|
|
96
|
+
export * as Purge from "./purge.js";
|
|
97
|
+
/**
|
|
98
|
+
* Hybrid search: reciprocal rank fusion over ranked branches, the reranker
|
|
99
|
+
* and branch seams every branch's scope runs through, and the embedding
|
|
100
|
+
* pipeline as seams (`fuseRankings`, `hybridSearch`, `embedPending`).
|
|
101
|
+
*/
|
|
102
|
+
export * as Search from "./search.js";
|
|
103
|
+
/**
|
|
104
|
+
* Write budgets: a declared ceiling on an account's writes in a rolling
|
|
105
|
+
* window, spent inside the write as a before hook or by a plain-row family,
|
|
106
|
+
* over a `BudgetCounter` seam (`bindBudget`, `budgetHook`).
|
|
107
|
+
*/
|
|
108
|
+
export * as Budgets from "./budgets.js";
|
|
109
|
+
/**
|
|
110
|
+
* Reactions: one reaction per account per node, a kind from the family's
|
|
111
|
+
* vocabulary, behind the target's read gate, with a grouped tally
|
|
112
|
+
* (`defineReactions` over a `ReactionStore`).
|
|
113
|
+
*/
|
|
114
|
+
export * as Reactions from "./reactions.js";
|
|
115
|
+
/**
|
|
116
|
+
* The reference resource cache: `./subtype`'s `ResourceCacheSeam`, with a
|
|
117
|
+
* read-through `get`, over a minimal versioned key-value seam
|
|
118
|
+
* (`makeResourceCache` over a `VersionedKv`).
|
|
119
|
+
*/
|
|
120
|
+
export * as Cache from "./cache.js";
|
|
121
|
+
/**
|
|
122
|
+
* Ordered collections: positioned members of a parent node, the order kept
|
|
123
|
+
* beside the chain or versioned with the parent (`defineCollection` over a
|
|
124
|
+
* `CollectionStore`).
|
|
125
|
+
*/
|
|
126
|
+
export * as Collections from "./collections.js";
|
|
127
|
+
/**
|
|
128
|
+
* The social graph: follow, mute and block between accounts, the follower
|
|
129
|
+
* seam filled from it, and the opt-in read filter over silenced authors
|
|
130
|
+
* (`defineSocial` over a `SocialStore`).
|
|
131
|
+
*/
|
|
132
|
+
export * as Social from "./social.js";
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;GAGG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C;;;;GAIG;AACH,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AAEnD,+FAA+F;AAC/F,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;GAGG;AACH,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;;GAKG;AACH,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAE9C;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AAEjD;;;;GAIG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;;;GAIG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;;GAIG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ListFilter } from "../filter.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Every column of `filter` rewritten by `rename`; the tree's shape and every
|
|
4
|
+
* comparand are kept. Exhaustive over the node kinds, so a new kind cannot
|
|
5
|
+
* slip through with its column unrenamed.
|
|
6
|
+
*/
|
|
7
|
+
export declare const renameColumns: <Following>(filter: ListFilter<Following>, rename: (column: string) => string) => ListFilter<Following>;
|
|
8
|
+
//# sourceMappingURL=filter-columns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-columns.d.ts","sourceRoot":"","sources":["../../src/internal/filter-columns.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,UAC7B,UAAU,CAAC,SAAS,CAAC,UACrB,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,KACjC,UAAU,CAAC,SAAS,CA4BpB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **A list filter's columns, renamed**: `./edges` qualifies a leaf's filter
|
|
3
|
+
* with an end's alias through it, so a store can render that filter against
|
|
4
|
+
* the view it joined under the alias.
|
|
5
|
+
*
|
|
6
|
+
* Internal: not a package entry point (absent from `package.json`
|
|
7
|
+
* `exports`) and excluded from the generated API docs (`docgen.json`).
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
import * as Match from "effect/Match";
|
|
12
|
+
/**
|
|
13
|
+
* Every column of `filter` rewritten by `rename`; the tree's shape and every
|
|
14
|
+
* comparand are kept. Exhaustive over the node kinds, so a new kind cannot
|
|
15
|
+
* slip through with its column unrenamed.
|
|
16
|
+
*/
|
|
17
|
+
export const renameColumns = (filter, rename) => Match.value(filter).pipe(Match.discriminatorsExhaustive("kind")({
|
|
18
|
+
always: (node) => node,
|
|
19
|
+
never: (node) => node,
|
|
20
|
+
eq: (node) => ({ ...node, column: rename(node.column) }),
|
|
21
|
+
ne: (node) => ({ ...node, column: rename(node.column) }),
|
|
22
|
+
in: (node) => ({ ...node, column: rename(node.column) }),
|
|
23
|
+
notIn: (node) => ({ ...node, column: rename(node.column) }),
|
|
24
|
+
gt: (node) => ({ ...node, column: rename(node.column) }),
|
|
25
|
+
gte: (node) => ({ ...node, column: rename(node.column) }),
|
|
26
|
+
lt: (node) => ({ ...node, column: rename(node.column) }),
|
|
27
|
+
lte: (node) => ({ ...node, column: rename(node.column) }),
|
|
28
|
+
anyOf: (node) => ({ ...node, column: rename(node.column) }),
|
|
29
|
+
noneOf: (node) => ({ ...node, column: rename(node.column) }),
|
|
30
|
+
isNull: (node) => ({ ...node, column: rename(node.column) }),
|
|
31
|
+
published: (node) => ({ ...node, column: rename(node.column) }),
|
|
32
|
+
notPublished: (node) => ({ ...node, column: rename(node.column) }),
|
|
33
|
+
locale: (node) => ({ ...node, column: rename(node.column) }),
|
|
34
|
+
and: (node) => ({
|
|
35
|
+
kind: "and",
|
|
36
|
+
filters: node.filters.map((part) => renameColumns(part, rename)),
|
|
37
|
+
}),
|
|
38
|
+
or: (node) => ({
|
|
39
|
+
kind: "or",
|
|
40
|
+
filters: node.filters.map((part) => renameColumns(part, rename)),
|
|
41
|
+
}),
|
|
42
|
+
}));
|
|
43
|
+
//# sourceMappingURL=filter-columns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-columns.js","sourceRoot":"","sources":["../../src/internal/filter-columns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as Order from "effect/Order";
|
|
2
|
+
import type { ColumnValue } from "../version-chain.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Strings by code point, as SQL's `"C"` collation orders them over UTF-8.
|
|
5
|
+
* JavaScript's `<` compares UTF-16 code units instead, which puts an astral
|
|
6
|
+
* character (a surrogate pair, from U+D800) before U+E000–U+FFFF.
|
|
7
|
+
*/
|
|
8
|
+
export declare const byCodePoint: Order.Order<string>;
|
|
9
|
+
/** One order key, structurally (`./subtype`'s `ListOrder` fits). */
|
|
10
|
+
interface OrderKey {
|
|
11
|
+
readonly column: string;
|
|
12
|
+
readonly direction: "asc" | "desc";
|
|
13
|
+
}
|
|
14
|
+
/** A row as the order reads it: its `id` and its columns by name. */
|
|
15
|
+
type SortRow = {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly [column: string]: ColumnValue;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The total order a list renders as `ORDER BY <key> <direction> NULLS LAST,
|
|
21
|
+
* …, id ASC`: each key in turn, a `NULL` (or absent) column after every
|
|
22
|
+
* value in either direction, then `id` ascending, so no two rows tie.
|
|
23
|
+
*/
|
|
24
|
+
export declare const rowOrder: (keys: ReadonlyArray<OrderKey>) => Order.Order<SortRow>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=list-order.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-order.d.ts","sourceRoot":"","sources":["../../src/internal/list-order.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAG3C,CAAC;AA8DF,oEAAoE;AACpE,UAAU,QAAQ;IAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;CACpC;AAED,qEAAqE;AACrE,KAAK,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,CAAC;AAgB/E;;;;GAIG;AACH,eAAO,MAAM,QAAQ,SAAU,aAAa,CAAC,QAAQ,CAAC,KAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CACvB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **The kernel's value and row orders**: the code-point string order that
|
|
3
|
+
* `./filter`'s comparison arms share with SQL's `COLLATE "C"`, and the list
|
|
4
|
+
* order the in-memory `LeafStore` fake sorts by (pulpit#112), so the fake and
|
|
5
|
+
* the filter never compare a string two ways.
|
|
6
|
+
*
|
|
7
|
+
* Internal: not a package entry point (absent from `package.json`
|
|
8
|
+
* `exports`) and excluded from the generated API docs (`docgen.json`).
|
|
9
|
+
* Typed structurally, so it never imports `./subtype`.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
import * as Array from "effect/Array";
|
|
14
|
+
import * as Order from "effect/Order";
|
|
15
|
+
import * as Predicate from "effect/Predicate";
|
|
16
|
+
/**
|
|
17
|
+
* Strings by code point, as SQL's `"C"` collation orders them over UTF-8.
|
|
18
|
+
* JavaScript's `<` compares UTF-16 code units instead, which puts an astral
|
|
19
|
+
* character (a surrogate pair, from U+D800) before U+E000–U+FFFF.
|
|
20
|
+
*/
|
|
21
|
+
export const byCodePoint = Order.mapInput(Order.Array(Order.Number), (text) => Array.map(Array.fromIterable(text), (char) => char.codePointAt(0) ?? 0));
|
|
22
|
+
/**
|
|
23
|
+
* Numbers as PostgreSQL's `float8` sorts them: `NaN` equal to itself and
|
|
24
|
+
* after every number, where Effect's `Order.Number` puts it first.
|
|
25
|
+
*/
|
|
26
|
+
const byNumber = Order.make((self, that) => {
|
|
27
|
+
if (Number.isNaN(self))
|
|
28
|
+
return Number.isNaN(that) ? 0 : 1;
|
|
29
|
+
return Number.isNaN(that) ? -1 : Order.Number(self, that);
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* One kind of sort-key value: its guard and its order, the order lifted to
|
|
33
|
+
* every {@link ColumnValue} (two values the guard doesn't both admit tie).
|
|
34
|
+
*/
|
|
35
|
+
const kind = (is, order) => ({
|
|
36
|
+
is,
|
|
37
|
+
order: Order.make((self, that) => (is(self) && is(that) ? order(self, that) : 0)),
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* The kinds of sort-key value, each sorted as PostgreSQL sorts its type: a
|
|
41
|
+
* boolean `false` first, a number numerically, a `bigint` by value, a
|
|
42
|
+
* string by code point, a `Date` by its instant (an invalid one as `NaN`).
|
|
43
|
+
*/
|
|
44
|
+
const kinds = [
|
|
45
|
+
kind(Predicate.isBoolean, Order.Boolean),
|
|
46
|
+
kind(Predicate.isNumber, byNumber),
|
|
47
|
+
kind(Predicate.isBigInt, Order.BigInt),
|
|
48
|
+
kind(Predicate.isString, byCodePoint),
|
|
49
|
+
kind(Predicate.isDate, Order.mapInput(byNumber, (date) => date.getTime())),
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* A value's place in {@link kinds}; a JSON object or array comes after
|
|
53
|
+
* them all. Two values of different kinds sort by it, which is outside the
|
|
54
|
+
* contract (a SQL column has one type), so it only keeps the fake's order
|
|
55
|
+
* total and deterministic.
|
|
56
|
+
*/
|
|
57
|
+
const kindOf = (value) => {
|
|
58
|
+
const index = kinds.findIndex((each) => each.is(value));
|
|
59
|
+
return index === -1 ? kinds.length : index;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Two non-`NULL` sort-key values: by kind, then by that kind's order. Two
|
|
63
|
+
* JSON objects or arrays tie, leaving the order to the next key.
|
|
64
|
+
*/
|
|
65
|
+
const byValue = Order.make((self, that) => {
|
|
66
|
+
const left = kindOf(self);
|
|
67
|
+
const right = kindOf(that);
|
|
68
|
+
if (left !== right)
|
|
69
|
+
return Order.Number(left, right);
|
|
70
|
+
const same = kinds[left];
|
|
71
|
+
return same === undefined ? 0 : same.order(self, that);
|
|
72
|
+
});
|
|
73
|
+
/** One key: its column's values in its direction, a `NULL` or absent column last in both. */
|
|
74
|
+
const byKey = (key) => {
|
|
75
|
+
const values = key.direction === "desc" ? Order.flip(byValue) : byValue;
|
|
76
|
+
return Order.make((self, that) => {
|
|
77
|
+
const left = self[key.column] ?? null;
|
|
78
|
+
const right = that[key.column] ?? null;
|
|
79
|
+
if (left === null)
|
|
80
|
+
return right === null ? 0 : 1;
|
|
81
|
+
return right === null ? -1 : values(left, right);
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
/** The closing key every list order ends with: `id` ascending, by code point. */
|
|
85
|
+
const byId = Order.mapInput(byCodePoint, (row) => row.id);
|
|
86
|
+
/**
|
|
87
|
+
* The total order a list renders as `ORDER BY <key> <direction> NULLS LAST,
|
|
88
|
+
* …, id ASC`: each key in turn, a `NULL` (or absent) column after every
|
|
89
|
+
* value in either direction, then `id` ascending, so no two rows tie.
|
|
90
|
+
*/
|
|
91
|
+
export const rowOrder = (keys) => Order.combineAll([...Array.map(keys, byKey), byId]);
|
|
92
|
+
//# sourceMappingURL=list-order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-order.js","sourceRoot":"","sources":["../../src/internal/list-order.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **The owned leaf's row reading**, shared by `./subtype` and `./edges` so
|
|
3
|
+
* the two cannot read the same view or row differently: the declared-column
|
|
4
|
+
* check (pulpit#79), the facts read off a row (pulpit#80), and the predicate
|
|
5
|
+
* over those facts, which `canViewOwned` delegates to (pulpit#85).
|
|
6
|
+
*
|
|
7
|
+
* Internal: not a package entry point (absent from `package.json`
|
|
8
|
+
* `exports`) and excluded from the generated API docs (`docgen.json`).
|
|
9
|
+
* Typed structurally, so it never imports `./subtype`.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
import * as Effect from "effect/Effect";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import { Visibility } from "../content.ts";
|
|
16
|
+
import type { ColumnValue } from "../version-chain.ts";
|
|
17
|
+
/** The owned access declaration's column names, structurally (`./subtype`'s owned `LeafAccess` fits). */
|
|
18
|
+
interface OwnedColumns {
|
|
19
|
+
readonly ownerColumn: string;
|
|
20
|
+
readonly visibilityColumn: string;
|
|
21
|
+
readonly draftColumn: Option.Option<string>;
|
|
22
|
+
readonly moderationColumn: Option.Option<string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The facts {@link canViewOwnedRow} reads off an owned row: `./subtype`'s
|
|
26
|
+
* `OwnedFacts`, except that the owner may be absent. A row whose owner
|
|
27
|
+
* column holds no string has no owner (pulpit#85).
|
|
28
|
+
*/
|
|
29
|
+
interface OwnedRowFacts {
|
|
30
|
+
readonly ownerId: Option.Option<string>;
|
|
31
|
+
readonly visibility: Visibility;
|
|
32
|
+
readonly draft: boolean;
|
|
33
|
+
/** Under review or rejected: a moderated row whose state is not exactly `approved` (pulpit#154). */
|
|
34
|
+
readonly unapproved: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** The parts of `./subtype`'s viewer, policy and follower seam the predicate reads, structurally. */
|
|
37
|
+
interface Account {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
}
|
|
40
|
+
interface PrivateRung<A> {
|
|
41
|
+
readonly canViewPrivate: (account: A) => boolean;
|
|
42
|
+
}
|
|
43
|
+
interface IsFollower<R> {
|
|
44
|
+
readonly isFollower: (followerId: string, ownerId: string) => Effect.Effect<boolean, never, R>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Whether the view carries every column an owned leaf declares (owner,
|
|
48
|
+
* visibility and, when declared, draft and moderation state). An owned leaf whose view lacks one
|
|
49
|
+
* reads no row: `ownedListFilter` lists nothing, and `defineSubtype`'s
|
|
50
|
+
* `get` / `getMany` and `./edges`' `canViewEndpoint` show nothing. Fail
|
|
51
|
+
* closed (`SEC-AUTH-ENUM-001`). Never throws.
|
|
52
|
+
*
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
export declare const declaresColumns: (access: OwnedColumns, viewColumns: ReadonlySet<string>) => boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Read an owned row's facts for `canViewOwned`, in `defineSubtype`'s
|
|
58
|
+
* `get` / `getMany` and `./edges`' `canViewEndpoint`. Each reading fails
|
|
59
|
+
* closed where `ownedListFilter` does (`SEC-AUTH-ENUM-001`): a visibility
|
|
60
|
+
* outside the enum (a dropped projection, a schema drift) reads as
|
|
61
|
+
* `private`, since the filter's `eq(visibility, "public")` arm lists only
|
|
62
|
+
* `public`; a draft column holding anything but an explicit `false` (a
|
|
63
|
+
* `NULL`, an absent key, a value outside the type) reads as a draft, since
|
|
64
|
+
* its `eq(draft, false)` arms list only `false`. A leaf without the draft
|
|
65
|
+
* axis reads `draft: false`. A moderation column holding anything but
|
|
66
|
+
* exactly `"approved"` reads as unapproved, since the filter's
|
|
67
|
+
* `eq(moderation, "approved")` arms list only `approved`; a leaf without the
|
|
68
|
+
* axis reads `unapproved: false`. An owner column holding anything but a string
|
|
69
|
+
* (a `NULL`, an absent key, a value outside the type) reads as no owner,
|
|
70
|
+
* never as its `String` form (pulpit#85; see pulpit#75): its `eq(owner, …)`
|
|
71
|
+
* and `in(owner, following)` arms match no `NULL`. Callers check
|
|
72
|
+
* {@link declaresColumns} first. Never throws.
|
|
73
|
+
*
|
|
74
|
+
* @internal
|
|
75
|
+
*/
|
|
76
|
+
export declare const ownedFacts: (access: OwnedColumns, row: {
|
|
77
|
+
readonly [column: string]: ColumnValue;
|
|
78
|
+
}) => OwnedRowFacts;
|
|
79
|
+
/**
|
|
80
|
+
* The owned-material read predicate over {@link ownedFacts}: `canViewOwned`
|
|
81
|
+
* in `./subtype` is this with a present owner, and `defineSubtype`'s
|
|
82
|
+
* `get` / `getMany` and `./edges`' `canViewEndpoint` call it directly. A
|
|
83
|
+
* row with no owner skips the owner arm and the follower check, so no
|
|
84
|
+
* viewer's id matches it and the follower seam is never asked about it:
|
|
85
|
+
* it is visible only when it is `public`, not a draft and not unapproved, or to the
|
|
86
|
+
* view-private rung, as `ownedListFilter` lists it (`SEC-AUTH-ENUM-001`).
|
|
87
|
+
* Never fails.
|
|
88
|
+
*
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
export declare const canViewOwnedRow: <A extends Account, R>(viewer: Option.Option<A>, policy: PrivateRung<A>, followers: IsFollower<R>, row: OwnedRowFacts) => Effect.Effect<boolean, never, R>;
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=owned-columns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-columns.d.ts","sourceRoot":"","sources":["../../src/internal/owned-columns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,yGAAyG;AACzG,UAAU,YAAY;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;CAClD;AAED;;;;GAIG;AACH,UAAU,aAAa;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,oGAAoG;IACpG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,qGAAqG;AACrG,UAAU,OAAO;IACf,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AACD,UAAU,WAAW,CAAC,CAAC;IACrB,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC;CAClD;AACD,UAAU,UAAU,CAAC,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;CAChG;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,WAAY,YAAY,eAAe,WAAW,CAAC,MAAM,CAAC,KAAG,OAM3C,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,UAAU,WACb,YAAY,OACf;IAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,KAC9C,aAcD,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,OAAO,EAAE,CAAC,UAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAChB,WAAW,CAAC,CAAC,CAAC,aACX,UAAU,CAAC,CAAC,CAAC,OACnB,aAAa,KACjB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAajC,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **The owned leaf's row reading**, shared by `./subtype` and `./edges` so
|
|
3
|
+
* the two cannot read the same view or row differently: the declared-column
|
|
4
|
+
* check (pulpit#79), the facts read off a row (pulpit#80), and the predicate
|
|
5
|
+
* over those facts, which `canViewOwned` delegates to (pulpit#85).
|
|
6
|
+
*
|
|
7
|
+
* Internal: not a package entry point (absent from `package.json`
|
|
8
|
+
* `exports`) and excluded from the generated API docs (`docgen.json`).
|
|
9
|
+
* Typed structurally, so it never imports `./subtype`.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
import * as Effect from "effect/Effect";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import * as Predicate from "effect/Predicate";
|
|
16
|
+
import * as Schema from "effect/Schema";
|
|
17
|
+
import { Visibility } from "../content.js";
|
|
18
|
+
const isVisibility = Schema.is(Visibility);
|
|
19
|
+
/**
|
|
20
|
+
* Whether the view carries every column an owned leaf declares (owner,
|
|
21
|
+
* visibility and, when declared, draft and moderation state). An owned leaf whose view lacks one
|
|
22
|
+
* reads no row: `ownedListFilter` lists nothing, and `defineSubtype`'s
|
|
23
|
+
* `get` / `getMany` and `./edges`' `canViewEndpoint` show nothing. Fail
|
|
24
|
+
* closed (`SEC-AUTH-ENUM-001`). Never throws.
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export const declaresColumns = (access, viewColumns) => [
|
|
29
|
+
access.ownerColumn,
|
|
30
|
+
access.visibilityColumn,
|
|
31
|
+
...Option.toArray(access.draftColumn),
|
|
32
|
+
...Option.toArray(access.moderationColumn),
|
|
33
|
+
].every((column) => viewColumns.has(column));
|
|
34
|
+
/**
|
|
35
|
+
* Read an owned row's facts for `canViewOwned`, in `defineSubtype`'s
|
|
36
|
+
* `get` / `getMany` and `./edges`' `canViewEndpoint`. Each reading fails
|
|
37
|
+
* closed where `ownedListFilter` does (`SEC-AUTH-ENUM-001`): a visibility
|
|
38
|
+
* outside the enum (a dropped projection, a schema drift) reads as
|
|
39
|
+
* `private`, since the filter's `eq(visibility, "public")` arm lists only
|
|
40
|
+
* `public`; a draft column holding anything but an explicit `false` (a
|
|
41
|
+
* `NULL`, an absent key, a value outside the type) reads as a draft, since
|
|
42
|
+
* its `eq(draft, false)` arms list only `false`. A leaf without the draft
|
|
43
|
+
* axis reads `draft: false`. A moderation column holding anything but
|
|
44
|
+
* exactly `"approved"` reads as unapproved, since the filter's
|
|
45
|
+
* `eq(moderation, "approved")` arms list only `approved`; a leaf without the
|
|
46
|
+
* axis reads `unapproved: false`. An owner column holding anything but a string
|
|
47
|
+
* (a `NULL`, an absent key, a value outside the type) reads as no owner,
|
|
48
|
+
* never as its `String` form (pulpit#85; see pulpit#75): its `eq(owner, …)`
|
|
49
|
+
* and `in(owner, following)` arms match no `NULL`. Callers check
|
|
50
|
+
* {@link declaresColumns} first. Never throws.
|
|
51
|
+
*
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export const ownedFacts = (access, row) => ({
|
|
55
|
+
ownerId: Option.liftPredicate(row[access.ownerColumn], Predicate.isString),
|
|
56
|
+
visibility: Option.getOrElse(Option.liftPredicate(row[access.visibilityColumn], isVisibility), () => "private"),
|
|
57
|
+
draft: Option.match(access.draftColumn, {
|
|
58
|
+
onNone: () => false,
|
|
59
|
+
onSome: (column) => row[column] !== false,
|
|
60
|
+
}),
|
|
61
|
+
unapproved: Option.match(access.moderationColumn, {
|
|
62
|
+
onNone: () => false,
|
|
63
|
+
onSome: (column) => row[column] !== "approved",
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* The owned-material read predicate over {@link ownedFacts}: `canViewOwned`
|
|
68
|
+
* in `./subtype` is this with a present owner, and `defineSubtype`'s
|
|
69
|
+
* `get` / `getMany` and `./edges`' `canViewEndpoint` call it directly. A
|
|
70
|
+
* row with no owner skips the owner arm and the follower check, so no
|
|
71
|
+
* viewer's id matches it and the follower seam is never asked about it:
|
|
72
|
+
* it is visible only when it is `public`, not a draft and not unapproved, or to the
|
|
73
|
+
* view-private rung, as `ownedListFilter` lists it (`SEC-AUTH-ENUM-001`).
|
|
74
|
+
* Never fails.
|
|
75
|
+
*
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
export const canViewOwnedRow = (viewer, policy, followers, row) => {
|
|
79
|
+
if (!row.draft && !row.unapproved && row.visibility === "public")
|
|
80
|
+
return Effect.succeed(true);
|
|
81
|
+
if (Option.isNone(viewer))
|
|
82
|
+
return Effect.succeed(false);
|
|
83
|
+
const account = viewer.value;
|
|
84
|
+
if (Option.contains(row.ownerId, account.id))
|
|
85
|
+
return Effect.succeed(true);
|
|
86
|
+
if (policy.canViewPrivate(account))
|
|
87
|
+
return Effect.succeed(true);
|
|
88
|
+
// Not the owner, not privileged: a draft, or a row not approved, is hidden whatever its visibility.
|
|
89
|
+
if (row.draft || row.unapproved)
|
|
90
|
+
return Effect.succeed(false);
|
|
91
|
+
if (row.visibility === "private")
|
|
92
|
+
return Effect.succeed(false);
|
|
93
|
+
return Option.match(row.ownerId, {
|
|
94
|
+
onNone: () => Effect.succeed(false),
|
|
95
|
+
onSome: (ownerId) => followers.isFollower(account.id, ownerId),
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=owned-columns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-columns.js","sourceRoot":"","sources":["../../src/internal/owned-columns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pieces `./proposals` and `./moderation`'s reports share: both are
|
|
3
|
+
* plain-row families (not nodes) with a sign-in gate, a write clock and a
|
|
4
|
+
* page query narrowed to one leaf type, an optional target and an
|
|
5
|
+
* optional status.
|
|
6
|
+
*
|
|
7
|
+
* @module pulpit/internal/plain-rows
|
|
8
|
+
*/
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Option from "effect/Option";
|
|
11
|
+
import { type ListFilter } from "../filter.ts";
|
|
12
|
+
import { Unauthorized, type Viewer, type ViewerAccount } from "../subtype.ts";
|
|
13
|
+
/** The write clock: the current instant, as the `Date` a row stores. */
|
|
14
|
+
export declare const nowDate: Effect.Effect<Date>;
|
|
15
|
+
/** The signed-in account, or `Unauthorized`. */
|
|
16
|
+
export declare const signedIn: <R>(viewer: Effect.Effect<Viewer, never, R>) => Effect.Effect<ViewerAccount, Unauthorized, R>;
|
|
17
|
+
/**
|
|
18
|
+
* A list request's store query: the leaf's rows under the viewer's `scope`,
|
|
19
|
+
* narrowed by target and status when asked, the page clamped to
|
|
20
|
+
* `MAX_PAGE_LIMIT` (`SEC-INPUT-003`).
|
|
21
|
+
*/
|
|
22
|
+
export declare const plainRowQuery: <Status extends string>(type: string, scope: ListFilter<never>, request: {
|
|
23
|
+
readonly targetId: Option.Option<string>;
|
|
24
|
+
readonly status: Option.Option<Status>;
|
|
25
|
+
readonly limit: number;
|
|
26
|
+
readonly offset: number;
|
|
27
|
+
}) => {
|
|
28
|
+
where: ListFilter<never>;
|
|
29
|
+
limit: number;
|
|
30
|
+
offset: number;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=plain-rows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-rows.d.ts","sourceRoot":"","sources":["../../src/internal/plain-rows.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAkB,YAAY,EAAE,KAAK,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9F,wEAAwE;AACxE,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAEvC,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,QAAQ,GAAI,CAAC,UAChB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,KACtC,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,YAAY,EAAE,CAAC,CAC4C,CAAC;AAE5F;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,MAAM,QAC3C,MAAM,SACL,UAAU,CAAC,KAAK,CAAC,WACf;IACP,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;IAED,KAAK;IASL,KAAK;IACL,MAAM;CACN,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pieces `./proposals` and `./moderation`'s reports share: both are
|
|
3
|
+
* plain-row families (not nodes) with a sign-in gate, a write clock and a
|
|
4
|
+
* page query narrowed to one leaf type, an optional target and an
|
|
5
|
+
* optional status.
|
|
6
|
+
*
|
|
7
|
+
* @module pulpit/internal/plain-rows
|
|
8
|
+
*/
|
|
9
|
+
import * as Clock from "effect/Clock";
|
|
10
|
+
import * as DateTime from "effect/DateTime";
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Option from "effect/Option";
|
|
13
|
+
import { always, and, eq } from "../filter.js";
|
|
14
|
+
import { MAX_PAGE_LIMIT, Unauthorized } from "../subtype.js";
|
|
15
|
+
/** The write clock: the current instant, as the `Date` a row stores. */
|
|
16
|
+
export const nowDate = Effect.map(Clock.currentTimeMillis, (millis) => DateTime.toDate(DateTime.makeUnsafe(millis)));
|
|
17
|
+
/** The signed-in account, or `Unauthorized`. */
|
|
18
|
+
export const signedIn = (viewer) => Effect.flatMap(viewer, (account) => Effect.fromOption(account, () => new Unauthorized()));
|
|
19
|
+
/**
|
|
20
|
+
* A list request's store query: the leaf's rows under the viewer's `scope`,
|
|
21
|
+
* narrowed by target and status when asked, the page clamped to
|
|
22
|
+
* `MAX_PAGE_LIMIT` (`SEC-INPUT-003`).
|
|
23
|
+
*/
|
|
24
|
+
export const plainRowQuery = (type, scope, request) => ({
|
|
25
|
+
where: and(eq("targetType", type), scope, Option.match(request.targetId, { onNone: () => always, onSome: (id) => eq("targetId", id) }), Option.match(request.status, {
|
|
26
|
+
onNone: () => always,
|
|
27
|
+
onSome: (status) => eq("status", status),
|
|
28
|
+
})),
|
|
29
|
+
limit: Math.max(1, Math.min(Math.trunc(request.limit), MAX_PAGE_LIMIT)),
|
|
30
|
+
offset: Math.max(0, Math.trunc(request.offset)),
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=plain-rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-rows.js","sourceRoot":"","sources":["../../src/internal/plain-rows.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAmB,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAmC,MAAM,eAAe,CAAC;AAE9F,wEAAwE;AACxE,MAAM,CAAC,MAAM,OAAO,GAAwB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,EAAE,CACzF,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAC7C,CAAC;AAEF,gDAAgD;AAChD,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,MAAuC,EACQ,EAAE,CACjD,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC;AAE5F;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,IAAY,EACZ,KAAwB,EACxB,OAKC,EACD,EAAE,CAAC,CAAC;IACJ,KAAK,EAAE,GAAG,CACR,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EACtB,KAAK,EACL,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAC5F,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE;QAC3B,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM;QACpB,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;KACzC,CAAC,CACH;IACD,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,CAAC;IACvE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;CAChD,CAAC,CAAC"}
|