@camox/api-contract 0.63.0 → 0.65.1
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/dist/analytics.d.ts +1 -1
- package/dist/drafts.d.ts +50 -2
- package/dist/drafts.js +57 -3
- package/dist/layout-routes.d.ts +20 -0
- package/dist/layout-routes.js +43 -0
- package/dist/patrol.d.ts +116 -8
- package/dist/patrol.js +33 -1
- package/dist/router.d.ts +10000 -9206
- package/dist/threads.d.ts +19 -12
- package/dist/threads.js +21 -8
- package/package.json +8 -2
- package/src/drafts.ts +67 -2
- package/src/layout-routes.ts +51 -0
- package/src/patrol.ts +129 -9
- package/src/threads.ts +32 -4
package/dist/analytics.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export declare const ga4MeasurementIdSchema: z.ZodString;
|
|
|
12
12
|
export declare const posthogProjectApiKeySchema: z.ZodString;
|
|
13
13
|
/** The PostHog Cloud region a project lives in. */
|
|
14
14
|
export declare const posthogRegionSchema: z.ZodEnum<{
|
|
15
|
-
us: "us";
|
|
16
15
|
eu: "eu";
|
|
16
|
+
us: "us";
|
|
17
17
|
}>;
|
|
18
18
|
export type PosthogRegion = z.output<typeof posthogRegionSchema>;
|
|
19
19
|
//#endregion
|
package/dist/drafts.d.ts
CHANGED
|
@@ -20,6 +20,41 @@ export declare const PUBLISHING_DRAFT_HEADER = "x-camox-publishing-draft";
|
|
|
20
20
|
* `PUBLISHING_DRAFT_HEADER`.
|
|
21
21
|
*/
|
|
22
22
|
export declare const PUBLISHING_DRAFT_VAR = "CAMOX_PUBLISHING_DRAFT";
|
|
23
|
+
/**
|
|
24
|
+
* Request header carrying a look token (ADR 0032): a short-lived, read-only credential the API
|
|
25
|
+
* signs for the agent's `look` tool, naming one project and one draft. A request carrying a valid
|
|
26
|
+
* one reads that draft's content, named with `DRAFT_HEADER`, as a member would, without a session.
|
|
27
|
+
* It writes nothing, reads no other draft, and reads none of Live's private data.
|
|
28
|
+
*/
|
|
29
|
+
export declare const LOOK_TOKEN_HEADER = "x-camox-look-token";
|
|
30
|
+
/**
|
|
31
|
+
* The cookie the browser `look` drives carries the look token in, set for the website's host
|
|
32
|
+
* only, so third-party requests never see it. The website forwards it as `LOOK_TOKEN_HEADER`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const LOOK_TOKEN_COOKIE = "camox_look";
|
|
35
|
+
/**
|
|
36
|
+
* The website's lightweight document the browser `look` drives loads (the SDK runtime's
|
|
37
|
+
* `RUNTIME_ROUTE_PATHS.look`): one page of the draft `DRAFT_SEARCH_PARAM` names, at the path
|
|
38
|
+
* `LOOK_PATH_PARAM` gives in the locale `LOOK_LOCALE_PARAM` names, its Default Locale without.
|
|
39
|
+
*/
|
|
40
|
+
export declare const LOOK_DOCUMENT_PATH = "/_camox/look";
|
|
41
|
+
export declare const LOOK_PATH_PARAM = "path";
|
|
42
|
+
export declare const LOOK_LOCALE_PARAM = "locale";
|
|
43
|
+
/**
|
|
44
|
+
* The look document's Block Definition mode: instead of a page, the block of the Block Definition
|
|
45
|
+
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with its default content and
|
|
46
|
+
* Block Settings and the overrides `LOOK_CONTENT_PARAM` and `LOOK_SETTINGS_PARAM` give as JSON, in
|
|
47
|
+
* the shape the content tools take.
|
|
48
|
+
*/
|
|
49
|
+
export declare const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
50
|
+
export declare const LOOK_CONTENT_PARAM = "content";
|
|
51
|
+
export declare const LOOK_SETTINGS_PARAM = "settings";
|
|
52
|
+
/**
|
|
53
|
+
* The id of a block shown without being placed, as the look document's Block Definition mode
|
|
54
|
+
* shows it: never a stored block's, which are UUIDs. Its element is
|
|
55
|
+
* `[data-camox-viewport-block="unplaced"]`.
|
|
56
|
+
*/
|
|
57
|
+
export declare const UNPLACED_BLOCK_ID = "unplaced";
|
|
23
58
|
/**
|
|
24
59
|
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
25
60
|
* exist yet. Its value is `"1"`.
|
|
@@ -68,18 +103,31 @@ export type PublishAbortReason = (typeof PUBLISH_ABORT_REASONS)[number];
|
|
|
68
103
|
export declare const PUBLISH_BLOCKED_ERROR = "PUBLISH_BLOCKED";
|
|
69
104
|
/**
|
|
70
105
|
* oRPC error code for a publish refused because the draft still has pending translations: every
|
|
71
|
-
* locale goes live together,
|
|
106
|
+
* locale goes live together, and there is no publishing anyway (ADR 0033).
|
|
72
107
|
*/
|
|
73
108
|
export declare const TRANSLATIONS_PENDING_ERROR = "TRANSLATIONS_PENDING";
|
|
109
|
+
/**
|
|
110
|
+
* oRPC error code for a publish refused because the draft has open findings, each to fix or for a
|
|
111
|
+
* member to dismiss: there is no publishing past them (ADR 0033).
|
|
112
|
+
*/
|
|
113
|
+
export declare const FINDINGS_OPEN_ERROR = "FINDINGS_OPEN";
|
|
114
|
+
/**
|
|
115
|
+
* oRPC error code for a publish refused because a patroller's check at publish hasn't read the
|
|
116
|
+
* draft's latest changes yet: publishing waits for it (ADR 0033).
|
|
117
|
+
*/
|
|
118
|
+
export declare const CHECKS_RUNNING_ERROR = "CHECKS_RUNNING";
|
|
74
119
|
/**
|
|
75
120
|
* Why the publish tool published nothing of a draft with changes, and returned a fresh preview to
|
|
76
121
|
* review again, by the error code of each: Live changed since the preview, the draft has blockers,
|
|
77
|
-
* translations are still running,
|
|
122
|
+
* translations are still running, the draft has open findings, a check at publish is still
|
|
123
|
+
* running, or the draft's code changed since the preview.
|
|
78
124
|
*/
|
|
79
125
|
export declare const NOT_PUBLISHED_CODES: {
|
|
80
126
|
readonly conflictsChanged: "CONFLICTS_CHANGED";
|
|
81
127
|
readonly blocked: "PUBLISH_BLOCKED";
|
|
82
128
|
readonly translating: "TRANSLATIONS_PENDING";
|
|
129
|
+
readonly findings: "FINDINGS_OPEN";
|
|
130
|
+
readonly checking: "CHECKS_RUNNING";
|
|
83
131
|
readonly revisionChanged: "REVISION_CHANGED";
|
|
84
132
|
};
|
|
85
133
|
export type NotPublishedReason = keyof typeof NOT_PUBLISHED_CODES;
|
package/dist/drafts.js
CHANGED
|
@@ -21,6 +21,41 @@ const PUBLISHING_DRAFT_HEADER = "x-camox-publishing-draft";
|
|
|
21
21
|
*/
|
|
22
22
|
const PUBLISHING_DRAFT_VAR = "CAMOX_PUBLISHING_DRAFT";
|
|
23
23
|
/**
|
|
24
|
+
* Request header carrying a look token (ADR 0032): a short-lived, read-only credential the API
|
|
25
|
+
* signs for the agent's `look` tool, naming one project and one draft. A request carrying a valid
|
|
26
|
+
* one reads that draft's content, named with `DRAFT_HEADER`, as a member would, without a session.
|
|
27
|
+
* It writes nothing, reads no other draft, and reads none of Live's private data.
|
|
28
|
+
*/
|
|
29
|
+
const LOOK_TOKEN_HEADER = "x-camox-look-token";
|
|
30
|
+
/**
|
|
31
|
+
* The cookie the browser `look` drives carries the look token in, set for the website's host
|
|
32
|
+
* only, so third-party requests never see it. The website forwards it as `LOOK_TOKEN_HEADER`.
|
|
33
|
+
*/
|
|
34
|
+
const LOOK_TOKEN_COOKIE = "camox_look";
|
|
35
|
+
/**
|
|
36
|
+
* The website's lightweight document the browser `look` drives loads (the SDK runtime's
|
|
37
|
+
* `RUNTIME_ROUTE_PATHS.look`): one page of the draft `DRAFT_SEARCH_PARAM` names, at the path
|
|
38
|
+
* `LOOK_PATH_PARAM` gives in the locale `LOOK_LOCALE_PARAM` names, its Default Locale without.
|
|
39
|
+
*/
|
|
40
|
+
const LOOK_DOCUMENT_PATH = "/_camox/look";
|
|
41
|
+
const LOOK_PATH_PARAM = "path";
|
|
42
|
+
const LOOK_LOCALE_PARAM = "locale";
|
|
43
|
+
/**
|
|
44
|
+
* The look document's Block Definition mode: instead of a page, the block of the Block Definition
|
|
45
|
+
* `LOOK_BLOCK_DEFINITION_PARAM` names, alone in the site's shell, with its default content and
|
|
46
|
+
* Block Settings and the overrides `LOOK_CONTENT_PARAM` and `LOOK_SETTINGS_PARAM` give as JSON, in
|
|
47
|
+
* the shape the content tools take.
|
|
48
|
+
*/
|
|
49
|
+
const LOOK_BLOCK_DEFINITION_PARAM = "blockDefinition";
|
|
50
|
+
const LOOK_CONTENT_PARAM = "content";
|
|
51
|
+
const LOOK_SETTINGS_PARAM = "settings";
|
|
52
|
+
/**
|
|
53
|
+
* The id of a block shown without being placed, as the look document's Block Definition mode
|
|
54
|
+
* shows it: never a stored block's, which are UUIDs. Its element is
|
|
55
|
+
* `[data-camox-viewport-block="unplaced"]`.
|
|
56
|
+
*/
|
|
57
|
+
const UNPLACED_BLOCK_ID = "unplaced";
|
|
58
|
+
/**
|
|
24
59
|
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
25
60
|
* exist yet. Its value is `"1"`.
|
|
26
61
|
*/
|
|
@@ -62,18 +97,31 @@ const PUBLISH_ABORT_REASONS = [
|
|
|
62
97
|
const PUBLISH_BLOCKED_ERROR = "PUBLISH_BLOCKED";
|
|
63
98
|
/**
|
|
64
99
|
* oRPC error code for a publish refused because the draft still has pending translations: every
|
|
65
|
-
* locale goes live together,
|
|
100
|
+
* locale goes live together, and there is no publishing anyway (ADR 0033).
|
|
66
101
|
*/
|
|
67
102
|
const TRANSLATIONS_PENDING_ERROR = "TRANSLATIONS_PENDING";
|
|
68
103
|
/**
|
|
104
|
+
* oRPC error code for a publish refused because the draft has open findings, each to fix or for a
|
|
105
|
+
* member to dismiss: there is no publishing past them (ADR 0033).
|
|
106
|
+
*/
|
|
107
|
+
const FINDINGS_OPEN_ERROR = "FINDINGS_OPEN";
|
|
108
|
+
/**
|
|
109
|
+
* oRPC error code for a publish refused because a patroller's check at publish hasn't read the
|
|
110
|
+
* draft's latest changes yet: publishing waits for it (ADR 0033).
|
|
111
|
+
*/
|
|
112
|
+
const CHECKS_RUNNING_ERROR = "CHECKS_RUNNING";
|
|
113
|
+
/**
|
|
69
114
|
* Why the publish tool published nothing of a draft with changes, and returned a fresh preview to
|
|
70
115
|
* review again, by the error code of each: Live changed since the preview, the draft has blockers,
|
|
71
|
-
* translations are still running,
|
|
116
|
+
* translations are still running, the draft has open findings, a check at publish is still
|
|
117
|
+
* running, or the draft's code changed since the preview.
|
|
72
118
|
*/
|
|
73
119
|
const NOT_PUBLISHED_CODES = {
|
|
74
120
|
conflictsChanged: CONFLICTS_CHANGED_ERROR,
|
|
75
121
|
blocked: PUBLISH_BLOCKED_ERROR,
|
|
76
122
|
translating: TRANSLATIONS_PENDING_ERROR,
|
|
123
|
+
findings: FINDINGS_OPEN_ERROR,
|
|
124
|
+
checking: CHECKS_RUNNING_ERROR,
|
|
77
125
|
revisionChanged: REVISION_CHANGED_ERROR
|
|
78
126
|
};
|
|
79
127
|
/**
|
|
@@ -96,6 +144,7 @@ const CONTENT_WRITES = {
|
|
|
96
144
|
getUsageCounts: false,
|
|
97
145
|
getPagesUsing: false,
|
|
98
146
|
getSyncedContent: false,
|
|
147
|
+
getUnplaced: false,
|
|
99
148
|
create: true,
|
|
100
149
|
updateContent: true,
|
|
101
150
|
updateSettings: true,
|
|
@@ -151,6 +200,11 @@ const CONTENT_WRITES = {
|
|
|
151
200
|
setLayout: true,
|
|
152
201
|
generateSeo: false
|
|
153
202
|
},
|
|
203
|
+
patrol: {
|
|
204
|
+
get: false,
|
|
205
|
+
applyFix: true,
|
|
206
|
+
dismissFinding: false
|
|
207
|
+
},
|
|
154
208
|
repeatableItems: {
|
|
155
209
|
get: false,
|
|
156
210
|
create: true,
|
|
@@ -169,4 +223,4 @@ function isContentWrite(path) {
|
|
|
169
223
|
}
|
|
170
224
|
|
|
171
225
|
//#endregion
|
|
172
|
-
export { CAMOX_ACTOR, CAMOX_NAME, CONFLICTS_CHANGED_ERROR, DRAFT_CREATE_HEADER, DRAFT_ENDED_ERROR_CODE, DRAFT_HEADER, DRAFT_SEARCH_PARAM, LIVE_READ_ONLY_ERROR, LOCALE_HEADER, NOT_PUBLISHED_CODES, PUBLISHING_DRAFT_HEADER, PUBLISHING_DRAFT_VAR, PUBLISH_ABORT_REASONS, PUBLISH_BLOCKED_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR, isContentWrite };
|
|
226
|
+
export { CAMOX_ACTOR, CAMOX_NAME, CHECKS_RUNNING_ERROR, CONFLICTS_CHANGED_ERROR, DRAFT_CREATE_HEADER, DRAFT_ENDED_ERROR_CODE, DRAFT_HEADER, DRAFT_SEARCH_PARAM, FINDINGS_OPEN_ERROR, LIVE_READ_ONLY_ERROR, LOCALE_HEADER, LOOK_BLOCK_DEFINITION_PARAM, LOOK_CONTENT_PARAM, LOOK_DOCUMENT_PATH, LOOK_LOCALE_PARAM, LOOK_PATH_PARAM, LOOK_SETTINGS_PARAM, LOOK_TOKEN_COOKIE, LOOK_TOKEN_HEADER, NOT_PUBLISHED_CODES, PUBLISHING_DRAFT_HEADER, PUBLISHING_DRAFT_VAR, PUBLISH_ABORT_REASONS, PUBLISH_BLOCKED_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR, UNPLACED_BLOCK_ID, isContentWrite };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/layout-routes.d.ts
|
|
2
|
+
/** How a layout's pages come about: authored by editors, derived from data, or one fixed page. */
|
|
3
|
+
export type LayoutKind = "curated" | "derived" | "singleton";
|
|
4
|
+
/** A layout as route matching reads it: its id, which is its file route, and its kind. */
|
|
5
|
+
export type LayoutRoute = {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: LayoutKind;
|
|
8
|
+
};
|
|
9
|
+
/** The segments of a layout's file route, such as `blog.$slug`: `$` segments are params. */
|
|
10
|
+
export declare function routeSegments(id: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* The singleton or derived layout whose route matches `pathname`, a path in its Locale, with its
|
|
13
|
+
* params, or null. The route with the fewest params wins, so a singleton's fixed route wins over
|
|
14
|
+
* a derived route that would match it too. The SDK renders pages and the API checks them with it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function matchLayoutRoute<L>(layouts: readonly L[], pathname: string, routeOf: (layout: L) => LayoutRoute): {
|
|
17
|
+
layout: L;
|
|
18
|
+
params: Record<string, string>;
|
|
19
|
+
} | null;
|
|
20
|
+
//#endregion
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/layout-routes.ts
|
|
2
|
+
/** The segments of a layout's file route, such as `blog.$slug`: `$` segments are params. */
|
|
3
|
+
function routeSegments(id) {
|
|
4
|
+
return id.split(".");
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The singleton or derived layout whose route matches `pathname`, a path in its Locale, with its
|
|
8
|
+
* params, or null. The route with the fewest params wins, so a singleton's fixed route wins over
|
|
9
|
+
* a derived route that would match it too. The SDK renders pages and the API checks them with it.
|
|
10
|
+
*/
|
|
11
|
+
function matchLayoutRoute(layouts, pathname, routeOf) {
|
|
12
|
+
const path = pathname.replace(/^\/|\/$/g, "").split("/");
|
|
13
|
+
const paramCount = (layout) => routeSegments(routeOf(layout).id).filter((s) => s.startsWith("$")).length;
|
|
14
|
+
const candidates = layouts.filter((layout) => routeOf(layout).kind !== "curated").sort((a, b) => paramCount(a) - paramCount(b));
|
|
15
|
+
for (const layout of candidates) {
|
|
16
|
+
const segments = routeSegments(routeOf(layout).id);
|
|
17
|
+
if (segments.length !== path.length) continue;
|
|
18
|
+
const params = {};
|
|
19
|
+
let matches = true;
|
|
20
|
+
for (const [index, segment] of segments.entries()) {
|
|
21
|
+
let value;
|
|
22
|
+
try {
|
|
23
|
+
value = decodeURIComponent(path[index]);
|
|
24
|
+
} catch {
|
|
25
|
+
matches = false;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
if (segment.startsWith("$") && value && !value.includes("/")) params[segment.slice(1)] = value;
|
|
29
|
+
else if (segment !== value) {
|
|
30
|
+
matches = false;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (matches) return {
|
|
35
|
+
layout,
|
|
36
|
+
params
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { matchLayoutRoute, routeSegments };
|
package/dist/patrol.d.ts
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
* studio shows it at the top of the Agent Sidebar. The API reads it for one scope, a draft or
|
|
5
5
|
* Live, and names each report's subject, so the studio needs no entity loaded to show it.
|
|
6
6
|
*/
|
|
7
|
-
/**
|
|
8
|
-
export
|
|
7
|
+
/** Every patroller's stable id. The registry in the API lists them all. */
|
|
8
|
+
export declare const PATROLLER_IDS: readonly ["translator", "seoManager", "linkChecker", "proofreader"];
|
|
9
|
+
/** A patroller's stable id. */
|
|
10
|
+
export type PatrollerId = (typeof PATROLLER_IDS)[number];
|
|
9
11
|
/**
|
|
10
12
|
* What a structured report says was done. Each has a failed form, by the report's outcome. A
|
|
11
13
|
* merge with Live's localization reads as a translation.
|
|
12
14
|
*/
|
|
13
|
-
export type ReportVerb = "translated" | "mergedWithLive" | "wroteSeo" | "describedFile" | "publishedCatchUp";
|
|
15
|
+
export type ReportVerb = "translated" | "mergedWithLive" | "wroteSeo" | "describedFile" | "publishedCatchUp" | "removedLink" | "fixedLink" | "fixedMistake";
|
|
14
16
|
/** What a report can be about. */
|
|
15
17
|
export type ReportEntity = "page" | "block" | "sharedContent" | "repeatableItem" | "record" | "file";
|
|
16
18
|
/** A report's subject, named as the Canvas names it, read when the Patrol is. */
|
|
@@ -41,8 +43,11 @@ export declare const reportLocale: (summary: {
|
|
|
41
43
|
}) => string | null;
|
|
42
44
|
/** Whether the work was done, or failed. A failure shows in its report only. */
|
|
43
45
|
export type ReportOutcome = "done" | "failed";
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Where a patroller is on duty, in drafts or on Live: it works as you go, checks when you
|
|
48
|
+
* publish, or is off there (ADR 0034).
|
|
49
|
+
*/
|
|
50
|
+
export type PatrollerDuty = "asYouGo" | "atPublish" | "off";
|
|
46
51
|
/**
|
|
47
52
|
* Where the studio shows a report's subject: a page on the Canvas, with the block and repeatable
|
|
48
53
|
* item to select on it, a collection record, or a file.
|
|
@@ -65,7 +70,6 @@ export type ReportView = {
|
|
|
65
70
|
id: string;
|
|
66
71
|
summary: ReportSummary;
|
|
67
72
|
outcome: ReportOutcome;
|
|
68
|
-
attention: AttentionLevel;
|
|
69
73
|
/** When the work last settled, in milliseconds since the epoch. */
|
|
70
74
|
at: number;
|
|
71
75
|
/** Whether the report is Live's, seen from a draft or from Live. */
|
|
@@ -76,6 +80,89 @@ export type ReportView = {
|
|
|
76
80
|
*/
|
|
77
81
|
place: ReportPlace | null;
|
|
78
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* What a finding is about (ADR 0034), by its kind:
|
|
85
|
+
* - `missingPage`: a link to a page that doesn't exist, the page's name as it was last known.
|
|
86
|
+
* - `brokenLink`: an external link that failed, and how.
|
|
87
|
+
* - `misspelling`, `grammar`: the flagged text, in the sentence it's in.
|
|
88
|
+
* A link's `url` is as content stores it: a page link's is `camox:page:<id>`, and `text` is what
|
|
89
|
+
* the link reads.
|
|
90
|
+
*/
|
|
91
|
+
export type FindingAbout = {
|
|
92
|
+
kind: "missingPage";
|
|
93
|
+
url: string;
|
|
94
|
+
text: string;
|
|
95
|
+
page: string | null;
|
|
96
|
+
} | {
|
|
97
|
+
kind: "brokenLink";
|
|
98
|
+
url: string;
|
|
99
|
+
text: string;
|
|
100
|
+
failure: LinkFailure;
|
|
101
|
+
} | {
|
|
102
|
+
kind: "misspelling" | "grammar";
|
|
103
|
+
text: string;
|
|
104
|
+
sentence: string;
|
|
105
|
+
};
|
|
106
|
+
/** How a link failed: an HTTP error status, no connection (DNS included), or no answer in time. */
|
|
107
|
+
export type LinkFailure = {
|
|
108
|
+
kind: "status";
|
|
109
|
+
status: number;
|
|
110
|
+
} | {
|
|
111
|
+
kind: "unreachable";
|
|
112
|
+
} | {
|
|
113
|
+
kind: "timeout";
|
|
114
|
+
};
|
|
115
|
+
export type FindingKind = FindingAbout["kind"];
|
|
116
|
+
/**
|
|
117
|
+
* The fix a finding suggests, which applying makes: removing the link, keeping its text, or
|
|
118
|
+
* replacing the flagged text with `replacement` in its sentence, keeping its formatting.
|
|
119
|
+
*/
|
|
120
|
+
export type FindingFix = {
|
|
121
|
+
kind: "removeLink";
|
|
122
|
+
} | {
|
|
123
|
+
kind: "replaceText";
|
|
124
|
+
replacement: string;
|
|
125
|
+
};
|
|
126
|
+
/** A finding, open, in the scope viewed. */
|
|
127
|
+
export type FindingView = {
|
|
128
|
+
/** What applying or dismissing it names. */
|
|
129
|
+
id: number;
|
|
130
|
+
about: FindingAbout;
|
|
131
|
+
/** The fix it suggests, if any. */
|
|
132
|
+
fix: FindingFix | null;
|
|
133
|
+
/** The content it's in, named in its locale. */
|
|
134
|
+
subject: ReportSubject;
|
|
135
|
+
/** The locale of the content it's in, by its tag. */
|
|
136
|
+
locale: string;
|
|
137
|
+
/** The content field it's in, by name. */
|
|
138
|
+
field: string;
|
|
139
|
+
/** When it was first raised, in milliseconds since the epoch. */
|
|
140
|
+
raisedAt: number;
|
|
141
|
+
/** Whether it's Live's. Live's are fixed in the Patrol Draft. */
|
|
142
|
+
live: boolean;
|
|
143
|
+
/** Where its content shows, as for reports. */
|
|
144
|
+
place: ReportPlace | null;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* A finding as one sentence, as the studio, emails, Briefs and refusals word it: "“About us” in
|
|
148
|
+
* Footer links to About, a page that no longer exists".
|
|
149
|
+
*/
|
|
150
|
+
export declare function findingSentence(finding: Pick<FindingView, "about" | "subject">): string;
|
|
151
|
+
/** A member's dismissal of what a finding was about: no finding like it is raised again. */
|
|
152
|
+
export type DismissalView = {
|
|
153
|
+
id: number;
|
|
154
|
+
about: FindingAbout;
|
|
155
|
+
by: {
|
|
156
|
+
id: string;
|
|
157
|
+
name: string;
|
|
158
|
+
};
|
|
159
|
+
/** When it was dismissed, in milliseconds since the epoch. */
|
|
160
|
+
at: number;
|
|
161
|
+
};
|
|
162
|
+
/** What applying a finding's fix did: applied it, or found its content changed and rechecked. */
|
|
163
|
+
export type ApplyResult = {
|
|
164
|
+
applied: boolean;
|
|
165
|
+
};
|
|
79
166
|
/** How many subjects a patroller is on in one locale, a locale's tag. */
|
|
80
167
|
export type LocaleCount = {
|
|
81
168
|
locale: string;
|
|
@@ -93,9 +180,19 @@ export type PatrollerView = {
|
|
|
93
180
|
id: PatrollerId;
|
|
94
181
|
/** Its role, as editors know it: "Translator", "SEO manager". */
|
|
95
182
|
role: string;
|
|
183
|
+
/** Its duty in the scope viewed. Off there, it still has its reports. */
|
|
184
|
+
duty: PatrollerDuty;
|
|
96
185
|
/** Null when it isn't working in the scope. */
|
|
97
186
|
working: PatrollerWorking | null;
|
|
98
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* When it last finished a check in the scope, whether it found anything or not, or null when it
|
|
189
|
+
* never checked there.
|
|
190
|
+
*/
|
|
191
|
+
lastCheckedAt: number | null;
|
|
192
|
+
/**
|
|
193
|
+
* Its latest activity in the scope: its last check, its newest report or when its pending work
|
|
194
|
+
* started, whichever is later. Null when it never worked there.
|
|
195
|
+
*/
|
|
99
196
|
lastActivityAt: number | null;
|
|
100
197
|
/** Its newest reports, newest first. */
|
|
101
198
|
reports: ReportView[];
|
|
@@ -104,10 +201,21 @@ export type PatrollerView = {
|
|
|
104
201
|
locale: string | null;
|
|
105
202
|
count: number;
|
|
106
203
|
}[];
|
|
204
|
+
/** Its open findings in the scope viewed, the oldest first. Their count is the row's badge. */
|
|
205
|
+
findings: FindingView[];
|
|
206
|
+
/** The project's dismissals of its findings, the newest first. */
|
|
207
|
+
dismissals: DismissalView[];
|
|
107
208
|
};
|
|
108
|
-
/**
|
|
209
|
+
/**
|
|
210
|
+
* Every patroller of the registry, the latest activity first; never-worked ones last. With the
|
|
211
|
+
* project's open Patrol Draft, where Live's findings are fixed, if any.
|
|
212
|
+
*/
|
|
109
213
|
export type PatrolView = {
|
|
110
214
|
patrollers: PatrollerView[];
|
|
215
|
+
patrolDraft: {
|
|
216
|
+
id: string;
|
|
217
|
+
name: string | null;
|
|
218
|
+
} | null;
|
|
111
219
|
};
|
|
112
220
|
/** How many reports the Patrol shows of each patroller; the rest are counted. */
|
|
113
221
|
export declare const REPORTS_SHOWN = 5;
|
package/dist/patrol.js
CHANGED
|
@@ -1,8 +1,40 @@
|
|
|
1
1
|
//#region src/patrol.ts
|
|
2
|
+
/**
|
|
3
|
+
* The Patrol (ADR 0024): every patroller of a project, the work each did as reports, as the
|
|
4
|
+
* studio shows it at the top of the Agent Sidebar. The API reads it for one scope, a draft or
|
|
5
|
+
* Live, and names each report's subject, so the studio needs no entity loaded to show it.
|
|
6
|
+
*/
|
|
7
|
+
/** Every patroller's stable id. The registry in the API lists them all. */
|
|
8
|
+
const PATROLLER_IDS = [
|
|
9
|
+
"translator",
|
|
10
|
+
"seoManager",
|
|
11
|
+
"linkChecker",
|
|
12
|
+
"proofreader"
|
|
13
|
+
];
|
|
2
14
|
/** The locale a summary's work was in: a structured summary's, if any. A text summary has none. */
|
|
3
15
|
const reportLocale = (summary) => summary.kind === "structured" ? summary.locale : null;
|
|
16
|
+
/** What a finding is about, after where it is: "links to About, a page that no longer exists". */
|
|
17
|
+
function aboutSentence(about) {
|
|
18
|
+
switch (about.kind) {
|
|
19
|
+
case "missingPage": return about.page === null ? "links to a page that no longer exists" : `links to ${about.page}, a page that no longer exists`;
|
|
20
|
+
case "brokenLink": {
|
|
21
|
+
const { failure } = about;
|
|
22
|
+
const how = failure.kind === "status" ? `answers with an error (${failure.status})` : failure.kind === "timeout" ? "doesn't answer in time" : "can't be reached";
|
|
23
|
+
return `links to ${about.url}, which ${how}`;
|
|
24
|
+
}
|
|
25
|
+
case "misspelling": return "may be misspelled";
|
|
26
|
+
case "grammar": return "may be a grammar mistake";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A finding as one sentence, as the studio, emails, Briefs and refusals word it: "“About us” in
|
|
31
|
+
* Footer links to About, a page that no longer exists".
|
|
32
|
+
*/
|
|
33
|
+
function findingSentence(finding) {
|
|
34
|
+
return `“${finding.about.text}” in ${finding.subject.name} ${aboutSentence(finding.about)}`;
|
|
35
|
+
}
|
|
4
36
|
/** How many reports the Patrol shows of each patroller; the rest are counted. */
|
|
5
37
|
const REPORTS_SHOWN = 5;
|
|
6
38
|
|
|
7
39
|
//#endregion
|
|
8
|
-
export { REPORTS_SHOWN, reportLocale };
|
|
40
|
+
export { PATROLLER_IDS, REPORTS_SHOWN, findingSentence, reportLocale };
|