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,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export Command
|
|
3
|
+
*
|
|
4
|
+
* Produces a self-contained, vite-built site artifact in `dist/` for
|
|
5
|
+
* hosting on a third-party CDN (Netlify, Vercel, GitHub Pages, S3 +
|
|
6
|
+
* CloudFront, etc.). Does NOT upload anywhere — `uniweb deploy --host`
|
|
7
|
+
* uploads to a third-party host; `uniweb publish` ships to Uniweb hosting.
|
|
8
|
+
*
|
|
9
|
+
* The `dist/` output bundles the runtime + foundation + content into
|
|
10
|
+
* concatenated packaging, with a vite-built `index.html` + `entry.js` +
|
|
11
|
+
* `assets/`. The user copies it to whatever host they like.
|
|
12
|
+
*
|
|
13
|
+
* Internally this is `uniweb build --bundle` plus user guidance for the
|
|
14
|
+
* upload step. The `--link` / `--bundle` flag pair is internal-only
|
|
15
|
+
* vocabulary now (Phase 2 of the CLI ergonomics overhaul); users see
|
|
16
|
+
* `uniweb publish` (Uniweb hosting), `uniweb deploy --host` (third-party),
|
|
17
|
+
* and `uniweb export` (self-contained artifact).
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* uniweb export Produce dist/ for static hosting
|
|
21
|
+
* uniweb export --no-prerender Skip per-page prerendered HTML
|
|
22
|
+
* uniweb export --host <name> Pick a host adapter for postBuild
|
|
23
|
+
* (e.g. cloudflare-pages, s3-cloudfront,
|
|
24
|
+
* github-pages, generic-static).
|
|
25
|
+
* Default: cloudflare-pages.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { execSync } from 'node:child_process'
|
|
29
|
+
import { existsSync } from 'node:fs'
|
|
30
|
+
import { join } from 'node:path'
|
|
31
|
+
|
|
32
|
+
import { resolveSiteDir } from './deploy.js'
|
|
33
|
+
|
|
34
|
+
const c = {
|
|
35
|
+
reset: '\x1b[0m',
|
|
36
|
+
dim: '\x1b[2m',
|
|
37
|
+
cyan: '\x1b[36m',
|
|
38
|
+
green: '\x1b[32m',
|
|
39
|
+
red: '\x1b[31m'
|
|
40
|
+
}
|
|
41
|
+
const say = {
|
|
42
|
+
ok: (m) => console.log(`${c.green}✓${c.reset} ${m}`),
|
|
43
|
+
info: (m) => console.log(`${c.cyan}→${c.reset} ${m}`),
|
|
44
|
+
err: (m) => console.error(`${c.red}✗${c.reset} ${m}`),
|
|
45
|
+
dim: (m) => console.log(` ${c.dim}${m}${c.reset}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function exportSite(args = []) {
|
|
49
|
+
const siteDir = await resolveSiteDir(args, 'export')
|
|
50
|
+
|
|
51
|
+
// Pass through --no-prerender and --host. Everything else is ignored.
|
|
52
|
+
// `uniweb export` stays low-flag: the user picks the destination host
|
|
53
|
+
// themselves outside the CLI, so there's nothing to configure beyond
|
|
54
|
+
// what `uniweb build --bundle` already exposes.
|
|
55
|
+
const noPrerender = args.includes('--no-prerender')
|
|
56
|
+
const buildArgs = ['build', '--bundle']
|
|
57
|
+
if (noPrerender) buildArgs.push('--no-prerender')
|
|
58
|
+
|
|
59
|
+
const { readFlagValue } = await import('../utils/args.js')
|
|
60
|
+
const hostFlag = readFlagValue(args, '--host')
|
|
61
|
+
if (hostFlag === null) {
|
|
62
|
+
// --host with no value → prompt here so the build subprocess gets
|
|
63
|
+
// a concrete value (and doesn't re-prompt against its own argv).
|
|
64
|
+
const { promptForHost } = await import('../utils/host-prompt.js')
|
|
65
|
+
try {
|
|
66
|
+
const chosen = await promptForHost({ args })
|
|
67
|
+
buildArgs.push('--host', chosen)
|
|
68
|
+
} catch (err) {
|
|
69
|
+
say.err(err.message)
|
|
70
|
+
process.exit(1)
|
|
71
|
+
}
|
|
72
|
+
} else if (typeof hostFlag === 'string') {
|
|
73
|
+
buildArgs.push('--host', hostFlag)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
say.info('Exporting site (vite build → dist/)…')
|
|
77
|
+
console.log('')
|
|
78
|
+
|
|
79
|
+
// Spawn the SAME CLI binary (process.argv[1]) — same reason as deploy.js:
|
|
80
|
+
// npx walks node_modules and could resolve to a different version.
|
|
81
|
+
try {
|
|
82
|
+
execSync(`node ${JSON.stringify(process.argv[1])} ${buildArgs.join(' ')}`, {
|
|
83
|
+
cwd: siteDir,
|
|
84
|
+
stdio: 'inherit'
|
|
85
|
+
})
|
|
86
|
+
} catch {
|
|
87
|
+
say.err('Build failed. See output above.')
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const distDir = join(siteDir, 'dist')
|
|
92
|
+
if (!existsSync(distDir)) {
|
|
93
|
+
say.err('Build did not produce dist/.')
|
|
94
|
+
process.exit(1)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log('')
|
|
98
|
+
say.ok('Export complete.')
|
|
99
|
+
console.log('')
|
|
100
|
+
console.log(` ${c.dim}Artifact:${c.reset} ${c.cyan}${distDir}${c.reset}`)
|
|
101
|
+
console.log('')
|
|
102
|
+
console.log(
|
|
103
|
+
` ${c.dim}Upload the contents of ${c.reset}${c.cyan}dist/${c.reset}${c.dim} to your static host. Examples:${c.reset}`
|
|
104
|
+
)
|
|
105
|
+
console.log(
|
|
106
|
+
` ${c.dim}Netlify:${c.reset} ${c.cyan}netlify deploy --prod --dir=dist${c.reset}`
|
|
107
|
+
)
|
|
108
|
+
console.log(` ${c.dim}Vercel:${c.reset} ${c.cyan}vercel --prod${c.reset}`)
|
|
109
|
+
console.log(
|
|
110
|
+
` ${c.dim}S3:${c.reset} ${c.cyan}aws s3 sync dist/ s3://your-bucket/${c.reset}`
|
|
111
|
+
)
|
|
112
|
+
console.log('')
|
|
113
|
+
console.log(
|
|
114
|
+
` ${c.dim}For Uniweb hosting instead, use ${c.reset}${c.cyan}uniweb publish${c.reset}${c.dim}.${c.reset}`
|
|
115
|
+
)
|
|
116
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uniweb families` — the standard section families this CLI knows.
|
|
3
|
+
*
|
|
4
|
+
* ⭐ NAMED AFTER THE FIELD, not after the things it lists. A developer's question
|
|
5
|
+
* is "what can I put in `family:`?", and they will type the word they just read
|
|
6
|
+
* in a `meta.js` or a doctor warning.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ IT REPORTS THE ROSTER THIS CLI SHIPS WITH, not a live fetch — the list comes
|
|
9
|
+
* from the `@uniweb/schemas` version this CLI resolved. That is the right answer,
|
|
10
|
+
* because it is also the list `uniweb doctor` matched against. A newer family
|
|
11
|
+
* than your CLI will not appear, and declaring one is not fatal either way: an
|
|
12
|
+
* unrecognized value falls back to a generic illustration.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { FAMILIES, GROUPS } from '@uniweb/schemas/families'
|
|
16
|
+
import { getCliVersion } from '../versions.js'
|
|
17
|
+
|
|
18
|
+
const colors = {
|
|
19
|
+
reset: '\x1b[0m',
|
|
20
|
+
bright: '\x1b[1m',
|
|
21
|
+
dim: '\x1b[2m',
|
|
22
|
+
cyan: '\x1b[36m'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function families(args = []) {
|
|
26
|
+
if (args.includes('--json')) {
|
|
27
|
+
// ⛔ stdout carries JSON and nothing else, so it pipes. Every human-facing
|
|
28
|
+
// line in this command goes to stdout only in the non-JSON branch.
|
|
29
|
+
process.stdout.write(
|
|
30
|
+
JSON.stringify(
|
|
31
|
+
{ cliVersion: getCliVersion(), count: FAMILIES.length, groups: GROUPS, families: FAMILIES },
|
|
32
|
+
null,
|
|
33
|
+
2
|
|
34
|
+
) + '\n'
|
|
35
|
+
)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const filter = args.find((a) => !a.startsWith('-'))
|
|
40
|
+
const shown = filter
|
|
41
|
+
? FAMILIES.filter(
|
|
42
|
+
(f) =>
|
|
43
|
+
f.id.includes(filter.toLowerCase()) ||
|
|
44
|
+
f.label.toLowerCase().includes(filter.toLowerCase()) ||
|
|
45
|
+
f.group === filter.toLowerCase()
|
|
46
|
+
)
|
|
47
|
+
: FAMILIES
|
|
48
|
+
|
|
49
|
+
console.log('')
|
|
50
|
+
console.log(
|
|
51
|
+
`${colors.bright}Section families${colors.reset} ${colors.dim}(uniweb ${getCliVersion()})${colors.reset}`
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if (shown.length === 0) {
|
|
55
|
+
console.log('')
|
|
56
|
+
console.log(` ${colors.dim}Nothing matches "${filter}".${colors.reset}`)
|
|
57
|
+
console.log(
|
|
58
|
+
` ${colors.dim}A name of your own is fine — it falls back to a generic illustration.${colors.reset}`
|
|
59
|
+
)
|
|
60
|
+
console.log('')
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const width = Math.max(...shown.map((f) => f.id.length))
|
|
65
|
+
for (const group of GROUPS) {
|
|
66
|
+
const rows = shown.filter((f) => f.group === group.id)
|
|
67
|
+
if (rows.length === 0) continue
|
|
68
|
+
console.log('')
|
|
69
|
+
console.log(` ${colors.bright}${group.label}${colors.reset} ${colors.dim}— ${group.description}${colors.reset}`)
|
|
70
|
+
for (const f of rows) {
|
|
71
|
+
console.log(` ${colors.cyan}${f.id.padEnd(width)}${colors.reset} ${colors.dim}${f.label}${colors.reset}`)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log('')
|
|
76
|
+
console.log(` ${colors.dim}Declare one in a section's meta.js: family: 'hero'${colors.reset}`)
|
|
77
|
+
console.log(
|
|
78
|
+
` ${colors.dim}A component already named for its family needs no declaration.${colors.reset}`
|
|
79
|
+
)
|
|
80
|
+
console.log(` ${colors.dim}--json for scripts. uniweb doctor reports what your sections resolved to.${colors.reset}`)
|
|
81
|
+
console.log('')
|
|
82
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uniweb forget` — remove what this project recorded about where it has synced and
|
|
3
|
+
* deployed. Local files only; nothing on any backend changes.
|
|
4
|
+
*
|
|
5
|
+
* uniweb forget --server <url> one backend
|
|
6
|
+
* uniweb forget --all everything — for a COPY that is to become a new project
|
|
7
|
+
*
|
|
8
|
+
* ## `--server <url>`
|
|
9
|
+
*
|
|
10
|
+
* - that backend's section of `sync.json` — the site uuid, the record map, asset
|
|
11
|
+
* ids, provisioned services and the rest of what it minted;
|
|
12
|
+
* - that backend's section of `.uniweb/backend-cache.json`;
|
|
13
|
+
* - the `deploys:` records in `deploy.yml` that name it. ⭐ Its TARGETS stay: a
|
|
14
|
+
* target is where you chose to ship, not something the backend told us, and the
|
|
15
|
+
* next publish there simply creates a new site.
|
|
16
|
+
*
|
|
17
|
+
* Every other backend is untouched, which is only possible because all three are
|
|
18
|
+
* keyed by backend.
|
|
19
|
+
*
|
|
20
|
+
* ## `--all`
|
|
21
|
+
*
|
|
22
|
+
* A copied project carries the original's `sync.json`, so its first push updates the
|
|
23
|
+
* ORIGINAL's site — the copy sends uuids that are the original's. `--all` deletes
|
|
24
|
+
* `sync.json`, `.uniweb/backend-cache.json` and `deploy.yml`, after which the copy's
|
|
25
|
+
* next push creates a new site.
|
|
26
|
+
*
|
|
27
|
+
* ⭐ **`deploy.yml` goes whole, targets included** *[Diego, 2026-09-21]*. Its targets
|
|
28
|
+
* name the original's destinations — its Pages project, its bucket, its domain — so a
|
|
29
|
+
* deploy from the copy would overwrite the original there. The copy's first deploy
|
|
30
|
+
* writes a fresh one.
|
|
31
|
+
*
|
|
32
|
+
* ## What neither form touches
|
|
33
|
+
*
|
|
34
|
+
* ⛔ **Record files.** A record's `$uuid` is its OWN id, not any backend's. It is
|
|
35
|
+
* written once, on the record's first push anywhere, and never changes after;
|
|
36
|
+
* removing it would delete the record's identity, which is not what forgetting a
|
|
37
|
+
* backend means. A copy keeps them too: they never reach a backend again once the
|
|
38
|
+
* map that pointed them at the original's entities is gone. *[Diego, 2026-09-20.]*
|
|
39
|
+
*
|
|
40
|
+
* ⛔ **Any backend.** Every site still exists where it was. Deleting one is a
|
|
41
|
+
* different operation, on the backend's side.
|
|
42
|
+
*
|
|
43
|
+
* ## Why it exists
|
|
44
|
+
*
|
|
45
|
+
* Two jobs. A script pushes a template site to a short-lived dev server and then
|
|
46
|
+
* removes the traces of it without discarding the rest of the project (`--server`)
|
|
47
|
+
* — which is also why traceless publish was dropped: push and pull leave traces too.
|
|
48
|
+
* And someone duplicates a project to start a new site from it (`--all`).
|
|
49
|
+
*
|
|
50
|
+
* ⚠️ **No default target.** Forgetting a backend you still use means its next push
|
|
51
|
+
* creates a second site there, so the verb makes you name it — `--server` is
|
|
52
|
+
* required even when the project has synced with only one.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
import { readFlagValue } from '../utils/args.js'
|
|
56
|
+
import { checkFlags } from '../utils/flag-guard.js'
|
|
57
|
+
import { resolveSiteDir } from './deploy.js'
|
|
58
|
+
import { forgetBackendCache, forgetAllBackendCaches } from '../backend/site-sync.js'
|
|
59
|
+
import { clearBackend, forgetSyncStore, readBackendState } from '@uniweb/build/uwx'
|
|
60
|
+
import { forgetDeploys, forgetDeployYml } from '@uniweb/build/site'
|
|
61
|
+
import { syncedBackends, normalizeOrigin } from '../utils/site-identity.js'
|
|
62
|
+
|
|
63
|
+
const c = {
|
|
64
|
+
reset: '\x1b[0m',
|
|
65
|
+
bold: '\x1b[1m',
|
|
66
|
+
dim: '\x1b[2m',
|
|
67
|
+
cyan: '\x1b[36m',
|
|
68
|
+
green: '\x1b[32m',
|
|
69
|
+
yellow: '\x1b[33m',
|
|
70
|
+
red: '\x1b[31m'
|
|
71
|
+
}
|
|
72
|
+
const say = {
|
|
73
|
+
ok: (m) => console.log(`${c.green}✓${c.reset} ${m}`),
|
|
74
|
+
info: (m) => console.log(`${c.cyan}→${c.reset} ${m}`),
|
|
75
|
+
warn: (m) => console.log(`${c.yellow}⚠${c.reset} ${m}`),
|
|
76
|
+
err: (m) => console.error(`${c.red}✗${c.reset} ${m}`),
|
|
77
|
+
dim: (m) => console.log(` ${c.dim}${m}${c.reset}`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** "a", "a and b", "a, b and c" */
|
|
81
|
+
function listed(items) {
|
|
82
|
+
return items.length < 2
|
|
83
|
+
? items.join('')
|
|
84
|
+
: `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string[]} args
|
|
89
|
+
* @returns {Promise<{ exitCode: number, forgot?: string[], removed?: string[] }>}
|
|
90
|
+
*/
|
|
91
|
+
export async function forget(args = []) {
|
|
92
|
+
const badFlag = checkFlags('forget', args)
|
|
93
|
+
if (badFlag) {
|
|
94
|
+
say.err(badFlag.message)
|
|
95
|
+
return { exitCode: 2 }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const all = args.includes('--all')
|
|
99
|
+
const flag = readFlagValue(args, '--server')
|
|
100
|
+
if (all && flag) {
|
|
101
|
+
say.err('Use --server <url> or --all, not both.')
|
|
102
|
+
return { exitCode: 2 }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const siteDir = await resolveSiteDir(args, 'forget')
|
|
106
|
+
const known = syncedBackends(siteDir)
|
|
107
|
+
|
|
108
|
+
if (all) return forgetAll(siteDir)
|
|
109
|
+
|
|
110
|
+
if (!flag) {
|
|
111
|
+
say.err('Name what to forget: uniweb forget --server <url>')
|
|
112
|
+
if (known.length) {
|
|
113
|
+
say.dim(`This project has synced with: ${known.join(', ')}`)
|
|
114
|
+
} else {
|
|
115
|
+
say.dim('This project has not synced with any backend.')
|
|
116
|
+
}
|
|
117
|
+
say.dim('For a copied project that should become a new one: uniweb forget --all')
|
|
118
|
+
return { exitCode: 2 }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const origin = normalizeOrigin(flag)
|
|
122
|
+
if (!origin) {
|
|
123
|
+
say.err(`Not a URL: ${flag}`)
|
|
124
|
+
return { exitCode: 2 }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Read before removing, so the report can say what the section held.
|
|
128
|
+
const state = readBackendState(siteDir, origin)
|
|
129
|
+
const removed = []
|
|
130
|
+
if (clearBackend(siteDir, origin)) removed.push('sync.json')
|
|
131
|
+
if (forgetBackendCache(siteDir, origin)) removed.push('.uniweb/backend-cache.json')
|
|
132
|
+
let deploys = []
|
|
133
|
+
try {
|
|
134
|
+
deploys = await forgetDeploys(siteDir, origin)
|
|
135
|
+
if (deploys.length) removed.push('deploy.yml')
|
|
136
|
+
} catch (err) {
|
|
137
|
+
// Not a stop: the identity above is already forgotten, and a deploy.yml that does
|
|
138
|
+
// not parse fails every deploy on its own. Rewriting a file we could not read
|
|
139
|
+
// would be the one thing worse than leaving it.
|
|
140
|
+
say.warn(`${err.message} — its deploy records were left as they are.`)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Idempotent on purpose: a script calls this after every run, and a second call
|
|
144
|
+
// (or a call for a backend the push never reached) is not an error.
|
|
145
|
+
if (!removed.length) {
|
|
146
|
+
say.info(`Nothing recorded for ${origin} — nothing to forget.`)
|
|
147
|
+
if (known.length) say.dim(`This project has synced with: ${known.join(', ')}`)
|
|
148
|
+
return { exitCode: 0, forgot: [origin], removed }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
say.ok(`Forgot ${c.bold}${origin}${c.reset}`)
|
|
152
|
+
if (state.site?.uuid) say.dim(`site ${state.site.uuid}`)
|
|
153
|
+
const counts = [
|
|
154
|
+
['records', state.records],
|
|
155
|
+
['assets', state.assets]
|
|
156
|
+
]
|
|
157
|
+
.map(([name, map]) => [name, map ? Object.keys(map).length : 0])
|
|
158
|
+
.filter(([, n]) => n > 0)
|
|
159
|
+
.map(([name, n]) => `${n} ${name}`)
|
|
160
|
+
if (counts.length) say.dim(counts.join(' · '))
|
|
161
|
+
if (deploys.length) {
|
|
162
|
+
say.dim(`deploy records: ${deploys.join(', ')} (the targets stay)`)
|
|
163
|
+
}
|
|
164
|
+
say.dim(`removed from ${listed(removed)}`)
|
|
165
|
+
say.dim('The site still exists on that backend; this removed only what this project recorded.')
|
|
166
|
+
|
|
167
|
+
return { exitCode: 0, forgot: [origin], removed }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** `--all`: the three files, whole. */
|
|
171
|
+
async function forgetAll(siteDir) {
|
|
172
|
+
const origins = forgetSyncStore(siteDir)
|
|
173
|
+
const cache = forgetAllBackendCaches(siteDir)
|
|
174
|
+
const targets = await forgetDeployYml(siteDir)
|
|
175
|
+
|
|
176
|
+
const removed = []
|
|
177
|
+
if (origins) removed.push('sync.json')
|
|
178
|
+
if (targets) removed.push('deploy.yml')
|
|
179
|
+
if (cache) removed.push('.uniweb/backend-cache.json')
|
|
180
|
+
|
|
181
|
+
if (!removed.length) {
|
|
182
|
+
say.info('Nothing recorded — this project has not synced or deployed anywhere.')
|
|
183
|
+
return { exitCode: 0, forgot: [], removed }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
say.ok('Forgot every backend and deploy target')
|
|
187
|
+
if (origins?.length) say.dim(`backends: ${origins.join(', ')}`)
|
|
188
|
+
if (targets?.length) say.dim(`deploy targets: ${targets.join(', ')}`)
|
|
189
|
+
say.dim(`removed ${listed(removed)}`)
|
|
190
|
+
say.dim('Its next push creates a new site. Every existing site is untouched.')
|
|
191
|
+
// ⛔ The mistake this cannot prevent: running it in the ORIGINAL. That project's
|
|
192
|
+
// next push would then mint a second site on every backend. Both files are
|
|
193
|
+
// committed, so the way back is one command — say it now, while it is cheap.
|
|
194
|
+
say.dim('If this was the original rather than a copy, restore sync.json and deploy.yml from git.')
|
|
195
|
+
|
|
196
|
+
return { exitCode: 0, forgot: origins || [], removed }
|
|
197
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* handoff — RESERVED (not available on the new backend yet).
|
|
3
|
+
*
|
|
4
|
+
* The "create a site and hand it off to a client" flow ran against the legacy
|
|
5
|
+
* platform (the PHP backend + Cloudflare Worker) the CLI no longer talks to. A
|
|
6
|
+
* new-backend CLI equivalent isn't built; the command name is kept reserved so a
|
|
7
|
+
* future rebuild can claim it without a breaking change.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export async function handoff() {
|
|
11
|
+
console.error(
|
|
12
|
+
"\x1b[31m✗\x1b[0m `uniweb handoff` isn't available on the new backend yet."
|
|
13
|
+
)
|
|
14
|
+
console.error(
|
|
15
|
+
' The legacy site-handoff flow was retired with the PHP backend.'
|
|
16
|
+
)
|
|
17
|
+
console.error(' Manage client sites from the Uniweb app for now.')
|
|
18
|
+
process.exit(1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default handoff
|