@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
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Suggested edits (proposals)** — a contributor's patch against a node
|
|
3
|
+
* they can read, stamped with the version it was written against, which
|
|
4
|
+
* the node's writer accepts (appending it) or rejects.
|
|
5
|
+
*
|
|
6
|
+
* The behavioural spec is gardeneria's `apps/api/src/operations/proposals.ts`,
|
|
7
|
+
* `proposal-patch.ts` and `proposal-conflict.ts` (#565), with their tests; a
|
|
8
|
+
* `#NNN` here names a gardeneria issue.
|
|
9
|
+
*
|
|
10
|
+
* ## The model (owner decisions on pulpit#49)
|
|
11
|
+
*
|
|
12
|
+
* - **A proposal is a plain row, not a node.** It carries the target, the
|
|
13
|
+
* patch as submitted, the `baseVersion` it was written against (stamped
|
|
14
|
+
* from the target's head, never client-supplied), its status (`pending |
|
|
15
|
+
* accepted | rejected | withdrawn`), the reviewer and the timestamps.
|
|
16
|
+
* Rejecting or withdrawing changes its status; only accepting writes to
|
|
17
|
+
* the target.
|
|
18
|
+
* - **Accepting appends through the target's own `update`** (`PUB-003`), as
|
|
19
|
+
* the account that accepted, so it runs the target's gate, its precondition
|
|
20
|
+
* and its before hooks, and lands as an ordinary `update` version
|
|
21
|
+
* (`VERSION-CHAIN-001/002`). The version records the proposer as its
|
|
22
|
+
* `proposedBy` fact beside that actor, so history shows both.
|
|
23
|
+
*
|
|
24
|
+
* ## Classification, in two tiers (#565, decision 2)
|
|
25
|
+
*
|
|
26
|
+
* - {@link classifyProposalBase} — `clean` or `moved`, from two version
|
|
27
|
+
* numbers in hand: no read, safe for every row of a list page.
|
|
28
|
+
* - {@link classifyProposalConflict} — `clean`, `stale` or `conflicting`,
|
|
29
|
+
* from the target's states at the base version and at the head
|
|
30
|
+
* (`diffStates`): two version reads, so only {@link ProposalOps.review}
|
|
31
|
+
* and {@link ProposalOps.accept} run it (`PERF-DB-003`).
|
|
32
|
+
*
|
|
33
|
+
* A touched attribute either state lacks (one kept in a side table, outside
|
|
34
|
+
* the chain) cannot be compared, so on a moved target it counts as
|
|
35
|
+
* conflicting: fail closed, since `stale` would let an accept overwrite a
|
|
36
|
+
* change nobody looked at.
|
|
37
|
+
*
|
|
38
|
+
* ## The gates
|
|
39
|
+
*
|
|
40
|
+
* - **Submit:** a signed-in account at the application's propose rung
|
|
41
|
+
* ({@link ProposalsDefinition.canPropose}) that can `get` the target; a
|
|
42
|
+
* target it can't read fails `NodeNotFound`, never `Forbidden`
|
|
43
|
+
* (`SEC-AUTH-ENUM-001`).
|
|
44
|
+
* - **Accept / reject / review:** the target's write gate (`requireWriter`:
|
|
45
|
+
* owner-or-moderator on an owned leaf, the corpus-write rung on a reference
|
|
46
|
+
* one), before the proposal's status is disclosed. Accept and review then
|
|
47
|
+
* read the two versions through the target's gated `compare` (`READ-009`).
|
|
48
|
+
* - **Withdraw:** the proposal's own author, while it is pending.
|
|
49
|
+
* - **Reads:** the moderate rung reads every proposal; any other signed-in
|
|
50
|
+
* account reads its own and those on targets it owns; the anonymous read
|
|
51
|
+
* none. A proposal is never public.
|
|
52
|
+
*
|
|
53
|
+
* ## A localised leaf (pulpit#184)
|
|
54
|
+
*
|
|
55
|
+
* On a leaf with a locale level (pulpit#56) a proposal may also carry a
|
|
56
|
+
* per-locale patch over the leaf's translated columns
|
|
57
|
+
* ({@link ProposalsDefinition.localeAttributes}), stored beside its shared
|
|
58
|
+
* patch and accepted through the same `update` as one version. Its conflict
|
|
59
|
+
* check reads each touched locale at the base and at the head: a touched
|
|
60
|
+
* translated column conflicts when it changed, when either version lacks it,
|
|
61
|
+
* or when the locale was added or dropped in between. A proposal may add a
|
|
62
|
+
* translation but never drop one (a `null` locale is refused): removing a
|
|
63
|
+
* locale is the owner's.
|
|
64
|
+
*
|
|
65
|
+
* A write budget (pulpit#199) is an opt-in: `budget` throttles `submit`.
|
|
66
|
+
* Notifications and the wire shape are the application's.
|
|
67
|
+
*
|
|
68
|
+
* @copyright Thomas Foster
|
|
69
|
+
* @module pulpit/proposals
|
|
70
|
+
* @since 0.1.0
|
|
71
|
+
*/
|
|
72
|
+
import * as Effect from "effect/Effect";
|
|
73
|
+
import * as Option from "effect/Option";
|
|
74
|
+
import * as Schema from "effect/Schema";
|
|
75
|
+
import type { BoundBudget } from "./budgets.ts";
|
|
76
|
+
import { type ListFilter } from "./filter.ts";
|
|
77
|
+
import { Forbidden, Unauthorized, type AccessPolicy, type Page, type SubtypeOps, type Viewer, type ViewerAccount, type WriteRejected } from "./subtype.ts";
|
|
78
|
+
import { NodeNotFound, type ChainPatch, type LocalePatch, type ChainWrite, type StaleVersion, type VersionChainStore, type VersionConflict, type VersionNotFound, type VersionSnapshot } from "./version-chain.ts";
|
|
79
|
+
/**
|
|
80
|
+
* A proposal's status. `pending` is the only open one; the other three are
|
|
81
|
+
* terminal, and a withdrawn proposal is recorded, not deleted.
|
|
82
|
+
*
|
|
83
|
+
* @since 0.1.0
|
|
84
|
+
*/
|
|
85
|
+
export declare const ProposalStatus: Schema.Literals<readonly ["pending", "accepted", "rejected", "withdrawn"]>;
|
|
86
|
+
/**
|
|
87
|
+
* The {@link ProposalStatus} literal union.
|
|
88
|
+
*
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
*/
|
|
91
|
+
export type ProposalStatus = typeof ProposalStatus.Type;
|
|
92
|
+
/**
|
|
93
|
+
* The cheap verdict: `moved` means "stale or conflicting, not yet told
|
|
94
|
+
* apart", never a claim that the patch still applies.
|
|
95
|
+
*
|
|
96
|
+
* @since 0.1.0
|
|
97
|
+
*/
|
|
98
|
+
export type ProposalBaseState = "clean" | "moved";
|
|
99
|
+
/**
|
|
100
|
+
* The full verdict: `clean` (the target has not moved), `stale` (it moved,
|
|
101
|
+
* but no touched attribute changed) or `conflicting`.
|
|
102
|
+
*
|
|
103
|
+
* @since 0.1.0
|
|
104
|
+
*/
|
|
105
|
+
export type ProposalConflictState = "clean" | "stale" | "conflicting";
|
|
106
|
+
/**
|
|
107
|
+
* One proposal row, as the {@link ProposalStore} keeps it.
|
|
108
|
+
*
|
|
109
|
+
* @since 0.1.0
|
|
110
|
+
*/
|
|
111
|
+
export interface ProposalRow {
|
|
112
|
+
readonly id: string;
|
|
113
|
+
/** The target node and its leaf type. */
|
|
114
|
+
readonly targetId: string;
|
|
115
|
+
readonly targetType: string;
|
|
116
|
+
/** The proposer. */
|
|
117
|
+
readonly authorId: string;
|
|
118
|
+
/** The patch as submitted (what the reviewer reads), decoded again at accept. */
|
|
119
|
+
readonly patch: Schema.Json;
|
|
120
|
+
/**
|
|
121
|
+
* A localised leaf's per-locale patch as submitted (pulpit#184), decoded
|
|
122
|
+
* again at accept; none for a proposal that touches no translation.
|
|
123
|
+
*/
|
|
124
|
+
readonly locales: Option.Option<Schema.Json>;
|
|
125
|
+
readonly rationale: Option.Option<string>;
|
|
126
|
+
/** The target's head when the proposal was submitted. */
|
|
127
|
+
readonly baseVersion: bigint;
|
|
128
|
+
readonly status: ProposalStatus;
|
|
129
|
+
readonly submittedAt: Date;
|
|
130
|
+
/** When, and by whom, it left `pending` (the author, for a withdrawal). */
|
|
131
|
+
readonly decidedAt: Option.Option<Date>;
|
|
132
|
+
readonly decidedBy: Option.Option<string>;
|
|
133
|
+
readonly decisionNote: Option.Option<string>;
|
|
134
|
+
/** The version an accepted proposal produced: its provenance pointer. */
|
|
135
|
+
readonly appliedVersion: Option.Option<bigint>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* A proposal row as a read returns it, with the target's head version (none
|
|
139
|
+
* when the target has no versions), read in the same query.
|
|
140
|
+
*
|
|
141
|
+
* @since 0.1.0
|
|
142
|
+
*/
|
|
143
|
+
export interface ProposalListing {
|
|
144
|
+
readonly row: ProposalRow;
|
|
145
|
+
readonly targetVersion: Option.Option<bigint>;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The write that closes a pending proposal.
|
|
149
|
+
*
|
|
150
|
+
* @since 0.1.0
|
|
151
|
+
*/
|
|
152
|
+
export interface ProposalDecision {
|
|
153
|
+
readonly status: Exclude<ProposalStatus, "pending">;
|
|
154
|
+
readonly decidedAt: Date;
|
|
155
|
+
readonly decidedBy: string;
|
|
156
|
+
readonly decisionNote: Option.Option<string>;
|
|
157
|
+
readonly appliedVersion: Option.Option<bigint>;
|
|
158
|
+
}
|
|
159
|
+
declare const ProposalNotFound_base: Schema.Class<ProposalNotFound, Schema.TaggedStruct<"ProposalNotFound", {
|
|
160
|
+
readonly id: Schema.String;
|
|
161
|
+
}>, import("effect/Cause").YieldableError & {
|
|
162
|
+
readonly brand: unique symbol;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* No proposal at that id that the viewer may read: the wire's 404.
|
|
166
|
+
*
|
|
167
|
+
* @since 0.1.0
|
|
168
|
+
*/
|
|
169
|
+
export declare class ProposalNotFound extends ProposalNotFound_base {
|
|
170
|
+
}
|
|
171
|
+
declare const ProposalClosed_base: Schema.Class<ProposalClosed, Schema.TaggedStruct<"ProposalClosed", {
|
|
172
|
+
readonly id: Schema.String;
|
|
173
|
+
readonly status: Schema.Literals<readonly ["pending", "accepted", "rejected", "withdrawn"]>;
|
|
174
|
+
}>, import("effect/Cause").YieldableError & {
|
|
175
|
+
readonly brand: unique symbol;
|
|
176
|
+
}>;
|
|
177
|
+
/**
|
|
178
|
+
* The proposal is no longer pending, so it can't be decided or withdrawn
|
|
179
|
+
* again: the wire's 409.
|
|
180
|
+
*
|
|
181
|
+
* @since 0.1.0
|
|
182
|
+
*/
|
|
183
|
+
export declare class ProposalClosed extends ProposalClosed_base {
|
|
184
|
+
}
|
|
185
|
+
declare const ProposalConflict_base: Schema.Class<ProposalConflict, Schema.TaggedStruct<"ProposalConflict", {
|
|
186
|
+
readonly id: Schema.String;
|
|
187
|
+
readonly attributes: Schema.$Array<Schema.String>;
|
|
188
|
+
/** The conflicting translated columns, by locale (pulpit#184); `{}` when none. */
|
|
189
|
+
readonly locales: Schema.$Record<Schema.String, Schema.$Array<Schema.String>>;
|
|
190
|
+
}>, import("effect/Cause").YieldableError & {
|
|
191
|
+
readonly brand: unique symbol;
|
|
192
|
+
}>;
|
|
193
|
+
/**
|
|
194
|
+
* The target changed underneath a touched attribute since the proposal was
|
|
195
|
+
* written (or one can't be compared), so accepting would overwrite an edit
|
|
196
|
+
* the reviewer never saw: the wire's 409. Reject it and resubmit against
|
|
197
|
+
* the new head.
|
|
198
|
+
*
|
|
199
|
+
* @since 0.1.0
|
|
200
|
+
*/
|
|
201
|
+
export declare class ProposalConflict extends ProposalConflict_base {
|
|
202
|
+
}
|
|
203
|
+
declare const InvalidProposalPatch_base: Schema.Class<InvalidProposalPatch, Schema.TaggedStruct<"InvalidProposalPatch", {
|
|
204
|
+
readonly type: Schema.String;
|
|
205
|
+
readonly reason: Schema.String;
|
|
206
|
+
}>, import("effect/Cause").YieldableError & {
|
|
207
|
+
readonly brand: unique symbol;
|
|
208
|
+
}>;
|
|
209
|
+
/**
|
|
210
|
+
* A patch that can't be proposed: not an object, empty, touching a
|
|
211
|
+
* forbidden or unknown attribute, or refused by the leaf's decoder. The
|
|
212
|
+
* wire's 422.
|
|
213
|
+
*
|
|
214
|
+
* @since 0.1.0
|
|
215
|
+
*/
|
|
216
|
+
export declare class InvalidProposalPatch extends InvalidProposalPatch_base {
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The cheap verdict, from the base version and the target's head: `clean`
|
|
220
|
+
* only when they are equal.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* import { strictEqual } from "node:assert";
|
|
225
|
+
* import { classifyProposalBase } from "@thomasfosterau/pulpit/proposals";
|
|
226
|
+
*
|
|
227
|
+
* strictEqual(classifyProposalBase(4n, 4n), "clean");
|
|
228
|
+
* strictEqual(classifyProposalBase(4n, 5n), "moved");
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* @since 0.1.0
|
|
232
|
+
*/
|
|
233
|
+
export declare const classifyProposalBase: (baseVersion: bigint, currentVersion: bigint) => ProposalBaseState;
|
|
234
|
+
/**
|
|
235
|
+
* The full verdict, and the attributes responsible for it.
|
|
236
|
+
*
|
|
237
|
+
* @since 0.1.0
|
|
238
|
+
*/
|
|
239
|
+
export interface ProposalConflictVerdict {
|
|
240
|
+
readonly state: ProposalConflictState;
|
|
241
|
+
/** The touched attributes that changed or can't be compared; empty unless `conflicting`. */
|
|
242
|
+
readonly conflictingAttributes: ReadonlyArray<string>;
|
|
243
|
+
/**
|
|
244
|
+
* The touched translated columns that changed or can't be compared, by
|
|
245
|
+
* locale (pulpit#184); a locale with none is omitted, so it is `{}` unless
|
|
246
|
+
* `conflicting`.
|
|
247
|
+
*/
|
|
248
|
+
readonly conflictingLocales: TouchedLocales;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* The translated columns a proposal touches, by locale (pulpit#184).
|
|
252
|
+
*
|
|
253
|
+
* @since 0.1.0
|
|
254
|
+
*/
|
|
255
|
+
export type TouchedLocales = {
|
|
256
|
+
readonly [locale: string]: ReadonlyArray<string>;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* The full verdict from the target's states at the base version and at the
|
|
260
|
+
* head, over the attributes the patch touches. Equal versions are `clean`
|
|
261
|
+
* without comparing anything. Otherwise a touched attribute conflicts when
|
|
262
|
+
* `diffStates` reports it changed (values compare structurally: a document
|
|
263
|
+
* by content, `null` against a value is a change, two `null`s are not) or
|
|
264
|
+
* when either state lacks it (fail closed).
|
|
265
|
+
*
|
|
266
|
+
* On a localised leaf, `touchedLocales` names the translated columns the
|
|
267
|
+
* proposal touches, by locale (pulpit#184), and each is read from the two
|
|
268
|
+
* versions' locale levels the same way. A locale neither version carries
|
|
269
|
+
* cannot conflict (a new translation); a locale only one carries (added or
|
|
270
|
+
* dropped in between) conflicts on every touched column. Pure.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```ts
|
|
274
|
+
* import { deepStrictEqual } from "node:assert";
|
|
275
|
+
* import { classifyProposalConflict } from "@thomasfosterau/pulpit/proposals";
|
|
276
|
+
*
|
|
277
|
+
* const at = (version: bigint, state: { readonly [column: string]: string }) => ({
|
|
278
|
+
* version,
|
|
279
|
+
* action: "update" as const,
|
|
280
|
+
* timestamp: new Date(0),
|
|
281
|
+
* state,
|
|
282
|
+
* });
|
|
283
|
+
* deepStrictEqual(
|
|
284
|
+
* classifyProposalConflict(at(4n, { name: "a", note: "x" }), at(5n, { name: "b", note: "x" }), [
|
|
285
|
+
* "name",
|
|
286
|
+
* "note",
|
|
287
|
+
* ]),
|
|
288
|
+
* { state: "conflicting", conflictingAttributes: ["name"], conflictingLocales: {} },
|
|
289
|
+
* );
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @since 0.1.0
|
|
293
|
+
*/
|
|
294
|
+
export declare const classifyProposalConflict: (base: VersionSnapshot, current: VersionSnapshot, touchedKeys: ReadonlyArray<string>, touchedLocales?: TouchedLocales) => ProposalConflictVerdict;
|
|
295
|
+
/**
|
|
296
|
+
* The attributes no proposal may carry, whatever the leaf declares:
|
|
297
|
+
* identity (`id`, `type`) and the publication axes (`visibility`, `draft`,
|
|
298
|
+
* `publishedAt`), which are the owner's to set (`PUB-005`). An application
|
|
299
|
+
* adds its own through {@link ProposalsDefinition.forbidden} (gardeneria
|
|
300
|
+
* adds `slug`, a node's public URL).
|
|
301
|
+
*
|
|
302
|
+
* @since 0.1.0
|
|
303
|
+
*/
|
|
304
|
+
export declare const PROPOSAL_FORBIDDEN_KEYS: ReadonlyArray<string>;
|
|
305
|
+
/**
|
|
306
|
+
* A patch that passed validation.
|
|
307
|
+
*
|
|
308
|
+
* @since 0.1.0
|
|
309
|
+
*/
|
|
310
|
+
export interface ValidatedPatch {
|
|
311
|
+
/** The decoded patch, ready for the target's `update`. */
|
|
312
|
+
readonly patch: ChainPatch;
|
|
313
|
+
/** The attribute names it touches, in the leaf's declaration order. */
|
|
314
|
+
readonly touchedKeys: ReadonlyArray<string>;
|
|
315
|
+
/** The decoded per-locale patch (pulpit#184), ready for the target's `update`; `{}` for none. */
|
|
316
|
+
readonly locales: LocalePatch;
|
|
317
|
+
/** The translated columns it touches, by locale, each in the declaration order. */
|
|
318
|
+
readonly touchedLocales: TouchedLocales;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Check a submitted patch's shape and keys against the leaf's proposable
|
|
322
|
+
* `attributes` (its update fields, in declaration order) and the
|
|
323
|
+
* `forbidden` keys, then decode it with the leaf's own decoder. Unknown keys
|
|
324
|
+
* are refused loudly rather than dropped (a misspelt attribute would
|
|
325
|
+
* otherwise accept and change nothing). Run at submit and again at accept,
|
|
326
|
+
* since the leaf's schema may have moved in between. Fails
|
|
327
|
+
* {@link InvalidProposalPatch}.
|
|
328
|
+
*
|
|
329
|
+
* On a localised leaf, `options.locales` is the per-locale patch as
|
|
330
|
+
* submitted (pulpit#184): an object from a non-empty locale tag to an object
|
|
331
|
+
* of changes to `options.localeAttributes` (the translated columns), each
|
|
332
|
+
* checked and decoded as the shared patch is. A `null` locale (dropping a
|
|
333
|
+
* translation) is refused, as is any locale on a leaf with no
|
|
334
|
+
* `localeAttributes`. The shared patch may then be `{}`, so long as some
|
|
335
|
+
* locale changes something.
|
|
336
|
+
*
|
|
337
|
+
* @since 0.1.0
|
|
338
|
+
*/
|
|
339
|
+
export declare const validateProposalPatch: <R>(type: string, patch: Schema.Json, options: {
|
|
340
|
+
readonly attributes: ReadonlyArray<string>;
|
|
341
|
+
readonly forbidden: ReadonlyArray<string>;
|
|
342
|
+
readonly decode: (patch: Schema.Json) => Effect.Effect<ChainPatch, InvalidProposalPatch, R>;
|
|
343
|
+
/** The per-locale patch as submitted (pulpit#184); absent, none. */
|
|
344
|
+
readonly locales?: Schema.Json | undefined;
|
|
345
|
+
/** The translated columns a proposal may touch, in declaration order; absent, none. */
|
|
346
|
+
readonly localeAttributes?: ReadonlyArray<string> | undefined;
|
|
347
|
+
}) => Effect.Effect<ValidatedPatch, InvalidProposalPatch, R>;
|
|
348
|
+
/**
|
|
349
|
+
* The proposal table an application supplies (gardeneria's
|
|
350
|
+
* `participation.proposal`). It applies no policy, never opens a
|
|
351
|
+
* transaction, and fails only with its `E`. See the package README → Seams
|
|
352
|
+
* for the expected schema.
|
|
353
|
+
*
|
|
354
|
+
* @since 0.1.0
|
|
355
|
+
*/
|
|
356
|
+
export interface ProposalStore<E, R> {
|
|
357
|
+
/** Mint a fresh proposal id (a UUID). */
|
|
358
|
+
readonly mintId: Effect.Effect<string, E, R>;
|
|
359
|
+
/** Insert a new (pending) row. */
|
|
360
|
+
readonly insert: (row: ProposalRow) => Effect.Effect<void, E, R>;
|
|
361
|
+
/** One row with its target's head version, or none. */
|
|
362
|
+
readonly get: (id: string) => Effect.Effect<Option.Option<ProposalListing>, E, R>;
|
|
363
|
+
/**
|
|
364
|
+
* One row, locked for the rest of the transaction (`SELECT … FOR
|
|
365
|
+
* UPDATE`), so two decisions on one proposal serialise and the second
|
|
366
|
+
* sees it closed.
|
|
367
|
+
*/
|
|
368
|
+
readonly lock: (id: string) => Effect.Effect<Option.Option<ProposalRow>, E, R>;
|
|
369
|
+
/** Close a pending row: write its terminal status, decider and provenance. */
|
|
370
|
+
readonly close: (id: string, decision: ProposalDecision) => Effect.Effect<void, E, R>;
|
|
371
|
+
/**
|
|
372
|
+
* The page under `where`, newest first (`submitted_at DESC, id DESC`,
|
|
373
|
+
* a total order), with the unpaged total. `where` reads the columns
|
|
374
|
+
* `authorId`, `targetId`, `targetType`, `status` and `targetOwnerId`
|
|
375
|
+
* (the target's owner, `core.node_owner`, or `NULL`).
|
|
376
|
+
*/
|
|
377
|
+
readonly list: (query: {
|
|
378
|
+
readonly where: ListFilter<never>;
|
|
379
|
+
readonly limit: number;
|
|
380
|
+
readonly offset: number;
|
|
381
|
+
}) => Effect.Effect<Page<ProposalListing>, E, R>;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* One leaf's proposal surface: its target operations, the stores, and the
|
|
385
|
+
* patch rules.
|
|
386
|
+
*
|
|
387
|
+
* @since 0.1.0
|
|
388
|
+
*/
|
|
389
|
+
export interface ProposalsDefinition<Resource, E, R> {
|
|
390
|
+
/** The target leaf's wire type: the proposals' `targetType`. */
|
|
391
|
+
readonly type: string;
|
|
392
|
+
/** The target leaf's operations: `get` gates a submission, `compare` and `update` an acceptance. */
|
|
393
|
+
readonly target: SubtypeOps<Resource, E, R>;
|
|
394
|
+
/** The target leaf's chain store, for the head a proposal is stamped with. */
|
|
395
|
+
readonly chain: VersionChainStore<E, R>;
|
|
396
|
+
/** The target's owner (its `LeafStore.ownerOf`), for the write gate and the reads. */
|
|
397
|
+
readonly ownerOf: (id: string) => Effect.Effect<Option.Option<string>, E, R>;
|
|
398
|
+
readonly proposals: ProposalStore<E, R>;
|
|
399
|
+
/** The request's viewer. */
|
|
400
|
+
readonly viewer: Effect.Effect<Viewer, never, R>;
|
|
401
|
+
readonly policy: AccessPolicy;
|
|
402
|
+
/** The rung that may propose (gardeneria: any signed-in account; website: contributor+). */
|
|
403
|
+
readonly canPropose: (account: ViewerAccount) => boolean;
|
|
404
|
+
/** The attributes a proposal may touch: the leaf's update fields, in declaration order. */
|
|
405
|
+
readonly attributes: ReadonlyArray<string>;
|
|
406
|
+
/** The keys no proposal may carry; {@link PROPOSAL_FORBIDDEN_KEYS} when omitted. */
|
|
407
|
+
readonly forbidden?: ReadonlyArray<string> | undefined;
|
|
408
|
+
/** The leaf's update decoder over a patch's values (`SEC-INPUT-001`), shared or one locale's. */
|
|
409
|
+
readonly decode: (patch: Schema.Json) => Effect.Effect<ChainPatch, InvalidProposalPatch, R>;
|
|
410
|
+
/**
|
|
411
|
+
* The translated columns a proposal may touch on a localised leaf
|
|
412
|
+
* (pulpit#184), in declaration order: the leaf's locale level's columns,
|
|
413
|
+
* or fewer. Omitted, a proposal carries no per-locale patch.
|
|
414
|
+
*/
|
|
415
|
+
readonly localeAttributes?: ReadonlyArray<string> | undefined;
|
|
416
|
+
/**
|
|
417
|
+
* A write budget on `submit` (pulpit#199, `./budgets`' `bindBudget`),
|
|
418
|
+
* spent as the `submit` action once the submission validates and before
|
|
419
|
+
* it is stored. Omitted, submissions are unthrottled.
|
|
420
|
+
*/
|
|
421
|
+
readonly budget?: BoundBudget<E, R> | undefined;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* A proposal as a read returns it: the row, and the cheap verdict while it
|
|
425
|
+
* is pending.
|
|
426
|
+
*
|
|
427
|
+
* @since 0.1.0
|
|
428
|
+
*/
|
|
429
|
+
export interface ProposalView {
|
|
430
|
+
readonly proposal: ProposalRow;
|
|
431
|
+
readonly baseState: Option.Option<ProposalBaseState>;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* A pending proposal as the review screen reads it: the full verdict too.
|
|
435
|
+
*
|
|
436
|
+
* @since 0.1.0
|
|
437
|
+
*/
|
|
438
|
+
export interface ProposalReview extends ProposalView {
|
|
439
|
+
readonly conflict: ProposalConflictVerdict;
|
|
440
|
+
}
|
|
441
|
+
type WriteGate = Unauthorized | Forbidden | NodeNotFound;
|
|
442
|
+
/**
|
|
443
|
+
* The operations {@link defineProposals} produces.
|
|
444
|
+
*
|
|
445
|
+
* @since 0.1.0
|
|
446
|
+
*/
|
|
447
|
+
export interface ProposalOps<E, R> {
|
|
448
|
+
/**
|
|
449
|
+
* Submit a pending proposal against `targetId`, stamped with its head.
|
|
450
|
+
* Fails `Unauthorized` when anonymous, `Forbidden` below the propose rung,
|
|
451
|
+
* `NodeNotFound` when the viewer can't `get` the target,
|
|
452
|
+
* {@link InvalidProposalPatch}, and `WriteRejected` (`RATE_LIMITED`) when
|
|
453
|
+
* the declared budget is spent.
|
|
454
|
+
*/
|
|
455
|
+
readonly submit: (input: {
|
|
456
|
+
readonly targetId: string;
|
|
457
|
+
readonly patch: Schema.Json;
|
|
458
|
+
/** A localised leaf's per-locale patch (pulpit#184); absent, none. */
|
|
459
|
+
readonly locales?: Schema.Json | undefined;
|
|
460
|
+
readonly rationale: Option.Option<string>;
|
|
461
|
+
}) => Effect.Effect<{
|
|
462
|
+
readonly id: string;
|
|
463
|
+
}, Unauthorized | Forbidden | NodeNotFound | InvalidProposalPatch | WriteRejected | E, R>;
|
|
464
|
+
/**
|
|
465
|
+
* One proposal the viewer may read (the moderate rung, its author, or the
|
|
466
|
+
* target's owner), with its cheap verdict while pending. Fails
|
|
467
|
+
* {@link ProposalNotFound} for a missing or unreadable one.
|
|
468
|
+
*/
|
|
469
|
+
readonly get: (id: string) => Effect.Effect<ProposalView, ProposalNotFound | E, R>;
|
|
470
|
+
/** One page of the proposals the viewer may read, newest first, optionally narrowed. */
|
|
471
|
+
readonly list: (request: {
|
|
472
|
+
readonly targetId: Option.Option<string>;
|
|
473
|
+
readonly status: Option.Option<ProposalStatus>;
|
|
474
|
+
readonly limit: number;
|
|
475
|
+
readonly offset: number;
|
|
476
|
+
}) => Effect.Effect<Page<ProposalView>, E, R>;
|
|
477
|
+
/**
|
|
478
|
+
* A pending proposal with the full verdict, behind the target's write
|
|
479
|
+
* gate and its gated `compare`. Fails `ProposalNotFound`, the gate's
|
|
480
|
+
* failures, `ProposalClosed`, `VersionNotFound`, or
|
|
481
|
+
* `InvalidProposalPatch` when the stored patch no longer validates.
|
|
482
|
+
*/
|
|
483
|
+
readonly review: (id: string) => Effect.Effect<ProposalReview, ProposalNotFound | WriteGate | ProposalClosed | VersionNotFound | InvalidProposalPatch | E, R>;
|
|
484
|
+
/**
|
|
485
|
+
* Accept a pending proposal: re-validate its patch, classify it against
|
|
486
|
+
* the head (failing {@link ProposalConflict} when conflicting), append it
|
|
487
|
+
* through the target's `update` with the head as its expected version and
|
|
488
|
+
* the author as `proposedBy`, and close it with the version it produced.
|
|
489
|
+
* Fails as `review` does, and as the target's `update` does
|
|
490
|
+
* (`StaleVersion` when the head moved after the classification;
|
|
491
|
+
* `WriteRejected` when one of its before hooks refuses the write).
|
|
492
|
+
*/
|
|
493
|
+
readonly accept: (id: string, options?: {
|
|
494
|
+
readonly note: Option.Option<string>;
|
|
495
|
+
}) => Effect.Effect<ChainWrite, ProposalNotFound | WriteGate | ProposalClosed | ProposalConflict | VersionNotFound | InvalidProposalPatch | StaleVersion | VersionConflict | WriteRejected | E, R>;
|
|
496
|
+
/**
|
|
497
|
+
* Reject a pending proposal, writing nothing to the target, behind its
|
|
498
|
+
* write gate (a proposal whose target was deleted can still be rejected).
|
|
499
|
+
* Fails `ProposalNotFound`, the gate's failures, `ProposalClosed`.
|
|
500
|
+
*/
|
|
501
|
+
readonly reject: (id: string, options?: {
|
|
502
|
+
readonly note: Option.Option<string>;
|
|
503
|
+
}) => Effect.Effect<void, ProposalNotFound | WriteGate | ProposalClosed | E, R>;
|
|
504
|
+
/**
|
|
505
|
+
* Withdraw the caller's own pending proposal. Fails `Unauthorized` when
|
|
506
|
+
* anonymous, `ProposalNotFound`, `Forbidden` for someone else's, and
|
|
507
|
+
* `ProposalClosed`.
|
|
508
|
+
*/
|
|
509
|
+
readonly withdraw: (id: string) => Effect.Effect<void, Unauthorized | ProposalNotFound | Forbidden | ProposalClosed | E, R>;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Bind one leaf's proposal operations. Every operation is traced as
|
|
513
|
+
* `${type}.proposals.<operation>`, and the writes run in the caller's
|
|
514
|
+
* transaction: an accept's append and its close commit or roll back
|
|
515
|
+
* together. An accept runs the target's `update`, so its before hooks, but
|
|
516
|
+
* not `subtypeHandlers`' write-through: an application that caches the
|
|
517
|
+
* target writes the accepted version through itself.
|
|
518
|
+
*
|
|
519
|
+
* @since 0.1.0
|
|
520
|
+
*/
|
|
521
|
+
export declare const defineProposals: <Resource, E, R>(definition: ProposalsDefinition<Resource, E, R>) => ProposalOps<E, R>;
|
|
522
|
+
export {};
|
|
523
|
+
//# sourceMappingURL=proposals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposals.d.ts","sourceRoot":"","sources":["../src/proposals.ts"],"names":[],"mappings":"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"}
|