@valbuild/server 0.120.4 → 0.122.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/CHANGELOG.md +242 -0
- package/dist/declarations/src/Service.d.ts +15 -0
- package/dist/declarations/src/ValOps.d.ts +156 -4
- package/dist/declarations/src/ValOpsFS.d.ts +16 -2
- package/dist/declarations/src/ValOpsHttp.d.ts +186 -5
- package/dist/declarations/src/ValServer.d.ts +106 -1
- package/dist/declarations/src/externalRecords.d.ts +366 -0
- package/dist/declarations/src/fixHandlers.d.ts +13 -0
- package/dist/declarations/src/history/HistoryError.d.ts +90 -0
- package/dist/declarations/src/history/types.d.ts +126 -0
- package/dist/declarations/src/index.d.ts +3 -1
- package/dist/declarations/src/tools/types.d.ts +22 -31
- package/dist/declarations/src/valServerConfig.d.ts +17 -14
- package/dist/valbuild-server.cjs.dev.js +2704 -306
- package/dist/valbuild-server.cjs.prod.js +2704 -306
- package/dist/valbuild-server.esm.js +2701 -309
- package/package.json +4 -4
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { type PatchId, type ModuleFilePath, ValModules } from "@valbuild/core";
|
|
2
2
|
import type { Patch as PatchT, ParentRef as ParentRefT } from "@valbuild/core/patch";
|
|
3
|
-
import { type AuthorId, type BaseSha, BinaryFileType, type CommitSha, GenericErrorMessage, MetadataOfType, OpsMetadata, PreparedCommit, ValOps, ValOpsOptions, WithGenericError, SaveSourceFilePatchResult, SchemaSha, OrderedPatchesMetadata, OrderedPatches, SourcesSha } from "./ValOps.js";
|
|
3
|
+
import { type AuthorId, type BaseSha, BinaryFileType, type CommitSha, GenericErrorMessage, MetadataOfType, OpsMetadata, PreparedCommit, ValOps, ValOpsOptions, WithGenericError, SaveSourceFilePatchResult, type PatchGroupMembership, SchemaSha, OrderedPatchesMetadata, OrderedPatches, SourcesSha } from "./ValOps.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import {
|
|
5
|
+
import type { HistoryError } from "./history/HistoryError.js";
|
|
6
|
+
import type { AffectedFile, StoredModuleVersion, CommitPage, CommitPatch, HistoricalCommit } from "./history/types.js";
|
|
7
|
+
import { ParentRef, ValCommit, ValDeployment, type PatchGroupT } from "@valbuild/shared/internal";
|
|
8
|
+
import { result } from "@valbuild/core/fp";
|
|
6
9
|
declare const PatchId: z.ZodString & z.ZodType<PatchId, string, z.core.$ZodTypeInternals<PatchId, string>>;
|
|
7
10
|
declare const CommitSha: z.ZodString & z.ZodType<CommitSha, string, z.core.$ZodTypeInternals<CommitSha, string>>;
|
|
8
11
|
declare const BaseSha: z.ZodString & z.ZodType<BaseSha, string, z.core.$ZodTypeInternals<BaseSha, string>>;
|
|
9
12
|
declare const AuthorId: z.ZodString & z.ZodType<AuthorId, string, z.core.$ZodTypeInternals<AuthorId, string>>;
|
|
10
13
|
declare const ModuleFilePath: z.ZodString & z.ZodType<ModuleFilePath, string, z.core.$ZodTypeInternals<ModuleFilePath, string>>;
|
|
14
|
+
export type PatchGroupMutationResult = {
|
|
15
|
+
patchIds: PatchId[];
|
|
16
|
+
status?: undefined;
|
|
17
|
+
error?: undefined;
|
|
18
|
+
} | {
|
|
19
|
+
patchIds: PatchId[];
|
|
20
|
+
status: 403 | 409 | 500;
|
|
21
|
+
error: GenericErrorMessage;
|
|
22
|
+
};
|
|
11
23
|
export declare class ValOpsHttp extends ValOps {
|
|
12
24
|
private readonly contentUrl;
|
|
13
25
|
private readonly project;
|
|
@@ -68,6 +80,10 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
68
80
|
commits: ValCommit[];
|
|
69
81
|
deployments: ValDeployment[];
|
|
70
82
|
patches: PatchId[];
|
|
83
|
+
/** Of `patches`, the ones that have shipped. See the implementation. */
|
|
84
|
+
appliedPatches: PatchId[];
|
|
85
|
+
/** The newest commit, which is the publish head. */
|
|
86
|
+
headCommitSha?: string;
|
|
71
87
|
} | {
|
|
72
88
|
type: "error";
|
|
73
89
|
error: GenericErrorMessage;
|
|
@@ -92,7 +108,120 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
92
108
|
patchIds?: PatchId[];
|
|
93
109
|
excludePatchOps: ExcludePatchOps;
|
|
94
110
|
}): Promise<ExcludePatchOps extends true ? OrderedPatchesMetadata : OrderedPatches>;
|
|
95
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Add patches to a patch group.
|
|
113
|
+
*
|
|
114
|
+
* The set arrives closed by the client — `withPatchIds` is the prefix closure
|
|
115
|
+
* over the patch sets the staged patches belong to. We forward it and do not
|
|
116
|
+
* second-guess it: deriving the closure needs the content schema, which this
|
|
117
|
+
* process does have but content.val.build does not, and having two
|
|
118
|
+
* implementations of the rule would be worse than having one.
|
|
119
|
+
*
|
|
120
|
+
* Membership rows are stamped with `coreVersion` on the content side — the
|
|
121
|
+
* same stamp the patch row carries — so which client wrote a row stays
|
|
122
|
+
* legible after the fact.
|
|
123
|
+
*/
|
|
124
|
+
stagePatches(patchGroupId: string,
|
|
125
|
+
/** What the user asked to stage. */
|
|
126
|
+
patchIds: PatchId[],
|
|
127
|
+
/**
|
|
128
|
+
* What has to come with it, because the staged patches are written on top
|
|
129
|
+
* of it.
|
|
130
|
+
*
|
|
131
|
+
* The content API stores each membership row as `explicit` or `dependency`
|
|
132
|
+
* and treats what it is not told about as a dependency. Folding the two
|
|
133
|
+
* halves into `patchIds` therefore files the patch somebody clicked as one
|
|
134
|
+
* the closure dragged in — the exact opposite of what happened, and the
|
|
135
|
+
* only record anywhere of what the author chose.
|
|
136
|
+
*/
|
|
137
|
+
withPatchIds: PatchId[],
|
|
138
|
+
/**
|
|
139
|
+
* WHO is asking, so the content API can refuse a group that is not theirs.
|
|
140
|
+
*
|
|
141
|
+
* Every call from this class carries the app's API key, which says which
|
|
142
|
+
* PROJECT is calling and nothing about which editor. Without this the
|
|
143
|
+
* content API cannot tell one of a project's editors from another, so the
|
|
144
|
+
* only check on stage and unstage is the one in `ValServer` — and anything
|
|
145
|
+
* reaching the content API by another route (an API key, a PAT) has none at
|
|
146
|
+
* all.
|
|
147
|
+
*
|
|
148
|
+
* `null` where there is no session. The content API refuses rather than
|
|
149
|
+
* treating that as a match: a group written by an api key has a null author
|
|
150
|
+
* too, and `null === null` must not read as ownership.
|
|
151
|
+
*/
|
|
152
|
+
authorId: AuthorId | null): Promise<PatchGroupMutationResult>;
|
|
153
|
+
/**
|
|
154
|
+
* Remove patches from a patch group.
|
|
155
|
+
*
|
|
156
|
+
* The set arrives closed FORWARDS by the client: unstaging a patch also
|
|
157
|
+
* unstages everything built on top of it within its patch sets, and that is
|
|
158
|
+
* what `withPatchIds` carries.
|
|
159
|
+
*/
|
|
160
|
+
unstagePatches(patchGroupId: string,
|
|
161
|
+
/** What the user asked to unstage. */
|
|
162
|
+
patchIds: PatchId[],
|
|
163
|
+
/** What has to go with it: everything built on top of it. */
|
|
164
|
+
withPatchIds: PatchId[],
|
|
165
|
+
/** See {@link stagePatches} — the content API's half of the ownership check. */
|
|
166
|
+
authorId: AuthorId | null): Promise<PatchGroupMutationResult>;
|
|
167
|
+
/**
|
|
168
|
+
* Every patch group on this branch, with what each holds.
|
|
169
|
+
*
|
|
170
|
+
* Read rather than mutated, and used to answer "which pending patches is THIS
|
|
171
|
+
* person allowed to see". A draft render that skips this shows base + every
|
|
172
|
+
* pending patch on the branch, including work other people have not
|
|
173
|
+
* published — which is what independent publish exists to prevent.
|
|
174
|
+
*
|
|
175
|
+
* A failure is an empty list rather than a throw, and the caller decides what
|
|
176
|
+
* that means. For a draft render the honest fallback is "show nothing
|
|
177
|
+
* pending" rather than "show everything": being shown your own committed
|
|
178
|
+
* content when the group lookup is down is a worse experience than being
|
|
179
|
+
* shown somebody else's unpublished draft is a bug.
|
|
180
|
+
*/
|
|
181
|
+
/**
|
|
182
|
+
* The last group lookup, and when it was made.
|
|
183
|
+
*
|
|
184
|
+
* A draft render calls `getPatchGroups` once per `fetchVal`, in series with
|
|
185
|
+
* the whole-chain fetch, and a page that calls `fetchVal` several times pays
|
|
186
|
+
* the round trip several times. Groups are per branch and change rarely, so a
|
|
187
|
+
* short window removes the multiplier without letting a stage go unseen for
|
|
188
|
+
* meaningfully longer than one render.
|
|
189
|
+
*
|
|
190
|
+
* Deliberately short. This is a read whose staleness decides whose draft
|
|
191
|
+
* content someone sees, so it is a per-request de-duplication rather than a
|
|
192
|
+
* cache: a second render a second later asks again.
|
|
193
|
+
*/
|
|
194
|
+
private patchGroupsCache;
|
|
195
|
+
getPatchGroups(options?: {
|
|
196
|
+
/**
|
|
197
|
+
* Ask the content API even if a recent answer is remembered.
|
|
198
|
+
*
|
|
199
|
+
* For the checks that DECIDE something rather than render something.
|
|
200
|
+
* `refuseUnlessOwn` reads this list to say whether a group is yours, and a
|
|
201
|
+
* group is at its youngest exactly when that matters: the first write
|
|
202
|
+
* creates it, the save response names it, and the shell flushes its queued
|
|
203
|
+
* stages immediately — well inside the cache window. Served from a list
|
|
204
|
+
* fetched before the group existed, every one of those was refused 403 and
|
|
205
|
+
* dropped, so the queue that exists to survive the post-publish window
|
|
206
|
+
* persisted nothing in the flow it was built for.
|
|
207
|
+
*
|
|
208
|
+
* Not solved by shortening the window: the cache sits on this instance,
|
|
209
|
+
* which outlives the request, so "recent" is recent for the whole server
|
|
210
|
+
* and not for one render.
|
|
211
|
+
*/
|
|
212
|
+
fresh?: boolean;
|
|
213
|
+
}): Promise<{
|
|
214
|
+
status: "ok";
|
|
215
|
+
patchGroups: PatchGroupT[];
|
|
216
|
+
} | {
|
|
217
|
+
status: "unsupported";
|
|
218
|
+
} | {
|
|
219
|
+
status: "error";
|
|
220
|
+
message: string;
|
|
221
|
+
}>;
|
|
222
|
+
private fetchPatchGroups;
|
|
223
|
+
private mutatePatchGroup;
|
|
224
|
+
protected saveSourceFilePatch(path: ModuleFilePath, patch: PatchT, patchId: PatchId, parentRef: ParentRefT, authorId: AuthorId | null, sessionId: string | null, patchGroup?: PatchGroupMembership): Promise<SaveSourceFilePatchResult>;
|
|
96
225
|
/**
|
|
97
226
|
* @deprecated For HTTP ops use direct upload instead (i.e. client should upload the files directly) since hosting platforms (Vercel) might have low limits on the size of the request body.
|
|
98
227
|
*/
|
|
@@ -108,7 +237,17 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
108
237
|
getBase64EncodedBinaryFileFromPatch(filePath: string, patchId: PatchId, remote: boolean): Promise<Buffer | null>;
|
|
109
238
|
protected getBase64EncodedBinaryFileMetadataFromPatch<T extends "file" | "image">(filePath: string, type: T, patchId: PatchId, remote: boolean): Promise<OpsMetadata<T>>;
|
|
110
239
|
protected getBinaryFileMetadata<T extends "file" | "image">(filePath: string, type: T): Promise<OpsMetadata<T>>;
|
|
111
|
-
deletePatches(patchIds: PatchId[]
|
|
240
|
+
deletePatches(patchIds: PatchId[],
|
|
241
|
+
/**
|
|
242
|
+
* Patches that are NOT deleted but must lose their group membership.
|
|
243
|
+
*
|
|
244
|
+
* Deleting a patch out of the middle of a patch set leaves every group
|
|
245
|
+
* still holding the rest with a non-prefix intersection — the patches after
|
|
246
|
+
* the hole were written against a view that had it. The content API cannot
|
|
247
|
+
* work out which those are (it has no schema), so the client sends the
|
|
248
|
+
* forward closure and it drops those memberships without deleting anything.
|
|
249
|
+
*/
|
|
250
|
+
unstagePatchIds?: PatchId[]): Promise<{
|
|
112
251
|
deleted: PatchId[];
|
|
113
252
|
errors?: undefined;
|
|
114
253
|
error?: undefined;
|
|
@@ -120,7 +259,22 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
120
259
|
errors?: undefined;
|
|
121
260
|
deleted?: undefined;
|
|
122
261
|
}>;
|
|
123
|
-
commit(prepared: PreparedCommit, message: string, committer: AuthorId, filesDirectory: string, newBranch?: string
|
|
262
|
+
commit(prepared: PreparedCommit, message: string, committer: AuthorId, filesDirectory: string, newBranch?: string,
|
|
263
|
+
/**
|
|
264
|
+
* The patch group this commit EMPTIES, if it empties one.
|
|
265
|
+
*
|
|
266
|
+
* The content API closes the group it is given — and closes it WITHOUT
|
|
267
|
+
* checking that the commit shipped all of it, so a caller that names a
|
|
268
|
+
* group still holding work takes those patches out of every group and
|
|
269
|
+
* leaves their author unable to publish them. The client therefore sends it
|
|
270
|
+
* only when the publish accounts for everything the group still holds.
|
|
271
|
+
*
|
|
272
|
+
* Omitting it is not neutral: the commit still empties the group (the
|
|
273
|
+
* content API drops applied ids from every group), but `published_at` is
|
|
274
|
+
* never set, so the id is reused across publishes instead of a new group
|
|
275
|
+
* per publish and the "already published" refusal can never fire.
|
|
276
|
+
*/
|
|
277
|
+
patchGroupId?: string): Promise<{
|
|
124
278
|
isNotFastForward?: boolean;
|
|
125
279
|
updatedFiles: string[];
|
|
126
280
|
commit: CommitSha;
|
|
@@ -130,5 +284,32 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
130
284
|
isNotFastForward?: boolean;
|
|
131
285
|
error: GenericErrorMessage;
|
|
132
286
|
}>;
|
|
287
|
+
/**
|
|
288
|
+
* One GET against the content service, parsed and Result-typed.
|
|
289
|
+
*
|
|
290
|
+
* Every history read has the same three failure modes - could not reach the
|
|
291
|
+
* service, the commit is not there, the answer was not what was expected -
|
|
292
|
+
* and each of them means something different to a caller deciding whether to
|
|
293
|
+
* offer a restore. Doing it once here is what keeps that consistent across
|
|
294
|
+
* the five endpoints.
|
|
295
|
+
*/
|
|
296
|
+
private getHistory;
|
|
297
|
+
listCommits(branch: string, options?: {
|
|
298
|
+
limit?: number;
|
|
299
|
+
cursor?: string;
|
|
300
|
+
}): Promise<result.Result<CommitPage, HistoryError>>;
|
|
301
|
+
getCommitPatches(commitSha: string): Promise<result.Result<{
|
|
302
|
+
commit: HistoricalCommit;
|
|
303
|
+
patches: CommitPatch[];
|
|
304
|
+
}, HistoryError>>;
|
|
305
|
+
getCommitModules(commitSha: string, options?: {
|
|
306
|
+
asOf?: boolean;
|
|
307
|
+
moduleFilePath?: ModuleFilePath;
|
|
308
|
+
}): Promise<result.Result<{
|
|
309
|
+
modules: StoredModuleVersion[];
|
|
310
|
+
complete: boolean;
|
|
311
|
+
}, HistoryError>>;
|
|
312
|
+
getCommitAffectedFiles(commitSha: string): Promise<result.Result<AffectedFile[], HistoryError>>;
|
|
313
|
+
getFileAtCommit(commitSha: string, filePath: string, remote: boolean): Promise<result.Result<Buffer, HistoryError>>;
|
|
133
314
|
}
|
|
134
315
|
export {};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { ValModules, ValConfig } from "@valbuild/core";
|
|
1
|
+
import { ValModules, PatchId, ModuleFilePath, ValConfig } from "@valbuild/core";
|
|
2
2
|
import { Api, ServerOf } from "@valbuild/shared/internal";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { ValOpsFS } from "./ValOpsFS.js";
|
|
5
|
+
import { CommitSha } from "./ValOps.js";
|
|
6
|
+
import { ValOpsHttp } from "./ValOpsHttp.js";
|
|
4
7
|
export type ValServerOptions = {
|
|
5
8
|
route: string;
|
|
6
9
|
valEnableRedirectUrl?: string;
|
|
@@ -33,6 +36,108 @@ export type ValServerCallbacks = {
|
|
|
33
36
|
onEnable: (success: boolean) => Promise<void>;
|
|
34
37
|
onDisable: (success: boolean) => Promise<void>;
|
|
35
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Refuse to touch a group that is not the caller's.
|
|
41
|
+
*
|
|
42
|
+
* Exported for `patchGroupOwnership.test.ts`: this is the whole of the
|
|
43
|
+
* authorization for stage and unstage, and nothing else in the process checks
|
|
44
|
+
* it, so it is worth testing as a policy rather than only through a route.
|
|
45
|
+
*
|
|
46
|
+
* `getAuth` only proves a session EXISTS; it says nothing about whose
|
|
47
|
+
* group this is. And the content API cannot decide either — every call
|
|
48
|
+
* from here carries the app's API key, not the editor's identity — so if
|
|
49
|
+
* this does not check, nothing does.
|
|
50
|
+
*
|
|
51
|
+
* `GET /patches?include_patch_groups=true` hands every editor the id and
|
|
52
|
+
* author of every open group on the branch, so without this any logged-in
|
|
53
|
+
* editor can unstage another author's patches (their next publish
|
|
54
|
+
* silently ships less) or stage into their group (it silently ships
|
|
55
|
+
* more). The 403 declared for this route in `ApiRoutes.ts` was
|
|
56
|
+
* unreachable.
|
|
57
|
+
*
|
|
58
|
+
* Fails CLOSED: if the groups cannot be read, the mutation is refused
|
|
59
|
+
* rather than allowed unverified.
|
|
60
|
+
*/
|
|
61
|
+
/**
|
|
62
|
+
* The patches a scoped draft render should apply: the caller's own group, plus
|
|
63
|
+
* everything already committed.
|
|
64
|
+
*
|
|
65
|
+
* Scoping is about PENDING work. A published patch stays in the chain with
|
|
66
|
+
* `appliedAt` set until the next deployment moves the base, and it is part of
|
|
67
|
+
* everyone's view in that window — the unscoped path applies it. Dropping it
|
|
68
|
+
* meant the moment somebody published, their own draft preview reverted the
|
|
69
|
+
* field they had just shipped, and nobody else saw it either until the deploy
|
|
70
|
+
* landed; anything written on top in that window is authored against content
|
|
71
|
+
* already stale on `main`.
|
|
72
|
+
*
|
|
73
|
+
* Keyed on `appliedAt` rather than on the group's `publishedAt`, because a
|
|
74
|
+
* PARTIAL publish leaves the group open with only some of its patches applied.
|
|
75
|
+
* Those are committed too, and no flag on the group names them.
|
|
76
|
+
*
|
|
77
|
+
* `undefined` scope is unscoped and never reaches here; an EMPTY scope is a
|
|
78
|
+
* caller holding nothing, and on a branch with nothing applied it correctly
|
|
79
|
+
* filters down to no patches, which renders base.
|
|
80
|
+
*/
|
|
81
|
+
export declare function scopedPatches<T extends {
|
|
82
|
+
patchId: PatchId;
|
|
83
|
+
appliedAt: {
|
|
84
|
+
commitSha: CommitSha;
|
|
85
|
+
} | null;
|
|
86
|
+
}>(patches: T[], ownPatchIds: PatchId[] | undefined): T[];
|
|
87
|
+
/**
|
|
88
|
+
* Which of the client's `unstagePatchIds` this server is willing to forward.
|
|
89
|
+
*
|
|
90
|
+
* The forward closure of a discard is the client's to compute — it needs the
|
|
91
|
+
* patch sets, which need the schema — and it was being forwarded verbatim. But
|
|
92
|
+
* the content API removes those memberships from EVERY group with no ownership
|
|
93
|
+
* check, so any logged-in editor could strip arbitrary patches out of any other
|
|
94
|
+
* author's group by attaching them to a delete of one of their own throwaway
|
|
95
|
+
* patches. That is the outcome the 403 on `/patch-groups` exists to prevent,
|
|
96
|
+
* reached by a different door: their next publish silently ships less.
|
|
97
|
+
*
|
|
98
|
+
* Neither server can compute the true closure, but this one can BOUND it. A
|
|
99
|
+
* patch can only be invalidated by a delete if it was written after that delete
|
|
100
|
+
* — its paths were chosen against a view that had it — and if it is in the same
|
|
101
|
+
* module, since a patch set never spans two. Anything outside those bounds was
|
|
102
|
+
* not in the closure whatever the client says, so it is dropped rather than
|
|
103
|
+
* refused: the delete is still correct, and refusing the whole request over an
|
|
104
|
+
* over-broad extra would turn a discard into an error the user cannot act on.
|
|
105
|
+
*
|
|
106
|
+
* Exported for the test. Pure, and given the chain rather than fetching it, so
|
|
107
|
+
* the ordering it depends on is visible in the test rather than mocked.
|
|
108
|
+
*/
|
|
109
|
+
export declare function boundUnstageClosure(
|
|
110
|
+
/** The pending chain, in chain order, as `fetchPatches` returns it. */
|
|
111
|
+
chain: readonly {
|
|
112
|
+
patchId: PatchId;
|
|
113
|
+
path: ModuleFilePath;
|
|
114
|
+
}[], deleted: readonly PatchId[], requested: readonly PatchId[]): PatchId[];
|
|
115
|
+
/**
|
|
116
|
+
* Which pending patches this caller may see, when they asked for "only mine".
|
|
117
|
+
*
|
|
118
|
+
* Shared by `/sources/~` and `/json`, and it has to be: a draft page renders
|
|
119
|
+
* both, so two answers to "whose work is this" put one person's half-finished
|
|
120
|
+
* edit on another person's preview through whichever route was not scoped. That
|
|
121
|
+
* is exactly what happened — `/json` applied every pending patch on the branch
|
|
122
|
+
* while the module content beside it was scoped.
|
|
123
|
+
*
|
|
124
|
+
* `undefined` means "apply everything", which is what every caller that does
|
|
125
|
+
* not ask for scoping gets and must keep getting.
|
|
126
|
+
*/
|
|
127
|
+
export declare function resolveOwnPatchScope(serverOps: ValOpsFS | ValOpsHttp, opts: {
|
|
128
|
+
/** A caller that named a list already knows what it wants. */
|
|
129
|
+
explicitPatchIds: PatchId[] | undefined;
|
|
130
|
+
ownGroupsOnly: boolean;
|
|
131
|
+
/** `undefined` where there is no session to have one. */
|
|
132
|
+
authorId: string | undefined;
|
|
133
|
+
}): Promise<{
|
|
134
|
+
ownPatchIds: PatchId[] | undefined;
|
|
135
|
+
scopeAlsoIncludesApplied: boolean;
|
|
136
|
+
}>;
|
|
137
|
+
export declare function refuseUnlessOwn(ops: ValOpsHttp, patchGroupId: string, authorId: string): Promise<{
|
|
138
|
+
status: 403 | 409 | 500;
|
|
139
|
+
message: string;
|
|
140
|
+
} | null>;
|
|
36
141
|
declare const IntegratedServerJwtPayload: z.ZodObject<{
|
|
37
142
|
sub: z.ZodString;
|
|
38
143
|
exp: z.ZodNumber;
|