@angeloashmore/prismic-cli-poc 0.0.0-canary.1d36cd8
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 +202 -0
- package/README.md +98 -0
- package/dist/index.mjs +2548 -0
- package/package.json +53 -0
- package/src/codegen-types.ts +82 -0
- package/src/codegen.ts +45 -0
- package/src/custom-type-add-field-boolean.ts +192 -0
- package/src/custom-type-add-field-color.ts +177 -0
- package/src/custom-type-add-field-date.ts +180 -0
- package/src/custom-type-add-field-embed.ts +177 -0
- package/src/custom-type-add-field-geo-point.ts +174 -0
- package/src/custom-type-add-field-image.ts +177 -0
- package/src/custom-type-add-field-key-text.ts +177 -0
- package/src/custom-type-add-field-link.ts +201 -0
- package/src/custom-type-add-field-number.ts +209 -0
- package/src/custom-type-add-field-rich-text.ts +202 -0
- package/src/custom-type-add-field-select.ts +192 -0
- package/src/custom-type-add-field-timestamp.ts +180 -0
- package/src/custom-type-add-field-uid.ts +177 -0
- package/src/custom-type-add-field.ts +111 -0
- package/src/custom-type-connect-slice.ts +220 -0
- package/src/custom-type-create.ts +118 -0
- package/src/custom-type-disconnect-slice.ts +177 -0
- package/src/custom-type-list.ts +110 -0
- package/src/custom-type-remove-field.ts +177 -0
- package/src/custom-type-remove.ts +144 -0
- package/src/custom-type-set-name.ts +144 -0
- package/src/custom-type-view.ts +118 -0
- package/src/custom-type.ts +85 -0
- package/src/index.ts +127 -0
- package/src/init.ts +64 -0
- package/src/lib/auth.ts +83 -0
- package/src/lib/config.ts +111 -0
- package/src/lib/custom-types-api.ts +438 -0
- package/src/lib/file.ts +49 -0
- package/src/lib/framework.ts +143 -0
- package/src/lib/json.ts +3 -0
- package/src/lib/request.ts +116 -0
- package/src/lib/slice.ts +115 -0
- package/src/lib/string.ts +6 -0
- package/src/lib/url.ts +25 -0
- package/src/locale-add.ts +116 -0
- package/src/locale-list.ts +107 -0
- package/src/locale-remove.ts +88 -0
- package/src/locale-set-default.ts +131 -0
- package/src/locale.ts +60 -0
- package/src/login.ts +152 -0
- package/src/logout.ts +36 -0
- package/src/page-type-add-field-boolean.ts +192 -0
- package/src/page-type-add-field-color.ts +177 -0
- package/src/page-type-add-field-date.ts +180 -0
- package/src/page-type-add-field-embed.ts +177 -0
- package/src/page-type-add-field-geo-point.ts +174 -0
- package/src/page-type-add-field-image.ts +177 -0
- package/src/page-type-add-field-key-text.ts +177 -0
- package/src/page-type-add-field-link.ts +201 -0
- package/src/page-type-add-field-number.ts +209 -0
- package/src/page-type-add-field-rich-text.ts +202 -0
- package/src/page-type-add-field-select.ts +192 -0
- package/src/page-type-add-field-timestamp.ts +180 -0
- package/src/page-type-add-field-uid.ts +177 -0
- package/src/page-type-add-field.ts +111 -0
- package/src/page-type-connect-slice.ts +220 -0
- package/src/page-type-create.ts +142 -0
- package/src/page-type-disconnect-slice.ts +177 -0
- package/src/page-type-list.ts +109 -0
- package/src/page-type-remove-field.ts +177 -0
- package/src/page-type-remove.ts +144 -0
- package/src/page-type-set-name.ts +144 -0
- package/src/page-type-set-repeatable.ts +153 -0
- package/src/page-type-view.ts +118 -0
- package/src/page-type.ts +90 -0
- package/src/preview-add.ts +126 -0
- package/src/preview-get-simulator.ts +104 -0
- package/src/preview-list.ts +106 -0
- package/src/preview-remove-simulator.ts +80 -0
- package/src/preview-remove.ts +109 -0
- package/src/preview-set-name.ts +137 -0
- package/src/preview-set-simulator.ts +116 -0
- package/src/preview.ts +75 -0
- package/src/pull.ts +247 -0
- package/src/push.ts +405 -0
- package/src/repo-create.ts +136 -0
- package/src/repo-get-access.ts +86 -0
- package/src/repo-list.ts +100 -0
- package/src/repo-set-access.ts +100 -0
- package/src/repo-set-name.ts +102 -0
- package/src/repo-view.ts +113 -0
- package/src/repo.ts +70 -0
- package/src/slice-add-field-boolean.ts +173 -0
- package/src/slice-add-field-color.ts +158 -0
- package/src/slice-add-field-date.ts +158 -0
- package/src/slice-add-field-embed.ts +158 -0
- package/src/slice-add-field-geo-point.ts +155 -0
- package/src/slice-add-field-image.ts +155 -0
- package/src/slice-add-field-key-text.ts +158 -0
- package/src/slice-add-field-link.ts +178 -0
- package/src/slice-add-field-number.ts +158 -0
- package/src/slice-add-field-rich-text.ts +183 -0
- package/src/slice-add-field-select.ts +173 -0
- package/src/slice-add-field-timestamp.ts +158 -0
- package/src/slice-add-field.ts +106 -0
- package/src/slice-add-variation.ts +145 -0
- package/src/slice-create.ts +148 -0
- package/src/slice-list-variations.ts +67 -0
- package/src/slice-list.ts +88 -0
- package/src/slice-remove-field.ts +128 -0
- package/src/slice-remove-variation.ts +118 -0
- package/src/slice-remove.ts +97 -0
- package/src/slice-rename.ts +128 -0
- package/src/slice-view.ts +77 -0
- package/src/slice.ts +90 -0
- package/src/status.ts +733 -0
- package/src/token-create.ts +203 -0
- package/src/token-delete.ts +182 -0
- package/src/token-list.ts +223 -0
- package/src/token-set-name.ts +193 -0
- package/src/token.ts +60 -0
- package/src/webhook-add-header.ts +118 -0
- package/src/webhook-create.ts +152 -0
- package/src/webhook-disable.ts +109 -0
- package/src/webhook-enable.ts +132 -0
- package/src/webhook-list.ts +93 -0
- package/src/webhook-remove-header.ts +117 -0
- package/src/webhook-remove.ts +106 -0
- package/src/webhook-set-triggers.ts +148 -0
- package/src/webhook-status.ts +90 -0
- package/src/webhook-test.ts +106 -0
- package/src/webhook-view.ts +147 -0
- package/src/webhook.ts +95 -0
- package/src/whoami.ts +62 -0
package/src/repo-list.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
|
|
4
|
+
import { isAuthenticated } from "./lib/auth";
|
|
5
|
+
import { stringify } from "./lib/json";
|
|
6
|
+
import { ForbiddenRequestError, request } from "./lib/request";
|
|
7
|
+
import { getRepoUrl, getUserServiceUrl } from "./lib/url";
|
|
8
|
+
|
|
9
|
+
const HELP = `
|
|
10
|
+
List all Prismic repositories.
|
|
11
|
+
|
|
12
|
+
USAGE
|
|
13
|
+
prismic repo list [flags]
|
|
14
|
+
|
|
15
|
+
FLAGS
|
|
16
|
+
--json Output as JSON
|
|
17
|
+
-h, --help Show help for command
|
|
18
|
+
|
|
19
|
+
LEARN MORE
|
|
20
|
+
Use \`prismic repo <command> --help\` for more information about a command.
|
|
21
|
+
`.trim();
|
|
22
|
+
|
|
23
|
+
const ProfileSchema = v.object({
|
|
24
|
+
repositories: v.array(
|
|
25
|
+
v.object({
|
|
26
|
+
domain: v.string(),
|
|
27
|
+
name: v.optional(v.string()),
|
|
28
|
+
role: v.string(),
|
|
29
|
+
}),
|
|
30
|
+
),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export async function repoList(): Promise<void> {
|
|
34
|
+
const {
|
|
35
|
+
values: { help, json },
|
|
36
|
+
} = parseArgs({
|
|
37
|
+
args: process.argv.slice(4), // skip: node, script, "repo", "list"
|
|
38
|
+
options: {
|
|
39
|
+
help: { type: "boolean", short: "h" },
|
|
40
|
+
json: { type: "boolean" },
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (help) {
|
|
45
|
+
console.info(HELP);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const authenticated = await isAuthenticated();
|
|
50
|
+
if (!authenticated) {
|
|
51
|
+
handleUnauthenticated();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const response = await fetchProfile();
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
58
|
+
handleUnauthenticated();
|
|
59
|
+
} else {
|
|
60
|
+
console.error(`Failed to fetch repositories: ${stringify(response.value)}`);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const repos = response.value.repositories;
|
|
67
|
+
|
|
68
|
+
if (json) {
|
|
69
|
+
const output = await Promise.all(
|
|
70
|
+
repos.map(async (repo) => ({
|
|
71
|
+
domain: repo.domain,
|
|
72
|
+
name: repo.name || null,
|
|
73
|
+
role: repo.role,
|
|
74
|
+
url: (await getRepoUrl(repo.domain)).toString(),
|
|
75
|
+
})),
|
|
76
|
+
);
|
|
77
|
+
console.info(stringify(output));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (repos.length === 0) {
|
|
82
|
+
console.info("No repositories found.");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const repo of repos) {
|
|
87
|
+
const name = repo.name || "(no name)";
|
|
88
|
+
console.info(`${repo.domain} ${name} ${repo.role}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function fetchProfile(): ReturnType<typeof request<v.InferOutput<typeof ProfileSchema>>> {
|
|
93
|
+
const url = new URL("profile", await getUserServiceUrl());
|
|
94
|
+
return await request(url, { schema: ProfileSchema });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function handleUnauthenticated() {
|
|
98
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { isAuthenticated } from "./lib/auth";
|
|
4
|
+
import { safeGetRepositoryFromConfig } from "./lib/config";
|
|
5
|
+
import { stringify } from "./lib/json";
|
|
6
|
+
import { ForbiddenRequestError, request } from "./lib/request";
|
|
7
|
+
import { getRepoUrl } from "./lib/url";
|
|
8
|
+
|
|
9
|
+
const VALID_LEVELS = ["private", "public", "open"] as const;
|
|
10
|
+
|
|
11
|
+
const HELP = `
|
|
12
|
+
Set the Content API access level of a Prismic repository.
|
|
13
|
+
|
|
14
|
+
By default, this command reads the repository from prismic.config.json at the
|
|
15
|
+
project root.
|
|
16
|
+
|
|
17
|
+
USAGE
|
|
18
|
+
prismic repo set-access <level> [flags]
|
|
19
|
+
|
|
20
|
+
ARGUMENTS
|
|
21
|
+
<level> The access level to set (private, public, open)
|
|
22
|
+
|
|
23
|
+
FLAGS
|
|
24
|
+
-r, --repo string Repository domain
|
|
25
|
+
-h, --help Show help for command
|
|
26
|
+
|
|
27
|
+
LEARN MORE
|
|
28
|
+
Use \`prismic <command> <subcommand> --help\` for more information about a command.
|
|
29
|
+
`.trim();
|
|
30
|
+
|
|
31
|
+
export async function repoSetAccess(): Promise<void> {
|
|
32
|
+
const {
|
|
33
|
+
values: { help, repo = await safeGetRepositoryFromConfig() },
|
|
34
|
+
positionals: [level],
|
|
35
|
+
} = parseArgs({
|
|
36
|
+
args: process.argv.slice(4), // skip: node, script, "repo", "set-access"
|
|
37
|
+
options: {
|
|
38
|
+
repo: { type: "string", short: "r" },
|
|
39
|
+
help: { type: "boolean", short: "h" },
|
|
40
|
+
},
|
|
41
|
+
allowPositionals: true,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (help) {
|
|
45
|
+
console.info(HELP);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!level) {
|
|
50
|
+
console.error("Missing required argument: <level>");
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!VALID_LEVELS.includes(level as (typeof VALID_LEVELS)[number])) {
|
|
56
|
+
console.error(`Invalid access level: ${level}. Must be one of: ${VALID_LEVELS.join(", ")}`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!repo) {
|
|
62
|
+
console.error("Missing prismic.config.json or --repo option");
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const authenticated = await isAuthenticated();
|
|
68
|
+
if (!authenticated) {
|
|
69
|
+
handleUnauthenticated();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const response = await setRepositoryAccess(repo, level);
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
76
|
+
handleUnauthenticated();
|
|
77
|
+
} else {
|
|
78
|
+
console.error(`Failed to set repository access: ${stringify(response.value)}`);
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.info(`Repository access set to: ${level}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function setRepositoryAccess(domain: string, level: string) {
|
|
88
|
+
const repoUrl = await getRepoUrl(domain);
|
|
89
|
+
const url = new URL("settings/security/apiaccess", repoUrl);
|
|
90
|
+
|
|
91
|
+
return await request(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
body: { api_access: level },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function handleUnauthenticated() {
|
|
98
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
|
|
4
|
+
import { isAuthenticated } from "./lib/auth";
|
|
5
|
+
import { safeGetRepositoryFromConfig } from "./lib/config";
|
|
6
|
+
import { stringify } from "./lib/json";
|
|
7
|
+
import { ForbiddenRequestError, request } from "./lib/request";
|
|
8
|
+
import { getRepoUrl } from "./lib/url";
|
|
9
|
+
|
|
10
|
+
const HELP = `
|
|
11
|
+
Set the display name of a Prismic repository.
|
|
12
|
+
|
|
13
|
+
By default, this command reads the repository from prismic.config.json at the
|
|
14
|
+
project root.
|
|
15
|
+
|
|
16
|
+
USAGE
|
|
17
|
+
prismic repo set-name <name> [flags]
|
|
18
|
+
|
|
19
|
+
ARGUMENTS
|
|
20
|
+
<name> The new display name for the repository
|
|
21
|
+
|
|
22
|
+
FLAGS
|
|
23
|
+
-r, --repo string Repository domain
|
|
24
|
+
-h, --help Show help for command
|
|
25
|
+
|
|
26
|
+
LEARN MORE
|
|
27
|
+
Use \`prismic <command> <subcommand> --help\` for more information about a command.
|
|
28
|
+
`.trim();
|
|
29
|
+
|
|
30
|
+
export async function repoSetName(): Promise<void> {
|
|
31
|
+
const {
|
|
32
|
+
values: { help, repo = await safeGetRepositoryFromConfig() },
|
|
33
|
+
positionals: [displayName],
|
|
34
|
+
} = parseArgs({
|
|
35
|
+
args: process.argv.slice(4), // skip: node, script, "repo", "set-name"
|
|
36
|
+
options: {
|
|
37
|
+
repo: { type: "string", short: "r" },
|
|
38
|
+
help: { type: "boolean", short: "h" },
|
|
39
|
+
},
|
|
40
|
+
allowPositionals: true,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (help) {
|
|
44
|
+
console.info(HELP);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!displayName) {
|
|
49
|
+
console.error("Missing required argument: <name>");
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!repo) {
|
|
55
|
+
console.error("Missing prismic.config.json or --repo option");
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const authenticated = await isAuthenticated();
|
|
61
|
+
if (!authenticated) {
|
|
62
|
+
handleUnauthenticated();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const response = await setRepositoryName(repo, displayName);
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
69
|
+
handleUnauthenticated();
|
|
70
|
+
} else if (v.isValiError(response.error)) {
|
|
71
|
+
console.error(
|
|
72
|
+
`Failed to set repository name: Invalid response: ${stringify(response.error.issues)}`,
|
|
73
|
+
);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
} else {
|
|
76
|
+
console.error(`Failed to set repository name: ${stringify(response.value)}`);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.info(`Repository name set to: ${response.value.repository.name}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function setRepositoryName(domain: string, displayName: string) {
|
|
86
|
+
const repoUrl = await getRepoUrl(domain);
|
|
87
|
+
const url = new URL("app/settings/repository", repoUrl);
|
|
88
|
+
|
|
89
|
+
const formData = new FormData();
|
|
90
|
+
formData.set("displayname", displayName);
|
|
91
|
+
|
|
92
|
+
return await request(url, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
body: formData,
|
|
95
|
+
schema: v.object({ repository: v.object({ name: v.string() }) }),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function handleUnauthenticated() {
|
|
100
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
}
|
package/src/repo-view.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import * as v from "valibot";
|
|
4
|
+
|
|
5
|
+
import { isAuthenticated } from "./lib/auth";
|
|
6
|
+
import { safeGetRepositoryFromConfig } from "./lib/config";
|
|
7
|
+
import { stringify } from "./lib/json";
|
|
8
|
+
import { ForbiddenRequestError, request } from "./lib/request";
|
|
9
|
+
import { getRepoUrl, getUserServiceUrl } from "./lib/url";
|
|
10
|
+
|
|
11
|
+
const HELP = `
|
|
12
|
+
View a Prismic repository.
|
|
13
|
+
|
|
14
|
+
By default, this command reads the repository from prismic.config.json at the
|
|
15
|
+
project root.
|
|
16
|
+
|
|
17
|
+
USAGE
|
|
18
|
+
prismic repo view [flags]
|
|
19
|
+
|
|
20
|
+
FLAGS
|
|
21
|
+
-w, --web Open repository in browser
|
|
22
|
+
-r, --repo string Repository domain
|
|
23
|
+
-h, --help Show help for command
|
|
24
|
+
|
|
25
|
+
LEARN MORE
|
|
26
|
+
Use \`prismic <command> <subcommand> --help\` for more information about a command.
|
|
27
|
+
`.trim();
|
|
28
|
+
|
|
29
|
+
const ProfileSchema = v.object({
|
|
30
|
+
repositories: v.array(
|
|
31
|
+
v.object({
|
|
32
|
+
domain: v.string(),
|
|
33
|
+
name: v.optional(v.string()),
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export async function repoView(): Promise<void> {
|
|
39
|
+
const {
|
|
40
|
+
values: { help, repo = await safeGetRepositoryFromConfig(), web },
|
|
41
|
+
} = parseArgs({
|
|
42
|
+
args: process.argv.slice(4), // skip: node, script, "repo", "view"
|
|
43
|
+
options: {
|
|
44
|
+
web: { type: "boolean", short: "w" },
|
|
45
|
+
repo: { type: "string", short: "r" },
|
|
46
|
+
help: { type: "boolean", short: "h" },
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (help) {
|
|
51
|
+
console.info(HELP);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!repo) {
|
|
56
|
+
console.error("Missing prismic.config.json or --repo option");
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const repoUrl = await getRepoUrl(repo);
|
|
62
|
+
|
|
63
|
+
if (web) {
|
|
64
|
+
openInBrowser(repoUrl.toString());
|
|
65
|
+
console.info(`Opening ${repoUrl}`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const authenticated = await isAuthenticated();
|
|
70
|
+
if (!authenticated) {
|
|
71
|
+
handleUnauthenticated();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const response = await fetchProfile();
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
78
|
+
handleUnauthenticated();
|
|
79
|
+
} else {
|
|
80
|
+
console.error(`Failed to fetch repository info: ${stringify(response.value)}`);
|
|
81
|
+
process.exitCode = 1;
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const repoData = response.value.repositories.find((r) => r.domain === repo);
|
|
87
|
+
if (!repoData) {
|
|
88
|
+
console.error(`Repository not found: ${repo}`);
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const name = repoData.name || "(no name)";
|
|
94
|
+
console.info(`Name: ${name}`);
|
|
95
|
+
console.info(`URL: ${repoUrl}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function fetchProfile(): ReturnType<typeof request<v.InferOutput<typeof ProfileSchema>>> {
|
|
99
|
+
const url = new URL("profile", await getUserServiceUrl());
|
|
100
|
+
return await request(url, { schema: ProfileSchema });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function openInBrowser(url: string): void {
|
|
104
|
+
const cmd =
|
|
105
|
+
process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
106
|
+
|
|
107
|
+
exec(`${cmd} "${url}"`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function handleUnauthenticated() {
|
|
111
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
}
|
package/src/repo.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { repoCreate } from "./repo-create";
|
|
4
|
+
import { repoGetAccess } from "./repo-get-access";
|
|
5
|
+
import { repoList } from "./repo-list";
|
|
6
|
+
import { repoSetAccess } from "./repo-set-access";
|
|
7
|
+
import { repoSetName } from "./repo-set-name";
|
|
8
|
+
import { repoView } from "./repo-view";
|
|
9
|
+
|
|
10
|
+
const HELP = `
|
|
11
|
+
Manage Prismic repositories.
|
|
12
|
+
|
|
13
|
+
USAGE
|
|
14
|
+
prismic repo <command> [flags]
|
|
15
|
+
|
|
16
|
+
COMMANDS
|
|
17
|
+
create Create a new Prismic repository
|
|
18
|
+
list List all repositories
|
|
19
|
+
view View repository details
|
|
20
|
+
get-access Get Content API access level
|
|
21
|
+
set-access Set Content API access level
|
|
22
|
+
set-name Set repository display name
|
|
23
|
+
|
|
24
|
+
FLAGS
|
|
25
|
+
-h, --help Show help for command
|
|
26
|
+
|
|
27
|
+
LEARN MORE
|
|
28
|
+
Use \`prismic repo <command> --help\` for more information about a command.
|
|
29
|
+
`.trim();
|
|
30
|
+
|
|
31
|
+
export async function repo(): Promise<void> {
|
|
32
|
+
const {
|
|
33
|
+
positionals: [subcommand],
|
|
34
|
+
} = parseArgs({
|
|
35
|
+
args: process.argv.slice(3), // skip: node, script, "repo"
|
|
36
|
+
options: {
|
|
37
|
+
help: { type: "boolean", short: "h" },
|
|
38
|
+
},
|
|
39
|
+
allowPositionals: true,
|
|
40
|
+
strict: false,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
switch (subcommand) {
|
|
44
|
+
case "create":
|
|
45
|
+
await repoCreate();
|
|
46
|
+
break;
|
|
47
|
+
case "list":
|
|
48
|
+
await repoList();
|
|
49
|
+
break;
|
|
50
|
+
case "view":
|
|
51
|
+
await repoView();
|
|
52
|
+
break;
|
|
53
|
+
case "get-access":
|
|
54
|
+
await repoGetAccess();
|
|
55
|
+
break;
|
|
56
|
+
case "set-access":
|
|
57
|
+
await repoSetAccess();
|
|
58
|
+
break;
|
|
59
|
+
case "set-name":
|
|
60
|
+
await repoSetName();
|
|
61
|
+
break;
|
|
62
|
+
default: {
|
|
63
|
+
if (subcommand) {
|
|
64
|
+
console.error(`Unknown repo subcommand: ${subcommand}\n`);
|
|
65
|
+
process.exitCode = 1;
|
|
66
|
+
}
|
|
67
|
+
console.info(HELP);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { BooleanField, SharedSlice } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
|
|
6
|
+
import { buildTypes } from "./codegen-types";
|
|
7
|
+
import { stringify } from "./lib/json";
|
|
8
|
+
import { findSliceModel } from "./lib/slice";
|
|
9
|
+
import { humanReadable } from "./lib/string";
|
|
10
|
+
|
|
11
|
+
const HELP = `
|
|
12
|
+
Add a boolean (toggle) field to an existing slice.
|
|
13
|
+
|
|
14
|
+
USAGE
|
|
15
|
+
prismic slice add-field boolean <slice-id> <field-id> [flags]
|
|
16
|
+
|
|
17
|
+
ARGUMENTS
|
|
18
|
+
slice-id Slice identifier (required)
|
|
19
|
+
field-id Field identifier (required)
|
|
20
|
+
|
|
21
|
+
Types are generated by default after changes. Use --no-types to skip.
|
|
22
|
+
|
|
23
|
+
FLAGS
|
|
24
|
+
-v, --variation string Target variation (default: first variation)
|
|
25
|
+
-l, --label string Display label for the field (inferred from field-id if omitted)
|
|
26
|
+
--default Set default value to true
|
|
27
|
+
--true-label string Label shown when toggle is on
|
|
28
|
+
--false-label string Label shown when toggle is off
|
|
29
|
+
--types string Output file for generated types (default: "prismicio-types.d.ts")
|
|
30
|
+
--no-types Skip type generation
|
|
31
|
+
-h, --help Show help for command
|
|
32
|
+
|
|
33
|
+
EXAMPLES
|
|
34
|
+
prismic slice add-field boolean my_slice featured
|
|
35
|
+
prismic slice add-field boolean hero show_overlay --default
|
|
36
|
+
prismic slice add-field boolean product available --true-label "In Stock" --false-label "Out of Stock"
|
|
37
|
+
`.trim();
|
|
38
|
+
|
|
39
|
+
export async function sliceAddFieldBoolean(): Promise<void> {
|
|
40
|
+
const {
|
|
41
|
+
values: {
|
|
42
|
+
help,
|
|
43
|
+
variation,
|
|
44
|
+
label,
|
|
45
|
+
default: defaultValue,
|
|
46
|
+
"true-label": trueLabel,
|
|
47
|
+
"false-label": falseLabel,
|
|
48
|
+
types,
|
|
49
|
+
"no-types": noTypes,
|
|
50
|
+
},
|
|
51
|
+
positionals: [sliceId, fieldId],
|
|
52
|
+
} = parseArgs({
|
|
53
|
+
args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "boolean"
|
|
54
|
+
options: {
|
|
55
|
+
variation: { type: "string", short: "v" },
|
|
56
|
+
label: { type: "string", short: "l" },
|
|
57
|
+
default: { type: "boolean" },
|
|
58
|
+
"true-label": { type: "string" },
|
|
59
|
+
"false-label": { type: "string" },
|
|
60
|
+
types: { type: "string" },
|
|
61
|
+
"no-types": { type: "boolean" },
|
|
62
|
+
help: { type: "boolean", short: "h" },
|
|
63
|
+
},
|
|
64
|
+
allowPositionals: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (help) {
|
|
68
|
+
console.info(HELP);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!sliceId) {
|
|
73
|
+
console.error("Missing required argument: slice-id\n");
|
|
74
|
+
console.error("Usage: prismic slice add-field boolean <slice-id> <field-id>");
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!fieldId) {
|
|
80
|
+
console.error("Missing required argument: field-id\n");
|
|
81
|
+
console.error("Usage: prismic slice add-field boolean <slice-id> <field-id>");
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Find the slice model
|
|
87
|
+
const result = await findSliceModel(sliceId);
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
console.error(result.error);
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const { model, modelPath } = result;
|
|
95
|
+
|
|
96
|
+
// Check for variations
|
|
97
|
+
if (model.variations.length === 0) {
|
|
98
|
+
console.error(`Slice "${sliceId}" has no variations.\n`);
|
|
99
|
+
console.error("Add a variation first before adding fields.");
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Find target variation
|
|
105
|
+
const targetVariation = variation
|
|
106
|
+
? model.variations.find((v) => v.id === variation)
|
|
107
|
+
: model.variations[0];
|
|
108
|
+
|
|
109
|
+
if (!targetVariation) {
|
|
110
|
+
console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
|
|
111
|
+
console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Initialize primary if it doesn't exist
|
|
117
|
+
if (!targetVariation.primary) {
|
|
118
|
+
targetVariation.primary = {};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check if field already exists in any variation
|
|
122
|
+
for (const v of model.variations) {
|
|
123
|
+
if (v.primary?.[fieldId]) {
|
|
124
|
+
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
125
|
+
process.exitCode = 1;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Build field definition
|
|
131
|
+
const fieldDefinition: BooleanField = {
|
|
132
|
+
type: "Boolean",
|
|
133
|
+
config: {
|
|
134
|
+
label: label ?? humanReadable(fieldId),
|
|
135
|
+
...(defaultValue && { default_value: true }),
|
|
136
|
+
...(trueLabel && { placeholder_true: trueLabel }),
|
|
137
|
+
...(falseLabel && { placeholder_false: falseLabel }),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Add field to variation
|
|
142
|
+
targetVariation.primary[fieldId] = fieldDefinition;
|
|
143
|
+
|
|
144
|
+
// Write updated model
|
|
145
|
+
try {
|
|
146
|
+
await writeFile(modelPath, stringify(model as SharedSlice));
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (error instanceof Error) {
|
|
149
|
+
console.error(`Failed to update slice: ${error.message}`);
|
|
150
|
+
} else {
|
|
151
|
+
console.error("Failed to update slice");
|
|
152
|
+
}
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.info(
|
|
158
|
+
`Added field "${fieldId}" (Boolean) to "${targetVariation.id}" variation in ${sliceId}`,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (!noTypes) {
|
|
162
|
+
try {
|
|
163
|
+
await buildTypes({ output: types });
|
|
164
|
+
console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.info();
|
|
171
|
+
console.info("Next: Add more fields with `prismic slice add-field`");
|
|
172
|
+
console.info(" Run `prismic status` when done to find next steps");
|
|
173
|
+
}
|