@anyday/sanity-workspace-manager 0.1.1 → 0.4.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 +50 -24
- package/dist/cli.mjs +151 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,8 +27,9 @@ From the root of the site repo:
|
|
|
27
27
|
# 1. Export the Studio's schema (writes sanity.schema.json)
|
|
28
28
|
cd studio && npx sanity schema extract && cd ..
|
|
29
29
|
|
|
30
|
-
# 2. Draft the manifest
|
|
31
|
-
|
|
30
|
+
# 2. Draft the manifest from the repo and the live project; it lists the site's pages to pick
|
|
31
|
+
# starter content from
|
|
32
|
+
npx @anyday/sanity-workspace-manager init --live
|
|
32
33
|
|
|
33
34
|
# 3. Review workspace-manager.json, then commit it next to the schema
|
|
34
35
|
|
|
@@ -42,15 +43,16 @@ npx @anyday/sanity-workspace-manager register --api https://anyday-workspace-man
|
|
|
42
43
|
npx @anyday/sanity-workspace-manager init [dir] [options]
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
`dir` is the site repo, and defaults to the current folder. `init` asks
|
|
46
|
+
`dir` is the site repo, and defaults to the current folder. `init` asks five questions, each with a
|
|
46
47
|
suggestion you can accept with Enter:
|
|
47
48
|
|
|
48
|
-
| Question | Suggested from
|
|
49
|
-
| ------------------------------------------- |
|
|
50
|
-
| Project type id, short and lowercase | The repo name in the git remote, e.g. `acme-site`
|
|
51
|
-
| Name shown in the app | The same repo name, capitalised
|
|
52
|
-
| Sanity project to copy schemas from | A `projectId: '…'` written in the Studio's config, if there is one
|
|
53
|
-
| Sanity organisation to create workspaces in | Looked up from that project with your login
|
|
49
|
+
| Question | Suggested from |
|
|
50
|
+
| ------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
51
|
+
| Project type id, short and lowercase | The repo name in the git remote, e.g. `acme-site` |
|
|
52
|
+
| Name shown in the app | The same repo name, capitalised |
|
|
53
|
+
| Sanity project to copy schemas from | A `projectId: '…'` written in the Studio's config, if there is one |
|
|
54
|
+
| Sanity organisation to create workspaces in | Looked up from that project with your login |
|
|
55
|
+
| Vercel team for the sites | Nothing: press Enter for Anyday's team; give a team id only for the client's own team |
|
|
54
56
|
|
|
55
57
|
The id is permanent: jobs store it and it prefixes each site's Vercel project. Registering a
|
|
56
58
|
different id later creates a second project type instead of updating this one.
|
|
@@ -62,27 +64,47 @@ different id later creates a second project type instead of updating this one.
|
|
|
62
64
|
| git remote and default branch | `site.repo`, `site.branch`, the suggested id and name |
|
|
63
65
|
| `.env.example`, names only | `siteEnv`, the variables each new site needs |
|
|
64
66
|
| `sanity.schema.json` | copy sections, singletons, home page, language documents, settings fields, colour and font templates |
|
|
65
|
-
| the live project, with `--live` | theme defaults, colour defaults
|
|
67
|
+
| the live project, with `--live` | theme defaults, colour defaults, starter pages, and its deployed Studio for `studioOrigins` |
|
|
66
68
|
|
|
67
69
|
`sanity.schema.json` is looked for in the repo root, `frontend`, `web`, `site`, `studio`, `apps`
|
|
68
70
|
and each folder in `apps`.
|
|
69
71
|
|
|
70
72
|
### Options
|
|
71
73
|
|
|
72
|
-
| Option
|
|
73
|
-
|
|
|
74
|
-
| `--yes`
|
|
75
|
-
| `--project <id>`
|
|
76
|
-
| `--org <id>`
|
|
77
|
-
| `--
|
|
78
|
-
| `--
|
|
79
|
-
| `--
|
|
80
|
-
| `--
|
|
81
|
-
| `--
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
| Option | Does |
|
|
75
|
+
| -------------------- | ----------------------------------------------------------------------------------------------- |
|
|
76
|
+
| `--yes` | Accepts the suggested id, name and project without asking |
|
|
77
|
+
| `--project <id>` | The Sanity project new workspaces copy their schema from |
|
|
78
|
+
| `--org <id>` | The Sanity organisation new workspaces are created in (found with `--live`) |
|
|
79
|
+
| `--vercel-team <id>` | The client's own Vercel team for the sites; leave out for Anyday's team |
|
|
80
|
+
| `--studio <origin>` | The Studio that opens new workspaces, e.g. `https://acme.sanity.studio` (found with `--live`) |
|
|
81
|
+
| `--live` | Reads the current theme, settings and starter pages from that project |
|
|
82
|
+
| `--dataset <name>` | The dataset `--live` reads (default `production`) |
|
|
83
|
+
| `--starter <pages>` | Starter pages without the list: `home`, slugs or document ids, comma-separated (needs `--live`) |
|
|
84
|
+
| `--force` | Replaces an existing `workspace-manager.json` |
|
|
85
|
+
| `--print` | Prints the draft instead of writing it |
|
|
86
|
+
|
|
87
|
+
### Starter pages
|
|
88
|
+
|
|
89
|
+
Starter pages are what a new workspace starts with when it doesn't copy another workspace. With
|
|
90
|
+
`--live`, `init` lists the live site's pages in the home page's language, home first:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
Pages of the live site:
|
|
94
|
+
1. Home (/home) ← home
|
|
95
|
+
2. About us (/about-us)
|
|
96
|
+
3. Accessibility (/accessibility)
|
|
97
|
+
Starter pages, by number (e.g. 1,3; Enter for one empty home page):
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Pick by number, or press Enter for one empty home page. To skip the list, name the pages with
|
|
101
|
+
`--starter`: `home` means whichever page the settings mark as the home page, and any other entry
|
|
102
|
+
is a page's slug or document id, e.g. `--starter home,about-us`. When translations share a
|
|
103
|
+
slug, the home page's language wins. With `--yes` and no `--starter`, the starter is one empty
|
|
104
|
+
home page.
|
|
105
|
+
|
|
106
|
+
Starter pages get `{{siteName}}` and `{{language}}` where the source site's name and language
|
|
107
|
+
were. Font files are never copied into theme defaults, since fonts are often licensed per brand.
|
|
86
108
|
|
|
87
109
|
### Review before registering
|
|
88
110
|
|
|
@@ -96,6 +118,9 @@ listed afterwards. Check these in particular:
|
|
|
96
118
|
- **Colour roles** come with empty descriptions. Add a short one each, saying where the colour is
|
|
97
119
|
used, so whoever sets up a brand knows what they are picking.
|
|
98
120
|
- **Language documents and singletons** are guessed from type names (`…Settings`, `l10n.locale`).
|
|
121
|
+
- **Vercel team:** sites go to Anyday's team unless you gave a team id. A client's own team needs
|
|
122
|
+
its token on the API as `VERCEL_TOKEN_<team id>` (a secret, added on Vercel by Anyday, never in
|
|
123
|
+
the manifest); `register` warns while it is missing.
|
|
99
124
|
|
|
100
125
|
## register
|
|
101
126
|
|
|
@@ -111,6 +136,7 @@ workspace manager. The live API is `https://anyday-workspace-manager-sanity-api.
|
|
|
111
136
|
- Registering again replaces the saved copy for that `id`, so a changed manifest needs no delete
|
|
112
137
|
first.
|
|
113
138
|
- It prints `Registered <name> (<id>)` when saved.
|
|
139
|
+
- It warns when the manifest names a Vercel team the API has no token for yet.
|
|
114
140
|
|
|
115
141
|
## Signing in
|
|
116
142
|
|
package/dist/cli.mjs
CHANGED
|
@@ -236,6 +236,14 @@ var workspace_manager_schema_default = {
|
|
|
236
236
|
description: "The Sanity project whose latest deployed Studio schema each workspace gets.",
|
|
237
237
|
$ref: "#/definitions/name"
|
|
238
238
|
},
|
|
239
|
+
studioOrigins: {
|
|
240
|
+
description: "Origins of the Studios that open these workspaces, e.g. https://acme.sanity.studio; every new workspace allows them.",
|
|
241
|
+
type: "array",
|
|
242
|
+
items: {
|
|
243
|
+
type: "string",
|
|
244
|
+
pattern: "^https?://[^/]+$"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
239
247
|
languages: {
|
|
240
248
|
type: "object",
|
|
241
249
|
required: ["document", "setupTypes"],
|
|
@@ -411,6 +419,7 @@ function configFrom(manifest) {
|
|
|
411
419
|
site: manifest.site,
|
|
412
420
|
siteEnv: manifest.siteEnv,
|
|
413
421
|
schemaSourceProjectId: manifest.schemaSourceProjectId,
|
|
422
|
+
studioOrigins: manifest.studioOrigins ?? [],
|
|
414
423
|
languageDocument: languages && ((code) => fill(languages.document, {
|
|
415
424
|
code,
|
|
416
425
|
codeUpper: code.toUpperCase(),
|
|
@@ -431,6 +440,7 @@ function configFrom(manifest) {
|
|
|
431
440
|
},
|
|
432
441
|
brand: {
|
|
433
442
|
colorRoles: brand.colorRoles,
|
|
443
|
+
fonts: brand.theme.font !== void 0,
|
|
434
444
|
documents: (values, homePageId) => brandDocuments(brand, values, homePageId)
|
|
435
445
|
}
|
|
436
446
|
};
|
|
@@ -558,11 +568,18 @@ function draftManifest(repo, answers, live = {}) {
|
|
|
558
568
|
);
|
|
559
569
|
if (!repo.repo) note("No GitHub remote found: set site.repo to owner/name");
|
|
560
570
|
if (!repo.hasRevalidateRoute) note("No /api/revalidate route found: check site.revalidatePath");
|
|
571
|
+
if (answers.vercelTeamId)
|
|
572
|
+
note(
|
|
573
|
+
`Sites go to Vercel team ${answers.vercelTeamId}: the API needs VERCEL_TOKEN_${answers.vercelTeamId} before setups reach Vercel`
|
|
574
|
+
);
|
|
575
|
+
if (answers.studioOrigins?.length) note(`Studio: ${answers.studioOrigins.join(", ")}`);
|
|
576
|
+
else note('No Studio found: add studioOrigins, e.g. ["https://acme.sanity.studio"]');
|
|
561
577
|
return {
|
|
562
578
|
manifest: {
|
|
563
579
|
id: answers.id,
|
|
564
580
|
title: answers.title,
|
|
565
581
|
organizationId: answers.organizationId,
|
|
582
|
+
...answers.vercelTeamId ? { vercelTeamId: answers.vercelTeamId } : {},
|
|
566
583
|
site: {
|
|
567
584
|
repo: repo.repo ?? "owner/name",
|
|
568
585
|
branch: repo.branch ?? "main",
|
|
@@ -570,6 +587,7 @@ function draftManifest(repo, answers, live = {}) {
|
|
|
570
587
|
},
|
|
571
588
|
siteEnv,
|
|
572
589
|
schemaSourceProjectId: answers.schemaSourceProjectId,
|
|
590
|
+
...answers.studioOrigins?.length ? { studioOrigins: answers.studioOrigins } : {},
|
|
573
591
|
...languages ? { languages } : {},
|
|
574
592
|
content: {
|
|
575
593
|
sections,
|
|
@@ -642,7 +660,7 @@ function draftStarter(schema, home, live, note) {
|
|
|
642
660
|
const page = { _id: "starter-home", _type: type };
|
|
643
661
|
if ("title" in fields) page.title = "{{siteName}}";
|
|
644
662
|
if ("language" in fields) page.language = "{{language}}";
|
|
645
|
-
note("Starter is one empty home page:
|
|
663
|
+
note("Starter is one empty home page: run with --live to pick real pages instead");
|
|
646
664
|
return { homeId: "starter-home", documents: [page] };
|
|
647
665
|
}
|
|
648
666
|
function draftBrand(schema, home, live, note) {
|
|
@@ -785,22 +803,51 @@ function sanityToken() {
|
|
|
785
803
|
if (!existsSync(config)) return null;
|
|
786
804
|
return JSON.parse(readFileSync(config, "utf8")).authToken ?? null;
|
|
787
805
|
}
|
|
788
|
-
async function
|
|
806
|
+
async function projectInfo(projectId, token) {
|
|
789
807
|
const response = await fetch(`https://api.sanity.io/v2021-06-07/projects/${projectId}`, {
|
|
790
808
|
headers: { Authorization: `Bearer ${token}` }
|
|
791
809
|
});
|
|
792
810
|
if (!response.ok) throw new Error(`Couldn't read project ${projectId}: ${response.status}`);
|
|
793
|
-
return
|
|
811
|
+
return await response.json();
|
|
812
|
+
}
|
|
813
|
+
async function organizationOf(projectId, token) {
|
|
814
|
+
return (await projectInfo(projectId, token)).organizationId ?? "";
|
|
815
|
+
}
|
|
816
|
+
async function studioOriginsOf(projectId, token) {
|
|
817
|
+
const response = await fetch(
|
|
818
|
+
`https://api.sanity.io/v2024-08-01/projects/${projectId}/user-applications`,
|
|
819
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
820
|
+
);
|
|
821
|
+
if (!response.ok) throw new Error(`Couldn't list ${projectId}'s Studios: ${response.status}`);
|
|
822
|
+
const apps = await response.json();
|
|
823
|
+
const origins = apps.filter((app) => app.type === "studio").map(
|
|
824
|
+
(app) => app.urlType === "external" ? new URL(app.appHost).origin : `https://${app.appHost}.sanity.studio`
|
|
825
|
+
);
|
|
826
|
+
const { studioHost } = await projectInfo(projectId, token);
|
|
827
|
+
if (studioHost) origins.push(`https://${studioHost}.sanity.studio`);
|
|
828
|
+
return [...new Set(origins)];
|
|
829
|
+
}
|
|
830
|
+
var liveClient = ({ projectId, dataset, token }) => createClient({
|
|
831
|
+
projectId,
|
|
832
|
+
dataset,
|
|
833
|
+
token,
|
|
834
|
+
apiVersion: "2026-08-15",
|
|
835
|
+
useCdn: false,
|
|
836
|
+
perspective: "published"
|
|
837
|
+
});
|
|
838
|
+
async function listPages(options) {
|
|
839
|
+
const { settings, pages } = await liveClient(options).fetch(
|
|
840
|
+
`{
|
|
841
|
+
"settings": *[_id == $settingsId][0],
|
|
842
|
+
"pages": *[_type == $type && defined(slug.current)]{_id, title, "slug": slug.current, language}
|
|
843
|
+
}`,
|
|
844
|
+
{ settingsId: options.home.documentId, type: options.pageType }
|
|
845
|
+
);
|
|
846
|
+
const homeId = settings?.[options.home.field]?._ref ?? null;
|
|
847
|
+
return { pages, homeId };
|
|
794
848
|
}
|
|
795
849
|
async function readLive(options) {
|
|
796
|
-
const client =
|
|
797
|
-
projectId: options.projectId,
|
|
798
|
-
dataset: options.dataset,
|
|
799
|
-
token: options.token,
|
|
800
|
-
apiVersion: "2026-08-15",
|
|
801
|
-
useCdn: false,
|
|
802
|
-
perspective: "published"
|
|
803
|
-
});
|
|
850
|
+
const client = liveClient(options);
|
|
804
851
|
const docs = await client.fetch("*[_id in $ids]", {
|
|
805
852
|
ids: [options.settingsId, options.themeId, ...options.starterIds]
|
|
806
853
|
});
|
|
@@ -861,6 +908,39 @@ function readRepo(root) {
|
|
|
861
908
|
};
|
|
862
909
|
}
|
|
863
910
|
|
|
911
|
+
// src/init/starter.ts
|
|
912
|
+
function resolveStarter(entries, pages, homeId) {
|
|
913
|
+
const home = pages.find((page) => page._id === homeId);
|
|
914
|
+
return entries.map((entry) => {
|
|
915
|
+
if (entry === "home") {
|
|
916
|
+
if (!homeId) throw new Error("The live settings name no home page: pass its slug instead");
|
|
917
|
+
return homeId;
|
|
918
|
+
}
|
|
919
|
+
if (pages.some((page) => page._id === entry)) return entry;
|
|
920
|
+
let matches = pages.filter((page) => page.slug === entry);
|
|
921
|
+
if (matches.length > 1 && home?.language)
|
|
922
|
+
matches = matches.filter((page) => page.language === home.language);
|
|
923
|
+
if (matches.length === 1) return matches[0]._id;
|
|
924
|
+
if (!matches.length) throw new Error(`No page with the slug or id "${entry}"`);
|
|
925
|
+
throw new Error(
|
|
926
|
+
`Several pages have the slug "${entry}": pass one of ${matches.map((page) => page._id).join(", ")}`
|
|
927
|
+
);
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
function pickable(pages, homeId) {
|
|
931
|
+
const home = pages.find((page) => page._id === homeId);
|
|
932
|
+
const shown = home?.language ? pages.filter((page) => page.language === home.language) : pages;
|
|
933
|
+
return [...shown].sort(
|
|
934
|
+
(a, b) => a._id === homeId ? -1 : b._id === homeId ? 1 : (a.title ?? "").localeCompare(b.title ?? "")
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
function parsePick(answer, count) {
|
|
938
|
+
const picked = answer.split(/[\s,]+/).filter(Boolean).map((part) => Number(part));
|
|
939
|
+
const wrong = picked.filter((n) => !Number.isInteger(n) || n < 1 || n > count);
|
|
940
|
+
if (wrong.length) throw new Error(`Pick numbers from 1 to ${count}`);
|
|
941
|
+
return [...new Set(picked)].map((n) => n - 1);
|
|
942
|
+
}
|
|
943
|
+
|
|
864
944
|
// src/register.ts
|
|
865
945
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
866
946
|
import { join as join3 } from "node:path";
|
|
@@ -894,9 +974,13 @@ Options:
|
|
|
894
974
|
--yes Accept the suggested id, title and project without asking
|
|
895
975
|
--project <id> The Sanity project new workspaces copy their schema from
|
|
896
976
|
--org <id> The Sanity organisation new workspaces are created in (found with --live)
|
|
977
|
+
--vercel-team <id> The client's own Vercel team for the sites (default: Anyday's team)
|
|
978
|
+
--studio <origin> The Studio that opens new workspaces, e.g. https://acme.sanity.studio
|
|
979
|
+
(found with --live from the project's deployed Studio)
|
|
897
980
|
--live Read the current theme, settings and starter pages from that project
|
|
898
981
|
--dataset <name> Dataset to read with --live (default: production)
|
|
899
|
-
--starter <
|
|
982
|
+
--starter <pages> Comma-separated pages to copy as starter content: \`home\`, slugs or
|
|
983
|
+
document ids (needs --live; without it, --live offers a list to pick from)
|
|
900
984
|
--force Overwrite an existing workspace-manager.json
|
|
901
985
|
--print Print the draft instead of writing it
|
|
902
986
|
|
|
@@ -919,20 +1003,23 @@ async function registerCommand(argv) {
|
|
|
919
1003
|
if (!token) throw new Error("register needs SANITY_AUTH_TOKEN or `npx sanity login`");
|
|
920
1004
|
const saved = await register({ dir: dirOf(positionals[0]), api, token });
|
|
921
1005
|
console.log(`Registered ${saved.title} (${saved.id})`);
|
|
1006
|
+
for (const warning of saved.warnings ?? []) console.error(`Warning: ${warning}`);
|
|
922
1007
|
}
|
|
923
1008
|
async function init(argv) {
|
|
924
1009
|
const { values, positionals } = parseArgs({
|
|
925
1010
|
args: argv,
|
|
926
1011
|
allowPositionals: true,
|
|
927
1012
|
options: {
|
|
928
|
-
yes: { type: "boolean", default: false },
|
|
929
|
-
project: { type: "string" },
|
|
930
|
-
org: { type: "string" },
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1013
|
+
"yes": { type: "boolean", default: false },
|
|
1014
|
+
"project": { type: "string" },
|
|
1015
|
+
"org": { type: "string" },
|
|
1016
|
+
"studio": { type: "string" },
|
|
1017
|
+
"vercel-team": { type: "string" },
|
|
1018
|
+
"live": { type: "boolean", default: false },
|
|
1019
|
+
"dataset": { type: "string", default: "production" },
|
|
1020
|
+
"starter": { type: "string" },
|
|
1021
|
+
"force": { type: "boolean", default: false },
|
|
1022
|
+
"print": { type: "boolean", default: false }
|
|
936
1023
|
}
|
|
937
1024
|
});
|
|
938
1025
|
const root = dirOf(positionals[0]);
|
|
@@ -945,7 +1032,11 @@ async function init(argv) {
|
|
|
945
1032
|
const orgFor = async (projectId) => values.org ?? (token && projectId ? await organizationOf(projectId, token) : "");
|
|
946
1033
|
const repo = readRepo(root);
|
|
947
1034
|
const suggested = { ...suggestNames(repo.repo), project: values.project ?? repo.projectId ?? "" };
|
|
948
|
-
const answers = values.yes ? {
|
|
1035
|
+
const answers = values.yes ? {
|
|
1036
|
+
...suggested,
|
|
1037
|
+
org: await orgFor(suggested.project),
|
|
1038
|
+
vercelTeam: values["vercel-team"] ?? ""
|
|
1039
|
+
} : await ask({ ...suggested, vercelTeam: values["vercel-team"] ?? "" }, orgFor);
|
|
949
1040
|
if (!answers.project)
|
|
950
1041
|
throw new Error("Pass --project <id>: the Sanity project to copy schemas from");
|
|
951
1042
|
if (!answers.org) throw new Error("Pass --org <id>, or --live to read it from the project");
|
|
@@ -953,17 +1044,28 @@ async function init(argv) {
|
|
|
953
1044
|
id: answers.id,
|
|
954
1045
|
title: answers.title,
|
|
955
1046
|
organizationId: answers.org,
|
|
956
|
-
|
|
1047
|
+
...answers.vercelTeam ? { vercelTeamId: answers.vercelTeam } : {},
|
|
1048
|
+
schemaSourceProjectId: answers.project,
|
|
1049
|
+
studioOrigins: values.studio ? [values.studio.replace(/\/+$/, "")] : token ? await studioOriginsOf(answers.project, token) : []
|
|
957
1050
|
};
|
|
958
1051
|
let draft = draftManifest(repo, base);
|
|
959
1052
|
if (token) {
|
|
1053
|
+
const project = { projectId: answers.project, dataset: values.dataset, token };
|
|
1054
|
+
const { pages, homeId } = await listPages({
|
|
1055
|
+
...project,
|
|
1056
|
+
pageType: draft.manifest.content.starter.documents[0]._type,
|
|
1057
|
+
home: draft.manifest.content.homePage
|
|
1058
|
+
});
|
|
1059
|
+
const starterIds = values.starter ? resolveStarter(
|
|
1060
|
+
values.starter.split(",").map((entry) => entry.trim()).filter(Boolean),
|
|
1061
|
+
pages,
|
|
1062
|
+
homeId
|
|
1063
|
+
) : values.yes ? [] : await pickStarter(pickable(pages, homeId), homeId);
|
|
960
1064
|
const live = await readLive({
|
|
961
|
-
|
|
962
|
-
dataset: values.dataset,
|
|
963
|
-
token,
|
|
1065
|
+
...project,
|
|
964
1066
|
settingsId: draft.manifest.brand.settings.documentId,
|
|
965
1067
|
themeId: draft.manifest.brand.theme.documentId,
|
|
966
|
-
starterIds
|
|
1068
|
+
starterIds
|
|
967
1069
|
});
|
|
968
1070
|
draft = draftManifest(repo, base, live);
|
|
969
1071
|
}
|
|
@@ -978,14 +1080,35 @@ Check before registering:`);
|
|
|
978
1080
|
for (const note of draft.notes) console.error(` - ${note}`);
|
|
979
1081
|
}
|
|
980
1082
|
async function ask(suggested, orgFor) {
|
|
981
|
-
const prompt = createInterface({ input: process.stdin, output: process.
|
|
1083
|
+
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
982
1084
|
const question = async (label, fallback) => (await prompt.question(`${label}${fallback ? ` (${fallback})` : ""}: `)).trim() || fallback;
|
|
983
1085
|
try {
|
|
984
1086
|
const id = await question("Project type id, short and lowercase", suggested.id);
|
|
985
1087
|
const title = await question("Name shown in the app", suggested.title);
|
|
986
1088
|
const project = await question("Sanity project to copy schemas from", suggested.project);
|
|
987
1089
|
const org = await question("Sanity organisation to create workspaces in", await orgFor(project));
|
|
988
|
-
|
|
1090
|
+
const vercelTeam = await question(
|
|
1091
|
+
"Vercel team for the sites, only if it's the client's own (Enter for Anyday's)",
|
|
1092
|
+
suggested.vercelTeam
|
|
1093
|
+
);
|
|
1094
|
+
return { id, title, project, org, vercelTeam };
|
|
1095
|
+
} finally {
|
|
1096
|
+
prompt.close();
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
async function pickStarter(pages, homeId) {
|
|
1100
|
+
if (!pages.length) return [];
|
|
1101
|
+
console.error("\nPages of the live site:");
|
|
1102
|
+
pages.forEach((page, index) => {
|
|
1103
|
+
const label = `${page.title ?? page._id} (/${page.slug})`;
|
|
1104
|
+
console.error(` ${index + 1}. ${label}${page._id === homeId ? " \u2190 home" : ""}`);
|
|
1105
|
+
});
|
|
1106
|
+
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
1107
|
+
try {
|
|
1108
|
+
const answer = await prompt.question(
|
|
1109
|
+
"Starter pages, by number (e.g. 1,3; Enter for one empty home page): "
|
|
1110
|
+
);
|
|
1111
|
+
return parsePick(answer, pages.length).map((index) => pages[index]._id);
|
|
989
1112
|
} finally {
|
|
990
1113
|
prompt.close();
|
|
991
1114
|
}
|