uniweb 0.12.2 → 0.12.4
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 +32 -22
- package/package.json +4 -4
- package/src/commands/add.js +88 -12
- package/src/commands/build.js +199 -28
- package/src/commands/deploy.js +318 -16
- package/src/commands/doctor.js +172 -130
- package/src/commands/handoff.js +1 -1
- package/src/commands/invite.js +2 -2
- package/src/commands/publish.js +297 -54
- package/src/commands/rename.js +310 -0
- package/src/framework-index.json +4 -4
- package/src/index.js +14 -5
- package/src/utils/receipt.js +91 -0
- package/src/utils/registry.js +33 -0
- package/templates/workspace/package.json.hbs +2 -4
package/src/commands/doctor.js
CHANGED
|
@@ -2,12 +2,30 @@
|
|
|
2
2
|
* uniweb doctor - Diagnose project configuration issues
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
5
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
|
|
6
6
|
import { join, resolve, basename, dirname, relative } from 'node:path'
|
|
7
7
|
import yaml from 'js-yaml'
|
|
8
8
|
import { resolveFoundationSrcPath, classifyPackage, isExtensionPackage as buildIsExtensionPackage } from '@uniweb/build'
|
|
9
9
|
import { getCliVersion } from '../versions.js'
|
|
10
10
|
import { readAgentsVersion } from '../utils/agents-stamp.js'
|
|
11
|
+
import { discoverFoundations, discoverSites } from '../utils/config.js'
|
|
12
|
+
import { findWorkspaceRoot } from '../utils/workspace.js'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse the `--fix [<issue-id>]` flag.
|
|
16
|
+
*
|
|
17
|
+
* Returns:
|
|
18
|
+
* null — no auto-fix requested.
|
|
19
|
+
* 'all' — fix every auto-fixable issue.
|
|
20
|
+
* '<issue-id>' — fix only issues with this id.
|
|
21
|
+
*/
|
|
22
|
+
function parseFixFlag(args) {
|
|
23
|
+
const idx = args.indexOf('--fix')
|
|
24
|
+
if (idx === -1) return null
|
|
25
|
+
const next = args[idx + 1]
|
|
26
|
+
if (!next || next.startsWith('--')) return 'all'
|
|
27
|
+
return next
|
|
28
|
+
}
|
|
11
29
|
|
|
12
30
|
// ANSI colors
|
|
13
31
|
const colors = {
|
|
@@ -119,29 +137,20 @@ export async function doctor(args = []) {
|
|
|
119
137
|
log(`${colors.blue}${colors.bright}Uniweb Doctor${colors.reset}`)
|
|
120
138
|
log(`${colors.dim}Checking project configuration...${colors.reset}`)
|
|
121
139
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
|
|
140
|
+
// Auto-fix mode. `--fix` alone fixes every recoverable issue;
|
|
141
|
+
// `--fix <issue-id>` targets one. Per-issue fix logic lives next to
|
|
142
|
+
// each diagnostic below so the rewrite happens with full context.
|
|
143
|
+
const fixFlag = parseFixFlag(args)
|
|
144
|
+
const shouldFix = (id) => fixFlag === 'all' || fixFlag === id
|
|
145
|
+
const fixed = (msg) => console.log(` ${colors.green}↳ Fixed:${colors.reset} ${msg}`)
|
|
126
146
|
|
|
127
|
-
|
|
128
|
-
workspaceDir = dirname(projectDir)
|
|
129
|
-
if (basename(workspaceDir) === 'sites') {
|
|
130
|
-
workspaceDir = dirname(workspaceDir)
|
|
131
|
-
}
|
|
132
|
-
} else if (isFoundation(projectDir)) {
|
|
133
|
-
workspaceDir = dirname(projectDir)
|
|
134
|
-
const parentName = basename(workspaceDir)
|
|
135
|
-
if (parentName === 'foundations' || parentName === 'extensions') {
|
|
136
|
-
workspaceDir = dirname(workspaceDir)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
147
|
+
const projectDir = resolve(process.cwd())
|
|
139
148
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
149
|
+
// Find workspace root via the canonical primitive (recognizes
|
|
150
|
+
// pnpm-workspace.yaml or package.json::workspaces).
|
|
151
|
+
const workspaceDir = findWorkspaceRoot(projectDir)
|
|
143
152
|
|
|
144
|
-
if (!
|
|
153
|
+
if (!workspaceDir) {
|
|
145
154
|
error('Not in a Uniweb workspace')
|
|
146
155
|
log(`${colors.dim}Run this command from your project root or a site/foundation directory.${colors.reset}`)
|
|
147
156
|
process.exit(1)
|
|
@@ -150,65 +159,76 @@ export async function doctor(args = []) {
|
|
|
150
159
|
log('')
|
|
151
160
|
info(`Workspace: ${workspaceDir}`)
|
|
152
161
|
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
folderName: 'foundation'
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Check multi-foundation layout
|
|
168
|
-
const foundationsDir = join(workspaceDir, 'foundations')
|
|
169
|
-
if (existsSync(foundationsDir)) {
|
|
162
|
+
// Workspace manifest sync — keep `pnpm-workspace.yaml::packages` and
|
|
163
|
+
// `package.json::workspaces` aligned. The CLI writes both on every
|
|
164
|
+
// mutation (see addWorkspaceGlob in utils/config.js), but a user who
|
|
165
|
+
// manually edits one can introduce drift. Drift breaks projects that
|
|
166
|
+
// switch package managers (pnpm-workspace.yaml is pnpm-only;
|
|
167
|
+
// package.json::workspaces is what npm and yarn read).
|
|
168
|
+
const issues = []
|
|
169
|
+
const ymlPath = join(workspaceDir, 'pnpm-workspace.yaml')
|
|
170
|
+
if (existsSync(ymlPath)) {
|
|
171
|
+
let ymlPackages = []
|
|
170
172
|
try {
|
|
171
|
-
|
|
172
|
-
for (const entry of entries) {
|
|
173
|
-
if (entry.isDirectory()) {
|
|
174
|
-
const foundationPath = join(foundationsDir, entry.name)
|
|
175
|
-
if (isFoundation(foundationPath)) {
|
|
176
|
-
const pkg = loadPackageJson(foundationPath)
|
|
177
|
-
foundations.push({
|
|
178
|
-
path: foundationPath,
|
|
179
|
-
name: pkg?.name || entry.name,
|
|
180
|
-
folderName: entry.name
|
|
181
|
-
})
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
173
|
+
ymlPackages = yaml.load(readFileSync(ymlPath, 'utf8'))?.packages || []
|
|
185
174
|
} catch {
|
|
186
|
-
//
|
|
175
|
+
// Malformed yaml — flag separately
|
|
176
|
+
issues.push({
|
|
177
|
+
id: 'workspace-yaml-malformed',
|
|
178
|
+
type: 'error',
|
|
179
|
+
message: 'pnpm-workspace.yaml is malformed and could not be parsed.',
|
|
180
|
+
})
|
|
181
|
+
error('pnpm-workspace.yaml is malformed and could not be parsed.')
|
|
182
|
+
}
|
|
183
|
+
const rootPkg = loadPackageJson(workspaceDir)
|
|
184
|
+
const pkgWorkspaces = Array.isArray(rootPkg?.workspaces) ? rootPkg.workspaces : []
|
|
185
|
+
const ymlSet = new Set(ymlPackages)
|
|
186
|
+
const pkgSet = new Set(pkgWorkspaces)
|
|
187
|
+
const onlyInYml = [...ymlSet].filter(g => !pkgSet.has(g))
|
|
188
|
+
const onlyInPkg = [...pkgSet].filter(g => !ymlSet.has(g))
|
|
189
|
+
if (onlyInYml.length || onlyInPkg.length) {
|
|
190
|
+
const issue = {
|
|
191
|
+
id: 'workspace-manifests-out-of-sync',
|
|
192
|
+
type: 'warn',
|
|
193
|
+
message: `pnpm-workspace.yaml and package.json::workspaces declare different package globs.`,
|
|
194
|
+
details: { onlyInYml, onlyInPkg },
|
|
195
|
+
}
|
|
196
|
+
issues.push(issue)
|
|
197
|
+
warn(`[workspace-manifests-out-of-sync] pnpm-workspace.yaml and package.json::workspaces are out of sync:`)
|
|
198
|
+
if (onlyInYml.length) log(` only in pnpm-workspace.yaml: ${onlyInYml.join(', ')}`)
|
|
199
|
+
if (onlyInPkg.length) log(` only in package.json::workspaces: ${onlyInPkg.join(', ')}`)
|
|
200
|
+
if (shouldFix('workspace-manifests-out-of-sync')) {
|
|
201
|
+
// Canonical resolution: write the union to both manifests.
|
|
202
|
+
const union = Array.from(new Set([...ymlPackages, ...pkgWorkspaces])).sort()
|
|
203
|
+
writeFileSync(ymlPath, yaml.dump({ packages: union }, { flowLevel: -1, quotingType: '"' }))
|
|
204
|
+
const rootPkgPath = join(workspaceDir, 'package.json')
|
|
205
|
+
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
|
|
206
|
+
rootPkg.workspaces = union
|
|
207
|
+
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
|
|
208
|
+
issue.fixed = true
|
|
209
|
+
fixed(`wrote union [${union.join(', ')}] to both manifests`)
|
|
210
|
+
} else {
|
|
211
|
+
log(` ${colors.dim}Pick one set of globs and copy it to the other manifest. The two should always match — pnpm reads pnpm-workspace.yaml, npm/yarn read package.json::workspaces.${colors.reset}`)
|
|
212
|
+
}
|
|
187
213
|
}
|
|
188
214
|
}
|
|
189
215
|
|
|
190
|
-
// Discover
|
|
216
|
+
// Discover foundations + sites via the canonical workspace globs.
|
|
217
|
+
// Doctor used to walk fixed paths (`foundation/`, `foundations/*`) which
|
|
218
|
+
// missed the default-path `src/` shape that Thread D made canonical.
|
|
219
|
+
// Using the same primitives every other command uses keeps doctor in
|
|
220
|
+
// step with whatever layout the workspace has.
|
|
221
|
+
const discovered = await discoverFoundations(workspaceDir)
|
|
222
|
+
const foundations = []
|
|
191
223
|
const extensions = []
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (isFoundation(extensionPath)) {
|
|
201
|
-
const pkg = loadPackageJson(extensionPath)
|
|
202
|
-
extensions.push({
|
|
203
|
-
path: extensionPath,
|
|
204
|
-
name: pkg?.name || entry.name,
|
|
205
|
-
folderName: entry.name
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
} catch {
|
|
211
|
-
// Ignore errors
|
|
224
|
+
for (const f of discovered) {
|
|
225
|
+
const fullPath = join(workspaceDir, f.path)
|
|
226
|
+
const folderName = basename(f.path)
|
|
227
|
+
const entry = { path: fullPath, name: f.name, folderName }
|
|
228
|
+
if (buildIsExtensionPackage(fullPath)) {
|
|
229
|
+
extensions.push(entry)
|
|
230
|
+
} else {
|
|
231
|
+
foundations.push(entry)
|
|
212
232
|
}
|
|
213
233
|
}
|
|
214
234
|
|
|
@@ -231,32 +251,12 @@ export async function doctor(args = []) {
|
|
|
231
251
|
}
|
|
232
252
|
}
|
|
233
253
|
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
sites.push({ path: siteDir, name: 'site' })
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Check multi-site layout
|
|
244
|
-
const sitesDir = join(workspaceDir, 'sites')
|
|
245
|
-
if (existsSync(sitesDir)) {
|
|
246
|
-
try {
|
|
247
|
-
const entries = readdirSync(sitesDir, { withFileTypes: true })
|
|
248
|
-
for (const entry of entries) {
|
|
249
|
-
if (entry.isDirectory()) {
|
|
250
|
-
const sitePath = join(sitesDir, entry.name)
|
|
251
|
-
if (isSite(sitePath)) {
|
|
252
|
-
sites.push({ path: sitePath, name: entry.name })
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
} catch {
|
|
257
|
-
// Ignore errors
|
|
258
|
-
}
|
|
259
|
-
}
|
|
254
|
+
// Discover sites via the canonical workspace globs (same rationale as
|
|
255
|
+
// foundations above: respects whatever layout the user chose).
|
|
256
|
+
const sites = (await discoverSites(workspaceDir)).map(s => ({
|
|
257
|
+
path: join(workspaceDir, s.path),
|
|
258
|
+
name: s.name,
|
|
259
|
+
}))
|
|
260
260
|
|
|
261
261
|
if (sites.length === 0) {
|
|
262
262
|
warn('No sites found')
|
|
@@ -268,9 +268,8 @@ export async function doctor(args = []) {
|
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
// Check each site
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
// Check each site (issues array was declared earlier alongside the
|
|
272
|
+
// workspace-manifest-sync check).
|
|
274
273
|
for (const site of sites) {
|
|
275
274
|
const siteName = site.name
|
|
276
275
|
const sitePath = site.path
|
|
@@ -305,17 +304,27 @@ export async function doctor(args = []) {
|
|
|
305
304
|
// Check if it might match a folder name instead
|
|
306
305
|
const folderMatch = foundations.find(f => f.folderName === foundationName)
|
|
307
306
|
if (folderMatch) {
|
|
308
|
-
|
|
307
|
+
const issue = {
|
|
308
|
+
id: 'foundation-name-mismatch',
|
|
309
309
|
type: 'error',
|
|
310
310
|
site: siteName,
|
|
311
|
-
message: `Foundation mismatch: site.yml uses folder name "${foundationName}" instead of package name "${folderMatch.name}"
|
|
312
|
-
}
|
|
313
|
-
|
|
311
|
+
message: `Foundation mismatch: site.yml uses folder name "${foundationName}" instead of package name "${folderMatch.name}"`,
|
|
312
|
+
}
|
|
313
|
+
issues.push(issue)
|
|
314
|
+
error(`[foundation-name-mismatch] Foundation mismatch:`)
|
|
314
315
|
log(` site.yml says: ${colors.yellow}foundation: ${foundationName}${colors.reset}`)
|
|
315
316
|
log(` This matches the folder name, but the package name is: ${colors.green}${folderMatch.name}${colors.reset}`)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
317
|
+
if (shouldFix('foundation-name-mismatch')) {
|
|
318
|
+
const siteYmlPath = join(sitePath, 'site.yml')
|
|
319
|
+
const updated = { ...siteYml, foundation: folderMatch.name }
|
|
320
|
+
writeFileSync(siteYmlPath, yaml.dump(updated, { flowLevel: -1, quotingType: "'" }))
|
|
321
|
+
issue.fixed = true
|
|
322
|
+
fixed(`${relative(workspaceDir, siteYmlPath)} now references "${folderMatch.name}"`)
|
|
323
|
+
} else {
|
|
324
|
+
log('')
|
|
325
|
+
log(` ${colors.dim}To fix, update site.yml:${colors.reset}`)
|
|
326
|
+
log(` foundation: ${folderMatch.name}`)
|
|
327
|
+
}
|
|
319
328
|
continue
|
|
320
329
|
}
|
|
321
330
|
|
|
@@ -340,30 +349,54 @@ export async function doctor(args = []) {
|
|
|
340
349
|
const depValue = deps[foundationName]
|
|
341
350
|
|
|
342
351
|
if (!depValue) {
|
|
343
|
-
|
|
352
|
+
const issue = {
|
|
353
|
+
id: 'missing-foundation-dep',
|
|
344
354
|
type: 'error',
|
|
345
355
|
site: siteName,
|
|
346
|
-
message: `Missing dependency "${foundationName}" in package.json
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
356
|
+
message: `Missing dependency "${foundationName}" in package.json`,
|
|
357
|
+
}
|
|
358
|
+
issues.push(issue)
|
|
359
|
+
error(`[missing-foundation-dep] Missing dependency "${foundationName}" in package.json`)
|
|
360
|
+
const expectedPath = `file:${relative(sitePath, matchingFoundation.path)}`
|
|
361
|
+
if (shouldFix('missing-foundation-dep')) {
|
|
362
|
+
const sitePkgPath = join(sitePath, 'package.json')
|
|
363
|
+
const updatedPkg = { ...sitePkg }
|
|
364
|
+
updatedPkg.dependencies = { ...(updatedPkg.dependencies || {}), [foundationName]: expectedPath }
|
|
365
|
+
writeFileSync(sitePkgPath, JSON.stringify(updatedPkg, null, 2) + '\n')
|
|
366
|
+
issue.fixed = true
|
|
367
|
+
fixed(`added "${foundationName}": "${expectedPath}" to ${relative(workspaceDir, sitePkgPath)}`)
|
|
368
|
+
} else {
|
|
369
|
+
log('')
|
|
370
|
+
log(` ${colors.dim}Add to site's package.json dependencies:${colors.reset}`)
|
|
371
|
+
log(` "${foundationName}": "${expectedPath}"`)
|
|
372
|
+
}
|
|
352
373
|
continue
|
|
353
374
|
}
|
|
354
375
|
|
|
355
376
|
if (depValue.startsWith('file:')) {
|
|
356
377
|
const depPath = join(sitePath, depValue.slice(5))
|
|
357
378
|
if (!existsSync(depPath)) {
|
|
358
|
-
|
|
379
|
+
const issue = {
|
|
380
|
+
id: 'stale-file-path',
|
|
359
381
|
type: 'error',
|
|
360
382
|
site: siteName,
|
|
361
|
-
message: `Dependency path doesn't exist: ${depValue}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
383
|
+
message: `Dependency path doesn't exist: ${depValue}`,
|
|
384
|
+
}
|
|
385
|
+
issues.push(issue)
|
|
386
|
+
error(`[stale-file-path] Dependency path doesn't exist: ${depValue}`)
|
|
387
|
+
const expectedPath = `file:${relative(sitePath, matchingFoundation.path)}`
|
|
388
|
+
if (shouldFix('stale-file-path')) {
|
|
389
|
+
const sitePkgPath = join(sitePath, 'package.json')
|
|
390
|
+
const updatedPkg = { ...sitePkg }
|
|
391
|
+
updatedPkg.dependencies = { ...(updatedPkg.dependencies || {}), [foundationName]: expectedPath }
|
|
392
|
+
writeFileSync(sitePkgPath, JSON.stringify(updatedPkg, null, 2) + '\n')
|
|
393
|
+
issue.fixed = true
|
|
394
|
+
fixed(`updated "${foundationName}" to "${expectedPath}" in ${relative(workspaceDir, sitePkgPath)}`)
|
|
395
|
+
} else {
|
|
396
|
+
log('')
|
|
397
|
+
log(` ${colors.dim}Update site's package.json:${colors.reset}`)
|
|
398
|
+
log(` "${foundationName}": "${expectedPath}"`)
|
|
399
|
+
}
|
|
367
400
|
continue
|
|
368
401
|
}
|
|
369
402
|
success(`Dependency path: ${depValue}`)
|
|
@@ -512,23 +545,32 @@ export async function doctor(args = []) {
|
|
|
512
545
|
log('')
|
|
513
546
|
log('─'.repeat(50))
|
|
514
547
|
|
|
515
|
-
|
|
516
|
-
|
|
548
|
+
// Fixed issues no longer count toward errors/warnings — they're
|
|
549
|
+
// resolved during this run. Exit code is based on what remains.
|
|
550
|
+
const errors = issues.filter(i => i.type === 'error' && !i.fixed)
|
|
551
|
+
const warnings = issues.filter(i => i.type === 'warn' && !i.fixed)
|
|
552
|
+
const fixedCount = issues.filter(i => i.fixed).length
|
|
517
553
|
|
|
518
|
-
if (errors.length === 0 && warnings.length === 0) {
|
|
554
|
+
if (errors.length === 0 && warnings.length === 0 && fixedCount === 0) {
|
|
519
555
|
log('')
|
|
520
556
|
log(`${colors.green}${colors.bright}All checks passed!${colors.reset}`)
|
|
521
557
|
log('')
|
|
522
558
|
} else {
|
|
523
559
|
log('')
|
|
560
|
+
if (fixedCount > 0) {
|
|
561
|
+
log(`${colors.green}${fixedCount} issue(s) fixed${colors.reset}`)
|
|
562
|
+
}
|
|
524
563
|
if (errors.length > 0) {
|
|
525
|
-
log(`${colors.red}${errors.length} error(s)${colors.reset}`)
|
|
564
|
+
log(`${colors.red}${errors.length} error(s) remaining${colors.reset}`)
|
|
526
565
|
}
|
|
527
566
|
if (warnings.length > 0) {
|
|
528
|
-
log(`${colors.yellow}${warnings.length} warning(s)${colors.reset}`)
|
|
567
|
+
log(`${colors.yellow}${warnings.length} warning(s) remaining${colors.reset}`)
|
|
568
|
+
}
|
|
569
|
+
if (fixFlag && (errors.length > 0 || warnings.length > 0)) {
|
|
570
|
+
log(`${colors.dim}Some issues were not auto-fixable. See the diagnostics above.${colors.reset}`)
|
|
529
571
|
}
|
|
530
572
|
log('')
|
|
531
573
|
}
|
|
532
574
|
|
|
533
|
-
return { issues, errors: errors.length, warnings: warnings.length }
|
|
575
|
+
return { issues, errors: errors.length, warnings: warnings.length, fixed: fixedCount }
|
|
534
576
|
}
|
package/src/commands/handoff.js
CHANGED
|
@@ -160,7 +160,7 @@ function showWebHandoff(email, name) {
|
|
|
160
160
|
console.log('')
|
|
161
161
|
info(`Web-based handoff`)
|
|
162
162
|
console.log('')
|
|
163
|
-
console.log(` 1. Create a site on ${colors.cyan}
|
|
163
|
+
console.log(` 1. Create a site on ${colors.cyan}uniweb.app${colors.reset} using ${colors.bright}${name}${colors.reset}`)
|
|
164
164
|
console.log(` 2. Add pages and content`)
|
|
165
165
|
console.log(` 3. Transfer ownership to ${colors.bright}${email}${colors.reset}:`)
|
|
166
166
|
console.log(` ${colors.dim}Settings → Transfer site${colors.reset}`)
|
package/src/commands/invite.js
CHANGED
|
@@ -275,10 +275,10 @@ async function handleCreate(args, email) {
|
|
|
275
275
|
console.log('')
|
|
276
276
|
if (isExtension) {
|
|
277
277
|
console.log(` ${colors.dim}When ${invite.email} adds ${name} to their site${colors.reset}`)
|
|
278
|
-
console.log(` ${colors.dim}on
|
|
278
|
+
console.log(` ${colors.dim}on uniweb.app or Studio, it will be authorized automatically.${colors.reset}`)
|
|
279
279
|
} else {
|
|
280
280
|
console.log(` ${colors.dim}When ${invite.email} creates a site with ${name}${colors.reset}`)
|
|
281
|
-
console.log(` ${colors.dim}on
|
|
281
|
+
console.log(` ${colors.dim}on uniweb.app or Studio, it will be authorized automatically.${colors.reset}`)
|
|
282
282
|
}
|
|
283
283
|
} catch (err) {
|
|
284
284
|
error(err.message)
|