@prenta/core 8.9.1 → 8.10.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 +102 -0
- package/dist/actions.d.ts +31 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +59 -4
- package/dist/actions.js.map +1 -1
- package/dist/ai/batch-links.d.ts +105 -0
- package/dist/ai/batch-links.d.ts.map +1 -0
- package/dist/ai/batch-links.js +667 -0
- package/dist/ai/batch-links.js.map +1 -0
- package/dist/ai/batch-list.d.ts +127 -4
- package/dist/ai/batch-list.d.ts.map +1 -1
- package/dist/ai/batch-list.js +250 -14
- package/dist/ai/batch-list.js.map +1 -1
- package/dist/ai/providers/http.d.ts +4 -0
- package/dist/ai/providers/http.d.ts.map +1 -1
- package/dist/ai/providers/http.js +9 -8
- package/dist/ai/providers/http.js.map +1 -1
- package/dist/ai/tasks/editor-text.d.ts +39 -0
- package/dist/ai/tasks/editor-text.d.ts.map +1 -0
- package/dist/ai/tasks/editor-text.js +45 -0
- package/dist/ai/tasks/editor-text.js.map +1 -0
- package/dist/ai/tasks/link-embeddings.d.ts +22 -0
- package/dist/ai/tasks/link-embeddings.d.ts.map +1 -1
- package/dist/ai/tasks/link-embeddings.js +24 -10
- package/dist/ai/tasks/link-embeddings.js.map +1 -1
- package/dist/ai/usage.d.ts +7 -0
- package/dist/ai/usage.d.ts.map +1 -1
- package/dist/ai/usage.js +11 -0
- package/dist/ai/usage.js.map +1 -1
- package/dist/api/guarded-db.d.ts +6 -0
- package/dist/api/guarded-db.d.ts.map +1 -1
- package/dist/api/guarded-db.js +13 -1
- package/dist/api/guarded-db.js.map +1 -1
- package/dist/api/handlers.d.ts.map +1 -1
- package/dist/api/handlers.js +2 -0
- package/dist/api/handlers.js.map +1 -1
- package/dist/api/openapi.d.ts.map +1 -1
- package/dist/api/openapi.js +47 -0
- package/dist/api/openapi.js.map +1 -1
- package/dist/api/route-helpers/forms.d.ts.map +1 -1
- package/dist/api/route-helpers/forms.js +7 -1
- package/dist/api/route-helpers/forms.js.map +1 -1
- package/dist/api/routes/ai-authoring.d.ts.map +1 -1
- package/dist/api/routes/ai-authoring.js +1 -0
- package/dist/api/routes/ai-authoring.js.map +1 -1
- package/dist/api/routes/ai-seo.d.ts.map +1 -1
- package/dist/api/routes/ai-seo.js +20 -18
- package/dist/api/routes/ai-seo.js.map +1 -1
- package/dist/api/routes/documents.d.ts.map +1 -1
- package/dist/api/routes/documents.js +20 -0
- package/dist/api/routes/documents.js.map +1 -1
- package/dist/api/routes/media.d.ts.map +1 -1
- package/dist/api/routes/media.js +3 -1
- package/dist/api/routes/media.js.map +1 -1
- package/dist/api/routes/scheduling.d.ts.map +1 -1
- package/dist/api/routes/scheduling.js +33 -2
- package/dist/api/routes/scheduling.js.map +1 -1
- package/dist/appearance/color.d.ts +17 -0
- package/dist/appearance/color.d.ts.map +1 -1
- package/dist/appearance/color.js +162 -1
- package/dist/appearance/color.js.map +1 -1
- package/dist/appearance/index.d.ts +3 -3
- package/dist/appearance/index.d.ts.map +1 -1
- package/dist/appearance/index.js +2 -2
- package/dist/appearance/index.js.map +1 -1
- package/dist/appearance/resolve.d.ts.map +1 -1
- package/dist/appearance/resolve.js +4 -2
- package/dist/appearance/resolve.js.map +1 -1
- package/dist/appearance/theme-tokens.d.ts +60 -11
- package/dist/appearance/theme-tokens.d.ts.map +1 -1
- package/dist/appearance/theme-tokens.js +184 -175
- package/dist/appearance/theme-tokens.js.map +1 -1
- package/dist/appearance/types.d.ts +16 -2
- package/dist/appearance/types.d.ts.map +1 -1
- package/dist/astro-site.d.ts +1 -11
- package/dist/astro-site.d.ts.map +1 -1
- package/dist/astro-site.js +4 -0
- package/dist/astro-site.js.map +1 -1
- package/dist/auth/team.d.ts +1 -0
- package/dist/auth/team.d.ts.map +1 -1
- package/dist/auth/team.js +1 -1
- package/dist/auth/team.js.map +1 -1
- package/dist/cache/http.d.ts +20 -0
- package/dist/cache/http.d.ts.map +1 -1
- package/dist/cache/http.js +42 -0
- package/dist/cache/http.js.map +1 -1
- package/dist/chrome/announcement.d.ts +30 -0
- package/dist/chrome/announcement.d.ts.map +1 -0
- package/dist/chrome/announcement.js +190 -0
- package/dist/chrome/announcement.js.map +1 -0
- package/dist/chrome/codegen.d.ts +17 -0
- package/dist/chrome/codegen.d.ts.map +1 -0
- package/dist/chrome/codegen.js +96 -0
- package/dist/chrome/codegen.js.map +1 -0
- package/dist/chrome/contract.d.ts +142 -0
- package/dist/chrome/contract.d.ts.map +1 -0
- package/dist/chrome/contract.js +2 -0
- package/dist/chrome/contract.js.map +1 -0
- package/dist/chrome/memory-store.d.ts +15 -0
- package/dist/chrome/memory-store.d.ts.map +1 -0
- package/dist/chrome/memory-store.js +54 -0
- package/dist/chrome/memory-store.js.map +1 -0
- package/dist/chrome/parse.d.ts +36 -0
- package/dist/chrome/parse.d.ts.map +1 -0
- package/dist/chrome/parse.js +277 -0
- package/dist/chrome/parse.js.map +1 -0
- package/dist/chrome/prisma-store.d.ts +11 -0
- package/dist/chrome/prisma-store.d.ts.map +1 -0
- package/dist/chrome/prisma-store.js +48 -0
- package/dist/chrome/prisma-store.js.map +1 -0
- package/dist/chrome/public.d.ts +22 -0
- package/dist/chrome/public.d.ts.map +1 -0
- package/dist/chrome/public.js +181 -0
- package/dist/chrome/public.js.map +1 -0
- package/dist/chrome/resolve.d.ts +36 -0
- package/dist/chrome/resolve.d.ts.map +1 -0
- package/dist/chrome/resolve.js +165 -0
- package/dist/chrome/resolve.js.map +1 -0
- package/dist/chrome/revalidate.d.ts +9 -0
- package/dist/chrome/revalidate.d.ts.map +1 -0
- package/dist/chrome/revalidate.js +51 -0
- package/dist/chrome/revalidate.js.map +1 -0
- package/dist/chrome/routes.d.ts +14 -0
- package/dist/chrome/routes.d.ts.map +1 -0
- package/dist/chrome/routes.js +306 -0
- package/dist/chrome/routes.js.map +1 -0
- package/dist/chrome/schema.d.ts +231 -0
- package/dist/chrome/schema.d.ts.map +1 -0
- package/dist/chrome/schema.js +73 -0
- package/dist/chrome/schema.js.map +1 -0
- package/dist/chrome/service.d.ts +76 -0
- package/dist/chrome/service.d.ts.map +1 -0
- package/dist/chrome/service.js +286 -0
- package/dist/chrome/service.js.map +1 -0
- package/dist/chrome/settings.d.ts +14 -0
- package/dist/chrome/settings.d.ts.map +1 -0
- package/dist/chrome/settings.js +142 -0
- package/dist/chrome/settings.js.map +1 -0
- package/dist/chrome/store.d.ts +48 -0
- package/dist/chrome/store.d.ts.map +1 -0
- package/dist/chrome/store.js +26 -0
- package/dist/chrome/store.js.map +1 -0
- package/dist/chrome/values.d.ts +98 -0
- package/dist/chrome/values.d.ts.map +1 -0
- package/dist/chrome/values.js +491 -0
- package/dist/chrome/values.js.map +1 -0
- package/dist/config/define.d.ts +2 -0
- package/dist/config/define.d.ts.map +1 -1
- package/dist/config/define.js +2 -0
- package/dist/config/define.js.map +1 -1
- package/dist/db/model-types.d.ts +62 -0
- package/dist/db/model-types.d.ts.map +1 -1
- package/dist/forms/attribution-settings.d.ts +23 -0
- package/dist/forms/attribution-settings.d.ts.map +1 -0
- package/dist/forms/attribution-settings.js +42 -0
- package/dist/forms/attribution-settings.js.map +1 -0
- package/dist/forms/attribution.d.ts +5 -1
- package/dist/forms/attribution.d.ts.map +1 -1
- package/dist/forms/attribution.js +6 -4
- package/dist/forms/attribution.js.map +1 -1
- package/dist/forms/client-validation.d.ts.map +1 -1
- package/dist/forms/client-validation.js +3 -0
- package/dist/forms/client-validation.js.map +1 -1
- package/dist/forms/form-model.d.ts +109 -0
- package/dist/forms/form-model.d.ts.map +1 -0
- package/dist/forms/form-model.js +192 -0
- package/dist/forms/form-model.js.map +1 -0
- package/dist/forms/index.d.ts +2 -2
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/service.d.ts +19 -1
- package/dist/forms/service.d.ts.map +1 -1
- package/dist/forms/service.js +152 -0
- package/dist/forms/service.js.map +1 -1
- package/dist/forms/spam.d.ts +0 -12
- package/dist/forms/spam.d.ts.map +1 -1
- package/dist/forms/spam.js +30 -0
- package/dist/forms/spam.js.map +1 -1
- package/dist/forms/submission.d.ts +7 -0
- package/dist/forms/submission.d.ts.map +1 -1
- package/dist/forms/submission.js +33 -0
- package/dist/forms/submission.js.map +1 -1
- package/dist/forms/types.d.ts +26 -1
- package/dist/forms/types.d.ts.map +1 -1
- package/dist/forms/types.js +9 -1
- package/dist/forms/types.js.map +1 -1
- package/dist/generated/browser.d.ts +35 -3
- package/dist/generated/client.d.ts +35 -3
- package/dist/generated/internal/class.d.ts +44 -0
- package/dist/generated/internal/class.js +4 -4
- package/dist/generated/internal/prismaNamespace.d.ts +403 -1
- package/dist/generated/internal/prismaNamespace.js +95 -1
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +102 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +95 -1
- package/dist/generated/models/ChromeRegion.d.ts +1203 -0
- package/dist/generated/models/ChromeRegion.js +1 -0
- package/dist/generated/models/Job.d.ts +732 -5
- package/dist/generated/models/JobEvent.d.ts +1339 -0
- package/dist/generated/models/JobEvent.js +1 -0
- package/dist/generated/models/JobReviewItem.d.ts +1470 -0
- package/dist/generated/models/JobReviewItem.js +1 -0
- package/dist/generated/models/SystemSetting.d.ts +952 -0
- package/dist/generated/models/SystemSetting.js +1 -0
- package/dist/generated/models.d.ts +4 -0
- package/dist/index.d.ts +12 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/jobs/batch-ai.d.ts +53 -0
- package/dist/jobs/batch-ai.d.ts.map +1 -0
- package/dist/jobs/batch-ai.js +314 -0
- package/dist/jobs/batch-ai.js.map +1 -0
- package/dist/jobs/contract.d.ts +186 -0
- package/dist/jobs/contract.d.ts.map +1 -0
- package/dist/jobs/contract.js +2 -0
- package/dist/jobs/contract.js.map +1 -0
- package/dist/jobs/error-text.d.ts +23 -0
- package/dist/jobs/error-text.d.ts.map +1 -0
- package/dist/jobs/error-text.js +110 -0
- package/dist/jobs/error-text.js.map +1 -0
- package/dist/jobs/handlers.d.ts.map +1 -1
- package/dist/jobs/handlers.js +48 -7
- package/dist/jobs/handlers.js.map +1 -1
- package/dist/jobs/memory-store.d.ts +26 -2
- package/dist/jobs/memory-store.d.ts.map +1 -1
- package/dist/jobs/memory-store.js +157 -3
- package/dist/jobs/memory-store.js.map +1 -1
- package/dist/jobs/outcomes.d.ts +46 -0
- package/dist/jobs/outcomes.d.ts.map +1 -0
- package/dist/jobs/outcomes.js +251 -0
- package/dist/jobs/outcomes.js.map +1 -0
- package/dist/jobs/prisma-store.d.ts +14 -2
- package/dist/jobs/prisma-store.d.ts.map +1 -1
- package/dist/jobs/prisma-store.js +257 -15
- package/dist/jobs/prisma-store.js.map +1 -1
- package/dist/jobs/queue.d.ts +62 -2
- package/dist/jobs/queue.d.ts.map +1 -1
- package/dist/jobs/queue.js +412 -36
- package/dist/jobs/queue.js.map +1 -1
- package/dist/jobs/retention.d.ts +11 -0
- package/dist/jobs/retention.d.ts.map +1 -0
- package/dist/jobs/retention.js +18 -0
- package/dist/jobs/retention.js.map +1 -0
- package/dist/jobs/review.d.ts +111 -0
- package/dist/jobs/review.d.ts.map +1 -0
- package/dist/jobs/review.js +461 -0
- package/dist/jobs/review.js.map +1 -0
- package/dist/jobs/routes.d.ts.map +1 -1
- package/dist/jobs/routes.js +491 -16
- package/dist/jobs/routes.js.map +1 -1
- package/dist/jobs/serialize.d.ts +40 -0
- package/dist/jobs/serialize.d.ts.map +1 -0
- package/dist/jobs/serialize.js +270 -0
- package/dist/jobs/serialize.js.map +1 -0
- package/dist/jobs/types.d.ts +141 -2
- package/dist/jobs/types.d.ts.map +1 -1
- package/dist/jobs/worker-status.d.ts +27 -0
- package/dist/jobs/worker-status.d.ts.map +1 -0
- package/dist/jobs/worker-status.js +66 -0
- package/dist/jobs/worker-status.js.map +1 -0
- package/dist/media/optimize.d.ts.map +1 -1
- package/dist/media/optimize.js +4 -2
- package/dist/media/optimize.js.map +1 -1
- package/dist/next-site.d.ts +1 -0
- package/dist/next-site.d.ts.map +1 -1
- package/dist/next-site.js +3 -0
- package/dist/next-site.js.map +1 -1
- package/dist/seo/audit-runner.d.ts.map +1 -1
- package/dist/seo/audit-runner.js +23 -2
- package/dist/seo/audit-runner.js.map +1 -1
- package/dist/seo/issue-fix-link-insert.d.ts +11 -0
- package/dist/seo/issue-fix-link-insert.d.ts.map +1 -1
- package/dist/seo/issue-fix-link-insert.js +122 -8
- package/dist/seo/issue-fix-link-insert.js.map +1 -1
- package/dist/server-site.d.ts.map +1 -1
- package/dist/server-site.js +15 -0
- package/dist/server-site.js.map +1 -1
- package/dist/site.d.ts +8 -0
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +6 -0
- package/dist/site.js.map +1 -1
- package/dist/webhooks/index.d.ts +3 -1
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/index.js.map +1 -1
- package/package.json +6 -1
- package/prisma/migrations/0025_job_cancel_review/down.sql +60 -0
- package/prisma/migrations/0025_job_cancel_review/migration.sql +56 -0
- package/prisma/migrations/0026_job_creator_system_settings/down.sql +30 -0
- package/prisma/migrations/0026_job_creator_system_settings/migration.sql +14 -0
- package/prisma/migrations/0027_chrome_regions/down.sql +24 -0
- package/prisma/migrations/0027_chrome_regions/migration.sql +16 -0
- package/prisma/schema.prisma +105 -15
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type ActionContext } from '../actions.js';
|
|
2
|
+
import { suggestBatchAiChange, type BatchAiItem, type BatchAiUsage } from '../ai/batch-list.js';
|
|
3
|
+
import type { PrentaDB } from '../db/client-types.js';
|
|
4
|
+
export type ReviewStatus = 'pending' | 'approved' | 'rejected';
|
|
5
|
+
/** "Save as draft" (or "Keep current status" on a published document) or "Publish". */
|
|
6
|
+
export type OnApprove = 'draft' | 'publish';
|
|
7
|
+
/** A `job_review_items` row: one change batch AI suggested for one document. */
|
|
8
|
+
export interface StoredReviewItem {
|
|
9
|
+
id: string;
|
|
10
|
+
jobId: string;
|
|
11
|
+
documentId: string;
|
|
12
|
+
documentTitle: string;
|
|
13
|
+
url: string;
|
|
14
|
+
field: string;
|
|
15
|
+
before: string;
|
|
16
|
+
after: string;
|
|
17
|
+
editedAfter: string | null;
|
|
18
|
+
status: ReviewStatus;
|
|
19
|
+
decidedById: string | null;
|
|
20
|
+
decidedAt: Date | null;
|
|
21
|
+
appliedRevisionId: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Where an approved change is written, as it is now: a document, or an image
|
|
25
|
+
* in the media library (collection `media`, whose alt text has no versions).
|
|
26
|
+
*/
|
|
27
|
+
export interface ReviewTarget {
|
|
28
|
+
kind: 'document' | 'media';
|
|
29
|
+
collection: string;
|
|
30
|
+
status: string;
|
|
31
|
+
data: Record<string, unknown>;
|
|
32
|
+
/** The document version read, for a save that must not overwrite a newer one. */
|
|
33
|
+
updatedAt?: Date | null;
|
|
34
|
+
}
|
|
35
|
+
/** Why a review action can't go ahead, with the HTTP status to answer with. */
|
|
36
|
+
export declare class ReviewError extends Error {
|
|
37
|
+
readonly status: 400 | 409;
|
|
38
|
+
constructor(message: string, status: 400 | 409);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generate one document's change and store it for review, without touching the
|
|
42
|
+
* document. A slice that dies after storing it runs again, so a change already
|
|
43
|
+
* stored for that document and field isn't stored twice.
|
|
44
|
+
*/
|
|
45
|
+
export declare function recordReviewSuggestion(db: PrentaDB, jobId: string, item: BatchAiItem, options?: Parameters<typeof suggestBatchAiChange>[2]): Promise<BatchAiUsage | undefined>;
|
|
46
|
+
export declare function getReviewItem(db: PrentaDB, jobId: string, itemId: string): Promise<StoredReviewItem | null>;
|
|
47
|
+
/** The document a change applies to, or null when it has been deleted. */
|
|
48
|
+
export declare function loadReviewTarget(db: PrentaDB, item: StoredReviewItem): Promise<ReviewTarget | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Approve a pending change and write it through the normal document save, as
|
|
51
|
+
* the approver: one save, so one revision, whose id is stored as
|
|
52
|
+
* `appliedRevisionId`. "Publish" also publishes a draft. A published document
|
|
53
|
+
* can't be saved as a draft (there's no draft copy), so approving it without
|
|
54
|
+
* "Publish" leaves the change pending. See CONFLICTS.md §4. Media alt text is
|
|
55
|
+
* written straight to the image and has no revision. A link is put in on a
|
|
56
|
+
* fresh read of the document, with a save that can't overwrite a newer one.
|
|
57
|
+
*/
|
|
58
|
+
export declare function approveReviewItem(db: PrentaDB, ctx: ActionContext, item: StoredReviewItem, target: ReviewTarget, options: {
|
|
59
|
+
onApprove: OnApprove;
|
|
60
|
+
after?: string;
|
|
61
|
+
}): Promise<StoredReviewItem>;
|
|
62
|
+
/** Reject a pending change. Nothing is written to the document. */
|
|
63
|
+
export declare function rejectReviewItem(db: PrentaDB, userId: string, item: StoredReviewItem): Promise<StoredReviewItem>;
|
|
64
|
+
/**
|
|
65
|
+
* Undo a decision, putting the change back in review. Undoing an approval
|
|
66
|
+
* writes only the changed field back to `before` (or takes out the link),
|
|
67
|
+
* recorded as a restore, so later edits to other fields stay. It refuses when
|
|
68
|
+
* the field changed after the approval, rather than overwrite that edit, and
|
|
69
|
+
* its save can't overwrite a newer one.
|
|
70
|
+
*/
|
|
71
|
+
export declare function undoReviewItem(db: PrentaDB, ctx: ActionContext, item: StoredReviewItem, target: ReviewTarget | null): Promise<StoredReviewItem>;
|
|
72
|
+
/**
|
|
73
|
+
* Approve every pending change of a job, {@link APPROVE_ALL_BATCH} at a time,
|
|
74
|
+
* until none are left or `deadline` (epoch ms) passes. A change that can't be
|
|
75
|
+
* applied (its document is gone or published, the caller can't write to it, or
|
|
76
|
+
* the save fails) stays pending and is counted as skipped.
|
|
77
|
+
*/
|
|
78
|
+
export declare function approveAllReviewItems(db: PrentaDB, ctx: ActionContext, jobId: string, options: {
|
|
79
|
+
onApprove: OnApprove;
|
|
80
|
+
canApprove: (target: ReviewTarget) => boolean;
|
|
81
|
+
deadline: number;
|
|
82
|
+
}): Promise<{
|
|
83
|
+
approved: number;
|
|
84
|
+
skipped: number;
|
|
85
|
+
remaining: number;
|
|
86
|
+
}>;
|
|
87
|
+
/** A page of a job's changes in the order they were suggested. */
|
|
88
|
+
export declare function listReviewItems(db: PrentaDB, jobId: string, query: {
|
|
89
|
+
status?: ReviewStatus;
|
|
90
|
+
cursor?: string;
|
|
91
|
+
limit: number;
|
|
92
|
+
}): Promise<{
|
|
93
|
+
items: StoredReviewItem[];
|
|
94
|
+
nextCursor: string | null;
|
|
95
|
+
}>;
|
|
96
|
+
/**
|
|
97
|
+
* About 900 tokens (or `tokensPerDocument`) and a minute per document. No
|
|
98
|
+
* monthly limit gives no percentage.
|
|
99
|
+
*/
|
|
100
|
+
export declare function estimateBatch(count: number, monthlyLimit: number | null | undefined, tokensPerDocument?: number): {
|
|
101
|
+
count: number;
|
|
102
|
+
tokens: number;
|
|
103
|
+
minutes: number;
|
|
104
|
+
pctOfMonthlyLimit: number | null;
|
|
105
|
+
};
|
|
106
|
+
/** `auto` is admin-only. Everyone else is forced to review. */
|
|
107
|
+
export declare function resolveReviewMode(requested: 'review' | 'auto', isAdmin: boolean): {
|
|
108
|
+
mode: 'review' | 'auto';
|
|
109
|
+
forbidden: boolean;
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/jobs/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { DocumentChangedError, updateDocumentWithVersion } from '../actions.js';
|
|
2
|
+
import { LINKS_FIELD, insertBodyLink, linkFromAfter, linkTargetLive, removeBodyLink, suggestBodyLinks, } from '../ai/batch-links.js';
|
|
3
|
+
import { MEDIA_ALT_FIELD, batchAiFieldByName, batchAiFieldValue, clipBatchAiText, suggestBatchAiChange, writeMediaAlt, } from '../ai/batch-list.js';
|
|
4
|
+
/** Approve-all writes this many changes per round trip to the database. */
|
|
5
|
+
const APPROVE_ALL_BATCH = 25;
|
|
6
|
+
/** Why a review action can't go ahead, with the HTTP status to answer with. */
|
|
7
|
+
export class ReviewError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
constructor(message, status) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'ReviewError';
|
|
12
|
+
this.status = status;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const ALREADY_DECIDED = 'This change was already decided.';
|
|
16
|
+
const CHANGED_WHILE_SAVING = 'The document changed while this was being saved, so nothing was written. Try again.';
|
|
17
|
+
function asStatus(value) {
|
|
18
|
+
return value === 'approved' || value === 'rejected' ? value : 'pending';
|
|
19
|
+
}
|
|
20
|
+
function toStored(row) {
|
|
21
|
+
const text = (value) => (typeof value === 'string' ? value : '');
|
|
22
|
+
const nullable = (value) => (typeof value === 'string' ? value : null);
|
|
23
|
+
return {
|
|
24
|
+
id: text(row.id),
|
|
25
|
+
jobId: text(row.jobId),
|
|
26
|
+
documentId: text(row.documentId),
|
|
27
|
+
documentTitle: text(row.documentTitle),
|
|
28
|
+
url: text(row.url),
|
|
29
|
+
field: text(row.field),
|
|
30
|
+
before: text(row.before),
|
|
31
|
+
after: text(row.after),
|
|
32
|
+
editedAfter: nullable(row.editedAfter),
|
|
33
|
+
status: asStatus(row.status),
|
|
34
|
+
decidedById: nullable(row.decidedById),
|
|
35
|
+
decidedAt: row.decidedAt instanceof Date ? row.decidedAt : null,
|
|
36
|
+
appliedRevisionId: nullable(row.appliedRevisionId),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function reload(db, id) {
|
|
40
|
+
const row = await db.jobReviewItem.findUnique({ where: { id } });
|
|
41
|
+
if (!row)
|
|
42
|
+
throw new ReviewError('This change no longer exists.', 409);
|
|
43
|
+
return toStored(row);
|
|
44
|
+
}
|
|
45
|
+
/** The item as stored, or `fallback` when it's gone. */
|
|
46
|
+
async function reloadOr(db, id, fallback) {
|
|
47
|
+
const row = await db.jobReviewItem.findUnique({ where: { id } });
|
|
48
|
+
return row ? toStored(row) : fallback;
|
|
49
|
+
}
|
|
50
|
+
function reviewField(item) {
|
|
51
|
+
const field = batchAiFieldByName(item.field);
|
|
52
|
+
if (!field)
|
|
53
|
+
throw new ReviewError(`Changes to "${item.field}" can't be applied here.`, 409);
|
|
54
|
+
return field;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generate one document's change and store it for review, without touching the
|
|
58
|
+
* document. A slice that dies after storing it runs again, so a change already
|
|
59
|
+
* stored for that document and field isn't stored twice.
|
|
60
|
+
*/
|
|
61
|
+
export async function recordReviewSuggestion(db, jobId, item, options) {
|
|
62
|
+
if (item.operation === 'links')
|
|
63
|
+
return recordLinkSuggestions(db, jobId, item, options);
|
|
64
|
+
const { change, usage } = await suggestBatchAiChange(db, item, options);
|
|
65
|
+
if (!change)
|
|
66
|
+
return usage;
|
|
67
|
+
const existing = await db.jobReviewItem.findFirst({
|
|
68
|
+
where: { jobId, documentId: item.documentId, field: change.field },
|
|
69
|
+
});
|
|
70
|
+
if (!existing) {
|
|
71
|
+
await db.jobReviewItem.create({
|
|
72
|
+
data: {
|
|
73
|
+
jobId,
|
|
74
|
+
documentId: item.documentId,
|
|
75
|
+
documentTitle: change.documentTitle,
|
|
76
|
+
url: change.url,
|
|
77
|
+
field: change.field,
|
|
78
|
+
before: change.before,
|
|
79
|
+
after: change.after,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return usage;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Store a document's suggested links for review, one item per link. A job
|
|
87
|
+
* stores a document's links once: a slice that dies after storing them runs
|
|
88
|
+
* again and stores none, without asking the AI again.
|
|
89
|
+
*/
|
|
90
|
+
async function recordLinkSuggestions(db, jobId, item, options) {
|
|
91
|
+
const stored = await db.jobReviewItem.findFirst({
|
|
92
|
+
where: { jobId, documentId: item.documentId, field: LINKS_FIELD },
|
|
93
|
+
});
|
|
94
|
+
if (stored)
|
|
95
|
+
return undefined;
|
|
96
|
+
const { changes, usage } = await suggestBodyLinks(db, item, options);
|
|
97
|
+
for (const change of changes) {
|
|
98
|
+
await db.jobReviewItem.create({
|
|
99
|
+
data: {
|
|
100
|
+
jobId,
|
|
101
|
+
documentId: item.documentId,
|
|
102
|
+
documentTitle: change.documentTitle,
|
|
103
|
+
url: change.url,
|
|
104
|
+
field: change.field,
|
|
105
|
+
before: change.before,
|
|
106
|
+
after: change.after,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return usage;
|
|
111
|
+
}
|
|
112
|
+
export async function getReviewItem(db, jobId, itemId) {
|
|
113
|
+
const row = await db.jobReviewItem.findFirst({ where: { id: itemId, jobId } });
|
|
114
|
+
return row ? toStored(row) : null;
|
|
115
|
+
}
|
|
116
|
+
/** The document a change applies to, or null when it has been deleted. */
|
|
117
|
+
export async function loadReviewTarget(db, item) {
|
|
118
|
+
if (item.field === MEDIA_ALT_FIELD.field) {
|
|
119
|
+
const media = await db.media.findUnique({ where: { id: item.documentId } });
|
|
120
|
+
if (!media)
|
|
121
|
+
return null;
|
|
122
|
+
return {
|
|
123
|
+
kind: 'media',
|
|
124
|
+
collection: 'media',
|
|
125
|
+
status: '',
|
|
126
|
+
data: { altText: media.altText ?? '' },
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const doc = await db.document.findFirst({ where: { id: item.documentId, deletedAt: null } });
|
|
130
|
+
if (!doc)
|
|
131
|
+
return null;
|
|
132
|
+
const data = doc.data && typeof doc.data === 'object' && !Array.isArray(doc.data) ? doc.data : {};
|
|
133
|
+
return {
|
|
134
|
+
kind: 'document',
|
|
135
|
+
collection: doc.collection,
|
|
136
|
+
status: doc.status,
|
|
137
|
+
data: data,
|
|
138
|
+
updatedAt: doc.updatedAt instanceof Date ? doc.updatedAt : null,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Write a change's text to its target. A document is saved like any edit and
|
|
143
|
+
* returns its version id. Media alt text has no versions, so it returns null.
|
|
144
|
+
*/
|
|
145
|
+
async function writeChange(db, ctx, item, target, patch, options) {
|
|
146
|
+
if (target.kind === 'media') {
|
|
147
|
+
await writeMediaAlt(db, item.documentId, String(patch[MEDIA_ALT_FIELD.key] ?? ''));
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const { versionId } = await updateDocumentWithVersion(target.collection, item.documentId, patch, ctx, options);
|
|
151
|
+
return versionId;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Save a patch built from the document as read, only while it's still that
|
|
155
|
+
* version. If another save landed in between (another decision, approve-all, an
|
|
156
|
+
* editor), read the document again and build the patch once more, so that
|
|
157
|
+
* save is never overwritten. A second clash is a 409 and writes nothing.
|
|
158
|
+
* Link changes need this because their patch replaces a whole rich text field.
|
|
159
|
+
*/
|
|
160
|
+
async function writeFromFreshRead(db, ctx, item, target, build, options) {
|
|
161
|
+
let current = target;
|
|
162
|
+
for (let attempt = 0;; attempt++) {
|
|
163
|
+
const patch = build(current);
|
|
164
|
+
try {
|
|
165
|
+
return await writeChange(db, ctx, item, current, patch, {
|
|
166
|
+
...options,
|
|
167
|
+
expectedUpdatedAt: current.updatedAt ?? undefined,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
if (!(err instanceof DocumentChangedError))
|
|
172
|
+
throw err;
|
|
173
|
+
if (attempt > 0)
|
|
174
|
+
throw new ReviewError(CHANGED_WHILE_SAVING, 409);
|
|
175
|
+
const fresh = await loadReviewTarget(db, item);
|
|
176
|
+
if (!fresh)
|
|
177
|
+
throw new ReviewError('The document no longer exists.', 409);
|
|
178
|
+
current = fresh;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** A text field's approved text: the edited or suggested text, clipped like the AI's. */
|
|
183
|
+
function approvedText(item, after) {
|
|
184
|
+
const field = reviewField(item);
|
|
185
|
+
const text = clipBatchAiText(after ?? item.editedAfter ?? item.after, field);
|
|
186
|
+
if (!text)
|
|
187
|
+
throw new ReviewError('The approved text is empty.', 400);
|
|
188
|
+
return {
|
|
189
|
+
patch: { [field.key]: text },
|
|
190
|
+
editedAfter: text === item.after ? null : text,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* The link a link suggestion approves. It can't be edited (400), and its page
|
|
195
|
+
* has to still be published and indexable at that address (409).
|
|
196
|
+
*/
|
|
197
|
+
async function approvedLink(db, item, after) {
|
|
198
|
+
if (after !== undefined && after !== item.after) {
|
|
199
|
+
throw new ReviewError("A link suggestion can't be edited. Approve it as it is, or reject it.", 400);
|
|
200
|
+
}
|
|
201
|
+
const link = linkFromAfter(item.after);
|
|
202
|
+
if (!link)
|
|
203
|
+
throw new ReviewError("This link suggestion can't be read.", 409);
|
|
204
|
+
if (!(await linkTargetLive(db, link.href))) {
|
|
205
|
+
throw new ReviewError(`The page this links to, ${link.href}, isn't published at that address any more.`, 409);
|
|
206
|
+
}
|
|
207
|
+
return link;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The patch that puts a link in a document as read: in the sentence the item
|
|
211
|
+
* shows (its `before`), so it lands where the reviewer saw it. 409 when the
|
|
212
|
+
* document already links to that page, or that sentence can't take it now.
|
|
213
|
+
*/
|
|
214
|
+
function linkPatch(item, target, link) {
|
|
215
|
+
const insert = insertBodyLink(target.collection, target.data, link, item.before);
|
|
216
|
+
if (!('reason' in insert))
|
|
217
|
+
return insert.patch;
|
|
218
|
+
throw new ReviewError(insert.reason === 'already-linked'
|
|
219
|
+
? `This document already links to ${link.href}.`
|
|
220
|
+
: `“${link.anchor}” can't be linked in the sentence it was suggested for any more. The sentence changed, or the phrase is in a heading or another link now. Reject it, or run the job again.`, 409);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Approve a pending change and write it through the normal document save, as
|
|
224
|
+
* the approver: one save, so one revision, whose id is stored as
|
|
225
|
+
* `appliedRevisionId`. "Publish" also publishes a draft. A published document
|
|
226
|
+
* can't be saved as a draft (there's no draft copy), so approving it without
|
|
227
|
+
* "Publish" leaves the change pending. See CONFLICTS.md §4. Media alt text is
|
|
228
|
+
* written straight to the image and has no revision. A link is put in on a
|
|
229
|
+
* fresh read of the document, with a save that can't overwrite a newer one.
|
|
230
|
+
*/
|
|
231
|
+
export async function approveReviewItem(db, ctx, item, target, options) {
|
|
232
|
+
if (item.status !== 'pending')
|
|
233
|
+
throw new ReviewError(ALREADY_DECIDED, 409);
|
|
234
|
+
const link = item.field === LINKS_FIELD ? await approvedLink(db, item, options.after) : null;
|
|
235
|
+
const text = link ? null : approvedText(item, options.after);
|
|
236
|
+
const publish = options.onApprove === 'publish';
|
|
237
|
+
if (target.status === 'PUBLISHED' && !publish) {
|
|
238
|
+
throw new ReviewError('This document is published, so the change stays in review. Approve it with Publish to apply it live.', 409);
|
|
239
|
+
}
|
|
240
|
+
const build = (current) => {
|
|
241
|
+
// A retry after a concurrent save reads the document again. If its publish
|
|
242
|
+
// state moved meanwhile, the reviewer's choice was made for a different
|
|
243
|
+
// document state: a newly published one would go live without Publish, and
|
|
244
|
+
// an unpublished one would be republished over that decision. Becoming
|
|
245
|
+
// published is fine for a Publish approval (another one got there first).
|
|
246
|
+
if (current !== target &&
|
|
247
|
+
current.status !== target.status &&
|
|
248
|
+
!(publish && current.status === 'PUBLISHED')) {
|
|
249
|
+
throw new ReviewError(CHANGED_WHILE_SAVING, 409);
|
|
250
|
+
}
|
|
251
|
+
const patch = link ? linkPatch(item, current, link) : { ...text.patch };
|
|
252
|
+
if (current.kind === 'document' && publish && current.status !== 'PUBLISHED') {
|
|
253
|
+
patch.status = 'PUBLISHED';
|
|
254
|
+
}
|
|
255
|
+
return patch;
|
|
256
|
+
};
|
|
257
|
+
// A link that can't go in is refused before the change is claimed.
|
|
258
|
+
if (link)
|
|
259
|
+
build(target);
|
|
260
|
+
// Claim the change before writing, so two approvals can't both apply it. Its
|
|
261
|
+
// decidedAt also keeps retention off the job while the change is written.
|
|
262
|
+
const editedAfter = text?.editedAfter ?? null;
|
|
263
|
+
const decidedAt = new Date();
|
|
264
|
+
const claimed = await db.jobReviewItem.updateMany({
|
|
265
|
+
where: { id: item.id, status: 'pending' },
|
|
266
|
+
data: { status: 'approved', editedAfter, decidedById: ctx.userId, decidedAt },
|
|
267
|
+
});
|
|
268
|
+
if (claimed.count !== 1)
|
|
269
|
+
throw new ReviewError(ALREADY_DECIDED, 409);
|
|
270
|
+
// The writes after the claim are updateMany, which skips an item that's gone
|
|
271
|
+
// (its job deleted by retention) instead of throwing over the outcome.
|
|
272
|
+
let versionId;
|
|
273
|
+
try {
|
|
274
|
+
// Every approval saves only while the document is the version read, so the
|
|
275
|
+
// publish-state check above also covers a text change whose document was
|
|
276
|
+
// published between the route's read and this save.
|
|
277
|
+
versionId = await writeFromFreshRead(db, ctx, item, target, build);
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
await db.jobReviewItem.updateMany({
|
|
281
|
+
where: { id: item.id },
|
|
282
|
+
data: {
|
|
283
|
+
status: 'pending',
|
|
284
|
+
editedAfter: item.editedAfter,
|
|
285
|
+
decidedById: null,
|
|
286
|
+
decidedAt: null,
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
throw err;
|
|
290
|
+
}
|
|
291
|
+
await db.jobReviewItem.updateMany({
|
|
292
|
+
where: { id: item.id },
|
|
293
|
+
data: { appliedRevisionId: versionId },
|
|
294
|
+
});
|
|
295
|
+
// The change is written, so it's answered as approved even if the item is gone.
|
|
296
|
+
return reloadOr(db, item.id, {
|
|
297
|
+
...item,
|
|
298
|
+
status: 'approved',
|
|
299
|
+
editedAfter,
|
|
300
|
+
decidedById: ctx.userId,
|
|
301
|
+
decidedAt,
|
|
302
|
+
appliedRevisionId: versionId,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
/** Reject a pending change. Nothing is written to the document. */
|
|
306
|
+
export async function rejectReviewItem(db, userId, item) {
|
|
307
|
+
const decided = await db.jobReviewItem.updateMany({
|
|
308
|
+
where: { id: item.id, status: 'pending' },
|
|
309
|
+
data: { status: 'rejected', decidedById: userId, decidedAt: new Date() },
|
|
310
|
+
});
|
|
311
|
+
if (decided.count !== 1)
|
|
312
|
+
throw new ReviewError(ALREADY_DECIDED, 409);
|
|
313
|
+
return reload(db, item.id);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* What undoing an approval writes on the document as read. A text field goes
|
|
317
|
+
* back to `before`. A link is taken out, keeping its words, while the markup it
|
|
318
|
+
* put in is still there. 409 when the field or link changed after the approval.
|
|
319
|
+
*/
|
|
320
|
+
function restorePatch(item, target) {
|
|
321
|
+
let patch;
|
|
322
|
+
if (item.field === LINKS_FIELD) {
|
|
323
|
+
const link = linkFromAfter(item.after);
|
|
324
|
+
patch = link ? removeBodyLink(target.collection, target.data, link) : null;
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
const field = reviewField(item);
|
|
328
|
+
const applied = clipBatchAiText(item.editedAfter ?? item.after, field);
|
|
329
|
+
patch = batchAiFieldValue(target.data, field) === applied ? { [field.key]: item.before } : null;
|
|
330
|
+
}
|
|
331
|
+
if (patch)
|
|
332
|
+
return patch;
|
|
333
|
+
throw new ReviewError(item.field === LINKS_FIELD
|
|
334
|
+
? 'The link changed after this was approved. Restore it from the document history instead.'
|
|
335
|
+
: 'The field changed after this was approved. Restore it from the document history instead.', 409);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Undo a decision, putting the change back in review. Undoing an approval
|
|
339
|
+
* writes only the changed field back to `before` (or takes out the link),
|
|
340
|
+
* recorded as a restore, so later edits to other fields stay. It refuses when
|
|
341
|
+
* the field changed after the approval, rather than overwrite that edit, and
|
|
342
|
+
* its save can't overwrite a newer one.
|
|
343
|
+
*/
|
|
344
|
+
export async function undoReviewItem(db, ctx, item, target) {
|
|
345
|
+
if (item.status === 'pending')
|
|
346
|
+
throw new ReviewError('There is no decision to undo.', 409);
|
|
347
|
+
if (item.status === 'rejected') {
|
|
348
|
+
const reopened = await db.jobReviewItem.updateMany({
|
|
349
|
+
where: { id: item.id, status: 'rejected' },
|
|
350
|
+
data: { status: 'pending', decidedById: null, decidedAt: null },
|
|
351
|
+
});
|
|
352
|
+
if (reopened.count !== 1)
|
|
353
|
+
throw new ReviewError(ALREADY_DECIDED, 409);
|
|
354
|
+
return reload(db, item.id);
|
|
355
|
+
}
|
|
356
|
+
if (!target) {
|
|
357
|
+
throw new ReviewError("The document no longer exists, so the change can't be undone.", 409);
|
|
358
|
+
}
|
|
359
|
+
// Refused before the decision is reopened when it can't be undone.
|
|
360
|
+
restorePatch(item, target);
|
|
361
|
+
const reopened = await db.jobReviewItem.updateMany({
|
|
362
|
+
where: { id: item.id, status: 'approved' },
|
|
363
|
+
data: { status: 'pending', appliedRevisionId: null, decidedById: null, decidedAt: null },
|
|
364
|
+
});
|
|
365
|
+
if (reopened.count !== 1)
|
|
366
|
+
throw new ReviewError(ALREADY_DECIDED, 409);
|
|
367
|
+
try {
|
|
368
|
+
await writeFromFreshRead(db, ctx, item, target, (current) => restorePatch(item, current), {
|
|
369
|
+
changeType: 'RESTORE',
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
// updateMany, like approve's revert, so an item that's gone can't hide `err`.
|
|
374
|
+
await db.jobReviewItem.updateMany({
|
|
375
|
+
where: { id: item.id },
|
|
376
|
+
data: {
|
|
377
|
+
status: 'approved',
|
|
378
|
+
appliedRevisionId: item.appliedRevisionId,
|
|
379
|
+
decidedById: item.decidedById,
|
|
380
|
+
decidedAt: item.decidedAt,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
throw err;
|
|
384
|
+
}
|
|
385
|
+
return reload(db, item.id);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Approve every pending change of a job, {@link APPROVE_ALL_BATCH} at a time,
|
|
389
|
+
* until none are left or `deadline` (epoch ms) passes. A change that can't be
|
|
390
|
+
* applied (its document is gone or published, the caller can't write to it, or
|
|
391
|
+
* the save fails) stays pending and is counted as skipped.
|
|
392
|
+
*/
|
|
393
|
+
export async function approveAllReviewItems(db, ctx, jobId, options) {
|
|
394
|
+
const skipped = new Set();
|
|
395
|
+
let approved = 0;
|
|
396
|
+
while (Date.now() < options.deadline) {
|
|
397
|
+
const rows = await db.jobReviewItem.findMany({
|
|
398
|
+
where: {
|
|
399
|
+
jobId,
|
|
400
|
+
status: 'pending',
|
|
401
|
+
...(skipped.size > 0 ? { id: { notIn: [...skipped] } } : {}),
|
|
402
|
+
},
|
|
403
|
+
orderBy: { id: 'asc' },
|
|
404
|
+
take: APPROVE_ALL_BATCH,
|
|
405
|
+
});
|
|
406
|
+
if (rows.length === 0)
|
|
407
|
+
break;
|
|
408
|
+
for (const row of rows) {
|
|
409
|
+
const item = toStored(row);
|
|
410
|
+
const target = await loadReviewTarget(db, item);
|
|
411
|
+
if (!target || !options.canApprove(target)) {
|
|
412
|
+
skipped.add(item.id);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
await approveReviewItem(db, ctx, item, target, { onApprove: options.onApprove });
|
|
417
|
+
approved++;
|
|
418
|
+
}
|
|
419
|
+
catch {
|
|
420
|
+
skipped.add(item.id);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const remaining = await db.jobReviewItem.count({ where: { jobId, status: 'pending' } });
|
|
425
|
+
return { approved, skipped: skipped.size, remaining };
|
|
426
|
+
}
|
|
427
|
+
/** A page of a job's changes in the order they were suggested. */
|
|
428
|
+
export async function listReviewItems(db, jobId, query) {
|
|
429
|
+
const rows = await db.jobReviewItem.findMany({
|
|
430
|
+
where: {
|
|
431
|
+
jobId,
|
|
432
|
+
...(query.status ? { status: query.status } : {}),
|
|
433
|
+
...(query.cursor ? { id: { gt: query.cursor } } : {}),
|
|
434
|
+
},
|
|
435
|
+
orderBy: { id: 'asc' },
|
|
436
|
+
take: query.limit,
|
|
437
|
+
});
|
|
438
|
+
const items = rows.map((row) => toStored(row));
|
|
439
|
+
const last = items.at(-1);
|
|
440
|
+
return { items, nextCursor: items.length === query.limit && last ? last.id : null };
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* About 900 tokens (or `tokensPerDocument`) and a minute per document. No
|
|
444
|
+
* monthly limit gives no percentage.
|
|
445
|
+
*/
|
|
446
|
+
export function estimateBatch(count, monthlyLimit, tokensPerDocument = 900) {
|
|
447
|
+
const tokens = count * tokensPerDocument;
|
|
448
|
+
return {
|
|
449
|
+
count,
|
|
450
|
+
tokens,
|
|
451
|
+
minutes: count,
|
|
452
|
+
pctOfMonthlyLimit: monthlyLimit && monthlyLimit > 0 ? Math.round((tokens / monthlyLimit) * 100) : null,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
/** `auto` is admin-only. Everyone else is forced to review. */
|
|
456
|
+
export function resolveReviewMode(requested, isAdmin) {
|
|
457
|
+
if (requested === 'auto' && !isAdmin)
|
|
458
|
+
return { mode: 'review', forbidden: true };
|
|
459
|
+
return { mode: requested, forbidden: false };
|
|
460
|
+
}
|
|
461
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/jobs/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/jobs/routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/jobs/routes.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AA4NhD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiVzD;AAED,4FAA4F;AAC5F,wBAAsB,cAAc,CAClC,EAAE,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,EAChC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAGxD"}
|