uniweb 0.13.16 → 0.14.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 +1 -1
- package/package.json +7 -7
- package/partials/agents.md +51 -0
- package/src/backend/client.js +173 -40
- package/src/backend/data-bundle.js +15 -3
- package/src/backend/foundation-bring-along.js +76 -21
- package/src/backend/payment-handoff.js +28 -9
- package/src/backend/site-media.js +147 -19
- package/src/backend/site-sync.js +362 -40
- package/src/commands/add.js +575 -273
- package/src/commands/build.js +160 -57
- package/src/commands/clone.js +79 -26
- package/src/commands/content.js +11 -7
- package/src/commands/deploy.js +80 -32
- package/src/commands/dev.js +39 -17
- package/src/commands/docs.js +44 -16
- package/src/commands/doctor.js +338 -82
- package/src/commands/export.js +15 -7
- package/src/commands/handoff.js +6 -2
- package/src/commands/i18n.js +248 -99
- package/src/commands/inspect.js +48 -19
- package/src/commands/invite.js +9 -3
- package/src/commands/org.js +19 -5
- package/src/commands/publish.js +229 -60
- package/src/commands/pull.js +157 -48
- package/src/commands/push.js +144 -42
- package/src/commands/refresh.js +37 -10
- package/src/commands/register.js +235 -64
- package/src/commands/rename.js +126 -46
- package/src/commands/runtime.js +74 -24
- package/src/commands/status.js +48 -15
- package/src/commands/sync.js +7 -2
- package/src/commands/template.js +12 -4
- package/src/commands/update.js +263 -87
- package/src/commands/validate.js +115 -32
- package/src/framework-index.json +16 -14
- package/src/index.js +298 -145
- package/src/templates/fetchers/github.js +7 -7
- package/src/templates/fetchers/npm.js +3 -3
- package/src/templates/fetchers/release.js +21 -18
- package/src/templates/index.js +34 -12
- package/src/templates/processor.js +44 -12
- package/src/templates/resolver.js +42 -15
- package/src/templates/validator.js +14 -7
- package/src/utils/asset-upload.js +90 -22
- package/src/utils/code-upload.js +62 -37
- package/src/utils/config.js +31 -10
- package/src/utils/dep-survey.js +33 -7
- package/src/utils/destination-prompt.js +27 -17
- package/src/utils/git.js +66 -22
- package/src/utils/host-prompt.js +4 -3
- package/src/utils/install-integrity.js +8 -4
- package/src/utils/interactive.js +3 -3
- package/src/utils/json-file.js +6 -2
- package/src/utils/names.js +15 -6
- package/src/utils/placement.js +16 -8
- package/src/utils/registry-auth.js +185 -57
- package/src/utils/registry-orgs.js +142 -53
- package/src/utils/runtime-upload.js +52 -14
- package/src/utils/scaffold.js +55 -14
- package/src/utils/site-content-refs.js +3 -1
- package/src/utils/update-check.js +43 -17
- package/src/utils/workspace.js +13 -7
- package/src/versions.js +18 -7
- package/templates/site/_gitignore +5 -0
|
@@ -37,7 +37,9 @@ function readState() {
|
|
|
37
37
|
if (existsSync(STATE_FILE)) {
|
|
38
38
|
return JSON.parse(readFileSync(STATE_FILE, 'utf8'))
|
|
39
39
|
}
|
|
40
|
-
} catch {
|
|
40
|
+
} catch {
|
|
41
|
+
/* ignore corrupt cache */
|
|
42
|
+
}
|
|
41
43
|
return {}
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -48,7 +50,9 @@ function writeState(state) {
|
|
|
48
50
|
try {
|
|
49
51
|
if (!existsSync(STATE_DIR)) mkdirSync(STATE_DIR, { recursive: true })
|
|
50
52
|
writeFileSync(STATE_FILE, JSON.stringify(state))
|
|
51
|
-
} catch {
|
|
53
|
+
} catch {
|
|
54
|
+
/* ignore write errors */
|
|
55
|
+
}
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
/**
|
|
@@ -66,12 +70,22 @@ function printNotification(current, latest, tone = 'soft') {
|
|
|
66
70
|
const updateCmd = globalCliUpdateCmd(detectGlobalCliPm())
|
|
67
71
|
console.error('')
|
|
68
72
|
if (tone === 'eager') {
|
|
69
|
-
console.error(
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
console.error(
|
|
74
|
+
`${yellow}Heads up:${reset} this CLI is ${dim}${current}${reset}; latest is ${cyan}${latest}${reset}.`
|
|
75
|
+
)
|
|
76
|
+
console.error(
|
|
77
|
+
`${dim}Templates ship with the CLI — consider updating first:${reset} ${updateCmd}`
|
|
78
|
+
)
|
|
79
|
+
console.error(
|
|
80
|
+
`${dim}Or run a one-shot fresh:${reset} npx uniweb@latest <command>`
|
|
81
|
+
)
|
|
72
82
|
} else {
|
|
73
|
-
console.error(
|
|
74
|
-
|
|
83
|
+
console.error(
|
|
84
|
+
`${yellow}Update available:${reset} ${dim}${current}${reset} → ${cyan}${latest}${reset}`
|
|
85
|
+
)
|
|
86
|
+
console.error(
|
|
87
|
+
`${dim}Run${reset} ${updateCmd} ${dim}to update the CLI${reset}`
|
|
88
|
+
)
|
|
75
89
|
}
|
|
76
90
|
}
|
|
77
91
|
|
|
@@ -131,11 +145,11 @@ export const maybeEagerNotification = maybeNotifyFromCache
|
|
|
131
145
|
export async function getLatestVersion({
|
|
132
146
|
timeoutMs = 1500,
|
|
133
147
|
allowNetwork = true,
|
|
134
|
-
maxAgeMs = CHECK_INTERVAL
|
|
148
|
+
maxAgeMs = CHECK_INTERVAL
|
|
135
149
|
} = {}) {
|
|
136
150
|
const state = readState()
|
|
137
151
|
const cached = state.latestVersion || null
|
|
138
|
-
const fresh = state.lastCheck &&
|
|
152
|
+
const fresh = state.lastCheck && Date.now() - state.lastCheck < maxAgeMs
|
|
139
153
|
if (fresh && cached) return cached
|
|
140
154
|
// A stale cache entry still beats nothing for an advisory, so it's the
|
|
141
155
|
// fallback for every failure path below rather than a hard null.
|
|
@@ -144,7 +158,9 @@ export async function getLatestVersion({
|
|
|
144
158
|
const controller = new AbortController()
|
|
145
159
|
const timer = setTimeout(() => controller.abort(), timeoutMs)
|
|
146
160
|
try {
|
|
147
|
-
const res = await fetch('https://registry.npmjs.org/uniweb/latest', {
|
|
161
|
+
const res = await fetch('https://registry.npmjs.org/uniweb/latest', {
|
|
162
|
+
signal: controller.signal
|
|
163
|
+
})
|
|
148
164
|
if (!res.ok) return cached
|
|
149
165
|
const data = await res.json()
|
|
150
166
|
const latest = data?.version || null
|
|
@@ -175,12 +191,17 @@ export async function getLatestVersion({
|
|
|
175
191
|
* @param {'eager'|'soft'} [opts.tone='soft'] Notification copy.
|
|
176
192
|
* @returns {Promise<boolean>} true if a notice was printed.
|
|
177
193
|
*/
|
|
178
|
-
export async function fetchAndNotifyIfNewer(
|
|
194
|
+
export async function fetchAndNotifyIfNewer(
|
|
195
|
+
currentVersion,
|
|
196
|
+
{ timeoutMs = 1500, tone = 'soft' } = {}
|
|
197
|
+
) {
|
|
179
198
|
const controller = new AbortController()
|
|
180
199
|
const timer = setTimeout(() => controller.abort(), timeoutMs)
|
|
181
200
|
let latest = null
|
|
182
201
|
try {
|
|
183
|
-
const res = await fetch('https://registry.npmjs.org/uniweb/latest', {
|
|
202
|
+
const res = await fetch('https://registry.npmjs.org/uniweb/latest', {
|
|
203
|
+
signal: controller.signal
|
|
204
|
+
})
|
|
184
205
|
if (res.ok) {
|
|
185
206
|
const data = await res.json()
|
|
186
207
|
latest = data?.version || null
|
|
@@ -213,8 +234,11 @@ export function startUpdateCheck(currentVersion) {
|
|
|
213
234
|
const state = readState()
|
|
214
235
|
|
|
215
236
|
// Use cached result if checked recently
|
|
216
|
-
if (state.lastCheck &&
|
|
217
|
-
if (
|
|
237
|
+
if (state.lastCheck && Date.now() - state.lastCheck < CHECK_INTERVAL) {
|
|
238
|
+
if (
|
|
239
|
+
state.latestVersion &&
|
|
240
|
+
compareSemver(state.latestVersion, currentVersion) > 0
|
|
241
|
+
) {
|
|
218
242
|
notification = state.latestVersion
|
|
219
243
|
}
|
|
220
244
|
return () => {
|
|
@@ -224,15 +248,17 @@ export function startUpdateCheck(currentVersion) {
|
|
|
224
248
|
|
|
225
249
|
// Background fetch (non-blocking)
|
|
226
250
|
const fetchPromise = fetch('https://registry.npmjs.org/uniweb/latest')
|
|
227
|
-
.then(r => r.json())
|
|
228
|
-
.then(data => {
|
|
251
|
+
.then((r) => r.json())
|
|
252
|
+
.then((data) => {
|
|
229
253
|
const latest = data.version
|
|
230
254
|
writeState({ lastCheck: Date.now(), latestVersion: latest })
|
|
231
255
|
if (compareSemver(latest, currentVersion) > 0) {
|
|
232
256
|
notification = latest
|
|
233
257
|
}
|
|
234
258
|
})
|
|
235
|
-
.catch(() => {
|
|
259
|
+
.catch(() => {
|
|
260
|
+
/* network error — ignore silently */
|
|
261
|
+
})
|
|
236
262
|
|
|
237
263
|
return async () => {
|
|
238
264
|
await fetchPromise
|
package/src/utils/workspace.js
CHANGED
|
@@ -160,9 +160,11 @@ export async function classifyPackage(packagePath) {
|
|
|
160
160
|
export async function findFoundations(workspaceRoot) {
|
|
161
161
|
const [packages, classify] = await Promise.all([
|
|
162
162
|
getWorkspacePackages(workspaceRoot),
|
|
163
|
-
getClassifier()
|
|
163
|
+
getClassifier()
|
|
164
164
|
])
|
|
165
|
-
return packages.filter(
|
|
165
|
+
return packages.filter(
|
|
166
|
+
(pkg) => classify(join(workspaceRoot, pkg)) === 'foundation'
|
|
167
|
+
)
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
/**
|
|
@@ -173,9 +175,9 @@ export async function findFoundations(workspaceRoot) {
|
|
|
173
175
|
export async function findSites(workspaceRoot) {
|
|
174
176
|
const [packages, classify] = await Promise.all([
|
|
175
177
|
getWorkspacePackages(workspaceRoot),
|
|
176
|
-
getClassifier()
|
|
178
|
+
getClassifier()
|
|
177
179
|
])
|
|
178
|
-
return packages.filter(pkg => classify(join(workspaceRoot, pkg)) === 'site')
|
|
180
|
+
return packages.filter((pkg) => classify(join(workspaceRoot, pkg)) === 'site')
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
/**
|
|
@@ -206,11 +208,15 @@ export async function promptSelect(message, choices) {
|
|
|
206
208
|
type: 'select',
|
|
207
209
|
name: 'value',
|
|
208
210
|
message,
|
|
209
|
-
choices: choices.map(c =>
|
|
211
|
+
choices: choices.map((c) =>
|
|
210
212
|
typeof c === 'string'
|
|
211
213
|
? { title: c, value: c }
|
|
212
|
-
: {
|
|
213
|
-
|
|
214
|
+
: {
|
|
215
|
+
title: c.title,
|
|
216
|
+
value: c.value !== undefined ? c.value : c.title,
|
|
217
|
+
description: c.description
|
|
218
|
+
}
|
|
219
|
+
)
|
|
214
220
|
})
|
|
215
221
|
|
|
216
222
|
return response.value ?? null
|
package/src/versions.js
CHANGED
|
@@ -95,7 +95,7 @@ export const PNPM_VERSION = '11'
|
|
|
95
95
|
*
|
|
96
96
|
* Verify with `npm view pnpm@<major> engines` when adding an entry.
|
|
97
97
|
*/
|
|
98
|
-
export const PNPM_MIN_NODE = {
|
|
98
|
+
export const PNPM_MIN_NODE = { 10: 18, 11: 22 }
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
101
|
* Resolve the pnpm major a generated CI workflow should install.
|
|
@@ -127,7 +127,8 @@ export const PNPM_MIN_NODE = { '10': 18, '11': 22 }
|
|
|
127
127
|
*/
|
|
128
128
|
export function resolveCiPnpmVersion(rootPkg, installedMajor = null) {
|
|
129
129
|
const declared = rootPkg?.packageManager
|
|
130
|
-
const match =
|
|
130
|
+
const match =
|
|
131
|
+
typeof declared === 'string' ? declared.match(/^pnpm@(\d+)/) : null
|
|
131
132
|
if (match) return match[1]
|
|
132
133
|
if (installedMajor) return String(installedMajor)
|
|
133
134
|
return PNPM_VERSION
|
|
@@ -148,10 +149,16 @@ export function resolveCiPnpmVersion(rootPkg, installedMajor = null) {
|
|
|
148
149
|
* @param {string} [fallback='20'] — used when engines.node is absent/unparseable.
|
|
149
150
|
* @returns {string} Node major, as a string for YAML interpolation.
|
|
150
151
|
*/
|
|
151
|
-
export function resolveCiNodeVersion(
|
|
152
|
+
export function resolveCiNodeVersion(
|
|
153
|
+
enginesNode,
|
|
154
|
+
packageManager,
|
|
155
|
+
pnpmVersion = PNPM_VERSION,
|
|
156
|
+
fallback = '20'
|
|
157
|
+
) {
|
|
152
158
|
const match = enginesNode ? String(enginesNode).match(/(\d+)/) : null
|
|
153
159
|
const declared = match ? Number(match[1]) : Number(fallback)
|
|
154
|
-
const floor =
|
|
160
|
+
const floor =
|
|
161
|
+
packageManager === 'pnpm' ? (PNPM_MIN_NODE[pnpmVersion] ?? 0) : 0
|
|
155
162
|
return String(Math.max(declared, floor))
|
|
156
163
|
}
|
|
157
164
|
|
|
@@ -340,7 +347,11 @@ export function getResolvedVersions() {
|
|
|
340
347
|
if (resolvedVersions) return resolvedVersions
|
|
341
348
|
|
|
342
349
|
const pkg = getCliPackageJson()
|
|
343
|
-
const deps = {
|
|
350
|
+
const deps = {
|
|
351
|
+
...pkg.dependencies,
|
|
352
|
+
...pkg.devDependencies,
|
|
353
|
+
...pkg.peerDependencies
|
|
354
|
+
}
|
|
344
355
|
|
|
345
356
|
// Seed from the CLI's own deps (the authoritative set when installed from npm).
|
|
346
357
|
const result = {}
|
|
@@ -410,7 +421,7 @@ export function getVersionsForTemplates() {
|
|
|
410
421
|
core: versions['@uniweb/core'],
|
|
411
422
|
kit: versions['@uniweb/kit'],
|
|
412
423
|
templates: versions['@uniweb/templates'],
|
|
413
|
-
cli: versions['uniweb']
|
|
424
|
+
cli: versions['uniweb']
|
|
414
425
|
}
|
|
415
426
|
}
|
|
416
427
|
|
|
@@ -440,6 +451,6 @@ export function updatePackageVersions(pkg) {
|
|
|
440
451
|
...pkg,
|
|
441
452
|
dependencies: updateDeps(pkg.dependencies),
|
|
442
453
|
devDependencies: updateDeps(pkg.devDependencies),
|
|
443
|
-
peerDependencies: updateDeps(pkg.peerDependencies)
|
|
454
|
+
peerDependencies: updateDeps(pkg.peerDependencies)
|
|
444
455
|
}
|
|
445
456
|
}
|
|
@@ -3,3 +3,8 @@ dist
|
|
|
3
3
|
.uniweb/
|
|
4
4
|
.DS_Store
|
|
5
5
|
*.local
|
|
6
|
+
|
|
7
|
+
# Compiled collections. Generated from collections/ on every build — it lands
|
|
8
|
+
# in the source tree rather than dist/, so without this it looks permanent,
|
|
9
|
+
# gets committed, and then looks like something you may edit. It isn't.
|
|
10
|
+
public/data/
|