uniweb 1.0.0 → 1.0.2
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 +201 -0
- package/README.md +532 -3
- package/package.json +60 -11
- package/partials/adding-pages.hbs +77 -0
- package/partials/agents.md +3000 -0
- package/partials/ai-assistance.hbs +28 -0
- package/partials/components-docs.hbs +13 -0
- package/partials/config-reference.hbs +66 -0
- package/partials/deployment.hbs +13 -0
- package/partials/learn-more.hbs +6 -0
- package/partials/quick-start.hbs +8 -0
- package/partials/search-docs.hbs +110 -0
- package/src/backend/asset-download.js +222 -0
- package/src/backend/client.js +986 -0
- package/src/backend/foundation-bring-along.js +692 -0
- package/src/backend/payment-handoff.js +362 -0
- package/src/backend/service-request.js +210 -0
- package/src/backend/site-media.js +255 -0
- package/src/backend/site-preview.js +77 -0
- package/src/backend/site-sync.js +2515 -0
- package/src/backend/workspace.js +234 -0
- package/src/commands/add.js +1900 -0
- package/src/commands/build.js +1214 -0
- package/src/commands/clone.js +466 -0
- package/src/commands/content.js +202 -0
- package/src/commands/deploy.js +537 -0
- package/src/commands/dev.js +202 -0
- package/src/commands/docs.js +530 -0
- package/src/commands/doctor.js +1982 -0
- package/src/commands/export.js +116 -0
- package/src/commands/families.js +82 -0
- package/src/commands/forget.js +197 -0
- package/src/commands/handoff.js +21 -0
- package/src/commands/i18n.js +1707 -0
- package/src/commands/inspect.js +375 -0
- package/src/commands/invite.js +24 -0
- package/src/commands/org.js +96 -0
- package/src/commands/publish.js +1087 -0
- package/src/commands/pull.js +1257 -0
- package/src/commands/push.js +663 -0
- package/src/commands/refresh.js +212 -0
- package/src/commands/register.js +1092 -0
- package/src/commands/rename.js +647 -0
- package/src/commands/site.js +358 -0
- package/src/commands/snapshot.js +461 -0
- package/src/commands/starter.js +206 -0
- package/src/commands/status.js +302 -0
- package/src/commands/sync.js +93 -0
- package/src/commands/template.js +107 -0
- package/src/commands/update.js +887 -0
- package/src/commands/validate.js +376 -0
- package/src/framework-index.json +248 -0
- package/src/index.js +2241 -0
- package/src/templates/fetchers/github.js +113 -0
- package/src/templates/fetchers/npm.js +85 -0
- package/src/templates/fetchers/release.js +92 -0
- package/src/templates/index.js +190 -0
- package/src/templates/processor.js +333 -0
- package/src/templates/resolver.js +232 -0
- package/src/templates/validator.js +155 -0
- package/src/utils/agents-stamp.js +110 -0
- package/src/utils/args.js +126 -0
- package/src/utils/asset-upload.js +270 -0
- package/src/utils/bytes.js +30 -0
- package/src/utils/code-upload.js +394 -0
- package/src/utils/config.js +417 -0
- package/src/utils/conformance.js +274 -0
- package/src/utils/dep-survey.js +176 -0
- package/src/utils/destination-prompt.js +146 -0
- package/src/utils/discover.js +75 -0
- package/src/utils/env.js +22 -0
- package/src/utils/exit.js +30 -0
- package/src/utils/fetch-retry.js +109 -0
- package/src/utils/flag-guard.js +246 -0
- package/src/utils/foundation-name.js +179 -0
- package/src/utils/git.js +342 -0
- package/src/utils/host-prompt.js +51 -0
- package/src/utils/install-integrity.js +210 -0
- package/src/utils/interactive.js +118 -0
- package/src/utils/json-file.js +72 -0
- package/src/utils/names.js +91 -0
- package/src/utils/placement.js +151 -0
- package/src/utils/pm.js +165 -0
- package/src/utils/preview.js +20 -0
- package/src/utils/pull-written.js +132 -0
- package/src/utils/records-guard.js +88 -0
- package/src/utils/registry-auth.js +994 -0
- package/src/utils/registry-orgs.js +290 -0
- package/src/utils/scaffold.js +483 -0
- package/src/utils/schemaless-report.js +30 -0
- package/src/utils/semver-precedence.js +80 -0
- package/src/utils/session-file.js +95 -0
- package/src/utils/site-content-refs.js +23 -0
- package/src/utils/site-copies.js +123 -0
- package/src/utils/site-data-upload.js +302 -0
- package/src/utils/site-identity.js +137 -0
- package/src/utils/snapshot-settings.js +112 -0
- package/src/utils/update-check.js +302 -0
- package/src/utils/uwx-read.js +157 -0
- package/src/utils/workspace.js +223 -0
- package/src/versions.js +467 -0
- package/starter/foundation/main.js +50 -0
- package/starter/foundation/sections/Section/index.jsx +95 -0
- package/starter/foundation/sections/Section/meta.js +44 -0
- package/starter/site/pages/about/1-about.md.hbs +13 -0
- package/starter/site/pages/about/page.yml +3 -0
- package/starter/site/pages/home/1-welcome.md.hbs +14 -0
- package/starter/site/pages/home/page.yml +3 -0
- package/templates/foundation/_gitignore +5 -0
- package/templates/foundation/components/.gitkeep +0 -0
- package/templates/foundation/main.js.hbs +33 -0
- package/templates/foundation/package.json.hbs +51 -0
- package/templates/foundation/sections/.gitkeep +0 -0
- package/templates/foundation/styles.css +6 -0
- package/templates/foundation/vite.config.js +3 -0
- package/templates/site/_gitignore +12 -0
- package/templates/site/entry.js +7 -0
- package/templates/site/index.html.hbs +13 -0
- package/templates/site/package.json.hbs +27 -0
- package/templates/site/public/favicon.svg +7 -0
- package/templates/site/site.yml.hbs +91 -0
- package/templates/site/theme.yml +99 -0
- package/templates/site/vite.config.js +7 -0
- package/templates/workspace/AGENTS.md.hbs +2 -0
- package/templates/workspace/README.md.hbs +87 -0
- package/templates/workspace/_gitignore +29 -0
- package/templates/workspace/_vscode/settings.json +6 -0
- package/templates/workspace/package.json.hbs +20 -0
- package/templates/workspace/pnpm-workspace.yaml.hbs +26 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uniweb site` — the sites in a workspace, on the backend you are logged in to.
|
|
3
|
+
*
|
|
4
|
+
* uniweb site list [--json] each site's name, uuid, and whether it is live
|
|
5
|
+
* uniweb site unpublish [<site-uuid>] [--yes] take a site offline; its content stays
|
|
6
|
+
* uniweb site delete [<site-uuid>] [--yes] delete a site — final, no restore
|
|
7
|
+
*
|
|
8
|
+
* Without a uuid, `unpublish` and `delete` act on the site this project is synced to on
|
|
9
|
+
* that backend. The workspace is the command's (`--org @x` / `--personal`), else the
|
|
10
|
+
* login's — as for every site request.
|
|
11
|
+
*
|
|
12
|
+
* ⭐ A live site is not deleted: the backend refuses while it is published, so `delete`
|
|
13
|
+
* says to unpublish it first, and anything else still active (a plan, a domain, stored
|
|
14
|
+
* form messages) is named in the backend's own words and resolved in the app. A delete
|
|
15
|
+
* of the project's own site also drops the project's record of it, as `uniweb forget`
|
|
16
|
+
* does, so its next push creates a new site.
|
|
17
|
+
*
|
|
18
|
+
* ⛔ Both write verbs ask first, and `--yes` is the only way past the question. Without
|
|
19
|
+
* a terminal they refuse rather than print what they would have done: a script that
|
|
20
|
+
* reads exit 0 as "deleted" must not be told 0 for nothing.
|
|
21
|
+
*
|
|
22
|
+
* Auth: the session of the backend you are logged in to (`uniweb login`) / UNIWEB_TOKEN.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { existsSync } from 'node:fs'
|
|
26
|
+
import { join, resolve } from 'node:path'
|
|
27
|
+
|
|
28
|
+
import { BackendClient, WorkspaceMismatchError, describeWorkspace } from '../backend/client.js'
|
|
29
|
+
import { resolveWorkspace } from '../backend/workspace.js'
|
|
30
|
+
import { checkFlags } from '../utils/flag-guard.js'
|
|
31
|
+
import { confirm, isNonInteractive } from '../utils/interactive.js'
|
|
32
|
+
import { readSiteIdentity } from '../utils/site-identity.js'
|
|
33
|
+
import { findSites, findWorkspaceRoot } from '../utils/workspace.js'
|
|
34
|
+
|
|
35
|
+
const c = {
|
|
36
|
+
reset: '\x1b[0m',
|
|
37
|
+
bold: '\x1b[1m',
|
|
38
|
+
dim: '\x1b[2m',
|
|
39
|
+
red: '\x1b[31m',
|
|
40
|
+
green: '\x1b[32m',
|
|
41
|
+
yellow: '\x1b[33m',
|
|
42
|
+
cyan: '\x1b[36m'
|
|
43
|
+
}
|
|
44
|
+
// As in every verb: errors on stderr, the rest on stdout — and under `--json` nothing but
|
|
45
|
+
// the JSON on stdout.
|
|
46
|
+
const say = {
|
|
47
|
+
ok: (m) => console.log(`${c.green}✓${c.reset} ${m}`),
|
|
48
|
+
info: (m) => console.log(`${c.cyan}→${c.reset} ${m}`),
|
|
49
|
+
warn: (m) => console.log(`${c.yellow}⚠${c.reset} ${m}`),
|
|
50
|
+
err: (m) => console.error(`${c.red}✗${c.reset} ${m}`),
|
|
51
|
+
dim: (m) => console.log(` ${c.dim}${m}${c.reset}`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const USAGE = [
|
|
55
|
+
'uniweb site <command>',
|
|
56
|
+
' list [--json] The sites in the workspace: name, uuid, whether live',
|
|
57
|
+
' unpublish [<site-uuid>] [--yes] Take a site offline (its content stays)',
|
|
58
|
+
' delete [<site-uuid>] [--yes] Delete a site — final',
|
|
59
|
+
'',
|
|
60
|
+
'Without a uuid, unpublish and delete act on the site this project is synced to.',
|
|
61
|
+
'The workspace is --org @x or --personal, else the one chosen at login.'
|
|
62
|
+
].join('\n')
|
|
63
|
+
|
|
64
|
+
/** A site-content uuid, loosely: enough to tell one from a site's name. */
|
|
65
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
66
|
+
|
|
67
|
+
/** The arguments that are not flags — skipping `--org`'s value. */
|
|
68
|
+
function positionals(args) {
|
|
69
|
+
const out = []
|
|
70
|
+
for (let i = 0; i < args.length; i++) {
|
|
71
|
+
const a = args[i]
|
|
72
|
+
if (a === '--org') {
|
|
73
|
+
i++
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
if (a.startsWith('-')) continue
|
|
77
|
+
out.push(a)
|
|
78
|
+
}
|
|
79
|
+
return out
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The site directory this command runs in — the site itself (it holds `site.yml`), or a
|
|
84
|
+
* workspace's only site. ⛔ Never a stop: outside a project — or from an install without
|
|
85
|
+
* `@uniweb/build`, which finding a workspace's sites may load — there is simply none.
|
|
86
|
+
*/
|
|
87
|
+
async function projectSiteDir() {
|
|
88
|
+
try {
|
|
89
|
+
const cwd = process.cwd()
|
|
90
|
+
if (existsSync(join(cwd, 'site.yml'))) return { dir: cwd }
|
|
91
|
+
const root = findWorkspaceRoot(cwd)
|
|
92
|
+
if (!root) return {}
|
|
93
|
+
const sites = await findSites(root)
|
|
94
|
+
if (sites.length === 1) return { dir: resolve(root, sites[0]) }
|
|
95
|
+
return sites.length > 1 ? { many: sites } : {}
|
|
96
|
+
} catch {
|
|
97
|
+
return {}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** A client on the backend you are logged in to, working in the command's workspace. */
|
|
102
|
+
async function connect(args, command) {
|
|
103
|
+
const client = new BackendClient({ args, command })
|
|
104
|
+
const ws = await resolveWorkspace({ client, args })
|
|
105
|
+
if (ws.refused) return { refused: ws.reason }
|
|
106
|
+
client.setWorkspace(ws.workspace, { source: ws.source })
|
|
107
|
+
return { client, workspace: ws.workspace }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Every site in the workspace, page by page. */
|
|
111
|
+
async function allSites(client) {
|
|
112
|
+
const limit = 1000
|
|
113
|
+
const sites = []
|
|
114
|
+
for (let offset = 0; ; offset += limit) {
|
|
115
|
+
const res = await client.listSites({ limit, offset })
|
|
116
|
+
if (!res.ok) throw new Error(`Could not list the sites: HTTP ${res.status} ${res.statusText}`)
|
|
117
|
+
const page = (await res.json().catch(() => null))?.sites
|
|
118
|
+
if (!Array.isArray(page)) throw new Error('Could not list the sites: the backend sent no list.')
|
|
119
|
+
sites.push(...page)
|
|
120
|
+
if (page.length < limit) return sites
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function list(args) {
|
|
125
|
+
const json = args.includes('--json')
|
|
126
|
+
const conn = await connect(args, 'Listing sites')
|
|
127
|
+
if (conn.refused) {
|
|
128
|
+
say.err(conn.refused)
|
|
129
|
+
return { exitCode: 2 }
|
|
130
|
+
}
|
|
131
|
+
const { client, workspace } = conn
|
|
132
|
+
const sites = await allSites(client)
|
|
133
|
+
const rows = sites.map((s) => ({
|
|
134
|
+
uuid: s.uuid,
|
|
135
|
+
name: s.name ?? null,
|
|
136
|
+
status: s.deployment?.status ?? null,
|
|
137
|
+
published: s.deployment?.status === 'published',
|
|
138
|
+
url: s.deployment?.published_url ?? null,
|
|
139
|
+
updated_at: s.updated_at ?? null
|
|
140
|
+
}))
|
|
141
|
+
if (json) {
|
|
142
|
+
console.log(JSON.stringify({ backend: client.origin, workspace: workspace ?? null, sites: rows }))
|
|
143
|
+
return { exitCode: 0 }
|
|
144
|
+
}
|
|
145
|
+
if (!rows.length) {
|
|
146
|
+
say.info(`No sites in ${describeWorkspace(workspace)} on ${client.origin}.`)
|
|
147
|
+
return { exitCode: 0 }
|
|
148
|
+
}
|
|
149
|
+
console.log(`${c.bold}Sites in ${describeWorkspace(workspace)}${c.reset} ${c.dim}on ${client.origin}${c.reset}`)
|
|
150
|
+
for (const r of rows) {
|
|
151
|
+
const state = r.published ? `${c.green}published${c.reset}` : `${c.dim}${r.status ?? 'never published'}${c.reset}`
|
|
152
|
+
const name = r.name ?? `${c.dim}(no name)${c.reset}`
|
|
153
|
+
console.log(` ${name} ${c.dim}${r.uuid}${c.reset} ${state}${r.published && r.url ? ` ${r.url}` : ''}`)
|
|
154
|
+
}
|
|
155
|
+
return { exitCode: 0 }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The site a write verb acts on: the uuid given, else this project's site on the
|
|
160
|
+
* backend the client goes to. Null, with the reason said, when there is neither.
|
|
161
|
+
*/
|
|
162
|
+
async function targetSite(args, client, verb) {
|
|
163
|
+
const [, given] = positionals(args)
|
|
164
|
+
if (given) {
|
|
165
|
+
if (!UUID.test(given)) {
|
|
166
|
+
say.err(`\`${given}\` is not a site uuid.`)
|
|
167
|
+
say.dim('`uniweb site list` shows each site with its uuid.')
|
|
168
|
+
return null
|
|
169
|
+
}
|
|
170
|
+
const project = await projectSiteDir()
|
|
171
|
+
const mine = project.dir ? readSiteIdentity(project.dir, client.origin).uuid : null
|
|
172
|
+
return { uuid: given, siteDir: mine === given ? project.dir : null }
|
|
173
|
+
}
|
|
174
|
+
const project = await projectSiteDir()
|
|
175
|
+
if (project.many) {
|
|
176
|
+
say.err(`This workspace has ${project.many.length} sites — name one: uniweb site ${verb} <site-uuid>, or run it inside the site.`)
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
const uuid = project.dir ? readSiteIdentity(project.dir, client.origin).uuid : null
|
|
180
|
+
if (!uuid) {
|
|
181
|
+
say.err(
|
|
182
|
+
project.dir
|
|
183
|
+
? `This project has no site on ${client.origin} — name one: uniweb site ${verb} <site-uuid>`
|
|
184
|
+
: `No site named, and this is not a Uniweb project — name one: uniweb site ${verb} <site-uuid>`
|
|
185
|
+
)
|
|
186
|
+
say.dim('`uniweb site list` shows each site with its uuid.')
|
|
187
|
+
return null
|
|
188
|
+
}
|
|
189
|
+
return { uuid, siteDir: project.dir }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** The site's row in the workspace's list, or null when the workspace does not list it. */
|
|
193
|
+
async function findSite(client, uuid) {
|
|
194
|
+
try {
|
|
195
|
+
return (await allSites(client)).find((s) => s.uuid === uuid) ?? null
|
|
196
|
+
} catch {
|
|
197
|
+
return null
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Ask, unless `--yes`. The exit code when the answer is not yes: 0 for a person who
|
|
203
|
+
* declined, 2 where nobody could be asked — so a script never reads 0 for nothing done.
|
|
204
|
+
*/
|
|
205
|
+
async function confirmed(args, question, verb) {
|
|
206
|
+
if (args.includes('--yes')) return { yes: true }
|
|
207
|
+
if (isNonInteractive(args)) {
|
|
208
|
+
say.err(`\`uniweb site ${verb}\` asks before it acts — pass --yes to confirm it here.`)
|
|
209
|
+
return { yes: false, exitCode: 2 }
|
|
210
|
+
}
|
|
211
|
+
if (await confirm(question, false)) return { yes: true }
|
|
212
|
+
say.info('Cancelled — nothing changed.')
|
|
213
|
+
return { yes: false, exitCode: 0 }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** What the backend said about a refused write, in its own words where it gave them. */
|
|
217
|
+
async function sayRefusal(res, { uuid, verb, origin }) {
|
|
218
|
+
const body = await res.json().catch(() => null)
|
|
219
|
+
if (res.status === 409 && Array.isArray(body?.blockers) && body.blockers.length) {
|
|
220
|
+
say.err(`The site cannot be deleted yet:`)
|
|
221
|
+
for (const b of body.blockers) {
|
|
222
|
+
// ⭐ `detail` is written for the site's owner; the set of blockers is open, so an
|
|
223
|
+
// unknown one is shown by its detail, never dropped.
|
|
224
|
+
console.error(` • ${b.detail || b.resource}`)
|
|
225
|
+
if (b.resource === 'published') console.error(` ${c.dim}→ uniweb site unpublish ${uuid}${c.reset}`)
|
|
226
|
+
}
|
|
227
|
+
if (body.blockers.some((b) => b.resource !== 'published')) {
|
|
228
|
+
say.dim('Anything else listed is resolved in the app.')
|
|
229
|
+
}
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
if (res.status === 401) {
|
|
233
|
+
say.err(`Your session on ${origin} is not accepted — sign in again: uniweb login`)
|
|
234
|
+
} else if (res.status === 403) {
|
|
235
|
+
say.err(`You may not ${verb} this site — only its owner or an admin of its workspace can.`)
|
|
236
|
+
} else if (res.status === 404) {
|
|
237
|
+
say.err(`${origin} has no site ${uuid}.`)
|
|
238
|
+
} else {
|
|
239
|
+
say.err(`The backend refused: HTTP ${res.status}${body?.detail ? ` — ${body.detail}` : ''}`)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* The project's record of a site it no longer has — what `uniweb forget` removes for one
|
|
245
|
+
* backend. Loaded here, not at the top: it needs `@uniweb/build`, which a command run
|
|
246
|
+
* outside a project does not have.
|
|
247
|
+
*/
|
|
248
|
+
async function forgetDeletedSite(siteDir, origin) {
|
|
249
|
+
try {
|
|
250
|
+
const { clearBackend } = await import('@uniweb/build/uwx')
|
|
251
|
+
const { forgetBackendCache } = await import('../backend/site-sync.js')
|
|
252
|
+
const { forgetDeploys } = await import('@uniweb/build/site')
|
|
253
|
+
clearBackend(siteDir, origin)
|
|
254
|
+
forgetBackendCache(siteDir, origin)
|
|
255
|
+
await forgetDeploys(siteDir, origin)
|
|
256
|
+
return true
|
|
257
|
+
} catch {
|
|
258
|
+
return false
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function unpublish(args) {
|
|
263
|
+
const conn = await connect(args, 'Unpublishing a site')
|
|
264
|
+
if (conn.refused) {
|
|
265
|
+
say.err(conn.refused)
|
|
266
|
+
return { exitCode: 2 }
|
|
267
|
+
}
|
|
268
|
+
const { client } = conn
|
|
269
|
+
const target = await targetSite(args, client, 'unpublish')
|
|
270
|
+
if (!target) return { exitCode: 2 }
|
|
271
|
+
const site = await findSite(client, target.uuid)
|
|
272
|
+
const label = site?.name ? `“${site.name}” (${target.uuid})` : target.uuid
|
|
273
|
+
const url = site?.deployment?.published_url
|
|
274
|
+
const ok = await confirmed(
|
|
275
|
+
args,
|
|
276
|
+
`Unpublish ${label} on ${client.origin}?${url ? ` Visitors get nothing at ${url} until it is published again.` : ''}`,
|
|
277
|
+
'unpublish'
|
|
278
|
+
)
|
|
279
|
+
if (!ok.yes) return { exitCode: ok.exitCode }
|
|
280
|
+
|
|
281
|
+
const res = await client.unpublishSite(target.uuid)
|
|
282
|
+
if (!res.ok) {
|
|
283
|
+
await sayRefusal(res, { uuid: target.uuid, verb: 'unpublish', origin: client.origin })
|
|
284
|
+
return { exitCode: 1 }
|
|
285
|
+
}
|
|
286
|
+
const body = await res.json().catch(() => null)
|
|
287
|
+
if (body?.was_published === false) {
|
|
288
|
+
say.info(`${label} was not published — nothing to take down.`)
|
|
289
|
+
} else {
|
|
290
|
+
say.ok(`Unpublished ${label}. Its content stays; \`uniweb publish\` puts it back online.`)
|
|
291
|
+
}
|
|
292
|
+
return { exitCode: 0 }
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async function remove(args) {
|
|
296
|
+
const conn = await connect(args, 'Deleting a site')
|
|
297
|
+
if (conn.refused) {
|
|
298
|
+
say.err(conn.refused)
|
|
299
|
+
return { exitCode: 2 }
|
|
300
|
+
}
|
|
301
|
+
const { client, workspace } = conn
|
|
302
|
+
const target = await targetSite(args, client, 'delete')
|
|
303
|
+
if (!target) return { exitCode: 2 }
|
|
304
|
+
const site = await findSite(client, target.uuid)
|
|
305
|
+
const label = site?.name ? `“${site.name}” (${target.uuid})` : target.uuid
|
|
306
|
+
if (site?.deployment?.status === 'published') {
|
|
307
|
+
say.err(`${label} is published — unpublish it first: uniweb site unpublish ${target.uuid}`)
|
|
308
|
+
return { exitCode: 1 }
|
|
309
|
+
}
|
|
310
|
+
const ok = await confirmed(
|
|
311
|
+
args,
|
|
312
|
+
`Delete ${label} on ${client.origin}, in ${describeWorkspace(workspace)}? ` +
|
|
313
|
+
'Its pages, settings and snapshots go with it, and it cannot be undone. Records it pushed stay in the workspace.',
|
|
314
|
+
'delete'
|
|
315
|
+
)
|
|
316
|
+
if (!ok.yes) return { exitCode: ok.exitCode }
|
|
317
|
+
|
|
318
|
+
const res = await client.deleteSite(target.uuid)
|
|
319
|
+
if (!res.ok) {
|
|
320
|
+
await sayRefusal(res, { uuid: target.uuid, verb: 'delete', origin: client.origin })
|
|
321
|
+
return { exitCode: 1 }
|
|
322
|
+
}
|
|
323
|
+
say.ok(`Deleted ${label}.`)
|
|
324
|
+
if (target.siteDir) {
|
|
325
|
+
if (await forgetDeletedSite(target.siteDir, client.origin)) {
|
|
326
|
+
say.dim(`This project no longer records a site on ${client.origin}; its next push creates a new one.`)
|
|
327
|
+
} else {
|
|
328
|
+
say.dim(`This project still records it — run \`uniweb forget --server ${client.origin}\` in it.`)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return { exitCode: 0 }
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function site(args = []) {
|
|
335
|
+
const badFlag = checkFlags('site', args)
|
|
336
|
+
if (badFlag) {
|
|
337
|
+
say.err(badFlag.message)
|
|
338
|
+
return { exitCode: 2 }
|
|
339
|
+
}
|
|
340
|
+
const sub = args[0]
|
|
341
|
+
try {
|
|
342
|
+
if (sub === 'list') return await list(args)
|
|
343
|
+
if (sub === 'unpublish') return await unpublish(args)
|
|
344
|
+
if (sub === 'delete') return await remove(args)
|
|
345
|
+
} catch (err) {
|
|
346
|
+
say.err(err instanceof WorkspaceMismatchError ? err.message : err?.message || String(err))
|
|
347
|
+
return { exitCode: 1 }
|
|
348
|
+
}
|
|
349
|
+
if (sub) {
|
|
350
|
+
say.err(`Unknown command: uniweb site ${sub}`)
|
|
351
|
+
console.error(USAGE)
|
|
352
|
+
return { exitCode: 2 }
|
|
353
|
+
}
|
|
354
|
+
console.log(USAGE)
|
|
355
|
+
return { exitCode: 0 }
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export default site
|