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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/package.json +7 -7
  3. package/partials/agents.md +51 -0
  4. package/src/backend/client.js +173 -40
  5. package/src/backend/data-bundle.js +15 -3
  6. package/src/backend/foundation-bring-along.js +76 -21
  7. package/src/backend/payment-handoff.js +28 -9
  8. package/src/backend/site-media.js +147 -19
  9. package/src/backend/site-sync.js +362 -40
  10. package/src/commands/add.js +575 -273
  11. package/src/commands/build.js +160 -57
  12. package/src/commands/clone.js +79 -26
  13. package/src/commands/content.js +11 -7
  14. package/src/commands/deploy.js +80 -32
  15. package/src/commands/dev.js +39 -17
  16. package/src/commands/docs.js +44 -16
  17. package/src/commands/doctor.js +338 -82
  18. package/src/commands/export.js +15 -7
  19. package/src/commands/handoff.js +6 -2
  20. package/src/commands/i18n.js +248 -99
  21. package/src/commands/inspect.js +48 -19
  22. package/src/commands/invite.js +9 -3
  23. package/src/commands/org.js +19 -5
  24. package/src/commands/publish.js +229 -60
  25. package/src/commands/pull.js +157 -48
  26. package/src/commands/push.js +144 -42
  27. package/src/commands/refresh.js +37 -10
  28. package/src/commands/register.js +235 -64
  29. package/src/commands/rename.js +126 -46
  30. package/src/commands/runtime.js +74 -24
  31. package/src/commands/status.js +48 -15
  32. package/src/commands/sync.js +7 -2
  33. package/src/commands/template.js +12 -4
  34. package/src/commands/update.js +263 -87
  35. package/src/commands/validate.js +115 -32
  36. package/src/framework-index.json +16 -14
  37. package/src/index.js +298 -145
  38. package/src/templates/fetchers/github.js +7 -7
  39. package/src/templates/fetchers/npm.js +3 -3
  40. package/src/templates/fetchers/release.js +21 -18
  41. package/src/templates/index.js +34 -12
  42. package/src/templates/processor.js +44 -12
  43. package/src/templates/resolver.js +42 -15
  44. package/src/templates/validator.js +14 -7
  45. package/src/utils/asset-upload.js +90 -22
  46. package/src/utils/code-upload.js +62 -37
  47. package/src/utils/config.js +31 -10
  48. package/src/utils/dep-survey.js +33 -7
  49. package/src/utils/destination-prompt.js +27 -17
  50. package/src/utils/git.js +66 -22
  51. package/src/utils/host-prompt.js +4 -3
  52. package/src/utils/install-integrity.js +8 -4
  53. package/src/utils/interactive.js +3 -3
  54. package/src/utils/json-file.js +6 -2
  55. package/src/utils/names.js +15 -6
  56. package/src/utils/placement.js +16 -8
  57. package/src/utils/registry-auth.js +185 -57
  58. package/src/utils/registry-orgs.js +142 -53
  59. package/src/utils/runtime-upload.js +52 -14
  60. package/src/utils/scaffold.js +55 -14
  61. package/src/utils/site-content-refs.js +3 -1
  62. package/src/utils/update-check.js +43 -17
  63. package/src/utils/workspace.js +13 -7
  64. package/src/versions.js +18 -7
  65. 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 { /* ignore corrupt cache */ }
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 { /* ignore write errors */ }
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(`${yellow}Heads up:${reset} this CLI is ${dim}${current}${reset}; latest is ${cyan}${latest}${reset}.`)
70
- console.error(`${dim}Templates ship with the CLI consider updating first:${reset} ${updateCmd}`)
71
- console.error(`${dim}Or run a one-shot fresh:${reset} npx uniweb@latest <command>`)
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(`${yellow}Update available:${reset} ${dim}${current}${reset} → ${cyan}${latest}${reset}`)
74
- console.error(`${dim}Run${reset} ${updateCmd} ${dim}to update the CLI${reset}`)
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 && (Date.now() - state.lastCheck) < maxAgeMs
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', { signal: controller.signal })
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(currentVersion, { timeoutMs = 1500, tone = 'soft' } = {}) {
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', { signal: controller.signal })
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 && (Date.now() - state.lastCheck) < CHECK_INTERVAL) {
217
- if (state.latestVersion && compareSemver(state.latestVersion, currentVersion) > 0) {
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(() => { /* network error — ignore silently */ })
259
+ .catch(() => {
260
+ /* network error — ignore silently */
261
+ })
236
262
 
237
263
  return async () => {
238
264
  await fetchPromise
@@ -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(pkg => classify(join(workspaceRoot, pkg)) === 'foundation')
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
- : { title: c.title, value: c.value !== undefined ? c.value : c.title, description: c.description }
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 = { '10': 18, '11': 22 }
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 = typeof declared === 'string' ? declared.match(/^pnpm@(\d+)/) : null
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(enginesNode, packageManager, pnpmVersion = PNPM_VERSION, fallback = '20') {
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 = packageManager === 'pnpm' ? (PNPM_MIN_NODE[pnpmVersion] ?? 0) : 0
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 = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies }
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/