saturndocs 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/dist/auth-FRCFGNYT.js +14 -0
- package/dist/brokenLinks-TTOBP4P7.js +48 -0
- package/dist/build-F5PWGP57.js +39 -0
- package/dist/chunk-3P2OFTXR.js +71 -0
- package/dist/chunk-3V753MRI.js +100 -0
- package/dist/chunk-5KX4ZK5E.js +104 -0
- package/dist/chunk-CMNX5DLQ.js +119 -0
- package/dist/chunk-GYRVGWDM.js +3499 -0
- package/dist/chunk-I6U4V7B4.js +1552 -0
- package/dist/chunk-J6P3VGGE.js +21 -0
- package/dist/chunk-KGJESHJC.js +37 -0
- package/dist/chunk-M2BZEDAS.js +57 -0
- package/dist/chunk-N7QPZMLP.js +82 -0
- package/dist/chunk-OEAEX5YW.js +51 -0
- package/dist/chunk-OZWTXMO3.js +584 -0
- package/dist/chunk-QLFODLVN.js +46 -0
- package/dist/chunk-R3X2DPFF.js +568 -0
- package/dist/chunk-S45UWCML.js +588 -0
- package/dist/chunk-SABK3R2P.js +2452 -0
- package/dist/chunk-STCCGFKC.js +246 -0
- package/dist/chunk-TKISMN3P.js +39 -0
- package/dist/chunk-U7PKMSB3.js +465 -0
- package/dist/chunk-VNYDYHXM.js +22 -0
- package/dist/chunk-VXEUNRVA.js +26 -0
- package/dist/chunk-XO4CUC7V.js +99 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +95 -0
- package/dist/deploy-QU7DCKWU.js +11 -0
- package/dist/dev-VDSDCBO2.js +43 -0
- package/dist/index.d.ts +382 -0
- package/dist/index.js +191 -0
- package/dist/init-7T5TEPBH.js +14 -0
- package/dist/manage-MKH27U3B.js +12 -0
- package/dist/openapiCheck-KGBQJTIQ.js +66 -0
- package/dist/pages-HIPXRLSY.js +15 -0
- package/dist/read-DMSJUEDA.js +160 -0
- package/dist/read-ZEVUZNNB.js +146 -0
- package/dist/requests-H5MIGBIS.js +13 -0
- package/dist/schema-XJUEZSIW.js +13 -0
- package/dist/sites-I4WI2MPG.js +14 -0
- package/dist/status-7R3NOI5H.js +14 -0
- package/dist/suggestions-4WFQ3APX.js +739 -0
- package/dist/validate-VXL4PL42.js +30 -0
- package/package.json +68 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBundleArchive,
|
|
3
|
+
deployBundle
|
|
4
|
+
} from "./chunk-I6U4V7B4.js";
|
|
5
|
+
import {
|
|
6
|
+
scanBrokenLinks
|
|
7
|
+
} from "./chunk-OEAEX5YW.js";
|
|
8
|
+
import {
|
|
9
|
+
renderTable
|
|
10
|
+
} from "./chunk-J6P3VGGE.js";
|
|
11
|
+
import {
|
|
12
|
+
PAGES_METADATA,
|
|
13
|
+
pagesLimitations,
|
|
14
|
+
registerPages
|
|
15
|
+
} from "./chunk-XO4CUC7V.js";
|
|
16
|
+
import {
|
|
17
|
+
STATUS_METADATA,
|
|
18
|
+
registerStatus,
|
|
19
|
+
statusText
|
|
20
|
+
} from "./chunk-3V753MRI.js";
|
|
21
|
+
import {
|
|
22
|
+
BrandFetcher,
|
|
23
|
+
DEFAULT_PRIMARY_COLOR,
|
|
24
|
+
buildDocsConfig,
|
|
25
|
+
colorToHex,
|
|
26
|
+
deriveDocsJson,
|
|
27
|
+
extensionForContentType,
|
|
28
|
+
extractBrandFromUrl,
|
|
29
|
+
extractBrandText,
|
|
30
|
+
extractCssColorCandidates,
|
|
31
|
+
extractManifestUrl,
|
|
32
|
+
extractStylesheetUrls,
|
|
33
|
+
extractThemeColorMetas,
|
|
34
|
+
fetchBrandAsset,
|
|
35
|
+
normalizeHexColor,
|
|
36
|
+
normalizeHttpUrl,
|
|
37
|
+
parseCssColor,
|
|
38
|
+
pickPrimaryColor,
|
|
39
|
+
scaffoldDocsProject,
|
|
40
|
+
scoreColorCandidates,
|
|
41
|
+
selectLogoAssets
|
|
42
|
+
} from "./chunk-SABK3R2P.js";
|
|
43
|
+
import {
|
|
44
|
+
collectPageEntries,
|
|
45
|
+
pageUrl,
|
|
46
|
+
resolvePageFile,
|
|
47
|
+
validateDocs
|
|
48
|
+
} from "./chunk-OZWTXMO3.js";
|
|
49
|
+
import "./chunk-S45UWCML.js";
|
|
50
|
+
import "./chunk-R3X2DPFF.js";
|
|
51
|
+
import {
|
|
52
|
+
findWebDir,
|
|
53
|
+
findWorkspaceRoot
|
|
54
|
+
} from "./chunk-VXEUNRVA.js";
|
|
55
|
+
import "./chunk-VNYDYHXM.js";
|
|
56
|
+
import {
|
|
57
|
+
MANAGE_METADATA
|
|
58
|
+
} from "./chunk-STCCGFKC.js";
|
|
59
|
+
import {
|
|
60
|
+
REQUESTS_CREATE_METADATA,
|
|
61
|
+
REQUESTS_METADATA,
|
|
62
|
+
registerRequests,
|
|
63
|
+
registerRequestsCreate
|
|
64
|
+
} from "./chunk-U7PKMSB3.js";
|
|
65
|
+
import {
|
|
66
|
+
STDIN_BYTE_CEILING,
|
|
67
|
+
readTextInput
|
|
68
|
+
} from "./chunk-N7QPZMLP.js";
|
|
69
|
+
import {
|
|
70
|
+
SCHEMA_METADATA,
|
|
71
|
+
registerSchema,
|
|
72
|
+
schemaDocument
|
|
73
|
+
} from "./chunk-5KX4ZK5E.js";
|
|
74
|
+
import {
|
|
75
|
+
COMMAND_GROUPS,
|
|
76
|
+
COMMAND_GROUP_NAMES,
|
|
77
|
+
findCommandGroup,
|
|
78
|
+
selectCommandGroup
|
|
79
|
+
} from "./chunk-QLFODLVN.js";
|
|
80
|
+
import {
|
|
81
|
+
AUTH_METADATA,
|
|
82
|
+
authStatusOf,
|
|
83
|
+
registerAuth
|
|
84
|
+
} from "./chunk-3P2OFTXR.js";
|
|
85
|
+
import {
|
|
86
|
+
SITES_METADATA,
|
|
87
|
+
registerSites,
|
|
88
|
+
requestedSite
|
|
89
|
+
} from "./chunk-CMNX5DLQ.js";
|
|
90
|
+
import {
|
|
91
|
+
TOKEN_VARIABLE,
|
|
92
|
+
asCliError,
|
|
93
|
+
clientFor
|
|
94
|
+
} from "./chunk-TKISMN3P.js";
|
|
95
|
+
import {
|
|
96
|
+
installInterrupt,
|
|
97
|
+
interruptSignal
|
|
98
|
+
} from "./chunk-KGJESHJC.js";
|
|
99
|
+
import {
|
|
100
|
+
applyCommandHelp,
|
|
101
|
+
helpBody
|
|
102
|
+
} from "./chunk-M2BZEDAS.js";
|
|
103
|
+
import {
|
|
104
|
+
CliError,
|
|
105
|
+
applyGlobalFlags,
|
|
106
|
+
applyGlobalFlagsDeep,
|
|
107
|
+
clientError,
|
|
108
|
+
createResultWriter,
|
|
109
|
+
failureResult,
|
|
110
|
+
interrupted,
|
|
111
|
+
invalidInput,
|
|
112
|
+
resolveGlobalOptions,
|
|
113
|
+
successResult,
|
|
114
|
+
wantsJson
|
|
115
|
+
} from "./chunk-GYRVGWDM.js";
|
|
116
|
+
export {
|
|
117
|
+
AUTH_METADATA,
|
|
118
|
+
BrandFetcher,
|
|
119
|
+
COMMAND_GROUPS,
|
|
120
|
+
COMMAND_GROUP_NAMES,
|
|
121
|
+
CliError,
|
|
122
|
+
DEFAULT_PRIMARY_COLOR,
|
|
123
|
+
MANAGE_METADATA,
|
|
124
|
+
PAGES_METADATA,
|
|
125
|
+
REQUESTS_CREATE_METADATA,
|
|
126
|
+
REQUESTS_METADATA,
|
|
127
|
+
SCHEMA_METADATA,
|
|
128
|
+
SITES_METADATA,
|
|
129
|
+
STATUS_METADATA,
|
|
130
|
+
STDIN_BYTE_CEILING,
|
|
131
|
+
TOKEN_VARIABLE,
|
|
132
|
+
applyCommandHelp,
|
|
133
|
+
applyGlobalFlags,
|
|
134
|
+
applyGlobalFlagsDeep,
|
|
135
|
+
asCliError,
|
|
136
|
+
authStatusOf,
|
|
137
|
+
buildDocsConfig,
|
|
138
|
+
clientError,
|
|
139
|
+
clientFor,
|
|
140
|
+
collectPageEntries,
|
|
141
|
+
colorToHex,
|
|
142
|
+
createBundleArchive,
|
|
143
|
+
createResultWriter,
|
|
144
|
+
deployBundle,
|
|
145
|
+
deriveDocsJson,
|
|
146
|
+
extensionForContentType,
|
|
147
|
+
extractBrandFromUrl,
|
|
148
|
+
extractBrandText,
|
|
149
|
+
extractCssColorCandidates,
|
|
150
|
+
extractManifestUrl,
|
|
151
|
+
extractStylesheetUrls,
|
|
152
|
+
extractThemeColorMetas,
|
|
153
|
+
failureResult,
|
|
154
|
+
fetchBrandAsset,
|
|
155
|
+
findCommandGroup,
|
|
156
|
+
findWebDir,
|
|
157
|
+
findWorkspaceRoot,
|
|
158
|
+
helpBody,
|
|
159
|
+
installInterrupt,
|
|
160
|
+
interruptSignal,
|
|
161
|
+
interrupted,
|
|
162
|
+
invalidInput,
|
|
163
|
+
normalizeHexColor,
|
|
164
|
+
normalizeHttpUrl,
|
|
165
|
+
pageUrl,
|
|
166
|
+
pagesLimitations,
|
|
167
|
+
parseCssColor,
|
|
168
|
+
pickPrimaryColor,
|
|
169
|
+
readTextInput,
|
|
170
|
+
registerAuth,
|
|
171
|
+
registerPages,
|
|
172
|
+
registerRequests,
|
|
173
|
+
registerRequestsCreate,
|
|
174
|
+
registerSchema,
|
|
175
|
+
registerSites,
|
|
176
|
+
registerStatus,
|
|
177
|
+
renderTable,
|
|
178
|
+
requestedSite,
|
|
179
|
+
resolveGlobalOptions,
|
|
180
|
+
resolvePageFile,
|
|
181
|
+
scaffoldDocsProject,
|
|
182
|
+
scanBrokenLinks,
|
|
183
|
+
schemaDocument,
|
|
184
|
+
scoreColorCandidates,
|
|
185
|
+
selectCommandGroup,
|
|
186
|
+
selectLogoAssets,
|
|
187
|
+
statusText,
|
|
188
|
+
successResult,
|
|
189
|
+
validateDocs,
|
|
190
|
+
wantsJson
|
|
191
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildDocsConfig,
|
|
3
|
+
printExtractionReport,
|
|
4
|
+
registerInit,
|
|
5
|
+
scaffoldDocsProject
|
|
6
|
+
} from "./chunk-SABK3R2P.js";
|
|
7
|
+
import "./chunk-R3X2DPFF.js";
|
|
8
|
+
import "./chunk-VNYDYHXM.js";
|
|
9
|
+
export {
|
|
10
|
+
buildDocsConfig,
|
|
11
|
+
printExtractionReport,
|
|
12
|
+
registerInit,
|
|
13
|
+
scaffoldDocsProject
|
|
14
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderTable
|
|
3
|
+
} from "./chunk-J6P3VGGE.js";
|
|
4
|
+
import {
|
|
5
|
+
parseOpenApiFile
|
|
6
|
+
} from "./chunk-S45UWCML.js";
|
|
7
|
+
import {
|
|
8
|
+
loadDocsConfig,
|
|
9
|
+
navigationGroups
|
|
10
|
+
} from "./chunk-R3X2DPFF.js";
|
|
11
|
+
import {
|
|
12
|
+
messageOf,
|
|
13
|
+
resolveDocsDir
|
|
14
|
+
} from "./chunk-VNYDYHXM.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/openapiCheck.ts
|
|
17
|
+
import { existsSync } from "fs";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
import pc from "picocolors";
|
|
20
|
+
function registerOpenapiCheck(program) {
|
|
21
|
+
program.command("openapi-check").description("Parse OpenAPI specs and print an operation table").argument("[dir]", "docs directory (contains docs.json)").action(async (dir) => {
|
|
22
|
+
const docsDir = resolveDocsDir(dir);
|
|
23
|
+
const config = await loadDocsConfig(join(docsDir, "docs.json"));
|
|
24
|
+
const specs = navigationGroups(config).filter((group) => group.openapi);
|
|
25
|
+
if (specs.length === 0) {
|
|
26
|
+
console.log(pc.dim("No navigation groups declare an openapi file."));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let hadError = false;
|
|
30
|
+
for (const group of specs) {
|
|
31
|
+
const openapiRel = group.openapi;
|
|
32
|
+
const openapiPath = join(docsDir, openapiRel);
|
|
33
|
+
console.log(pc.bold(`
|
|
34
|
+
${group.group} \u2014 ${openapiRel}`));
|
|
35
|
+
if (!existsSync(openapiPath)) {
|
|
36
|
+
console.error(pc.red(` error: file not found: ${openapiRel}`));
|
|
37
|
+
hadError = true;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const spec = await parseOpenApiFile(openapiPath);
|
|
42
|
+
console.log(pc.dim(` ${spec.title} v${spec.version}`));
|
|
43
|
+
const rows = spec.operations.map((op) => [
|
|
44
|
+
op.method.toUpperCase(),
|
|
45
|
+
op.path,
|
|
46
|
+
op.slug,
|
|
47
|
+
op.summary ?? ""
|
|
48
|
+
]);
|
|
49
|
+
const table = renderTable(
|
|
50
|
+
["METHOD", "PATH", "SLUG", "SUMMARY"],
|
|
51
|
+
rows
|
|
52
|
+
);
|
|
53
|
+
console.log(
|
|
54
|
+
table.split("\n").map((line) => ` ${line}`).join("\n")
|
|
55
|
+
);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(pc.red(` error: ${messageOf(error)}`));
|
|
58
|
+
hadError = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (hadError) process.exit(1);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
registerOpenapiCheck
|
|
66
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PAGES_METADATA,
|
|
3
|
+
pagesLimitations,
|
|
4
|
+
registerPages
|
|
5
|
+
} from "./chunk-XO4CUC7V.js";
|
|
6
|
+
import "./chunk-CMNX5DLQ.js";
|
|
7
|
+
import "./chunk-TKISMN3P.js";
|
|
8
|
+
import "./chunk-KGJESHJC.js";
|
|
9
|
+
import "./chunk-M2BZEDAS.js";
|
|
10
|
+
import "./chunk-GYRVGWDM.js";
|
|
11
|
+
export {
|
|
12
|
+
PAGES_METADATA,
|
|
13
|
+
pagesLimitations,
|
|
14
|
+
registerPages
|
|
15
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requestedSite
|
|
3
|
+
} from "./chunk-CMNX5DLQ.js";
|
|
4
|
+
import {
|
|
5
|
+
asCliError,
|
|
6
|
+
clientFor
|
|
7
|
+
} from "./chunk-TKISMN3P.js";
|
|
8
|
+
import "./chunk-KGJESHJC.js";
|
|
9
|
+
import {
|
|
10
|
+
applyCommandHelp
|
|
11
|
+
} from "./chunk-M2BZEDAS.js";
|
|
12
|
+
import {
|
|
13
|
+
ACTIVITY_LIMIT_CEILING,
|
|
14
|
+
ACTIVITY_OUTCOMES,
|
|
15
|
+
CliError,
|
|
16
|
+
activityJobFound,
|
|
17
|
+
commandMetadata,
|
|
18
|
+
createResultWriter,
|
|
19
|
+
failureResult,
|
|
20
|
+
listActivity,
|
|
21
|
+
readActivityJob,
|
|
22
|
+
resolveGlobalOptions,
|
|
23
|
+
resolveTarget,
|
|
24
|
+
successResult
|
|
25
|
+
} from "./chunk-GYRVGWDM.js";
|
|
26
|
+
|
|
27
|
+
// src/commands/activity/read.ts
|
|
28
|
+
var ACTIVITY_METADATA = Object.freeze([
|
|
29
|
+
commandMetadata("activity list", {
|
|
30
|
+
description: `One page of operational activity, newest first: what the platform looked at, what it decided, and what failed. The filters are the ones the route keeps and no others: --cursor, --limit, --outcome (${ACTIVITY_OUTCOMES.join(", ")}), --repo, and the inclusive UTC dates --from and --to. A range or an outcome the server does not keep is refused here, before anything is read. A site nothing has happened on answers an empty page, which is not a read that failed.`,
|
|
31
|
+
target: { arguments: [{ name: "site-id", required: false, description: "The site to read. Defaults to the site the credential resolves to." }] },
|
|
32
|
+
effect: "Nothing. One read of one page of the activity log.",
|
|
33
|
+
output: { fields: ["site_id", "events", "next_cursor"], ids: [], limitations: ["page_bounded"] },
|
|
34
|
+
errors: ["invalid_input", "unauthorized", "forbidden", "not_found", "rate_limited", "service_unavailable", "transport_failure", "interrupted"],
|
|
35
|
+
examples: [
|
|
36
|
+
{ command: "saturndocs activity list", description: "The newest page of activity for the credential's site." },
|
|
37
|
+
{ command: "saturndocs activity list --outcome failed --from 2026-09-01 --to 2026-09-18", description: "Only the work that failed, over an inclusive UTC range." },
|
|
38
|
+
{ command: 'saturndocs activity list --cursor "2026-09-18T11:00:00.000Z|job-published" --json', description: "The next page, from the previous answer's next_cursor." }
|
|
39
|
+
]
|
|
40
|
+
}),
|
|
41
|
+
commandMetadata("activity get", {
|
|
42
|
+
description: "One job by id, read through the activity route's job_id filter rather than by scanning page one, so a job that queued before a hundred later events is still found. The answer keeps the job's progress, its outcome, its failure, and the suggestion, release, and pull request it is linked to. A job this site does not have is reported as not found; a job whose own work failed is a read that succeeded and exits 0.",
|
|
43
|
+
target: { arguments: [{ name: "job-id", required: true, description: "The job to read, as the server minted it." }] },
|
|
44
|
+
effect: "Nothing. One filtered read of the activity log.",
|
|
45
|
+
output: { fields: ["site_id", "job_id", "event"], ids: ["job_id", "suggestion_id", "release_id", "pr_number"], limitations: [] },
|
|
46
|
+
errors: ["invalid_input", "unauthorized", "forbidden", "not_found", "rate_limited", "service_unavailable", "transport_failure", "interrupted"],
|
|
47
|
+
examples: [
|
|
48
|
+
{ command: "saturndocs activity get job-example --site acme --json", description: "One job as a result object, with its durable identities in the envelope." },
|
|
49
|
+
{ command: "saturndocs activity get job-example", description: "The same read as a line of text." }
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
]);
|
|
53
|
+
function wholeNumber(value) {
|
|
54
|
+
return Number(value);
|
|
55
|
+
}
|
|
56
|
+
function activityLimitations(page, requestedLimit) {
|
|
57
|
+
const limitations = [];
|
|
58
|
+
if (page.next_cursor !== null) {
|
|
59
|
+
limitations.push({
|
|
60
|
+
code: "page_bounded",
|
|
61
|
+
message: `This is one page of the activity log, not the site's whole history. Read the next page with --cursor ${page.next_cursor}.`,
|
|
62
|
+
at: "events"
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (requestedLimit !== void 0 && requestedLimit > ACTIVITY_LIMIT_CEILING) {
|
|
66
|
+
limitations.push({
|
|
67
|
+
code: "page_bounded",
|
|
68
|
+
message: `The server returns at most ${ACTIVITY_LIMIT_CEILING} events per page, so --limit ${requestedLimit} was answered with that many at most.`,
|
|
69
|
+
at: "events"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return limitations;
|
|
73
|
+
}
|
|
74
|
+
function eventLine(event) {
|
|
75
|
+
const parts = [`${event.created_at} ${event.id} ${event.operation} ${event.state}`];
|
|
76
|
+
if (event.skip_reason != null) parts.push(`skipped ${event.skip_reason}`);
|
|
77
|
+
if (event.outcome_code !== null) parts.push(event.outcome_code);
|
|
78
|
+
if (event.error_code !== null) parts.push(`failed ${event.error_code}`);
|
|
79
|
+
if (event.repository !== null) parts.push(event.repository);
|
|
80
|
+
if (event.suggestion_id !== null) parts.push(`suggestion ${event.suggestion_id}`);
|
|
81
|
+
if (event.pr_number !== null) parts.push(`pr ${event.pr_number}`);
|
|
82
|
+
if (event.release != null) parts.push(`release ${event.release.release_id}`);
|
|
83
|
+
return parts.join(" ");
|
|
84
|
+
}
|
|
85
|
+
function listText(page) {
|
|
86
|
+
if (page.events.length === 0) {
|
|
87
|
+
return `${page.site_id}: no activity matched. That is an answer, not a failed read.`;
|
|
88
|
+
}
|
|
89
|
+
const tail = page.next_cursor === null ? "End of the log for these filters." : `More activity follows: --cursor ${page.next_cursor}`;
|
|
90
|
+
return [...page.events.map(eventLine), tail].join("\n");
|
|
91
|
+
}
|
|
92
|
+
function jobText(read) {
|
|
93
|
+
const event = read.event;
|
|
94
|
+
const lines = [
|
|
95
|
+
`job: ${event.id}`,
|
|
96
|
+
`site: ${read.site_id}`,
|
|
97
|
+
`operation: ${event.operation}`,
|
|
98
|
+
`state: ${event.state}${event.outcome_code === null ? "" : ` (${event.outcome_code})`}`,
|
|
99
|
+
`started: ${event.created_at}, last change ${event.updated_at}`,
|
|
100
|
+
event.error_code === null ? "failure: none" : `failure: ${event.error_code}${event.error_message === null ? "" : ` \u2014 ${event.error_message}`}`,
|
|
101
|
+
`repository: ${event.repository ?? "none recorded"}`,
|
|
102
|
+
`suggestion: ${event.suggestion_id ?? "none"}`,
|
|
103
|
+
`pull request: ${event.pr_number === null ? "none" : String(event.pr_number)}`,
|
|
104
|
+
`release: ${event.release == null ? "none" : event.release.release_id}`
|
|
105
|
+
];
|
|
106
|
+
if (event.skip_reason != null) lines.push(`skipped: ${event.skip_reason}`);
|
|
107
|
+
if (event.reason != null) lines.push(`reason: ${event.reason}`);
|
|
108
|
+
return lines.join("\n");
|
|
109
|
+
}
|
|
110
|
+
function identitiesOf(event) {
|
|
111
|
+
const ids = { job_id: event.id };
|
|
112
|
+
if (event.suggestion_id !== null) ids.suggestion_id = event.suggestion_id;
|
|
113
|
+
if (event.pr_number !== null) ids.pr_number = event.pr_number;
|
|
114
|
+
if (event.release != null) ids.release_id = event.release.release_id;
|
|
115
|
+
return ids;
|
|
116
|
+
}
|
|
117
|
+
function registerActivity(program, _cliDir, environment = {}) {
|
|
118
|
+
const activity = program.command("activity").description("Read what the platform did, and one job by id");
|
|
119
|
+
const list = activity.command("list").argument("[site-id]", "The site to read. Defaults to the site the credential resolves to.").option("--limit <n>", `Events per page, up to the server's ceiling of ${ACTIVITY_LIMIT_CEILING}.`, wholeNumber).action(async (siteId, options, self) => {
|
|
120
|
+
const globals = resolveGlobalOptions(self);
|
|
121
|
+
const writer = createResultWriter({ json: globals.json });
|
|
122
|
+
const context = { command: "activity list", siteId: null };
|
|
123
|
+
try {
|
|
124
|
+
const client = clientFor(globals, environment);
|
|
125
|
+
const named = requestedSite(siteId, globals.site);
|
|
126
|
+
const target = await resolveTarget(client, named === void 0 ? {} : { site: named });
|
|
127
|
+
context.siteId = target.site_id;
|
|
128
|
+
const page = await listActivity(client, target.site_id, options);
|
|
129
|
+
context.limitations = activityLimitations(page, options.limit);
|
|
130
|
+
process.exitCode = writer.write(successResult(context, page), { text: listText(page) });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
process.exitCode = writer.write(failureResult(asCliError(error), context));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
applyCommandHelp(list, ACTIVITY_METADATA[0]);
|
|
136
|
+
const get = activity.command("get").argument("<job-id>", "The job to read, as the server minted it.").action(async (jobId, _options, self) => {
|
|
137
|
+
const globals = resolveGlobalOptions(self);
|
|
138
|
+
const writer = createResultWriter({ json: globals.json });
|
|
139
|
+
const context = { command: "activity get", siteId: null };
|
|
140
|
+
try {
|
|
141
|
+
const client = clientFor(globals, environment);
|
|
142
|
+
const target = await resolveTarget(client, globals.site === null ? {} : { site: globals.site });
|
|
143
|
+
context.siteId = target.site_id;
|
|
144
|
+
const read = await readActivityJob(client, target.site_id, jobId);
|
|
145
|
+
if (!activityJobFound(read)) {
|
|
146
|
+
throw new CliError("not_found", `${target.site_id} has no job ${jobId}. The server answered with no events, which is this site not having that job rather than a read that failed.`);
|
|
147
|
+
}
|
|
148
|
+
context.ids = identitiesOf(read.event);
|
|
149
|
+
process.exitCode = writer.write(successResult(context, read), { text: jobText(read) });
|
|
150
|
+
} catch (error) {
|
|
151
|
+
process.exitCode = writer.write(failureResult(asCliError(error), context));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
applyCommandHelp(get, ACTIVITY_METADATA[1]);
|
|
155
|
+
}
|
|
156
|
+
export {
|
|
157
|
+
ACTIVITY_METADATA,
|
|
158
|
+
activityLimitations,
|
|
159
|
+
registerActivity
|
|
160
|
+
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requestedSite
|
|
3
|
+
} from "./chunk-CMNX5DLQ.js";
|
|
4
|
+
import {
|
|
5
|
+
asCliError,
|
|
6
|
+
clientFor
|
|
7
|
+
} from "./chunk-TKISMN3P.js";
|
|
8
|
+
import "./chunk-KGJESHJC.js";
|
|
9
|
+
import {
|
|
10
|
+
applyCommandHelp
|
|
11
|
+
} from "./chunk-M2BZEDAS.js";
|
|
12
|
+
import {
|
|
13
|
+
RELEASE_PAGE_MAX,
|
|
14
|
+
activeStatusOf,
|
|
15
|
+
classifyReleaseActivation,
|
|
16
|
+
commandMetadata,
|
|
17
|
+
createResultWriter,
|
|
18
|
+
failureResult,
|
|
19
|
+
getRelease,
|
|
20
|
+
listReleases,
|
|
21
|
+
resolveGlobalOptions,
|
|
22
|
+
resolveTarget,
|
|
23
|
+
successResult
|
|
24
|
+
} from "./chunk-GYRVGWDM.js";
|
|
25
|
+
|
|
26
|
+
// src/commands/releases/read.ts
|
|
27
|
+
import { InvalidArgumentError } from "commander";
|
|
28
|
+
var RELEASES_METADATA = Object.freeze([
|
|
29
|
+
commandMetadata("releases list", {
|
|
30
|
+
description: "Read one page of this site's releases, newest first, with when each one was built, what it was built from, the job behind it, and its activation record. The answer also carries which release the site is serving and whether that could be read at all: active_release_status unknown means the activation store did not answer, which is not the same as the site having no active release.",
|
|
31
|
+
target: { arguments: [{ name: "site-id", required: false, description: "The site to read. Defaults to the site the credential resolves to." }] },
|
|
32
|
+
effect: "Nothing. One read of the release listing.",
|
|
33
|
+
output: { fields: ["site_id", "active_release_id", "active_release_status", "releases", "next_cursor"], ids: ["release_id"], limitations: ["page_bounded", "activation_unknown"] },
|
|
34
|
+
errors: ["invalid_input", "unauthorized", "forbidden", "not_found", "rate_limited", "service_unavailable", "transport_failure", "interrupted"],
|
|
35
|
+
examples: [
|
|
36
|
+
{ command: "saturndocs releases list", description: "The newest page of releases and what the site is serving." },
|
|
37
|
+
{ command: "saturndocs releases list --limit 10", description: "A smaller page, within the route's ceiling of 50." },
|
|
38
|
+
{ command: "saturndocs releases list --cursor <next_cursor> --json", description: "The page after the one whose next_cursor this is." }
|
|
39
|
+
]
|
|
40
|
+
}),
|
|
41
|
+
commandMetadata("releases get", {
|
|
42
|
+
description: "Read one release by id through the listing's release_id filter, so a release older than the first page is found without paging to it. The release is reported as live, historical, or built: a release with no activation record was never published, and a release that was activated but is not the active one is history. An empty answer is that id not being this site's, and never a claim about which release is active.",
|
|
43
|
+
target: { arguments: [{ name: "release-id", required: true, description: "The release to read, as release_id." }] },
|
|
44
|
+
effect: "Nothing. One filtered read of the release listing.",
|
|
45
|
+
output: { fields: ["site_id", "release", "activation", "page"], ids: ["release_id", "job_id"], limitations: ["activation_unknown"] },
|
|
46
|
+
errors: ["invalid_input", "unauthorized", "forbidden", "not_found", "rate_limited", "service_unavailable", "transport_failure", "interrupted"],
|
|
47
|
+
examples: [
|
|
48
|
+
{ command: "saturndocs releases get old-release --site acme", description: "One release by id, including one built long before the newest page." },
|
|
49
|
+
{ command: "saturndocs releases get old-release --json", description: "The release, its activation, and the answer it came from as one result object." }
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
]);
|
|
53
|
+
function pageSize(value) {
|
|
54
|
+
const limit = Number(value);
|
|
55
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > RELEASE_PAGE_MAX) {
|
|
56
|
+
throw new InvalidArgumentError(`--limit takes a whole number from 1 to ${RELEASE_PAGE_MAX}; the route refuses anything else rather than trimming it.`);
|
|
57
|
+
}
|
|
58
|
+
return limit;
|
|
59
|
+
}
|
|
60
|
+
var UNKNOWN_ACTIVATION = {
|
|
61
|
+
code: "activation_unknown",
|
|
62
|
+
message: "The activation store did not answer, so which release readers are seeing could not be read. active_release_id null here means unread, not that the site has no active release.",
|
|
63
|
+
at: "active_release_id"
|
|
64
|
+
};
|
|
65
|
+
function releaseLimitations(page) {
|
|
66
|
+
const limitations = [];
|
|
67
|
+
if (activeStatusOf(page) === "unknown") limitations.push(UNKNOWN_ACTIVATION);
|
|
68
|
+
if (page.next_cursor !== null) {
|
|
69
|
+
limitations.push({
|
|
70
|
+
code: "page_bounded",
|
|
71
|
+
message: "This is one page of releases. Older releases remain behind next_cursor; read an exact one with releases get rather than paging to it.",
|
|
72
|
+
at: "releases"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return limitations;
|
|
76
|
+
}
|
|
77
|
+
function activeLine(page) {
|
|
78
|
+
if (activeStatusOf(page) === "unknown") return "active release: unknown \u2014 the activation record could not be read";
|
|
79
|
+
return page.active_release_id === null ? "active release: none reported" : `active release: ${page.active_release_id}`;
|
|
80
|
+
}
|
|
81
|
+
function listText(page) {
|
|
82
|
+
const rows = page.releases.map((release) => {
|
|
83
|
+
const activation = classifyReleaseActivation(release, page);
|
|
84
|
+
return `${release.release_id} ${release.state} built ${release.built_at} ${activation.state} job ${release.job.job_id}`;
|
|
85
|
+
});
|
|
86
|
+
const tail = page.next_cursor === null ? "end of the listing" : `more releases behind cursor ${page.next_cursor}`;
|
|
87
|
+
return [`${page.site_id}: ${page.releases.length} releases on this page`, activeLine(page), ...rows, tail].join("\n");
|
|
88
|
+
}
|
|
89
|
+
function getText(result) {
|
|
90
|
+
const { release, activation } = result;
|
|
91
|
+
return [
|
|
92
|
+
`release: ${release.release_id} (${release.state})`,
|
|
93
|
+
`built: ${release.built_at} from ${release.source_revision_id}${release.git_commit === null ? "" : ` at ${release.git_commit}`}`,
|
|
94
|
+
`digest: ${release.digest ?? "not recorded"}`,
|
|
95
|
+
`job: ${release.job.job_id}${release.job.operation === null ? "" : ` (${release.job.operation})`}${release.job.requested_by === null ? "" : ` requested by ${release.job.requested_by}`}`,
|
|
96
|
+
`activation: ${activation.state} \u2014 ${activation.summary}`,
|
|
97
|
+
activeLine(result.page)
|
|
98
|
+
].join("\n");
|
|
99
|
+
}
|
|
100
|
+
function registerReleases(program, _cliDir, environment = {}) {
|
|
101
|
+
const releases = program.command("releases").description("Read this site's release history and one release by id");
|
|
102
|
+
const list = releases.command("list").argument("[site-id]", "The site to read. Defaults to the site the credential resolves to.").option("--limit <n>", `Page size, from 1 to ${RELEASE_PAGE_MAX}.`, pageSize).action(async (siteId, options, self) => {
|
|
103
|
+
const globals = resolveGlobalOptions(self);
|
|
104
|
+
const writer = createResultWriter({ json: globals.json });
|
|
105
|
+
const context = { command: "releases list", siteId: null };
|
|
106
|
+
try {
|
|
107
|
+
const client = clientFor(globals, environment);
|
|
108
|
+
const named = requestedSite(siteId, globals.site);
|
|
109
|
+
const target = await resolveTarget(client, named === void 0 ? {} : { site: named });
|
|
110
|
+
context.siteId = target.site_id;
|
|
111
|
+
const page = await listReleases(client, target.site_id, {
|
|
112
|
+
...options.limit === void 0 ? {} : { limit: options.limit },
|
|
113
|
+
...options.cursor === void 0 ? {} : { cursor: options.cursor }
|
|
114
|
+
});
|
|
115
|
+
context.limitations = releaseLimitations(page);
|
|
116
|
+
if (page.active_release_id !== null && activeStatusOf(page) === "known") context.ids = { release_id: page.active_release_id };
|
|
117
|
+
process.exitCode = writer.write(successResult(context, page), { text: listText(page) });
|
|
118
|
+
} catch (error) {
|
|
119
|
+
process.exitCode = writer.write(failureResult(asCliError(error), context));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
applyCommandHelp(list, RELEASES_METADATA[0]);
|
|
123
|
+
const get = releases.command("get").argument("<release-id>", "The release to read, as release_id.").action(async (releaseId, _options, self) => {
|
|
124
|
+
const globals = resolveGlobalOptions(self);
|
|
125
|
+
const writer = createResultWriter({ json: globals.json });
|
|
126
|
+
const context = { command: "releases get", siteId: null };
|
|
127
|
+
try {
|
|
128
|
+
const client = clientFor(globals, environment);
|
|
129
|
+
const target = await resolveTarget(client, globals.site === null ? {} : { site: globals.site });
|
|
130
|
+
context.siteId = target.site_id;
|
|
131
|
+
context.ids = { release_id: releaseId };
|
|
132
|
+
const result = await getRelease(client, target.site_id, releaseId);
|
|
133
|
+
context.limitations = releaseLimitations(result.page);
|
|
134
|
+
context.ids = { release_id: result.release.release_id, job_id: result.release.job.job_id };
|
|
135
|
+
process.exitCode = writer.write(successResult(context, result), { text: getText(result) });
|
|
136
|
+
} catch (error) {
|
|
137
|
+
process.exitCode = writer.write(failureResult(asCliError(error), context));
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
applyCommandHelp(get, RELEASES_METADATA[1]);
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
RELEASES_METADATA,
|
|
144
|
+
registerReleases,
|
|
145
|
+
releaseLimitations
|
|
146
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
REQUESTS_METADATA,
|
|
3
|
+
registerRequests
|
|
4
|
+
} from "./chunk-U7PKMSB3.js";
|
|
5
|
+
import "./chunk-N7QPZMLP.js";
|
|
6
|
+
import "./chunk-TKISMN3P.js";
|
|
7
|
+
import "./chunk-KGJESHJC.js";
|
|
8
|
+
import "./chunk-M2BZEDAS.js";
|
|
9
|
+
import "./chunk-GYRVGWDM.js";
|
|
10
|
+
export {
|
|
11
|
+
REQUESTS_METADATA,
|
|
12
|
+
registerRequests
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SCHEMA_METADATA,
|
|
3
|
+
registerSchema,
|
|
4
|
+
schemaDocument
|
|
5
|
+
} from "./chunk-5KX4ZK5E.js";
|
|
6
|
+
import "./chunk-QLFODLVN.js";
|
|
7
|
+
import "./chunk-M2BZEDAS.js";
|
|
8
|
+
import "./chunk-GYRVGWDM.js";
|
|
9
|
+
export {
|
|
10
|
+
SCHEMA_METADATA,
|
|
11
|
+
registerSchema,
|
|
12
|
+
schemaDocument
|
|
13
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SITES_METADATA,
|
|
3
|
+
registerSites,
|
|
4
|
+
requestedSite
|
|
5
|
+
} from "./chunk-CMNX5DLQ.js";
|
|
6
|
+
import "./chunk-TKISMN3P.js";
|
|
7
|
+
import "./chunk-KGJESHJC.js";
|
|
8
|
+
import "./chunk-M2BZEDAS.js";
|
|
9
|
+
import "./chunk-GYRVGWDM.js";
|
|
10
|
+
export {
|
|
11
|
+
SITES_METADATA,
|
|
12
|
+
registerSites,
|
|
13
|
+
requestedSite
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STATUS_METADATA,
|
|
3
|
+
registerStatus,
|
|
4
|
+
statusText
|
|
5
|
+
} from "./chunk-3V753MRI.js";
|
|
6
|
+
import "./chunk-TKISMN3P.js";
|
|
7
|
+
import "./chunk-KGJESHJC.js";
|
|
8
|
+
import "./chunk-M2BZEDAS.js";
|
|
9
|
+
import "./chunk-GYRVGWDM.js";
|
|
10
|
+
export {
|
|
11
|
+
STATUS_METADATA,
|
|
12
|
+
registerStatus,
|
|
13
|
+
statusText
|
|
14
|
+
};
|