@taprootio/site-authoring 0.7.2 → 0.8.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/README.md +36 -13
- package/package.json +1 -1
- package/src/api.js +15 -4
- package/src/cli.js +68 -5
- package/src/config.js +15 -0
- package/src/constants.js +10 -1
- package/src/content/free-form-section-registry.json +44 -1
- package/src/content/tiptap-prosemirror.ts +38 -0
- package/src/content/validate-document.js +17 -0
- package/src/content/vocabulary.js +2 -0
- package/src/fixture-init.js +5 -0
- package/src/reference-help.js +12 -1
- package/src/session.js +83 -10
- package/src/surface.js +152 -0
- package/src/verbs/deploy.js +51 -7
- package/src/verbs/pull.js +54 -24
- package/src/verbs/sites.js +13 -8
- package/src/verbs/status.js +43 -9
- package/src/verbs/use.js +22 -3
- package/src/verbs/whoami.js +9 -1
package/src/verbs/status.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
PUBLISH_KEY_ENVIRONMENT_VARIABLE,
|
|
18
18
|
REFUSAL_CLI_OUTDATED,
|
|
19
19
|
REFUSAL_PLATFORM_PAUSED,
|
|
20
|
+
SURFACE_DOCS_PRESENTATION,
|
|
20
21
|
VERB_STATUS,
|
|
21
22
|
} from "../constants.js";
|
|
22
23
|
import { boundedList, openSession, successResult } from "../session.js";
|
|
@@ -100,8 +101,20 @@ function reportPlatform(platform, onProgress) {
|
|
|
100
101
|
return { externalWritesEnabled: enabled };
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* What a managed Docs site's status leaves out (TR00790), said the same way
|
|
106
|
+
* the platform switch says "unknown": by shape. The image library and the
|
|
107
|
+
* broken-reference report are page-authoring reads a Docs site refuses, so
|
|
108
|
+
* they are reported as not covered rather than as empty — an automation
|
|
109
|
+
* reading `failed: 0` off a report that was never made would be reading a lie.
|
|
110
|
+
*/
|
|
111
|
+
const DOCS_SITE_NOT_COVERED_NOTE =
|
|
112
|
+
"This is a managed Docs site: its pages come from the Docs artifact, so the image library and broken-reference "
|
|
113
|
+
+ "reads do not apply and were not made.";
|
|
114
|
+
|
|
103
115
|
export async function status(invocation) {
|
|
104
|
-
const { client, siteId, platform, release, onProgress } = await openSession(invocation);
|
|
116
|
+
const { client, siteId, surface, platform, release, onProgress } = await openSession(invocation);
|
|
117
|
+
const presentationOnly = surface === SURFACE_DOCS_PRESENTATION;
|
|
105
118
|
// Said first, and before any wire read: an operator running `status` because
|
|
106
119
|
// writes are being refused should not have to wait on network calls to
|
|
107
120
|
// learn that the platform is paused — and this answer needs none of them.
|
|
@@ -110,7 +123,15 @@ export async function status(invocation) {
|
|
|
110
123
|
|
|
111
124
|
return await withRefusalGuidance(onProgress, "status check", async () => {
|
|
112
125
|
onProgress("Reading publishing readiness.");
|
|
113
|
-
const
|
|
126
|
+
const reviewed = await getDeploySelection(client, siteId);
|
|
127
|
+
// The review is site-type-blind: a managed Docs site's settings-only
|
|
128
|
+
// production manifest makes any draft navigation row read as changed
|
|
129
|
+
// forever. Readiness is asked about the candidate `deploy` would actually
|
|
130
|
+
// send there — settings only — so hasCandidateChanges answers for it
|
|
131
|
+
// (TR00790).
|
|
132
|
+
const selection = presentationOnly
|
|
133
|
+
? { ...reviewed, stagedPageIds: [], includeNavigation: false }
|
|
134
|
+
: reviewed;
|
|
114
135
|
const readiness = await getPublishingReadiness(client, siteId, {
|
|
115
136
|
...selection,
|
|
116
137
|
stagedPageIds: selection.stagedPageIds.length > 100 ? undefined : selection.stagedPageIds,
|
|
@@ -120,10 +141,19 @@ export async function status(invocation) {
|
|
|
120
141
|
deployments,
|
|
121
142
|
truncated: deploymentsTruncated,
|
|
122
143
|
} = await listDeployments(client, siteId, { pageSize: MAXIMUM_DEPLOYMENTS });
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
144
|
+
if (presentationOnly) {
|
|
145
|
+
onProgress(DOCS_SITE_NOT_COVERED_NOTE);
|
|
146
|
+
}
|
|
147
|
+
let images = [];
|
|
148
|
+
let summary = { totalImages: 0, processingImages: 0 };
|
|
149
|
+
let truncated = false;
|
|
150
|
+
let brokenReferencePages = [];
|
|
151
|
+
if (!presentationOnly) {
|
|
152
|
+
onProgress("Reading image processing state.");
|
|
153
|
+
({ images, summary, truncated } = await listSiteImages(client, siteId));
|
|
154
|
+
onProgress("Reading broken references.");
|
|
155
|
+
brokenReferencePages = await getSiteBrokenReferences(client, siteId);
|
|
156
|
+
}
|
|
127
157
|
const reportedBrokenPages = boundedList(brokenReferencePages, MAXIMUM_BROKEN_REFERENCE_PAGES);
|
|
128
158
|
const brokenPages = reportedBrokenPages.items.map((page) => {
|
|
129
159
|
const images = boundedList(page.missingImageIds, MAXIMUM_MISSING_TARGETS);
|
|
@@ -154,11 +184,14 @@ export async function status(invocation) {
|
|
|
154
184
|
const reportedDeployments = boundedList(deployments, MAXIMUM_DEPLOYMENTS);
|
|
155
185
|
const blockers = boundedList(readiness.blockers, MAXIMUM_BLOCKERS);
|
|
156
186
|
|
|
157
|
-
|
|
187
|
+
if (!presentationOnly) {
|
|
188
|
+
onProgress(`Broken references: ${brokenReferencePages.length} page(s) with missing targets.`);
|
|
189
|
+
}
|
|
158
190
|
|
|
159
191
|
return successResult(VERB_STATUS, siteId, {
|
|
160
192
|
platform: platformReport,
|
|
161
193
|
cliRelease: cliReleaseReport,
|
|
194
|
+
...(presentationOnly ? { authoringSurface: SURFACE_DOCS_PRESENTATION } : {}),
|
|
162
195
|
readiness: {
|
|
163
196
|
state: readiness.state,
|
|
164
197
|
approvedPageCount: readiness.approvedPageCount,
|
|
@@ -177,7 +210,8 @@ export async function status(invocation) {
|
|
|
177
210
|
...(reportedDeployments.truncated ? { itemsTruncated: true } : {}),
|
|
178
211
|
...(deploymentsTruncated ? { listTruncated: true } : {}),
|
|
179
212
|
},
|
|
180
|
-
images: {
|
|
213
|
+
images: presentationOnly ? { covered: false, reason: DOCS_SITE_NOT_COVERED_NOTE } : {
|
|
214
|
+
covered: true,
|
|
181
215
|
total: summary.totalImages,
|
|
182
216
|
processing: summary.processingImages,
|
|
183
217
|
complete: byState[IMAGE_PROCESSING_STATE_COMPLETE] ?? 0,
|
|
@@ -187,7 +221,7 @@ export async function status(invocation) {
|
|
|
187
221
|
...(failedImages.truncated ? { failedItemsTruncated: true } : {}),
|
|
188
222
|
...(truncated ? { listTruncated: true } : {}),
|
|
189
223
|
},
|
|
190
|
-
brokenReferences: {
|
|
224
|
+
brokenReferences: presentationOnly ? { covered: false, reason: DOCS_SITE_NOT_COVERED_NOTE } : {
|
|
191
225
|
covered: true,
|
|
192
226
|
totalPages: brokenReferencePages.length,
|
|
193
227
|
pages: brokenPages,
|
package/src/verbs/use.js
CHANGED
|
@@ -7,11 +7,13 @@ import {
|
|
|
7
7
|
CONFIG_FILE_NAME,
|
|
8
8
|
CONFIG_VERSION,
|
|
9
9
|
DEFAULT_WORKSPACE_DIR,
|
|
10
|
+
SURFACE_STANDARD,
|
|
10
11
|
VERB_SITES,
|
|
11
12
|
VERB_USE,
|
|
12
13
|
} from "../constants.js";
|
|
13
14
|
import { isCanonicalUuid, sanitizeDiagnostic, SiteAuthoringError } from "../errors.js";
|
|
14
15
|
import { openAccountSession, successResult } from "../session.js";
|
|
16
|
+
import { describeSiteKind, describeSurface } from "../surface.js";
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* `taproot-site use <site>` — choose the site the next command writes to.
|
|
@@ -88,6 +90,11 @@ export async function use(invocation) {
|
|
|
88
90
|
{
|
|
89
91
|
configVersion: CONFIG_VERSION,
|
|
90
92
|
siteId: site.siteId,
|
|
93
|
+
// What the site accepts, as Taproot reported it just now (TR00790).
|
|
94
|
+
// Recorded so a verb the site cannot take is refused offline, in
|
|
95
|
+
// words; every write re-checks it on the server, so this is a
|
|
96
|
+
// convenience that can go stale, never an authority.
|
|
97
|
+
...(site.authoringSurface === undefined ? {} : { authoringSurface: site.authoringSurface }),
|
|
91
98
|
workspaceDir,
|
|
92
99
|
// No endpoint. Which Taproot this is talking to lives with the
|
|
93
100
|
// credential, per machine — writing it here would pin a project to
|
|
@@ -116,13 +123,25 @@ export async function use(invocation) {
|
|
|
116
123
|
});
|
|
117
124
|
|
|
118
125
|
// Sanitized for the same reason the listing is: the name is authored
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
// by a person and this line is what confirms the selection.
|
|
127
|
+
onProgress(
|
|
128
|
+
`Now authoring ${sanitizeDiagnostic(site.name, site.siteId)} (${site.siteId}) [${describeSiteKind(site)}].`,
|
|
129
|
+
);
|
|
130
|
+
if (site.authoringSurface !== undefined && site.authoringSurface !== SURFACE_STANDARD) {
|
|
131
|
+
onProgress(`Authoring surface ${site.authoringSurface}: ${describeSurface(site.authoringSurface)}.`);
|
|
132
|
+
}
|
|
121
133
|
onProgress(`Recorded in ${configPath}.`);
|
|
122
134
|
|
|
123
135
|
return successResult(VERB_USE, site.siteId, {
|
|
124
136
|
accountId: signIn.accountId,
|
|
125
|
-
site: {
|
|
137
|
+
site: {
|
|
138
|
+
siteId: site.siteId,
|
|
139
|
+
name: site.name,
|
|
140
|
+
primaryDomain: site.primaryDomain,
|
|
141
|
+
siteType: site.siteType,
|
|
142
|
+
...(site.docsPublicationMode === undefined ? {} : { docsPublicationMode: site.docsPublicationMode }),
|
|
143
|
+
...(site.authoringSurface === undefined ? {} : { authoringSurface: site.authoringSurface }),
|
|
144
|
+
},
|
|
126
145
|
configPath: configPath,
|
|
127
146
|
});
|
|
128
147
|
});
|
package/src/verbs/whoami.js
CHANGED
|
@@ -15,6 +15,7 @@ import { credentialApiOrigin, findCredential } from "../credentials.js";
|
|
|
15
15
|
import { SITE_AUTHORING_CAPABILITIES } from "../capabilities.js";
|
|
16
16
|
import { openAnonymousSession, successResult } from "../session.js";
|
|
17
17
|
import { environmentNameFor } from "../settings.js";
|
|
18
|
+
import { describeSurface } from "../surface.js";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* What the last exchange recorded about the platform authoring switch, dated
|
|
@@ -109,7 +110,11 @@ export async function whoami(invocation) {
|
|
|
109
110
|
}
|
|
110
111
|
onProgress(
|
|
111
112
|
config?.siteId
|
|
112
|
-
? `Site: ${config.siteId}
|
|
113
|
+
? `Site: ${config.siteId}${
|
|
114
|
+
config.authoringSurface === undefined
|
|
115
|
+
? ""
|
|
116
|
+
: ` (${config.authoringSurface}: ${describeSurface(config.authoringSurface)})`
|
|
117
|
+
}`
|
|
113
118
|
: `No site selected. Run '${CLI_BINARY_NAME} ${VERB_USE} <site>'.`,
|
|
114
119
|
);
|
|
115
120
|
// What the last exchange actually produced, when there has been one. That is
|
|
@@ -156,6 +161,9 @@ export async function whoami(invocation) {
|
|
|
156
161
|
credentialPath,
|
|
157
162
|
}),
|
|
158
163
|
...(config?.configPath === undefined ? {} : { configPath: config.configPath }),
|
|
164
|
+
// As `use` recorded it (TR00790); absent from a configuration written
|
|
165
|
+
// before the field existed, and never a live read.
|
|
166
|
+
...(config?.authoringSurface === undefined ? {} : { authoringSurface: config.authoringSurface }),
|
|
159
167
|
// Named for what each is. `capabilities` alone would conflate the ceiling
|
|
160
168
|
// with the grant, which are different numbers and differently trustworthy.
|
|
161
169
|
capabilityCeiling: SITE_AUTHORING_CAPABILITIES,
|