@angeloashmore/prismic-cli-poc 0.0.0-canary.2ff9563
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 +1996 -0
- package/package.json +52 -0
- package/src/custom-type-add-field-boolean.ts +171 -0
- package/src/custom-type-add-field-color.ts +158 -0
- package/src/custom-type-add-field-date.ts +161 -0
- package/src/custom-type-add-field-embed.ts +158 -0
- package/src/custom-type-add-field-geo-point.ts +155 -0
- package/src/custom-type-add-field-image.ts +158 -0
- package/src/custom-type-add-field-key-text.ts +158 -0
- package/src/custom-type-add-field-link.ts +180 -0
- package/src/custom-type-add-field-number.ts +190 -0
- package/src/custom-type-add-field-rich-text.ts +181 -0
- package/src/custom-type-add-field-select.ts +164 -0
- package/src/custom-type-add-field-timestamp.ts +161 -0
- package/src/custom-type-add-field-uid.ts +158 -0
- package/src/custom-type-add-field.ts +111 -0
- package/src/custom-type-connect-slice.ts +221 -0
- package/src/custom-type-create.ts +92 -0
- package/src/custom-type-disconnect-slice.ts +179 -0
- package/src/custom-type-list.ts +110 -0
- package/src/custom-type-remove-field.ts +161 -0
- package/src/custom-type-remove.ts +126 -0
- package/src/custom-type-set-name.ts +128 -0
- package/src/custom-type-view.ts +118 -0
- package/src/custom-type.ts +85 -0
- package/src/index.ts +100 -0
- package/src/init.ts +62 -0
- package/src/lib/auth.ts +60 -0
- package/src/lib/config.ts +111 -0
- package/src/lib/file.ts +49 -0
- package/src/lib/json.ts +3 -0
- package/src/lib/request.ts +116 -0
- package/src/lib/slice.ts +112 -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 +143 -0
- package/src/logout.ts +36 -0
- package/src/page-type-add-field-boolean.ts +171 -0
- package/src/page-type-add-field-color.ts +158 -0
- package/src/page-type-add-field-date.ts +161 -0
- package/src/page-type-add-field-embed.ts +158 -0
- package/src/page-type-add-field-geo-point.ts +155 -0
- package/src/page-type-add-field-image.ts +158 -0
- package/src/page-type-add-field-key-text.ts +158 -0
- package/src/page-type-add-field-link.ts +180 -0
- package/src/page-type-add-field-number.ts +190 -0
- package/src/page-type-add-field-rich-text.ts +181 -0
- package/src/page-type-add-field-select.ts +164 -0
- package/src/page-type-add-field-timestamp.ts +161 -0
- package/src/page-type-add-field-uid.ts +158 -0
- package/src/page-type-add-field.ts +111 -0
- package/src/page-type-connect-slice.ts +221 -0
- package/src/page-type-create.ts +93 -0
- package/src/page-type-disconnect-slice.ts +179 -0
- package/src/page-type-list.ts +109 -0
- package/src/page-type-remove-field.ts +161 -0
- package/src/page-type-remove.ts +126 -0
- package/src/page-type-set-name.ts +128 -0
- package/src/page-type-set-repeatable.ts +137 -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-list.ts +106 -0
- package/src/preview-remove.ts +109 -0
- package/src/preview-set-name.ts +137 -0
- package/src/preview.ts +60 -0
- package/src/repo-create.ts +136 -0
- package/src/repo-list.ts +100 -0
- package/src/repo-set-name.ts +102 -0
- package/src/repo-view.ts +113 -0
- package/src/repo.ts +60 -0
- package/src/slice-add-field-boolean.ts +150 -0
- package/src/slice-add-field-color.ts +137 -0
- package/src/slice-add-field-date.ts +137 -0
- package/src/slice-add-field-embed.ts +137 -0
- package/src/slice-add-field-geo-point.ts +134 -0
- package/src/slice-add-field-image.ts +134 -0
- package/src/slice-add-field-key-text.ts +137 -0
- package/src/slice-add-field-link.ts +155 -0
- package/src/slice-add-field-number.ts +137 -0
- package/src/slice-add-field-rich-text.ts +160 -0
- package/src/slice-add-field-select.ts +143 -0
- package/src/slice-add-field-timestamp.ts +137 -0
- package/src/slice-add-field.ts +106 -0
- package/src/slice-add-variation.ts +137 -0
- package/src/slice-create.ts +129 -0
- package/src/slice-list-variations.ts +67 -0
- package/src/slice-list.ts +88 -0
- package/src/slice-remove-field.ts +117 -0
- package/src/slice-remove-variation.ts +108 -0
- package/src/slice-remove.ts +81 -0
- package/src/slice-rename.ts +112 -0
- package/src/slice-view.ts +77 -0
- package/src/slice.ts +90 -0
- package/src/sync.ts +309 -0
- package/src/token-create.ts +185 -0
- package/src/token-delete.ts +161 -0
- package/src/token-list.ts +212 -0
- package/src/token-set-name.ts +165 -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/lib/slice.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { SharedSlice } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
|
|
3
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
|
|
6
|
+
import { exists, findUpward } from "./file";
|
|
7
|
+
|
|
8
|
+
export const SharedSliceSchema = v.object({
|
|
9
|
+
id: v.string(),
|
|
10
|
+
type: v.literal("SharedSlice"),
|
|
11
|
+
name: v.string(),
|
|
12
|
+
description: v.optional(v.string()),
|
|
13
|
+
variations: v.array(
|
|
14
|
+
v.object({
|
|
15
|
+
id: v.string(),
|
|
16
|
+
name: v.string(),
|
|
17
|
+
description: v.optional(v.string()),
|
|
18
|
+
docURL: v.optional(v.string()),
|
|
19
|
+
version: v.optional(v.string()),
|
|
20
|
+
imageUrl: v.optional(v.string()),
|
|
21
|
+
primary: v.optional(v.record(v.string(), v.unknown())),
|
|
22
|
+
items: v.optional(v.record(v.string(), v.unknown())),
|
|
23
|
+
}),
|
|
24
|
+
),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
type SliceModelResult =
|
|
28
|
+
| { ok: true; model: SharedSlice; modelPath: URL }
|
|
29
|
+
| { ok: false; error: string };
|
|
30
|
+
|
|
31
|
+
export async function findSliceModel(sliceId: string): Promise<SliceModelResult> {
|
|
32
|
+
const projectRoot = await findUpward("package.json");
|
|
33
|
+
if (!projectRoot) {
|
|
34
|
+
return { ok: false, error: "Could not find project root (no package.json found)" };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const slicesDirectory = await getSlicesDirectory();
|
|
38
|
+
|
|
39
|
+
// List all directories in slices folder
|
|
40
|
+
let entries: string[];
|
|
41
|
+
try {
|
|
42
|
+
entries = await readdir(slicesDirectory, { withFileTypes: false }) as unknown as string[];
|
|
43
|
+
} catch {
|
|
44
|
+
return { ok: false, error: `No slices directory found at ${slicesDirectory.href}` };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Search for a slice with matching ID
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
const modelPath = new URL(`${entry}/model.json`, slicesDirectory);
|
|
50
|
+
try {
|
|
51
|
+
const contents = await readFile(modelPath, "utf8");
|
|
52
|
+
const parsed = JSON.parse(contents);
|
|
53
|
+
if (parsed.id === sliceId) {
|
|
54
|
+
const result = v.safeParse(SharedSliceSchema, parsed);
|
|
55
|
+
if (!result.success) {
|
|
56
|
+
return { ok: false, error: `Invalid slice model at ${modelPath.href}` };
|
|
57
|
+
}
|
|
58
|
+
return { ok: true, model: result.output as SharedSlice, modelPath };
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
// Skip directories without valid model.json
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { ok: false, error: `Slice not found: ${sliceId}\n\nCreate it first with: prismic slice create ${sliceId}` };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function getSlicesDirectory(): Promise<URL> {
|
|
69
|
+
const framework = await detectFramework();
|
|
70
|
+
const projectRoot = await findUpward("package.json");
|
|
71
|
+
if (!projectRoot) {
|
|
72
|
+
throw new Error("Could not find project root (no package.json found)");
|
|
73
|
+
}
|
|
74
|
+
const projectDir = new URL(".", projectRoot);
|
|
75
|
+
|
|
76
|
+
switch (framework) {
|
|
77
|
+
case "next": {
|
|
78
|
+
const hasSrcDir = await exists(new URL("src", projectDir));
|
|
79
|
+
if (hasSrcDir) return new URL("src/slices/", projectDir);
|
|
80
|
+
}
|
|
81
|
+
case "nuxt": {
|
|
82
|
+
const hasAppDir = await exists(new URL("app", projectDir));
|
|
83
|
+
if (hasAppDir) return new URL("app/slices/", projectDir);
|
|
84
|
+
}
|
|
85
|
+
case "sveltekit": {
|
|
86
|
+
return new URL("src/slices/", projectDir);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return new URL("slices/", projectDir);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const PackageJsonSchema = v.object({
|
|
93
|
+
dependencies: v.optional(v.record(v.string(), v.string())),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
type Framework = "next" | "nuxt" | "sveltekit";
|
|
97
|
+
|
|
98
|
+
async function detectFramework(): Promise<Framework | undefined> {
|
|
99
|
+
const packageJsonPath = await findUpward("package.json");
|
|
100
|
+
if (!packageJsonPath) return;
|
|
101
|
+
try {
|
|
102
|
+
const contents = await readFile(packageJsonPath, "utf8");
|
|
103
|
+
const { dependencies = {} } = v.parse(PackageJsonSchema, JSON.parse(contents));
|
|
104
|
+
if ("next" in dependencies) return "next";
|
|
105
|
+
if ("nuxt" in dependencies) return "nuxt";
|
|
106
|
+
if ("@sveltejs/kit" in dependencies) return "sveltekit";
|
|
107
|
+
} catch {}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function pascalCase(input: string): string {
|
|
111
|
+
return input.toLowerCase().replace(/(^|[-_\s]+)(.)?/g, (_, __, c) => c?.toUpperCase() ?? "");
|
|
112
|
+
}
|
package/src/lib/url.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readHost } from "./auth";
|
|
2
|
+
|
|
3
|
+
export async function getRepoUrl(repo: string): Promise<URL> {
|
|
4
|
+
const host = await readHost();
|
|
5
|
+
host.hostname = `${repo}.${host.hostname}`;
|
|
6
|
+
return appendTrailingSlash(host);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function getInternalApiUrl(): Promise<URL> {
|
|
10
|
+
const host = await readHost();
|
|
11
|
+
host.hostname = `api.internal.${host.hostname}`;
|
|
12
|
+
return appendTrailingSlash(host);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function getUserServiceUrl(): Promise<URL> {
|
|
16
|
+
const host = await readHost();
|
|
17
|
+
host.hostname = `user-service.${host.hostname}`;
|
|
18
|
+
return appendTrailingSlash(host);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function appendTrailingSlash(url: string | URL): URL {
|
|
22
|
+
const newURL = new URL(url);
|
|
23
|
+
if (!newURL.pathname.endsWith("/")) newURL.pathname += "/";
|
|
24
|
+
return newURL;
|
|
25
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
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 HELP = `
|
|
10
|
+
Add a new locale to a Prismic repository.
|
|
11
|
+
|
|
12
|
+
By default, this command reads the repository from prismic.config.json at the
|
|
13
|
+
project root.
|
|
14
|
+
|
|
15
|
+
USAGE
|
|
16
|
+
prismic locale add <code> [flags]
|
|
17
|
+
|
|
18
|
+
ARGUMENTS
|
|
19
|
+
<code> Locale code (e.g. fr-fr, es-es)
|
|
20
|
+
|
|
21
|
+
FLAGS
|
|
22
|
+
-n, --name string Custom display name (creates custom locale)
|
|
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 localeAdd(): Promise<void> {
|
|
31
|
+
const {
|
|
32
|
+
values: { help, name, repo = await safeGetRepositoryFromConfig() },
|
|
33
|
+
positionals: [code],
|
|
34
|
+
} = parseArgs({
|
|
35
|
+
args: process.argv.slice(4), // skip: node, script, "locale", "add"
|
|
36
|
+
options: {
|
|
37
|
+
name: { type: "string", short: "n" },
|
|
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 (!code) {
|
|
50
|
+
console.error("Missing required argument: <code>");
|
|
51
|
+
process.exitCode = 1;
|
|
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 authenticated = await isAuthenticated();
|
|
62
|
+
if (!authenticated) {
|
|
63
|
+
handleUnauthenticated();
|
|
64
|
+
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const response = name
|
|
69
|
+
? await addCustomLocale(repo, code, name)
|
|
70
|
+
: await addStandardLocale(repo, code);
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
if (
|
|
73
|
+
typeof response.value === "string" &&
|
|
74
|
+
response.value.includes("already existing languages")
|
|
75
|
+
) {
|
|
76
|
+
// Treat as success
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
81
|
+
handleUnauthenticated();
|
|
82
|
+
} else {
|
|
83
|
+
console.error(`Failed to add locale: ${stringify(response.value)}`);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.info(`Locale added: ${code}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function addStandardLocale(repo: string, code: string) {
|
|
94
|
+
const url = new URL("/app/settings/multilanguages", await getRepoUrl(repo));
|
|
95
|
+
return await request(url, {
|
|
96
|
+
method: "POST",
|
|
97
|
+
body: { languages: [code] },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function addCustomLocale(repo: string, code: string, name: string) {
|
|
102
|
+
const [langPart, regionPart] = code.split("-");
|
|
103
|
+
const url = new URL("/app/settings/multilanguages/custom", await getRepoUrl(repo));
|
|
104
|
+
return await request(url, {
|
|
105
|
+
method: "POST",
|
|
106
|
+
body: {
|
|
107
|
+
lang: { label: name, id: langPart || code },
|
|
108
|
+
region: { label: name, id: regionPart || langPart || code },
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function handleUnauthenticated() {
|
|
114
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
115
|
+
process.exitCode = 1;
|
|
116
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
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, type ParsedRequestResponse, request } from "./lib/request";
|
|
8
|
+
import { getInternalApiUrl } from "./lib/url";
|
|
9
|
+
|
|
10
|
+
const HELP = `
|
|
11
|
+
List all locales in 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 locale list [flags]
|
|
18
|
+
|
|
19
|
+
FLAGS
|
|
20
|
+
--json Output as JSON
|
|
21
|
+
-r, --repo string Repository domain
|
|
22
|
+
-h, --help Show help for command
|
|
23
|
+
|
|
24
|
+
LEARN MORE
|
|
25
|
+
Use \`prismic <command> <subcommand> --help\` for more information about a command.
|
|
26
|
+
`.trim();
|
|
27
|
+
|
|
28
|
+
export async function localeList(): Promise<void> {
|
|
29
|
+
const {
|
|
30
|
+
values: { help, repo = await safeGetRepositoryFromConfig(), json },
|
|
31
|
+
} = parseArgs({
|
|
32
|
+
args: process.argv.slice(4), // skip: node, script, "locale", "list"
|
|
33
|
+
options: {
|
|
34
|
+
json: { type: "boolean" },
|
|
35
|
+
repo: { type: "string", short: "r" },
|
|
36
|
+
help: { type: "boolean", short: "h" },
|
|
37
|
+
},
|
|
38
|
+
allowPositionals: false,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (help) {
|
|
42
|
+
console.info(HELP);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!repo) {
|
|
47
|
+
console.error("Missing prismic.config.json or --repo option");
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const authenticated = await isAuthenticated();
|
|
53
|
+
if (!authenticated) {
|
|
54
|
+
handleUnauthenticated();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const response = await getLocales(repo);
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
61
|
+
handleUnauthenticated();
|
|
62
|
+
} else if (v.isValiError(response.error)) {
|
|
63
|
+
console.error(
|
|
64
|
+
`Failed to list locales: Invalid response: ${stringify(response.error.issues)}`,
|
|
65
|
+
);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
} else {
|
|
68
|
+
console.error(`Failed to list locales: ${stringify(response.value)}`);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const locales = response.value.results;
|
|
75
|
+
if (json) {
|
|
76
|
+
console.info(stringify(locales));
|
|
77
|
+
} else {
|
|
78
|
+
for (const locale of locales) {
|
|
79
|
+
const defaultLabel = locale.isMaster ? " (default)" : "";
|
|
80
|
+
console.info(`${locale.id} ${locale.label}${defaultLabel}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const LocaleSchema = v.object({
|
|
86
|
+
id: v.string(),
|
|
87
|
+
label: v.string(),
|
|
88
|
+
customName: v.nullable(v.string()),
|
|
89
|
+
isMaster: v.boolean(),
|
|
90
|
+
});
|
|
91
|
+
export type Locale = v.InferOutput<typeof LocaleSchema>;
|
|
92
|
+
|
|
93
|
+
const GetLocalesResponseSchema = v.object({
|
|
94
|
+
results: v.array(LocaleSchema),
|
|
95
|
+
});
|
|
96
|
+
type GetLocalesResponse = v.InferOutput<typeof GetLocalesResponseSchema>;
|
|
97
|
+
|
|
98
|
+
export async function getLocales(repo: string): Promise<ParsedRequestResponse<GetLocalesResponse>> {
|
|
99
|
+
const url = new URL("/locale/repository/locales", await getInternalApiUrl());
|
|
100
|
+
url.searchParams.set("repository", repo);
|
|
101
|
+
return await request(url, { schema: GetLocalesResponseSchema });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function handleUnauthenticated() {
|
|
105
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
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 { getInternalApiUrl } from "./lib/url";
|
|
8
|
+
|
|
9
|
+
const HELP = `
|
|
10
|
+
Remove a locale from a Prismic repository.
|
|
11
|
+
|
|
12
|
+
By default, this command reads the repository from prismic.config.json at the
|
|
13
|
+
project root.
|
|
14
|
+
|
|
15
|
+
USAGE
|
|
16
|
+
prismic locale remove <code> [flags]
|
|
17
|
+
|
|
18
|
+
ARGUMENTS
|
|
19
|
+
<code> Locale code (e.g. en-us, fr-fr)
|
|
20
|
+
|
|
21
|
+
FLAGS
|
|
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
|
+
export async function localeRemove(): Promise<void> {
|
|
30
|
+
const {
|
|
31
|
+
values: { repo = await safeGetRepositoryFromConfig(), help },
|
|
32
|
+
positionals: [code],
|
|
33
|
+
} = parseArgs({
|
|
34
|
+
args: process.argv.slice(4), // skip: node, script, "locale", "remove"
|
|
35
|
+
options: {
|
|
36
|
+
repo: { type: "string", short: "r" },
|
|
37
|
+
help: { type: "boolean", short: "h" },
|
|
38
|
+
},
|
|
39
|
+
allowPositionals: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (help) {
|
|
43
|
+
console.info(HELP);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!code) {
|
|
48
|
+
console.error("Missing required argument: <code>");
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!repo) {
|
|
54
|
+
console.error("Missing prismic.config.json or --repo option");
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const authenticated = await isAuthenticated();
|
|
60
|
+
if (!authenticated) {
|
|
61
|
+
handleUnauthenticated();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const response = await removeLocale(repo, code);
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
68
|
+
handleUnauthenticated();
|
|
69
|
+
} else {
|
|
70
|
+
console.error(`Failed to remove locale: ${stringify(response.value)}`);
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.info(`Removed locale: ${code}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function removeLocale(repository: string, code: string) {
|
|
80
|
+
const url = new URL(`/locale/repository/locales/${code}`, await getInternalApiUrl());
|
|
81
|
+
url.searchParams.set("repository", repository);
|
|
82
|
+
return await request(url, { method: "DELETE" });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function handleUnauthenticated() {
|
|
86
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
87
|
+
process.exitCode = 1;
|
|
88
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
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 { getInternalApiUrl } from "./lib/url";
|
|
9
|
+
import { type Locale, getLocales } from "./locale-list";
|
|
10
|
+
|
|
11
|
+
const HELP = `
|
|
12
|
+
Set the default locale for 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 locale set-default <code> [flags]
|
|
19
|
+
|
|
20
|
+
ARGUMENTS
|
|
21
|
+
<code> Locale code (e.g. en-us, fr-fr)
|
|
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 localeSetDefault(): Promise<void> {
|
|
32
|
+
const {
|
|
33
|
+
values: { help, repo = await safeGetRepositoryFromConfig() },
|
|
34
|
+
positionals: [code],
|
|
35
|
+
} = parseArgs({
|
|
36
|
+
args: process.argv.slice(4), // skip: node, script, "locale", "set-default"
|
|
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 (!code) {
|
|
50
|
+
console.error("Missing required argument: <code>");
|
|
51
|
+
process.exitCode = 1;
|
|
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 authenticated = await isAuthenticated();
|
|
62
|
+
if (!authenticated) {
|
|
63
|
+
handleUnauthenticated();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const localesResponse = await getLocales(repo);
|
|
68
|
+
if (!localesResponse.ok) {
|
|
69
|
+
if (localesResponse.error instanceof ForbiddenRequestError) {
|
|
70
|
+
handleUnauthenticated();
|
|
71
|
+
} else if (v.isValiError(localesResponse.error)) {
|
|
72
|
+
console.error(
|
|
73
|
+
`Failed to set default locale: Invalid response: ${stringify(localesResponse.error.issues)}`,
|
|
74
|
+
);
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
} else {
|
|
77
|
+
console.error(`Failed to set default locale: ${stringify(localesResponse.value)}`);
|
|
78
|
+
process.exitCode = 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const locales = localesResponse.value.results;
|
|
85
|
+
const locale = locales.find((l) => l.id === code);
|
|
86
|
+
if (!locale) {
|
|
87
|
+
console.error(
|
|
88
|
+
`Locale "${code}" not found in repository. Available locales: ${locales.map((l) => l.id).join(", ")}`,
|
|
89
|
+
);
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (locale.isMaster) {
|
|
95
|
+
console.error(`Locale "${code}" is already the default.`);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const response = await setDefaultLocale(repo, locale);
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
if (response.error instanceof ForbiddenRequestError) {
|
|
103
|
+
handleUnauthenticated();
|
|
104
|
+
} else {
|
|
105
|
+
console.error(`Failed to set default locale: ${stringify(response.value)}`);
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.info(`Default locale set: ${code}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function setDefaultLocale(repo: string, locale: Locale) {
|
|
115
|
+
const url = new URL("/locale/repository/locales", await getInternalApiUrl());
|
|
116
|
+
url.searchParams.set("repository", repo);
|
|
117
|
+
return await request(url, {
|
|
118
|
+
method: "POST",
|
|
119
|
+
body: {
|
|
120
|
+
id: locale.id,
|
|
121
|
+
label: locale.label,
|
|
122
|
+
customName: locale.customName,
|
|
123
|
+
isMaster: true,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function handleUnauthenticated() {
|
|
129
|
+
console.error("Not logged in. Run `prismic login` first.");
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
}
|
package/src/locale.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { localeAdd } from "./locale-add";
|
|
4
|
+
import { localeList } from "./locale-list";
|
|
5
|
+
import { localeRemove } from "./locale-remove";
|
|
6
|
+
import { localeSetDefault } from "./locale-set-default";
|
|
7
|
+
|
|
8
|
+
const HELP = `
|
|
9
|
+
Manage locales in a Prismic repository.
|
|
10
|
+
|
|
11
|
+
USAGE
|
|
12
|
+
prismic locale <command> [flags]
|
|
13
|
+
|
|
14
|
+
COMMANDS
|
|
15
|
+
add Add a locale to a repository
|
|
16
|
+
list List locales in a repository
|
|
17
|
+
remove Remove a locale from a repository
|
|
18
|
+
set-default Set the default locale for a repository
|
|
19
|
+
|
|
20
|
+
FLAGS
|
|
21
|
+
-h, --help Show help for command
|
|
22
|
+
|
|
23
|
+
LEARN MORE
|
|
24
|
+
Use \`prismic locale <command> --help\` for more information about a command.
|
|
25
|
+
`.trim();
|
|
26
|
+
|
|
27
|
+
export async function locale(): Promise<void> {
|
|
28
|
+
const {
|
|
29
|
+
positionals: [subcommand],
|
|
30
|
+
} = parseArgs({
|
|
31
|
+
args: process.argv.slice(3), // skip: node, script, "locale"
|
|
32
|
+
options: {
|
|
33
|
+
help: { type: "boolean", short: "h" },
|
|
34
|
+
},
|
|
35
|
+
allowPositionals: true,
|
|
36
|
+
strict: false,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
switch (subcommand) {
|
|
40
|
+
case "add":
|
|
41
|
+
await localeAdd();
|
|
42
|
+
break;
|
|
43
|
+
case "list":
|
|
44
|
+
await localeList();
|
|
45
|
+
break;
|
|
46
|
+
case "remove":
|
|
47
|
+
await localeRemove();
|
|
48
|
+
break;
|
|
49
|
+
case "set-default":
|
|
50
|
+
await localeSetDefault();
|
|
51
|
+
break;
|
|
52
|
+
default: {
|
|
53
|
+
if (subcommand) {
|
|
54
|
+
console.error(`Unknown locale subcommand: ${subcommand}\n`);
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
}
|
|
57
|
+
console.info(HELP);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|